Cercetarile si propunerile rundelor 4-6 pe editarea facturii emise. Starea rundei 6 si ce s-a stabilit intra in progres.md. Nou: docs/conventii_mediu_oracle.md - pe dev/test se lucreaza numai cu ROA_CENTRAL si schemele CONTAFIN_ORACLE si MARIUSM_AUTO; schema ACN nu se foloseste. Scripturile de pachet sunt necalificate, deci schema tinta o decide sirul de conectare, nu fisierul. roafacturare.pj2 regenerat de git_sync. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013gYCNE26G1G7UoGu2ju7aS
4255 lines
326 KiB
Markdown
4255 lines
326 KiB
Markdown
# Plan #13 — formular unificat de facturare + editare prin regenerare
|
||
|
||
Sursa: `COMUN\docs\todos.txt` punctul 13.
|
||
Mockup: `docs\mockup_13_formular_unificat.html` (versiunea 5).
|
||
Cercetare pe cod, toata in `docs\cercetare\`: `inventar_controale_formulare.md`,
|
||
`proforma_copiere_puncte_intrare.md`, `import_roris_roaacnpro.md`, `discount_pe_articol.md` si
|
||
`discount_verificare2.md` (a doua il corecteaza pe primul), `modifica_antet_bifa.md`,
|
||
`valuta_si_curs.md`, `buton_comutator_picture.md`, `modifica_date_factura_parametri.md`,
|
||
`retur_si_lista_preturi.md`, `factura_retur_document.md`, `roaauto_facturi.md`,
|
||
`roaauto_articole_lista_preturi.md`, `cont_venit_articol_fara_politica.md`.
|
||
Stare: **propunere, neinceput**. Analiza facuta pe cod la 09.08.2026, in sase runde.
|
||
|
||
## Cerinta, asa cum a fost formulata
|
||
|
||
Trei lucruri intr-un singur punct:
|
||
|
||
1. **Unificarea formularelor** — `date_factura` / `date_aviz` sa intre in formularul de facturare,
|
||
ca sa nu mai fie doua ferestre pentru acelasi document.
|
||
2. **Fara incarcarea prealabila a tuturor articolelor** din toate politicile de preturi — pot fi mii
|
||
si dureaza mult aducerea lor de pe server.
|
||
3. **Editarea facturii / avizului prin regenerare**, in toate variantele (politici de preturi,
|
||
comanda, contract, aviz): formularul se redeschide completat ca inainte de salvarea initiala, se
|
||
fac modificarile ca la introducere, iar la confirmare documentul initial se marcheaza `sters = 1`
|
||
si se salveaza unul nou — ca sa se vada ce s-a modificat.
|
||
|
||
Decizia lui Marius, 09.08.2026: **intai unificarea, apoi editarea prin regenerare.** Explicit
|
||
**nu** pe calea editarii directe a notelor / rulajelor / articolelor.
|
||
|
||
## Deciziile lui Marius, 09.08.2026 — luate, nu de reluat
|
||
|
||
1. **#13 coexista cu #6**, nu il inlocuieste.
|
||
2. **`ID_FACT` se pastreaza**, ca la orice modificare. Documentul reemis nu-si schimba identitatea.
|
||
3. **Toate datele se pastreaza, inclusiv numarul documentului.** Scopul e modificarea documentului,
|
||
nu emiterea altuia.
|
||
4. **Antetul care intra in generarea lui `ID_FACT` (serie, numar, data) are cale proprie de
|
||
modificare** — nu trece prin regenerare.
|
||
5. **Un singur formular, aceeasi infatisare la introducere si la modificare.** Fara banda de
|
||
avertisment, fara coloane cu valorile initiale, fara panou de diferente.
|
||
6. **Se integreaza si modificarea de antet, si modificarea de articol care exista azi** — sa nu
|
||
ramana trei actiuni de modificare pe acelasi document.
|
||
|
||
## Deciziile lui Marius, runda 3 (09.08.2026) — luate, nu de reluat
|
||
|
||
7. **`frm_alte_date` intra in formular**, in sectiunea pliata. Se inchide intrebarea ramasa deschisa
|
||
in runda 2 (recomandarea de atunci — „ramane dialog” — **cade**).
|
||
8. **Sectiunea pliata primeste in plus analiticele**: venit / cheltuiala, sectie, responsabil (si,
|
||
prin simetrie, lucrare). Antetul vizibil ramane aerisit, cu **controalele grupate** pe intelesuri,
|
||
nu insirate.
|
||
9. **Un singur buton comutator pe antet.** Antetul se deschide blocat. Un singur `but_modifica`
|
||
(creionul) il deblocheaza si **isi schimba imaginea in discheta lui `but_salvare`**; a doua
|
||
apasare salveaza **doar antetul** si il blocheaza la loc. Un singur control, nu bifa plus buton —
|
||
mai compact. **Toata factura se salveaza in continuare din `Termina`.** Rostul ramane acelasi:
|
||
antetul se editeaza intentionat, nu din greseala, si se poate corecta fara a trece prin articole.
|
||
|
||
**Butonul singur deschide tot antetul. Nu mai exista bife individuale** — nici cele patru de azi
|
||
(serie / numar / data / scadenta). Un singur control comanda toata protectia antetului.
|
||
|
||
*Istoric, ca sa nu se reia:* runda 3 propusese un buton `Modificare / Salveaza` care bloca **tot
|
||
documentul** — respins, protectia e doar pe antet. Runda 4 propusese **bifa + buton separat** —
|
||
respins la 09.08.2026 in favoarea butonului comutator. Runda 5 propusese **pastrarea celor patru
|
||
bife individuale sub buton** — respins la 09.08.2026: bifele dispar cu totul.
|
||
|
||
**Verificat pe cod la 09.08.2026** (`docs\cercetare\buton_comutator_picture.md`): **tiparul exista
|
||
deja in suita si se copiaza, nu se inventeaza.** `frm_rulaje.se_modifica_assign`
|
||
(`COMUN\clase\rulaje.vc2:4716-4773`) comuta exact asa **o singura instanta** de `but_modifica`
|
||
intre creion si discheta — nu instantiaza a doua clasa. Trei lucruri de retinut din el:
|
||
- se rescriu **impreuna** `.cpicturedown`, `.cpictureup` **si** `.Picture`, plus `.ToolTipText`,
|
||
urmate de `.Refresh()`. Numai `.Picture` nu ajunge: hover-ul standard din
|
||
`buton.MouseEnter` / `MouseLeave` (`_cmd_base.vc2:88-97`) rescrie `Picture` din `cPictureUp` /
|
||
`cPictureDown`, deci iconita veche ar reveni la primul mouse-over;
|
||
- numele de fisier se dau **fara cale** (`"save_sus.bmp"`), rezolvate prin `SET PATH` — care
|
||
include si `GRAFICE`, si `COMUN\GRAFICE` (`Programe\roafacturare.prg:85-108`). Calea relativa
|
||
`..\grafice\...` din clasa e buna doar la design-time;
|
||
- imaginile exista: `COMUN\grafice\save_sus.bmp` / `save_jos.bmp` (discheta),
|
||
`modific_sus.bmp` / `modific_jos.bmp` (creion, perechea folosita de clasa).
|
||
|
||
Clasa de salvare din biblioteca se numeste **`but_salveaza`**, nu `but_salvare`
|
||
(`cmd_butoane.vc2:340-352`); e sursa numelor de imagini, dar nu se instantiaza. Clasa
|
||
`but_modifica` e la `cmd_butoane.vc2:184-198`. Butoanele **nu** au `do_activeaza` /
|
||
`do_dezactiveaza` — pe ele se lucreaza direct pe `.Enabled`.
|
||
|
||
**Consecinta asupra celor patru bife individuale** (serie / numar / data / scadenta, vezi I):
|
||
**se elimina**, si **odata cu ele se abandoneaza si conditia lor** de azi
|
||
(`chkSerieAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))`, `ofacturare_comun.vc2:5736-5750`).
|
||
Decis de Marius la 09.08.2026: **butonul deschide tot**, fara conditii pe camp. Un singur control,
|
||
o singura regula. Cat de departe merge „tot” — vezi **decizia 19**: exact cat scrie
|
||
`modifica_date_factura`, parametru cu parametru.
|
||
10. **Proforma foloseste acelasi formular.**
|
||
11. **Copierea foloseste acelasi formular**, ca document nou, cu antetul editabil.
|
||
12. **Formularul trebuie sa *poata* fi apelat cu sursa deja completata** — din pagina de comenzi cu
|
||
comanda, si din programul de contracte cu contractul, fara ca utilizatorul sa mai aleaga ulterior.
|
||
**Nu se integreaza contractele acum**; nu depinde de #10.
|
||
13. **Un singur buton de adaugare a articolelor, cu `xmenu()`** — nu doua butoane separate „adauga
|
||
tot” si „alege”. Optiunile din meniu se schimba dupa sursa si acopera **comanda, contractul si
|
||
avizele**, cu alegere selectiva acolo unde are sens (de exemplu o singura rata de contract).
|
||
Butoanele de linie stau deasupra tabelului.
|
||
14. **Discountul pe articol, procent si valoare absoluta**, amandoua accesibile.
|
||
15. **Data cursului valutar apare doar cand are sens.** Sunt doua concepte diferite, care azi impart
|
||
acelasi camp mereu vizibil: (a) **factura in valuta**, unde si articolele au pret in valuta, si
|
||
(b) **factura in lei cu articole care pot avea pret in valuta**, convertite in lei la cursul din
|
||
data cursului, cu documentul si contabilitatea in lei. Formularul trebuie sa fie **ergonomic si
|
||
simplu** — campul nu apare cand nu e nimic de convertit.
|
||
|
||
### Deciziile lui Marius, runda 6 (09.08.2026)
|
||
|
||
16. **Lista de preturi e disponibila mereu, indiferent de sursa — si liniile suplimentare se pot si
|
||
sterge.** Pe o factura din comanda sau din contract trebuie sa se poata **adauga si sterge**
|
||
articole libere din lista de preturi, nu doar articole din sursa. Cazul real, formulat de Marius:
|
||
clientul a comandat ceva, iar la facturare mai vrea ceva in plus sau vrea sa schimbe — deci
|
||
documentul trebuie sa poata devia de la comanda, in ambele sensuri. Sursa umple documentul, nu il
|
||
inchide. Optiunea „Cauta in lista de preturi…" ramane in meniul butonului de adaugare **pentru
|
||
toate sursele**, inclusiv pentru documentele deja emise care se modifica.
|
||
**Verificat pe cod** (`docs\cercetare\retur_si_lista_preturi.md`, B): **contractul o are deja**
|
||
(`crsarticole` e populat de `cursor_preturi` / `cursor_contract` cu lista intreaga, al doilea grid
|
||
e un adaos, nu o restrictie), **comanda nu** — `cursor_comanda` umple `crsarticole` **doar** cu
|
||
articolele comenzii (`ofacturare.prg:266-308`). Deci golul real e pe comanda, si e in **continutul
|
||
cursorului**, nu in vreun `Visible` de buton. Reteta exista deja in produs: ramura de copiere
|
||
adauga lista de preturi peste cursorul sursei cu `APPEND FROM` (`ofacturare.prg:454-473`) — se
|
||
generalizeaza ea, nu se inventeaza alta.
|
||
17. **Returul intra in formularul unificat, cu tot cu alegerea facturilor sursa.** Factura de retur
|
||
facuta din facturi anterioare e un caz de acoperit explicit — lipsea si din mockup, si din
|
||
proiectare. *Vezi sectiunea N.*
|
||
**Sunt doua mecanisme distincte, si prima cercetare l-a vazut doar pe al doilea:**
|
||
(a) **factura de retur ca document** (tipurile 8, 9, si avizul 24) — alege facturile sursa **la
|
||
nivel de document**, cu selectie multipla, si isi populeaza liniile din ele; **gestiunea si
|
||
pretul de achizitie vin neschimbate din linia originala**, verificat in `cursor_retur_document`.
|
||
**Exista deja si merge** — nu se reproiecteaza. Vezi N.1;
|
||
(b) **`But_retur`** — retur de articole intr-o factura de vanzare normala (tipurile 1, 5, 7, 10),
|
||
unde factura sursa se alege **per articol**, iar gestiunea nu se mosteneste, ci se alege. Vezi N.2.
|
||
Sunt doua fluxuri de cod independente, fara punct comun. Decizia 17 le duce pe amandoua in
|
||
formularul unificat; ce se proiecteaza nou e (b) ridicat la nivel de document, nu (a).
|
||
18. **Facturile emise din ROAAUTO intra in perimetru la modificare.** ROAAUTO le emite din formularul
|
||
lui, dar scrie tot in `VANZARI_DETALII`, si pe ele trebuie sa se poata adauga articole din lista
|
||
de preturi. **Emiterea ramane la ROAAUTO** — se unifica doar modificarea.
|
||
**Verificat pe cod** (`docs\cercetare\roaauto_facturi.md`): acelasi `PACK_FACTURARE`, acelasi drum
|
||
`VANZARI_DETALII_TEMP` -> `VANZARI_DETALII`, tip de document **`-12`**, pe care editorul lui #6 il
|
||
**vede deja**, testat pe date reale.
|
||
**Precizarea lui Marius, 09.08.2026, verificata pe cod**
|
||
(`docs\cercetare\roaauto_articole_lista_preturi.md`): in ROAAUTO **exista deja adaugarea de
|
||
articole reale**, pe langa liniile generice — mecanismul „Alte servicii” din `frm_incasare_finala`.
|
||
Deci descrierea „doar linii sintetice cu `id_articol` negativ” din primul raport e **incompleta**.
|
||
Nuanta care conteaza pentru proiectare: sursa lui e **nomenclatorul brut**, nu lista de preturi,
|
||
articolele oferite sunt **fara stoc** (`in_stoc = 0 and in_crm = 1`), iar **pretul se tasteaza
|
||
manual** — nu vine din politici. Ce se cere e ca **acelasi lucru sa fie posibil si la modificarea
|
||
documentului**, nu doar la emitere, **si nu numai pentru facturile auto, ci pentru orice tip**,
|
||
cu **ambele surse**: lista de preturi (cu pret calculat) sau nomenclatorul (cu pret tastat).
|
||
**Vezi O.**
|
||
19. **Toti parametrii lui `modifica_date_factura` trebuie sa fie modificabili din butonul de antet.**
|
||
Butonul comutator nu deschide un subset ales de noi: daca procedura Oracle stie sa scrie un camp
|
||
de antet, formularul trebuie sa aiba controlul prin care acel camp se poate schimba.
|
||
**Verificat pe cod** (`docs\cercetare\modifica_date_factura_parametri.md`): sunt 15 parametri,
|
||
din care **14 sunt campuri** — al 15-lea, `V_ID_VANZARE`, e identitatea randului si nu se
|
||
editeaza. Din cele 14:
|
||
- **13 au deja control** in `frm_modifica_factura` si se muta ca atare in antetul unificat;
|
||
- **`V_EFACTURA` nu are niciun control nicaieri** (`ofacturare_comun.vc2:4576` il forteaza `0`
|
||
la selectie multipla, altfel vine din `Scatter`) — **primeste unul**, e singurul camp nou-nout
|
||
cerut de decizia asta;
|
||
- `V_TIP_SAFT` are control, dar ascuns dupa `gl406` (`:5739-5741`) — ramane conditionat, nu se
|
||
forteaza vizibil.
|
||
Vezi I-bis pentru contractul procedurii, care impune si **cum** se cheama, nu doar ce se trimite.
|
||
20. **Din nomenclator se aleg si articole gestionabile, si negestionabile.** Filtrul `in_stoc = 0`
|
||
al lui ROAAUTO **nu se preia** — acolo e o ocolire a subiectului gestiunii, nu o regula de produs.
|
||
Consecinta acceptata: pe documentele auto vor coexista linii care descarca stoc cu linii care nu
|
||
descarca, caz care azi nu exista nicaieri. *Vezi J si O-bis, intrebarea 2.*
|
||
**Intrebarea care insotea decizia — „cu ce cont de venit intra un articol fara politica de pret”
|
||
— s-a inchis prin cercetare: nu exista cont de venit pe linie.** Vezi **J-bis**.
|
||
|
||
### Deciziile lui Marius, runda 7 (09.08.2026)
|
||
|
||
21. **Cand `NOM_ARTICOLE.CONT` e gol pe un articol negestionabil, se aplica un fallback la un cont
|
||
implicit.** Nu se accepta `NULL` (comportamentul de azi al liniilor „Alte servicii" din ROAAUTO) si
|
||
nu se refuza adaugarea articolului. Contul anume se alege la implementare.
|
||
**Atentie la perimetru:** decizia priveste **contul de gestiune** (`VANZARI_DETALII.CONT`). Cand a
|
||
fost luata nu se stia inca faptul, stabilit mai tarziu in aceeasi runda, ca pe linie exista **doua**
|
||
conturi cu surse diferite — cel de venit (`NOTE_CONTABILE.SCC`, prin politica de pret) nu e acoperit
|
||
de aceasta decizie si e inca deschis. *Vezi J-bis.*
|
||
Ipoteza de la care a pornit Marius — corespondenta 3xx -> 7xx dintr-un tabel — **nu s-a confirmat
|
||
ca tabel**, dar intentia ei da: legatura articol -> cont de venit exista, prin politica de pret si
|
||
`NOTE_CONTABILE`, configurata manual de contabil.
|
||
22. **Linia de retur fara factura originala e permisa.** Pe tipurile 8, 9, 24, „Cauta in lista de
|
||
preturi…" si „Alege din nomenclator…" se comporta ca pe orice alt document — nu apar doar pentru
|
||
corectii si nu sunt marcate special. Consecinta acceptata: gestiunea si pretul de achizitie se
|
||
aleg (nu se mostenesc), iar maximul returnabil de pe server nu se aplica acelei linii. *Vezi N.3.*
|
||
23. **Secventierea deciziei 18: `pack_auto` se cerceteaza acum**, inainte de orice estimare, nu cand ii
|
||
vine randul la livrare. *Vezi O, „Secventierea".* **Rezultat:** riscul tehnic nu exista —
|
||
`PACK_AUTO` nu citeste `VANZARI` / `VANZARI_DETALII` deloc. Decizia 18 nu mai trebuie sa fie ultima.
|
||
24. ~~**Articolul ales din nomenclator primeste `id_pol`-ul unei politici de pret implicite.**~~
|
||
**RETRASA in runda 8, inlocuita de decizia 27.** Ramane in plan doar ca sa nu fie reintrodusa:
|
||
politica implicita ar fi evitat codul nou in `pack_facturare`, dar cu pretul unei intrebari de
|
||
configurare cu contabilul si al unui cont de venit uniform pentru orice articol adaugat asa.
|
||
Marius a ales in loc corespondentele `CORESP_CONT_VENCHELT`. *Vezi decizia 27 si J-quater.*
|
||
25. **Butonul de antet deschide tot; ce nu se poate salva pe loc forteaza regenerare.** La a doua
|
||
apasare, cei **14 parametri** merg prin `modifica_date_factura`, iar orice camp schimbat din
|
||
**grupul B** (tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi)
|
||
sau **C** (incasare) **marcheaza documentul pentru regenerare**, aplicata la `Termina`. Decizia 9
|
||
ramane intacta ca intentie — butonul chiar deschide tot antetul —, dar ruta de scriere se bifurca
|
||
dupa camp, nu dupa buton. *Vezi G-bis.*
|
||
**Consecinta pe etape:** in **etapa I** regenerarea nu exista inca, deci acele campuri nu au unde
|
||
sa se salveze. **Planul le tine blocate in etapa I**, cu explicatie la hover, si le deschide odata
|
||
cu etapa II. Motivul alegerii, in lipsa unei instructiuni contrare: un camp care se deschide dar nu
|
||
se salveaza e o capcana — pierderea tacuta a unei modificari e mai rea decat un camp inca blocat.
|
||
26. **Analiticele raman read-only in #13; editarea lor e a lui #6.** Venit/cheltuiala, sectie,
|
||
responsabil si lucrare se **afiseaza** in sectiunea pliata, cu valoarea de antet, dar nu se
|
||
editeaza din formularul unificat — cine vrea sa le schimbe trece prin editarea notei contabile.
|
||
Motivul: sunt deja editabile acolo, **la nivel de linie de nota**, iar #13 le-ar scrie uniform pe
|
||
tot documentul — doua ferestre care scriu acelasi camp cu semantici diferite, cu risc ca #13 sa
|
||
suprascrie tacit o diferentiere facuta din #6. **Zero suprapunere intre fire.** *Vezi G-bis.*
|
||
Asta **nuanteaza decizia 8**: analiticele intra in sectiunea pliata ca **afisare**, nu ca editare.
|
||
|
||
### Deciziile lui Marius, runda 8 (09.08.2026)
|
||
|
||
27. **Contul de venit vine din corespondente si din nomenclator, nu dintr-o politica de pret
|
||
implicita. Decizia 24 se retrage.** Regula, pe doua ramuri:
|
||
- **articol gestionabil** (cont de gestiune de clasa 3xx): contul de venit se ia din tabelul de
|
||
corespondente `CORESP_CONT_VENCHELT` — `select id_ccv, cont, cont_chelt, cont_venit, sters,
|
||
dataoras, cont_aprovizionare, cont_diferente from coresp_cont_venchelt`, cautand pe `CONT`
|
||
(contul de gestiune al liniei) si luand `CONT_VENIT`;
|
||
- **articol negestionabil**: se foloseste `NOM_ARTICOLE.CONT` **daca e deja un cont de clasa 7xx
|
||
sau 6xx**; altfel, implicit **704**.
|
||
|
||
Motivul respingerii politicii implicite: ea muta problema in configurare (cine creeaza politica,
|
||
cu ce `SCC`, una sau mai multe) si obliga la o intrebare cu contabilul inainte de orice livrare.
|
||
Corespondentele exista deja ca date de productie si leaga contul de gestiune de cel de venit —
|
||
exact relatia cautata, doar ca sub alt nume decat s-a cautat in runda 7.
|
||
27-bis. ~~**Regula din 27 se implementeaza FARA cod nou in `pack_facturare`.**~~ **RELAXATA de decizia
|
||
34 si inchisa de decizia 35** — pachetul se modifica punctual, si e singurul cod de contare, si la
|
||
emitere si la editare. Textul de mai jos ramane doar ca istoric al rationamentului.
|
||
(Marius, runda 8, dupa
|
||
prima formulare a lui 27). Motivul: pachetul e mare si e folosit de toate produsele suitei — o
|
||
ramura noua acolo e un risc peste tot, nu doar in ROAFACTURARE.
|
||
Deci **regula de derivare a contului de venit se aplica pe partea VFP**, inainte ca articolul sa
|
||
plece spre Oracle, iar `contabilizeaza_articol` ruleaza **neschimbata**. Calea de verificat:
|
||
VFP calculeaza contul de venit dupa regula de mai sus si alege un `id_pol` a carui nota are deja
|
||
acel `SCC`, astfel incat `FACT-024` sa nu se mai poata declansa.
|
||
**Modificarea pachetului ramane planul B**, folosit doar daca se dovedeste ca nu exista nicio cale
|
||
dinspre VFP. *Vezi J-quater;* fezabilitatea: `docs\cercetare\coresp_cont_venchelt.md`, punctul 8.
|
||
|
||
**PREMISA A FOST VERIFICATA (Marius, runda 8):** „in ROAACNPRO, dar si la factura din comanda /
|
||
contract, se adauga articole fara politica de preturi — de ce nu se poate si aici?" **Raspuns:
|
||
observatia e reala, dar niciunul din cele doua exemple nu e un articol fara politica.** ROAACNPRO
|
||
nu cheama deloc `contabilizeaza_articol` (are propria contabilizare, `pack_acn.salveaza_regdoc`);
|
||
pe contract, articolele vin din `cursor_contract` / `cursor_preturi`, care le livreaza **cu `id_pol`
|
||
atasat**. `FACT-024` ramane blocantul. *Detalii, cu dovezi: J-quater, punctul 1.*
|
||
**REZULTAT: calea VFP exista si e mai buna decat modificarea pachetului** — se sprijina pe un RPC
|
||
existent (`pack_preturi.adauga_politica_pret_art`) si aduce, pe langa `SCC`, si `CU_TVA` /
|
||
`IN_VALUTA`, pe care un fallback in pachet ar fi trebuit sa le hardcodeze. *Vezi J-quater, punctul 3.*
|
||
**Planul B (modificarea `pack_facturare`) se abandoneaza.**
|
||
28. **Pe factura ROAAUTO pot exista si alte articole decat cele de pe deviz.** Nepotrivirea de afisare
|
||
dintre ecranul de deviz si factura retiparita (O, intrebarea 1) **e acceptata**: cerinta e ca
|
||
**MANOPERA si MATERIALE sa fie conform devizului**, plus orice alte articole adaugate. Nu se cere
|
||
cod nou in ROAAUTO ca sa aduca ecranul de deviz la zi. *Vezi O, intrebarea 1.*
|
||
29. **Stergerea unei linii venite din comanda ramane fara protectie.** Linia se sterge ca oricare alta;
|
||
comanda va aparea, corect, ca **facturata partial**. Nu se adauga confirmare, nu se marcheaza
|
||
„refuzat", nu se ajusteaza numararea acoperirii. *Vezi S4e.*
|
||
30. **Nu se coordoneaza cu firul #6.** #13 **incepe dupa ce #6 se termina**, deci suprapunerea pe
|
||
fisiere nu se poate produce si nu e nevoie de impartire de perimetru. Consecinta pe interdictii:
|
||
cele doua fisiere ale lui #6 raman intangibile **cat timp #6 e in lucru**, dar restrictia expira
|
||
odata cu el, nu cere negociere. Decizia 26 (analiticele read-only in #13) ramane in picioare — ea
|
||
tine de semantica, nu de coliziunea de lucru. *Vezi „Relatia cu #6".*
|
||
|
||
### Deciziile lui Marius, runda 9 (10.08.2026)
|
||
|
||
**31. Datele din Dev nu sunt baza de proiectare.** Fiecare client isi defineste propriile politici de
|
||
pret, fiecare cu nota ei contabila de vanzare salvata pe un `ID_SET`. Orice masurare pe `MARIUSM_AUTO`
|
||
vale ca **dovada ca un mecanism exista** si ca sursa de concluzii **structurale**, niciodata ca harta a
|
||
ce e configurat la client. Nicio decizie de proiectare nu se sprijina pe numarul de politici sau de note
|
||
gasite pe Dev. *(Generalizeaza regula „zero cazuri in date nu e dovada" in ambele sensuri: nici prezenta
|
||
nu e dovada.)*
|
||
|
||
**32. Intrebarea de raspuns inainte de orice implementare a contului de venit:** cum alege programul nota
|
||
contabila de vanzare la **factura pe baza de comanda**, care **nu are politica de pret**? Daca acel
|
||
mecanism se poate refolosi pentru articolul adaugat ad-hoc, **reteta in 4 pasi din J-quater se
|
||
abandoneaza** in favoarea lui. Vezi J-quater, „Intrebarea deschisa care poate anula toata reteta".
|
||
|
||
**34. `contabilizeaza_articol` primeste un parametru de cont contabil. Decizia 27-bis e RELAXATA.**
|
||
Marius, 10.08.2026, textual: *„poți să adaugi parametrul contul contabil la `contabilizeaza_articol`."*
|
||
Consecinta: **reteta in 4 pasi din J-quater se abandoneaza.** Nu mai e nevoie de politica tehnica, nici de
|
||
interogarea inversa pe `SCC`, nici de inserarea articolului in politica. VFP calculeaza contul dupa regula
|
||
deciziei 27 si **il trimite direct**.
|
||
**Ce rămâne de proiectat, si nu e „doar un parametru":** contul nu e singurul lucru care venea de pe nota.
|
||
`cursor_articol` aducea si `SCD`, `CU_TVA`, `IN_VALUTA`, `EXPLICATIE`, `ID_VENCHELT`, `ID_SECTIE`, iar bucla
|
||
care il consuma apeleaza **si** `scrie_nota` **si** `descarca_gestiune`. Pe un articol fara politica,
|
||
`FACT-024` sare inainte. Deci e nevoie de **parametru + ramura fara politica**, care sa furnizeze ce
|
||
furniza nota si sa ruleze `descarca_gestiune` **exact o data**. Obiectia rundei 8 („`CU_TVA` si `IN_VALUTA`
|
||
n-au sursa in afara lui `NOTE_CONTABILE`") **nu mai e blocanta, e proiectare** — de reevaluat daca se pot
|
||
deriva din document.
|
||
**Constrangeri de forma, ca sa nu se strice suita:** parametru nou **cu `DEFAULT NULL`**, la finalul listei,
|
||
si ramura inerta cand lipseste — apelanții existenți nu se schimba. `pack_facturare` e comun **intregii
|
||
suite**, deci cere regresie pe ROACONT / ROAGEST / ROACONTRACTE / ROAAUTO / ROAACNPRO, nu doar ROAFACTURARE.
|
||
**Ramura noua nu moșteneste bug-ul de set multi-rand** din L.0-ter.
|
||
**PROIECTATA** — `docs\cercetare\canal_cont_venit_fara_politica.md`, sectiunea „Proiectarea parametrului
|
||
de cont contabil", liniile 13-227. Verdictul, in trei randuri, pentru ca schimba forma modificarii:
|
||
`contabilizeaza_articol` primeste azi **un singur parametru**, `detalii_articol
|
||
VANZARI_DETALII_TEMP%ROWTYPE` — deci contul **nu intra literal pe ea**, ar fi cosmetic. Intra ca
|
||
**coloana noua `VANZARI_DETALII_TEMP.CONT_VENIT VARCHAR2(4) NULL`**, populata printr-un parametru nou
|
||
`V_CONT_VENIT IN VARCHAR2 DEFAULT NULL` la **coada lui `adauga_articol_factura`** (procedura chemata
|
||
direct din VFP), pe care `contabilizeaza_articol` o primeste automat: cei trei apelanti interni fac
|
||
`SELECT * BULK COLLECT` intr-un `TABLE OF ...%ROWTYPE`, deci `scrie_factura2`,
|
||
`scrie_factura_avize_retur` si `scrie_aviz_retur` **nu se ating deloc**.
|
||
> **Corectie de nume, runda 11 — mecanismul insa rezista.** Al doilea apelant e **`scrie_factura_avize`**
|
||
> (`:6708-6749`), nu `scrie_factura_avize_retur`, care nici nu cheama `contabilizeaza_articol`.
|
||
> **Verificat pe cod ca toti trei apelantii reali** — `scrie_factura2` (`:6039-6063`),
|
||
> `scrie_factura_avize` (`:6708-6749`), `scrie_aviz_retur` (`:7097-7106`) — fac intr-adevar
|
||
> `SELECT * BULK COLLECT INTO` un `TABLE OF VANZARI_DETALII_TEMP%ROWTYPE`, **fara lista explicita de
|
||
> coloane**. Deci coloana noua curge automat prin toti trei si **niciunul nu se atinge**; concluzia
|
||
> proiectarii sta, doar doua din cele trei nume erau gresite. In `scrie_factura_avize`, `tab_detalii(i)`
|
||
> e modificat inainte de apel doar pe `.cantitate` / `.id_rata` — `CONT_VENIT` ramane neatins. Efectul cerut de Marius e exact
|
||
acelasi; doar mecanica de livrare difera de formularea literala. Precedentul e in aceeasi semnatura:
|
||
`V_TAXCODE` si `V_LOT` sunt deja doi parametri adaugati ulterior, la coada, cu `DEFAULT NULL`, iar apelul
|
||
VFP e pozitional si se opreste la `V_LOT`.
|
||
Ramura noua se activeaza pe `detalii_articol.cont_venit IS NOT NULL`, **infasoara si blocul `FACT-024`**
|
||
(garda ramane litera cu litera pe ramura veche: o linie fara politica **si** fara cont trimis cade in
|
||
continuare cu `FACT-024`), n-are cursor deloc — deci `descarca_gestiune` ruleaza **exact o data prin
|
||
constructie** si bug-ul de set multi-rand nu se mosteneste, fara sa se repare ramura veche.
|
||
**Doua hardcodari raman decizii deschise pentru Marius**, nu descoperiri: `SCD = '4111'` si `CU_TVA = 1`
|
||
— vezi „Ce ramane de decis" mai jos.
|
||
|
||
**VERIFICATA ADVERSARIAL** — `docs\cercetare\parametru_cont_contabilizeaza_articol.md`. Proiectarea
|
||
rezista; patru rezultate schimba insa detalii de executie:
|
||
|
||
- **Parametrul se cableaza in DOUA locuri VFP, nu unul.** `ofacturare.vc2:14069` si `:18089` **nu** sunt
|
||
o duplicare a aceleiasi metode, cum se presupusese: sunt **doua clase distincte**,
|
||
`frm_facturare_articole.do_scrie_articole` (`:13967-14195`) si
|
||
`frm_facturare_articole2.do_scrie_articole` (`:18003-18221`), fiecare construindu-si separat apelul RPC.
|
||
- **`CU_TVA = 1` nu e inofensiv, cum spunea proiectarea.** Actualizarea lui `nproc_tva_max` /
|
||
`nid_jtva_coloana` / `nTaxCode` e chiar in interiorul lui `IF V_CU_TVA = 1` (`:12537-12558`), iar
|
||
comparatia `nproc_tva_max < V_PTVA` **se uita doar la rata, nu la suma**. O linie fallback cu TVA real
|
||
0% ar intra deci in comparatia de maxim si, daca e prima linie a documentului (`nproc_tva_max` porneste
|
||
`-1`, `:1885`), **castiga** — iar coloana si taxcode-ul ei ajung sa descrie **linia de discount a
|
||
intregii facturi** (`:6164-6184`). Combinatia e ingusta (linie scutita + discount global + acea linie e
|
||
„maximul" de pana atunci), dar efectul e real. Motivul pentru care decizia ii apartine lui Marius e
|
||
acum concret, nu formal.
|
||
- **`INSERT INTO VANZARI_DETALII ... FROM VANZARI_DETALII_TEMP` are lista de coloane explicita** — 24 de
|
||
coloane, `PACK_FACTURARE:13705-13757`, in `scrie_in_vanzari`. Deci daca se vrea `CONT_VENIT` pastrat si
|
||
dupa fapt in `VANZARI_DETALII`, **lista trebuie extinsa explicit**; altfel coloana traieste doar in
|
||
`VANZARI_DETALII_TEMP` si `ACT_TEMP`.
|
||
- **Articolul compus nu e o gaura in proiectare** — e exclus structural, nu prin presupunere. `COMPUS`,
|
||
asa cum il citeste `contabilizeaza_articol` (`:7279-7283`), e definit in `VCRM_POLITICI_PRET_ART` ca
|
||
proprietate a **perechii (articol, politica)**, identificata prin `ID_POL_ART`. O linie fara politica
|
||
n-are `ID_POL_ART`, deci intrebarea nu se poate pune.
|
||
|
||
**Golul `ntip = 4` — INCHIS in runda 11.** Cercetat (`docs\cercetare\gol_ntip4_factura_din_avize.md`) si
|
||
**verificat adversarial** (`docs\cercetare\verif_goluri_ntip_aviz.md`). Trei rezultate, dintre care doua
|
||
schimba ce trebuie scris in pachet:
|
||
|
||
- **`ntip = 4` e exclus structural — dar nu prin garda pe care o presupunea proiectarea.** Blocajul nu e
|
||
`FACT-024` din `contabilizeaza_articol`, ci **o functie mai devreme**: `adauga_articol_factura`, ramura
|
||
`WHEN ntip = 4` (`:5080-5103`), cauta randul sursa din `VANZARI_DETALII` prin `A.ID_POL = V_ID_POL`
|
||
**fara handler de exceptie**. Cu `V_ID_POL = NULL` — exact cazul liniei fara politica — comparatia nu
|
||
se poate potrivi niciodata, deci apelul cade cu `ORA-01403` **la adaugarea articolului**, in bucla
|
||
`do_scrie_articole` (`ofacturare.vc2:13967-14106`), care ruleaza intotdeauna inaintea `Do Case`-ului
|
||
(`:14282`). Linia nu ajunge niciodata la `contabilizeaza_articol`; ramura noua n-are nimic de tratat
|
||
acolo, si **nu are nevoie de garda defensiva** (ar fi redundanta peste doua straturi independente).
|
||
- **GOL REAL, mai ingust decat parea, dar efectiv atins: `SCD` pe avize.** Ramurile de aviz care chiar
|
||
ajung la `contabilizeaza_articol` — `ntip IN (28,29)` → `SCD = '461'`, restul avizelor „simple"
|
||
(`21, 22, 24, 27`) → `SCD = '418'` (`:7413-7422`) — **sunt accesibile cu `cont_venit` populat**, pentru
|
||
ca `adauga_articol_factura` nu cere `id_pol` pe niciunul din ele. Ramura noua, care ia `SCD` din
|
||
optiunea deciziei 36 (`4111`), l-ar scrie **necontitionat de `ntip`** → **cont contabil gresit pe
|
||
aviz**. Deci ramura noua **alege `SCD` dupa `ntip`**: `'461'` pentru `IN (28,29)`, `'418'` pentru
|
||
celelalte avize atinse, si abia pe restul optiunea `RF_CONT_ART_FARA_POL`.
|
||
**Verificarea a restrans lista:** `ntip IN (23,25,30,41,42,47)` **nu ajung deloc** la
|
||
`contabilizeaza_articol` — sunt deviate mai devreme, in `scrie_factura2`, spre `transfera_articol`
|
||
(`23,25,30,41`) sau direct spre `descarca_gestiune` (`42,47`). Golul nu li se aplica.
|
||
- **Al doilea gol confirmat: garda `ntip = 46`.** `nTipNotaPlata` **este** `46`, iar `scrie_nota` e
|
||
sarita azi intentionat pentru el (`IF ntip <> nTipNotaPlata`, `:7441`). Un articol fara politica poate
|
||
ajunge si pe acest tip. **Ramura noua trebuie sa reproduca garda** — altfel scrie o nota care azi e
|
||
sarita deliberat.
|
||
|
||
**CORECTIE la proiectare — al doilea apelant intern e numit gresit peste tot.** Nu
|
||
`scrie_factura_avize_retur`, ci **`scrie_factura_avize`** (`:6692-7058`) — care e chiar handler-ul Oracle
|
||
al lui `ntip = 4`, apelat din `ofacturare.vc2:14318`; apelul catre `contabilizeaza_articol` e la `:6858`,
|
||
in interiorul lui `IF articole_aviz(j).custodie = 1`. `scrie_factura_avize_retur` (`:6264-6657`) **nu
|
||
cheama deloc** `contabilizeaza_articol` — insereaza direct in `VANZARI_DETALII_TEMP` din
|
||
`VANZARI_DETALII`. Iar `scrie_aviz_retur` (`:7085-7171`) **n-are niciun apelant VFP gasit** in tot
|
||
`COMUN\` si in tot proiectul — posibil cod mort sau apelata din alt produs. Greseala e propagata in
|
||
`canal_cont_venit_fara_politica.md:67` si `nota_contabila_fara_politica.md:103`; se citeaza de acum
|
||
lista corectata de mai sus.
|
||
|
||
**Nota de metoda, valabila pentru toate rapoartele:** presupunerea ca liniile din exportul
|
||
`PACK_FACTURARE` au un **offset constant `+17`** fata de rapoartele vechi e **falsa**. Nu exista offset
|
||
universal (masurat: `+9` fata de `nota_contabila_fara_politica.md`, `0` fata de alte rapoarte). Numerele
|
||
de linie se **re-verifica direct pe fisier**, niciodata prin corectie presupusa.
|
||
|
||
**Nu se implementeaza** — decizia 30 sta, #13 incepe dupa #6.
|
||
|
||
**33. Mockup-ul nu se republica la v7.** Se duce la **v8** cu rezultatele verificarilor rundei 9 si abia
|
||
atunci se republica — o singura citire a HTML-ului, o singura republicare. Url-ul artifact rămâne la v6
|
||
pana atunci.
|
||
|
||
### Deciziile lui Marius, runda 10 (10.08.2026)
|
||
|
||
**35. Un singur cod de scriere contabila: `pack_facturare`, si la emitere si la editare.
|
||
`oscrie_in_fisiere` NU se foloseste in #13.** Marius, 10.08.2026, textual: *„nu doresc folosirea scrie in
|
||
fisiere ci doar `pack_facturare` la emitere si la editare pentru ca nu vreau sa intretin doua coduri."*
|
||
|
||
**Ce anuleaza:** impartirea propusa la finalul rundei 9 — „emiterea prin parametrul deciziei 34, editarea
|
||
prin canalul generic catre `ACT_TEMP`, care nu cere nimic in pachet" — e **respinsa**. Canalul
|
||
`actactan` / `tact` → `COMUN\programe\oscrie_in_fisiere.prg` → `pack_contafin.SCRIE_IN_ACT` exista si e
|
||
folosit azi in productie de fluxul de editare al lui #6, dar folosirea lui in #13 ar insemna **doua
|
||
implementari ale aceleiasi reguli de contare** — una in pachet, pe emitere, alta in VFP, pe editare —
|
||
tinute in pas manual la fiecare schimbare a regulii deciziei 27. Motivul e de **intretinere**, nu tehnic,
|
||
si nu se reargumenteaza cu „canalul exista deja".
|
||
|
||
**Ce impune:** editarea prin regenerare (etapa II) scrie pe **exact acelasi drum** ca emiterea —
|
||
`scrie_factura2` → `contabilizeaza_articol`, cu parametrul de cont de la decizia 34. Nu exista ramura de
|
||
scriere separata pentru documentul reemis si nu exista editare directa a randului din `ACT_TEMP` din #13.
|
||
|
||
**Ce nu atinge decizia 35:**
|
||
- **fluxul lui #6** ramane cum e (`ofacturare_comun.vc2:3796-3821` → `frm_modific2024`) — decizia priveste
|
||
#13; retragerea lui e alt subiect si alt perimetru — **inchis de decizia 38: coexista, se decide dupa
|
||
ce #13 livreaza**;
|
||
- **stergerea** documentului vechi din S9 ramane pe drumul existent (`do_sterge` → `oscrie_in_fisiere` +
|
||
`pack_contafin.finalizeaza_stergere_nota`), pentru ca acolo **nu exista al doilea cod de intretinut**:
|
||
`pack_facturare` nu are echivalent de stergere a notei, iar drumul de stergere e comun intregii suite.
|
||
*Presupunere declarata, de infirmat daca Marius vrea si stergerea mutata in pachet — ar fi alt mandat si
|
||
alta suprafata de risc.*
|
||
|
||
**Ce castiga:** regula deciziei 27 traieste intr-un singur loc, si o corectie pe ea nu trebuie facuta de
|
||
doua ori. **Ce costa:** etapa II nu mai are cale ieftina — depinde de parametrul deciziei 34 exact cat
|
||
depinde etapa I, deci **S9 nu poate porni inaintea parametrului**, iar regresia pe suita se plateste o
|
||
singura data, dar obligatoriu.
|
||
|
||
**36. Cele doua campuri ramase fara sursa pe ramura fara politica — decis.** Verificarea a stabilit intai
|
||
ca **nu exista in cod nicio sursa alternativa** pentru ele: nici optiune de firma existenta, nici cont pe
|
||
partener, nici flag de scutire pe articol sau client (`parametru_cont_contabilizeaza_articol.md`,
|
||
sectiunea 4). Deci sunt decizii de produs, si Marius le-a luat asa:
|
||
|
||
- **`SCD` — fix, dar citit din configurare, nu hardcodat.** O optiune de firma, cu **`4111` ca implicit**.
|
||
**PROIECTATA** — `docs\cercetare\optiune_firma_cont_debit.md`. **Costul e mult mai mic decat parea:
|
||
tiparul exact exista deja in productie, in acelasi pachet, pe acelasi camp.**
|
||
`pack_facturare.scrie_incasare2` (`PACK_FACTURARE:13161-13234`) isi ia `V_SCD` in **trei niveluri**:
|
||
parametru explicit daca a fost dat → **optiunea de firma** (`RF_CONT_INCASARE_BONFISCAL` s.a.m.d., cate
|
||
una per tip de incasare) → **constanta hardcodata** daca optiunea lipseste. Se copiaza identic, si se
|
||
inlocuieste punctual linia `SCD := '4111'` din proiectarea ramurii noi.
|
||
Mecanismul are 15+ ani: tabelul `OPTIUNI` (458 randuri azi), `PACK_SESIUNE.getoptiunefirma`, si un
|
||
**ecran de editare complet generic** peste tabel (`frm_optiuni` / `frm_optiuni_nou`,
|
||
`COMUN\clase\oOptiuni.vc2`) — deci **cheia noua nu cere niciun cod VFP nou**, doar randul in tabel.
|
||
Nu exista `ID_FIRMA`: fiecare firma are schema Oracle proprie, deci `OPTIUNI` din schema de conexiune
|
||
**este** deja „optiunile firmei curente".
|
||
**Dubla plasa de siguranta, si asta acopera integral cerinta lui Marius:** implicitul `4111` traieste si
|
||
in randul din `OPTIUNI` (scris de migrare, editabil fara recompilare), si hardcodat langa
|
||
`getoptiunefirma` — deci si o instalare veche fara migrare, si un rand golit din ecran cad tot pe `4111`.
|
||
`getoptiunefirma` intoarce `''` cand nu gaseste, ceea ce in Oracle e `IS NULL`, deci ambele cazuri se
|
||
trateaza cu aceeasi conditie.
|
||
**`ASCD` nu trebuie atins** — se calculeaza deja din `V_SCD`, deci primeste automat valoarea corecta
|
||
indiferent de sursa.
|
||
**`PROGRAME` se pune larg, nu doar `ROAFACTURARE`** — intrebarea a ramas deschisa in raport, dar se
|
||
inchide combinand-o cu masuratoarea de regresie: apelul catre `adauga_articol_factura` traieste in
|
||
`COMUN\clase\ofacturare.vc2`, fisier prezent si folosit in **toate cele sapte produse**, deci ramura noua
|
||
e atinsa de toata suita, exact ca `RF_CONT_INCASARE_*` (care listeaza sase produse).
|
||
- **`CU_TVA` — derivat din cota liniei**, nu fixat: `1` daca `proc_tvav > 0`, altfel `0`. Asta **elimina
|
||
prin constructie** efectul gasit la verificare: o linie scutita nu mai intra in comparatia de maxim din
|
||
`nproc_tva_max`, deci nu mai poate imprumuta coloana si taxcode-ul ei liniei de discount a intregii
|
||
facturi. Pretul e o regula in plus in pachet si un comportament **diferit de ce face azi nota** pentru o
|
||
linie scutita — diferenta e intentionata, nu accidentala, si se noteaza ca atare la testare.
|
||
|
||
Deci lista parametrilor noi ramane la **unul singur** (`V_CONT_VENIT`): `SCD` vine din configurare, iar
|
||
`CU_TVA` se deriva in pachet din date deja prezente pe rand.
|
||
|
||
**37. Cheia optiunii si validarea — decise (10.08.2026).**
|
||
- **Cheia: `RF_CONT_ART_FARA_POL`**, aliniata la familia `RF_CONT_INCASARE_*` — adica exact optiunile care
|
||
alimenteaza azi `SCD` in acelasi pachet. Cele cinci apar astfel **grupate alaturi in ecranul de
|
||
optiuni**, ceea ce le face inteligibile impreuna. Incape in `OPTIUNI.VARNAME` (`VARCHAR2(30)`).
|
||
`VARTYPE = 'CHARACTER'`, `VARVALUE = '4111'`, `PROGRAM = 'ROAFACTURARE'`, `PROGRAME` larg (vezi 36).
|
||
- **Fara validare de cont**, nici la salvare, nici la citire — se copiaza tiparul existent. Motivul:
|
||
niciuna dintre optiunile de tip cont nu e validata azi nicaieri, iar `RF_CONT_INCASARE_*` traieste asa
|
||
de 15 ani; a introduce validare aici ar fi o imbunatatire noua, nu continuarea unui tipar, si ar cere
|
||
fie cod nou in pachet, fie prima logica per-cheie din ecranul generic `COMUN\clase\oOptiuni.vc2` —
|
||
fisier al intregii suite. **Garda gratuita ramane lungimea:** un `VARVALUE` peste 4 caractere da
|
||
`ORA-12899` la `INSERT INTO ACT_TEMP`, deci esec zgomotos, nu cont tacut gresit.
|
||
*De consemnat la testare ca risc acceptat constient:* un cont inexistent in planul de conturi, scris din
|
||
greseala in ecran, ajunge pe nota neschimbat — acelasi risc pe care produsul il are deja, nu unul nou.
|
||
|
||
### Deciziile lui Marius, runda 11 (10.08.2026)
|
||
|
||
**38. Fluxul de editare al lui #6 nu se retrage odata cu #13. Coexista, si se decide mai tarziu.**
|
||
Intrebarea pusa la finalul rundei 10 — daca decizia 35 („un singur cod de scriere contabila") obliga la
|
||
rerutarea editarii lui #6 pe acelasi drum — primeste raspuns: **nu acum**. #6 ramane pe editarea directa
|
||
a randului din `ACT_TEMP` (`ofacturare_comun.vc2:3796-3821` → `frm_modific2024` → `oscrie_in_fisiere`),
|
||
#13 merge pe regenerare prin `pack_facturare`. Cele doua traiesc separat, pe povesti separate.
|
||
**Ce inseamna concret:** decizia 35 se citeste strict ca perimetru al lui #13 — nu se proiecteaza si nu
|
||
se planifica nicio retragere a fluxului lui #6 in aceasta poveste, si nu se adauga in #13 nicio piesa
|
||
care sa pregateasca acea retragere. Subiectul **nu e inchis definitiv**: se redeschide dupa ce #13
|
||
livreaza regenerarea si se vede in practica daca intretinerea celor doua drumuri doare cu adevarat.
|
||
Pana atunci nu se reargumenteaza in niciun sens.
|
||
|
||
**39. S4 ramane integrala: se desface si registrul de cantitate ramasa.** Proiectarea rundei 11 a aratat
|
||
ca `crsarticole` nu e doar sursa gridului, ci **registrul cantitatii ramase de facturat** — scris de
|
||
`do_sterge` la stergerea unei linii (`ofacturare.vc2:14640-14669`) si citit prin
|
||
`Calculate Sum(cantitate) To lnCantitateRamasa` ca sa se decida **inchiderea automata** a comenzii /
|
||
avizului (`:14303-14311`, `:14334-14338`). Varianta ieftina ar fi fost sa se restranga S4 la lista de
|
||
preturi; Marius a ales varianta intreaga: **bookkeeping-ul se decupleaza de cursorul incarcat in masa**,
|
||
ca sa poata disparea incarcarea si pe comanda si pe aviz.
|
||
**Consecinta, declarata explicit:** S4 nu mai e o poveste de performanta pe formular, ci atinge
|
||
**inchiderea automata a documentelor sursa** — cea mai mare suprafata de regresie din etapa I, si
|
||
singura care poate lasa o comanda deschisa (sau o poate inchide prematur) fara ca operatorul sa vada
|
||
ceva. Criteriul de „gata" al lui S4 include de acum, obligatoriu, **paritate pe inchiderea automata**:
|
||
acelasi document sursa, aceleasi linii facturate partial, acelasi `INCHISA` la final, pe fiecare tip cu
|
||
document sursa. Registrul nou trebuie sa fie sursa unica — nu o a doua copie tinuta in pas cu prima,
|
||
altfel povestea introduce exact tipul de dublura pe care decizia 35 il refuza in alta parte.
|
||
|
||
**40. Bug-ul de dezalocare POS se repara in S3b, in trecere.** Vezi `L.4`. Consecinta acceptata: diff-ul
|
||
lui S3b **nu mai e o mutare pur mecanica**, deci testarea lui trebuie sa acopere si dezalocarea POS pe
|
||
calea veche, nu doar paritatea de emitere.
|
||
|
||
**41. Sectiunea pliata are DOUA comutatoare, nu unul si nu cinci.** Grupul de **incasare** — singurul cu
|
||
efecte laterale reale (alocare / dezalocare de numere) si singurul blocat pe document emis prin decizia
|
||
25 — primeste comutator propriu. Delegat/transport, adresa, text aditional si analiticele stau impreuna
|
||
sub al doilea. Motivul e izolarea riscului: garda de non-alocare la toggle
|
||
(`opt_incasat.ProgrammaticChange`) se scrie si se testeaza **intr-un singur loc**, nu pe cinci stari.
|
||
|
||
**42. Validarea de curs valutar se restrange la valuta articolului cautat.** Pe varianta filtrata a
|
||
cursoarelor, `verifica_cursuri_valute` nu mai ruleaza global, ci doar pe valuta randului adus.
|
||
**Schimbare de comportament asumata:** un curs lipsa pe **alta** valuta nu mai e semnalat la deschiderea
|
||
formularului, ci abia cand se ajunge la un articol pe acea valuta. Se consemneaza la testare ca
|
||
diferenta intentionata fata de azi, nu ca regresie.
|
||
|
||
#### Puncte marunte ramase din proiectarile rundei 11 — se merge pe recomandare daca Marius nu spune altfel
|
||
|
||
Nu blocheaza nimic; se inchid la implementarea povestii respective. Enumerate ca sa nu se piarda intre runde.
|
||
|
||
| # | Punct | Poveste | Se merge pe |
|
||
|---|---|---|---|
|
||
| a | Textul exact al tooltip-urilor pentru analiticele read-only si pentru grupul de incasare blocat | S3b | formularea propusa in raport, sectiunile 2.2 si 5.3 |
|
||
| b | Eager vs. lazy pentru lookup-urile Oracle din `Init` (delegat / masina ultimei facturi, casa) | S3b, S3 | **lazy**, ca sa nu se plateasca la fiecare depliere; deschis si in `s3_portare_antet.md` §5 |
|
||
| c | `_checkbox1` vs. `chkDetaliat` — care devine campul unic de „listare detaliata" | S3b, S1 | **INCHIS (runda 12)**, pe cod: sunt **doua controale distincte** in `frm_alte_date`, nu o duplicare — nu exista nimic de ales. `docs\cercetare\s4c_discount_in_grid.md`, sectiunea 11 |
|
||
| d | Forma lui `toSursa`: obiect scatter (duck-typing) sau clasa dedicata | S3c | **duck-typing**, ca azi — o clasa noua n-ar schimba nimic functional |
|
||
| e | Conversia comenzii si a contractului: un commit sau doua | S3c | **un singur commit** — ating aceleasi trei fisiere comune, separarea nu reduce regresia, doar amana testarea pe ROACONTRACTE |
|
||
| f | `goComanda = ''` redundant la `Cw3.do_actiune` dupa conversie | S3c | **se lasa**, marcat explicit „intentionat" in diff, ca sa nu para omisiune la review |
|
||
| g | Contractul are doua meniuri (articole vs. rate): eticheta generica sau diferentiata pe `OPT_FACTURARE` | S4b | **diferentiata** — „Alege ratele de facturat…" e gresita pe contractele cu articole |
|
||
| h | „Alege facturile de returnat…" ramane doar la antet sau capata incarcare aditiva din bara | S4b | **ramane la antet** in etapa I; mutarea e o poveste separata |
|
||
| i | `But_renunt1` / `But_reset1` primesc `Caption` pentru consistenta cu bara etichetata | S4b | **da** — decizia 13 cere etichete, nu iconite mute; exceptia ar fi inconsecventa |
|
||
| j | Ordinea si formularea optiunilor din `xmenu()` per sursa | S4b | tabelul din sectiunea 3 a raportului, ca propunere |
|
||
| k | UX-ul contractului cu doua surse pe acelasi grid conceptual (`crsarticole` filtrat + `crsarticole1`) | S4 | de confirmat vizual la mockup, nu pe hartie |
|
||
|
||
### Ce s-a dovedit ca exista deja (deciziile 10, 11, 12, 14)
|
||
|
||
Verificat pe cod la 09.08.2026; rapoartele complete sunt in `docs\cercetare\`
|
||
(`proforma_copiere_puncte_intrare.md`, `discount_pe_articol.md`,
|
||
`inventar_controale_formulare.md`, `import_roris_roaacnpro.md`).
|
||
|
||
- **Proforma nu e tip de document si nu are formular propriu.** E valoarea `PROFORMA` din combo-ul
|
||
„Tip document” (`ct_clb_fdoc._combobox1`, `RowSource = "FACTURA,PROFORMA,BON FISCAL"`,
|
||
`ofacturare.vc2:8745-8754`), care seteaza `nIdTipDoc = 23` si, prin setter,
|
||
`eProforma = 1` (`ofacturare_comun.prg:593-599`, `nIdTipDocProforma = 23` la `:104`). Deci intra in
|
||
formularul unificat **fara nimic de portat**. Specific proformei si de pastrat: serie si numar
|
||
proprii, realocate la comutarea din combo (`ofacturare.vc2:9415,9427-9428`); **fara nota contabila
|
||
si fara atasamente**, prin garzile `poDate.eProforma = 0`
|
||
(`ofacturare.prg:1960,1996,2052,2063,2103`); raport propriu (`:1638-1643`, `COMUN\Rapoarte\proforma.fr2`);
|
||
relistarea pe cale separata (`ofacturare_comun.vc2:7230-7264`).
|
||
- **Copierea foloseste deja acelasi formular, cu antetul editabil.** `do_copiaza` -> `copiere_factura`
|
||
-> `factureaza(tip, toFactura)` -> `frm_date_factura` precompletat de
|
||
`completeaza_setari_document(toFactura, .T.)` (`ofacturare_comun.prg:362-412`). Numar nou se aloca
|
||
**intotdeauna**, neconditionat de copiere (`ofacturare.prg:208,211`). Nimic din traseu nu blocheaza
|
||
controale de antet.
|
||
- **Butonul de facturare din pagina de comenzi exista deja in ROAFACTURARE**: `ct_comenzi.do_factura`
|
||
(`ocomenzi.vc2:1580-1596`) face `SCATTER NAME goComanda MEMO` si cheama `facturare_comenzi` ->
|
||
`factureaza(3)`; butonul `But_factura1` (`ocomenzi.vc2:932-937`) e ascuns cand comanda e deja
|
||
facturata (`:2199-2203`), si e montat pe Page5 (`ofundal_facturare.vc2:604`, `Ferestre\fundal.sc2:206`).
|
||
- **Precompletarea contractului vine din programul de contracte** (`ROACONTRACTE`):
|
||
`ferestre_contracte.vc2:1538-1549` si `:1605` -> `facturare_contracte` -> `factureaza(2/6/52)`,
|
||
cu contractul deja completat — exact ce cere decizia 12, si **functioneaza azi**. In ROAFACTURARE
|
||
exista, in plus, calea din meniu **fara** precompletare (`ofundal_facturare.vc2:886-897`), unde
|
||
utilizatorul alege contractul in formular. Cele doua coexista; #13 nu adauga o lista de contracte
|
||
in ROAFACTURARE si **nu depinde de #10**.
|
||
- **Discountul pe articol are deja si procent, si valoare — dar intr-un dialog separat.** Vezi K.
|
||
- **Deblocarea antetului exista deja**, dar sub forma a patru bife individuale in
|
||
`frm_modifica_factura`; in formularul unificat ele sunt inlocuite de un singur buton comutator.
|
||
Vezi I.
|
||
- **Data cursului valutar nu e conditionata azi de valuta.** Vezi M.
|
||
|
||
### Canalul de precompletare e un global, nu un parametru
|
||
|
||
`factureaza(tnTip, toFactura)` (`ofacturare.prg:81-82`) nu are parametru pentru sursa: comanda si
|
||
contractul se transmit prin globalele `goComanda` / `goContract`, citite in `oDateFactura.Init`
|
||
(`ofacturare_comun.prg:301-328` comanda, `:261-297` contract). De aceea calea generica de comanda e
|
||
obligata sa scrie explicit `goComanda = ''` inainte de apel (`ofundal_facturare.vc2:899-902`), altfel
|
||
ar ramane precompletata cu ce era in sesiune. **Calea generica de contract nu face resetarea
|
||
simetrica** (`:886-897`) — de verificat daca `goContract` poate ramane populat intr-o sesiune si
|
||
precompleta tacit un document nou. Decizia 12 se implementeaza corect prin **parametru explicit**, nu
|
||
prin inca un global.
|
||
|
||
## Relatia cu #6 — transata: #13 incepe dupa #6
|
||
|
||
`plan_06_editare_factura.md` rezolva **aceeasi problema de fond** (o factura emisa nu se poate
|
||
corecta fara ca notele si rulajele sa ramana in urma) pe calea opusa: editare directa in
|
||
`frm_modific2024`, cu `id_fact` pastrat. Planul #6 a respins explicit regenerarea, cu motivul ca
|
||
*"emiterea face verificari de stoc si alte protectii dependente de tipul documentului; la
|
||
regenerare acestea ar esua pe date care intre timp s-au schimbat"*.
|
||
|
||
Argumentul acela **cade partial** daca stergerea si reemiterea se fac in aceeasi tranzactie, in
|
||
ordinea corecta — vezi sectiunea "Stocul" mai jos. Dar nu cade complet: raman verificarile care nu
|
||
tin de stoc (configurare politica / contract / cota TVA, vezi `adauga_articol_factura`).
|
||
|
||
Cele doua nu se exclud tehnic, dar **se suprapun pe aceleasi fisiere** si, mai important, produc
|
||
doua semantici diferite pentru "am corectat factura":
|
||
|
||
| | #6 — editare directa | #13 — regenerare |
|
||
|---|---|---|
|
||
| Punct de intrare | registru jurnal + formular facturi | formularul de facturi |
|
||
| Utilizator vizat | contabil | operatorul de facturare |
|
||
| `ID_FACT` | pastrat prin constructie | **pastrat, prin cerinta** (vezi E) |
|
||
| Serie, numar, data | neschimbate | neschimbate (cale proprie, vezi F) |
|
||
| `COD`, `ID_VANZARE` | `COD` nou, `ID_VANZARE` pastrat | ambele noi |
|
||
| Notele si rulajele | rescrise din formularul de note | **regenerate din articole**, ca la emitere |
|
||
| Documentul sursa (comanda/aviz/contract) | neatins | **eliberat si reconsumat** |
|
||
| Efort | mediu (in curs, S1–S3 livrate) | mare |
|
||
|
||
**Decizia lui Marius (09.08.2026): coexista, cu roluri separate.** #6 ramane calea contabilului
|
||
pentru corectii pe nota — si e singura cale posibila din registrul jurnal din ROACONT/ROAGEST, unde
|
||
nu exista contextul de facturare (`poDate`, `crsfactura`, politici, serii). #13 devine calea
|
||
operatorului de facturare: modific documentul, notele si rulajele se refac singure.
|
||
|
||
**Coliziune de lucru: nu exista. DECIS (decizia 30): #13 incepe dupa ce #6 se termina.** Sesiunea de
|
||
la #6 a atins `COMUN\clase\ofacturare_comun.vc2` (`do_editare_factura`, `:3715-3869`), a creat
|
||
`COMUN\programe\ofacturare_editare.prg` si a adus `omodificari.vcx` in proiect (`97d1613`) — dar
|
||
implementarea lui #13 nu porneste cat timp acestea sunt in lucru, deci **nu e nevoie nici de
|
||
impartire de perimetru, nici de coordonare intre fire.** Cele doua buguri semnalate (L.0 si L.0-bis)
|
||
raman semnalate catre #6, nu reparate din #13.
|
||
Ce **nu** decade odata cu coordonarea: **decizia 26** — analiticele raman read-only in #13. Motivul ei
|
||
e semantic (#6 le editeaza la nivel de linie de nota, #13 le-ar scrie uniform pe tot documentul), nu
|
||
o problema de calendar.
|
||
|
||
---
|
||
|
||
## Ce s-a stabilit din cod
|
||
|
||
### A. Formularul unificat exista deja ca prototip, oprit din 2017
|
||
|
||
`frm_facturare_articole2` (`COMUN\clase\ofacturare.vc2:15741-19355`) **este** formularul cerut la
|
||
punctul 13, la nivel de controale:
|
||
|
||
- are deja campurile de antet mutate din `frm_date_factura`: `Clb_serie_act1`, `Clb_nract`,
|
||
`Clb_dataact`, `Clb_zi_curs`, `Clb_data_scadenta`, `Ct_clb_nume_client`, `Ct_clb_responsabil`,
|
||
`Ct_clb_sectie`, `Ct_clb_lucrare`, `Ct_clb_venchelt`, `Ct_clb_altele`, `Ct_clb_valuta`,
|
||
`clb_fdoc`, `Ed_tx_simplu1` (`:15744-15812`);
|
||
- **nu** are `grd_articole`, `grd_contracte`, `cb_politici_preturi`, `cb_contracte`, casetele de
|
||
cautare `txtCodmat` / `txtArticole` — adica exact partea care azi consuma incarcarea in masa;
|
||
- are grid editabil in linie, cu combouri `combosql` din `cautare.vcx` pe `cCodMat.cboCodmat`,
|
||
`cDenumire.cCboDenumire`, `cGestiune.cCboGestiune` (`:16751-16881`), plus `But_nou1`;
|
||
- e lansat de `factureaza2` (`COMUN\programe\ofacturare.prg:590-1080`), care se cheama numai daca
|
||
`gnFacturareNou = 1` **si** utilizatorul raspunde DA la un `AMESSAGEBOX` (`:87-92`).
|
||
|
||
**Cat de mort e prototipul.** In `factureaza2`, deschiderea formularului de date si incarcarea
|
||
articolelor sunt inchise cu `If .F.`: `:707-711` (formularul de date), `:826-829` (executia
|
||
cursorului de articole), `:838` (verificarea de "nu exista articole"), `:985-1008` (`crspolitici`
|
||
si `crscontracte`). `Init`-ul lui `frm_facturare_articole2` are 92 de linii (`:18988-19080`) fata
|
||
de 368 la `frm_facturare_articole` (`:14976-15344`) si **nu completeaza niciun camp de antet** —
|
||
controalele sunt acolo, logica nu.
|
||
|
||
**Drift-ul dintre `factureaza` si `factureaza2`** (fork din 08.06.2017, nesincronizat): lipsesc din
|
||
`factureaza2` tipurile 51 si 52, ramura `llCopiere` / `toFactura`, completarea `codmatc` /
|
||
`codnc8` / `codcpv`, `GetInstitutiePublica`, `GetSoldClient`, filtrul `RORTC` pe `jtva_coloane`,
|
||
tratarea `eProforma`, `verifica_numar(16, ...)` pentru chitanta, `cursor_retur_document`,
|
||
`cursor_avize` cu tip 23. **Concluzie: nu se continua cu doua proceduri.** Se merge pe una singura,
|
||
cu un parametru de mod, altfel divergenta se reia imediat (exact tiparul care a produs problema
|
||
reparata la #8).
|
||
|
||
### B. Nu doua formulare, ci patru
|
||
|
||
Fluxul de azi are **patru** ferestre. Runda 2 numarase trei; a patra, `frm_articol_factura`
|
||
(`ofacturare.vc2:1108-2659`), se deschide **pentru fiecare articol adaugat**, din
|
||
`do_adauga_articol` (`:12873`, `ofrmadarticol.Show(1)`, doar daca `!tlImplicit`) — si e locul in care
|
||
se introduce azi discountul pe linie (vezi K). Formularul unificat o desfiinteaza, deci campurile ei
|
||
trebuie sa aiba unde sa se mute.
|
||
|
||
Celelalte trei:
|
||
|
||
1. `frm_date_factura` (`ofacturare.vc2:8482-9869`) sau `frm_date_aviz` (`:6566-7618`) —
|
||
17, respectiv 13 metode `do_cauta_*`, plus `do_schimba_tipdoc`, `inainte_de_do_termin` si un
|
||
`Init` de 234 / 247 de linii;
|
||
2. `frm_facturare_articole` (`:10968-15739`) — compunerea;
|
||
3. `frm_alte_date` (`COMUN\clase\ferestre_cere_date.vc2:2219-3353`) — **aratat dupa** confirmarea
|
||
articolelor, din `inainte_de_do_termin` (`ofacturare.vc2:14921-14941`): delegat, auto, agent,
|
||
adresa de facturare, incasare (numerar / chitanta / bon fiscal / POS), text aditional. Aloca si
|
||
numere proprii (bon fiscal, POS, chitanta).
|
||
|
||
Punctul 13 vorbeste doar despre primele doua. **Decizia 7 le aduce pe toate trei**: `frm_alte_date`
|
||
intra in formular, ca zona pliata. Recomandarea din runda 2 („ramane dialog in prima etapa”) e
|
||
respinsa.
|
||
|
||
Ce inseamna concret, din inventarul de controale: se muta patru grupuri — delegat si transport
|
||
(`Ct_clb_delegat`, `Ct_clb_masina`, `Ct_clb_agent`, `Clb_dataora_exp`), incasare (radiogrupul
|
||
`opt_incasat` cu patru optiuni, `Cb_casa`, `Clb_serie_chit`, `Clb_nrchit`, `Clb_incasat`,
|
||
`cmdModificaBon`, `chkPOS`, `chkDetaliat`, `cboTipFactura`), adresa de facturare
|
||
(`clb_adresa_facturare`) si textul aditional (`Ed_tx_simplu1`) —
|
||
`ferestre_cere_date.vc2:2343-2638`. **Masina de stari se muta ca atare, nu se rescrie**:
|
||
`actualizeaza_tipincasare` (`:2698-2856`) comuta vizibilitatea pe cele patru valori si aloca sau
|
||
dezaloca numarul de chitanta (`:2783`), de bon fiscal (`:2807`) sau de POS (`:2844`). Riscul semnalat
|
||
in runda 2 nu dispare, dar e localizat: **alocarea de numere trebuie sa ramana legata de aceleasi
|
||
evenimente**, nu de deschiderea formularului.
|
||
|
||
Peste ele coboara analiticele din antet (decizia 8): `Ct_clb_venchelt`, `Ct_clb_sectie`,
|
||
`Ct_clb_responsabil`, `Ct_clb_lucrare`.
|
||
|
||
### C. Incarcarea articolelor — de ce dureaza si ce inlocuieste
|
||
|
||
`factureaza` executa, inainte de a deschide compunerea, **un singur apel** care aduce toate
|
||
articolele disponibile: `pack_facturare.cursor_preturi` (`ofacturare.prg:281-286`, corp la
|
||
`PACK_FACTURARE:2121+`), respectiv `cursor_contract` / `cursor_comanda` / `cursor_avize` /
|
||
`cursor_gestiune` / `cursor_retur` dupa tip (`ofacturare.prg:265-311`). Rezultatul intra in
|
||
`crsarticole` si tine gridul de sus.
|
||
|
||
`cursor_preturi` **nu are filtru pe articol** — semnatura e
|
||
`(V_DATA_CURS, V_TIP, V_ID_VALUTA, V_ID_GESTIUNE_INIT, V_LUNA, V_AN, V_ID_UTIL, V_ID_SUCURSALA)`
|
||
(`PACK_FACTURARE:335-343`). De aici vin miile de randuri.
|
||
|
||
Mecanismul de inlocuire **exista deja**, in prototip: `combosql` cauta pe server, incremental, cu
|
||
`csourcesql = select codmat, denumire, um, grupa, subgrupa, codbare, id_articol from vnom_articole`
|
||
si `csourcewhere = inactiv = 0` (`ofacturare.vc2:16751-16766`).
|
||
|
||
**Dar `vnom_articole` e nomenclatorul, nu lista de preturi.** Nu are pret, nota contabila, cota TVA,
|
||
valuta, `id_pol`, `gestionabil`, `pret_cu_tva` — toate vin azi din `cursor_preturi`. Deci partea
|
||
Oracle a lucrarii e o **varianta filtrata pe articol** a cursoarelor de facturare, apelata la
|
||
alegerea liniei, nu la deschiderea formularului. Nu e o simplificare: ramurile pe tip din
|
||
`cursor_preturi` (restaurant, custodie, retur, contract, comanda) trebuie pastrate identic, altfel
|
||
pretul difera intre cele doua cai.
|
||
|
||
**Legatura cu #12.** Daca articolul poate purta el insusi pretul si nota contabila (varianta C din
|
||
`plan_12`), cautarea in linie devine directa si nu mai are nevoie de o rezolvare separata a listei
|
||
de preturi. #13 nu depinde de #12, dar cine face #12 dupa #13 va rescrie exact bucata asta.
|
||
|
||
### D. Regenerarea — piesele exista, montajul nu
|
||
|
||
**1. Stergerea elibereaza deja documentul sursa.** `pack_facturare.sterge_factura`
|
||
(`PACK_FACTURARE:5415-5591`) face, pe langa `sters = 1` pe `VANZARI` si `VANZARI_DETALII`:
|
||
|
||
- `FACTURAT = 0, ID_UTILFACT = NULL, DATA_FACTURAT = NULL` pe avizele facturate (tip 4 si 24);
|
||
- `STERS = 1` pe `VANZARI_CANTITATI` (cantitatile consumate de pe avize);
|
||
- `STERS = 1` pe `COMENZI_ELEMENTE` cu `CANTITATE < 0` (consumul din comanda);
|
||
- `STERS = 1` pe `VANZARI_CORESP` si pe `CTR_RATE_FACTURI` (contracte in rate, tip 2/6/52).
|
||
|
||
Adica **exact reversul consumului sursei** — conditia ca reemiterea sa poata reconsuma aceeasi
|
||
comanda / acelasi aviz / aceeasi rata. Sunt si garzi: refuza stergerea daca s-au emis facturi sau
|
||
avize de retur peste document (`:5432-5477`).
|
||
|
||
**2. Calea VFP de stergere completa exista.** `frm_facturi.do_sterge`
|
||
(`COMUN\clase\ofacturare_comun.vc2:4658-4874`): tranzactie manuala, `oscrie_in_fisiere`, apoi
|
||
`pack_contafin.finalizeaza_stergere_nota` (care cheama `sterge_din_vanzari`). Rulajele si notele
|
||
dispar pe aceasta cale, nu prin `sterge_factura`.
|
||
|
||
**3. Reconstituirea liniilor exista.** `pack_facturare.cursor_retur_document(..., V_COPIERE = 1, ...)`
|
||
(`PACK_FACTURARE:3932-4045`) reface liniile din `VANZARI_DETALII`, cu `explicatie`, `id_gestiune`,
|
||
`pret_achizitie`, `pretd`, `id_jtva_coloana`, `id_jtva_coloana_ex`, `lot`, `serie`, `id_pol`,
|
||
`pret_cu_tva`, plus `curs` / `multiplicator` din `VANZARI_CURSURI`. E deja folosita, exact asa, la
|
||
copierea unei facturi.
|
||
|
||
**4. "Redeschide formularul precompletat" exista.** `frm_facturi.do_copiaza`
|
||
(`ofacturare_comun.vc2:3640-3713`) -> `copiere_factura` (`oproceduri_facturare.prg:150-153`) ->
|
||
`factureaza(tip, toFactura)`, iar in `factureaza` ramura `llCopiere` (`ofacturare.prg:255-257`,
|
||
`:458-473`) incarca liniile documentului si adauga peste ele lista de preturi, ca sa se poata
|
||
adauga articole noi. `oDateFactura.completeaza_setari_document(toFactura, .T.)`
|
||
(`COMUN\programe\ofacturare_comun.prg:362-412`) precompleteaza antetul.
|
||
|
||
**Ce nu se poate refolosi ca atare:** `do_copiaza` **degradeaza intentionat tipul** — factura din
|
||
contract / comanda / aviz devine `tip = 1`, avizele devin `22`, transferurile `10`
|
||
(`ofacturare_comun.vc2:3696-3710`), cu comentariul *"nu are sens sa fie copiata, dar o tratez ca pe
|
||
o factura din lista de preturi"*. La regenerare, degradarea e **exact ce nu trebuie sa se intample**:
|
||
documentul nou trebuie sa ramana pe acelasi tip, ca sa reconsume sursa. Deci se cloneaza structura
|
||
lui `do_copiaza`, nu comportamentul.
|
||
|
||
### E. `ID_FACT` — cerinta si ce presupune ea
|
||
|
||
**Cerinta (decizia 2):** documentul reemis pastreaza `ID_FACT`.
|
||
|
||
**Starea de azi, verificata:** `ID_FACT` se genereaza cu secventa, neconditionat.
|
||
`PACK_CONTAFIN.SET_IDFACT(V_GCS)` e `SELECT SEQ_IdFact.NEXTVAL`
|
||
(`COMUN\docs\PACK_CONTAFIN.pck:3037-3040`), citit cu `get_idFact()` (`:725`), iar `DOCUMENTE`
|
||
primeste rand nou cu acel `ID_DOC` (`:796-808`).
|
||
|
||
**Dar intuitia „id_fact depinde de numar si data" e corecta istoric:** exista in pachet varianta
|
||
`SET_IDFACT(tdDataAct, tcSerie_Act, tnNrAct, tnId_Ctr)` care cauta intai in `DOCUMENTE` dupa
|
||
`NRACT` + `SERIE_ACT` + `DATAACT` + `ID_CTR` si ia secventa doar la `NO_DATA_FOUND`
|
||
(`:3016-3035`) — **comentata**, deci inactiva.
|
||
|
||
**Ce inseamna pentru #13** (de proiectat in S9, dupa verificarea din handoff):
|
||
|
||
- fie se reactiveaza cautarea, sub un comutator folosit **numai** de regenerare — modificarea lui
|
||
`SET_IDFACT` fara comutator ar schimba comportamentul pentru toata suita, ceea ce nu se face;
|
||
- fie se transmite `ID_FACT`-ul cunoscut, ca parametru, pe drumul de scriere;
|
||
- **capcana de ordine**: cautarea filtreaza `STERS = 0`. Daca documentul vechi e marcat sters
|
||
inainte, cautarea nu-l mai gaseste si se genereaza id nou. Deci `ID_FACT`-ul se citeste **inainte**
|
||
de stergere, in aceeasi tranzactie.
|
||
|
||
Cu `ID_FACT` pastrat, ce ramane de inventariat e mult mai putin decat in varianta cu id nou:
|
||
`ATASAMENTE_VANZARI` si `marcheaza_facturat` merg pe `ID_VANZARE` (care **se schimba**),
|
||
`ANAF_EFACTURA` e gol prin garda, iar `DOCUMENTE` / `ACT` / `RUL` / `JV2007` / `IREG_PARTENERI` merg
|
||
pe `ID_FACT` (pastrat). **`ID_VANZARE` nou ramane singura discontinuitate reala** — de verificat
|
||
daca `DOCUMENTE` primeste un al doilea rand pe acelasi `ID_DOC` sau il refoloseste.
|
||
|
||
### F. Serie, numar, data — cale proprie, nu regenerare
|
||
|
||
**Cerinta (deciziile 3 si 4):** toate datele se pastreaza, inclusiv numarul; iar antetul care intra
|
||
in identitatea documentului se modifica pe cale proprie.
|
||
|
||
Calea exista deja si e exact ce trebuie: `pack_facturare.modifica_date_factura`
|
||
(`PACK_FACTURARE:14392-14463`) face `UPDATE` in loc si **propaga serie / numar / data / scadenta
|
||
pe `VANZARI`, `DOCUMENTE`, `ACT`, `IREG_PARTENERI`, `JV2007`, `RUL`, dupa `ID_FACT`**
|
||
(`:14427-14460`). Tot ea scrie delegat, agent, masina, adresa de facturare, text aditional,
|
||
`dataora_exp`, `listare_detaliata`, `tip_saft`, `efactura`. E procedura din spatele actiunii de azi
|
||
`frm_facturi.do_modifica` -> `frm_modifica_factura`.
|
||
|
||
**Deci in formularul unificat:** campurile de antet se scriu prin `modifica_date_factura`, nu prin
|
||
regenerare. Regenerarea porneste doar pentru ce atinge sumele. Vezi tabelul din G-bis.
|
||
|
||
`oGeneratorNumere` (`COMUN\programe\oserii_numere.prg:227-233`) nu incurca: la modificare nu se
|
||
aloca numar nou, deci nu e nimic de dezalocat. Intrebarea despre o eventuala constrangere de
|
||
unicitate pe `VANZARI(SERIE_ACT, NUMAR_ACT)` **dispare** — nu mai exista doua documente nesterse cu
|
||
acelasi numar, pentru ca numarul nu se realoca; ramane doar cazul „vechi sters + nou nesters", care
|
||
e exact situatia de azi de la orice stergere si reintroducere.
|
||
|
||
### G-bis. Cele trei modificari de azi, si ce se scrie la confirmare
|
||
|
||
Pe `frm_facturi` exista azi trei actiuni care ating acelasi document, fiecare cu fereastra ei:
|
||
|
||
| Actiune de azi | Formular | Ce atinge | Sursa |
|
||
|---|---|---|---|
|
||
| `do_modifica` | `frm_modifica_factura` | antet: ruta, delegat, agent, serie, numar, date | `ofacturare_comun.vc2:4538-4637` |
|
||
| `do_modifica_explicatie` | `frm_modifica_articol_factura` | `explicatie` + `taxcode` pe o linie | `:4639-4656` |
|
||
| `do_editare_factura` (#6) | `frm_modific2024` | nota contabila si rulajele | `:3715-3869` |
|
||
| — | — | **cantitati, preturi, linii: nicaieri** | — |
|
||
|
||
Decizia 6 le comaseaza in formularul unificat. Ruta de scriere se alege dupa ce s-a schimbat:
|
||
|
||
| Ce s-a schimbat | Cum se scrie | Efect |
|
||
|---|---|---|
|
||
| Serie, numar, data, scadenta, delegat, auto, agent, adresa facturare, text aditional | pe loc, `modifica_date_factura` | propaga dupa `ID_FACT` |
|
||
| Explicatia si `taxcode` pe o linie | pe loc, `modifica_explicatie_articol` (`PACK_FACTURARE:14464-14472`) | doua coloane, nicio suma |
|
||
| Cantitati, preturi, linii adaugate/sterse, discount, gestiune, cota TVA | **regenerare** | vechiul `sters = 1`, documentul nou scris pe drumul de emitere, note si rulaje refacute |
|
||
| Nimic | nimic | documentul nu se rescrie degeaba |
|
||
|
||
Ultima linie nu e cosmetica: fara ea, orice deschidere a formularului ar produce un document nou si
|
||
ar umple `VANZARI` cu randuri sterse.
|
||
|
||
**Gol descoperit la S1 (runda 7): tabelul de mai sus nu acopera tot antetul.** Inventarul camp-cu-camp
|
||
(`docs\S1_inventar_campuri_formular_unificat.md`) a gasit trei grupuri de campuri de antet care **nu
|
||
sunt printre cei 14 parametri** ai lui `modifica_date_factura` si pentru care nu s-a gasit alta ruta:
|
||
|
||
- **analiticele** — venit/cheltuiala, sectie, responsabil, lucrare (grupul „Pliat — analitice” din I);
|
||
- **identitate/sursa, altele decat serie/numar/data/scadenta** — tip document, valuta, zi curs, client,
|
||
sursa/„altele”, gestiune sursa, politica de preturi;
|
||
- **grupul de incasare** — mod incasare, casa, serie si numar de chitanta/bon, suma incasata, POS.
|
||
|
||
**Verificat (runda 7): `docs\cercetare\rute_scriere_antet.md`.** Cautare exhaustiva in ambele straturi
|
||
— Oracle (pachetul de facturare curent, plus `PACK_CONTAFIN`, `PACK_UPDATE`, `PACK_MIGRARE`; toate
|
||
cele 13 aparitii de `UPDATE VANZARI` inspectate individual) si VFP (indexul complet: 316 fisiere,
|
||
1128 clase, 9281 metode). Rezultatul e neuniform pe cele trei grupuri:
|
||
|
||
| Grup | Verdict | Ce inseamna |
|
||
|---|---|---|
|
||
| **B** — tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi | **NU**, toate sapte | Controalele traiesc **exclusiv** in wizardul de emitere; nu exista niciun `UPDATE` care sa le atinga dupa emitere. Un „nu" verificabil, nu o absenta de cautare. |
|
||
| **C** — mod incasare, casa, serie/nr chitanta, suma, POS | **NU direct** | Nu exista coloane proprii pe `VANZARI`: incasarea devine ea insasi **o linie de nota contabila** (`scrie_incasare2`). Nicio procedura de tip „modifica incasare". |
|
||
| **A** — sectie, responsabil, lucrare | **DA** | Dar nu prin `modifica_date_factura`, ci prin **mecanismul lui #6**, aterizat chiar pe branch-ul asta (`97d1613`). Vezi mai jos. |
|
||
| **A** — venit/cheltuiala (`ID_VENCHELT`) | **neconfirmat** | Gridul afiseaza coloana `dst_chlt`, dar `do_modifica` nu are caz pentru ea. |
|
||
|
||
**Descoperirea care conteaza: analiticele sunt deja editabile, dar din #6.** `frm_facturi.do_editare_factura`
|
||
(`ofacturare_comun.vc2:3690-3869`) e acum cablat la `frm_modific2024` (`omodificari.vc2`), incarca
|
||
nota contabila a documentului emis si o rescrie prin `OSCRIE_IN_FISIERE` ->
|
||
`pack_contafin.finalizeaza_modificare_nota`, care **resincronizeaza `VANZARI`**. `do_modifica`
|
||
(`omodificari.vc2:13934-13943`) trateaza explicit `id_lucrare` si `id_responsabil`.
|
||
|
||
**Doua nuante care schimba proiectarea, nu doar inventarul:**
|
||
1. **Editarea e la nivel de LINIE de nota, nu de antet.** La emitere, cele patru analitice se scriu
|
||
uniform pe tot documentul, din variabilele de sesiune. Prin editorul lui #6, fiecare linie se poate
|
||
edita separat — deci un document poate ajunge cu **sectii diferite pe linii diferite**, stare
|
||
imposibila la emitere. Conteaza pentru orice raportare care presupune „un singur `ID_SECTIE` per
|
||
factura".
|
||
2. **Bug suspectat pe `sectie`** (`omodificari.vc2:13941`): `replace ... id_valuta with
|
||
loCauta.id_sectie` — pare sa scrie in `id_valuta` in loc de `id_sectie`. Daca e real, textul afisat
|
||
se schimba dar coloana nu. **E in perimetrul lui #6** — se semnaleaza, nu se repara aici. Pana la
|
||
verificare, „DA" pentru `ID_SECTIE` e un da cu rezerva.
|
||
|
||
**Consecinta pentru decizia 9**, acum pe fapte: `but_modifica` **poate salva pe loc doar cei 14
|
||
parametri**. Pentru grupurile B si C nu exista alta cale decat **regenerarea**, care le rescrie oricum
|
||
pe toate, fiind chiar drumul de emitere. Pentru grupul A exista o a treia cale, dar e a lui #6 si
|
||
lucreaza pe alt nivel (linie de nota).
|
||
|
||
**Tabelul de rutare, completat (deciziile 25 si 26):**
|
||
|
||
| Ce s-a schimbat | Cum se scrie |
|
||
|---|---|
|
||
| cei **14 parametri** (serie, numar, data, scadenta, ruta, delegat, masina, agent, `dataora_exp`, adresa facturare, text aditional, `listare_detaliata`, `tip_saft`, `efactura`) | **pe loc**, `modifica_date_factura` |
|
||
| explicatia si `taxcode` pe o linie | **pe loc**, `modifica_explicatie_articol` |
|
||
| cantitati, preturi, linii, discount, gestiune, cota TVA | **regenerare** |
|
||
| **grupul B** — tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi | **regenerare** (decizia 25); blocate in etapa I |
|
||
| **grupul C** — incasare | **regenerare** (decizia 25); blocate in etapa I |
|
||
| **grupul A** — venit/cheltuiala, sectie, responsabil, lucrare | **niciuna din #13** — read-only, editarea e a lui #6 (decizia 26) |
|
||
| nimic | nimic |
|
||
|
||
### G. Stocul — de ce argumentul lui #6 nu inchide subiectul
|
||
|
||
Verificarea de stoc **nu** e in `adauga_articol_factura`: acolo erorile sunt de configurare
|
||
("Nu a fost gasita cota de TVA", politica / contract lipsa — `PACK_FACTURARE:5125-5180`).
|
||
Descarcarea efectiva de gestiune se face la emitere, in `contabilizeaza_articol` ->
|
||
`descarca_gestiune` (`:7631+`). Plafonul pe cantitate pe care il vede utilizatorul azi vine din
|
||
**cursorul client** `crsarticole` (`frm_facturare_articole.do_adauga_articol`,
|
||
`ofacturare.vc2:12813-13086`) — cursor care in formularul unificat **nu mai exista**, pentru ca nu
|
||
se mai incarca in masa.
|
||
|
||
Deci, pe #13:
|
||
|
||
- in timpul compunerii **nu exista plafon** — coincide cu decizia deja luata de Marius pe #6 la
|
||
08.08.2026 ("editarea unei facturi emise nu are plafon si nu verifica stocul");
|
||
- la finalizare, daca **stergerea ruleaza inaintea reemiterii, in aceeasi tranzactie**, stocul
|
||
consumat de documentul initial e deja eliberat cand se descarca gestiunea pentru documentul nou.
|
||
|
||
**Aici e riscul tehnic principal.** Azi stergerea si emiterea deschid fiecare propria tranzactie
|
||
(`do_deschide_tranzactie` / `do_inchide_tranzactie` in ambele cai). O tranzactie nu poate fi tinuta
|
||
deschisa peste minutele in care utilizatorul editeaza formularul. Ordinea corecta e deci:
|
||
**citire (fara tranzactie) -> editare -> o singura tranzactie la confirmare, care contine intai
|
||
stergerea, apoi scrierea.** Asta cere mutarea apelului de stergere in interiorul tranzactiei
|
||
deschise de `do_scrie_articole`, nu inaintea ei.
|
||
|
||
Atentie si la `VANZARI_DETALII_TEMP`, care e GTT `ON COMMIT DELETE ROWS`: umplerea si consumul
|
||
trebuie sa ramana in aceeasi tranzactie — ceea ce e compatibil cu schema de mai sus, dar interzice
|
||
un `commit` intermediar dupa stergere.
|
||
|
||
### H. Pretul rescris de server la reemitere
|
||
|
||
`adauga_articol_factura` (`PACK_FACTURARE:4972-5268`) ramifica pe `V_OPT_FACTURARE` si, pe unele
|
||
ramuri, **re-deriva pretul, cota TVA si valuta din documentul sursa** (ex. `V_OPT_FACTURARE = 3`,
|
||
preturile de pe contract, `:5129-5168`), in timp ce pe ramura implicita valoarea venita din VFP
|
||
castiga (`V_PRET := V_PRET_TEMP`, `:5183-5186`). Planul #6 semnalase deja acelasi lucru.
|
||
|
||
**Consecinta pentru #13:** pe facturile din contract (si posibil pe alte ramuri), pretul editat de
|
||
utilizator poate fi suprascris tacut la reemitere. De inventariat ramura cu ramura, si de decis daca
|
||
regenerarea trece un flag "preturile vin din formular, nu se re-deriva". **Nu se porneste
|
||
implementarea inainte de acest inventar** — e singurul punct din care poate iesi o factura reemisa
|
||
cu alte sume decat cele confirmate pe ecran.
|
||
|
||
### I. Asezarea antetului (deciziile 8 si 9)
|
||
|
||
**Doua grupuri vizibile, restul pliat.** Grupurile si etichetele reale, din inventar:
|
||
|
||
| Grup | Controale | Note |
|
||
|---|---|---|
|
||
| Identitatea documentului | `Ct_clb_fdoc` („Tip document”: FACTURA / PROFORMA / BON FISCAL), `Clb_serie_act`, `Clb_nract`, `Clb_dataact`, `Clb_data_scadenta`, `Clb_zi_curs`, `Ct_clb_valuta` | scadenta e **dezactivata**, nu eliminata, cand `gnScadentaAutomata = 1` (`ofacturare.vc2:9713-9715`); ziua de curs se elimina pe retur (`:9717-9722`, tipurile 8 si 9 — nu si 24); valuta se elimina cand `in_valuta = 0` (`:9725-9728`) |
|
||
| Partener si sursa | `Ct_clb_nume_client`, `txtCodFiscal` + `But_verifica1` (ANAF), `txtSoldLei`, `Ct_clb_altele` (sursa), `Ct_clb_gestiune_init`, pe aviz `Ct_clb_politici_preturi` | codul fiscal si soldul sunt read-only si derivate |
|
||
| **Pliat** — analitice | `Ct_clb_venchelt`, `Ct_clb_sectie`, `Ct_clb_responsabil`, `Ct_clb_lucrare` | responsabilul si gestiunea sursa se elimina azi cand `gnScadereStoc = 0` sau tipul e 4/7/8/9/48/49 (`ofacturare.vc2:9646-9707`) |
|
||
| **Pliat** — alte date | cele patru grupuri din `frm_alte_date`, vezi B | |
|
||
|
||
**Butonul de modificare a antetului (decizia 9).** Mecanismul **exista deja**, si e mai fin decat
|
||
credeam: `frm_modifica_factura` (`ofacturare_comun.vc2:5262-5774`) are **patru bife individuale** —
|
||
`chkSerieAct`, `chkNrAct`, `chkDataAct`, `chkDataScad` — fiecare deblocand exact textbox-ul ei
|
||
(`thisform.txtDataAct.Enabled = this.Value`, `:5758-5772`), si toate patru sunt ele insele inactive
|
||
daca documentul nu are numar (`this.chkSerieAct.Enabled = !EMPTY(NVL(poRec.numar_act,0))`,
|
||
`:5736-5750`). **Restul campurilor de antet nu sunt blocate deloc** — delegat, agent, masina, ruta,
|
||
adresa, dataora expediere, text aditional sunt mereu editabile.
|
||
|
||
In formularul unificat (**decizia 9, forma finala — un singur buton comutator, fara nicio bifa**):
|
||
|
||
- in bara panoului de antet sta **un singur `but_modifica`**; apasat, deblocheaza **tot antetul** —
|
||
si campurile „moi”, si cele patru de identitate — si **isi schimba imaginea in discheta lui
|
||
`but_salvare`**; documentul deschis pentru consultare ramane inert;
|
||
- **cele patru bife individuale dispar.** Nu se transpun in formularul unificat sub nicio forma:
|
||
butonul e singurul control de protectie a antetului;
|
||
- **si conditia lor se abandoneaza.** Azi bifele de serie si numar sunt ele insele inactive dupa
|
||
`!EMPTY(NVL(poRec.numar_act,0))` (`:5736-5750`); regula asta nu se mai transpune pe campuri.
|
||
Cu antetul deschis, **toate campurile de antet sunt editabile, fara exceptie si fara conditie de
|
||
stare**. E o pierdere deliberata de protectie, in schimbul unei singure reguli inteligibile:
|
||
antet blocat sau antet deschis, atat;
|
||
- a doua apasare **salveaza doar antetul**. E posibil pentru ca
|
||
`do_modifica` cheama azi **exclusiv** `pack_facturare.modifica_date_factura`, cu 15 parametri toti
|
||
de antet, si niciun apel spre articole, note sau `oscrie_in_fisiere` (`ofacturare_comun.vc2:4587-4630`).
|
||
Acopera cazul „vreau sa corectez doar delegatul”.
|
||
**Precizare, ca sa nu se citeasca gresit:** „nu atinge notele si rulajele” e adevarat **la nivel de
|
||
apel VFP**, nu si in Oracle. Corpul procedurii propaga seria, numarul si datele in `JV2007` si `RUL`
|
||
(`PACK_FACTURARE.pck:14428-14459`) — coloane de **identitate**, nu sume: nicio valoare nu se
|
||
recalculeaza. Pentru celelalte zece campuri, scrierea e strict in `VANZARI`. Vezi I-bis.
|
||
- **`Termina` ramane salvarea intregului document**, cu rutarea din G-bis.
|
||
|
||
**Ce nu exista si trebuie scris:** containerele efectiv folosite in antet nu au un mecanism gata
|
||
facut de blocare. `ct_clb_cautare` are `do_activeaza` / `do_dezactiveaza` (`caut_ora.vc2:780-806`),
|
||
dar acestea doar ascund iconita de cautare, iar in `ofacturare_comun.vc2` nu sunt apelate nicaieri;
|
||
`clb_tx_simplu` (`lb_tx.vc2:551-585`) si `clb_serie_act` (`serii_numere.vc2:7`) **nu au deloc**
|
||
metode de activare. Singura reteta completa din biblioteca e `clb_tx_data.dezactiveaza()` /
|
||
`reactiveaza()` (`lb_tx.vc2:521-538`: `ReadOnly` + `TabStop` + butonul de calendar) — se
|
||
generalizeaza de la ea, nu se inventeaza alta.
|
||
|
||
Decizia 5 ramane in picioare: **asezarea e identica** la introducere si la modificare; difera doar
|
||
starea antetului.
|
||
|
||
### I-bis. Contractul lui `modifica_date_factura` (decizia 19)
|
||
|
||
Raport complet: `docs\cercetare\modifica_date_factura_parametri.md`. Spec `PACK_FACTURARE.pck:921-935`,
|
||
corp `:14392-14462`, singurul apel VFP la `ofacturare_comun.vc2:4599-4614`.
|
||
|
||
Procedura are **doua regimuri de scriere**, si diferenta dintre ele decide cum se cheama din
|
||
formularul unificat:
|
||
|
||
| Parametri | Regim | Unde ajung |
|
||
|---|---|---|
|
||
| `V_ID_VANZARE` | doar `WHERE` | identitatea randului; sursa lui `lnIdFact` (`:14424-14426`) |
|
||
| `V_ID_RUTA`, `V_ID_DELEGAT`, `V_ID_AGENT`, `V_ID_MASINA`, `V_DATAORA_EXP`, `V_ID_FACTURARE`, `V_LISTARE_DETALIATA`, `V_TEXT_ADITIONAL`, `V_TIP_SAFT`, `V_EFACTURA` | **scrise neconditionat**, inclusiv cu `NULL` | `VANZARI`, randul curent (`:14414-14423`) |
|
||
| `V_DATA_ACT`, `V_DATA_SCAD`, `V_NUMAR_ACT`, `V_SERIE_ACT` | scrise **doar daca** sunt `NOT NULL` **si** difera de valoarea curenta | `VANZARI` + propagare in `DOCUMENTE`, `ACT`, `IREG_PARTENERI`, `JV2007`, `RUL` (si `RUL.DATAOUT`), toate **dupa `ID_FACT`**, nu dupa `ID_VANZARE` (`:14428-14459`) |
|
||
|
||
**Consecinta 1 — apelul trimite intotdeauna antetul intreg.** Cele zece campuri din regimul
|
||
neconditionat se scriu cu ce primesc, deci un apel cu `poRec` completat partial **goleste** in baza
|
||
campurile netrimise. Butonul de antet nu poate trimite „doar ce s-a schimbat”: incarca antetul
|
||
curent, aplica modificarile peste el, trimite tot.
|
||
|
||
**Consecinta 2 — cele patru campuri de identitate ating cinci tabele.** Propagarea dupa `ID_FACT`
|
||
inseamna ca schimbarea seriei sau a numarului dintr-un document atinge toate randurile legate de
|
||
acelasi `ID_FACT`. E acelasi mecanism pe care se sprijina S9 (reemiterea cu `ID_FACT` pastrat) si
|
||
acelasi motiv pentru care ordinea operatiilor conteaza acolo.
|
||
|
||
**Consecinta 3 — un camp nou.** `V_EFACTURA` se scrie neconditionat dar nu are niciun control in
|
||
niciun formular; azi valoarea vine din `Scatter` sau e fortata `0` (`ofacturare_comun.vc2:4576`).
|
||
In antetul unificat primeste control, langa `V_TIP_SAFT` (ambele tin de raportare, nu de document).
|
||
|
||
**Unde stau cele 14 in formularul unificat** (raportat la gruparea din I): cele patru de identitate
|
||
in antetul vizibil; ruta, delegatul, agentul, masina, `dataora_exp` si adresa de facturare in
|
||
sectiunea pliata, la „delegat si transport” / „adresa de facturare”; `text_aditional` si
|
||
`listare_detaliata` tot in pliat; `tip_saft` si `efactura` formeaza acolo un **grup nou, de
|
||
raportare**. Niciunul dintre cei 14 nu vine azi din `frm_alte_date` — clasa aceea nu e implicata
|
||
deloc in fluxul `do_modifica`, deci sectiunea B si I-bis nu se suprapun.
|
||
|
||
### J. Butoanele de linie si adaugarea din sursa (decizia 13)
|
||
|
||
**Cum sunt azi.** In `frm_facturare_articole` butoanele sunt imprastiate lateral, intre cele doua
|
||
griduri, si sunt iconite de 30x27 fara text: `But_modifica1` / `But_sterge1` la 773/61 si 811/61,
|
||
`But_reset1` la 303/295, `But_urmator1` la 343/348, `But_urmator_tot1` la 343/378, `But_retur` la
|
||
343/407 (`ofacturare.vc2:11192-11257`). **`But_urmator_tot1` — „adauga tot” — nu are nici caption
|
||
nici `ToolTipText`** (`:11257`); metoda lui, `do_adauga_tot` (`:13169-13198`), face SCAN peste
|
||
`crsarticole` si cheama `do_adauga_articol(.T.)` pe fiecare linie.
|
||
|
||
**In prototip sunt deja unde trebuie**: `But_nou1` si `But_sterge1` la `Top = 175`, gridul la
|
||
`Top = 204` (`:15936`, `:15955`) — adica **deasupra tabelului**, exact cum cere decizia 13.
|
||
`But_nou1.Click -> do_adauga` (`:17118-17122`) e `APPEND BLANK` + focus in grid.
|
||
|
||
**Ce lipseste: contractele.** `But_urmator_tot1` e vizibil pe `eProforma = 1`, `lCopiere`, tip 3
|
||
(comanda), tip 4 (din avize), 21/28/42/47, 25, 8/9, 24 (`:15113-15245`). **Tipurile de contract
|
||
(2, 6, 26, 52) nu sunt in lista.** Deci „adauga tot” acopera deja avizele, dar nu contractele.
|
||
|
||
**Alegerea selectiva — tiparul importului RORIS.** In ROAACNPRO, `cmdImport` („Import Roris &
|
||
Contracte”, `oacnpro.vc2:6894-6905`) face exact ce s-a cerut aici, si merita copiat ca structura:
|
||
|
||
1. **buton activ conditionat** de document editabil **si** tip care are sursa
|
||
(`llFacturaEditabila and llRorisSauContracte`, `oacnpro.vc2:8117-8145`);
|
||
2. **o metoda unica de intrare** care ramifica pe tip (`do_executa` -> `factura_import`,
|
||
`proceduri_acnpro.prg:3151-3212`);
|
||
3. **dialog modal de selectie** cu coloana de bifat si criterii de cautare (`frm_tranzit`, coloana
|
||
`cAles` legata de `crsConvoaie.ales`, `oacnpro.vc2:14500-14515`, `:14801`), urmat de un al doilea
|
||
nivel de calcul / confirmare;
|
||
4. **populare aditiva** prin `INSERT INTO` in cursorul local de articole, fara nicio procedura Oracle
|
||
— pachetele intra abia la salvare (`proceduri_acnpro.prg:3331-3467`);
|
||
5. **protectie minimala la dublu-import**: butonul se dezactiveaza dupa un import reusit
|
||
(`oacnpro.vc2:7827-7834`), plus avertisment neblocant daca sursa a mai fost folosita
|
||
(`:14915-14930`).
|
||
|
||
Ce **nu** se copiaza: sursele de date si calculele ACN (`ips_*`, tarife, ecluzari), formularele lor,
|
||
si valorile `poDate.cTip`. Ce trebuie facut mai bine: la zero rezultate, dialogul RORIS nu spune
|
||
nimic — butonul pare ca nu face nimic (`oacnpro.vc2:14898-14943`).
|
||
|
||
**Bara propusa, deasupra gridului (decizia 13):** linie noua · sterge linia · detalii linie ‖
|
||
**un singur buton „Adauga articole”**, care deschide un `xmenu()` cu optiunile potrivite sursei —
|
||
nu doua butoane separate. Tiparul e deja folosit in produs: `frm_facturi.but_modifica1` ->
|
||
`inainte_de_do_modifica` -> `xmenu("Modificare date factura;Editare factura (articole, cantitati,
|
||
preturi)")` (`ofacturare_comun.vc2:4925-4934`).
|
||
|
||
| Sursa documentului | Optiunile din meniu |
|
||
|---|---|
|
||
| comanda | Adauga tot din comanda · Alege din comanda… · Cauta in lista de preturi… |
|
||
| contract | Adauga tot din contract · **Alege ratele de facturat…** · Cauta in lista de preturi… |
|
||
| avize | Adauga tot din avize · Alege avizele… · Alege liniile din avize… · Cauta in lista de preturi… |
|
||
| lista de preturi | Cauta in lista de preturi… · Retur de articole… |
|
||
| retur (tip 8, 9, 24) | Alege facturile de returnat… · Alege liniile de returnat… · Cauta in lista de preturi… |
|
||
|
||
**Constanta meniului (deciziile 16 si 18): ultimele doua optiuni sunt aceleasi peste tot** —
|
||
**„Cauta in lista de preturi…”** (cu pret din politici) si **„Alege din nomenclator…”** (cu pret
|
||
tastat, ca „Alte servicii” din ROAAUTO, O-bis). Apar inclusiv pe documentele cu sursa, pe cele de
|
||
retur si pe cele deja emise care se modifica. Sursa umple documentul, nu il inchide.
|
||
|
||
**Decizia 20 (Marius, 09.08.2026): din nomenclator se pot alege si articole gestionabile, si
|
||
negestionabile.** Nu se preia filtrul `in_stoc = 0` al lui ROAAUTO — acolo e o ocolire a subiectului
|
||
gestiunii, nu o regula de produs. Consecinta directa: pe documentele auto vor putea aparea linii care
|
||
descarca stoc langa linii care nu descarca, caz care azi nu exista nicaieri (O-bis, intrebarea 2).
|
||
|
||
#### J-bis. Contul de venit al liniei — intrebarea lui Marius era corect pusa
|
||
|
||
Doua cercetari, a doua o corecteaza pe prima. **Valabil e al doilea raport:**
|
||
`docs\cercetare\cont_venit_corespondente.md`. Primul (`cont_venit_articol_fara_politica.md`) ramane
|
||
util pentru contul de **gestiune**, dar concluzia lui pe venit e gresita si nu se citeaza.
|
||
|
||
**Ce a gresit primul raport.** A cautat literalii `707` / `704` / `706` / `708` in `pack_facturare`,
|
||
nu i-a gasit (corect — nu sunt hardcodati nicaieri) si a conchis ca **nu exista cont de venit pe
|
||
linie**. Exista. E doar **indirect**, si sta chiar in `pack_facturare`, nu intr-un pachet de
|
||
contabilitate separat.
|
||
|
||
**Sunt doua conturi pe aceeasi linie de vanzare, cu surse complet diferite:**
|
||
|
||
| | Contul de **gestiune** | Contul de **venit** |
|
||
|---|---|---|
|
||
| Unde ajunge | `VANZARI_DETALII.CONT` (`varchar(4)`) | `SCC` in randul de nota contabila |
|
||
| De unde vine | `NOM_ARTICOLE.CONT` / `STOC.CONT` / `NOM_GESTIUNI.CONT` | `NOTE_CONTABILE.SCC` |
|
||
| Prin ce | alegerea lotului (`do_alege_stoc`) | **politica de pret** a articolului |
|
||
| Cine il consuma | `descarca_gestiune` (`ff_...:7485-7507`) | `scrie_nota` (`ff_...:7452-7476`) |
|
||
|
||
Lantul care aduce venitul, in `pack_facturare.contabilizeaza_articol` (`ff_...:7182-7556`, cursorul
|
||
`cursor_articol` la `:7227-7280`):
|
||
|
||
**`CRM_POLITICI_PRET_ART` -> `CRM_POLITICI_PRETURI.ID_NOTA` -> `CRM_NOTE_VANZARI.ID_SET` ->
|
||
`NOTE_CONTABILE.SCD` / `SCC`**
|
||
|
||
Pentru o factura normala (`ntip <= 20`), `SCD` e contul debitor (creanta) si **`SCC` e contul de
|
||
venit efectiv** al liniei (`ff_...:7407-7437`). Nu e derivat din nimic: perechea SCD/SCC e **scrisa
|
||
manual de un contabil**, per sablon de nota, din ecranul „Configurare note contabile"
|
||
(`COMUN\ferestre\frm_config_note_contabile[2007].sc2`, clasa `onote_contabile.vc2:2401-2435`,
|
||
salvare la `:315-322`, `:486-493`).
|
||
|
||
**Nu exista tabel de corespondenta 3xx -> 7xx.** Cautat in `SCRIPTURI_CLAR` sub toate numele
|
||
plauzibile — negativ. Ipoteza lui Marius era corecta ca **intentie** (exista un mecanism care leaga
|
||
articolul de contul de venit), dar mecanismul e **configurare manuala pe politica de pret**, nu
|
||
derivare automata din contul de stoc.
|
||
|
||
**Consecinta care conteaza pentru #13 — si care valideaza intrebarea initiala a lui Marius.** Daca
|
||
contul de venit vine **prin politica de pret**, atunci un articol adaugat **direct din nomenclator,
|
||
fara politica** (exact ce cere decizia 16 / 20) nu are `ID_POL`, deci cursorul de mai sus — filtrat
|
||
`WHERE A.ID_POL = detalii_articol.id_pol` — nu intoarce niciun rand, si `SCD` / `SCC` raman `NULL`
|
||
(sunt `LEFT JOIN`-uri). **Intrebarea „cu ce cont de venit intra un articol fara politica de pret" era
|
||
deci exact intrebarea corecta.**
|
||
|
||
#### J-ter. Raspunsul: nu „cu niciunul”, ci **eroare** — si nu exista precedent
|
||
|
||
Verificat: `docs\cercetare\nota_contabila_fara_politica.md`. Doua rezultate, amandoua mai dure decat
|
||
se anticipase.
|
||
|
||
**1. Codul nu scrie tacut un cont gol — refuza documentul.** `contabilizeaza_articol` cauta politica
|
||
articolului **inainte** de cursorul care aduce `SCC` (`ff_...:7286-7311`), si pe `NO_DATA_FOUND`
|
||
ridica `RAISE_APPLICATION_ERROR` cu **`FACT-024`** („Articolul … nu este definit in politica de
|
||
preturi …”). Cu `id_pol` `NULL`, `ID_POL = detalii_articol.id_pol` nu poate potrivi nimic, deci
|
||
**mereu** se intra pe exceptie. Cursorul cu `SCC` nu se mai deschide. Nu exista ramura de default,
|
||
nu exista fallback, si `scrie_nota` (`ff_...:12338-12570`) **nu are nicio validare pe cont** — dar
|
||
nici nu ajunge sa fie chemat.
|
||
Concluzie: o linie fara politica trecuta prin codul de azi **opreste tranzactia cu eroare**, nu produce
|
||
o nota incompleta. Din perspectiva datelor e vestea buna; din perspectiva lui #13, e blocantul dur.
|
||
|
||
**2. „Alte servicii" din ROAAUTO NU e precedent** — premisa pe care se sprijinea decizia 18 cade.
|
||
Liniile acelea chiar ajung cu `id_pol` gol (confirmat: nici `crsalteserv`, nici `crsvanztemp`, nici
|
||
semnatura lui `adauga_articol_factura_deviz` nu au `id_pol`, iar `INSERT`-ul in
|
||
`VANZARI_DETALII_TEMP` nu include coloana). **Dar ele nu trec niciodata prin
|
||
`contabilizeaza_articol`**: fluxul ROAAUTO cheama `initializeaza_date_factura` ->
|
||
`adauga_articol_factura_deviz` -> `scrie_in_vanzari` -> `pack_auto.actualizeaza_deviz`
|
||
(`oproceduri_devize.prg:1211-1310`), iar `scrie_in_vanzari` (`ff_...:13497-13962`, citit cap-coada)
|
||
**nu genereaza nicio nota contabila de venit** — copiaza `ID_POL` (deci `NULL`) direct in
|
||
`VANZARI_DETALII` si actualizeaza totalurile.
|
||
Deci ROAAUTO nu demonstreaza ca articolele fara politica sunt tolerate; demonstreaza ca **exista o cale
|
||
paralela de facturare care ocoleste contabilizarea de venit prin `pack_facturare`**. Unde capata acele
|
||
documente contul de venit — daca il capata — **nu se vede in codul cercetat**; `actualizeaza_deviz`
|
||
presupune deja existenta unui rand in `ACT`, a carui sursa nu a fost gasita.
|
||
|
||
**3. Apelantii sunt trei, si acopera fluxul principal** (lasat neverificat de raportul 2):
|
||
`scrie_factura2` (`ff_...:6150`) — factura normala si majoritatea tipurilor —, `scrie_factura_avize_retur`
|
||
(`:6867`) si `scrie_aviz_retur` (`:7149`). Nu exista al patrulea.
|
||
|
||
**4. `NOM_ARTICOLE.CONT` ca sursa de venit: NU.** Grep pe `NOM_ARTICOLE.CONT` in tot pachetul — zero
|
||
potriviri. `V_SCC` vine exclusiv din `D.SCC` al lantului de politica. Varianta propusa de Marius nu
|
||
exista nici macar ca ramura moarta.
|
||
|
||
**Ce inseamna asta pentru perimetru.** „Alege din nomenclator…" nu mai e o adaugare de UI peste un
|
||
mecanism existent: **cere modificare in `pack_facturare`**, adica in COMUN, cu impact peste toata
|
||
suita — sau evitarea completa a lui `contabilizeaza_articol`, ca la ROAAUTO, ceea ce inseamna document
|
||
fara nota de venit. **Aceasta e o schimbare de cost, nu un detaliu**, si se decide de Marius (vezi
|
||
intrebarea deschisa de mai jos).
|
||
|
||
**`NOM_ARTICOLE.CONT` nu e restrans la clasa 3** — confirmat: `verific_cont`
|
||
(`COMUN\programe\oproceduri_comune.prg:2389-2415`) verifica doar ca acel cont exista in planul de
|
||
conturi al anului (`vplcont_sintetic`), fara filtru de clasa; nu exista `CHECK CONSTRAINT` pe coloana
|
||
si nici vreo ramificare pe `Left(cont,1)` aplicata articolelor. Deci un articol negestionabil **poate**
|
||
purta legitim un cont 6xx / 7xx, cum a spus Marius. **Dar codul de azi nu-l foloseste asa**: acel camp
|
||
merge in `VANZARI_DETALII.CONT` si de acolo la `descarca_gestiune`, niciodata la `SCC`. Ca sugestia lui
|
||
Marius sa devina comportament, ar trebui **cod nou in `pack_facturare`** — adica in COMUN, cu impact
|
||
peste toata suita. *Vezi intrebarea deschisa de mai jos.*
|
||
|
||
**`ID_VENCHELT` / `NOM_VENIT_CHELTUIELI` nu e sursa contului.** Tabelul nu are coloana de cont;
|
||
`ID_VENCHELT` se rezolva separat (`NVL(nid_venchelt, NVL(A.ID_VENCHELT, C.ID_VENCHELT))`,
|
||
`ff_...:7205`) si pleaca la `scrie_nota` ca **parametru propriu**, alaturi de `SCD`/`SCC` — e o a
|
||
treia dimensiune analitica (centru de venituri/cheltuieli, pentru raportare), nu contul insusi.
|
||
Presupunerea din runda 7 ca „venitul vine din `Ct_clb_venchelt`" **se retrage**.
|
||
|
||
De unde vine `CONT`, pe cele doua cai:
|
||
|
||
| Cale | Sursa contului | Fallback |
|
||
|---|---|---|
|
||
| **gestionabil, cu stoc** — trece prin `do_alege_stoc` (`ofacturare.vc2:13239-13345`) | `STOC.CONT`, de pe lotul ales (`cursor_gestiuni_articol`) | **niciunul** — lot cu `CONT` gol ramane `NULL` |
|
||
| **gestionabil, fara stoc** (`RF_FACTURARE_FARA_STOC = 1`) | `NOM_GESTIUNI.CONT` -> ultimul `STOC.CONT` -> `'371'` hardcodat (`cursor_gestiuni_articol_stoc0`) | singurul loc din pachet cu cascada si default |
|
||
| **negestionabil** — `frm_articol_factura` direct (`:12871-12880`) | `NOM_ARTICOLE.CONT`, citit la cautarea articolului | **niciunul**; gol -> sentinela `'XXXX'` -> `NULL` la INSERT |
|
||
|
||
`adauga_articol_factura` **nu recalculeaza** contul: il primeste ca parametru `V_CONT` si il scrie ca
|
||
atare. **Nu exista nicio exceptie pe `CONT`** in tot pachetul — spre deosebire de cota de TVA, unde
|
||
lipsa produce explicit `FACT-012` / `FACT-013` / `FACT-018`. O linie fara cont se scrie tacut.
|
||
|
||
**Precedentul ROAAUTO nu ofera o regula, ci absenta ei.** „Alte servicii” (O-bis) trimite literal `''`
|
||
catre `adauga_articol_factura_deviz` (`oproceduri_devize.prg:1256`), care ajunge `NULL` in Oracle,
|
||
fara `NVL` si fara fallback. Liniile de articole reale din ROAAUTO **ajung deci cu `CONT = NULL`**.
|
||
|
||
**Decizia 21 (Marius, 09.08.2026)** acopera **contul de gestiune**: cand `NOM_ARTICOLE.CONT` e gol pe
|
||
un articol negestionabil ales din nomenclator, se aplica un **fallback la un cont implicit** — nu se
|
||
accepta `NULL` ca la ROAAUTO, nu se refuza adaugarea. Precedentul de forma exista in pachet:
|
||
`cursor_gestiuni_articol_stoc0` cade in cascada pana la `'371'` hardcodat. Contul anume ramane de ales
|
||
la implementare. **Decizia 21 nu rezolva insa contul de venit** — sunt doua campuri diferite, cum arata
|
||
tabelul de mai sus; la momentul cand a fost luata, distinctia nu era inca stabilita.
|
||
|
||
~~**Decizia 24: articolul ales din nomenclator primeste `id_pol`-ul unei politici de pret
|
||
implicite.**~~ **RETRASA in runda 8.** Argumentul ei — zero cod Oracle nou, COMUN neatins — ramane
|
||
valabil ca argument, dar pretul lui era o intrebare de configurare cu contabilul (care politica, cu ce
|
||
`SCC`, una sau mai multe) si un cont de venit uniform pentru orice articol adaugat asa. Marius a ales
|
||
in loc derivarea contului. **Nu se reintroduce.** *Vezi J-quater.*
|
||
|
||
Ramane valabil de aici, si e important: **alegerea politicii de catre operator** a fost si ea respinsa
|
||
— muta costul pe fiecare adaugare si cere operatorului sa stie ce inseamna o nota contabila.
|
||
|
||
**Ce se stie sigur pana atunci:** decizia 16 si decizia 20 **nu sunt anulate** de subiectul asta — pe
|
||
articolele **cu** politica de pret (lista de preturi, comanda, contract, retur) contul de venit vine
|
||
ca azi si nimic nu se schimba. Blocajul e strict pe ramura **„Alege din nomenclator…"**, adica pe
|
||
partea din S4g care adauga articole fara politica.
|
||
|
||
**Unde e efectiv de lucru pentru asta:** doar pe **comanda**. Verificat
|
||
(`docs\cercetare\retur_si_lista_preturi.md`, B): pe contract, `crsarticole` contine deja lista de
|
||
preturi intreaga, deci adaugarea libera **merge azi**; pe comanda, `cursor_comanda` umple `crsarticole`
|
||
strict cu articolele comenzii (`ofacturare.prg:266-308`), deci nu merge. Restrictia **nu** e pe buton
|
||
si nu e la validare — e in continutul cursorului. Se rezolva ca la copiere: `APPEND FROM` peste
|
||
`crsarticole` cu rezultatul lui `cursor_preturi` (`ofacturare.prg:454-473`).
|
||
|
||
#### J-quater. Deciziile 27 / 27-bis — contul de venit derivat, aplicat din VFP
|
||
|
||
> **DEPASITA IN PARTE — de citit cu avertismentul asta in fata.** **Decizia 34** relaxeaza 27-bis
|
||
> (`contabilizeaza_articol` primeste parametru de cont) si **decizia 35** cere ca `pack_facturare` sa fie
|
||
> singurul cod de contare, si la emitere si la editare. Prin urmare:
|
||
> - **punctul 1** (de ce ROAACNPRO si contractul nu sunt contraexemple) si **punctul 2** (derivarea
|
||
> contului din `CORESP_CONT_VENCHELT` — regula deciziei 27) **raman valabile integral**;
|
||
> - **punctul 3, „reteta in 4 pasi"** — politica tehnica per `SCC`, interogarea inversa,
|
||
> `pack_preturi.adauga_politica_pret_art`, inserarea articolului in politica — e **ABANDONAT**. Se
|
||
> pastreaza doar ca trasabilitate a rationamentului. **Nu se implementeaza si nu se reargumenteaza.**
|
||
> - **cele trei variante** de la finalul sectiunii (reteta / nota pe antet / nota pe antet ca fallback)
|
||
> sunt **caduce**: alegerea a fost facuta prin decizia 34.
|
||
>
|
||
> Proiectarea in vigoare e parametrul deciziei 34 — `docs\cercetare\parametru_cont_contabilizeaza_articol.md`.
|
||
|
||
Raport: `docs\cercetare\coresp_cont_venchelt.md`. Trei lucruri s-au stabilit, in ordinea in care conteaza.
|
||
|
||
**1. Intrebarea lui Marius („in ROAACNPRO si pe factura din comanda / contract se adauga articole fara
|
||
politica — de ce nu si aici?") a primit raspuns: observatia e reala, dar niciunul din cele doua exemple
|
||
nu e un contraexemplu.** `FACT-024` ramane blocantul.
|
||
|
||
- **ROAACNPRO nu foloseste deloc `contabilizeaza_articol`.** Salvarea facturii ACN
|
||
(`proceduri_acnpro.prg:3331-3467`) merge pe `initializeaza_date_factura` ->
|
||
**`adauga_articol_factura_deviz`** -> **`scrie_in_vanzari`** -> **`pack_acn.salveaza_regdoc`**.
|
||
Cautare directa dupa `contabilizeaza_articol` in acel fisier: **zero rezultate**. Nota contabila o
|
||
scrie o procedura proprie ACN, care nici nu primeste `id_pol` printre parametri. Acelasi tipar ca
|
||
ROAAUTO „Alte servicii" (J-ter, punctul 2): **o cale de facturare paralela**, nu o dovada ca articolele
|
||
fara politica sunt tolerate.
|
||
- **Pe contract, articolul „liber" nu e fara politica.** `crsarticole` e populat de
|
||
`pack_facturare.cursor_contract` / `cursor_preturi`, care **selecteaza explicit `A.ID_POL`**
|
||
(`ff_...:2162-2167`) si care ruleaza la fiecare apel `completare_politica_stoc` (`ff_...:2151`).
|
||
Deci fiecare rand din grila vine deja **cu o politica reala atasata**. „Adaugare libera pe contract"
|
||
inseamna „orice articol din lista de preturi, nu doar cele din contract" — nu „articol fara politica".
|
||
|
||
**Diferenta reala e cursorul-sursa al grilei, nu tipul de document:** `caut_articol`
|
||
(`COMUN\programe\ocautare.prg:1636-1735`, cautarea in nomenclator) **nu are coloana `id_pol` in nicio
|
||
ramura**; `cursor_preturi` / `cursor_contract` o au, pentru ca pleaca de la politica, nu de la
|
||
nomenclator. Povestea #13 cere exact ce nu exista azi nicaieri.
|
||
- **Ce verifica de fapt `FACT-024`:** `SELECT COMPUS, ID_POL_ART FROM VCRM_POLITICI_PRET_ART WHERE
|
||
ID_ARTICOL = ... AND ID_POL = ...` (`ff_...:7278-7302`) — deci **apartenenta articolului la politica
|
||
de pe linie**. Ipoteza din runda 8 e **partial** confirmata: verificarea e de apartenenta, dar `id_pol`
|
||
**nu** vine din antet ca valoare unica — e parametru per linie, trimis de VFP. Doua cauze diferite
|
||
(`id_pol` gol; articol nemembru) produc aceeasi eroare, iar codul nu le distinge.
|
||
|
||
**2. `CORESP_CONT_VENCHELT` exista, e populat si e folosit in productie — dar niciodata pentru
|
||
`CONT_VENIT`.** Toti consumatorii gasiti (`pack_vin`, `pack_devize`, `gestiune_pack_gest_import`,
|
||
rapoarte de gestiune) citesc `CONT_CHELT` sau `CONT_APROVIZIONARE`. Coloana `CONT_VENIT` **are date
|
||
reale** dar **zero consumatori**, nici Oracle nici VFP. Cheia de join e stabila si testata: pe `CONT`, cu
|
||
`STERS = 0`, prin `LEFT JOIN` — tiparul se copiaza identic. Deci regula lui Marius e implementabila; e
|
||
insa **un consumator nou**, nu o reteta deja rulata.
|
||
|
||
**Masurat pe baza vie (10.08.2026, `MARIUSM_AUTO`) — `docs\cercetare\verif_baza_vie_cont_venit.md`:**
|
||
tabelul are **41 de randuri active**, din care exact **20 au `CONT_VENIT`** populat; restul 21 sunt
|
||
conturile de ajustari (`391`…`398`, toate cu `CONT_CHELT = 681`), care nu poarta marfa. **Niciun `CONT`
|
||
nu e duplicat**, deci pasul 1 al retetei e determinist — desi schema nu are unique pe `CONT`, doar `PK`
|
||
pe `ID_CCV`. Si, decisiv: **zero articole active cad pe un rand cu `CONT_VENIT` gol**, deci ramura
|
||
„cont derivat gol" se trateaza defensiv dar nu are cazuri reale. DDL-ul complet e in raport.
|
||
|
||
**3. Calea VFP (decizia 27-bis) exista si e construita din piese functionale.** Patru pasi.
|
||
|
||
> **Clarificare ceruta de Marius (10.08.2026) — de citit inainte de cei patru pasi.** Politica **nu e
|
||
> necesara ca sa se afle contul.** Regula deciziei 27 il determina complet, in VFP: corespondentele pe
|
||
> clasa 3, contul de pe articol daca e 6xx / 7xx, `704` altfel. Aia e **pasul 1**, si e verificata pe date.
|
||
> Politica e necesara **doar ca canal de transport** catre Oracle: `contabilizeaza_articol` **nu are
|
||
> parametru de cont de venit** — primeste `V_ID_POL` si deduce singura contul prin lantul politica → nota →
|
||
> `NOTE_CONTABILE.SCC`. Deci **pasii 2-4 nu decid nimic**, doar convertesc un cont pe care VFP il stie deja
|
||
> intr-o forma pe care pachetul o accepta. Indirectarea e consecinta deciziei **27-bis**, nu a regulii lui
|
||
> Marius: daca pachetul ar putea fi modificat, un parametru de cont ar face pasii 2-4 sa dispara.
|
||
> **INCHIS (runda 9 + decizia 35).** Cautarea canalului direct s-a terminat —
|
||
> `docs\cercetare\canal_cont_venit_fara_politica.md`. Verdict: canalul **exista** (`actactan` / `tact` →
|
||
> `oscrie_in_fisiere` → `pack_contafin.SCRIE_IN_ACT`), dar e cablat pe **editarea unei note deja scrise**,
|
||
> nu pe emitere; emiterea trece exclusiv prin `scrie_factura2` → `contabilizeaza_articol`. Pistele
|
||
> `V_CONT` (e contul de gestiune), setterele de sesiune, `ID_VENCHELT` si `GetAnaliticByGrupUtilizatori`
|
||
> sunt **toate NU**.
|
||
> **Si nu se foloseste oricum:** decizia 35 il respinge explicit in #13, ca sa nu existe doua coduri de
|
||
> contare. Reteta in 4 pasi cade prin **decizia 34** (parametru de cont in pachet), nu prin canal.
|
||
|
||
1. **VFP calculeaza `SCC`-ul** dupa regula deciziei 27: `CORESP_CONT_VENCHELT.CONT_VENIT` pe contul de
|
||
gestiune al liniei (articol gestionabil), `NOM_ARTICOLE.CONT` daca e 6xx / 7xx, altfel `'704'`.
|
||
2. **VFP cauta o politica a carei nota are deja acel `SCC`** — interogarea inversa pe acelasi lant:
|
||
`CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI -> NOTE_CONTABILE`, `WHERE NC.SCC = :cont_calculat`.
|
||
Interogare **noua**, dar pe coloane si relatii deja confirmate.
|
||
**Corectat pe baza vie:** legatura nu e politica -> nota, ci politica -> **set de note** —
|
||
`CRM_POLITICI_PRETURI.ID_NOTA` -> `CRM_NOTE_VANZARI.ID_SET` -> `NOTE_CONTABILE.ID_SET`. Pe cele 7 note
|
||
de vanzari active fiecare set are **un** rand, dar in tabel exista seturi cu pana la **30** de randuri,
|
||
deci „nota politicii" e bine definita doar cat timp seturile de vanzari rămân cu un rand.
|
||
**Si mai important: filtrarea pe `SCC` singur nu e suficienta** — vezi „Ce nu e gratuit" mai jos.
|
||
3. **VFP se asigura ca articolul e membru al acelei politici** — RPC **existent**
|
||
`pack_preturi.adauga_politica_pret_art`, deja folosit exact asa (verifica intai, insereaza daca
|
||
lipseste) in `ofacturare.vc2:15551-15587`, la modificarea listei de preturi de la NIR. **`pack_preturi`
|
||
nu e `pack_facturare`** — nu se atinge nimic din pachetul comun de facturare.
|
||
4. **VFP trimite acel `id_pol`** in `adauga_articol_factura` (`V_ID_POL` e parametru de intrare explicit,
|
||
`ff_...:4989-5015`). `contabilizeaza_articol` ruleaza **neschimbata**.
|
||
|
||
**Modelul „politica tehnica, configurata o data, populata automat" exista deja in pachet:**
|
||
`completare_politica_stoc` (`ff_...:2093-2120`) face `MERGE` in `CRM_POLITICI_PRET_ART` pentru toate
|
||
articolele `IN_STOC = 1` sub politica `pack_facturare.nid_politica_stoc`, alimentata din optiunea globala
|
||
`gnId_pol_pret_stoc` (`ofacturare.vc2:21733-21753`). Nu e direct reutilizabila — are o singura nota
|
||
pentru toate articolele, iar decizia 27 cere pana la sase conturi diferite — dar arata ca tiparul e
|
||
acceptat in produs.
|
||
|
||
**Calea VFP e mai completa decat modificarea pachetului**, nu doar mai ieftina: politica reala aduce si
|
||
`CU_TVA`, `IN_VALUTA`, `EXPLICATIE`, `ASCD`, `ASCC` din nota configurata. Un fallback in
|
||
`contabilizeaza_articol` ar da doar `SCC`; `CU_TVA` si `IN_VALUTA` **nu au nicio sursa alternativa** in
|
||
afara lui `NOTE_CONTABILE`, deci ar trebui hardcodate — cu risc de calcul gresit al bazei si al TVA.
|
||
|
||
**Ce nu e gratuit, si trebuie stiut inainte de S4g:**
|
||
|
||
- **Pasul 2 depinde de configurarea fiecarui client — deci nu se poate proiecta pe acoperire.**
|
||
Decizia lui Marius, 10.08.2026: **datele din Dev nu sunt baza de proiectare.** Fiecare client isi
|
||
defineste propriile politici de pret, fiecare cu nota ei de vanzare salvata pe un `ID_SET`. Pe schema
|
||
de dezvoltare masurarea a dat `704` cu 19 politici valabile, `707` cu 4, `7015` cu 1, si zero pentru
|
||
`711` / `702` / `703` / `7018` — **dar aceste numere nu se folosesc ca argument**, pe o baza de client
|
||
distributia poate fi complet alta. Ce se pastreaza din masurare e strict **structural** (forma lantului,
|
||
absenta unique-ului pe `CONT`, bug-ul de set multi-rand) plus un fapt negativ: **afirmatia rundei 8 ca
|
||
„pentru `704` nu exista nicio nota configurata" nu se susține ca regula** — pe Dev exista patru, deci
|
||
pasul „se creeaza nota pentru 704" nu poate fi pus in plan ca obligatoriu.
|
||
**Consecinta de proiectare:** reteta nu are voie sa presupuna ca gaseste o politica pentru `SCC`-ul
|
||
calculat. Ori garanteaza singura existenta a ceea ce foloseste (politica tehnica creata de produs), ori
|
||
are o cale care **nu trece prin politica deloc** — vezi mai jos.
|
||
- **`PTVA` de pe nota e inofensiv — verificat pe cod, nu presupus.** `cursor_articol`
|
||
(`PACK_FACTURARE:7218-7271`) **nu selecteaza `D.PTVA`**; cota folosita efectiv vine din
|
||
`detalii_articol.proc_tvav * 100 - 100` (`:7464`), adica din articol / document. Deci o nota cu
|
||
`PTVA = 5` pe un articol cu 21% **nu produce nimic** — coloana e moarta pentru aceasta procedura.
|
||
Ingrijorarea initiala („criteriul trebuie sa fie `(SCC, PTVA)`") **se retrage**.
|
||
`IN_VALUTA = 1` de pe nota pe un document in lei nu da nici eroare, nici suma greșita — doar populeaza
|
||
redundant `ACT_TEMP.SUMA_VAL` la curs 1 (`scrie_nota:12391-12404`, `:12492-12507`): inconsistenta
|
||
cosmetica, nu contabila. `ASCD` / `ASCC` nule au fallback automat prin
|
||
`GetAnaliticByGrupUtilizatori` (`:7409-7428`), iar `ID_PARTD` / `ID_PARTC` **nu se citesc de pe nota**
|
||
deloc — vin din contul si din contextul documentului (`:12510-12530`).
|
||
- **In schimb, `ID_SET` cu mai multe randuri dubleaza venitul SI descarcarea de gestiune.** Asta e
|
||
riscul real, si e mai grav decat cel presupus. `cursor_articol` face `LEFT JOIN NOTE_CONTABILE D ON
|
||
C.ID_SET = D.ID_SET` **fara `ROWNUM`, fara agregare, fara filtru**, iar bucla care il consuma
|
||
(`:7393-7542`) executa `scrie_nota` **si** `descarca_gestiune` **o data pentru fiecare rand al
|
||
setului, cu aceeasi cantitate si acelasi pret intreg de fiecare data** — nu impartite. Nu exista
|
||
nicio logica de distributie: `ORDINE` nu apare in tot pachetul. Deci pasul 2 nu trebuie doar sa
|
||
gaseasca un rand cu `SCC`-ul potrivit, ci **sa garanteze ca setul ales are exact un rand**. Cele 7
|
||
note de vanzari active au, azi, exact un rand fiecare — dar 30 din cele 40 de seturi din baza au mai
|
||
multe, cu maxim 30. **Conditia care face reteta sigura e o coincidenta a datelor curente, nu o
|
||
garanție a codului.** Sursa: `docs\cercetare\s10_pret_rederivat.md`, „Completare: nota contabila a
|
||
politicii", punctul 1.
|
||
- **Pasul 3 poluează o lista de preturi de producție.** Politica **este** lista de preturi: candidatele
|
||
reale contin `STOC PRODUSE` cu **6310** articole si `LISTA PRETURI LEI` cu **909**, plus liste cu nume de
|
||
client si de sezon (`CHIOSC`, `SERVICE AUTO`, `S7 CRACIUN`…). Un articol adaugat ad-hoc pe factura ar
|
||
aparea de acum in acea lista, cu pretul cu care a fost facturat o data. **Deci pasul 2 nu trebuie sa
|
||
caute orice politica potrivita, ci o politica tehnica dedicata, una per `SCC`** — modelul
|
||
`gnId_pol_pret_stoc` extins de la una la sapte. Cele **sase** politici cu 0 articole din baza vie arata
|
||
ca o politica goala e o stare acceptata de produs.
|
||
- **Ambiguitatea celor 19 politici pe `704` e de lista de preturi, nu de rezultat contabil** — majoritatea
|
||
trimit la aceeasi `id_nota = 1`, deci toate dau `704` / `PTVA = 21` / lei. Cu atat mai mult, criteriul de
|
||
departajare corect e „care lista de preturi accept sa murdaresc", iar raspunsul e „niciuna dintre cele
|
||
existente".
|
||
- **Politica tehnica devine vizibila utilizatorului** in `caut_politici_curente_util()` — aceeasi functie
|
||
ca la cautarea normala. Ori se filtreaza explicit (flag / prefix dedicat), ori se accepta riscul ca
|
||
cineva sa o aleaga din greseala pe o factura normala. **De decis in S4g.**
|
||
- **`id_pol` devine populat** acolo unde azi ar fi gol. Nu s-a gasit cod care sa presupuna „`id_pol` gol =
|
||
articol fara politica", dar nici nu s-a cautat exhaustiv.
|
||
- **Doua politici active nu au `ID_NOTA`** (`32 HOTEL TAXE`, `33 HOTEL CAZARE`) — `id_pol` valid, nota
|
||
absenta. Ce face `contabilizeaza_articol` in acest caz e intrebare deschisa, trimisa pe cod. E o gaura
|
||
care **exista deja azi**, independenta de #13.
|
||
|
||
**RASPUNS LA DECIZIA 32 — reteta RAMANE. `docs\cercetare\idpol_comanda_contract.md`.**
|
||
|
||
Intrebarea era: cum alege programul nota contabila la factura din comanda, care „nu are politica de pret"?
|
||
**Raspuns: are. Structural nu poate sa nu aiba.** `COMENZI_ELEMENTE.ID_POL` e **`NOT NULL`** la nivel de
|
||
schema (constrangerea `SYS_C0015376`, plus `FK_COMENZI_ELEMENTE_002`) — verificat direct: **0 din 7108
|
||
randuri** au `ID_POL` nul sau zero, 9 politici distincte in uz, toate cu nota atasata. Deci nu exista nicio
|
||
ruta alternativa catre nota, si **nu exista contradictie cu concluzia rundei 8**: pe comanda cazul „`id_pol`
|
||
gol" e imposibil, nu doar neintalnit. Ce percepe operatorul ca „n-am ales nicio politica" e faptul ca
|
||
politica se alege **o data pe comanda** — manual sau moștenita dintr-o optiune legata de tipul comenzii —
|
||
si de atunci fiecare articol adaugat o primeste automat, din `com_vpreturi_utilizator`, view care filtreaza
|
||
`id_pol IS NOT NULL` la sursa. Pe **contract** tiparul e acelasi, dar cheia stocata e
|
||
`CTR_ARTICOLE.ID_POL_ART` — FK direct la randul din `CRM_POLITICI_PRET_ART`, **nullable**, cu cazuri reale.
|
||
|
||
**De ce `FACT-024` nu se declanseaza pe comanda / contract:** nu pentru ca ar exista un fallback, ci pentru
|
||
ca **articolul nu e ales niciodata din nomenclator** — e ales dintr-o lista deja filtrata pe politica, deci
|
||
apartenenta e garantata **prin construcția listei**, nu prin validare. Exact aici e diferenta cu #13, unde
|
||
`caut_articol` ofera nomenclatorul intreg.
|
||
|
||
**Deci refolosirea nu simplifica nimic:** mecanismul de jos — RPC de inserare + apartenenta garantata — e
|
||
**exact** ce propune reteta in 4 pasi. Ce ar simplifica cu adevarat („ia politica curenta fixa si pune
|
||
articolul in ea") e **decizia 24, retrasa**, si motivul retragerii sta: o politica unica da **un singur**
|
||
cont de venit oricarui articol, indiferent de natura lui — opusul deciziei 27. Comanda si contractul nu
|
||
raspund niciodata la intrebarea „**care** politica pentru **acest** articol", pentru ca la ele politica vine
|
||
gata aleasa, o data, de operator.
|
||
|
||
**CORECTIE, a doua tura a aceluiasi agent — premisa lui Marius ERA corecta, dar pe contract, nu pe comanda.**
|
||
Exista o ruta reala catre nota contabila **complet in afara lui `id_pol`**: la **contractele cu rate /
|
||
scadentar** (`OPT_FACTURARE IN (1, 2)`), o functie separata — **`contabilizeaza_rata`** — scrie nota direct
|
||
din **`CONTRACTE.ID_NOTA`**, fara sa treaca prin `CRM_POLITICI_PRETURI`. Confirmat pe cod de agent si pe o
|
||
factura reala (`id_vanzare 360`: `SCD = 4111` / `SCC = 704` in `ACT`, pe o linie fara articol si fara
|
||
politica). **Structura confirmata independent de sesiunea principala:** `CONTRACTE.ID_NOTA` exista, e
|
||
nullable, si e **populat pe 19 din 242 de contracte**, rezolvand la note reale — `1 NOTA 1` → `SCC 704`
|
||
(5 contracte), `2 DISCOUNT` → `SCC 4111` (5), `5 VANZARE MARFA` → `SCC 707` (1). Deci nota **pe antetul
|
||
documentului** nu e o ipoteza, e un mecanism in uz.
|
||
|
||
**Ce inseamna asta pentru #13, si de ce e o decizie de produs, nu una tehnica.** Tiparul „nota pe antet"
|
||
ar fi **mai simplu decat reteta in 4 pasi**: n-ar mai fi nevoie nici de gasirea politicii, nici de
|
||
inserarea articolului in ea, nici de politica tehnica — antetul ar purta nota, iar liniile ad-hoc ar
|
||
moșteni-o. **Dar cere cod nou in `pack_facturare`**, pentru ca `contabilizeaza_rata` trateaza rate, nu
|
||
articole de factura. Adica **incalca exact decizia 27-bis** („`pack_facturare` nu se atinge").
|
||
**Deci alegerea e a lui Marius, intre trei variante:**
|
||
|
||
1. **reteta in 4 pasi** (decizia 27-bis respectata, `pack_facturare` neatins, dar cere politica tehnica per
|
||
`SCC` si o interogare inversa noua);
|
||
2. **nota pe antet ca la `contabilizeaza_rata`** (mult mai simplu si mai curat conceptual, dar **relaxeaza
|
||
decizia 27-bis** — cod nou in pachetul comun intregii suite);
|
||
3. **nota pe antet doar ca fallback** pentru articolele fara politica, lasand restul neschimbat.
|
||
|
||
**Nu se implementeaza nimic pana la aceasta alegere.** Detalii: `idpol_comanda_contract.md`, sectiunea E-bis.
|
||
|
||
**Doua observatii din date, gasite la confirmarea verdictului:**
|
||
|
||
- **Precedentul cerut de decizia 27 exista deja in producție, si e mai bun decat `gnId_pol_pret_stoc`.**
|
||
Politica `7 DISCOUNT` apare pe **870 de linii de comanda** si trimite la nota `2 DISCOUNT`
|
||
(`SCD = 667`, `SCC = 4111`). E o politica de pret folosita **exclusiv ca mecanism de rutare contabila**,
|
||
nu ca lista comerciala de preturi. Deci „politica tehnica, dedicata unui cont, populata automat" nu e o
|
||
invenție a lui #13 — **produsul o face deja**, pentru discount. Argument direct pentru politica tehnica
|
||
per `SCC`.
|
||
- **Garantia prin construcția listei nu e etanșă in date: 37 de linii de comanda au un articol care NU e
|
||
membru al politicii de pe linie.** **VERIFICAT (runda 10)** —
|
||
`docs\cercetare\linii_comanda_articol_nemembru.md`. **Decizia 32 NU se redeschide in sensul periculos:
|
||
nu exista cale de cod care sa ocoleasca `FACT-024`.** Patru rezultate:
|
||
- **Cifra 37 se reconfirma, dar numitorul din plan era gresit** — `6868` era alt numitor; cel corect
|
||
pentru linii cu `ID_POL NOT NULL` e **7108**.
|
||
- **Premisa „37 de linii ar cadea la facturare" era partial gresita.** Un rand cu `CANTITATE < 0` **nu
|
||
dovedeste ca linia a fost facturata**: singurul loc care il insereaza e `inchide_comanda`
|
||
(`PACK_FACTURARE:5769-5820`), care scrie *diferenta ramasa* la **inchiderea** comenzii, chiar si cand
|
||
nimic nu s-a facturat pe acea linie. **34 din 35 de linii negative n-au nicio factura in spate, nici
|
||
macar stearsa** — comenzile au fost inchise, nu facturate.
|
||
- **Una singura chiar a ajuns intr-o factura emisa** — comanda `497`, articolul `4294507522`
|
||
(„VOUCHER DISCOUNT") pe politica `7` („DISCOUNT"), in factura `ID_VANZARE = 1028`, `20.03.2026`. Si
|
||
codul **chiar a rulat** `contabilizeaza_articol` pentru ea: apelul e in ramura `ELSE` a lui
|
||
`CASE pack_facturare.ntip` din `scrie_factura2`, care exclude doar transferurile, avizele de custodie
|
||
si facturile cu rate — tipul 3 cade in `ELSE`. Deci **fie articolul era membru al politicii la
|
||
20.03.2026 si a fost scos ulterior, fie verificarea a fost ocolita altfel; dovada pentru a doua
|
||
varianta nu exista.**
|
||
- **Cauza e NEDETERMINABILA DIN DATE, structural.** `CRM_POLITICI_PRET_ART` **n-are coloana `STERS`** si
|
||
n-are tabel de istoric — stergerile sunt **fizice, fara urma**, deci nu se poate reconstitui starea de
|
||
la 20.03.2026. Coloanele de audit ale facturii (`VANZARI.ID_UTILS` / `DATAORAS` si cele de pe cele
|
||
doua linii) sunt **toate NULL**, deci nici o editare ulterioara nu s-a inregistrat. Indiciu de tipar,
|
||
nu dovada: aceeasi pereche articol-politica apare pe **35 de comenzi diferite**, ceea ce sustine o
|
||
**curatare de catalog** mai degraba decat 35 de greseli independente de introducere.
|
||
|
||
**Ce ramane, si cum se formuleaza:** pentru celelalte 36 de linii, „zero facturi in date" **nu
|
||
demonstreaza ca nu se pot factura** — demonstreaza doar ca nu s-a intamplat. Iar cu starea de azi a lui
|
||
`CRM_POLITICI_PRET_ART`, toate cele 37 **ar** cadea cu `FACT-024` daca ar trece acum prin
|
||
`contabilizeaza_articol` (verificat pe view-ul `VCRM_POLITICI_PRET_ART`, care n-are filtru propriu, deci
|
||
vede exact aceleasi perechi ca tabelul). **Concluzia pentru #13 e neschimbata:** garantia prin
|
||
constructia listei e reala cat timp catalogul nu se editeaza sub documente deja emise.
|
||
|
||
**Verificarile pe baza vie sunt facute** (10.08.2026) — `docs\cercetare\verif_baza_vie_cont_venit.md`:
|
||
interogarea inversa pe fiecare `SCC` candidat, DDL-ul lui `CORESP_CONT_VENCHELT`, distributia articolelor
|
||
pe ramurile deciziei 27 (6125 din 6430 pe ramura gestionabila), efectele colaterale ale pasului 3 si trei
|
||
fragilitati de structura. **Rămâne deschisa doar partea de cod**, listata mai sus.
|
||
|
||
### K. Discountul pe linie (decizia 14)
|
||
|
||
Verificat de doua ori, pe formularul real si pe DDL. Raspunsul la intrebarea „e doar procentual?” e
|
||
**nu, si nici doar valoric — sunt amandoua, dar in alta fereastra**.
|
||
|
||
**Intrarea pentru operator exista deja, in dialogul de articol.** `frm_articol_factura`
|
||
(`ofacturare.vc2:1108-2659`), deschis la fiecare adaugare de articol, are trei campuri legate:
|
||
`Clb_procent_discount` (procent), `Clb_discount_unitar` (suma, in lei sau valuta) si
|
||
`Clb_discountctva` (varianta cu TVA). Toate cheama
|
||
`frm_articol_factura.do_calculeaza_discount(valoare, tip)` (`:1874-1976`) cu `tip = 1` procent,
|
||
`tip = 2` lei, `tip = 3` valuta (`:2602-2649`) — tastezi in oricare, se recalculeaza celelalte.
|
||
Rezultatul intra in `poArticol.discount_unitar` si variantele lui, apoi in `crsfactura` prin
|
||
`Replace` (`:12956-12957`).
|
||
|
||
**Se stocheaza o singura coloana, si e valoare.** `VANZARI_DETALII.DISCOUNT_UNITAR NUMBER(22,6)`
|
||
(`ff_2024_06_13_02_COMUN_FACTURARE.sql:3`; simetric pe `VANZARI_DETALII_TEMP` la `:9` si pe
|
||
`CRM_POLITICI_PRET_ART` la `:16` — **trei tabele diferite, nu aceeasi coloana de trei ori**).
|
||
**Nu exista coloana de procent** pe `VANZARI_DETALII` — procentul e doar mod de introducere.
|
||
Parametru Oracle: `V_DISCOUNT_UNITAR` in `adauga_articol_factura`
|
||
(`ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql:4986`), scazut din pretul fara TVA inainte de TVA
|
||
(`:15794-15847`).
|
||
|
||
**In grid, azi, comportamentul e inconsecvent.** Pe factura in lei ramane `cDiscountCTva`, care e
|
||
`ReadOnly = .T.` (`ofacturare.vc2:12311-12317`); pe factura in valuta ramane `cVdiscountftva`, care
|
||
**e editabila** — dar nu are niciun `Valid` / `InteractiveChange`, deci o editare directa in celula
|
||
schimba valoarea bruta fara sa refaca totalurile. Excluderea reciproca e la `:15269-15278`.
|
||
|
||
**Corectie fata de runda 3:** afirmasem ca prototipul are deja procent pe linie, ca argument pentru
|
||
pornirea de la el. **Fals.** `procdisc` apare o singura data in tot fisierul, ca `ControlSource` de
|
||
coloana (`:16721`), fara niciun `Replace` care sa-l populeze si fara corespondent Oracle — e schela
|
||
moarta. (Restul aparitiilor de „procdisc” sunt variabila de optiune `gnMemProcDisc`, altceva.)
|
||
Argumentele pentru prototip raman celelalte doua: controalele de antet si butoanele deasupra gridului.
|
||
|
||
**Ce ramane de facut:**
|
||
|
||
- cele doua campuri din dialogul de articol devin **coloane in grid** — procent si valoare unitara —
|
||
cu **acelasi calcul reciproc** din `do_calculeaza_discount`, mutat pe evenimentele coloanelor;
|
||
- se repara astfel si inconsecventa de mai sus: aceleasi validari in ambele monede;
|
||
- se pastreaza excluderea pe `in_valuta`;
|
||
- modelul de date **nu se atinge**;
|
||
- **de verificat separat, blocant**: daca `discount_unitar` apare pe rapoartele `.frx` si daca e
|
||
transmis in eFactura (UBL) si SAF-T. Daca nu apare pe hartie, documentul tiparit nu explica totalul.
|
||
|
||
#### K-bis. Discountul de DOCUMENT — cota, explicatia si atribuirea pe cote
|
||
|
||
Cercetare terminata, verificata la sursa (doua runde, a doua a corectat concluzii ale primei —
|
||
vezi rezervele de mai jos). Detaliu complet: `docs\cercetare\discount_document_cota_tva.md`.
|
||
|
||
**Cota discountului de document = cota MAXIMA de pe factura, ca regula implicita.** Nimeni n-o
|
||
alege: nu exista control in formular si nicio coloana pe `VANZARI` pentru ea.
|
||
`Calculate Max(proc_tvav)` — `COMUN\programe\oproceduri_facturare.prg:1387`,
|
||
`COMUN\clase\ofacturare_comun.vc2:4495` si `:7294`, `COMUN\programe\ofacturare_stoc.prg:582`.
|
||
Discountul intra ca **pseudo-linie negativa** printr-un rand-sentinela `Replicate('Z',20)`
|
||
(`COMUN\programe\ofacturare_comun.prg:1886-1897`), care devine linia „Discount NN.NN % Factura"
|
||
(`:1273-1392`).
|
||
|
||
**Explicatia nu exista ca notiune — e o constanta.** In XML, `AllowanceChargeReason="Discount"`
|
||
si `ReasonCode="95"` sunt hardcodate (`COMUN\programe\xmlefactura.prg:774-776`), la fel
|
||
`currencyID="RON"` (`:778`). Textul construit in VFP („Discount 10.00 % Factura") nu ajunge in
|
||
XML.
|
||
|
||
**Regula e implementata de doua ori, independent — nu intr-un singur loc.** In VFP (mai sus) si
|
||
in PL/SQL: `PACK_FACTURARE.recalculeaza_totaluri_vanzari`,
|
||
`MAX(ROUND(discount*(a1.proc_tvav-1),...)) as DISC_TVA_RON` —
|
||
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16081-16092`,
|
||
scris in `VANZARI.DISCOUNT_TVA` si de acolo in `TOTAL_TVA` / `TOTAL_CU_TVA` (`:16214-16227`).
|
||
**Pentru #13: doua locuri de schimbat, nu unul** — daca se schimba doar unul, `VANZARI.TOTAL_TVA`
|
||
si TVA-ul din XML diverg pe facturile cu cote mixte.
|
||
|
||
**Defectul dovedit e de atribuire fiscala, nu de validare.** Pe cote mixte, tot TVA-ul
|
||
discountului se scade din cota maxima. Exemplu: 1000 lei la 21% + 1000 lei la 11%, discount de
|
||
document 10% (200 lei) → se declara 10 lei TVA in minus, mereu in acelasi sens (TVA colectat
|
||
subdeclarat). Aceeasi valoare gresita ajunge si in nota contabila si in jurnalul de TVA. Caz-limita
|
||
real, masurat: daca liniile de la cota maxima sunt o mica parte din total, `TaxSubtotal` iese cu
|
||
baza negativa (`TaxableAmount = -410.00`).
|
||
|
||
**Ipoteza bazei negative — verdict nuantat, asa cum a iesit din verificare, nu simplificat.**
|
||
Temerea: pseudo-linia, avand `id_jtva_coloana = 0`, iese din `LEFT JOIN` cu `coloana_jv` NULL si
|
||
formeaza grup propriu in `C_TVA_FACTURA`. **Infirmata pe factura obisnuita** — masurat headless,
|
||
`IIF()` din VFP intoarce ramura falsa, nu `.NULL.`, cand conditia e nula, deci pseudo-linia se
|
||
contopeste corect. **Confirmata insa pe facturile scutite / taxare inversa / intracomunitare**,
|
||
unde liniile reale au `scutit = 1` si `expltva` completat iar pseudo-linia are `0` si gol: apar
|
||
doua grupuri, deci un `TaxSubtotal` in plus cu baza negativa si categoria `Z`, iar
|
||
`agettipcota(1)` (`xmlefactura.prg:782-786`) devine ambiguu intre `E` si `Z`.
|
||
|
||
**Nu blocheaza factura — validat, nu presupus.** Validat offline cu DUKIntegrator, 6 scenarii,
|
||
inclusiv un control negativ care chiar iese cu erori (`BR-CO-13` + `BR-CO-15`) — deci cele „ok"
|
||
inseamna ceva. Trece inclusiv un caz cu `TaxableAmount = -400.00`. Regulile pe categorii
|
||
(`BR-S-08` / `BR-E-08` / `BR-Z-08`) se satisfac trivial: aritmetica inchide, modelarea fiscala e
|
||
cea gresita, si asta niciun schematron nu prinde. **Rezerva de scris explicit:** validatorul local
|
||
e din 2022; validatorul ANAF online n-a fost apelat (interdictie).
|
||
|
||
**`currencyID="RON"` hardcodat e neconformitate reala si activa, dar fara dovada ca ar cauza
|
||
respingere.** Dovedit pe fisier: XML-ul in EUR de la VENDING_MASTER e identic pe SHA256 cu cel din
|
||
`TRIMISE` (deci exact ce a plecat la ANAF) si a fost acceptat. Respingerea din `ERORI` e a unei
|
||
incarcari anterioare, pentru alte reguli.
|
||
|
||
**Nu s-a putut proba pe date reale, si asta ramane netransat.** In baza accesibila sunt 3 facturi
|
||
cu discount de document (toate cu o singura cota, anterioare eFacturii) si 34 cu cote mixte fara
|
||
discount — intersectia e goala. Cele 4 XML-uri de productie cu alocare de document sunt, dupa trei
|
||
indicii independente, discounturi pe linie, nu de document. Absenta din date nu e dovada (regula
|
||
casei). Ramane nedovedit prin rulare: reproducerea end-to-end prin program a scenariului „factura
|
||
scutita + discount de document".
|
||
|
||
**Recomandarea cercetarii pentru #13:** repartizare proportionala automata pe cote, **nu se cere
|
||
utilizatorului cota**. Discountul de document nu are o cota proprie de ales — natura lui de TVA e
|
||
determinata de liniile pe care le reduce; a pune operatorul sa aleaga inseamna a-i cere o decizie
|
||
fiscala pe care datele o dau deja. Pentru explicatie: un singur camp text optional pe document,
|
||
folosit ca `AllowanceChargeReason` in locul constantei (`ReasonCode` ramane `95`).
|
||
|
||
**Doua completari obligatorii daca se implementeaza, altfel reparatia e degeaba:**
|
||
- bucatile de discount trebuie sa primeasca **`id_jtva_coloana` al grupului pe care il reduc**, nu
|
||
doar cota — cheia de grupare are cinci campuri si `expltva` se completeaza tot prin
|
||
`id_jtva_coloana`. O implementare care seteaza doar `proc_tva` lasa grupul orfan exact unde e azi;
|
||
- **eFactura nu are nevoie de nicio modificare** — `xmlefactura.prg:758-792` grupeaza deja
|
||
`GROUP BY proc_tva` si emite cate un `AllowanceCharge` per cota.
|
||
|
||
Doua consecinte vizibile daca se implementeaza: factura tiparita va arata N randuri „Discount X %
|
||
Factura" in loc de unul, si nota contabila primeste TVA-ul discountului spart pe cote.
|
||
|
||
**Decizia a fost luata — decizia 59 (runda 16): repartizare proportionala pe cote.** Vezi sectiunea
|
||
„Decizia 59" de la deciziile rundei 16, cu toate consecintele de implementare.
|
||
|
||
**Cele doua puncte ramase s-au inchis si ele, tot in runda 16.** Campul text optional de motiv —
|
||
**decizia 61**: da, se adauga (`AllowanceChargeReason`, `ReasonCode` ramane `95`), cu stocare noua
|
||
pe `VANZARI` si un control nou in formular. Asezarea lui s-a inchis in runda 17 — **decizia 66**: sta in banda de totaluri, langa discount. Retroactivi-
|
||
tatea la relistare/retrimitere — **decizia 62**: restrictia de modificare e strict `EsteInEFactura`,
|
||
fara legatura cu nicio data; ramane insa deschis, separat, cazul relistarii (nu editarii) unei
|
||
facturi vechi deja trimise, vezi decizia 62.
|
||
|
||
### M. Valuta si data cursului (decizia 15)
|
||
|
||
**Cele doua concepte exista in cod, distinct** — decizia 15 nu introduce o distinctie noua, o face
|
||
vizibila:
|
||
|
||
- **(a) factura in valuta**: `poDate.in_valuta` / `Curs` / `multiplicator` / `id_valuta`, un singur
|
||
curs pentru tot documentul;
|
||
- **(b) articol cu pret in valuta pe document in lei**: `poArticol.tip_valuta = 1`, proprietate a
|
||
politicii de pret, independenta de `in_valuta`. Conversia se face **in VFP**, cu cursul zilei:
|
||
`poArticol.pretftva = Round(poArticol.pretftva_val * poArticol.Curs / poArticol.multiplicator, gnPPretV)`
|
||
(`ofacturare.vc2:1989`, `:2017`, `:2953`). Cursurile zilei se incarca exact pe ramura „document in
|
||
lei”: `If poDate.in_valuta = 1 ... Else citeste_cursuri_zi(poDate.zi_curs)` (`ofacturare.prg:407-418`).
|
||
|
||
**In baza, exact cum ai descris:** `VANZARI_DETALII` **nu are coloana `CURS`**; pastreaza `PRET` (in
|
||
lei, valoarea de facturare) plus `PRETD` si `ID_VALUTAD` ca urma a pretului original in valuta.
|
||
Cursurile ajung in `VANZARI_CURSURI`, scrise neconditionat la emitere pentru **orice** valuta straina
|
||
aparuta pe linii — deci si pe o factura in lei
|
||
(`PACK_FACTURARE.sql:14491-14501`, `scrie_cursuri`).
|
||
|
||
**`in_valuta` nu e o alegere, e o proprietate a tipului de document.** Se seteaza o singura data, in
|
||
`Init`: `If Inlist(tnIdSet,223,225,226,227,271) OR INLIST(m.tnTip, 5,6,7,9,10,52) -> .in_valuta = 1`
|
||
(`ofacturare_comun.prg:248-250`), si nu se mai schimba. Selectorul de valuta e chiar eliminat din
|
||
formular cand `in_valuta = 0` (`ofacturare.vc2:9725-9728`), deci operatorul nici nu-l poate alege.
|
||
|
||
**Problema semnalata, confirmata:** `Clb_zi_curs` e eliminat **doar** pe retur (tip 8, 9), la
|
||
`ofacturare.vc2:9717-9722` — si niciodata in functie de valuta, desi blocul imediat urmator,
|
||
`:9725-9728`, face exact asta pentru selectorul de valuta. Deci **azi campul apare si pe facturi in
|
||
lei**, unde de multe ori nu are ce cauta. Validarea e la randul ei asimetrica: `frm_date_factura`
|
||
cere ziua cursului doar cand `in_valuta = 1` (`:9484`), dar `frm_date_aviz_lucrare` o cere
|
||
**neconditionat** (`:8076`).
|
||
|
||
**Regula propusa:** campul apare cand tipul nu e retur **si** (documentul e in valuta **sau** exista
|
||
pe document macar un articol cu pret in valuta).
|
||
|
||
**Unificarea face regula posibila.** Azi cazul (b) nu se poate sti la deschiderea antetului — se
|
||
afla abia dupa incarcarea articolelor, cand antetul e deja inchis si eliberat (`Release
|
||
ofrmceredate`, `ofacturare.prg:248`). In formularul unificat antetul si gridul sunt in aceeasi
|
||
fereastra, deci campul poate aparea in clipa in care intra pe grid primul articol cu pret in valuta.
|
||
**Din acelasi motiv dispare si mecanismul lui #16**: bug-ul de focus si de renumerotare apare la
|
||
revenirea din `frm_curs` intr-un antet care tocmai s-a inchis — in formularul unificat nu mai exista
|
||
un antet inchis la care sa te intorci. `frm_curs` e in `COMUN\clase\onom_curs.vc2:537`, deschis din
|
||
`vizualizeaza_curs` (`oproceduri_curs.prg:8-42`) ca recuperare la eroarea Oracle 20005
|
||
(`ofacturare.prg:313-317`).
|
||
|
||
**Capcana:** `poDate.zi_curs` se trimite **neconditionat** ca prim parametru catre `cursor_preturi` /
|
||
`cursor_articole_k` / `cursor_gestiune` / `cursor_lucrare` (`ofacturare.prg:272-303`), inclusiv pe
|
||
tip 1. Ascunderea campului nu inseamna golirea valorii — valoarea implicita (data documentului)
|
||
trebuie sa ramana. Iar pe avizul de lucrare, ascunderea fara repararea validarii de la `:8076` ar
|
||
bloca finalizarea antetului cerand un camp care nu mai e pe ecran.
|
||
|
||
### N. Returul din facturi anterioare (decizia 17)
|
||
|
||
Rapoarte: `docs\cercetare\factura_retur_document.md` (mecanismul principal) si
|
||
`retur_si_lista_preturi.md`, A (al doilea mecanism).
|
||
|
||
**Sunt doua fluxuri de cod independente**, care ating aceeasi clasa de formular prin metode si
|
||
proceduri Oracle diferite. Nu au niciun punct comun in afara conventiei de semn a cantitatii.
|
||
|
||
#### N.1 Factura de retur ca document (tipurile 8, 9 — si avizul de retur, 24)
|
||
|
||
**Asta e mecanismul pe care il descrie Marius, si functioneaza deja cap-coada.**
|
||
|
||
- **Intrare:** tile-ul de pe ecranul de facturare (`ofundal_facturare.vc2:882-884`) -> `politica.mpr`
|
||
-> `factureaza(8)` / `factureaza(9)` (`Meniuri\politica.mn2:14-15, 45-46`).
|
||
- **Alegerea facturilor, la nivel de document:** `frm_date_factura.do_cauta_facturi`
|
||
(`ofacturare.vc2:9173-9212`) cheama `caut_facturi_multiple_client`
|
||
(`oproceduri_facturare.prg:2091-2121`) — browse cu **selectie multipla**, titlu „Alegeti facturile
|
||
(mouse-click pe numar sau apasati SPACE)”. Filtrare pe **client** (obligatoriu ales inainte) si
|
||
**valuta**; sursele exclud tipurile de retur, deci nu se face retur dintr-un retur. Id-urile alese
|
||
se aduna intr-un CSV in `poDate.listaid`, numerele in `poDate.descriere`, iar antetul primeste
|
||
automat textul „RETUR FACTURA …”. Fara alegere nu se poate continua (`:9523-9526`).
|
||
- **Popularea liniilor:** `pack_facturare.cursor_retur` -> `cursor_retur_document`
|
||
(`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:3943-3956`, `:3958-4071`) selecteaza direct din
|
||
`VANZARI_DETALII` liniile facturilor alese si le pune in acelasi `crsarticole` pe care celelalte
|
||
tipuri il umplu cu lista de preturi (`ofacturare.prg:306-311`). **Confirmat exact ce spunea Marius:**
|
||
`ID_GESTIUNE` vine din linia originala (`:4034`, `:4055`), `PRET_ACHIZITIE` la fel, **neschimbat**
|
||
(`:4035`, `:4056`), iar pretul de vanzare se recalculeaza pe curs doar daca moneda nu e nationala
|
||
(`:4016-4030`). `GESTIONABIL` e `NVL2(A1.ID_GESTIUNE,1,0)` — gestionabil doar daca originalul avea
|
||
gestiune.
|
||
- **Ce se poate face manual:** **stergerea liniilor aduse merge** si cantitatea redevine disponibila
|
||
in cursorul sursa (`do_sterge`, `ofacturare.vc2:14608-14693`, ramura de retur la `:14658-14659`);
|
||
**returul partial merge** (`do_verifica_articol`, `:14743-14754`, fata de maximul calculat pe
|
||
server).
|
||
- **Avizul de retur (24)** foloseste acelasi `cursor_retur` si aceleasi ramuri; difera doar antetul —
|
||
`nIdTipDoc = 6` si `frm_date_aviz` in loc de `frm_date_factura` (`ofacturare.prg:194-195`, `:225`).
|
||
|
||
**Singurul gol real, si e acelasi ca la comanda:** pe un document de retur **nu se poate adauga o
|
||
linie din afara facturilor sursa**, pentru ca `crsarticole` **este** rezultatul lui `cursor_retur`
|
||
(`do_adauga_articol` ia articolul mereu din el, `ofacturare.vc2:12843-12851`). Nu e o interdictie
|
||
explicita, e continutul cursorului — exact cauza de la comanda (J). Se rezolva la fel, prin
|
||
`APPEND FROM`, si abia asta face reala decizia 16 pe documentele de retur.
|
||
|
||
#### N.2 Retur de articole intr-o factura de vanzare normala (`But_retur`)
|
||
|
||
Butonul (`cmd_butoane.vc2:324-338`, `caction = do_retur`) e vizibil **doar** pe tipurile 1, 5, 7, 10
|
||
(`ofacturare.vc2:15122-15127`) — pe un document de retur nu exista deloc. Aici factura sursa se alege
|
||
**per articol**, la fiecare linie: `caut_facturi_multiple_client_articol`
|
||
(`oproceduri_facturare.prg:2124-2159`), filtrat suplimentar pe articolul curent. Perechile
|
||
`ID_ARTICOL:ID_VANZARE` se acumuleaza in `thisform.cListaIdArticoleRetur` (`:12888`) si pleaca ca
|
||
`poDate.listaid` (`:13977-13979`). Gestiunea se alege prin
|
||
`pack_facturare.cursor_gestiuni_articol_retur`, nu vine din factura sursa — **diferenta de fond fata
|
||
de N.1**.
|
||
|
||
**Legatura linie-de-retur -> linie originala: neverificat** pe schema. In VFP nu exista coloana de
|
||
linie sursa; la nivel de antet exista `poDate.nid_vanzare_retur` (`ofacturare.vc2:14448`, `:14509`).
|
||
Conteaza doar pentru **afisare** — daca formularul poate arata din ce factura vine fiecare linie.
|
||
|
||
#### N.3 Ce se schimba in formularul unificat
|
||
|
||
- **N.1 se muta ca atare.** Alegerea facturilor devine o optiune in meniul butonului de adaugare
|
||
(„Alege facturile de returnat…”), cu acelasi dialog, aceleasi filtre si aceeasi populare din
|
||
`cursor_retur`. **Nu se reproiecteaza nimic din ce merge**, si in special nu se atinge preluarea
|
||
gestiunii si a pretului de achizitie din facturile originale.
|
||
- **N.2 capata si alegerea la nivel de document**, dupa modelul lui N.1, pastrand calea per-articol
|
||
pentru cazul cu un singur articol.
|
||
- **Lista de preturi devine disponibila si pe documentele de retur** (decizia 16), prin acelasi
|
||
`APPEND FROM` ca la comanda. Consecinta de proiectat: pe acelasi document vor coexista linii
|
||
aduse din facturi sursa (cu gestiune si pret de achizitie mostenite) si linii libere, care nu au
|
||
factura sursa.
|
||
**Decizia 22 (Marius, 09.08.2026): linia de retur fara factura originala e permisa, ca pe orice alt
|
||
document.** Returul nu face exceptie de la regula deciziei 16 — sursa umple documentul, nu il
|
||
inchide, si nici nu apare doar „pentru corectii”. Consecintele de proiectat, acum ferme:
|
||
- **gestiunea si pretul de achizitie nu se pot mosteni** pe o linie libera, pentru ca nu exista linie
|
||
originala. Se aleg, ca la N.2 (`cursor_gestiuni_articol_retur`), nu se preiau ca la N.1;
|
||
- **maximul returnabil calculat pe server nu se aplica** unei linii fara factura sursa — nu exista
|
||
cantitate originala fata de care sa se limiteze;
|
||
- afisarea „din ce factura vine linia” trebuie sa suporte si valoarea goala (vezi mai sus, legatura
|
||
linie-de-retur -> linie originala, inca neverificata pe schema).
|
||
|
||
*De pastrat cum e:* excluderea returului dintr-un retur, filtrarea pe client si valuta, maximul
|
||
returnabil calculat pe server, si mostenirea gestiunii si a pretului de achizitie. Nu se ating.
|
||
|
||
### O. Facturile din ROAAUTO (decizia 18)
|
||
|
||
Raport: `docs\cercetare\roaauto_facturi.md`.
|
||
|
||
> **Precizare la descrierea liniilor de mai jos.** „Liniile unei facturi ROAAUTO nu sunt articole” e
|
||
> adevarat doar pentru liniile **generate din deviz**. Langa ele pot sta articole reale, adaugate
|
||
> prin mecanismul **„Alte servicii”** — vezi O-bis, verificat pe cod
|
||
> (`docs\cercetare\roaauto_articole_lista_preturi.md`). Restul sectiunii ramane valabil: tipul `-12`,
|
||
> drumul comun prin `PACK_FACTURARE`, faptul ca editorul lui #6 le vede, si blocarea modificarii
|
||
> dupa facturare — ultima **reconfirmata**.
|
||
|
||
**Ce se confirma.** ROAAUTO nu are cale proprie spre baza: `factureaza_deviz`
|
||
(`ROAAUTO\Programe\oproceduri_devize.prg:846`) cheama acelasi `PACK_FACTURARE` partajat —
|
||
`initializeaza_date_factura` (`:1211`), `adauga_articol_factura_deviz` (`:1240`), `oscrie_in_fisiere`
|
||
(`:1269`), `scrie_in_vanzari` (`:1302`) — deci liniile trec prin acelasi `VANZARI_DETALII_TEMP` si
|
||
ajung in acelasi `VANZARI_DETALII` ca orice factura ROA. Tipul documentului e **`-12`**
|
||
(`:922`). Editorul lui #6 le vede deja, fara cod de recunoastere a sursei, verificat pe date reale
|
||
(`id_vanzare = 1047`). **Deci partea de „le vede” e gratuita.**
|
||
|
||
**Ce nu se confirma — si asta schimba dimensiunea deciziei.** „Se pot modifica ulterior” **nu e
|
||
adevarat azi, in niciun produs**:
|
||
|
||
- in ROAAUTO, formularul de devize isi dezactiveaza butonul de modificare de indata ce comanda are
|
||
numar de factura (`oviz_devize.vc2:4536`); singura actiune post-facturare gasita e re-listarea
|
||
(`oproceduri_devize.prg:1516`), care nu scrie nimic. Niciun apel din ROAAUTO catre
|
||
`modifica_date_factura`;
|
||
- in ROAFACTURARE, gridul de articole din editorul nou (`frm_modific2024`, `COMUN\clase\omodificari.vc2`)
|
||
e **read-only prin design**, la nivel de grid si pe fiecare `Text1`.
|
||
|
||
Deci decizia 18 nu extinde o cale existenta, **creeaza o capacitate care nu exista nicaieri**.
|
||
|
||
**Cum arata liniile.** `factureaza_deviz` agrega sumele devizului si insereaza cate o linie sintetica
|
||
per categorie, cu `id_articol` **negativ**: `-100000` MANOPERA (`:965-967`), `-100003` MATERIALE
|
||
(`:947-949`), `-100001` discount manopera, `-100005` / `-100006` avans si stornare avans,
|
||
`-100007` / `-100008` inspectie tehnica si spalare (`:936-1027`). Optional, cu
|
||
`gnAUTOIdArticolReparatii` setat, toate se cumuleaza intr-o singura linie cu un articol real
|
||
(`:989-1004`). Langa ele pot sta **articole reale**, prin „Alte servicii” — vezi O-bis.
|
||
|
||
### O-bis. „Alte servicii” — cum se adauga azi articole reale in ROAAUTO
|
||
|
||
Raport: `docs\cercetare\roaauto_articole_lista_preturi.md`. **Asta e mecanismul de refolosit.**
|
||
|
||
- **Unde:** formularul `frm_incasare_finala` (`ROAAUTO\Clase\oviz_devize.vc2:5435-7143`), aratat **la
|
||
emiterea facturii finale** (`do_factureaza_final`, `:2569`) — nu pe devizul propriu-zis.
|
||
- **Sursa articolelor:** `cauta_nom_articole` pe `vnom_articole_toate`
|
||
(`COMUN\programe\ocautare.prg:1781-1823`), filtrat `in_stoc = 0 and in_crm = 1` si cu id-urile
|
||
sintetice excluse (`oviz_devize.vc2:6539-6580`). **Nomenclatorul brut, si numai articole fara
|
||
stoc** — nu lista de preturi, nu politici.
|
||
- **Pretul se tasteaza manual.** `do_adauga` nu completeaza pretul si cantitatea; operatorul le pune
|
||
in grid, iar `do_modifica_alteserv` recalculeaza valoarea (`:6692-6698`, `:7064-7070`). Nu exista
|
||
preluare automata de pret pe calea asta.
|
||
- **Liniile raman separate.** Cumularea in „REPARATII AUTO” include doar id-urile sintetice
|
||
(`oproceduri_devize.prg:999-1012`); randurile din `crsalteserv` se insereaza dupa, cu `id_articol`
|
||
real, si ajung ca atare in `VANZARI_DETALII_TEMP` (`:1036-1041`, `:1240-1257`).
|
||
- **Gestiune: tot zero.** `id_gestiune` nu e completat de niciun `INSERT` si pleaca `0` spre Oracle
|
||
(`:1201-1206`, `:1255`) — consistent cu filtrul `in_stoc = 0`. Deci **nici articolele reale din
|
||
ROAAUTO nu descarca gestiune**. Diferenta fata de liniile sintetice e doar `id_articol`.
|
||
- **Stergere si modificare:** exista, dar **doar cat timp formularul e deschis, inainte de emitere**
|
||
(`do_sterge`, `:6730-6741`).
|
||
- **Contul pleaca gol.** `crsvanztemp` are coloana `Cont c(4)`, dar `INSERT`-ul care il umple nu o
|
||
include (`oproceduri_devize.prg:1190-1206`); apelul trimite literal `''` (`:1256`), care ajunge
|
||
`NULL` in `VANZARI_DETALII_TEMP.CONT`, fara `NVL` si fara fallback. Deci **liniile de articole reale
|
||
din ROAAUTO se scriu azi fara cont** de gestiune, tacut. Vezi J-bis.
|
||
- **Si fara politica de pret — dar pe alta cale decat credeam.** `id_pol` lipseste peste tot pe firul
|
||
asta (nu e nici in `crsalteserv`, nici in `crsvanztemp`, nici in semnatura lui
|
||
`adauga_articol_factura_deviz`). **Motivul pentru care asta nu produce `FACT-024`** e ca fluxul
|
||
ROAAUTO **nu trece prin `contabilizeaza_articol`**: merge pe `scrie_in_vanzari`, care nu genereaza
|
||
nicio nota de venit. Vezi **J-ter**.
|
||
|
||
> **Corectie importanta la temeiul deciziei 18.** Ideea ca „«Alte servicii» face deja jumatate din ce
|
||
> cerem, deci se generalizeaza” **nu se sustine**. Mecanismul acela functioneaza tocmai pentru ca
|
||
> ocoleste contabilizarea de venit; generalizat pe fluxul ROAFACTURARE, unde `contabilizeaza_articol`
|
||
> **este** apelata (`scrie_factura2`, `ff_...:6150`), s-ar lovi de `FACT-024`. Ce ramane valabil din
|
||
> O-bis e descrierea UI (articole reale langa linii sintetice, pret tastat, fara gestiune) — nu si
|
||
> concluzia ca partea grea e deja rezolvata.
|
||
|
||
**Ce inseamna asta pentru decizia 18.** Doua lucruri, in directii opuse:
|
||
|
||
- **usureaza** partea de model: un articol real langa linii sintetice **nu e o noutate**, e deja
|
||
cazul normal al facturilor auto. Intrebarea „cum coexista” are deja un raspuns in produs;
|
||
- **nu rezolva** cerinta: mecanismul traieste in formularul de emitere al ROAAUTO si moare odata cu
|
||
el. Ce cere Marius e aceeasi capacitate **la modificare**, care nu exista nici acolo, nici aici.
|
||
|
||
**Intrebarile ramase, in ordinea in care blocheaza:**
|
||
|
||
1. ~~**Ce se intampla cu totalul devizului**~~ — **RASPUNS (runda 7)**, raport
|
||
`docs\cercetare\pack_auto_actualizeaza_deviz.md`. Premisa intrebarii era gresita: **nu exista niciun
|
||
`SUM` peste `VANZARI_DETALII`, pentru ca `PACK_AUTO` nu citeste deloc `VANZARI` /
|
||
`VANZARI_DETALII`** — zero potriviri pe `VANZARI` in tot pachetul (1804 linii).
|
||
`actualizeaza_deviz` (`ff_2026_03_31_02_AUTO_PACK_AUTO.sql:692-733`) face trei lucruri, toate pe
|
||
structura proprie ROAAUTO: scrie cota TVA pe `DEV_ORDL`, stampileaza `ID_FACT` pe `RUL`, si — doar
|
||
pe anumite `id_set` — pe `NOM_LUCRARI`. E o legatura **deviz -> document**, nu un recalcul
|
||
**document -> total deviz**. Nu e nici macar specifica facturarii: aceleasi trei apeluri o
|
||
folosesc si la inchiderea de productie si de regie, care scriu note contabile, nu facturi.
|
||
**Deci o linie noua pe `tip = -12` nu poate dezechilibra nimic pe partea Oracle**, si nu e nevoie
|
||
de niciun apel suplimentar catre ROAAUTO. Precedentul „Alte servicii” confirma pe date live:
|
||
liniile reale coexista de mult cu cele sintetice, fara ca `actualizeaza_deviz` sa faca distinctie.
|
||
**Ce ramane, si e de alt fel:** o **desincronizare de afisare**. Totalul devizului aratat in
|
||
ROAAUTO se calculeaza din `RUL` si din cursoarele de facturare (`oviz_devize.vc2:7816-7823`),
|
||
**niciodata** din `VANZARI_DETALII` — deci nu va arata linia adaugata, nici azi, nici dupa #13.
|
||
In schimb **relistarea o va arata**: `relisteaza_factura_deviz` citeste `fact_vfacturi_detalii`
|
||
(`oproceduri_devize.prg:1564`), un view neconditionat peste `VANZARI_DETALII`
|
||
(`ff_2024_06_04_01_COMUN_FACTURARE.sql:8-94`). Factura retiparita si ecranul de deviz vor spune
|
||
lucruri diferite — **DECIS (decizia 28): e acceptabil.** Cerinta lui Marius e ca **MANOPERA si
|
||
MATERIALE sa fie conform devizului**; restul articolelor pot exista pe factura fara sa apara in
|
||
ecranul de deviz. Nu se cere cod nou in ROAAUTO si nu se mai pune intrebarea.
|
||
2. **Gestiunea, pentru articole cu stoc. DECIS (decizia 20):** se admit si articolele gestionabile.
|
||
ROAAUTO ocoleste subiectul filtrand `in_stoc = 0`; filtrul acela **nu se preia**. Deci pe
|
||
documentele auto vor coexista linii care descarca stoc cu linii care nu descarca — caz nou, de
|
||
proiectat, nu de evitat.
|
||
3. **Cine ramane proprietarul documentului** dupa ce ROAFACTURARE ii adauga o linie — mai poate
|
||
ROAAUTO sa-l relisteze corect (`relisteaza_factura_deviz` citeste din `fact_vfacturi`)?
|
||
|
||
**Reconfirmat:** dupa emitere nu exista cale de intoarcere in ROAAUTO. `verifica_stornare`
|
||
(`oviz_devize.vc2:4513-4514`) e o metoda **goala**; `do_storneaza_avans` priveste doar avansul.
|
||
Singurul instrument gasit asupra unei facturi emise e stergerea totala (soft-delete) prin ecranul
|
||
generic din COMUN — nu o editare.
|
||
|
||
**Secventierea — reevaluata dupa raport (runda 7).** Marius a cerut ca `pack_auto` sa fie cercetat
|
||
inainte de orice estimare (decizia 23), si a avut dreptate: raspunsul **rastoarna recomandarea
|
||
initiala**. Motivul pentru care decizia 18 urma sa se livreze ultima era riscul tehnic de a scrie pe
|
||
un produs pe care #13 nu-l controleaza. **Acel risc nu exista** — `PACK_AUTO` nu citeste `VANZARI` /
|
||
`VANZARI_DETALII` deloc, deci nu are ce sa se dezechilibreze (vezi intrebarea 1 de mai sus).
|
||
|
||
Ce ramane nu mai e risc tehnic, ci **o singura intrebare de produs**:
|
||
1. ~~e acceptabil ca ecranul de deviz sa nu arate linia adaugata din #13~~ — **RASPUNS, decizia 28:
|
||
da, e acceptabil.** Conditia e alta: MANOPERA si MATERIALE conform devizului.
|
||
2. cine ramane proprietarul documentului (intrebarea 3 de mai jos) — nu s-a schimbat.
|
||
|
||
**Decizia 18 nu mai trebuie sa fie ultima din motive tehnice.** Ordinea de lucru din S4g ramane insa
|
||
valabila din alt motiv, mai bun: se face intai pe documentele ROAFACTURARE, unde scrierea e a
|
||
noastra, pentru ca acolo se aseaza mecanismul; `tip = -12` vine dupa, ca **aplicare**, nu ca risc.
|
||
|
||
**Perimetru:** gridul read-only din `frm_modific2024` si `ofacturare_editare.prg` sunt ale lui **#6**.
|
||
Deschiderea lui la scriere nu se face din #13 fara intelegere explicita — un singur scriitor pe fisier.
|
||
|
||
### L. Observatii colaterale, gasite in timpul verificarii
|
||
|
||
Nu fac parte din #13 si nu se repara aici — se semnaleaza ca sa nu se piarda.
|
||
|
||
0-ter. **(runda 9) O nota de vanzari cu set multi-rand inregistreaza venitul si descarca gestiunea de N
|
||
ori.** In `pack_facturare.contabilizeaza_articol`, `cursor_articol` face `LEFT JOIN NOTE_CONTABILE D ON
|
||
C.ID_SET = D.ID_SET` **fara `ROWNUM`, fara agregare, fara filtru**
|
||
(`ff_2026_08_09_01_...:7218-7271`), iar bucla care il consuma (`:7393-7542`) executa `scrie_nota`
|
||
**si** `descarca_gestiune` **o data pentru fiecare rand al setului, cu aceeasi cantitate si acelasi
|
||
pret intreg** — nu impartite. Nu exista nicio logica de distributie: `ORDINE` nu apare in tot pachetul.
|
||
Azi nu se manifesta pentru ca toate cele 7 note de vanzari active au exact un rand pe set — dar **30
|
||
din cele 40 de seturi din baza au mai multe, cu maxim 30 de randuri**. Deci e o bomba armata de
|
||
configurare: cine ataseaza unei politici de pret o nota cu set multi-rand obtine **dublare de venit si
|
||
dublare de descarcare de gestiune**, silentios. **E in `PACK_FACTURARE`, adica in COMUN** — se
|
||
semnaleaza, nu se repara din #13. Conteaza direct pentru reteta din J-quater: vezi acolo.
|
||
Sursa: `docs\cercetare\s10_pret_rederivat.md`, „Completare", p. 1 + `verif_baza_vie_cont_venit.md` p. 6.
|
||
0-quater. **(runda 9) Politica de pret fara `ID_NOTA` nu are nicio plasa de siguranta.** Spre deosebire de
|
||
articolul lipsa din politica (`FACT-024`), aici nu exista cod de eroare: lantul de `LEFT JOIN` din
|
||
`cursor_articol` supravietuieste inelului lipsa, cursorul intoarce **un rand cu totul `NULL`**, iar
|
||
`scrie_nota` insereaza in `ACT_TEMP` un rand cu conturile de debit si credit **nule**. Daca `ACT_TEMP`
|
||
are `NOT NULL` pe ele, iese un `ORA-01400` generic in loc de un mesaj `FACT-0xx` — **neverificat**,
|
||
DDL-ul lui `ACT_TEMP` nu e in export. Starea exista in baza vie **azi**: politicile active `32 HOTEL
|
||
TAXE` si `33 HOTEL CAZARE` n-au `ID_NOTA`. Independent de #13.
|
||
0-bis. **(runda 7) `do_modifica` pare sa scrie `id_valuta` in loc de `id_sectie`.** In
|
||
`frm_modific2024.do_modifica` (`COMUN\clase\omodificari.vc2:13941`), ramura
|
||
`CASE m.lcControl = 'sectie'` face `replace sectie with loCauta.sectie, id_valuta with
|
||
loCauta.id_sectie`. Daca e ce pare, textul afisat al sectiei se schimba dar coloana `id_sectie`
|
||
nu — si, in plus, se strica `id_valuta`. **Necitit pe date, doar pe cod.** Fisierul e in
|
||
**perimetrul lui #6** (`omodificari.vcx` a intrat in proiect prin `97d1613`) — se semnaleaza acolo,
|
||
nu se repara de aici. Conteaza pentru #13 pentru ca sustine partial verdictul „`ID_SECTIE` e
|
||
editabil": teoretic da, practic poate nu.
|
||
0. **(runda 7) Handler-ul lui `FACT-024` se auto-saboteaza cand `id_pol` e `NULL`.** In
|
||
`pack_facturare.contabilizeaza_articol` (`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7286-7311`),
|
||
ramura `WHEN NO_DATA_FOUND` construieste mesajul cu inca doua `SELECT ... INTO`, dintre care al
|
||
doilea e `FROM CRM_POLITICI_PRETURI WHERE id_pol = detalii_articol.id_pol`. Cu `id_pol` `NULL`,
|
||
**si acel `SELECT` da `NO_DATA_FOUND`**, iar in handler nu exista al doilea nivel de tratare — deci
|
||
utilizatorul primeste un `ORA-01403` generic in loc de mesajul `FACT-024` formatat. Articolul
|
||
apucase sa fie rezolvat, deci informatia nu se pierde de tot, dar diagnosticul e mult mai prost.
|
||
**E in `PACK_FACTURARE`, adica in COMUN** — se semnaleaza, nu se repara din #13. Devine relevant
|
||
direct daca se alege varianta 3 din J-bis.
|
||
1. **`do_copiaza`, ramura de avize: variabila gresita.** La `ofacturare_comun.vc2:3702-3703`, ramura
|
||
`CASE INLIST(loFactura.tip, T21, T24, T26, T30, ...)` scrie `lnTip = T22` in loc de
|
||
`loFactura.tip = T22`, deci degradarea de tip **nu se aplica** pe acea ramura. **Fisierul e in
|
||
perimetrul lui #6** — nu se atinge de aici; efectul nu a fost verificat pe date.
|
||
2. **„Proforma -> factura” merge prin omisiune.** Copierea nu propaga `nIdTipDoc` pentru ca linia e
|
||
comentata (`ofacturare_comun.prg:370`), deci copia unei proforme porneste implicit pe FACTURA.
|
||
Functioneaza, dar ca efect secundar, nu ca ramura dedicata. Daca #13 atinge copierea, merita
|
||
transformat in intentie explicita.
|
||
3. **Asimetria de resetare a globalelor** — vezi „Canalul de precompletare”, mai sus.
|
||
4. **Modificarea in bloc pare sa goleasca campuri pe care nu le-ai atins.** Pe selectie multipla
|
||
(`lnNrInreg > 1`), `do_modifica` face `Scatter Name poRec Memo Blank` si reseteaza explicit ruta,
|
||
delegatul, agentul, masina, `dataora_exp`, `id_facturare`, `listare_detaliata`, `tip_saft`,
|
||
`text_aditional` si `efactura` (`ofacturare_comun.vc2:4565-4580`). Cum acesti zece parametri se
|
||
scriu **neconditionat** in `VANZARI` (I-bis), un `SCAN` peste facturile alese pare sa scrie valorile
|
||
goale pe **fiecare** dintre ele — deci schimbarea rutei pe trei facturi ar sterge delegatul si
|
||
textul aditional de pe toate trei. **De confirmat pe date inainte de a fi numit bug**: e posibil ca
|
||
fluxul sa presupuna ca operatorul completeaza tot ce vrea propagat. **Fisierul e in perimetrul lui
|
||
#6** — se semnaleaza, nu se repara de aici. Conteaza si pentru #13: formularul unificat lucreaza
|
||
pe un singur document si trebuie sa trimita antetul intreg (I-bis, consecinta 1), deci nu
|
||
mosteneste problema.
|
||
|
||
**L.4 (runda 11). Numarul de POS nu se dezaloca la Renunt.** In `frm_alte_date`, la anulare se
|
||
dezaloca numarul de chitanta (16) si cel de bon fiscal (3), dar **nu si cel de POS (26)** —
|
||
`docs\cercetare\s3b_alte_date_analitice.md`, sectiunea 9. Bug preexistent, in productie, **nu introdus
|
||
de #13**. Conteaza pentru S3b pentru ca „`actualizeaza_tipincasare` se muta ca atare" **l-ar propaga
|
||
in formularul unificat**. Se repara in trecere sau se lasa ca azi si se preia separat — punct de decis,
|
||
vezi lista de la finalul rundei 11.
|
||
|
||
---
|
||
|
||
## Stories
|
||
|
||
Ordinea e strict pe risc: unificarea intai (livrabil de sine statator, util si fara regenerare),
|
||
regenerarea peste ea.
|
||
|
||
## Metoda de executie (Marius, runda 14) — obligatorie, nu recomandare
|
||
|
||
**Planul asta e un document de proiectare, nu un plan de executie. La implementare se SPARGE PE
|
||
STORIES, si fiecare story se executa ca livrare de sine statatoare.** Nu se porneste implementarea pe
|
||
tot #13 deodata, nu se acumuleaza modificari nelivrate peste mai multe povesti, si nu se trece la
|
||
povestea urmatoare cu cea precedenta netestata si nerevizuita.
|
||
|
||
### Ce inseamna „spart pe stories"
|
||
|
||
- **O story = o unitate de livrare.** Are perimetru propriu de fisiere, criteriu „gata cand" propriu
|
||
(fiecare story de mai jos il are deja scris) si se incheie cu diff + review + commit propriu.
|
||
- **Inainte de prima linie de cod dintr-o story**, se scrie o **nota de executie** in `docs\` care
|
||
transpune proiectarea in pasi concreti: fisierele atinse, metodele atinse, ordinea editarilor, si ce
|
||
se testeaza dupa fiecare. Proiectarea spune *ce* si *de ce*; nota de executie spune *unde* si *in ce
|
||
ordine*. Rapoartele din `docs\cercetare\` sunt materia prima — nu se reface cercetarea.
|
||
- **Povestile cu dependente declarate** (`*Depinde de:*`, la fiecare story) **nu se pornesc in paralel
|
||
cu cele de care depind.** Unde nu e dependenta, se pot rula in paralel de agenti diferiti — dar
|
||
**un singur scriitor pe fisier**, niciodata doi agenti pe aceeasi metoda.
|
||
- **O story care se dovedeste prea mare la executie se sparge mai departe**, cu acordul lui Marius, si
|
||
se noteaza in plan. Mai bine cinci livrari mici decat una care nu se poate revizui.
|
||
|
||
### Teste la fiecare pas — nu doar la S6 si S12
|
||
|
||
`S6` si `S12` raman testele **pe flux real**, la capatul fiecarei etape. **Ele nu inlocuiesc testarea
|
||
per story.** Fiecare story se incheie cu teste proprii, rulate si trecute, **inainte** de review:
|
||
|
||
- **Harness headless** (`COMUN\docs\depanare_testare_vfp.md`) pentru logica — cazurile minime ale
|
||
povestii, plus **cel putin o proba de neregresie** pe calea veche, care trebuie sa ramana neatinsa.
|
||
- **Harness UI vizibil** (`COMUN\docs\testare-ui-vfp.md`) unde povestea atinge formulare sau griduri —
|
||
coloanele de grid **nu se materializeaza headless**, deci acolo verificarea headless nu e concludenta.
|
||
- **Rezultatul asteptat se declara INAINTE de rulare**, inclusiv pentru cazurile care trebuie sa dea
|
||
eroare. Un test scris dupa ce s-a vazut rezultatul nu dovedeste nimic.
|
||
- **Un esec documentat e livrabil valid** — se raporteaza, nu se ascunde si nu se reia la nesfarsit.
|
||
- Testele fiecarei povesti **se pastreaza**, si intra in suita rulata de S6 / S12. Nu se scriu de
|
||
unica folosinta.
|
||
|
||
### Code review dupa implementare, inainte de commit — pentru fiecare story
|
||
|
||
**Nicio story nu se comite fara review, si review-ul vine dupa implementare si dupa teste, nu in loc
|
||
de ele.** Ordinea, fixa:
|
||
|
||
1. **Implementare** (delegata unui subagent, conform modului de lucru din `CLAUDE.md`).
|
||
2. **Teste** — rulate, trecute, cu rezultatele raportate.
|
||
3. **Diff ca fisier in `docs\`** (`diff_s<N>_<subiect>.patch`), inclusiv partea din `COMUN`.
|
||
4. **Code review pe diff**, de catre **un agent care nu a scris codul** — altfel isi revizuieste
|
||
propriile presupuneri. Review-ul verifica cel putin: regresia pe calea veche, conventiile per zona
|
||
atinsa (`COMUN\docs\reguli_lucru.md`, punctul 7 — encoding `cp1250` la `.vc2`/`.sc2`, `GO` pe
|
||
`Recno()`, `goExecutor` + `ALTER TABLE`, UX formulare/griduri), comentariile (istoric **numai** in
|
||
antetul fisierului, max o linie in cod), si ca write-back-ul text→binar e facut pentru fiecare
|
||
fisier atins.
|
||
5. **Aprobarea lui Marius.**
|
||
6. **Commit** — in **ambele** repo-uri unde e cazul (ROAFACTURARE si COMUN), cu changelog.
|
||
|
||
**Afirmatiile review-ului se verifica, nu se cred.** Un review poate citi structura corect si presupune
|
||
semantica gresit; cand semnaleaza un defect, se deschide codul citat inainte sa fie acceptat — la fel
|
||
cum se procedeaza cu rapoartele de cercetare.
|
||
|
||
**Ce NU face review-ul:** nu reargumenteaza deciziile luate (lista lor e in acest plan), nu extinde
|
||
perimetrul povestii, si nu propune refactorizari colaterale. Ce gaseste in afara perimetrului se
|
||
**raporteaza separat**, nu se repara in trecere — exact cum s-a procedat cu defectul `lnTip` din
|
||
`do_copiaza`.
|
||
|
||
### Etapa I — formularul unificat
|
||
|
||
#### S1 — Inventarul de campuri si alegerea bazei
|
||
Deciziile de perimetru sunt luate (vezi listele de la inceput). Ramane: **se porneste de la prototipul
|
||
`frm_facturare_articole2` sau de la `frm_facturare_articole` extins?**
|
||
Recomandare: **de la prototip**, si acum cu trei argumente in plus fata de runda 2 — are deja
|
||
controalele de antet, are butoanele **deasupra** gridului (decizia 13), si are coloanele de discount
|
||
editabile plus procentul pe linie (decizia 14). Partea grea de layout e deja acolo; logica lipsa se
|
||
porteaza in el.
|
||
Livrabil: tabel camp-cu-camp `frm_date_factura` / `frm_date_aviz` / `frm_modifica_factura` /
|
||
`frm_alte_date` -> formular unificat, cu ce se pastreaza, **in ce grup din cele patru intra** (I),
|
||
ce se pliaza, ce dispare, si **cu ruta de scriere a fiecarui camp** (pe loc sau prin regenerare —
|
||
vezi G-bis). Baza de pornire: `docs\cercetare\inventar_controale_formulare.md`, care are deja
|
||
etichetele reale si conditiile de vizibilitate.
|
||
**Livrat (runda 7): `docs\S1_inventar_campuri_formular_unificat.md`** — 30 de campuri de antet, cu
|
||
grupul din I, conditiile de vizibilitate si ruta de scriere pentru fiecare, plus randul dedicat lui
|
||
`V_EFACTURA` (singurul camp fara control azi, nicaieri) si cele patru bife marcate ca disparute.
|
||
Tabelul a scos la iveala **golul de rute de scriere** din G-bis — vezi acolo. Are si o sectiune
|
||
„Neclarificate" cu opt puncte, dintre care doua ambiguitati de nume (`chkDetaliat`, `cboTipFactura`
|
||
apar in doua formulare si nu s-a confirmat pe cod ca scriu acelasi camp).
|
||
**Coloana „ruta de scriere" e completa acum** — `rute_scriere_antet.md` a inchis cele trei grupuri
|
||
lasate neclarificate, iar deciziile 25 si 26 le-au dat ruta. Tabelul se citeste **impreuna cu tabelul
|
||
de rutare din G-bis**, care e sursa de adevar pentru ruta fiecarui camp; sectiunea „Neclarificate" din
|
||
S1 ramane valabila doar pentru punctele **4, 5, 7 si 8** (ambiguitatile `chkDetaliat` / `cboTipFactura`,
|
||
liniile exacte de definire a controalelor, si dependenta de drepturi).
|
||
*Gata cand:* tabelul e aprobat. **APROBAT de Marius, 09.08.2026 — S1 e incheiata.** Tabelul devine
|
||
referinta pentru S3 si S3b; modificarile ulterioare se fac in el, nu se rescrie de la zero.
|
||
|
||
**ASEZAREA ZONEI DE JOS — INCHISA prin decizia 57 (Marius, runda 15): VARIANTA D.**
|
||
Cerinta initiala (runda 14), formulata de el: *„totalurile de jos sa fie mai compacte, si sa includa
|
||
si discount-ul; formularul trebuie sa fie compact si aerisit; incasarea si alte date jos de tot,
|
||
eventual 2 butoane pe acelasi rand — vezi modelul Saga; in centrul atentiei sa fie datele facturii"*.
|
||
Referinta vizuala: `{06D747B8-0824-488C-8832-DEB9AE661974}.png`.
|
||
Rundele 14-15 au dat patru variante (A / B / C, apoi D). **Aleasa: D.** Vezi „Decizia 57" la
|
||
deciziile rundei 15, care are enuntul complet, cele patru consecinte de implementare si punctul lasat
|
||
deschis. Ce e de retinut aici, pentru executia lui S1:
|
||
|
||
- **Antetul se strange la doua randuri**, fara titluri de grup — campurile se recunosc dupa eticheta.
|
||
- **Panoul separat „Discount pe document" dispare**; discountul devine rand editabil in banda de
|
||
totaluri, cu procentul pe loc.
|
||
- **Banda de totaluri** e pe toata latimea, lipita de grid: baza, discount articole, discount document
|
||
cu procentul, TVA — desfacute pe un rand — si totalul mare singur la dreapta.
|
||
- **Incasare si Alte date NU sunt dialoguri** — sunt doua sectiuni colapsabile in formular, **una
|
||
langa alta pe acelasi rand**, sub totaluri, fiecare cu rezumatul continutului pe randul inchis.
|
||
- **Bara de comenzi de jos nu exista**: `but_renunt` / `but_termin` raman in banda de titlu.
|
||
|
||
**Cota de TVA a discountului de document s-a decis — decizia 59, runda 16** (vezi sectiunea K-bis):
|
||
repartizare proportionala automata pe cote, discountul **NU cere cota de la utilizator**, deci **nu
|
||
e nevoie de o a treia sectiune pentru cota**. Ce mai cere UI e **un camp text optional de motiv**
|
||
(pentru `AllowanceChargeReason`), mult mai mic decat o sectiune. **Decizia 61 (runda 16) l-a
|
||
materializat: Marius vrea campul. Asezarea lui s-a inchis definitiv abia in runda 17 — decizia 64
|
||
(a treia sectiune jos) a fost **rasturnata de decizia 66: motivul sta in banda de totaluri, langa
|
||
suma pe care o explica**, iar randul de jos ramane cu **doua** sectiuni, ca la decizia 57. Varianta
|
||
grea (cota + explicatie proprii) ramane exclusa, ca mai sus.
|
||
|
||
**Cele doua pagini online ale lui #13 — nu se confunda:**
|
||
- **mockup-ul formularului** (fisier pe disc, `docs\mockup_13_formular_unificat.html`, **v9** din runda
|
||
17, cu asezarea D si motivul discountului in banda de totaluri):
|
||
**https://claude.ai/code/artifact/e9d73e86-7518-4f50-a998-43c49e083142**.
|
||
Are copie pe disc, si ea e sursa de adevar; artifactul se republica din ea (`WebFetch` pe URL intai,
|
||
apoi `Artifact` cu `url`). Decizia 33 e consumata — URL-ul e la zi.
|
||
- **pagina cu variantele de asezare** (A/B/C/D), **fara copie pe disc**, deci artifactul **e** sursa de
|
||
adevar:
|
||
|
||
Pagina cu variantele: **https://claude.ai/code/artifact/dfc70d38-856f-48fd-b6af-3da78e9da4f7**
|
||
— **nu mai are copie pe disc** (cerinta lui Marius, runda 15: „doar online, ca sa nu mai intretii 2
|
||
variante"). Procedura de modificare: `WebFetch` pe URL → fisier de lucru **in scratchpad, nu in
|
||
`docs\`** → `Artifact` cu `url` = link-ul de mai sus.
|
||
|
||
#### S2 — O singura procedura `factureaza`
|
||
Se elimina `factureaza2` ca procedura paralela; `factureaza` primeste un mod
|
||
(`gnFacturareNou` ramane comutatorul de rulare, dar nu mai duce la alt cod duplicat). Se pastreaza
|
||
integral ramurile care lipsesc azi din `factureaza2` (lista din A).
|
||
|
||
**PROIECTAT (runda 9) — `docs\cercetare\s2_factureaza_unificare.md`.**
|
||
**S2 e mult mai ieftina decat arata planul.** `factureaza2` nu e a doua implementare functionala care
|
||
cere fuziune atenta — e un fork din 08.06.2017 la care **executia interogarii de articole e dezactivata**
|
||
(`lnSucces = 1` hardcodat, `goExecutor.oExecute` niciodata apelat) si mai multe blocuri intregi sunt
|
||
inchise cu `If .F.`. Are **exact un apelant** in tot codul — `ofacturare.prg:90`, din interiorul lui
|
||
`factureaza`, in spatele unui `AMESSAGEBOX` de confirmare — deci **zero utilizatori reali**. Ambele sunt
|
||
proceduri globale in `COMUN\programe\ofacturare.prg` (`:81-577` si `:583-1081`, ~500 de linii fiecare),
|
||
fara omonime. Singura diferenta functionala care justifica existenta lui `factureaza2` e formularul de
|
||
articole (`frm_facturare_articole2` vs `frm_facturare_articole`).
|
||
**Obstacolul nu e tehnic:** formularul spre care duce e tot un prototip neterminat, deci unificarea
|
||
procedurilor **nu** face formularul nou utilizabil — doar elimina duplicarea. Aia rămâne treaba lui S3.
|
||
**Trei corectii la lista din sectiunea A:** `verifica_numar(16, ...)` pentru chitanta **nu lipseste** din
|
||
`factureaza2` (e identic, `:502-504` vs `:1018-1020`) — planul greseste; „`cursor_avize` cu tip 23" e
|
||
imprecis — tipul 23 nu lipseste, e **rutat diferit** (`cursor_preturi` in `factureaza` vs
|
||
`cursor_gestiune` in `factureaza2`), ceea ce e mai grav decat o omisiune; si lipsesc din plan **tipul 52**
|
||
pe ramura de contract si **tipul 24** pe ramura de retur. Semnatura propusa, ramificarea interna, ordinea
|
||
in care se face fara sa strice suita si criteriul de „gata" verificabil sunt in raport, sectiunile 5-7.
|
||
**`ofacturare.prg` e cod comun al intregii suite** (copie in fiecare produs ROA, sincronizata manual) —
|
||
la fel ca S3c, nu se face impreuna cu alta modificare.
|
||
*Gata cand:* `factureaza2` nu mai exista, iar comutatorul alege formularul, nu procedura.
|
||
*Depinde de:* S1.
|
||
|
||
#### S3 — Portarea logicii de antet in formularul unificat
|
||
Cele 17 + 13 metode `do_cauta_*`, `do_schimba_tipdoc`, validarile din `inainte_de_do_termin`
|
||
(`ofacturare.vc2:9455-9561` si `:7277-7352`) si `Init`-urile. Se porteaza **o singura data**, cu
|
||
ramificare pe factura / aviz in interior, nu doua copii.
|
||
Punct de atentie cunoscut: **#16 din `todos.txt`** — la revenirea din formularul de curs valutar,
|
||
focusul sare pe tip document si iesirea din serie regenereaza numarul actului.
|
||
|
||
**PROIECTAT (runda 9) — `docs\cercetare\s3_portare_antet.md`.** Doua rezultate schimba povestea:
|
||
|
||
- **Portarea „o singura data cu ramificare" nu e posibila ca atare.** `Init`, `inainte_de_do_termin` si
|
||
partial `do_cauta_fdoc` sunt **omonime cu semantica total diferita pe toate cele patru formulare-sursa**
|
||
(antet vs. articole vs. alte-date). Deci nu e o metoda cu ramificare interna, sunt **patru fuziuni de
|
||
metoda**. Obstacolul principal al lui S3 nu e codul de validare — majoritatea e `Do Case` / `amessagebox`
|
||
mecanic — ci **reconcilierea a patru cicluri de viata `Init` / `inainte_de_do_termin` independente
|
||
intr-unul singur**, cu ordinea de dependente din sectiunea 5 a raportului. Numarul real de `do_cauta_*`
|
||
e **29, nu 30**. Lista completa a omonimelor e la sectiunea 2 — **se citeste inainte de orice editare**,
|
||
altfel portarea le confunda (capcana deja platita o data cu `do_calculeaza_discount`).
|
||
- **#16 nu e un bug de focus, si nu e in perimetrul in care il caută planul.** Reprodus pe cod pana la
|
||
linia exacta: bucla de reincercare din `factureaza` / `factureaza2` (`ofacturare.prg:174-571`) trateaza
|
||
**orice esec SQL** — nu doar cursul valutar lipsa — ca pe un „DA, continui cu alt document", si
|
||
redeschide formularul de antet de la zero. Deci **unificarea nu-l reproduce automat**; poate chiar sa-l
|
||
elimine ca efect secundar, daca antetul nu se mai reconstruieste din `Init` dupa un esec Oracle in pasul
|
||
urmator. **Cade premisa „ori se rezolva #16 aici, ori se reproduce bug-ul".** Si leaga #16 de **S2**, nu
|
||
de S3 — bucla e in procedura, nu in formular.
|
||
|
||
*Gata cand:* un document se emite integral din formularul unificat, pe tip 1 (lista de preturi), cu
|
||
acelasi rezultat in `vanzari` / `act` / `rul` ca pe calea veche — criteriul rescris verificabil e la
|
||
sectiunea 7 a raportului, iar ce **nu** se poate testa headless la sectiunea 8.
|
||
*Depinde de:* S2.
|
||
|
||
#### S3b — Sectiunea pliata: alte date + analitice
|
||
Deciziile 7 si 8. Se muta in formular cele patru grupuri din `frm_alte_date` (B) si coboara acolo
|
||
analiticele din antet. `actualizeaza_tipincasare` se muta ca atare; **alocarea si dezalocarea
|
||
numerelor** de chitanta / bon fiscal / POS raman legate de aceleasi evenimente ca azi, nu de
|
||
deschiderea formularului. `frm_alte_date` nu se sterge cat timp calea veche mai e in uz.
|
||
**Doua precizari din runda 7, amandoua restrang povestea:**
|
||
- **analiticele coboara ca AFISARE, nu ca editare** (decizia 26) — venit/cheltuiala, sectie,
|
||
responsabil, lucrare sunt read-only in formularul unificat; se editeaza din editorul de nota al lui
|
||
**#6**, care le trateaza pe linie. Eticheta / tooltip trebuie sa spuna asta, altfel campul pare stricat;
|
||
- **pe un document deja emis, grupul de incasare e blocat in etapa I** (decizia 25) — nu are ruta de
|
||
scriere pe loc, iar regenerarea nu exista inca. La emitere se comporta ca azi.
|
||
**PROIECTAT (runda 11) — `docs\cercetare\s3b_alte_date_analitice.md`.** S3b nu e o mutare de controale.
|
||
Trei rezultate schimba povestea:
|
||
|
||
- **Riscul din criteriul de „gata" e real, si are mecanism.** Alocarea numarului de chitanta nu porneste
|
||
din clicul utilizatorului, ci din **orice atribuire programatica** a lui `.Value`:
|
||
`opt_incasat.ProgrammaticChange` (`ferestre_cere_date.vc2:3351-3352`) cheama acelasi
|
||
`actualizeaza_tipincasare()` ca `.Click` (`:3250-3251`). Consecinta neasteptata: **azi, deja**,
|
||
`Init` (`:3150`) seteaza singur `opt_incasat.Value = 2` cand documentul soseste cu `poDate.incasat<>0`
|
||
(cazul copierii), deci deschiderea dialogului aloca un numar fara ca cineva sa atinga ceva. Intr-un
|
||
formular unde zona se plieaza si se deplieaza repetat pe acelasi `poDate` persistent, o repopulare
|
||
naiva a starii ar aloca si dezaloca **la fiecare toggle**. Solutia proiectata: populare **o singura
|
||
data**, iar plierea strict pe `Visible`/`Height` — niciodata pe reasignare de `.Value`. Criteriul de
|
||
non-alocare e formulat ca **assert headless pe `poGeneratorNumere`**, pe doua scenarii de start
|
||
(document nou **si** document copiat cu incasare presetata — al doilea e cel care azi chiar aloca).
|
||
- **Nu exista mecanism de pliere de refolosit.** Cautare exhaustiva in `ofacturare.vc2`: zero potriviri
|
||
in prototipul `frm_facturare_articole2`. Cel mai apropiat tipar din suita e
|
||
`frm_modific2024.afiseaza_rulaje` (`omodificari.vc2:13169-13199`, perimetrul #6 — **citit, neatins**),
|
||
acelasi idiom sus/jos validat deja pentru `but_modifica`/`but_salveaza` la decizia 9. Deci **cod nou**,
|
||
dupa un tipar existent, nu o clasa reutilizabila.
|
||
- **Decizia 26 cere mai mult decat mecanismul existent.** `ct_clb_cautare.do_dezactiveaza()`
|
||
(`caut_ora.vc2:800-806`) ascunde **doar lupa de cautare**; textbox-ul ramane tastabil. Read-only real
|
||
cere `ReadOnly` explicit pe langa el — nesemnalat pana acum.
|
||
|
||
**Bug preexistent, gasit in trecere:** la Renunt se dezaloca chitanta (16) si bonul fiscal (3), dar
|
||
**nu si POS (26)**. Nu e introdus de S3b, dar „`actualizeaza_tipincasare` se muta ca atare" **l-ar
|
||
propaga**. **Decizia 40: se repara aici, in trecere** — deci diff-ul lui S3b nu mai e o mutare pur
|
||
mecanica, si testarea acopera si dezalocarea POS pe calea veche.
|
||
|
||
**Decizia 41 fixeaza granularitatea plierii: doua comutatoare.** Grupul de **incasare** are comutator
|
||
propriu — e singurul cu efecte laterale (alocare/dezalocare) si singurul blocat pe document emis prin
|
||
decizia 25 — iar delegat/transport, adresa, text aditional si analiticele stau impreuna sub al doilea.
|
||
Garda de non-alocare la toggle se scrie si se testeaza astfel **intr-un singur loc**.
|
||
|
||
*Gata cand:* criteriul rescris verificabil e la sectiunea 10 a raportului, in cinci puncte — mai strans
|
||
decat formularea de mai jos pe trei dintre ele: paritatea de emitere se cere pe **toate patru** tipurile
|
||
de incasare (nu doar bon fiscal), non-alocarea la toggle se cere pe **ambele** scenarii de start, iar
|
||
blocarea grupului de incasare si read-only-ul analiticelor se cer pe **ambele stari ale antetului**
|
||
(inainte si dupa `but_modifica`), nu doar la deschidere. Formularea initiala, pastrata ca rezumat: un
|
||
document cu incasare prin bon fiscal emis din formularul unificat produce aceleasi randuri si acelasi
|
||
numar de bon ca pe calea veche; deschiderea si inchiderea formularului fara a atinge zona de incasare
|
||
**nu aloca si nu dezaloca niciun numar**; iar pe un document emis analiticele se vad dar nu se pot edita.
|
||
*Depinde de:* S3.
|
||
|
||
#### S3c — Sursa ca parametru, nu ca global
|
||
Decizia 12. Punctele de intrare exista deja (comanda: `ocomenzi.vc2:1580-1596`; contract: din
|
||
ROACONTRACTE), dar transmit prin globalele `goComanda` / `goContract`. Se adauga parametru explicit
|
||
pe `factureaza` si pe `oDateFactura`, cu globalele pastrate ca sursa de rezerva pana se convertesc
|
||
toti apelantii (inclusiv cei din ROACONTRACTE si ROAGEST — e cod comun). Se verifica intai asimetria
|
||
de resetare semnalata la L.3.
|
||
**PROIECTAT (runda 11) — `docs\cercetare\s3c_sursa_ca_parametru.md`.** Se poate face, e o interventie
|
||
mica — dar **planul supraestimeaza cat de „globala" e problema azi**, si in doua sensuri opuse:
|
||
|
||
- **`goContract` nu e scris nicaieri in ROAFACTURARE** — nici in codul produsului, nici in `COMUN`-ul
|
||
lui. Deci ramura de precompletare din contract (`ofacturare_comun.prg:261-297`) e **cod mort in acest
|
||
produs**, iar **asimetria de resetare de la L.3** (`ofundal_facturare.vc2:886-902`) exista textual dar
|
||
e **inerta**: n-are ce sa lase nereseta, pentru ca n-are scriitor. Devine risc real abia daca cineva
|
||
adauga in viitor un scriitor in ROAFACTURARE — moment in care lipsa resetarii s-ar activa **tacut**.
|
||
- **`goComanda` chiar e viu, si are DOI scriitori**, nu unul: clicul pe „Factureaza"
|
||
(`ocomenzi.vc2:1583`) **si** navigarea in grid (`:2199`, doar ca sa decida vizibilitatea unui buton).
|
||
Al doilea n-are nicio legatura cu facturarea si **ramane si dupa conversie** — deci globala nu dispare.
|
||
- **Criteriul „pana se convertesc toti apelantii" nu se poate citi ca „pana dispare globala".** In
|
||
ROACONTRACTE, `goContract` e **bufferul de editare al intregului ecran de contracte** (peste 100 de
|
||
`ControlSource` legate de el), populat de navigarea in grid, independent de facturare. Nu dispare la
|
||
aceasta poveste si nici la vreuna rezonabila urmatoare; S3c schimba **doar canalul** prin care valoarea
|
||
ajunge la `oDateFactura.Init`.
|
||
|
||
**Suprafata de regresie, masurata:** doi scriitori de convertit (`ocomenzi.vc2:1580-1596`;
|
||
`ferestre_contracte.vc2:1538-1549` + `:1598-1606` in ROACONTRACTE), **trei** fisiere comune atinse o
|
||
singura data fiecare (`ofacturare.prg`, `oproceduri_facturare.prg`, `ofacturare_comun.prg`), si **zero
|
||
schimbari** la celelalte ~31 de puncte de intrare din inventarul S2 — toate cheama `factureaza(N)` cu un
|
||
singur argument. Cele cinci fisiere sunt **identice pe MD5** in cele sapte produse, cu o singura exceptie:
|
||
**ROAIMOB**, o linie lipsa in `ofacturare_comun.prg` — acolo diff-ul se aplica **manual**, nu prin copiere
|
||
mecanica.
|
||
|
||
**Semnatura propusa:** `factureaza(tnTip, toFactura, toSursa)` si `oDateFactura::Init(tnIdSet, tnTip,
|
||
toSursa)` — parametru nou la coada, cu implicit, fallback pe global cand lipseste.
|
||
**Capcana de limbaj, semnalata explicit:** garda se scrie `Type('toSursa') = 'O'`, **nu**
|
||
`Type('toSursa') <> 'U'`. Un parametru VFP nepasat **nu** e `'U'` (aia e pentru variabile nedeclarate),
|
||
ci `'L'` cu `.F.` — o garda `<> 'U'` ar trece mereu adevarat si ar incerca sa citeasca `.id_part` de pe
|
||
`.F.`, eroare la primul apel neconvertit. Raportul cere verificarea comportamentului `Type()` pe un
|
||
`.prg` de proba **inainte** de a atinge fisierele reale.
|
||
|
||
*Gata cand:* criteriul rescris e la sectiunea 10 punctul 4 al raportului, pe patru probe — una
|
||
structurala (parametrul prezent cu semnatura identica in toate cele trei fisiere comune, in toate cele
|
||
sapte produse) si trei comportamentale: **calea convertita** cu globala deliberat „murdara" dintr-o
|
||
navigare anterioara produce documentul dat prin parametru, nu pe cel din globala; **calea neconvertita**
|
||
(oricare din cele ~31 de apeluri cu un singur argument) produce acelasi document ca inainte; iar
|
||
**ROACONTRACTE** da aceeasi precompletare ca azi, verificat manual pe build separat.
|
||
*Depinde de:* S2. **Atinge cod comun intregii suite** — nu se face impreuna cu alta modificare.
|
||
|
||
#### S4 — Cautarea articolelor pe server, in linie
|
||
Partea Oracle: variante filtrate pe articol ale cursoarelor de facturare, cu aceleasi ramuri pe tip
|
||
ca `cursor_preturi` / `cursor_contract` / `cursor_comanda` / `cursor_avize` / `cursor_gestiune`.
|
||
Partea VFP: `combosql` pe cod si pe denumire completeaza linia cu pret, cota TVA, valuta, `id_pol`,
|
||
`gestionabil`, `pret_cu_tva`; `crsarticole` nu se mai incarca in masa.
|
||
Se pastreaza "adauga tot" pentru tipurile care au document sursa (comanda, aviz, contract) — acolo
|
||
setul e marginit si incarcarea lui e legitima.
|
||
**PROIECTAT (runda 11) — `docs\cercetare\s4_cautare_articole_server.md`. Criteriul de mai jos nu e
|
||
atingibil ca atare, si motivul nu e UX.**
|
||
|
||
- **`crsarticole` nu e doar sursa de populare a gridului — e un registru al cantitatii ramase de
|
||
facturat.** E citit **si scris** de `do_adauga_tot`, `do_sterge` si `do_scrie_factura` pentru toate
|
||
tipurile cu document sursa: stergerea unei linii **reface** cantitatea in `crsarticole`
|
||
(`ofacturare.vc2:14640-14669`), iar la scriere se face `Calculate Sum(cantitate) To lnCantitateRamasa`
|
||
peste el ca sa se decida daca se inchide automat comanda / avizul (`:14303-14311`, `:14334-14338`).
|
||
Deci pe **comanda, aviz si contract** incarcarea in masa **nu poate disparea**, indiferent de decizia
|
||
de UX privind „adauga tot" — bookkeeping-ul e cablat pe cursorul incarcat. **S4 se aplica curat doar
|
||
pe ramurile de lista de preturi** (`cursor_preturi`, plus jumatate din `cursor_contract` si
|
||
`cursor_gestiune`).
|
||
**DEPASIT de proiectarea punctului 2 (runda 12)** — se citeste doar ca istoric al deciziei 39.
|
||
Concluzia „incarcarea in masa nu poate disparea" cadea pentru ca `crsarticole` era tratat ca un
|
||
registru omogen; sunt de fapt **doua mecanisme distincte** (Rol A / Rol B), si niciunul nu cere
|
||
cursorul incarcat. Vezi mai jos.
|
||
- **`combosql` e un prototip la jumatate, si e singura lui utilizare din suita.**
|
||
`grd_factura.cCodMat.cboCodmat` / `cCboDenumire` (`ofacturare.vc2:16751-16797`, wiring la
|
||
`:19288-19334`) chiar cauta pe server, dar scrie **doar** `codmat` / `denumire` / `id_articol`, pentru
|
||
ca sursa lui (`vnom_articole`) n-are pret, TVA, valuta, `id_pol`, `gestionabil`. Cautare in
|
||
`COMUNROA` si `ROAGEST`: **zero alte utilizari** — nu exista de unde copia un exemplu complet.
|
||
Confirma insa exact punctul C: de facut e **varianta filtrata pe articol a celor cinci cursoare**, nu
|
||
o cautare noua.
|
||
- **`cursor_contract` produce deja doua cursoare** — `V_CURSOR` (`crsarticole`, prin delegare la
|
||
`cursor_preturi`) si `V_CURSOR2` (`crsarticole1`, articole **sau** rate). Filtrarea se aplica curat
|
||
doar pe jumatatea `crsarticole`; **randurile de rata n-au `id_articol`** si raman needitate.
|
||
- **Vizibilitatea de azi a butonului „adauga tot" coincide aproape exact cu impartirea utila pentru S4**
|
||
(`ofacturare.vc2:15108-15248`: ascuns pe lista de preturi, vizibil pe comanda / aviz / retur) —
|
||
confirmare pe cod, nu presupunere.
|
||
- **Legatura cu S10, confirmata:** pretul se cauta **o singura data**, la alegerea liniei, si se
|
||
transmite mai departe neschimbat — exact ce face azi `adauga_articol_factura`, care il primeste ca
|
||
parametru in loc sa-l re-derive.
|
||
- **Efect secundar al filtrarii, rezolvat prin decizia 42:** `verifica_cursuri_valute` e azi
|
||
neconditionata in procedura, deci pe varianta filtrata s-ar declansa la **fiecare** cautare de articol
|
||
in loc de o data la deschidere — cu `-20005` posibil pe o valuta pe care operatorul n-o foloseste,
|
||
inainte sa vada vreun rand. Se **restrange la valuta articolului cautat**.
|
||
- **Cele doua puncte „de inchis inainte de implementare" sunt INCHISE (runda 12)** —
|
||
`docs\cercetare\s4_puncte_deschise.md`. Raspunsul de baza e la amandoua „filtrarea nu schimba nimic",
|
||
dar **fiecare lasa in urma o cerinta de implementare, nu doar o bifa**:
|
||
- **`id_jtva_coloana` chiar lipseste** din `cursor_preturi`, din `cursor_gestiune` si din `V_CURSOR2`
|
||
al lui `cursor_contract`, pe toate ramurile — confirmat pe SQL. **Nu e bug:** `do_initializeaza_articol`
|
||
pune `0`, iar `frm_articol_factura.Init` (mostenit si de `frm_articol_gest_factura`) **il rederiva
|
||
mereu** din `proc_tvav` via `jtva_coloane`, pe orice linie adaugata prin `do_adauga_articol`.
|
||
**Cerinta care rezulta pentru S4:** derivarea tine **numai** daca linia trece prin
|
||
`do_adauga_articol`. `combosql`-ul prototip de azi (`ofacturare.vc2:19288-19306`) face `REPLACE`
|
||
direct in `crsfactura` si **ocoleste toata derivarea**; daca S4 extinde acel `REPLACE` fara sa treaca
|
||
prin `do_adauga_articol`, `id_jtva_coloana` ramane nederivat si Oracle
|
||
(`adauga_articol_factura`, ramura `ELSE`) arunca **`-20000 FACT-013`** sau scrie cota gresita.
|
||
**Bug nou posibil, introdus de S4** — intra ca cerinta explicita in proiectare, nu ca observatie.
|
||
- **`but_urmator_tot1` are `Visible = .F.` la design** (`ofacturare.vc2:11265`); tipurile 23 si 41 au
|
||
`Case` propriu, dar **niciunul nu-l face vizibil** — confirmat, nu presupus. Nu exista alt mecanism
|
||
de „adauga tot"; exista insa `but_urmator1` (adaugare rand-cu-rand), **neconditionat de tip**, care
|
||
merge prin acelasi `do_adauga_articol` — deci dupa S4 **nu se pierde nimic** pe aceste tipuri.
|
||
- **Corectie de rutare fata de ce presupunea planul:** pe formularul **standard** (`factureaza`,
|
||
`ofacturare.prg:266-308`) doar **tipul 41** cheama `cursor_gestiune`; **tipul 23 cheama de fapt
|
||
`cursor_preturi`** (grupat cu lista de preturi). Tipurile **45, 48, 49 nu ating deloc**
|
||
`cursor_gestiune` (45 → `cursor_preturi`, 48/49 → `cursor_articole_k`, alta procedura). Doar pe
|
||
**prototip** (`factureaza2`, opt-in `gnFacturareNou`) 23 si 41 merg impreuna pe `cursor_gestiune` —
|
||
**divergenta reala intre cele doua formulare**, semnalata, neatinsa, in afara perimetrului S4.
|
||
|
||
**Decizia 39 largeste povestea peste ce propunea raportul.** Raportul recomanda restrangerea la lista de
|
||
preturi, tocmai pentru ca registrul de cantitate ramasa blocheaza restul; Marius a ales sa se desfaca si
|
||
registrul. Deci S4 are de acum **doua bucati, nu una**:
|
||
1. **varianta filtrata a cursoarelor** + completarea liniei din `combosql` (partea proiectata in raport);
|
||
2. **decuplarea bookkeeping-ului de cantitate ramasa** de cursorul incarcat in masa — sursa unica, nu o a
|
||
doua copie tinuta in pas cu prima. Atinge `do_adauga_tot`, `do_sterge`, `do_scrie_factura` si
|
||
**inchiderea automata** a comenzii / avizului.
|
||
|
||
**Punctul 2 — PROIECTAT (runda 12): `docs\cercetare\s4_punct2_registru_cantitate_ramasa.md`.** Iese mult
|
||
mai ieftin decat parea, pentru un motiv care nu se vedea din raportul punctului 1.
|
||
|
||
- **`crsarticole.cantitate` are DOUA roluri, nu unul** — si numai unul e „registrul" temut.
|
||
**Rol A — cantitate ramasa de facturat dintr-un document sursa** (comanda `3,21,25,28,42,47`; avize
|
||
`4`). **Rol B — plafon de cantitate in sesiune** (lista de preturi gestionabila `1,22,29` si jumatatea
|
||
de contract, transfer `23,41`, retur `8,9,24`): impiedica operatorul sa adauge mai mult decat vede pe
|
||
ecran. **Rol B nu alimenteaza nicio decizie Oracle** — e plafon de UI, nu registru de business.
|
||
- **Pe Rolul A, cursorul VFP e o copie redundanta a unui calcul pe care Oracle il repeta oricum.**
|
||
`do_scrie_factura` sumeaza `crsarticole` doar ca sa decida ce trimite in `pnParametruAditional`, iar
|
||
Oracle **recalculeaza independent, din tabele reale**, in `inchide_comanda()` / `marcheaza_facturat()`,
|
||
chiar in procedura care scrie factura.
|
||
- **Nu exista coloana `INCHISA`.** Cautare in tot pachetul: **zero potriviri** (verificat separat de
|
||
sesiunea principala). „Comanda inchisa" e o stare **derivata** din `COMENZI_ELEMENTE` vs
|
||
`VANZARI_DETALII`; `inchide_comanda()` insereaza un **rand compensator**, nu seteaza un flag. Pe
|
||
comanda, `pnParametruAditional` e strict **binar** — „s-a cerut fortarea inchiderii?" —, iar cantitatea
|
||
trimisa de VFP **nu participa** la calculul Oracle.
|
||
- **Pe avize e altfel, si aici sta subtilitatea:** `VANZARI.FACTURAT` **e** un flag persistat, iar
|
||
`V_VERIFICARE` (= `pnParametruAditional`) alege intre „**increde-te in VFP** si marcheaza toate avizele
|
||
referite" (`0`) si „**recalculeaza per-aviz** din tabele reale si marcheaza doar cele cu `ramas = 0`"
|
||
(`1`). Deci pe aviz suma din VFP schimba semantica, nu doar declanseaza o actiune.
|
||
- **Un bug preexistent, de REPRODUS identic, nu de reparat in trecere:** cand un `crsarticole` agrega mai
|
||
multe avize, suma globala poate da `0` desi un aviz are ramas si altul are exces care-l compenseaza —
|
||
caz in care toate se marcheaza facturate, inclusiv cel cu ramas real. Varianta noua pastreaza aceeasi
|
||
conditie de declansare (suma globala pe tranzactie, nu per document).
|
||
- **`23` si `41` nu apar deloc in `CASE`-ul de finalizare** — cad pe `ELSE`, fara nicio inchidere:
|
||
transferul n-are document sursa de inchis, doar plafon (Rol B). Contractul (`2,6,52`) intra pe
|
||
`scrie_rate_factura`, care **nu e o inchidere**, e alta operatie.
|
||
- **Recomandarea: (b) pentru Rolul A, (c) pentru Rolul B.**
|
||
**(b)** cele doua `Calculate Sum` din `do_scrie_factura` se inlocuiesc cu un apel Oracle facut **dupa**
|
||
`do_scrie_articole()` (cand `VANZARI_DETALII_TEMP` contine exact liniile pe cale sa fie scrise) si
|
||
**inainte** de `Do Case`-ul care alege procedura de scriere. Cele doua functii Oracle noi sunt o
|
||
**extragere** a interogarii pe care `inchide_comanda` / `marcheaza_facturat` o ruleaza oricum, nu logica
|
||
noua. Efect secundar gratuit: dispare si un bug latent de concurenta — cursorul local nu vede azi ce a
|
||
facturat intre timp alt operator din aceeasi comanda.
|
||
**(c)** plafonul Rol B se cere pe server **la fiecare adaugare/editare**, minus ce e deja in
|
||
`crsfactura` — deci nu mai exista a doua copie de tinut in sincron.
|
||
Varianta cu un cursor propriu, minimal, a fost **respinsa motivat**: ramane tot o a doua copie manuala,
|
||
doar mai ingusta. Nu e „sursa unica".
|
||
- **Cazul limita cerut in plan** (adauga si sterge inainte de salvare) devine **trivial**, nu doar
|
||
acoperit: liniile adaugate-si-sterse nu ajung niciodata in `VANZARI_DETALII_TEMP`, deci nu influenteaza
|
||
calculul, fara nicio actiune de refacere.
|
||
- **CORECTIE asupra punctului 1:** pasul lui 5 (`s4_cautare_articole_server.md:417-424`) opreste
|
||
incarcarea in masa si pe `23,41`, presupunand ca n-au bookkeeping — **au Rol B**, confirmat pe cod.
|
||
Punctul 1 **nu se poate aplica pe `23,41`** inainte ca punctul 2 sa acopere Rolul B pe ele.
|
||
|
||
**Toate trei sunt INCHISE (runda 13). Nu se mai reiau.**
|
||
1. ~~**Asimetria din `do_modifica`**~~ — azi, pe grupul `1,22,29` + contract-lista, plafonul **nu** se
|
||
ajusteaza la editarea cantitatii unei linii deja adaugate. E preexistenta. **INCHIS — decizia 45
|
||
(runda 13, pe recomandare):** se lasa sa se **corecteze de la sine** prin recalculul la cerere, cost
|
||
zero, dar corectia se **declara explicit in changelog** — S4 schimba atunci un comportament punctual,
|
||
nu doar „decupleaza".
|
||
2. ~~**Corectia pe `23,41`**~~ — **INCHIS — decizia 46 (Marius, runda 13): asteapta punctul 2.**
|
||
Punctul 1 **nu se redeschide** acum; aplicarea lui pe `23,41` vine odata cu recalculul pe server, care
|
||
acopera Rolul B. Nu se pierde nimic: ordinea de implementare oricum le pune dupa.
|
||
3. ~~**Contract `26,52`**: nu s-a gasit dovada nici de prezenta, nici de absenta a Rolului B.~~
|
||
**INCHIS de proiectarea S5** (`docs\cercetare\s5_acoperire_tipuri.md`): `26` si `52` **n-au niciun
|
||
bookkeeping**, nici Rol A, nici Rol B — excluderea e totala, pe `Do Case` exhaustiv fara ramura
|
||
implicita. Deci „dovedit absent", nu „nepresupus". Nu mai e o decizie de luat.
|
||
|
||
**Cerinta de revizuire**: cele doua functii Oracle noi sunt o extragere din proceduri existente, dar
|
||
raman **PL/SQL nou in `PACK_FACTURARE`**, cu `JOIN`-urile reproduse **din citire, nu din executie**. Se
|
||
verifica pe Oracle inainte de a continua — e primul pas al implementarii, nu o formalitate.
|
||
|
||
**Nota de executie (decizia 60):** pe documentele de tip **48/49** (custodie), cautarea pe server in
|
||
linie ramane restransa la articole `IN_STOC = 0` — nu se ofera articole gestionabile pe aceste tipuri.
|
||
Siguranta regenerarii la editarea custodiei (decizia 60,
|
||
`docs\cercetare\custodie_48_49_stergere_reemitere.md`) atarna de acest invariant.
|
||
|
||
*Gata cand:* patru probe, nu una. **(a)** Deschiderea formularului nu mai executa niciun cursor de
|
||
articole, **pe niciun tip** — nu doar pe lista de preturi. **(b)** Alegerea unei linii produce aceleasi
|
||
valori ca randul corespunzator din `crsarticole` de azi, pe fiecare tip; maparea camp-cu-camp e la
|
||
sectiunea 6 a raportului, cu coloanele semnalate explicit acolo unde varianta filtrata **nu** poate
|
||
produce aceeasi valoare. **(c)** **Paritate pe inchiderea automata** (decizia 39): acelasi document
|
||
sursa, aceleasi linii facturate partial, **aceeasi stare finala** — pe comanda, acelasi rand compensator
|
||
in `COMENZI_ELEMENTE` (nu exista flag `INCHISA` de comparat); pe aviz, exact aceleasi `VANZARI.FACTURAT`
|
||
marcate, inclusiv in cazul in care avizele agregate se compenseaza intre ele — pe fiecare tip cu document
|
||
sursa —
|
||
inclusiv cazul in care operatorul adauga si apoi sterge linii inainte de a salva, care azi trece prin
|
||
refacerea cantitatii in `crsarticole`. **(d)** O linie adaugata prin cautarea in grid ajunge in
|
||
`crsfactura` cu **`id_jtva_coloana` derivat** — adica trece prin `do_adauga_articol`, nu prin `REPLACE`
|
||
direct ca prototipul de azi; proba e ca documentul se scrie fara `FACT-013` si cu aceeasi cota ca pe
|
||
calea veche. **(e)** Pe un document de tip 48/49, cautarea pe server nu ofera si nu permite adaugarea
|
||
unui articol cu `IN_STOC <> 0` (decizia 60).
|
||
*Depinde de:* S3. **Punctul 2 nu e proiectat** — se proiecteaza separat inainte de implementare.
|
||
|
||
#### S4b — Bara de butoane si meniul de adaugare
|
||
Decizia 13, proiectata in J. Trei bucati:
|
||
1. **Butoanele de linie deasupra gridului**, cu eticheta, nu iconite mute: linie noua (`but_nou`),
|
||
sterge linia (`but_sterge`), detalii linie.
|
||
2. **Un singur buton „Adauga articole” cu `xmenu()`**, cu optiunile din tabelul din J. Inlocuieste
|
||
`But_urmator_tot1` (azi fara caption si fara `ToolTipText`) si butonul separat de alegere.
|
||
**Acopera si contractele** — tipurile 2, 6, 26, 52 lipsesc azi din conditiile de vizibilitate
|
||
(`ofacturare.vc2:15113-15245`), desi avizele sunt acolo.
|
||
3. **Alegerea selectiva**, dupa tiparul RORIS: dialog modal cu coloana de bifat si criterii de
|
||
cautare, populare aditiva in cursorul local, nicio scriere in baza pana la salvare. Pe contract,
|
||
unitatea de selectie e **rata** — cazul explicit cerut. Spre deosebire de modelul RORIS, la zero
|
||
rezultate se spune de ce, nu se inchide in tacere.
|
||
**PROIECTAT (runda 11) — `docs\cercetare\s4b_bara_butoane_meniu.md`.** Implementabila fara cod nou major,
|
||
cu **patru corectii** fata de textul de mai sus:
|
||
|
||
- **Golul de contract e mai mare decat „lipseste `but_urmator_tot1.Visible`".** Pe **tipul 52**
|
||
formularul nu intra in **niciun** `Case` al `Do Case`-ului (`ofacturare.vc2:15109-15248`) — deci pierde
|
||
si titlul, si eliminarea coloanei `cSerie`, nu doar butonul „tot".
|
||
- **Nu se porneste de la tiparul RORIS.** `frm_tranzit` e specific ROAACNPRO si ar insemna formular nou;
|
||
ROAFACTURARE are deja `cauta_alfa(..., tnTipReturn=1)` — mecanism **generic** de selectie multipla cu
|
||
bifare, criterii de cautare si populare aditiva, folosit **chiar in acest formular** pentru returul
|
||
multi-factura (`do_cauta_facturi`). Mai ieftin, si deja dovedit in productie.
|
||
- **„Unitatea de selectie e rata" e adevarat doar pe jumatate.** `crsarticole1` are **doua ramuri
|
||
disjuncte** in SQL — `OPT_FACTURARE = 3` (articole reale) si `OPT_FACTURARE IN (1,2)` (rate de
|
||
scadentar) — iar un contract e mereu pe una singura, niciodata pe amandoua. Eticheta „Alege ratele de
|
||
facturat…" e corecta doar pe a doua ramura; **contractul are deci doua meniuri, nu unul**.
|
||
- **Un gol de cod, nu doar de vizibilitate:** `do_adauga_tot` parcurge azi **exclusiv `crsarticole`,
|
||
niciodata `crsarticole1`**. Fara extindere, „adauga tot" pe contract fie n-ar face nimic, fie ar aduce
|
||
liniile gresite — deci pe contract butonul trebuie **scris**, nu doar facut vizibil.
|
||
|
||
**Echivalenta „tot" = „alege total"** tine azi prin constructie, pe o singura rutina comuna de adaugare
|
||
pe rand (`do_adauga_articol`) — se pastreaza asa, iar pe contract devine adevarata abia dupa extinderea
|
||
de mai sus.
|
||
|
||
*Gata cand:* pe fiecare sursa (comanda, contract, avize, document returnat) meniul ofera si „tot" si
|
||
„alege", iar rezultatul in `crsfactura` e identic pe cele doua cai cand selectia e totala — **inclusiv
|
||
pe contract**, unde azi „tot" nu parcurge cursorul potrivit, si **inclusiv pe tipul 52**, care azi nu
|
||
intra in nicio ramura. Pasii cu criterii verificabile sunt la sectiunea 7 a raportului; ce nu se poate
|
||
testa headless, la sectiunea 8.
|
||
*Depinde de:* S4.
|
||
|
||
#### S4c — Discountul pe linie, mutat din dialog in grid
|
||
Decizia 14, proiectata in K. Dialogul de articol dispare odata cu unificarea, deci cele doua campuri
|
||
de discount ale lui — **procent** si **valoare unitara** — devin coloane in grid, cu acelasi calcul
|
||
reciproc din `frm_articol_factura.do_calculeaza_discount` mutat pe evenimentele coloanelor. Se repara
|
||
in acelasi timp inconsecventa de azi (read-only in lei, editabil fara recalcul in valuta). Se
|
||
pastreaza excluderea pe `in_valuta`. Modelul de date **nu se atinge** — se stocheaza tot valoarea.
|
||
**VERIFICAT — S4c e deblocata, dar capcana e alta decat se credea.** Raport:
|
||
`docs\cercetare\discount_in_rapoarte_si_efactura.md`.
|
||
|
||
- **Niciun raport de factura nu tipareste discountul pe linie** — nici valoare, nici procent. Cautare
|
||
in toate `.fr2` de factura / proforma / invoice din `COMUN\Rapoarte`: **zero potriviri** pe „disc".
|
||
Singurele doua `.fr2` cu „DISCOUNT" sunt de NIR, nu de facturi emise. Se tipareste `pretftva` si
|
||
`valftva`, **deja nete de discount** (`prelucreaza_factura`, `ofacturare_comun.prg:1055-1059`,
|
||
`:1156-1248`, in cursorul `crsfacttemp`).
|
||
- **eFactura foloseste exact acelasi cursor** (`xmlefactura.prg`) — `LineExtensionAmount` si
|
||
`PriceAmount` sunt aceleasi valori nete, cu optiunea (dezactivata implicit) de a adauga si un
|
||
`cac:AllowanceCharge` informativ pe linie.
|
||
- **SAF-T (D406) nu exista in ROAFACTURARE** — doar tabele de nomenclator cu prefix `saft_` (coduri
|
||
TVA / plata), pe partea de achizitii, fara legatura cu `DISCOUNT_UNITAR`.
|
||
- **Deci ingrijorarea initiala („utilizatorul schimba totalul fara sa se vada pe hartie") era gresit
|
||
tintita:** discountul nu se vede pe hartie **prin design**, iar totalul se vede corect pentru ca
|
||
pretul tiparit e deja net.
|
||
|
||
**PROIECTAT (runda 12) — `docs\cercetare\s4c_discount_in_grid.md`.** Implementabila, cu **capcana
|
||
retintita**: formularea de mai jos, din rundele anterioare, era in acelasi timp prea alarmista si prea
|
||
vaga.
|
||
|
||
- **Baza de date nu e in pericol.** `do_scrie_articole` trimite spre Oracle **direct** din
|
||
`discountftva` / `discountctva` / `vdiscountftva` / `vdiscountctva` (`ofacturare.vc2:14081-14083`,
|
||
ales pe `cu_tva` si `tip_valuta`) — verificat pe cod, nu presupus. Deci
|
||
`VANZARI_DETALII.DISCOUNT_UNITAR` iese **mereu corect**, indiferent de starea campurilor agregate.
|
||
- **Riscul e strict local, si e o inconsistenta, nu o valoare veche.** `valdiminuatftva` /
|
||
`valdiminuatctva` sunt agregate citite de `prelucreaza_factura` **din acelasi `crsfactura` din
|
||
memorie**, nereincarcat din Oracle. Netratate, factura tiparita poate iesi cu `pretftva` corect si
|
||
`valftva` inconsistent — **pret x cantitate diferit de valoare**, ceea ce se vede pe hartie.
|
||
- **Exista deja azi calea care demonstreaza gaura:** editarea `vdiscountftva` in grid, pe factura in
|
||
valuta, **nu declanseaza recalculul** agregatelor (`discount_verificare2.md`, punctul 3).
|
||
- **Calculul e deja generic si refolosibil**, nu trebuie rescris: `do_calculeaza_discount`
|
||
(`ofacturare.vc2:1874-1976`) plus `calculeaza_totaluri()` (`oproceduri_facturare.prg:2258-2381`),
|
||
care ruleaza pe `Scatter Name`, **fara dialog**.
|
||
- **Evenimentul recomandat pe coloanele noi e `Text1.LostFocus`**, nu `InteractiveChange` sau `Valid` —
|
||
tiparul e deja folosit in acelasi fisier, pe `frm_avizare_lucrare.grd_articole.cCantitate` /
|
||
`cPret` (`:6549-6562`).
|
||
- **Punctul deschis din S1 e inchis in trecere:** `_checkbox1` si `chkDetaliat` sunt **doua controale
|
||
distincte** in `frm_alte_date`, nu o duplicare — subiectul nu are legatura cu S4c.
|
||
|
||
*Gata cand:* tastarea in oricare din cele doua coloane produce aceleasi valori in `crsfactura` ca
|
||
dialogul de azi, pe ambele monede; totalurile se refac imediat; discountul venit din politica de pret
|
||
se comporta ca azi; **si `valdiminuatftva` / `valdiminuatctva` se recalculeaza la fiecare editare**,
|
||
astfel incat pe factura tiparita `pret x cantitate` sa dea exact valoarea — verificat prin retiparire
|
||
si prin XML-ul de eFactura, nu doar pe ecran. Pasii cu criterii verificabile sunt la sectiunea 7 a
|
||
raportului; ce nu se poate testa headless, la sectiunea 9.
|
||
*Depinde de:* S4.
|
||
|
||
#### S4d — Data cursului valutar, numai cand are sens
|
||
Decizia 15, proiectata in M. Campul apare cand tipul nu e retur **si** (documentul e in valuta **sau**
|
||
a intrat pe grid macar un articol cu pret in valuta) — evaluat reactiv, ceea ce devine posibil abia
|
||
in formularul unificat.
|
||
**VERIFICAT — S4d e deblocata.** Raport: `docs\cercetare\zi_curs_validare.md`. Ascunderea selectorului
|
||
**nu** poate lasa documentul fara curs, cu o conditie deja indeplinita de cod:
|
||
|
||
- **Implicitul exista si e neconditionat.** `poDate.zi_curs` primeste data documentului chiar in
|
||
`oDateFactura.Init` / `Reset` (`COMUN\programe\ofacturare_comun.prg:247`, `:496`), **inainte** ca
|
||
formularul sa decida ce ascunde. **Nicaieri codul nu goleste `zi_curs` cand controlul e ascuns.**
|
||
Deci „valoarea implicita ramane" nu e ceva de construit — e comportamentul actual, de **nestricat**.
|
||
- **Precedentul cerut exista deja**, in alt formular: `frm_date_factura`, tipurile 8 / 9 (retur), unde
|
||
`clb_zi_curs` se elimina **neconditionat** si documentul se salveaza corect — in principal pentru ca
|
||
`cursor_retur` nici nu foloseste `poDate.zi_curs`.
|
||
- **Linia `:8076` nu e in formularul de factura.** Apartine lui `frm_date_aviz_lucrare`
|
||
(`inainte_de_do_termin`, `ofacturare.vc2:8054-8119`), un formular restrans pentru **aviz pe lucrare /
|
||
aviz pe NIR** (tipurile 27 si 30), care nici nu are control de valuta. Valideaza `zi_curs` pentru ca
|
||
tipul 27 are nevoie de curs pentru articolele din comanda, **independent de `poDate.in_valuta`** —
|
||
deci nu e o inconsecventa de reparat orbeste, are un motiv. Se aliniaza doar daca formularul unificat
|
||
preia si tipurile 27 / 30.
|
||
|
||
**Riscul real e in alta parte, si nu tine de vizibilitatea campului:**
|
||
`pack_facturare.verifica_cursuri_valute` (chemata din `cursor_preturi`) ruleaza **neconditionat de
|
||
`in_valuta`** si exclude doar moneda nationala. Deci un `zi_curs` implicit (azi) fara curs setat in
|
||
`CURS` pentru o valuta prezenta in listele de preturi ale utilizatorului **poate pica oricum**
|
||
(`-20005`, „Nu este setat cursul…"), indiferent daca selectorul e vizibil sau nu. **Ascunderea nu
|
||
introduce riscul asta si nici nu-l rezolva** — dar il face mai greu de inteles pentru operator, care nu
|
||
mai vede campul din cauza caruia primeste eroarea. De tratat in mesajul de eroare, nu in vizibilitate.
|
||
|
||
**PROIECTAT (runda 12) — `docs\cercetare\s4d_zi_curs_reactiv.md`.** Nu se inventeaza nimic; se
|
||
reevalueaza vizibilitatea unui control care exista deja.
|
||
|
||
- **Cheia reactivitatii e un camp deja prezent in cursorul gridului: `crsfactura.tip_valuta`**,
|
||
interogabil cu **exact tiparul deja folosit in cod** (`ofacturare.prg:1656`, `:1730`:
|
||
`Select Distinct ... From crsfactura Where tip_valuta = 1`). Nu e nevoie de o structura noua.
|
||
- **Prototipul are deja `Clb_zi_curs` propriu, editabil, legat la `poDate.zi_curs`**
|
||
(`ofacturare.vc2:16285-16305`) — se schimba doar **cand** e vizibil.
|
||
- **Mesajul `-20005` contine DEJA data si numele valutei lipsa** (`STRINGAGG` peste toate valutele fara
|
||
curs) — deci partea de „sa spuna care valuta si ce zi" nu e de construit. **Decizia 42 nu schimba
|
||
continutul mesajului, ii schimba domeniul**: il restrange la valuta articolului cautat, dar **numai pe
|
||
varianta filtrata** (S4 punctul 1); pe caile cu document sursa incarcarea in masa ramane
|
||
neconditionata, deci acolo eroarea poate inca numi o valuta straina de documentul curent.
|
||
- **Ce lipseste cu adevarat, si intra ca pas de implementare, nu ca optiune:** sectiunea M cere ca la
|
||
aceasta eroare campul sa **revina vizibil** — altfel operatorul primeste o eroare despre un camp pe
|
||
care nu-l vede.
|
||
- **#16 nu e in perimetrul S4d.** E legat de S2 (bucla de reincercare din `ofacturare.prg`), cu verdict
|
||
separat in `s3_portare_antet.md`. S4d doar **confirma** ca antetul persistent ii inlatura mecanismul,
|
||
cu conditia ca S2/S3 sa nu recreeze formularul la eroare.
|
||
- ~~**De confirmat cu Marius (mic, de UX):** ce se intampla cand se sterge **ultimul** articol in
|
||
valuta?~~ **INCHIS — decizia 47 (Marius, runda 13): simetrie.** Campul **se ascunde la loc** cand
|
||
dispare ultimul articol in valuta, pe tiparul `lb_cursuri`. „Clipitul" la adaugari/stergeri repetate
|
||
e acceptat ca pret al unei reguli unice: aparitia si disparitia urmeaza aceeasi conditie, nu doua.
|
||
|
||
*Gata cand:* o factura in lei fara articole in valuta nu arata campul si se emite corect; aceeasi
|
||
factura, dupa adaugarea unui articol cu pret in valuta, arata campul cu data implicita completata;
|
||
factura in valuta se comporta ca azi; iar la `-20005` **campul redevine vizibil**, cu mesajul de azi
|
||
(care deja numeste valuta si ziua). Pasii cu criterii verificabile sunt la sectiunea 7 a raportului; ce
|
||
nu se poate testa headless, la sectiunea 9.
|
||
*Depinde de:* S4. **#16 se urmareste in S2/S3, nu aici** — vezi M.
|
||
|
||
#### S4e — Lista de preturi disponibila si pe factura din comanda
|
||
Decizia 16, proiectata in J. Singurul gol real: pe contract merge deja, pe comanda nu, pentru ca
|
||
`cursor_comanda` umple `crsarticole` doar cu articolele comenzii. Se adauga lista de preturi peste
|
||
cursorul sursei, exact ca la copiere (`ofacturare.prg:454-473`), si optiunea „Cauta in lista de
|
||
preturi…” intra in meniu pe toate sursele.
|
||
**Si stergerea intra aici**, nu doar adaugarea: cazul cerut e „clientul mai vrea ceva sau vrea sa
|
||
schimbe”, deci o linie adaugata trebuie sa poata fi si scoasa.
|
||
**DECIS (decizia 29): stergerea unei linii venite din comanda ramane fara protectie.** Se sterge ca
|
||
oricare alta; comanda ramane cu cantitatea nefacturata si va aparea **facturata partial**, ceea ce e
|
||
si starea corecta. Nu se cere confirmare, nu se marcheaza „refuzat", nu se ajusteaza numararea
|
||
acoperirii.
|
||
Ramane un singur efect lateral de tratat, si e pe **adaugare**, nu pe stergere: capul de coloana
|
||
„Cantitate comandata” si mesajul „A fost facturata intreaga cantitate comandata”
|
||
(`ofacturare.vc2:15144-15150`) nu sunt adevarate pentru liniile libere adaugate langa cele din
|
||
comanda.
|
||
**PROIECTAT (runda 12) — `docs\cercetare\s4e_lista_preturi_pe_sursa.md`. Reteta din decizia 16 NU se
|
||
generalizeaza literal** — si asta e rezultatul principal al proiectarii.
|
||
|
||
- **`APPEND FROM` peste cursorul sursei ar strica doua lucruri pe comanda**, ambele tacut:
|
||
**(1)** `id_c` e `ROWNUM` per executie Oracle, deci randurile din lista de preturi ar **coliziona** cu
|
||
cele ale comenzii, iar `do_sterge` ajusteaza cantitatea `For id_c = poArticol.id_c` (`:14652-14655`) —
|
||
ar atinge randul gresit; **(2)** `do_scrie_factura` face `Sum(cantitate)` peste `crsarticole` pe exact
|
||
aceste tipuri (`:14332-14338`), iar in `cursor_preturi` **`cantitate` inseamna STOC**, nu „ramas de
|
||
facturat" — suma care decide inchiderea comenzii ar fi poluata.
|
||
- **De ce merge totusi pe contract azi**, verificat: lista de preturi si articolele contractului sunt
|
||
**doua cursoare separate** de la bun inceput (`crsarticole` / `crsarticole1`), iar `cursor_contract`
|
||
emite `id_c` ca **`rownum - 10000`** (`PACK_FACTURARE:2722` — confirmat direct pe export de sesiunea
|
||
principala), adica autorii au tratat coliziunea de `id_c` ca risc real. In plus, tipurile de contract
|
||
**nu au deloc** ramura cu `Sum(cantitate)` in `do_scrie_factura` — cad pe `Otherwise`. Nu e un tipar
|
||
de copiat, e o coincidenta favorabila.
|
||
- **Solutia curata, verificata fezabila pe cod: liniile libere NU intra deloc in `crsarticole`.** Se
|
||
adauga direct in `crsfactura` prin `APPEND BLANK` + `combosql` — tipar **deja existent** in
|
||
`frm_facturare_articole2.do_adauga` si pe linia de discount (`ofacturare.vc2:14531`). Atunci `id_c`
|
||
ramane `0` implicit, si **`do_sterge` devine no-op prin constructie**, fara nicio modificare de cod.
|
||
- **Se aplica identic pe AVIZE (tip 4), nu doar pe comanda** — `cursor_avize` are aceeasi semantica
|
||
„ramas de facturat" si aceeasi ramura de `Sum`. Titlul povestii spune „din comanda", perimetrul real
|
||
e „orice sursa cu registru".
|
||
- **Avertisment care traverseaza in S4f:** pe returul ca document (`8,9,24`) riscul de coliziune `id_c`
|
||
**ramane** (`do_sterge` ajusteaza cu semn opus, urmarind maximul returnabil), desi **fara** poluarea
|
||
sumei de inchidere. Deci S4f foloseste acelasi mecanism, nu `APPEND FROM`.
|
||
- **Validarea de cantitate pe liniile din comanda e satisfacuta prin constructie** — drumul
|
||
`do_adauga_articol` → `do_verifica_articol` nu e atins, fiindca liniile libere nu modifica `crsarticole`.
|
||
- **Gol real ramas, neacoperit de S4 si S4b:** nu exista mecanism de validare a cantitatii/stocului
|
||
pentru un rand ales prin `combosql` — ambele rapoarte se opresc la maparea campurilor. `do_verifica_articol`
|
||
nu se poate refolosi ca atare (cere un `poArticol` scatter-uit dintr-un cursor sursa incarcat).
|
||
**DECIS — decizia 44 (Marius, runda 13): `poArticol` devine parametru explicit.** Se pastreaza un
|
||
**singur loc de validare**: `do_verifica_articol` primeste `poArticol` ca **parametru**, in loc sa
|
||
citeasca variabila `Private` populata de apelant. Schimbarea de contract a metodei e **aprobata ca
|
||
atare**; consecinta obligatorie e actualizarea **tuturor apelantilor existenti**, inventariati inainte
|
||
de prima editare. Aceeasi decizie acopera si `do_alege_stoc` / `frm_articol_gest_factura` din S4f (R7)
|
||
— o singura solutie pentru amandoua, cum cerea raportul.
|
||
|
||
*Gata cand:* pe o factura la comanda **si pe una din avize** se poate adauga un articol care nu e in
|
||
sursa, cu pretul din lista de preturi, si se poate sterge o linie adaugata, fara ca liniile din sursa
|
||
sa-si piarda validarea de cantitate **si fara ca suma care decide inchiderea automata sa se schimbe** —
|
||
proba directa: aceeasi comanda, cu si fara linii libere adaugate, produce acelasi rezultat de inchidere.
|
||
*Depinde de:* S2. **Interactioneaza cu S4 punctul 2** (registrul) si **avertizeaza S4f**.
|
||
|
||
#### S4f — Returul in formularul unificat
|
||
Decizia 17, proiectata in N. **Partea grea nu e ce credeam.** Factura de retur ca document (tipurile
|
||
8, 9, 24) functioneaza deja cap-coada: alegere multipla a facturilor sursa, populare din
|
||
`cursor_retur`, gestiune si pret de achizitie mostenite din liniile originale, stergere si retur
|
||
partial. Munca e:
|
||
|
||
1. **mutarea lui N.1 ca sursa in meniul de adaugare**, fara sa se atinga popularea — acelasi dialog,
|
||
aceleasi filtre, acelasi `cursor_retur`;
|
||
2. **ridicarea lui N.2 (`But_retur`) la nivel de document**, dupa modelul lui N.1, cu calea
|
||
per-articol pastrata;
|
||
3. **lista de preturi pe documentele de retur**, prin acelasi `APPEND FROM` ca la S4e.
|
||
|
||
Nu se ating: excluderea returului dintr-un retur, filtrarea pe client si valuta, maximul returnabil
|
||
calculat pe server, mostenirea gestiunii si a pretului de achizitie.
|
||
**DECIS (decizia 22):** linia de retur care nu vine din nicio factura originala **e permisa**, ca pe
|
||
orice alt document. Deci punctul 3 nu mai are conditie de intrare. Ce trebuie proiectat in schimb, pe
|
||
liniile libere: gestiunea si pretul de achizitie **se aleg** (ca la N.2), nu se mostenesc, iar maximul
|
||
returnabil calculat pe server **nu se aplica** — nu exista cantitate originala.
|
||
**Afisarea provenientei — VERIFICAT, si raspunsul e „nu la nivel de linie".** Raport:
|
||
`docs\cercetare\legatura_linie_retur.md`. Deci **S4f se livreaza fara coloana de provenienta pe linie**;
|
||
nu se inventeaza. Ce s-a stabilit, ca sa nu se reia:
|
||
|
||
- **Legatura se pierde chiar in cursorul care aduce datele.** `cursor_retur_document`
|
||
(`ff_...:3949-4062`) foloseste `V_LISTAID` **doar ca filtru** (`WHERE A1.ID_VANZARE IN (...)`,
|
||
`:4054-4055`); in lista de coloane a `SELECT`-ului extern (`:3965-4028`) **nu apar nici
|
||
`ID_VANZARE`, nici `ID_VANZARE_DET`**. `crsarticole` nu are de unde sti din ce factura vine randul.
|
||
- **`INSERT`-ul in `VANZARI_DETALII` nu are nicio coloana de sursa.**
|
||
- **Exista insa o legatura la nivel de DOCUMENT, si nu era cunoscuta in plan: `VANZARI_CORESP`.**
|
||
`scrie_corespondente_vanzari(3)` (`ff_...:14834-14836`, din `finalizeaza_factura`) scrie
|
||
`(ID_VANZARE_FACT = documentul de retur, ID_VANZARE_AVIZ = fiecare factura sursa, TIP = 3)`
|
||
(`:15481-15516`) — **cate un rand per factura sursa aleasa**, nu per linie. Numele coloanei e generic,
|
||
reutilizat si pentru perechi aviz-factura (`TIP = 1/2`).
|
||
- **Consecinta pentru UI:** cand s-a ales **o singura** factura sursa, se poate afisa corect „documentul
|
||
asta de retur provine din factura Y" — la nivel de antet, nu de linie. Cand s-au ales **mai multe**
|
||
(selectie multipla, suportata explicit de dialog), `VANZARI_CORESP` da **multimea** de facturi
|
||
posibile, deci nici macar antetul nu poate arata o sursa unica. **De asezat in UI ca informatie de
|
||
document, niciodata ca proprietate de linie.**
|
||
- **N.2 (`But_retur`) nu scrie nicio legatura.** `listaid` (perechi `ID_ARTICOL:ID_VANZARE`) e folosit
|
||
in `pack_facturare` (`ff_...:8142-8212`) exclusiv ca filtru pe `RUL`, ca sa calculeze cantitatea inca
|
||
disponibila din acea vanzare. Sursa nu ramane atribut al liniei noi.
|
||
**PROIECTAT (runda 12) — `docs\cercetare\s4f_retur_formular_unificat.md`**, cu **trei corectii** fata de
|
||
textul de mai sus:
|
||
|
||
- **Punctul 1 se restrange.** Alegerea facturilor sursa **nu se muta** in bara de butoane — ramane la
|
||
antet / in sectiunea pliata (confirmat impotriva `s4b_bara_butoane_meniu.md` §9.3 si a tabelului de
|
||
meniu de acolo). Ce se muta in meniul de adaugare e doar **„adauga tot din facturile alese"** si
|
||
**„alege liniile"**.
|
||
- **Un risc concret, netratat nicaieri pana acum (R1):** `frm_articol_gest_factura`
|
||
(`ofacturare.vc2:4094-4103`) face, sub `If Thisform.lRetur`, `poArticol.pretftva = pretv` — adica
|
||
**suprascrie pretul de vanzare cu pretul din stoc pe ORICE linie de retur** (verificat direct de
|
||
sesiunea principala). Corect pentru liniile **mostenite** dintr-o factura sursa; **gresit pentru
|
||
liniile libere** permise de decizia 22, care trebuie sa pastreze pretul din lista de preturi.
|
||
Raportul propune fixul.
|
||
- **Distinctia „linie libera" vs. „linie mostenita" nu cere camp nou: `crsfactura.id_c = 0`.** Oracle nu
|
||
produce niciodata `id_c = 0` din `ROWNUM`, deci valoarea implicita e ea insasi semnalul. Vine din
|
||
mecanismul impus de S4e: liniile libere intra direct in `crsfactura` (`APPEND BLANK` + `combosql`),
|
||
**nu** in `crsarticole` — asa ca ajustarea din `do_sterge` (care pe retur urmareste maximul returnabil)
|
||
devine **no-op prin constructie**. Acelasi semnal dezactiveaza si suprascrierea de pret de mai sus.
|
||
- **Gol nou (R7), pe care S4e nu-l are** (comanda si avizele n-au dialog de gestiune): azi se intra in
|
||
`do_alege_stoc` / `frm_articol_gest_factura` **doar** dintr-un `poArticol` scatter-uit din
|
||
`crsarticole`. O linie libera din `crsfactura` nu are asa ceva, iar decizia 22 cere ca gestiunea **sa
|
||
se aleaga**. Deci trebuie un **punct de intrare nou** in dialog. **Se unifica cu golul echivalent din
|
||
S4e** (validarea cantitatii, `do_verifica_articol`): e aceeasi problema structurala — dialogurile sunt
|
||
cuplate de `crsarticole` —, deci merita **o singura solutie**, nu doua.
|
||
**INCHIS prin decizia 44** (runda 13): `poArticol` devine **parametru explicit** si aici, nu variabila
|
||
`Private` populata de apelant — aceeasi solutie ca in S4e, cum cerea raportul.
|
||
- **R4 e inchis** (verificare independenta): `scrie_corespondente_vanzari(3)` e gatata pe `ntip IN (8,9)`,
|
||
nu pe `listaid`.
|
||
- **`VANZARI_CORESP` nu e afectata de liniile libere** — se scrie din `poDate.listaid`, fixat la antet.
|
||
**De confirmat (R4):** pentru `But_retur` ridicat la nivel de document, raspunsul pare a fi „fara
|
||
corespondenta persistata", pentru ca scrierea e gatata pe `ntip IN (8,9)`, nu pe `listaid`.
|
||
|
||
*Gata cand:* un document de retur deschis in formularul unificat aduce liniile facturilor alese cu
|
||
aceleasi valori ca azi — inclusiv gestiunea si pretul de achizitie —, permite stergere si cantitate
|
||
partiala, iar pe o factura normala se poate face retur alegand facturile o singura data. **In plus: o
|
||
linie libera pe un document de retur isi pastreaza pretul din lista de preturi**, adica nu trece prin
|
||
suprascrierea de la `:4094-4103`. Pasii cu criterii verificabile sunt la sectiunea 9 a raportului; ce nu
|
||
se poate testa headless, la sectiunea 11; riscurile R1-R6, la sectiunea 12.
|
||
*Depinde de:* S2, S4e.
|
||
|
||
#### S4g — Adaugarea de articole la modificarea oricarui document, inclusiv auto
|
||
Decizia 18, proiectata in O si O-bis. **Nu se porneste de la zero:** „Alte servicii” din ROAAUTO
|
||
face deja jumatate — articole reale langa linii sintetice, cu pret tastat, fara gestiune — doar ca
|
||
traieste in formularul de emitere si moare odata cu el. Se generalizeaza in formularul unificat, ca
|
||
a doua sursa din meniu („Alege din nomenclator…”), disponibila **si la modificare**, pe orice tip de
|
||
document, nu doar pe cele auto.
|
||
**Ordinea in care se lucreaza**, ca sa nu se blocheze tot: intai pe documentele ROAFACTURARE, unde
|
||
scrierea e a noastra; abia apoi pe `tip = -12`.
|
||
**Decizia 20 se aplica aici:** din nomenclator se ofera **si articole gestionabile, si
|
||
negestionabile** — nu se copiaza filtrul `in_stoc = 0` al lui ROAAUTO.
|
||
**Blocantul real e contul de venit, si el priveste doar ramura „Alege din nomenclator…”** (J-bis,
|
||
J-ter). Contul de venit vine din `NOTE_CONTABILE.SCC` **prin politica de pret**; un articol fara
|
||
`ID_POL` nu ajunge la cont gol, ci **la eroare** — `contabilizeaza_articol` ridica `FACT-024` si
|
||
opreste tranzactia. Pe ramura „Cauta in lista de preturi…” nu se schimba nimic: acolo politica exista.
|
||
**Premisa de la care pornea povestea asta a cazut:** „Alte servicii” din ROAAUTO **nu face deja
|
||
jumatate** din treaba — acele linii ocolesc complet `contabilizeaza_articol`, printr-o cale de
|
||
facturare paralela care nu genereaza nota de venit. Nu e un mecanism de generalizat, e o exceptie.
|
||
**DECIS (decizia 27, care inlocuieste 24):** contul de venit se **deriva**, nu se ia prin politica —
|
||
din `CORESP_CONT_VENCHELT` pentru articolele gestionabile (pe contul de gestiune al liniei), din
|
||
`NOM_ARTICOLE.CONT` daca e 6xx / 7xx pentru cele negestionabile, altfel **704**. **Derivarea se face
|
||
in VFP**, dar **transportul s-a schimbat la decizia 34**: contul calculat se trimite **direct, ca
|
||
parametru nou al lui `contabilizeaza_articol`**. Ocolul prin `id_pol` cu nota potrivita — politica
|
||
tehnica, interogarea inversa pe `SCC`, `pack_preturi.adauga_politica_pret_art` — e **abandonat**;
|
||
J-quater punctul 3 se citeste doar ca trasabilitate. **Decizia 35** adauga ca acelasi drum serveste si
|
||
editarea prin regenerare, deci nu se proiecteaza aici o a doua ruta de contare.
|
||
~~**De decis in aceasta poveste, nu inainte:** ce se intampla cand linia are **si** politica, **si**
|
||
cont trimis din VFP — cine castiga.~~ **PROIECTAT (runda 13) —
|
||
`docs\cercetare\s4g_adaugare_articole_modificare.md`.** Intrebarile despre politica tehnica in ecranul
|
||
de cautare a politicilor **au disparut** odata cu reteta.
|
||
|
||
**Raspunsul: niciuna dintre cele trei variante pure — parametrul castiga, dar combinatia ambigua e
|
||
oprita explicit, nu rezolvata tacit.**
|
||
- **Combinatia nu poate aparea in fluxul normal, si asta e dovedit, nu presupus.** `crsfactura.id_pol`
|
||
e `N(20) Null` (`COMUN\programe\ofacturare_comun.prg`, `creeaza_facturacrs` — **verificat direct**),
|
||
deci la `APPEND BLANK` ramane `.NULL.`, si ajunge la Oracle ca literalul `NULL`
|
||
(`ofacturare.vc2:14072`). Cursorul de cautare din nomenclator **n-are deloc coloana `id_pol`**, deci
|
||
nu exista punct in care o linie „din nomenclator" sa-l poata popula.
|
||
- **Singurul scenariu real de ambiguitate e regenerarea** (decizia 35): daca derivarea contului ar rula
|
||
**necondiționat** pe toate liniile documentului, si nu doar pe cele fara `id_pol`, o linie cu politica
|
||
reala ar primi si cont derivat. **E un risc de implementare VFP, nu Oracle** — dar proiectarea Oracle
|
||
nu trebuie sa-l faca invizibil.
|
||
- **Deci: `cont_venit IS NOT NULL` intra pe ramura noua; daca in acel moment `id_pol` e si el populat,
|
||
se ridica eroare** (cod nou, distinct de `FACT-024`, care ramane pentru cazul „nici politica, nici
|
||
cont"). Variantele „politica castiga" si „fallback la `NO_DATA_FOUND`" au fost respinse motivat:
|
||
prima defineste castigatorul pe **prezenta** campului, nu pe rezolvarea lui, si ar reintroduce
|
||
`FACT-024` acolo unde VFP a oferit deja o solutie; a doua e semantic cea mai curata, dar cere
|
||
**restructurarea interna** a functiei (un flag propagat din `EXCEPTION` pana la punctul de decizie),
|
||
fata de un singur `IF` la intrarea in ramura deja proiectata. **Ambele ascund o eroare de date in loc
|
||
s-o semnaleze.**
|
||
- **Regresie zero pe apelantii de azi**, prin constructie: cand `cont_venit` e `NULL` — adica toti
|
||
apelantii existenti, care nu cunosc parametrul —, executia intra direct pe `ELSE`, garda nu se
|
||
evalueaza niciodata, comportamentul e identic cu cel de azi.
|
||
- **De ales de Marius:** numarul concret al codului de eroare nou (`FACT-0xx`).
|
||
Separat, contul de **gestiune** e rezolvat ca regula (decizia 21): fallback, nu `NULL`, nu refuz.
|
||
**`pack_auto` nu mai e blocant** — `PACK_AUTO` nu citeste `VANZARI` / `VANZARI_DETALII` deloc (O,
|
||
intrebarea 1). Desincronizarea de afisare e **acceptata** (decizia 28); conditia e MANOPERA si
|
||
MATERIALE conform devizului.
|
||
**Blocantul netehnic a cazut si el:** gridul read-only din `frm_modific2024` e al lui #6, dar #13
|
||
incepe dupa ce #6 se termina (decizia 30).
|
||
**Restul proiectarii S4g, pe scurt** (detaliile in raport):
|
||
- **Suprafata pe Oracle**: `contabilizeaza_articol` primeste contul prin `VANZARI_DETALII_TEMP%ROWTYPE`
|
||
(`cont_venit`), deci semnatura functiei ramane aceeasi — se extinde **tipul de rand**. Consecinta de
|
||
livrare: **DB inainte de EXE**.
|
||
- **Derivarea in VFP** urmeaza fix decizia 27: `CORESP_CONT_VENCHELT` pentru gestionabile (pe contul de
|
||
gestiune al liniei), `NOM_ARTICOLE.CONT` daca e 6xx/7xx pentru negestionabile, altfel **704**. Ruleaza
|
||
**doar pe liniile fara `id_pol`** — vezi garda de mai sus; aici se leaga cele doua.
|
||
- **Fluxul in formular** refoloseste exact mecanismul lui S4e: linia „din nomenclator" intra prin
|
||
`APPEND BLANK` + `combosql` **direct in `crsfactura`**, niciodata in `crsarticole`.
|
||
- **Ramane deschis, mostenit din S4e:** validarea de cantitate/stoc pentru linia libera — se rezolva
|
||
prin decizia 44 (`poArticol` ca parametru explicit), aceeasi solutie pe ambele surse.
|
||
- **De re-rulat inainte de implementare, nu de presupus incheiat:** cautarea apelantilor lui
|
||
`adauga_articol_factura` in restul suitei (ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB). Risc asteptat zero
|
||
— folosesc proceduri separate sau alt pachet —, dar cautarea **nu s-a terminat in nicio runda**.
|
||
- **Trei hardcodari raman de confirmat de Marius, nu de presupus inofensive:** `CU_TVA = 1` (are efect
|
||
masurat prin `nproc_tva_max`, pe linie scutita + discount global), numele cheii de optiune de firma
|
||
pentru `SCD` (decizia 36) si domeniul ei `PROGRAME`, si trasabilitatea `CONT_VENIT` pe
|
||
`VANZARI_DETALII` (optionala pentru functionare, dar fara ea coloana nu se pastreaza dupa fapt).
|
||
|
||
**Nota de executie (decizia 60):** pe documentele de tip **48/49** (custodie), „Alege din
|
||
nomenclator…" ramane restrans la articole `IN_STOC = 0`, la fel ca ramura „Cauta in lista de
|
||
preturi…" (S4) — decizia 20 (si articole gestionabile, si negestionabile) **nu se aplica** pe
|
||
tipurile 48/49. Altfel se rupe invariantul pe care se sprijina siguranta regenerarii la editarea
|
||
custodiei (decizia 60, `docs\cercetare\custodie_48_49_stergere_reemitere.md`).
|
||
|
||
*Gata cand:* pe un document deja emis se poate adauga o linie noua, din lista de preturi sau din
|
||
nomenclator, si documentul se salveaza consistent — pe fluxurile ROAFACTURARE, cu partea auto
|
||
livrata separat, dupa (1). Pe un document 48/49, „Alege din nomenclator…" nu ofera si nu permite
|
||
adaugarea unui articol cu `IN_STOC <> 0`.
|
||
*Depinde de:* S4e, si de deciziile de mai sus. **Nu blocheaza etapa I.**
|
||
|
||
#### S5 — Acoperirea tuturor tipurilor
|
||
`frm_facturare_articole.Init` are 20 de ramuri pe `poDate.tip` (`:15107-15250`) care schimba titlul,
|
||
capul coloanei de cantitate, mesajul de stoc, vizibilitatea discountului, prezenta seriei. Toate
|
||
trebuie sa existe si in formularul unificat. Tipurile speciale raman pe calea lor:
|
||
`tip = 27` (`frm_avizare_lucrare`), `tip = 30` (aviz din NIR, formular nevizibil).
|
||
**PROIECTAT (runda 12) — `docs\cercetare\s5_acoperire_tipuri.md`. Povestea e mult mai mare decat
|
||
„porteaza cele 20 de ramuri", si motivul e ca baza de pornire aleasa nu are aproape nimic de portat.**
|
||
|
||
- **`Do Case`-ul de azi acopera 21 de valori de `tip`** (in 14 ramuri). **Patru tipuri reale,
|
||
reachable prin `factureaza()`, nu intra in niciun `Case`: `45` (factura restaurant), `48` / `49`
|
||
(custodie), `52` (contract, factura fiscala valuta)** — pierd titlu, cap de coloana, mesaj de stoc,
|
||
vizibilitatea discountului si eliminarea coloanei `cSerie`. **Nu doar `52`**, cum semnalase S4b.
|
||
Rutarea cursorului le recunoaste (`ofacturare.prg:271-282`); doar `Init` nu le-a „prins" niciodata.
|
||
**Nota de executie (decizia 60):** randul de configurare pentru `48`/`49` trebuie sa pastreze
|
||
restrictia la articole `IN_STOC = 0` mostenita de la sursa lor de azi (`cursor_articole_k`,
|
||
`PACK:3595-3701`, `:3695`) — vezi notele echivalente la S4 si S4g; e conditia de siguranta pentru
|
||
regenerarea la editarea custodiei (decizia 60,
|
||
`docs\cercetare\custodie_48_49_stergere_reemitere.md`).
|
||
- **Cinci tipuri (`43,44,46,50,51`) nu ajung deloc la acest formular** — zero potriviri in tot arborele
|
||
`D:\ROA`. `50` e marcat „in lucru" in sursa. Se declara explicit ramase in afara.
|
||
- **Descoperirea care schimba estimarea: prototipul nu e o versiune partiala a `Do Case`-ului — e
|
||
aproape gol.** `frm_facturare_articole2.Init` (`:18988-19080`) alege pe tip **doar** cuvantul
|
||
„factura"/„aviz", pe o lista mai scurta (lipseste `24`). Nu seteaza titlu (nu exista
|
||
`lb_titlu_alb_b121` in tot prototipul), nu schimba capul coloanei, nu schimba mesajul de stoc, nu
|
||
ascunde discountul, si **n-are deloc conceptul de coloana `cSerie`**. Daca formularul unificat porneste
|
||
de la prototip — cum decide S1 —, **toata diferentierea pe tip se reconstruieste de la zero**, nu se
|
||
completeaza. Asta e cel mai mare cost ascuns al etapei I descoperit pana acum.
|
||
- **Rutarea cursorului diverge pe TREI tipuri, nu unul:** pe prototip, ramura de contract e
|
||
`Inlist(tnTip, 2, 26, 6)` (`ofacturare.prg:762`) fata de `Inlist(tnTip, 2, 26, 6, 52)` pe standard
|
||
(`:283`) — **verificat direct de sesiunea principala** —, iar ramura de retur omite `24`. Pe aceste
|
||
tipuri, prin prototip, `lcSqlCursor` ar ramane **nedefinit**: eroare, nu doar comportament diferit.
|
||
- **Punctul lasat deschis de S4 punctul 2 se inchide aici:** tipurile **`26` si `52` n-au niciun
|
||
bookkeeping** `crsarticole` — nici Rol A, nici Rol B. Excluderea e totala, pe `Do Case` exhaustiv fara
|
||
ramura implicita, deci e „dovedit absent", nu „neconfirmat".
|
||
- **`30` nu e un formular separat**, cum spunea planul: e **acelasi `frm_facturare_articole`**, trecut
|
||
prin acelasi `Init`, dar niciodata aratat (`ofacturare.prg:444-453` — calculeaza totalurile, apasa
|
||
programatic `but_termin1.Click()`, apoi `Release()`, fara `Show()`). Deci **e afectat de golurile din
|
||
`Do Case`** ca oricare alt tip; doar ca defectele nu se vad pe ecran. `27` chiar ramane pe calea lui.
|
||
- **Alegerea de proiectare centrala, recomandata: tabel de configurare per tip**, un rand per `tip`, cu
|
||
exact proprietatile pe care le seteaza azi `Do Case`-ul (titlu, cap cantitate, mesaj stoc, discount
|
||
vizibil, are serie, tip doc, butoane, grup-sursa pentru meniul S4b). Motivul nu e estetic: **un
|
||
`Do Case` fara `Otherwise` nu semnaleaza niciodata un tip lipsa** — exact mecanismul care a lasat
|
||
patru tipuri pierdute ani la rand. Cu tabel, un tip necunoscut devine **eroare la deschidere**, iar
|
||
completitudinea se verifica **mecanic**, cu un `SELECT` fata de `tipuri_documente_facturare.md`, fara
|
||
sa porneasca formularul. Variantele „completeaza `Do Case`-ul" si „metoda per grup" au fost respinse
|
||
motivat: amandoua raman implicite, deci nu adauga detectie.
|
||
- **DECIS — decizia 48 (Marius, runda 13): tabelul e un CURSOR GENERAT IN COD la pornire**, nu `DBF`
|
||
static (recomandarea raportului) si nu tabela pe Oracle. Ambele au fost puse pe masa cu argumentele
|
||
lor si respinse: `DBF`-ul adauga un fisier de intretinut, de livrat la fiecare update si de tinut
|
||
sincron intre produsele ROA; tabela Oracle ar cere script de migrare si o citire in plus la
|
||
deschiderea formularului. **Ce NU se pierde prin alegerea asta:** detectia ramane intacta — tip
|
||
necunoscut = **eroare la deschidere**, exact castigul pentru care exista propunerea —, iar proba
|
||
mecanica de completitudine ramane posibila, doar ca ruleaza **din aplicatie**, nu cu un `SELECT`
|
||
din afara. **Ce se accepta:** orice tip nou de document cere **recompilare si versiune noua de exe**,
|
||
ca azi. Forma concreta: un `.prg` cu `CREATE CURSOR` + `INSERT`-uri, un rand per tip, incarcat o
|
||
singura data si citit de `Init` prin `SEEK` pe `tip`.
|
||
|
||
*Gata cand:* fiecare tip din `COMUN\docs\tipuri_documente_facturare.md` fie e acoperit, fie e
|
||
declarat explicit ramas pe calea veche — **verificat prin proba mecanica de la sectiunea 8 a raportului**,
|
||
nu prin citire. Include cele patru tipuri lipsa azi (`45,48,49,52`) si alinierea rutarii de cursor intre
|
||
standard si prototip. Pe `48`/`49`, in plus: restrictia `IN_STOC = 0` mostenita ramane activa (decizia
|
||
60) — nu se poate adauga un articol gestionabil.
|
||
*Depinde de:* S4.
|
||
|
||
#### S5b — Proforma si copierea pe formularul unificat
|
||
Deciziile 10 si 11. Amandoua vin **aproape gratuit**, pentru ca folosesc deja acest drum: proforma e
|
||
o valoare in combo-ul de tip document, copierea e `factureaza(tip, toFactura)` cu antetul
|
||
precompletat. De facut, concret:
|
||
- combo-ul `Ct_clb_fdoc` ramane in antetul unificat, cu realocarea de serie si numar la comutare;
|
||
- garzile `eProforma = 0` de pe notele contabile si atasamente raman intacte, iar raportul propriu de
|
||
proforma continua sa fie ales;
|
||
- copierea deschide formularul in starea „document nou”, cu antetul editabil (comportamentul de azi);
|
||
- **degradarea de tip din `do_copiaza` ramane pentru copiere si nu se aplica la regenerare** (D) —
|
||
sunt doua moduri distincte ale aceluiasi formular, nu acelasi comportament.
|
||
*Gata cand:* 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.
|
||
**VERIFICAT (runda 9) — `docs\cercetare\s5b_proforma_descarcare_gestiune.md`. Verificarea 4 e inchisa.**
|
||
**NU, gestiunea nu se descarca pe proforma** — pentru niciun articol, indiferent daca e gestionabil in
|
||
nomenclator. Si nu e un efect colateral al ascunderii stocului, e **prin design**: VFP marcheaza toate
|
||
liniile proformei negestionabile inainte de compunerea documentului, ceea ce le trimite cu sentinela
|
||
`id_gestiune = -1000`, iar pe Oracle `contabilizeaza_articol` sare apelul catre `descarca_gestiune`
|
||
exact pe acest sentinel. Intentia e explicita in changelog (12.03.2021 / 2.7.x): *„Articolele din
|
||
proforma sunt marcate 'negestionabile', astfel incat nu mai este necesara existenta articolelor in stoc
|
||
pentru a genera proforma."* — deci cerinta a fost „proforma trebuie sa mearga si fara stoc", nu „nu arata
|
||
plafonul". **Se corecteaza presupunerea din plan** ca zeroizarea `gestionabil` ar fi doar cosmetica.
|
||
Consecinta pentru S5b: sentinela `-1000` e contractul care trebuie pastrat — vezi sectiunile 6 si 7 ale
|
||
raportului pentru constrangerile de proiectare si ce lipseste la copiere.
|
||
|
||
**PROIECTAT (runda 12) — `docs\cercetare\s5b_proiectare_proforma_copiere.md`. „Aproape gratuit" nu mai
|
||
tine: proiectarea a scos la iveala un risc de date care nu era semnalat nicaieri.**
|
||
|
||
- **Mecanismul real care tine proforma curata nu e sentinela, ci routing-ul.** In `do_scrie_factura`
|
||
(`ofacturare.vc2:14282-14300`), `eProforma = 1` alege `scrie_proforma`, care **nu cheama niciodata**
|
||
`contabilizeaza_articol` — comentariul din cod o spune direct: *„salveaza doar in vanzari, nu si in
|
||
contabilitate"* (verificat de sesiunea principala). Sentinela `-1000` e al doilea strat, nu primul.
|
||
- **RISCUL CENTRAL — „drumul invers", nesemnalat pana acum si cu consecinta pe date.** Operatorul
|
||
adauga linii cu documentul pe **Proforma** (deci marcate `gestionabil = 0` / `id_gestiune = -1000`),
|
||
apoi comuta combo-ul inapoi pe **Factura** inainte de „Termina". Atunci routing-ul alege
|
||
`scrie_factura2`, care **chiar** cheama `contabilizeaza_articol` — dar acesta sare `descarca_gestiune`
|
||
exact pe sentinela `-1000` (`PACK:7472-7476`). Rezultatul: **o factura reala iese cu stocul
|
||
nedescarcat, silentios** — `-1000` e o valoare valida, nu ridica nicio exceptie. **Azi nu exista
|
||
nicio plasa pentru acest caz**, si nici nu putea exista: combo-ul traieste in dialogul separat
|
||
`frm_date_factura`, inchis **inainte** sa existe vreo linie. Riscul se naste **din unificare**.
|
||
- **De aici si de ce marcarea negestionabila nu mai poate fi un singur `UPDATE` de masa:** in
|
||
formularul unificat trebuie extrasa intr-o metoda refolosita din **trei** puncte — la incarcare, la
|
||
adaugarea unei linii, si la comutarea tipului cu linii deja prezente.
|
||
- **`id_c` la copiere: SIGUR, cu dovada.** `do_copiaza` degradeaza tipul spre grupul-tinta
|
||
**`{1,5,7,10,22,23}`**, care nu intra niciodata in ramurile Rol A din `do_scrie_factura` / `do_sterge`.
|
||
Coliziunea tehnica exista in date, dar **n-are efect observabil**. (Intrebarea venea din corectia lui
|
||
S4e — vezi acolo.)
|
||
> **CORECTIE (runda 13, verificata direct pe cod).** Grupul-tinta scris pana acum in plan
|
||
> (`{1,5,10,22}`) era **gresit**, si la fel era si `{1,5,7,10}` din raportul S5c. Setul real e cel de
|
||
> mai sus, citit din primul `CASE` al lui `frm_facturi.do_copiaza`
|
||
> (`COMUN\clase\ofacturare_comun.vc2:3693-3694`), care lasa neatinse exact `T1,T5,T7,T10,T22,T23`.
|
||
> Concluzia „copierea e sigura" **nu se schimba** — `7` si `23` nu au bookkeeping Rol A —, dar cifrele
|
||
> se corecteaza peste tot unde apar. Aceeasi corectie se aplica lui
|
||
> `s5b_proiectare_proforma_copiere.md` §2.1 / §7.
|
||
- **DEFECT PREEXISTENT, gasit in trecere la verificarea de mai sus — de raportat, NU de reparat acum.**
|
||
In `frm_facturi.do_copiaza`, ramura de avize scrie `lnTip = T22`
|
||
(`COMUN\clase\ofacturare_comun.vc2:3703`) in loc de `loFactura.tip = T22` — **singura ramura din tot
|
||
`Do Case`-ul care nu atribuie in obiect**; toate celelalte cinci scriu `loFactura.tip`. Consecinta:
|
||
la copierea unui aviz (`21,24,26,30,-7,-9,-10,-13,28,29,42`) **degradarea nu se produce**, iar
|
||
`copiere_factura` cheama `factureaza(toFactura.Tip, ...)`
|
||
(`COMUN\programe\oproceduri_facturare.prg:150-152`) cu tipul **original** — deci copia unui „aviz pe
|
||
baza de comanda" reintra pe ruta de comanda, nu pe cea de lista de preturi. **Verificat ca `factureaza`
|
||
nu citeste un `lnTip` privat** (`ofacturare.prg:101` declara `lnTipTemp`, nu `lnTip`), deci
|
||
atribuirea chiar se pierde; in plus `lnTip` e nedeclarat in metoda, deci poate suprascrie un `lnTip`
|
||
al apelantului. **Fisierul e in perimetrul interzis (#6) — se raporteaza, nu se atinge.**
|
||
|
||
**VERIFICAT (runda 12, la cererea lui Marius) — `docs\cercetare\verif_proforma_alegere_stoc.md`.
|
||
Pe proforma NU se alege stoc azi, si asta e deliberat.**
|
||
|
||
- **Un singur mecanism activ, si e in VFP, la incarcare:** `ofacturare.prg:333-336` face
|
||
`UPDATE (lcCursor) SET gestionabil = 0` cand `eProforma = 1`, **inainte** sa se deschida gridul.
|
||
Comentariul din cod spune intentia direct: *„Daca este o proforma, consider toate articolele
|
||
negestionabile, **pentru a nu mai alege din stoc**"* (12.03.2021). Deci `Do Case`-ul de la
|
||
`ofacturare.vc2:13803` vede mereu `gestionabil = 0` → **`do_alege_stoc` nu ruleaza niciodata**.
|
||
Valabil pe **toate** cursoarele de creare directa a unei proforme; **niciunul** n-are parametru
|
||
`V_PROFORMA` (verificat pe ~9 proceduri `cursor_` din pachet).
|
||
- **Mecanismul Oracle exista, dar e mort in fluxul curent:** `cursor_retur_document` (`PACK:3993-4000`)
|
||
are `CASE V_PROFORMA = 1 THEN 0`, insa se cheama doar la **copiere**, unde `V_PROFORMA` trimis e
|
||
`eProforma` al documentului **nou** — mereu `0`. **Nu e o contradictie intre rapoarte**: sunt doua
|
||
mecanisme reale, doar unul activ.
|
||
- **`pret_achizitie` depinde de sursa:** pe calea principala (lista de preturi) ramane `0` —
|
||
`cursor_preturi` nici nu-l selecteaza. Pe surse care carata un document existent (avize, copiere)
|
||
vine real din `VANZARI_DETALII.PRET_ACHIZITIE`.
|
||
- **Daca liniile ar pastra gestiunea reala pana la salvare, nu s-ar strica nimic pe contabilizare sau
|
||
stoc:** `adauga_articol_factura` se cheama oricum si pentru proforma, dar `scrie_proforma` **nu**
|
||
cheama `contabilizeaza_articol`, deci `descarca_gestiune` tot n-ar rula; iar **`do_alege_stoc` nu
|
||
rezerva stoc** (doar `SELECT` + scadere locala in memorie, zero scriere Oracle). Singurul loc unde
|
||
s-ar vedea o diferenta e la **relistare** (`crsDetaliiListare` / `fact_vfacturi2` citesc
|
||
`id_gestiune` fara filtru pe `eproforma`) — **neconfirmat** daca vreun raport chiar il tipareste.
|
||
|
||
**Consecinta care schimba forma deciziei: cele doua sensuri nu sunt simetrice.**
|
||
- **FACTURA → PROFORMA cu linii deja adaugate:** liniile au trecut deja prin `do_alege_stoc`, deci au
|
||
gestiune reala si pret de achizitie corect. **E sigur, si sentinela se poate aplica abia la salvare**
|
||
— exact varianta ceruta de Marius. **Fara atentionare.**
|
||
- **PROFORMA → FACTURA cu linii deja adaugate:** liniile au fost adaugate **fara** alegere de stoc
|
||
(`gestionabil` fortat `0`), deci **nu au gestiune**. Aici e riscul „drumului invers".
|
||
- **A forta alegerea stocului si pe proforma NU e o optiune** — ar regresa cerinta din 12.03.2021
|
||
(*„nu mai este necesara existenta articolelor in stoc pentru a genera proforma"*): un articol fara
|
||
stoc n-ar mai putea intra pe proforma, pentru ca `do_alege_stoc` ar cere un lot inexistent.
|
||
|
||
### Decizia 43 (Marius, runda 12) — proforma NU alege stoc, si factura se face DIN proforma
|
||
|
||
**Pe proforma nu se alege stoc, si asta e cerinta, nu efect colateral.** Motivul, in cuvintele lui
|
||
Marius: *„sa dau o proforma chiar si in absenta stocului, pentru ca ma intereseaza doar pretul de
|
||
vanzare, nu si cel de achizitie din stoc"*. Deci:
|
||
- **Varianta (b) — realegerea gestiunii linie cu linie la comutare — e RESPINSA.** Nu se mai
|
||
reargumenteaza.
|
||
- **Comutarea PROFORMA → FACTURA cu linii prezente se blocheaza**, cu mesaj explicit. Comportamentul de
|
||
azi (`gestionabil = 0` fortat la incarcare, `ofacturare.prg:333-336`) se **pastreaza**, nu se rafineaza.
|
||
- **Sensul FACTURA → PROFORMA ramane liber**, fara atentionare, cu sentinela aplicata **la salvare** —
|
||
liniile au deja gestiune reala, deci nu se pierde nimic.
|
||
|
||
**Cerinta noua: „ulterior o sa vreau si o factura din proforma".** Nu prin comutarea tipului pe acelasi
|
||
document, ci ca **document nou**, generat din proforma. **Mecanismul pare sa existe deja pe calea de
|
||
copiere** — `cursor_retur_document` reface gestionabilitatea reala cand `V_COPIERE = 1`
|
||
(`GESTIONABIL = B.IN_STOC`, `PACK:3993-4000`), deci liniile venite dintr-o proforma **redevin
|
||
gestionabile**, trec prin `do_alege_stoc` la adaugare, primesc `id_gestiune` real si descarca gestiune
|
||
normal (`docs\cercetare\s5b_proiectare_proforma_copiere.md` §2.6). **De verificat inainte de a te baza
|
||
pe asta**, pentru ca §2.6 descria copierea in general, nu cazul „sursa e o proforma":
|
||
1. poate fi azi o **proforma** aleasa ca sursa de copiere, sau e exclusa undeva?
|
||
2. `do_copiaza` degradeaza tipul spre `{1,5,10,22}` — ce tip rezulta dintr-o proforma si e cel dorit?
|
||
3. ~~se pastreaza legatura proforma → factura?~~ **RASPUNS (Marius, runda 12): DA — „ar fi bine sa aiba
|
||
urma sursei, la fel ca factura din aviz".** Deci trasabilitatea **e ceruta**, si tiparul de urmat e
|
||
cel deja existent pentru aviz → factura: `scrie_corespondente_vanzari(1)`, chemata din
|
||
`finalizeaza_factura`, care scrie in **`VANZARI_CORESP`** perechea
|
||
`(ID_VANZARE_FACT = factura, ID_VANZARE_AVIZ = documentul sursa, TIP = 1)`. Numele coloanei e generic,
|
||
deja reutilizat pentru mai multe feluri de perechi (`TIP = 1/2` aviz-factura, `TIP = 3` retur), deci
|
||
**structura nu se schimba — se adauga o valoare noua de `TIP`** pentru proforma → factura.
|
||
**De proiectat, nu de presupus:** ce valoare de `TIP` se aloca; de unde stie fluxul de copiere ca
|
||
sursa a fost o proforma (azi `do_copiaza` degradeaza tipul, deci informatia s-ar putea pierde
|
||
**inainte** de scriere — vezi punctul 2); si daca `marcheaza_facturat` / `FACTURAT` trebuie sau nu
|
||
atinse (pe aviz sunt, pe proforma probabil **nu**, pentru ca proforma nu e un document de livrare —
|
||
**de confirmat, e exact genul de detaliu care se copiaza gresit din tiparul avizului**).
|
||
~~**Aceasta e prima sarcina de proiectare a rundei 13.**~~ **LIVRATA — vezi S5c mai jos.**
|
||
|
||
*Depinde de:* S5.
|
||
|
||
#### S5c — Factura din proforma (decizia 43, cerinta noua)
|
||
**PROIECTAT (runda 13) — `docs\cercetare\s5c_factura_din_proforma.md`. Toate cele trei intrebari si
|
||
ambele capcane au raspuns cu dovada. Vestea buna: mecanismul de baza chiar exista, si nu se atinge.**
|
||
|
||
- **(a) O proforma poate fi azi aleasa ca sursa de copiere, fara nicio excludere.** `IsCopy` returneaza
|
||
**necondiționat `.T.`** (`COMUN\clase\ofacturare_comun.vc2:4969`, cu comentariul explicit *„POT SA
|
||
COPIEZ ORICE, TRATEZ TIPURILE IN DO_COPIAZA"*; filtrul vechi pe tip e comentat dedesubt, la `:4971`) —
|
||
**verificat direct**. Nici vizibilitatea butonului, nici filtrul de grid „Facturi&Avize / Proforme" nu
|
||
se uita la `eproforma`. Deci nu e nimic de deblocat.
|
||
- **(b) Tipul rezultat e corect, fara schimbare.** Copierea produce un document real
|
||
(`nIdTipDoc = 5`, `eproforma = 0`) — factura fiscala, exact ce trebuie. Degradarea lasa neatins
|
||
grupul-tinta **`{1,5,7,10,22,23}`** (vezi corectia de cifre de mai sus).
|
||
- **(c) `TIP = 4` e liber in `VANZARI_CORESP`** si se aloca pentru „factura din proforma". Confirmat
|
||
**cod + date** pe schema vie: tabela are un **singur scriitor in toata baza**
|
||
(`pack_facturare.scrie_corespondente_vanzari`), iar azi se folosesc doar `1/2/3`. **Structura nu se
|
||
schimba.**
|
||
- **Capcana (i) — confirmata, si e miezul poveștii.** `id_vanzare` al proformei **supravietuieste**
|
||
copierii (prin `poDate.listaid`), dar faptul ca **sursa era o proforma se pierde**:
|
||
`completeaza_setari_document` copiaza `.listaid`, dar **nu** si `eproforma`
|
||
(`COMUN\programe\ofacturare_comun.prg:387` — **verificat direct: `eproforma` nu apare nicaieri in tot
|
||
fisierul**). De aceea legatura **nu se poate agata de `CASE`-ul din `finalizeaza_factura`**, care e
|
||
cheiat pe `ntip` — `ntip` nu poarta distinctia. Solutia: un semnal nou, client-side
|
||
(`poDate.lProformaSursa`), capturat exact acolo unde informatia mai exista, plus un **apel Oracle
|
||
explicit separat** care reutilizeaza `scrie_corespondente_vanzari(4)` **neschimbata**. Zero cod PL/SQL
|
||
nou pe calea recomandata.
|
||
- **Capcana (ii) — INFIRMATA presupunerea comoda, cu patru argumente: `marcheaza_facturat` NU se cheama
|
||
pe proforma.** Proforma n-are `VANZARI_CANTITATI`, n-are ramura de reversare la stergere in
|
||
`sterge_factura`, nimic nu filtreaza dupa `FACTURAT` pe proforme, si oricum calea aleasa e in afara
|
||
`CASE`-ului care il cupleaza azi. Era exact detaliul care se copia gresit din tiparul avizului.
|
||
|
||
**Ce NU se schimba:** `IsCopy`, vizibilitatea butonului de copiere, filtrul de grid, degradarea de tip
|
||
din `do_copiaza`, `cursor_retur_document` (`GESTIONABIL = B.IN_STOC`), si `scrie_corespondente_vanzari`
|
||
insasi.
|
||
|
||
**INCHISE, nu de reintrebat (marcaj pus in runda 17).** Cele cinci puncte de mai jos au primit raspuns: punctul 1 (`TIP = 4`) prin **decizia 51**, restul in bloc prin **decizia 56** („da la toate"). Lista ramane ca **inventar al recomandarilor acceptate**, ca sa se stie ce s-a decis si de ce — nu ca intrebari:
|
||
1. **`TIP = 4`** — liber azi, dar alocarea e **ireversibila in date** odata intrata in productie. De
|
||
confirmat explicit, nu tacit.
|
||
2. **Apel pe starea de sesiune a pachetului (`clistaid` / `nid_vanzare`) vs. procedura noua cu
|
||
parametri expliciti.** *Recomandarea raportului:* varianta simpla (zero cod Oracle nou), **cu
|
||
conditia** verificata la implementare ca niciun apel Oracle intercalat nu reseteaza starea intre
|
||
scrierea facturii si scrierea corespondentei.
|
||
3. **Aceeasi proforma poate fi copiata de N ori**, fiecare copie cu randul ei `TIP = 4`. E comportamentul
|
||
implicit al oricarei copieri de azi. *Recomandare:* daca deranjeaza, avertisment — **nu** blocare.
|
||
4. **Garda simetrica la stergere** (*„nu poti sterge o proforma care are deja factura generata din ea"*),
|
||
pe tiparul `TIP IN (1,2,3)` din `sterge_factura` — de decis daca se doreste.
|
||
5. **Afisarea „provine din proforma X"** pe factura noua — vine gratis din legatura scrisa, la nivel de
|
||
**document** (ca la retur), nu de linie. De decis daca intra acum sau mai tarziu.
|
||
|
||
*Gata cand:* dintr-o proforma emisa se genereaza o factura reala, cu numar nou, care descarca gestiunea
|
||
normal, are rand `TIP = 4` in `VANZARI_CORESP` catre proforma sursa, iar proforma **nu** e marcata
|
||
`FACTURAT`.
|
||
*Depinde de:* S5b.
|
||
|
||
### Decizia 49 (Marius, runda 13) — cele doua formulare merg IN PARALEL, si ALEGE UTILIZATORUL
|
||
|
||
**Cerinta, in cuvintele lui Marius:** *„utilizatorul sa poata accesa alternativ, daca doreste"*. Deci
|
||
**nu** o setare care ruteaza tacit pe un flux sau altul, si **nu** un pilot pe cativa oameni: ambele
|
||
formulare raman accesibile, iar **alegerea o face omul, in momentul in care factureaza**. Rostul e sa
|
||
existe mereu **un flux despre care se stie ca functioneaza**, cat timp cel nou se stabilizeaza.
|
||
|
||
> **Corectie a rundei 13:** prima formulare a acestei decizii descria un pilot per utilizator, prin
|
||
> optiunea de firma. **Gresit** — Marius a corectat: optiunea **nu alege**, ci doar **face alegerea
|
||
> disponibila**. Nu se reargumenteaza in varianta veche.
|
||
|
||
**Mecanismul exista deja in produs si face exact asta**, nu se inventeaza:
|
||
- `factureaza` (`COMUN\programe\ofacturare.prg:87-93`) verifica `gnFacturareNou` si, cand e pornita,
|
||
**intreaba la fiecare facturare**: `AMESSAGEBOX('Facturare noua (DA) sau standard (NU)?', 4+32, ...)`.
|
||
Optiunea deschide alegerea; raspunsul il da utilizatorul, de fiecare data.
|
||
- `gnFacturareNou` e o **optiune de firma**: `optiuni_firma` (`COMUN\programe\oinit_optiuni.prg:225-275`)
|
||
cheama `SCRIE_OPTIUNI(gcUserName)`, parcurge `v_optiuni` si **declara dinamic** globalele publice dupa
|
||
tip (`Public gn&lcvarname` pentru `NUMERIC`), cu filtru optional pe program
|
||
(`Isnull(programe) Or gcNumeProgram $ programe`). **Deci se activeaza si se dezactiveaza din date,
|
||
fara livrare de exe.**
|
||
- **Fluxul vechi ramane intreg:** `factureaza` + `frm_facturare_articole`. S2 sterge doar
|
||
**`factureaza2`**, un fork mort din 2017 (executia interogarii dezactivata, `lnSucces = 1` hardcodat,
|
||
zero utilizatori reali) — **nu** calea veche. **S2 nu are voie sa desfiinteze alegerea.**
|
||
- **Pentru etapa II plasa e alta, si exista deja:** editarea prin regenerare e o **actiune noua**, deci
|
||
„fluxul vechi" pentru ea e **fluxul lui #6**, pe care decizia 38 il pastreaza oricum.
|
||
|
||
**Cum se prezinta alegerea — de ales la implementare, ambele satisfac cerinta:**
|
||
- **(A) intrebarea de azi**, modal la fiecare facturare. Exista deja, zero cod. Neajuns: intreaba si
|
||
cand utilizatorul stie de o luna ce vrea.
|
||
- **(B) doua intrari distincte** in meniu / doua butoane („Facturare" si „Facturare (nou)"). Aceeasi
|
||
libertate, fara modal la fiecare document. **Recomandat.** Se poate porni cu (A), care e gata, si trece
|
||
la (B).
|
||
|
||
**Limita, si trebuie spusa explicit ca sa nu creeze o falsa siguranta: alegerea acopera VFP-ul, nu
|
||
Oracle.** Modificarile din pachete — parametrul nou al lui `contabilizeaza_articol` (decizia 34),
|
||
variabila noua din `SET_IDFACT`, si `INSERT` → `MERGE` in `DOCUMENTE` (S9) — sunt **cod comun al
|
||
intregii suite** si se aplica **tuturor deodata**, indiferent pe ce formular alege omul sa lucreze.
|
||
Proiectarea le face **inerte prin constructie** (parametru `NULL` → executie identica cu azi;
|
||
`WHEN MATCHED` care nu se declanseaza pe drumul normal), dar asta e o garantie de regresie zero,
|
||
**nu** o cale de intoarcere. Consecinta practica: pe formular si procedura intoarcerea e imediata; pe
|
||
baza de date, siguranta vine din **testarea unui ciclu normal de scriere in fiecare produs** (deja
|
||
ceruta in S9).
|
||
|
||
### Decizia 50 (Marius, runda 13) — se editeaza documente curente, nu documente dintr-un lant
|
||
|
||
**Formularea lui Marius:** *„in principiu nu se poate edita un document pentru care s-a facut retur;
|
||
de principiu se pot modifica documente curente, nu cele care fac parte dintr-un lant"*.
|
||
|
||
**Deci garda de azi ramane, si devine regula declarata, nu limitare tolerata.** `sterge_factura` arunca
|
||
`ORA-20000` cand documentul are deja facturi / avize de retur emise peste el; S7 **semnaleaza conditia
|
||
inainte de intrarea in formular**, cu mesaj clar, nu ca eroare Oracle la final. Utilizatorul care chiar
|
||
vrea sa editeze sterge intai documentele-copil — comportament existent, nu ceva de construit.
|
||
|
||
**PRECIZAT de Marius (runda 13), si inchide punctul: „lantul" se citeste IN AMONTE, nu in ambele
|
||
sensuri.** In cuvintele lui: *„daca este generata factura din aviz, avizul nu se mai poate modifica,
|
||
factura da, pentru ca este documentul curent; ma refeream la documentele din lant anterioare"*.
|
||
|
||
Deci regula, in forma finala:
|
||
- **Documentul care are urmasi se blocheaza** — avizul din care s-a facut factura, factura peste care
|
||
s-a emis retur. Are deja o reprezentare in cod: garda din `sterge_factura`.
|
||
- **Documentul de la capatul lantului ramane editabil** — el e „documentul curent". **Factura din aviz
|
||
(`ntip = 4`) ESTE editabila**, chiar daca are parinte.
|
||
- Prin urmare **perimetrul etapei II nu se restrange**, iar intrebarea deschisa din S10 despre `ntip = 4`
|
||
(aceeasi re-derivare tacuta ca pe contract, dar cu alta sursa de comparat) **ramane in picioare** — nu
|
||
dispare, cum s-ar fi intamplat la citirea stricta.
|
||
|
||
**VERIFICAT in runda 14 — si premisa era gresita.** Raport: `docs\cercetare\garda_aviz_facturat.md`.
|
||
Se credea ca garda de azi blocheaza documentul doar cand are **retururi** peste el. **Nu e asa:** a doua
|
||
garda din `sterge_factura` testeaza `TIP IN (1, 2)`, iar **`TIP = 1` este corespondenta aviz → factura
|
||
normala, nu retur** (`EXPORT:5464-5476`, semantica citita ramura cu ramura din `CASE`-ul lui
|
||
`finalizeaza_factura`, `EXPORT:14818-14839`). Formularea gresita venea din citirea comentariului
|
||
`-- verific daca exista facturi sau avize de retur`, in care „de retur" se distribuia si peste „facturi";
|
||
codul zice altceva. **Deci regula ceruta de decizia 50 e deja implementata pentru avize** — nu e nevoie de
|
||
nicio garda noua ca *regula*.
|
||
|
||
**Dar sunt trei garzi, nu doua, si a treia schimba enuntul deciziei 50:**
|
||
|
||
| garda | `EXPORT` | ce blocheaza |
|
||
|---|---|---|
|
||
| 1 | 5452-5462 | **factura** care are facturi de retur peste ea (`TIP = 3`) |
|
||
| 2 | 5466-5476 | **aviz** care are factura (`TIP = 1`) sau aviz de retur (`TIP = 2`) peste el |
|
||
| 3 | 5480-5494 | **factura din aviz** ale carei avize-sursa au primit intre timp aviz de retur |
|
||
|
||
Prin urmare **„factura din aviz ESTE editabila" nu e neconditionat**: e editabila doar cat timp niciunul
|
||
dintre avizele ei nu a primit aviz de retur. Nu e „capat de lant" prin definitie.
|
||
|
||
**Ce lipseste nu e regula, e MOMENTUL.** Garda traieste in interiorul lui `sterge_factura`, deci se
|
||
manifesta ca `ORA-20000` **in mijlocul** pasului de stergere din regenerare — dupa ce utilizatorul a
|
||
completat formularul si dupa deschiderea tranzactiei. S7 are nevoie de un **pre-flight read-only** pe
|
||
**exact aceeasi conditie**, fara reimplementarea regulii (vezi S7). Interogarea se face pe
|
||
`VANZARI_CORESP`, **nu** pe `VANZARI.FACTURAT`: `FACTURAT` e un marcaj derivat, scris si resetat, dar
|
||
**necitit de nicio garda** — semnalul autoritar e `VANZARI_CORESP`.
|
||
|
||
**GOLUL REAL NU E PE AVIZ, E PE PROFORMA — si a devenit relevant chiar in runda 14, odata cu decizia 51.**
|
||
`pack_facturare.sterge_proforma` (`EXPORT:5610-5635`) **nu are nicio garda**: corpul ei e doua
|
||
`UPDATE ... SET STERS = 1`. E o procedura **complet separata**, care nu cheama `sterge_factura`, deci
|
||
garda existenta **nu se extinde automat** la `TIP = 4`. O proforma din care s-a emis factura se poate
|
||
sterge azi fara niciun avertisment. Calea VFP iese devreme din `do_sterge`
|
||
(`ofacturare_comun.vc2:4707-4719`), inainte de restul verificarilor. **Asta e continutul concret al
|
||
punctului deschis 4 din S5c** („garda simetrica la stergere") — nu mai e o intrebare de principiu, e o
|
||
garda de scris intr-o procedura care azi n-are niciuna.
|
||
|
||
**Comanda si contractul nu trec prin `VANZARI_CORESP`** si n-au garda de tip „are urmasi" pe factura:
|
||
comanda se leaga prin `VANZARI.ID_COMANDA` + `inchide_comanda`, iar garda ei e **in VFP si pe comanda**,
|
||
nu pe factura (`COMUN\clase\ocomenzi.vc2:1806-1807` la modificare, `:2065-2066` la stergere); contractul
|
||
se leaga prin `VANZARI.ID_CTR` + `CTR_RATE_FACTURI`.
|
||
|
||
### Deciziile lui Marius, runda 13 (10.08.2026) — luate, nu de reluat
|
||
|
||
Cele cinci puncte neblocante ramase din runda 12. **Patru din cinci au mers pe recomandare; al
|
||
cincilea (48) a respins-o motivat.** Fiecare e scrisa si la locul ei, in povestea careia ii apartine.
|
||
|
||
44. **`poArticol` devine parametru explicit** al dialogurilor de linie (`do_verifica_articol`,
|
||
`do_alege_stoc` / `frm_articol_gest_factura`), in loc de variabila `Private` populata de apelant.
|
||
**O singura solutie pentru golul din S4e si cel din S4f (R7)** — e aceeasi problema structurala.
|
||
Schimbare de contract, **aprobata ca atare**; cere inventarul si actualizarea tuturor apelantilor
|
||
existenti inainte de prima editare. (S4e, S4f)
|
||
45. **Asimetria din `do_modifica`** se lasa sa se **corecteze de la sine** prin recalculul la cerere,
|
||
dar corectia se **declara explicit in changelog**. (S4, punctul 2)
|
||
46. **Corectia pe tipurile `23,41` asteapta punctul 2** (recalculul pe server, care acopera Rolul B).
|
||
Punctul 1 **nu se redeschide** acum. (S4, punctul 2)
|
||
47. **`zi_curs`: simetrie.** Campul se ascunde la loc la stergerea ultimului articol in valuta;
|
||
„clipitul" e acceptat ca pret al unei reguli unice. (S4d)
|
||
48. **Tabelul de configurare per tip = cursor generat in cod la pornire**, nu `DBF` static, nu tabela
|
||
Oracle. Detectia tipului necunoscut (eroare la deschidere) se pastreaza; se accepta recompilarea
|
||
la orice tip nou. (S5)
|
||
|
||
### Deciziile lui Marius, runda 14 (11.08.2026) — luate, nu de reluat
|
||
|
||
51. **`TIP = 4` in `VANZARI_CORESP` = „factura scrisa dintr-o proforma".** Confirmat explicit, dupa ce
|
||
i s-a explicat ce inseamna `1/2/3` (`TIP` = **natura legaturii parinte-copil**, nu tipul
|
||
documentului: `1` = aviz → factura, `2` = aviz → aviz de retur, `3` = factura → factura de retur).
|
||
`4` intra in aceeasi familie cu `1`. Valoarea e libera pe ambele fronturi (niciun apel cu `4` in
|
||
pachet, zero randuri in date), tabela are un singur scriitor in toata suita, structura nu se
|
||
schimba. **Alocarea e ireversibila odata cu primele date de productie** — acceptat ca atare. (S5c)
|
||
52. **`do_modifica` ramane activ pentru multi-selectie.** Formularul unificat preia cazul cu un singur
|
||
document; calea veche ramane pentru modificarea in bloc. **Nicio capacitate nu se pierde la
|
||
retragere** — dar consecinta e ca S2 nu poate desfiinta nici aceasta ruta, nu doar alegerea de la
|
||
decizia 49. (S8b, punctul 10)
|
||
53. **Atasamentul PDF se sterge la reemitere**, nu se remigreaza si nu se marcheaza „versiune
|
||
inlocuita". Documentul reemis porneste curat; PDF-ul se regenereaza la prima listare. **Consecinta
|
||
semnalata explicit lui Marius si acceptata de el:** urma a ceea ce s-a trimis efectiv clientului
|
||
dispare din sistem. Pasul `UPDATE ATASAMENTE_VANZARI SET id_vanzare = :nou`, adaugat in S9 la runda
|
||
13, **se inlocuieste cu stergere**. (S11, punctul 15)
|
||
54. **La reemitere se scriu valorile din formular, nu se reciteste sursa.** Formularea lui Marius:
|
||
*„nu inteleg de ce se schimba valorile fata de ce se incarca din factura sursa care se modifica?
|
||
asta este comportamentul pe care il doresc — modific sursa"*. **Asta rastoarna S10:** intrebarea nu
|
||
mai e „ce garda punem peste re-derivare", ci **„re-derivarea chiar se produce pe calea de
|
||
reemitere?"** — si daca da, se **elimina**, nu se avertizeaza. Avertizarea + confirmarea propuse de
|
||
raportul S10 sunt **respinse**: nu se cere utilizatorului sa confirme o schimbare pe care n-a
|
||
cerut-o. Vezi S10, rescris. (S10, punctele 11 si 12)
|
||
56. **„DA LA TOATE" — Marius a acceptat in bloc toate recomandarile deschise, runda 14.** Formularea
|
||
lui: *„da la toate, mai putin"* cele doua puncte pe care le-a intrebat separat (48/49 si voiajele).
|
||
**Nu se mai reintreaba niciunul dintre punctele de mai jos** — sunt luate, si fiecare e scris si la
|
||
locul lui, in povestea careia ii apartine:
|
||
- **S8** — canalul de citire a liniilor: **(B), procedura noua `cursor_editare_document`** (nu se
|
||
extinde `cursor_retur_document`, ca sa nu se schimbe comportamentul copierii; nu
|
||
`FACT_VFACTURI_DETALII`, care pierde `ID_POL`, `PRETD` si tratamentul valutar — argument intarit
|
||
de faptul ca **`VVANZARI_ARTICOLE` nu expune `ID_POL` / `ID_CTR`**, vezi S10).
|
||
- **S8** — `GESTIONABIL` la editare: **din document**, nu din nomenclatorul curent.
|
||
- **S8** — `text_aditional`: **se normalizeaza la incarcare** (`Chr(170)` → `CR+LF`) si se
|
||
re-normalizeaza la comparatie. Formele diferite salvate de cele doua rute de scriere se
|
||
**semnaleaza separat** ca defect preexistent.
|
||
- **S8** — `zi_curs` pe calea de editare: **ascuns** (precedent: tipurile 8/9). Abatere mica de la
|
||
decizia 5, asumata.
|
||
- **S8** — `poDate.lEditare`: **proprietate pe `oDateFactura`**, nu parametru (patru locuri au
|
||
nevoie de semnal; `lCopiere` e deja acolo cu acelasi rol).
|
||
- **S8** — `id_ruta`: **proprietate noua pe `oDateFactura`** (fara ea S8c nu poate implementa unul
|
||
din cei 14 parametri).
|
||
- **S8** — defectul de prefixare `text_aditional` la `Init` pentru contracte: **se ocoleste in #13**
|
||
prin `lEditare` si **se semnaleaza separat**, nu se repara pe calea de emitere.
|
||
- **S5c** — apelul Oracle pentru legatura proforma → factura: **varianta simpla**, pe starea de
|
||
sesiune a pachetului, zero cod PL/SQL nou — **cu conditia verificata la implementare** ca niciun
|
||
apel intercalat nu reseteaza starea intre scrierea facturii si scrierea corespondentei.
|
||
- **S5c** — aceeasi proforma facturata de N ori: **avertisment, nu blocare**.
|
||
- **S5c** — garda simetrica la stergerea proformei: **se scrie**. Nu e reutilizare —
|
||
`sterge_proforma` n-are azi nicio garda (vezi decizia 50, sectiunea rescrisa).
|
||
- **S5c** — afisarea „provine din proforma X": **da**, la nivel de document.
|
||
- **S4g** — `CU_TVA = 1` hardcodat: **se verifica pe date inainte de implementare**, nu se
|
||
presupune inofensiv. Efectul prin `nproc_tva_max` e masurat, pe linie scutita + discount global.
|
||
- **S4g** — trasabilitatea `CONT_VENIT` pe `VANZARI_DETALII`: **da**, se pastreaza coloana.
|
||
- **Decizia 54, cele trei consecinte: acceptate toate trei.** `IN_STOC` vine din formular (si **S8
|
||
trebuie sa-l incarce** — vezi S10, consecinta 1); **se pierde validarea** liniei fata de comanda
|
||
pe ramura comenzi, asumat; **`PROC_TVAV` ramane derivat** — reemiterea dupa o modificare legala
|
||
de cota va da cota noua, **acceptat deocamdata**; transformarea lui in parametru ramane o
|
||
decizie separata, daca se cere vreodata reproducere exacta si peste asta.
|
||
- **Defectul `lnTip` din `do_copiaza`** (runda 13): **se repara la #6**, fisierul fiind al lui.
|
||
- **Punctele pur interne** (numarul codului de eroare `FACT-0xx`, numele cheii de optiune
|
||
`FACT_SCD_ARTFPRET`, forma semnalului de regenerare) — **lasate la latitudinea implementarii**,
|
||
cu recomandarile deja scrise in povestile lor.
|
||
|
||
**Raman deschise doar doua**, si amandoua din motive proprii, nu din lipsa de raspuns:
|
||
**(a) tipurile 48/49** (custodie) — Marius a cerut sa stie implicatiile, i s-au explicat, decizia
|
||
n-a fost inca data. *Inchis intre timp — decizia 60, runda 16: da, sunt editabile prin #13,
|
||
cu executia conditionata de verificarea custodiei in curs.*
|
||
**(b) cota si explicatia de TVA a discountului de document** —
|
||
**cercetare TERMINATA** (sectiunea K-bis): cota era regula implicita „cota maxima de pe factura",
|
||
explicatia e azi o constanta hardcodata (`ReasonCode="95"`, text „Discount"). **Partea de
|
||
repartizare s-a decis — decizia 59, runda 16: proportional pe cote.** Ramane deschis doar campul
|
||
text optional de motiv — **inchis si el: decizia 61** (da, se adauga), cu asezarea fixata de
|
||
**decizia 66** (in banda de totaluri, langa discount).
|
||
55. **Metoda de executie e obligatorie, si e scrisa in plan.** La implementare planul **se sparge pe
|
||
stories**, fiecare story fiind o livrare de sine statatoare; **fiecare pas se testeaza**, nu doar
|
||
capetele de etapa (S6 / S12); si **fiecare story trece prin code review dupa implementare si dupa
|
||
teste, inainte de commit**. Sectiunea **„Metoda de executie"**, imediat inainte de Etapa I. S13
|
||
nu mai e momentul review-ului, ci al inchiderii.
|
||
|
||
### Deciziile lui Marius, runda 15 (11.08.2026) — luate, nu de reluat
|
||
|
||
57. **Asezarea zonei de jos: VARIANTA D.** Aprobata explicit („sunt de acord cu varianta D"), dupa doua
|
||
corectii cerute de el pe drum: (a) *„imi place linia de totaluri de la varianta C, dar incasarea si
|
||
alte date le vreau tot in acelasi formular, colapsate, mai jos de totaluri"*; (b) *„sectiunile
|
||
incasare si alte date colapsate trebuie sa fie pe acelasi rand — este destul loc pentru amandoua,
|
||
detaliile pot sa fie grupate pe orizontala, nu pe verticala"*. A / B / C **cad**.
|
||
|
||
**Ce inseamna D, concret, pentru S1 si S3:**
|
||
1. **Banda de totaluri** (preluata din C): pe toata latimea, lipita de grid, cu baza, discountul pe
|
||
articole, discountul de document **cu procentul editabil pe loc** si TVA desfacute pe un rand;
|
||
totalul mare, singur, la dreapta.
|
||
2. **Incasare si Alte date sunt sectiuni colapsabile in formular, nu dialoguri modale** — **una
|
||
langa alta pe acelasi rand**, sub totaluri, fiecare pe jumatate de latime. Randul inchis arata
|
||
**rezumatul continutului** („NUMERAR · 5 570,55 lei"), nu doar un titlu. Independente: se poate
|
||
tine deschisa doar una. Campurile dinauntru se aseaza **pe orizontala**, doua randuri fiecare.
|
||
3. **Nu exista bara de comenzi jos.** `but_renunt` / `but_termin` raman unde sunt azi — in banda de
|
||
titlu, sus in dreapta (`COMUN\clase\cmd_butoane.vc2:288` si `:386`, butoane-imagine cu
|
||
`Top = 1`, `Anchor = 8/9`, tooltip „Renuntare (ESC)" / „Terminare (CTRL+F)").
|
||
4. **Antetul strans la doua randuri**, fara titluri de grup, si **panoul „Discount pe document"
|
||
dispare** ca panou separat.
|
||
|
||
**Patru consecinte de dus in executie, nu de redescoperit:**
|
||
- **Dispare „renunt doar la incasare".** Fara `Accept` propriu pe dialog, ce se completeaza in
|
||
sectiune se scrie la `Termina`, impreuna cu documentul. **I-a fost spus explicit** inainte de
|
||
aprobare si a acceptat.
|
||
- **Validarea incasarii nu mai are moment propriu** — se muta in `Termina`, langa restul
|
||
verificarilor. **De scris explicit in S9.**
|
||
- **Starea deschis/inchis a sectiunilor** — de decis daca se retine intre documente sau porneste
|
||
mereu inchisa. Nu blocheaza nimic; recomandare: porneste inchisa, se retine per utilizator.
|
||
- **Caption pe cele doua butoane.** Sus in dreapta, langa `✕`-ul ferestrei, un `✓` verde fara text
|
||
e ambiguu. Punctul era deja notat in v8 pentru `But_renunt1` / `But_reset1`; D il face mai
|
||
apasat, pentru ca acum ele sunt **singura** cale de iesire.
|
||
|
||
**INCHIS.** Cercetarea despre cota si explicatia de TVA a discountului de document (punctul
|
||
deschis (b) de la decizia 56) **s-a terminat** — vezi sectiunea K-bis — si repartizarea s-a decis
|
||
(**decizia 59, runda 16**: proportional pe cote, fara sa se ceara cota de la utilizator), deci a
|
||
treia sectiune „grea" (cota + explicatie proprii) nu mai e in discutie. Ramane varianta minimala:
|
||
**decizia 61 (runda 16) a materializat-o** — Marius vrea campul text optional de motiv. Asezarea
|
||
lui a oscilat o data: decizia 64 il facea a treia sectiune jos, **decizia 66 (runda 17) o
|
||
rastoarna si il muta in banda de totaluri, langa discount**. **Punctul 2 de mai sus ramane deci
|
||
exact cum a fost aprobat: doua sectiuni jos, fiecare pe jumatate de latime.** D ramane intr-un etaj.
|
||
|
||
58. **Mockup-ul asezarii ramane doar online.** Formularea lui: *„nu vreau artifactul html, doar online,
|
||
ca sa nu mai intretii 2 variante"*. `docs\mockup_13_variante_asezare_jos.html` **a fost scos din
|
||
`docs\`**; sursa de adevar e
|
||
**https://claude.ai/code/artifact/dfc70d38-856f-48fd-b6af-3da78e9da4f7**.
|
||
Ca sa-l modifici: `WebFetch` pe URL → scrie HTML-ul intr-un fisier de lucru **in scratchpad, nu in
|
||
`docs\`** → `Artifact` cu **`url` = link-ul de mai sus** (fara `url` se creeaza link nou).
|
||
**`docs\mockup_13_formular_unificat.html` (v8) nu intra sub regula asta** — cerinta a fost data
|
||
numai pentru mockup-ul asezarii.
|
||
|
||
### Decizia 59 (Marius, runda 16) — luata, nu de reluat
|
||
|
||
59. **Discountul de DOCUMENT se repartizeaza PROPORTIONAL PE COTE.** Formularea lui: *„discount pe
|
||
document repartizat proportional pe cote"*. Se adopta recomandarea cercetarii din **K-bis**:
|
||
regula de azi („toata valoarea discountului primeste cota MAXIMA de pe factura", prin
|
||
`Calculate Max(proc_tvav)`) **se inlocuieste** cu repartizarea proportionala cu baza fiecarei
|
||
cote de pe factura. **Nu se cere utilizatorului cota** — repartizarea e automata.
|
||
|
||
**Ce atrage dupa sine, tot din K-bis:**
|
||
1. **Doua locuri de schimbat, nu unul, si in ACEEASI livrare:** `prelucreaza_facturacrs` (VFP,
|
||
`COMUN\programe\ofacturare_comun.prg:1886-1897`) trebuie sa insereze cate un rand-sentinela
|
||
**per cota** in loc de unul singur; si `recalculeaza_totaluri_vanzari` (PL/SQL,
|
||
`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16081-16092`) trebuie sa inlocuiasca `MAX(...)`
|
||
cu suma repartizarii. Daca se schimba doar unul, `VANZARI.TOTAL_TVA` si TVA-ul din eFactura
|
||
**diverg** pe facturile cu cote mixte. **Nu e optional si nu se poate esalona.**
|
||
2. **Bucatile de discount trebuie sa primeasca `id_jtva_coloana` al grupului pe care il reduc**,
|
||
nu doar cota. Cheia de grupare din `xmlefactura.prg:246` are cinci campuri si `expltva` se
|
||
completeaza tot prin `id_jtva_coloana`. O implementare care seteaza doar `proc_tva` **lasa
|
||
grupul orfan exact unde e azi** — repara jumatate din defect si o lasa pe cealalta.
|
||
3. **eFactura nu cere nicio modificare** — `xmlefactura.prg:758-792` grupeaza deja
|
||
`GROUP BY proc_tva` si emite cate un `AllowanceCharge` per cota.
|
||
4. **Diferenta de rotunjire cade pe cota cu baza cea mai mare**, ca suma bucatilor sa fie exact
|
||
`VANZARI.DISCOUNT`. E recomandarea cercetarii, luata ca implicita — Marius a fost instiintat
|
||
ca se merge asa fara sa mai fie intrebat, deci se schimba doar daca obiecteaza. (Raportul
|
||
spune pe alocuri „ultima cota preia diferenta"; **regula care se implementeaza e cea de aici**,
|
||
ca sa nu ramana doua formulari in circulatie.)
|
||
5. **Doua consecinte vizibile, acceptate implicit prin decizie:** factura tiparita va arata **N
|
||
randuri** „Discount X % Factura" in loc de unul, pe facturile cu cote mixte; si **nota
|
||
contabila** primeste TVA-ul discountului spart pe cote.
|
||
6. **Rezolva si grupul orfan** de pe facturile scutite / taxare inversa / intracomunitare
|
||
(K-bis), fara garda separata, si desfiinteaza ambiguitatea lui `agettipcota(1)`.
|
||
|
||
**Raman DESCHISE, nu de presupus rezolvate:**
|
||
- **campul text optional de motiv** (`AllowanceChargeReason` in locul constantei „Discount";
|
||
`ReasonCode` ramane `95`) — Marius **nu s-a pronuntat**; de el atarna si intrebarea de asezare
|
||
din S1 / decizia 57 (a treia sectiune pe rand sau rand propriu);
|
||
- **retroactivitatea la relistare / retrimitere**: o factura veche relistata sau retrimisa in
|
||
eFactura ar genera alt XML decat cel trimis initial. **Nedecis.**
|
||
|
||
### Deciziile 60-65 (Marius, runda 16) — luate, nu de reluat
|
||
|
||
60. **Facturile de marfa in CUSTODIE (tipurile 48 si 49) SUNT editabile prin #13.** Formularea lui:
|
||
*„vreau sa fie posibila editarea si a facturilor in custodie"*. Intra deci in perimetrul
|
||
**etapei II**, contrar recomandarii „nu acum" din raportul S8 (intrebarea 7, §8.2).
|
||
|
||
**Inchide** punctul **(a)** de la **decizia 56** (tipurile 48/49, singurul ramas deschis din
|
||
blocul „da la toate") si **necunoscuta N5** din `docs\cercetare\s8_incarcare_document.md` §8.1,
|
||
plus restul intrebarii 7 din §8.2.
|
||
|
||
**Ramificatie noua pentru S8:** pe tipurile 48/49, controlul `ct_clb_altele` e scos
|
||
**neconditionat** la copiere (`ofacturare.vc2:9705-9712`), spre deosebire de tipurile 1/5/10
|
||
unde copierea il **pastreaza** si il reeticheteaza (`s8_incarcare_document.md` §3.2, ramura 3).
|
||
Calea de **editare** trebuie sa-l pastreze si pe custodie — ramura 48/49 a copierii nu poate fi
|
||
refolosita ca atare.
|
||
|
||
**VERIFICAT — blocantul CADE, dar premisa initiala era gresita.** Raportul:
|
||
`docs\cercetare\custodie_48_49_stergere_reemitere.md`. `scrie_fact_aviz_custodie` **nu are
|
||
legatura cu tipurile 48/49** — are un singur apel in tot pachetul (`PACK:7521`), pe ramura
|
||
`pack_facturare.ntip <> 4` (`:7472`), deci serveste `ntip = 4` (factura din avize), nu custodia;
|
||
numele procedurii a indus in eroare, si premisa gresita a circulat pana in aceasta decizie.
|
||
Emiterea unui document 48/49 **nu atinge deloc stocul**: sursa lor unica de articole e
|
||
`cursor_articole_k` (`PACK:3595-3701`), restransa explicit la `WHERE C.IN_STOC = 0` (`:3695`),
|
||
iar `descarca_gestiune` se cheama doar cand `in_stoc = 1` (garda dubla, la apelant `:7472-7475`
|
||
si in corpul procedurii `:7789-7797`). `sterge_factura` (`:5432-5607`) nu are ramura dedicata
|
||
pentru 48/49, si nici cele trei garzi de refuz al stergerii (`:5452-5494`) nu le prind — dar
|
||
**n-are ce reversa**, fiindca nimic legat de stoc n-a fost scris la emitere. **Regenerarea e
|
||
sigura pe 48/49**, nu pentru ca reversarea ar functiona, ci pentru ca nu exista nimic de
|
||
reversat.
|
||
|
||
**Rezerva, de scris, nu de ascuns:** siguranta atarna de un invariant azi impus doar de sursa de
|
||
articole — „documentele 48/49 contin numai articole cu `IN_STOC = 0`". Invariantul **nu s-a
|
||
verificat exhaustiv**, doar constatat pe sursa curenta. #13 schimba modul de adaugare a
|
||
articolelor (**S4** — cautare pe server, in linie; **S4g** — adaugare de articole la modificarea
|
||
oricarui document): daca formularul unificat ajunge sa permita adaugarea unui articol
|
||
**gestionabil** pe un document 48/49, invariantul se rupe si concluzia de siguranta pica.
|
||
**Cerinta pentru S4/S4g/S5: pe tipurile 48/49 se pastreaza restrictia la articole `IN_STOC = 0`**
|
||
— vezi notele de executie la acele povesti; devine **criteriu de test**, nu presupunere.
|
||
|
||
Pentru **emitere**, tipurile 48/49 erau oricum deja acoperite de etapa I (S5 completeaza cele
|
||
patru randuri lipsa din `Do Case`: 45, 48, 49, 52) — decizia 60 priveste doar **editarea**.
|
||
|
||
61. **Discountul de document primeste un CAMP TEXT OPTIONAL de motiv.** Formularea lui: *„la
|
||
discount, da, un camp text optional"*.
|
||
|
||
**Inchide** ultimul punct ramas deschis din **K-bis** si din **decizia 56 (b)** — campul de
|
||
motiv nu mai e „Marius nu s-a pronuntat".
|
||
|
||
**Ce inseamna concret:**
|
||
- inlocuieste constanta hardcodata `"Discount"` ca `cbc:AllowanceChargeReason`
|
||
(`COMUN\programe\xmlefactura.prg:774-776`); **`ReasonCode` ramane `95`**;
|
||
- cere **stocare noua** — azi nu exista nicio coloana pe `VANZARI` pentru motivul discountului
|
||
de document;
|
||
- cere **un control nou in formular** — singura bucata din reparatia discountului (K-bis /
|
||
decizia 59) care chiar cere UI nou, restul fiind repartizare automata fara interactiune.
|
||
|
||
**Redeschisese, in varianta minimala, intrebarea de asezare de la decizia 57. INCHISA DEFINITIV
|
||
PRIN DECIZIA 66 (runda 17): campul sta in banda de totaluri, langa discount.** Decizia 64, care il
|
||
facea a treia sectiune jos, **e rasturnata** — randul de jos ramane cu doua sectiuni, ca la decizia
|
||
57. Varianta D ramane intr-un etaj. Paragrafele din **S1** si din **decizia 57** sunt actualizate
|
||
in acest sens.
|
||
|
||
62. **Restrictia de modificare e „documentul sa NU fi fost trimis in eFactura" — si de aici
|
||
retroactivitatea NU mai e o intrebare.** Formularea lui: *„singura restrictie pentru modificare
|
||
este sa nu fie trimisa in eFactura, deci nu are legatura retroactivitatea"*.
|
||
|
||
Garda insasi nu e noua — **S7** o are deja, reutilizata din #6
|
||
(`COMUN\programe\ofacturare_editare.prg:19-28`, functia `EsteInEFactura`; apelata din
|
||
`COMUN\clase\ofacturare_comun.vc2:3764`). Ce era intrebare deschisa era
|
||
doar partea lasata de **decizia 59**: daca o factura veche, retrimisa, ar trebui tratata altfel
|
||
fata de una noua. Raspunsul lui Marius **inchide** acea intrebare: nu se leaga de nicio data si
|
||
de niciun flag suplimentar — verificarea `EsteInEFactura` ramane singurul criteriu de
|
||
modificare.
|
||
|
||
**Ramane un rest neacoperit, semnalat lui Marius, nedecis inca:** o factura **veche, deja
|
||
trimisa**, daca e doar **relistata** (tiparita din nou, nu editata), trece iar prin
|
||
`prelucreaza_facturacrs` si — dupa decizia 59 — ar produce **N randuri de discount in loc de
|
||
unul** pe facturile cu cote mixte, deci hartia ar diferi de originalul trimis in eFactura.
|
||
Relistarea nu e modificare, deci garda `EsteInEFactura` nu o acopera.
|
||
|
||
63. **CERINTA NOUA DE AUDIT pe documente.** Formularea lui: *„este doar util de stiut data crearii,
|
||
data modificarii daca este cazul, utilizatorul crearii si al modificarii daca este cazul,
|
||
respectiv data stergere si utilizator stergere daca este cazul, pentru audit"*. Sase informatii:
|
||
**data + utilizator** pentru **creare**, **modificare** si **stergere**.
|
||
|
||
Scrisa initial ca cerinta, cu cercetarea in curs. **Cercetarea TERMINATA**, raport:
|
||
`docs\cercetare\audit_vanzari_creare_modificare_stergere.md`.
|
||
|
||
**Verdict, in doua randuri:** patru din cele sase informatii cerute **exista deja** pe `VANZARI`
|
||
si se scriu consecvent (`ID_UTIL`/`DATAORA` la creare, `ID_UTILS`/`DATAORAS` la stergere); **lipseste
|
||
complet perechea de modificare** (nicio coloana, verificat cu filtru `%MODIF%` pe
|
||
`all_tab_columns`), iar editarea prin stergere+reemitere (S9) ar **suprascrie tacit** perechea de
|
||
creare cu utilizatorul si data regenerarii, daca nu se transporta explicit — acelasi risc deja
|
||
rezolvat pentru `ID_FACT` (sectiunea „E. `ID_FACT`", linia 762).
|
||
|
||
**Poveste noua, proiectata: S14** — verdict complet, recomandare si punctele ramase de decis cu
|
||
Marius acolo.
|
||
|
||
64. ~~**Asezarea campului de motiv: RANDUL SE IMPARTE IN TREI.**~~ **RASTURNATA DE DECIZIA 66
|
||
(runda 17) — NU MAI E IN VIGOARE.** Formularea de atunci: *„campul de motiv imparte randul in 3"*;
|
||
randul de jos ar fi avut trei sectiuni (incasare, alte date, motivul discountului), ~440 px
|
||
fiecare la 1366 px.
|
||
|
||
**Se pastreaza ca istorie, nu ca regula**, si merita pastrata: varianta a fost **construita in
|
||
mockup (v9) si respinsa dupa ce Marius a vazut-o** — *„motiv discount vreau sa fie langa discount,
|
||
nu a treia coloana"*. E argumentul cel mai bun din tot planul pentru **de ce se face mockup
|
||
inainte de cod**: decizia luata pe descriere s-a intors la prima privire pe forma desenata.
|
||
Ce e in vigoare: **decizia 66**, mai jos.
|
||
|
||
65. **Auditul (decizia 63) se afiseaza in gridul din `frm_facturi`, nu in formularul facturii.**
|
||
Formularea lui: *„auditul presupun coloanele dataora si utilizator adaugat/modificat/sters, le
|
||
vreau pe grid-ul din formularul frm_facturi, nu in formularul facturii propriu-zise - este
|
||
posibil sa fie deja coloane"*.
|
||
|
||
Confirma continutul cerintei de audit (decizia 63): trei perechi **data + utilizator**, pentru
|
||
**adaugat**, **modificat** si **sters**. Locul de afisare e **gridul din `frm_facturi`**, nu
|
||
formularul unificat — deci **S14 nu cere controale noi in formularul unificat**, cere **coloane
|
||
in gridul listei de facturi**. E o cerinta mai usoara decat presupunea S14, si e de spus explicit.
|
||
|
||
**Sarcina de verificat la implementarea lui S14, adaugata ca prim pas al povestii:** Marius
|
||
banuieste ca unele coloane exista deja in acel grid. **Nu s-a verificat.** S14 incepe deci cu
|
||
**inventarul gridului din `frm_facturi`** — ce coloane de audit sunt deja acolo, ce surse au —
|
||
si abia apoi adauga ce lipseste. Nu se presupune nici ca exista, nici ca nu.
|
||
|
||
### Decizia 66 (Marius, runda 17) — luata, nu de reluat. RASTOARNA DECIZIA 64.
|
||
|
||
66. **Motivul discountului sta LANGA DISCOUNT, in banda de totaluri — nu ca a treia sectiune jos.**
|
||
Formularea lui: *„motiv discount vreau sa fie langa discount, nu a treia coloana"*.
|
||
|
||
**Anuleaza decizia 64** (randul de jos se imparte in trei). Randul de jos revine la **doua
|
||
sectiuni colapsabile** — incasare si alte date — adica exact la ce aprobase decizia 57, punctul 2,
|
||
inainte ca decizia 61 sa redeschida discutia. **Decizia 57 ramane intreaga; nu se mai atinge.**
|
||
|
||
**Ce inseamna concret, pentru S1 si S3:**
|
||
- campul de motiv e un **control in banda de totaluri**, imediat dupa suma discountului de
|
||
document, inainte de TVA; ia latimea ramasa pana la totalul mare, care sta la dreapta;
|
||
- **cele doua sectiuni de jos redevin pe jumatate de latime** (~660 px la 1366 px), nu ~440 —
|
||
argumentul „strans, asumat ca atare" din decizia 64 **cade odata cu ea**;
|
||
- **regula de activare, adaugata de proiectare, nu ceruta explicit:** campul e activ **numai cand
|
||
discountul de document nu e zero**. Un motiv fara discount n-are ce explica, si ar ajunge in
|
||
`AllowanceChargeReason` pe un `AllowanceCharge` inexistent. Daca Marius vrea altfel, e o linie
|
||
de schimbat.
|
||
|
||
**Consecinta de asezare, de stiut la implementare:** banda de totaluri devine plina — baza,
|
||
discount articole, discount document (procent + suma + bifa „evidentiat"), motiv, TVA, total. La
|
||
latimi mici **se rupe pe doua randuri** (`flex-wrap`), si asta e acceptat: alternativa ar fi
|
||
scoaterea bifei „evidentiat" din banda, care n-a fost ceruta.
|
||
|
||
Restul deciziei 61 (stocare noua pe `VANZARI`, `AllowanceChargeReason`, `ReasonCode` ramane `95`)
|
||
**e neatins** — se schimba doar locul controlului in formular.
|
||
|
||
#### S6 — Test pe fluxul real, formularul unificat
|
||
Headless (`COMUN\docs\depanare_testare_vfp.md`) + UI (`COMUN\docs\testare-ui-vfp.md`), cate un caz
|
||
pe fiecare sursa: lista de preturi, comanda, contract, aviz, retur, transfer, valuta. Comparatie
|
||
directa cu documentul emis pe calea veche: `vanzari`, `vanzari_detalii`, `act`, `rul`, totalurile
|
||
denormalizate, listarea.
|
||
*Depinde de:* S5.
|
||
|
||
### Etapa II — editarea prin regenerare
|
||
|
||
#### S7 — Actiunea si garzile
|
||
Actiune noua pe `frm_facturi`, sub tokenul de drepturi existent. Garzi refolosite din
|
||
`COMUN\programe\ofacturare_editare.prg` (`EsteInEFactura:12`, plus luna inchisa, luna curenta,
|
||
`ReferinteDocumenteNota`) — **nu se rescriu**, sunt deja extrase de #6. Plus garzile proprii
|
||
regenerarii: refuz daca documentul are **urmasi**.
|
||
|
||
**PRECIZAT in runda 14, pe cod** (`docs\cercetare\garda_aviz_facturat.md`): regula exista deja integral
|
||
in Oracle, in **trei** garzi consecutive din `sterge_factura` — factura cu retururi (`TIP = 3`,
|
||
`EXPORT:5452-5462`), **aviz cu factura sau aviz de retur** (`TIP IN (1,2)`, `EXPORT:5466-5476`), si
|
||
factura din aviz ale carei avize-sursa au primit intre timp aviz de retur (`EXPORT:5480-5494`).
|
||
**S7 nu reimplementeaza regula** — o citeste **mai devreme**, read-only, inainte de intrarea in
|
||
formular:
|
||
|
||
```sql
|
||
select count(*) from vanzari_coresp
|
||
where sters = 0 and id_vanzare_aviz = :id_vanzare and tip in (1, 2, 3)
|
||
```
|
||
|
||
plus subinterogarea din garda 3 pentru cazul „factura din aviz". Se interogheaza `VANZARI_CORESP`,
|
||
**nu `VANZARI.FACTURAT`** — `FACTURAT` e derivat si necitit de nicio garda. Garda din `sterge_factura`
|
||
**ramane pe loc ca plasa de siguranta**: nu se muta, nu se slabeste.
|
||
|
||
**Gol de acoperit, iesit tot in runda 14:** pentru **proforma** (`TIP = 4`, decizia 51) garda **nu
|
||
exista deloc** — `sterge_proforma` (`EXPORT:5610-5635`) e o procedura separata fara nicio verificare,
|
||
iar calea VFP iese din `do_sterge` inainte de restul (`ofacturare_comun.vc2:4707-4719`). Garda simetrica
|
||
ceruta de S5c e **cod nou**, nu reutilizare.
|
||
*Gata cand:* actiunea refuza corect si cu mesaj clar documentele trimise in eFactura, sterse, din
|
||
luna inchisa, referentiate, sau care au urmasi (retur, factura din aviz, factura din proforma) —
|
||
**inainte** de deschiderea formularului, nu ca `ORA-20000` la final.
|
||
*Depinde de:* S6, si de inchiderea perimetrului cu #6 (fisier partajat).
|
||
|
||
#### S8 — Incarcarea documentului in formular
|
||
|
||
> **PROIECTAT INTEGRAL in runda 14 — `docs\cercetare\s8_incarcare_document.md` (52 KB, 8 sectiuni).**
|
||
> **Schita de mai jos e corecta ca directie, dar gresita in piese, si nu marunt:**
|
||
> 1. **`completeaza_setari_document(toFactura, .T.)` copiaza 16 proprietati din ~120**
|
||
> (`COMUN\programe\ofacturare_comun.prg:361-411`) si **niciuna de identitate**. Lipsesc serie,
|
||
> numar, data, scadenta, `text_aditional`, `id_facturare`, `id_ruta`, `tip_saft`, `efactura`,
|
||
> `listare_detaliata`, `dataora_exp`, discountul de document, `discount_evidentiat`, `eproforma`,
|
||
> valuta, cursul.
|
||
> 2. **`cursor_retur_document(V_COPIERE = 1)` nu umple documentul, ci selectorul-sursa.** Rezultatul
|
||
> intra in `crsarticole` (gridul din stanga); `crsfactura` se creeaza **gol si ramane gol** —
|
||
> comentariul din cod e explicit (`COMUN\programe\ofacturare.prg:338`, `:455-457`). Transferul se
|
||
> face doar prin `do_adauga_tot` → `do_adauga_articol`, care pentru articolele gestionabile trece
|
||
> **prin dialogul de alegere din stoc**.
|
||
> 3. **`cursor_retur_document` nu intoarce `ID_VANZARE_DET` si nici `TAXCODE`**
|
||
> (`PACK_FACTURARE:3949-4054`). Fara `ID_VANZARE_DET`, cheia de linie presupusa de S8b **nu exista**,
|
||
> iar ruta ieftina `modifica_explicatie_articol` **devine neapelabila** — primul ei parametru *este*
|
||
> `V_ID_VANZARE_DET` (`PACK_FACTURARE:14511-14519`).
|
||
>
|
||
> **Recomandarea centrala:** S8 se construieste pe precedentul care face deja exact asta —
|
||
> `relisteaza_ofacturare_stoc` (`COMUN\programe\ofacturare_stoc.prg:456-742`), care reconstituie
|
||
> `poDate` + cursorul de linii dintr-un document salvat, prin `FACT_VFACTURI` + `FACT_VFACTURI_DETALII`
|
||
> (ambele au `ID_VANZARE_DET` si `TAXCODE`). Canalul final e intrebarea 1 din §8.2 al raportului
|
||
> (*recomandat:* procedura noua `cursor_editare_document`, ca sa nu se schimbe comportamentul copierii).
|
||
>
|
||
> **CORECTIE la raportul S8, facuta de sesiunea principala (runda 14):** raportul lasa deschis (N6,
|
||
> intrebarea 7) daca „`frm_facturare_articole2` (varianta paralela)" intra in perimetru, si recomanda
|
||
> „nu acum". **Premisa e gresita: `frm_facturare_articole2` NU e o varianta paralela de exclus — e
|
||
> PROTOTIPUL pe care se construieste formularul unificat**, conform S1 („se porneste de la prototip",
|
||
> `ofacturare.vc2:15741-19355`). Deci S8 il tinteste pe el, nu pe `frm_facturare_articole`. Faptul ca
|
||
> are `do_adauga_tot` / `do_adauga_articol` proprii, cu logica divergenta (fara testul `llGestionabil`,
|
||
> `ofacturare.vc2:17476`, `:17124`), **nu e un motiv de excludere, e exact driftul din 2017 pe care S2
|
||
> il inchide** — cele doua se unifica, nu se aleg. Partea de tipuri 48/49 din intrebarea 7 **s-a
|
||
> inchis prin decizia 60**: sunt editabile. Intrebarea 7 e deci inchisa integral.
|
||
|
||
> **CERINTA DE EXECUTIE ADAUGATA IN RUNDA 17 — `IN_STOC` se incarca din document, nu din nomenclator.**
|
||
> Vine din consecinta 1 a deciziei 54 (vezi S10, „Trei consecinte"), si se prinde **aici**, nu la S12.
|
||
> Cu flag-ul de regenerare pornit, `IN_STOC` nu mai e re-derivat de `adauga_articol_factura`, ci **vine
|
||
> din formular** — deci valoarea pe care o incarca S8 devine valoarea care decide **descarcarea de
|
||
> gestiune la reemitere**. Azi loader-ul lui #6 o citeste din nomenclatorul curent
|
||
> (`ofacturare_editare.prg:302-303`), deci un articol devenit intre timp gestionabil (sau invers) ar
|
||
> face reemiterea sa atinga **alt stoc decat documentul initial**, tacut.
|
||
>
|
||
> Trei consecinte concrete pentru canalul de citire (intrebarea 1 din §8.2, *recomandat* (B),
|
||
> `cursor_editare_document`):
|
||
> - canalul trebuie sa intoarca `IN_STOC` **asa cum a fost la emitere**, nu `GESTIONABIL = B.IN_STOC`
|
||
> din nomenclatorul de azi, cum face `cursor_retur_document` (`PACK:3993-4000`). E un **al treilea
|
||
> argument** pentru procedura noua, langa `ID_VANZARE_DET` / `TAXCODE` si langa `ID_POL` / `ID_CTR`
|
||
> lipsa din `VVANZARI_ARTICOLE`;
|
||
> - **valoarea istorica nu e stocata nicaieri**: `IN_STOC` nu e coloana pe `VANZARI_DETALII` (verificat
|
||
> pe DB, vezi S10), traieste doar in temp. Deci primul pas al lui S8 pe aceasta cerinta e sa
|
||
> stabileasca **de unde se reconstituie** — fie din urma lasata in rulaje / gestiune pentru documentul
|
||
> respectiv, fie se accepta nomenclatorul curent ca aproximatie **declarata explicit**, fie se adauga
|
||
> coloana (migrare DB, deci **DB inainte de EXE**, ca la S10). **Nu se presupune niciuna dintre
|
||
> variante**; e o **preconditie de proiectare a lui S8**, nu un detaliu de implementare;
|
||
> - pe tipurile **48/49** cerinta se intalneste cu decizia 60: acolo invariantul e `IN_STOC = 0` prin
|
||
> constructie, deci valoarea incarcata trebuie sa fie `0` indiferent ce zice nomenclatorul azi.
|
||
>
|
||
> *Criteriu de test (intra in „gata cand" al lui S8):* un document emis cu un articol caruia i s-a
|
||
> schimbat intre timp `IN_STOC` in nomenclator, deschis in formular, poarta **valoarea de la emitere**;
|
||
> iar reemiterea lui lasa **stocul agregat neschimbat** (masurat inainte / dupa, nu prin inspectia
|
||
> codului).
|
||
|
||
> **Cerinta noua din S8b e mai blanda decat se credea:** lookup-ul „ultimul delegat / ultima masina"
|
||
> **are deja o garda** — `Empty(id_delegat) And Empty(id_masina)` (`ferestre_cere_date.vc2:3111`).
|
||
> Riscul ramane real, dar **numai** pe documentele fara delegat si fara masina. Raportul da inventarul
|
||
> complet al celorlalte initializari „pentru document nou" care trebuie sarite (§2.2).
|
||
|
||
`completeaza_setari_document` pentru antet + `cursor_retur_document(V_COPIERE = 1)` pentru linii,
|
||
**fara** degradarea de tip din `do_copiaza`. Se incarca in plus, fata de copiere: serie / numar /
|
||
data / scadenta reale, discountul de document (`VANZARI.DISCOUNT`), `discount_evidentiat`, textul
|
||
aditional, datele din `frm_alte_date` (delegat, auto, agent, adresa de facturare), explicatia si
|
||
`taxcode` pe fiecare linie, si legatura cu sursa (`id_comanda`, `id_ctr`, lista de avize din
|
||
`vanzari_coresp`) — ca reemiterea sa reconsume aceeasi sursa.
|
||
**Campul de sursa exista deja** — nu e de adaugat, ci de pastrat vizibil: e `Ct_clb_altele`, cu
|
||
eticheta schimbata pe tip de `do_schimba_explicatia` („Nr. contract” / „Nr. comanda” / „Nr. factura” /
|
||
„Nr. facturi” / „Locatie”, `ofacturare.vc2:9633-9643`), eliminat azi din formular cand
|
||
`gnScadereStoc = 0` si tipul e 1/5/10 fara copiere. La modificare e blocat: schimbarea sursei ar
|
||
insemna alt document, nu o corectie.
|
||
Formularul arata **identic** cu cel de introducere: fara banda de avertizare, fara coloane cu
|
||
valorile initiale, fara panou de diferente (decizia 5). Se schimba titlul ferestrei si **butonul
|
||
principal** (decizia 9, vezi S8c).
|
||
*Gata cand:* formularul deschis pe un document existent arata exact documentul, pe fiecare tip de
|
||
sursa, si nu se distinge vizual de formularul de introducere; **si** liniile incarcate poarta `IN_STOC`
|
||
de la emitere, nu din nomenclatorul de azi (cerinta rundei 17, mai sus).
|
||
*Depinde de:* S7.
|
||
|
||
#### S8b — Rutarea scrierii dupa ce s-a schimbat
|
||
Comasarea celor trei actiuni de modificare (G-bis): la confirmare se compara starea din formular cu
|
||
cea incarcata si se alege ruta — `modifica_date_factura` pentru antet, `modifica_explicatie_articol`
|
||
pentru explicatia liniei, regenerare pentru orice atinge sumele, nimic daca nu s-a schimbat nimic.
|
||
Cele trei actiuni vechi de pe `frm_facturi` (`do_modifica`, `do_modifica_explicatie`) se retrag
|
||
abia dupa ce formularul unificat le acopera, nu inainte.
|
||
**PROIECTAT (runda 13) — `docs\cercetare\s8b_rutarea_scrierii.md`. Reteta G-bis e corecta ca directie,
|
||
dar avea un gol nedocumentat, si el schimba forma solutiei.**
|
||
|
||
- **Cele patru rute NU sunt teste independente, ci un lant cu prioritate — sumele primele.**
|
||
Motivul e concret: **`modifica_date_factura` nu e singura ruta care scrie cei 14 parametri de antet.**
|
||
**Sapte din 14** (`id_delegat`, `id_masina`, `id_facturare`, `listare_detaliata`, `dataora_exp`,
|
||
`id_agent`, `text_aditional`) sunt scrisi **si** de calea normala de emitere, prin `scrie_factura2`,
|
||
direct din `poDate` — **verificat direct de sesiunea principala** pe apelul de la
|
||
`COMUN\clase\ofacturare.vc2:14345-14359`. Nu exista doi proprietari ai acestor campuri: e **acelasi
|
||
obiect `poDate`** citit de ambele cai.
|
||
- **Deci, cand regenerarea porneste, `modifica_date_factura` NU se mai cheama.** Inainte de regenerare
|
||
ar scrie pe randul care urmeaza sa fie sters — pierdut. Dupa, ar fi a doua scriere pe aceleasi sapte
|
||
coloane, pe alt `ID_VANZARE`. Regenerarea **este** deja calea de scriere a antetului cand sumele se
|
||
schimba, nu o cale care trebuie compusa cu alta.
|
||
- **Ordinea rutarii:** (1) s-au schimbat liniile / discountul de document? → **regenerare, gata**;
|
||
(2) altfel, antet? → `modifica_date_factura`; (3) altfel, doar explicatie de linie? →
|
||
`modifica_explicatie_articol`; (4) altfel → **nimic**.
|
||
- **Explicatia de linie e transportata gratuit de regenerare**, prin parametrii nativi ai lui
|
||
`adauga_articol_factura` (`V_EXPLICATIE`, `V_TAXCODE`) — **cu conditia** ca regenerarea sa citeasca
|
||
din cursorul curent al formularului, nu dintr-un snapshot separat.
|
||
- **Cel mai probabil fals pozitiv al criteriului „deschid si inchid → nicio scriere":** lookup-ul
|
||
„ultimul delegat / masina al clientului" din `frm_alte_date.Init`
|
||
(`COMUN\clase\ferestre_cere_date.vc2:3119-3136`). E cod gandit pentru **document nou**. Pe calea de
|
||
editare ar suprascrie delegatul **incarcat corect din document** cu ultimul folosit de client — deci
|
||
ori documentul apare „modificat" fara ca nimeni sa fi atins nimic, ori, daca ruleaza inainte de
|
||
snapshot, **salveaza tacit delegatul gresit**. **S8 trebuie sa-l sara explicit pe calea de editare.**
|
||
- **Comparatia se face pe valori rotunjite la precizia de scriere** (`gnPc` / `gnPPretV` / `gnPCant`),
|
||
nu pe valoarea binara — altfel rotunjirea singura produce diferente.
|
||
|
||
**INCHIS, nu de reintrebat (marcaj pus in runda 17).** Punctul de mai jos are raspuns: **decizia 52** — `do_modifica` ramane activ pentru multi-selectie, iar formularul unificat preia doar cazul cu un singur document. Se pastreaza enuntul, nu intrebarea:
|
||
1. **Editarea multipla** — `do_modifica` de azi lucreaza pe multi-selectie, capacitate fara echivalent
|
||
in formularul unificat. Se accepta pierderea ei la retragere, sau `do_modifica` ramane activ separat
|
||
exact pentru cazul asta?
|
||
|
||
**Doua goluri de inchis inainte de implementare (semnalate, nu presupuse):**
|
||
- **Ce canal scrie `serie_act` / `numar_act` / `data_act` / `data_scad` / `id_ruta` / `tip_saft` /
|
||
`efactura`** pe documentul reemis — **nu apar in `scrie_factura2`**, deci vin pe alt drum. Raspunsul
|
||
decide daca mai e nevoie de o scriere separata dupa regenerare. **Se inchide in S9.**
|
||
- ~~**`cursor_retur_document` re-deriva pretul la incarcare?**~~ **INCHIS (runda 13): NU** — pretul vine
|
||
din `VANZARI_DETALII.PRET` stocat, fara `JOIN` catre contract sau politici (`PACK_FACTURARE:3960-4062`,
|
||
verificat direct). **Mecanismul de detectie e valid.** Detaliul despre rotunjire si `DIFERENTA` — in S10.
|
||
|
||
*Gata cand:* fiecare din cele patru situatii din tabelul G-bis produce exact scrierile din tabel si
|
||
nimic in plus; in special, deschiderea si inchiderea fara modificari nu scrie nimic.
|
||
*Depinde de:* S8.
|
||
|
||
#### S8c — Butonul comutator de antet si salvarea separata a antetului
|
||
Decizia 9, proiectata in I. Antetul unui document existent porneste **blocat**; un singur
|
||
`but_modifica` il deschide si isi schimba imaginea in discheta de salvare; a doua apasare cheama
|
||
`modifica_date_factura` si **nu atinge articolele** — exact ce face azi `do_modifica`, dar din
|
||
formularul unificat, dupa care antetul se blocheaza la loc si butonul revine la creion. **Fara nicio
|
||
bifa**: butonul deschide tot antetul, inclusiv serie / numar / data / scadenta; cele patru bife de
|
||
azi nu se transpun. `Termina` ramane salvarea intregului document.
|
||
Se generalizeaza reteta de blocare din `clb_tx_data.dezactiveaza()` / `reactiveaza()`
|
||
(`lb_tx.vc2:521-538`) la containerele de antet care azi nu au niciuna (I), si se aplica **uniform**
|
||
tuturor campurilor de antet — asta e ce face posibila eliminarea bifelor.
|
||
Comutarea imaginii butonului se copiaza din `frm_rulaje.se_modifica_assign` (`rulaje.vc2:4716-4773`):
|
||
o singura instanta `but_modifica`, cu `.cpicturedown` / `.cpictureup` / `.Picture` rescrise impreuna
|
||
si `.Refresh()` — vezi decizia 9 pentru capcana hover-ului.
|
||
**Ce deschide efectiv butonul (decizia 25, verificat pe cod in G-bis).** „Tot antetul” nu inseamna
|
||
ca totul se salveaza pe aceeasi ruta:
|
||
- **cei 14 parametri** — pe loc, prin `modifica_date_factura`. Asta livreaza S8c;
|
||
- **grupul B** (tip document, valuta, zi curs, client, sursa, gestiune sursa, politica de preturi) si
|
||
**grupul C** (incasare) — **nu au ruta de scriere pe loc**, deci raman **blocate in etapa I**, cu
|
||
explicatie la hover; se deschid in etapa II, cand modificarea lor marcheaza documentul pentru
|
||
regenerare;
|
||
- **grupul A** (analiticele) — **read-only permanent in #13** (decizia 26), editarea e a lui #6.
|
||
|
||
Deci in etapa I butonul deschide **exact cei 14**, si asta nu e o abatere de la decizia 9, ci
|
||
consecinta ei corecta pe starea de azi a codului: restul campurilor n-ar avea unde sa se scrie.
|
||
*Gata cand:* se poate corecta delegatul unui document emis, salva antetul si inchide formularul,
|
||
**fara nicio scriere in `VANZARI_DETALII` si fara recalcul de sume in note sau rulaje**; se poate
|
||
corecta si data scadentei prin acelasi buton, fara alt control intermediar; iar un document deschis
|
||
si inchis fara a apasa butonul nu produce nicio scriere.
|
||
*Atentie la formularea criteriului:* „nicio scriere in note si rulaje” ar fi un criteriu imposibil —
|
||
schimbarea seriei / numarului / datei propaga coloanele de identitate in `JV2007` si `RUL` prin
|
||
procedura insasi (I-bis). Ce se verifica e ca **nu se ating sumele**, nu ca nu se atinge tabelul.
|
||
*Depinde de:* S8.
|
||
|
||
#### S9 — Stergerea si reemiterea intr-o singura tranzactie, cu `ID_FACT` pastrat
|
||
Partea grea. Doua lucruri simultan:
|
||
|
||
**Constrangere de la decizia 35, inainte de orice:** reemiterea **scrie prin `pack_facturare`**, pe acelasi
|
||
drum ca emiterea (`scrie_factura2` → `contabilizeaza_articol`, cu parametrul de cont de la decizia 34).
|
||
`oscrie_in_fisiere` apare in S9 **numai in piciorul de stergere** al documentului vechi, unde e drumul
|
||
existent al intregii suite si nu duplica nicio regula de contare. **Nu se scrie si nu se corecteaza niciun
|
||
rand din `ACT_TEMP` direct din VFP.** Consecinta de secventiere: **S9 nu poate porni inaintea parametrului
|
||
deciziei 34** — nu mai exista varianta „editarea nu cere nimic in pachet".
|
||
|
||
**VERIFICAT ca decizia 35 e realizabila** (`docs\cercetare\parametru_cont_contabilizeaza_articol.md`,
|
||
sectiunea 1): pe partea Oracle, **a doua emitere a aceluiasi document merge pe cod identic**.
|
||
`scrie_factura2` cheama `initializeaza_date_factura` (`PACK_FACTURARE:1808-1846`) la fiecare apel, iar
|
||
aceasta face `DELETE FROM VANZARI_DETALII_TEMP` (`:1835`) si `nid_act := 0` (`:1836`) — contorul folosit
|
||
de `scrie_nota` / `scrie_discount` / `scrie_tva` la fiecare `INSERT INTO ACT_TEMP` **porneste curat si la
|
||
reemitere**. Nimic din `contabilizeaza_articol`, ramura noua inclusa, nu citeste vreo stare care sa
|
||
presupuna „documentul e nou": variabilele de sesiune sunt **citite**, nu comparate cu o stare anterioara.
|
||
**Singurul obstacol real al regenerarii e in alt pachet** — `PACK_CONTAFIN`, prin `SET_IDFACT` si
|
||
`PK_DOCUMENTE`, exact ce e deja analizat mai jos in acest S9. Adica: „cod separat" inseamna **alta
|
||
procedura, in alt pachet**, nu o a doua ruta de contare — deci **decizia 35 nu e contrazisa**.
|
||
|
||
- **Tranzactia.** Apelul de stergere (`oscrie_in_fisiere` + `finalizeaza_stergere_nota` +
|
||
`sterge_factura`) se muta in interiorul tranzactiei deschise de `do_scrie_articole`, inaintea
|
||
primului `adauga_articol_factura`. Fara `commit` intermediar (`VANZARI_DETALII_TEMP` e GTT
|
||
`ON COMMIT DELETE ROWS`). La orice eroare, rollback total.
|
||
- **Tripleta de mai sus e si ce face ciclul NEUTRU fata de stoc — nu se simplifica.** `sterge_factura`
|
||
**nu** reverseaza rulajele. Revenirea stocului vine din `PACK_CONTAFIN.STERGE_DIN_RUL`
|
||
(`UPDATE RUL SET STERS = 1, ID_UTILS = ..., DATAORAS = ...`,
|
||
`ff_2026_07_29_03_COMUN_PACK_CONTAFIN.sql:1867-1882`, apelata la `:8473`), la care se ajunge prin
|
||
`finalizeaza_scriere_act_rul(tnScrieSterge = 2)` ← `oscrie_in_fisiere(2, ...)`. Adica **stocul e
|
||
derivat** din miscari nesterse, iar marcarea lor `STERS = 1` inchide subiectul — dar **numai daca
|
||
piciorul de stergere chiar trece prin `oscrie_in_fisiere`**. O implementare care „simplifica" pasul
|
||
la un apel direct de `sterge_factura` ar lasa rulajele in picioare si reemiterea ar descarca
|
||
gestiunea **a doua oara**, tacut. Verificat pe sursa pachetului.
|
||
`docs\cercetare\stoc_la_stergere_si_reemitere.md`.
|
||
- **`ID_FACT`.** Se citeste inainte de stergere (vezi capcana `STERS = 0` din E) si se impune
|
||
documentului nou, printr-un comutator folosit **numai** de regenerare. `SET_IDFACT` nu se schimba
|
||
neconditionat — e cod comun intregii suite.
|
||
- **`ID_UTIL` / `DATAORA` (audit de creare, S14).** Acelasi tipar ca la `ID_FACT`: se citesc din
|
||
documentul vechi **inainte** de stergere si se impun explicit documentului nou — altfel `INSERT
|
||
INTO VANZARI` de la reemitere le rescrie cu utilizatorul si momentul curente, si „data/utilizatorul
|
||
crearii" se pierde tacut. Detaliu si recomandare de coloane: S14.
|
||
|
||
**VERIFICAT — se poate, dar cere TREI schimbari simultane, nu una.** Raport:
|
||
`docs\cercetare\idfact_refolosire_si_documente.md`. Verdict: **DA, cu conditii.**
|
||
|
||
1. **Varianta comentata din `SET_IDFACT` NU rezolva S9** — nu se reactiveaza.
|
||
(`PACK_CONTAFIN.pck:3016-3035`) cauta documentul pe `NRACT + SERIE_ACT + DATAACT + ID_CTR` cu
|
||
`STERS = 0`; dupa soft-delete `STERS` e deja 1, deci **nu-l gaseste** si cade tot pe secventa.
|
||
In plus e vulnerabila la coliziuni cu un document viitor neinrudit care are aceleasi patru campuri.
|
||
`ID_FACT`-ul se **citeste explicit inainte de stergere** (VFP il are in cursor) si se **transmite**.
|
||
2. **`SET_IDFACT` are nevoie de o cale de intrare noua, inerta implicit.** Azi **nu exista niciun
|
||
canal**: `pack_contafin.nIdFact` e scrisa neconditionat de fiecare apel, si nu exista alt global sau
|
||
parametru de sesiune. Solutia cu suprafata minima: **variabila noua de pachet** („ID_FACT fortat",
|
||
implicit `NULL`), citita **doar in corpul activ** al lui `SET_IDFACT`, consumata si resetata la prima
|
||
folosire. **Nu se atinge semnatura `SET_IDFACT(V_GCS)`** — altfel s-ar schimba apelul pentru toti.
|
||
3. **Blocajul real nu e in `SET_IDFACT`, ci in `DOCUMENTE`** — si asta e descoperirea care schimba
|
||
estimarea. Scrierea de azi (`PACK_CONTAFIN.pck:796-817`) e un **`INSERT` simplu** pe `ID_DOC`, care e
|
||
**PRIMARY KEY** (`PK_DOCUMENTE`, `fn_script.sql:5192-5198`). Stergerea (`STERGE_DIN_ACT:1835-1855`) e
|
||
**soft-delete pur** — randul vechi ramane fizic in tabel cu `STERS = 1`. Deci reemiterea cu acelasi
|
||
`ID_FACT`, cu codul de azi, **arunca `ORA-00001`**. Dovada, nu presupunere.
|
||
`MERGE`-ul deja comentat (`:818-847`) **nu ajuta**: are doar `WHEN NOT MATCHED`, deci ar ignora tacit
|
||
randul existent si documentul reemis ar ramane cu `STERS = 1`. E nevoie de **upsert real**, cu
|
||
`WHEN MATCHED THEN UPDATE SET STERS = 0, ...` pe restul coloanelor de identitate.
|
||
|
||
**Succesiunea corecta**, in aceeasi tranzactie: citeste `ID_FACT` **si lista sursa** -> sterge documentul
|
||
vechi (soft-delete, ca azi) -> seteaza variabila fortata -> scrie documentul nou pe drumul obisnuit ->
|
||
**remigreaza atasamentele** -> commit doar daca toate au reusit; orice eroare -> rollback total,
|
||
documentul vechi intact.
|
||
|
||
**DOI PASI ADAUGATI DE S11 (runda 13) — niciunul nu „vine gratis" din drumul normal:**
|
||
1. **Citirea listei sursa INAINTE de stergere, si refurnizarea ei la reemitere.** `VANZARI_CORESP` si
|
||
`marcheaza_facturat` **se rescriu singure** prin `CASE`-ul pe `ntip` din `finalizeaza_factura` — dar
|
||
**numai daca** `ntip` si lista sursa (`clistaid` / `clistaid_avize`) sunt refurnizate. Ele traiesc in
|
||
randurile `VANZARI_CORESP` ale documentului **vechi**, care dupa stergere nu mai sunt disponibile.
|
||
**Fara acest pas nu apare nicio eroare — corespondenta si `FACTURAT` pur si simplu nu se scriu.**
|
||
Scriere lipsa silentioasa, exact tipul de defect care trece de o verificare vizuala.
|
||
2. ~~**`UPDATE ATASAMENTE_VANZARI SET id_vanzare = :nou`**~~ — **INLOCUIT de decizia 53 (runda 14):
|
||
atasamentele NU se remigreaza, se sterg la reemitere.** Documentul reemis porneste curat; PDF-ul se
|
||
regenereaza la prima listare. Pasul ramane **cod nou**, dar e o **stergere**, nu un `UPDATE`
|
||
(`STERS = 1`, ca sa ramana consistent cu view-ul `VATASAMENTE_VANZARI`, care filtreaza `b.sters = 0`
|
||
— vezi S11). Consecinta acceptata explicit de Marius: **urma PDF-ului efectiv trimis clientului
|
||
dispare din sistem.**
|
||
|
||
**Suprafata de risc pentru suita**, masurata: **~25-30 cai de apel** — cate o copie a lui
|
||
`COMUN\programe\oscrie_in_fisiere.prg` in fiecare produs ROA, plus trei variante care cheama
|
||
`SCRIE_IN_ACT` direct. Toate converg in acelasi punct, `SET_IDFACT(V_GCS)`. **Garantia e structurala,
|
||
nu prin inspectie:** cu variabila implicit `NULL` si citita strict local, toate cele ~25-30 de cai raman
|
||
identice cu azi — nu trebuie verificat fiecare apelant.
|
||
**Dar `INSERT` -> `MERGE` in `DOCUMENTE` e cod comun apelat de toata suita.** Practic ramura noua e
|
||
inerta (secventa e monoton crescatoare, `WHEN MATCHED` nu se declanseaza niciodata pe drumul normal),
|
||
**dar se testeaza un ciclu normal de scriere in fiecare produs care scrie facturi sau note**, nu doar in
|
||
ROAFACTURARE.
|
||
|
||
*Gata cand:* o editare care mareste cantitatea peste stocul curent trece (stocul documentului
|
||
initial e eliberat inainte); documentul reemis are **acelasi `ID_FACT`, serie, numar si data** ca
|
||
inainte; **randul din `DOCUMENTE` e acelasi, revenit la `STERS = 0`**, nu unul nou; o eroare la scriere
|
||
lasa documentul initial intact; si un ciclu normal de scriere ramane neschimbat in celelalte produse.
|
||
*Depinde de:* S8b.
|
||
|
||
#### S10 — Pretul care nu trebuie re-derivat
|
||
Inventarul ramurilor din `adauga_articol_factura` (H) si, unde e nevoie, un mod in care preturile
|
||
vin din formular.
|
||
|
||
**VERIFICAT (runda 9) — `docs\cercetare\s10_pret_rederivat.md`. Verificarea 3 e inchisa.**
|
||
**Exista exact o ramura care suprascrie pretul: contractul.** Cu `OPT_FACTURARE = 3` (sau `NULL`, care
|
||
se implicit-eaza tot la 3), daca `CTR_ARTICOLE.PRET_UNITAR` e diferit de 0, acea valoare **inlocuieste**
|
||
pretul trimis de VFP — `DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR)` — necondiționat de faptul
|
||
ca linia a fost sau nu atinsa pe ecran. Procedura **nu are nicio notiune de „reemitere"**: la fiecare
|
||
apel cu acelasi `V_ID_CTR` se reface derivarea din contract. Pe celelalte ramuri (implicita, restaurant)
|
||
pretul trimis de VFP e respectat ca atare. **Nu exista niciun parametru sau flag care sa opreasca
|
||
re-derivarea** — deci S10 nu poate „cere pachetului sa nu re-derive", trebuie sa lucreze in jurul
|
||
ramurii de contract. Riscul se materializeaza doar cand pretul din contract s-a schimbat intre emitere
|
||
si reemitere; pana atunci rezultatul e identic si nimeni nu observa. Detaliile pe discount, TVA si curs
|
||
sunt in sectiunile 6 si 7 ale raportului.
|
||
**PROIECTAT (runda 13) — `docs\cercetare\s10_pret_contract_reemitere.md`. Faptul portant al rundei 9
|
||
se reconfirma la sursa, dar problema e mai larga decat „pretul".**
|
||
|
||
- **Nu e doar pretul: acelasi `SELECT` de pe ramura de contract alimenteaza CINCI valori.**
|
||
**Verificat direct de sesiunea principala** (`PACK_FACTURARE:5149-5166`): `DECODE(A.PRET_UNITAR, 0,
|
||
V_PRET_TEMP, A.PRET_UNITAR)` **impreuna cu** `B.PROC_TVAV`, `B.ID_VALUTA`, `A.PRET_CU_TVA` si
|
||
`C.IN_STOC` intra in aceeasi interogare. Raportul semnalase trei (pret, TVA, valuta); sunt **cinci** —
|
||
se adauga flagul „preturi cu TVA" si **gestionabilitatea**, care vine din **nomenclatorul curent**,
|
||
nu din document. **Orice garda trebuie sa acopere tot setul**, nu doar pretul.
|
||
- **Nu exista alt loc care suprascrie pretul mai departe in lant** — `scrie_in_vanzari` copiaza `PRET`
|
||
neschimbat din `VANZARI_DETALII_TEMP` in `VANZARI_DETALII`.
|
||
- **Divergenta e reala, nu ipotetica:** pe baza de dezvoltare, **3 din 11** linii deja facturate pe
|
||
contract au azi alt pret in contract decat cel facturat. Esantionul e mic si **nu se extrapoleaza** la
|
||
productie — dar demonstreaza ca situatia se intampla.
|
||
- **Discountul ramane passthrough** — acolo nu e nicio problema.
|
||
- **Recomandarea raportului: varianta (c) — se avertizeaza si se cere confirmare, cu diferenta
|
||
afisata.** Satisface literal criteriul „decis explicit, nu accidental", se implementeaza **integral in
|
||
VFP**, fara sa se atinga `pack_facturare`. Variantele: (a) accepta tacit — respinsa, e exact ce cere
|
||
criteriul sa nu se intample; (b) blocheaza — mai sigura, dar frustranta daca divergentele sunt dese;
|
||
(d) ocoleste ramura trimitand `V_ID_CTR = NULL` — **respinsa motivat**, pierde **permanent** legatura
|
||
`VANZARI_DETALII.ID_CTR`.
|
||
- **„Reemitere identica" nu e garantata uniform:** pe ramurile `ELSE` / restaurant, da; pe **comenzi**
|
||
esueaza **tare** (eroare, deci vizibila); pe **contract** si pe **aviz (`ntip = 4`)** esueaza **tacit**.
|
||
Riscul pe aviz **nu fusese semnalat pana acum** ca decizie explicita.
|
||
|
||
**GOLUL LUI S8b E INCHIS — `cursor_retur_document` NU re-deriva pretul.** Verificat direct de sesiunea
|
||
principala (`PACK_FACTURARE:3960-4062`): pretul vine din **`VANZARI_DETALII.PRET`** stocat, printr-un
|
||
`FROM VANZARI_DETALII A1` fara niciun `JOIN` catre `CTR_ARTICOLE` sau catre politici; `PROC_TVAV` la fel,
|
||
din document. **Deci mecanismul de detectare a schimbarii din S8b e valid** — un document deschis nu
|
||
apare „modificat" din cauza citirii. **Confirmat independent si pe partea VFP** (raportul S10): in
|
||
`ofacturare.prg:266-283`, ramura `Case m.llCopiere` are **prioritate indiferent de tip** — pentru un
|
||
document de contract (`2,6,26,52`) **nu se ajunge deloc** la `cursor_contract` la incarcare. Citirea si
|
||
scrierea sunt guvernate de **cursoare complet diferite, fara cod comun**: riscul de suprascriere tacita
|
||
apare **strict la re-scriere**, niciodata la deschidere. O garda pusa la scriere nu afecteaza citirea si
|
||
nu e afectata de ea.
|
||
> **Dar citirea nu e o copie curata, si asta conteaza pentru S12.** Pretul returnat e
|
||
> `ROUND(A.PRET, nzecimale_pretv) + A.DIFERENTA` (pe valuta: `ROUND(CURS * ROUND(PRET, ...) /
|
||
> MULTIPLICATOR, ...) + DIFERENTA`). Adica **rotunjit la precizia de sesiune si cu `DIFERENTA` pliata
|
||
> inauntru**. La reemitere se trimite inapoi valoarea pliata, deci **impartirea `PRET` / `DIFERENTA` se
|
||
> reface**, nu se conserva. De verificat in S12 ca o reemitere identica reproduce **suma**, chiar daca
|
||
> nu reproduce neaparat aceeasi impartire — si ca `DIFERENTA` nu se acumuleaza la reemiteri repetate.
|
||
|
||
### RASTURNAT de decizia 54 (Marius, runda 14) — nu garda, ci eliminarea re-derivarii
|
||
|
||
Cele trei intrebari de mai sus (blocare vs. avertizare; ramura de aviz; masurarea frecventei) **sunt
|
||
inchise, si nu prin alegerea uneia dintre variante — prin respingerea premisei lor.** Formularea lui
|
||
Marius: *„nu inteleg de ce se schimba valorile fata de ce se incarca din factura sursa care se modifica?
|
||
asta este comportamentul pe care il doresc — modific sursa"*.
|
||
|
||
**Deci:** la reemitere se scriu **valorile din formular** (incarcate din documentul editat), nu se
|
||
reciteste sursa. Nu se cere utilizatorului sa confirme o schimbare pe care n-a cerut-o. Variantele
|
||
(b) si (c) **cad amandoua**; ramane obiectivul (a-invers): re-derivarea, unde exista pe calea de
|
||
reemitere, se **elimina**.
|
||
|
||
**Si aici e problema reala, spusa pe fata:** runda 9 a stabilit deja ca **„nu exista niciun parametru
|
||
sau flag care sa opreasca re-derivarea"**, iar singura varianta care ocolea ramura — (d), `V_ID_CTR =
|
||
NULL` — a fost **respinsa motivat**, pentru ca pierde permanent legatura `VANZARI_DETALII.ID_CTR`.
|
||
Prin urmare decizia 54 **cere, cel mai probabil, o modificare in `pack_facturare`** (un semnal „nu
|
||
re-deriva, foloseste ce ti-am trimis" pe `adauga_articol_factura`), nu o solutie curat VFP. Asta atinge
|
||
un pachet din `COMUN`, partajat de toata suita — **iar modificarile de pachet se aplica tuturor
|
||
deodata, fara cale de intoarcere prin alegerea de la decizia 49.** Trebuie proiectata ca inerta pentru
|
||
apelantii de azi (implicit = comportamentul actual), exact ca la S4g.
|
||
|
||
**VERIFICAT in runda 14 — `docs\cercetare\s10_rederivare_pe_calea_reemiterii.md`.** Confirmat pe fisier
|
||
**si** pe DB (`all_source`, corp VALID, `last_ddl_time = 2026-08-09 20:03:50`).
|
||
|
||
**Se pierd intr-un SINGUR loc:** `adauga_articol_factura`, in `CASE`-ul de la `PF:5052-5220`, adica
|
||
**inainte** de `INSERT INTO VANZARI_DETALII_TEMP` (`PF:5222`). Tot ce urmeaza — copierea temp →
|
||
`VANZARI_DETALII` (`PF:13705-13757`) — e **1:1**, deci „copiaza `PRET` neschimbat" e adevarat dar **nu
|
||
e o protectie**: dauna e amonte de temp.
|
||
|
||
**RAMURILE CARE RE-DERIVA SUNT TREI, NU UNA. Raportul rundei 9 gresea.**
|
||
|
||
| valoare | **contract** (2/6/26/52) | **aviz** (`ntip = 4`) | **comenzi** (3/21/28/42/47) | restaurant (45) | `ELSE` |
|
||
|---|---|---|---|---|---|
|
||
| `PRET` | re-derivat din `CTR_ARTICOLE.PRET_UNITAR` daca `<> 0`; temp daca `= 0`; **NULL daca e NULL** (`PF:5149`) | **re-derivat neconditionat** din avizul sursa (`PF:5082`) | temp de facto — `WHERE A.PRET = V_PRET_TEMP` (`PF:5077`) | temp | temp |
|
||
| `PROC_TVAV` | re-derivat din `CRM_POLITICI_PRET_ART` | re-derivat din aviz | re-derivat din `COMENZI_ELEMENTE.PTVA` | derivat din `JTVA_COLOANE` | derivat din `JTVA_COLOANE` pe `ID_JTVA_COLOANA` **din formular** |
|
||
| `ID_VALUTA` | re-derivat | re-derivat | re-derivat | temp | temp |
|
||
| `PRET_CU_TVA` | re-derivat | re-derivat | re-derivat | temp | temp |
|
||
| `IN_STOC` | re-derivat din `NOM_ARTICOLE` | re-derivat | re-derivat | temp | temp |
|
||
|
||
- **Ramura AVIZ e cea mai agresiva din tot `CASE`-ul** (`PF:5080-5103`): `PRET` se inlocuieste
|
||
**neconditionat**, nu exista nici `DECODE`, nici `AND A.PRET = V_PRET_TEMP`, **si nu exista bloc
|
||
`EXCEPTION`**. Un pret modificat pe ecran e inlocuit tacit. In plus **nu filtreaza `A.STERS = 0`**,
|
||
desi coloana exista — linii sterse ale avizului sursa pot fi citite. Si depinde de `clistaid`, care
|
||
la reemitere **trebuie repopulata** (leaga direct de pasul 1 adaugat in S9).
|
||
- **Ramura comenzi esueaza tare, nu tacit** — fara `EXCEPTION`, o linie care nu se mai potriveste da
|
||
**ORA-01403**, vizibila. Mai putin periculoasa, dar tot re-derivare.
|
||
- **Ramura contract are o portita** — `EXCEPTION WHEN NO_DATA_FOUND` (`PF:5167-5185`) pune **toate cele
|
||
cinci** pe valorile din formular. **Comportamentul cerut de decizia 54 exista deja in cod**, dar
|
||
numai pe calea de exceptie. Aviz si comenzi **nu au** asa ceva.
|
||
- **Capcana NULL, dedusa din semantica `DECODE`, nerulata:** daca `CTR_ARTICOLE.PRET_UNITAR` e `NULL`
|
||
(nu `0`), `DECODE` nu potriveste literalul `0` → rezultatul e **NULL**, deci pretul din formular se
|
||
pierde complet si linia intra cu `PRET` gol. In dev cazul nu apare (27 randuri, 0 NULL) — **ceea ce
|
||
nu spune nimic despre productie**.
|
||
- **`PROC_TVAV` nu vine din formular pe NICIO ramura** — nu e parametru al procedurii. Pe calea „buna"
|
||
se deriva din `JTVA_COLOANE` pe `ID_JTVA_COLOANA`-ul trimis de formular, deci reproduce documentul
|
||
**doar cat timp cota nu s-a schimbat**. La o modificare legala de cota, reemiterea schimba TVA-ul
|
||
**chiar si pe `ELSE`**.
|
||
- **`IN_STOC` nu ajunge in `VANZARI_DETALII`** — coloana nu exista (verificat pe DB). Traieste doar in
|
||
temp, unde decide **descarcarea de gestiune**.
|
||
- **Dupa insertul in temp nimic nu mai suprascrie cele cinci valori.** `adauga_diferente_pret` atinge
|
||
numai `DIFERENTA`, `scrie_factura_avize` numai `CANTITATE`, `scrie_seturi` numai `ID_VANZARE_SET`.
|
||
|
||
### Cum se implementeaza decizia 54
|
||
|
||
**Curat VFP nu se poate — confirmat cu dovada pozitiva, nu prin absenta.** Semnatura n-are comutator
|
||
(`PF:4989-5015`, 27 de parametri, toti date de linie); globalele pachetului n-au (`PF:126-212`); poarta
|
||
`CASE`-ului se decide pe `ntip` (care ajunge in `VANZARI.TIP`, deci nu se poate falsifica) si pe
|
||
`CONTRACTE.OPT_FACTURARE` (date de contract, nu parametru). Singurele parghii VFP care ar devia pe
|
||
`NO_DATA_FOUND` sunt `V_ID_CTR = NULL` — **deja respinsa** — si `V_ID_POL = NULL`, care are **exact
|
||
acelasi defect pe alta coloana** (`PF:5258` → `temp.ID_POL` → `PF:13737` → `VANZARI_DETALII.ID_POL`) si
|
||
in plus ar rupe ramura aviz, care potriveste pe `A.ID_POL`. **Notata aici tocmai ca sa nu fie
|
||
redescoperita ca „solutie" intr-o runda urmatoare.**
|
||
|
||
**Deci decizia 54 cere obligatoriu modificare in `pack_facturare`** — dar mica, si care nu adauga
|
||
comportament nou:
|
||
|
||
- **Semnalul:** variabila noua de pachet („regenerare in curs"), implicit `0` = comportamentul de azi,
|
||
scrisa de VFP **dupa** `initializeaza_date_factura` (`ofacturare.vc2:13981`) si inainte de bucla de
|
||
`adauga_articol_factura`. *Recomandata* fata de un parametru `DEFAULT 0`, din trei motive: se
|
||
potriveste cu stilul pachetului (deja o punga de stare de sesiune); se scrie o data pe document, nu
|
||
o data pe linie, in toate produsele; si **punctul de resetare exista deja** —
|
||
`initializeaza_date_factura` (`PF:1808-1917`) reinitializeaza ~40 de globale si goleste temp
|
||
(`PF:1835`), deci flag-ul nu poate scapa in documentul urmator.
|
||
- **Ce face:** un `WHEN` nou, **primul** in `CASE`-ul de la `PF:5052`, cu **acelasi corp ca `ELSE`-ul de
|
||
azi** (`PF:5189-5203`). Nimic inventat — se forteaza ramura care exista deja. **Acopera dintr-o data
|
||
toate trei ramurile problematice**, fiind in acelasi `CASE`. `INSERT`-ul de la `PF:5222` ramane
|
||
neatins.
|
||
- **Inert prin constructie** pentru toti apelantii de azi, exact ca la S4g. **Consecinta de livrare:
|
||
DB inainte de EXE.**
|
||
|
||
### Trei consecinte de acceptat explicit, nu de descoperit la S12
|
||
|
||
1. **`IN_STOC` ar veni din formular.** Nu murdareste documentul (coloana nu exista), dar schimba
|
||
**comportamentul de stoc** al reemiterii. Ca reemiterea sa fie identica, **S8 trebuie sa incarce
|
||
valoarea cu care s-a scris documentul initial** — si **azi nu o incarca**: loader-ul lui #6 o citeste
|
||
din nomenclatorul curent (`ofacturare_editare.prg:302-303`). **Flag-ul singur nu rezolva asta.**
|
||
**PRELUAT (runda 17) ca cerinta de executie in S8**, cu cele trei consecinte pentru canalul de citire
|
||
si criteriul de test — vezi caseta „CERINTA DE EXECUTIE ADAUGATA IN RUNDA 17" din S8. Aici nu mai e
|
||
nimic de decis.
|
||
2. **Se pierde o validare pe ramura comenzi.** Azi, `A.PRET = V_PRET_TEMP` + lipsa lui `EXCEPTION` fac
|
||
ca o linie care nu se mai potriveste cu comanda sa **opreasca** scrierea. Cu flag-ul pornit,
|
||
reemiterea unei facturi din comanda nu mai verifica linia fata de comanda. Decizia 54 pare sa vrea
|
||
exact asta, dar e schimbare de comportament — **se declara, nu se descopera**.
|
||
3. **`PROC_TVAV` ramane derivat, nu preluat.** Reproducerea exacta cere ca S8 sa pastreze
|
||
`ID_JTVA_COLOANA` **si** ca `JTVA_COLOANE` sa nu se fi schimbat. Daca se cere reproducere exacta si
|
||
peste o modificare legala de cota, `PROC_TVAV` trebuie sa devina **parametru** — schimbare mai mare
|
||
decat flag-ul, **de decis separat**.
|
||
|
||
### Obstacol pentru S9, gasit in treacat
|
||
|
||
**`VVANZARI_ARTICOLE` nu expune `ID_POL` si nu expune `ID_CTR`** (lista de coloane interogata pe DB) —
|
||
exact cei doi pe care `adauga_articol_factura` ii cere (`V_ID_POL`, `V_ID_CTR`) si pe care
|
||
`VANZARI_DETALII` ii pastreaza. **Reemiterea nu poate folosi acest view ca atare**: ori se completeaza
|
||
view-ul, ori loader-ul citeste direct din `VANZARI_DETALII`. Se leaga de intrebarea 1 din S8 (canalul de
|
||
citire a liniilor) — **un argument in plus pentru varianta (B), procedura noua.**
|
||
|
||
*Gata cand:* pentru fiecare tip, documentul reemis are **exact valorile din formular** — pret, TVA,
|
||
valuta, flag „preturi cu TVA" — iar o reemitere fara modificari reproduce documentul identic, inclusiv
|
||
dupa ce pretul din contract s-a schimbat intre timp.
|
||
*Depinde de:* S9.
|
||
|
||
#### S11 — Legaturile care raman pe `ID_VANZARE`
|
||
`ID_FACT`, seria, numarul si data se pastreaza (E, F), deci legaturile prin `ID_FACT` sunt in
|
||
regula. Ramane discontinuitatea pe **`ID_VANZARE`**, care se schimba: `ATASAMENTE_VANZARI`,
|
||
`marcheaza_facturat`, `vanzari_coresp`, si eventualele referinte de incasari / plati.
|
||
De verificat si daca `DOCUMENTE` primeste un al doilea rand pe acelasi `ID_DOC` sau il refoloseste.
|
||
|
||
**PROIECTAT (runda 13) — `docs\cercetare\s11_legaturi_id_vanzare.md`. Inventarul s-a facut prin
|
||
FK-urile reale din Oracle, nu prin grep — si asta a scos doi consumatori pe care nicio cautare de text
|
||
nu-i gasise.**
|
||
|
||
- **Premisa centrala, corectata: mecanismul lui #6 NU se mosteneste de S9.** La #6, documentul isi
|
||
**pastreaza randul** din `VANZARI` — `actualizeaza_vanzari` face `UPDATE ... SET COD = nou,
|
||
STERS = 0`, deci **`ID_VANZARE` nu se schimba**, doar `COD`, si atasamentele se realiniaza in acelasi
|
||
gest. La S9, reemiterea merge pe drumul normal de emitere (`INSERT ... RETURNING ID_VANZARE`), deci
|
||
**rand nou, cheie noua, si `actualizeaza_vanzari` nu se declanseaza deloc.** Tot ce e protejat azi
|
||
tacit de #6 e **expus** la regenerare. Asta nu era in plan.
|
||
- **Sapte tabele au FK declarat pe `VANZARI.ID_VANZARE`. Doua nu erau in nicio lista:**
|
||
**`REST_NOTE_PLATA`** (modul restaurant) si **`IPS_VOYAGES_VANZARI`** (modul specific unui client).
|
||
Clasificate **(A) suspecte** — pachetele lor PL/SQL n-au fost citite integral.
|
||
**INCHIS de Marius, runda 14 — riscul dispare, si nu prin presupunere.** Intrebat direct, a raspuns:
|
||
*„daca este vorba despre facturarea voiajelor din ROAACNPRO, acolo nu merge modificarea de genul
|
||
acesta, ci doar editarea de la #6"*. **Documentele acestor module sunt IN AFARA domeniului
|
||
regenerabil al #13** — pentru ele ramane calea #6 (modificare pe loc). Pachetele lor **nu mai trebuie
|
||
citite**. Doua consecinte de dus mai departe: **(a) garda lui S7 trebuie sa le refuze EXPLICIT**, nu
|
||
doar sa nu le trateze — altfel „in afara domeniului" e o intentie, nu o garantie; **(b)** conditia se
|
||
declara in S13, la actualizarea `tipuri_documente_facturare.md`.
|
||
- **`ATASAMENTE_VANZARI` — corectie de premisa, in favoarea noastra.** **Nu** sunt documente incarcate
|
||
de utilizator: sunt **PDF-uri auto-generate la listare** (`poDate.scrieAtasamente()` dupa
|
||
`export2pdf`; cursorul nu vine din niciun dialog de fisier — cautat explicit, zero potriviri). Deci
|
||
**nu e pierdere ireparabila**, cum presupusese briefingul. Se rup totusi real: view-ul
|
||
`VATASAMENTE_VANZARI` filtreaza pe `b.sters = 0`, deci dupa regenerare atasamentele vechi **dispar
|
||
tacit** din toate interogarile (inclusiv din ROAGEST / ROAIMOB), desi BLOB-ul ramane fizic.
|
||
~~**(A) — remigrare printr-un simplu `UPDATE ... SET id_vanzare = :nou`**~~ — **INCHIS altfel,
|
||
decizia 53 (runda 14): se STERG la reemitere.** Marius a ales a treia varianta, nici remigrare, nici
|
||
marcaj „versiune inlocuita". Documentul reemis porneste curat. **Consecinta i-a fost spusa explicit
|
||
si a acceptat-o:** motivatia care sustinea remigrarea — *pastrarea urmei PDF-ului trimis clientului* —
|
||
**cade odata cu ea**; dupa editare nu mai exista in sistem dovada a ce a primit clientul. Punctul 15
|
||
se inchide aici.
|
||
- **Incasarile si platile nu sunt afectate — si dovada e structurala, nu statistica:** niciun tabel de
|
||
incasari/plati n-are FK pe `ID_VANZARE`, si nici referinta text. Se leaga prin **`ID_FACT`**, care se
|
||
pastreaza. **(C)**, cu dovada dubla.
|
||
- **eFactura, `DOCUMENTE`, listarile, `VANZARI_CANTITATI` — (C)**, toate cheiate pe `ID_FACT` sau
|
||
rescrise automat.
|
||
|
||
**INCHISE, nu de reintrebat (marcaj pus in runda 17).** Punctul 1 e transat de cercetarea garzilor din runda 14 (garda exista si e corecta; S7 o muta in pre-flight read-only) — ramane **limitare declarata**. Punctul 2 e rasturnat de **decizia 53**: atasamentul vechi **nu se remigreaza, se sterge**, deci premisa „factura editata ajunge cu PDF-ul vechi" nu se mai produce. Punctul 3 e inchis in runda 14, cu cerinta ca **S7 sa refuze explicit** cele doua tipuri. Se pastreaza ca inventar:
|
||
1. **Editarea unui document care are deja retur emis pe el e azi BLOCATA, nu doar riscanta** —
|
||
`sterge_factura` arunca `ORA-20000`. Garda e corecta (protejeaza lantul), iar **S7 planifica deja
|
||
sa semnaleze conditia inainte de intrarea in formular**, nu ca eroare Oracle la final. Ce ramane de
|
||
decis: se accepta ca **limitare declarata** (utilizatorul sterge intai documentele-copil), sau se
|
||
vrea alt comportament?
|
||
2. **Atasamentul vechi arata continutul dinainte de editare.** Remigrat pe documentul nou, factura
|
||
editata ajunge sa aiba atasat PDF-ul **vechi**. De decis daca asta e exact ce se vrea (audit trail),
|
||
sau daca vechiul ar trebui marcat cumva ca „versiune inlocuita".
|
||
3. **`REST_NOTE_PLATA` / `IPS_VOYAGES_VANZARI`** — de confirmat ca tipurile lor sunt in afara
|
||
domeniului regenerabil.
|
||
|
||
*Gata cand:* documentul reemis se regaseste corect in borderoul eFactura, in listari, in atasamente
|
||
si in rapoartele care il cauta dupa numar.
|
||
*Depinde de:* S9.
|
||
|
||
#### S12 — Test pe fluxul real, regenerarea
|
||
Cate un caz pe fiecare sursa, rulat de doua ori (o data fara modificari — reemitere identica, o data
|
||
cu modificari de cantitate, pret si linii adaugate / sterse). Se verifica: documentul initial
|
||
`sters = 1` cu nota si rulajele lui, documentul nou corect, sursa eliberata **si** reconsumata
|
||
(comanda redevine facturabila si redevine facturata), stocul corect dupa ciclu, totalurile
|
||
denormalizate din `VANZARI`, si ca o reemitere identica produce **exact** aceleasi sume.
|
||
|
||
**Probe adaugate de runda 13:**
|
||
- **Reemitere repetata de trei ori pe acelasi document** — `DIFERENTA` **nu se acumuleaza**. Motivul:
|
||
`cursor_retur_document` intoarce pretul deja **rotunjit si cu `DIFERENTA` pliata inauntru** (S10), iar
|
||
reemiterea trimite inapoi valoarea pliata, deci impartirea `PRET` / `DIFERENTA` se **reface** la
|
||
fiecare ciclu. Se verifica **suma**, nu impartirea — dar se verifica si ca impartirea nu deriveaza.
|
||
- **„Reemitere identica" nu e garantata uniform** (S10): pe `ELSE` / restaurant da; pe **comenzi**
|
||
esueaza **tare** (eroare vizibila); pe **contract** si pe **aviz (`ntip = 4`)** esueaza **tacit**.
|
||
Fiecare din cele patru situatii isi are cazul lui de test, cu rezultatul asteptat **declarat dinainte**
|
||
— inclusiv cele care trebuie sa dea eroare.
|
||
- **Deschid si inchid fara sa modific nimic → nicio scriere** (S8b), rulat pe un document al unui client
|
||
**cu activitate recenta** — cazul in care lookup-ul „ultimul delegat / masina" ar polua antetul.
|
||
|
||
*Depinde de:* S10, S11.
|
||
|
||
#### S14 — Audit: creare, modificare si stergere pe document
|
||
|
||
**Cerinta (decizia 63):** pentru fiecare document, sase informatii de audit — data + utilizator
|
||
pentru creare, pentru modificare (daca e cazul) si pentru stergere (daca e cazul).
|
||
|
||
**Cercetarea s-a terminat** — `docs\cercetare\audit_vanzari_creare_modificare_stergere.md`.
|
||
Verificat pe `all_tab_columns` (`ROA_CENTRAL`, schema live) si pe cod.
|
||
|
||
**Ce exista deja, pe `VANZARI`:**
|
||
- `ID_UTIL` + `DATAORA` — **creare**, ambele `NOT NULL`, scrise consecvent la fiecare `INSERT`
|
||
(`PACK_FACTURARE.scrie_in_vanzari`, `EXPORT:13598-13640`, si a doua ruta din
|
||
`finalizeaza_avize_lucrare`, `EXPORT:14930`). Niciun `UPDATE VANZARI SET ID_UTIL/DATAORA` in tot
|
||
pachetul (cautare directa, zero rezultate).
|
||
- `ID_UTILS` + `DATAORAS` — **stergere**, nullable, scrise consecvent de `sterge_factura`
|
||
(`EXPORT:5496-5499`) si `sterge_proforma`.
|
||
- (neceruta, dar arata conventia) `ID_UTILFACT` + `DATA_FACTURAT` — facturare din aviz.
|
||
- Pe `VANZARI_DETALII`: acelasi tipar de creare/stergere, plus `ID_UTIL_VALID` + `DATAORA_VALID`
|
||
(validare).
|
||
|
||
**Conventia casei:** o pereche utilizator + data per eveniment. Patru din cele sase informatii
|
||
cerute exista deja si se scriu consecvent.
|
||
|
||
**Ce lipseste, integral:** nicio coloana de **modificare**, nici pe `VANZARI`, nici pe
|
||
`VANZARI_DETALII`. Interogat explicit `all_tab_columns` cu filtru pe `%MODIF%` — zero rezultate.
|
||
`DATA_ACT` nu e echivalentul: e data contabila, propagata in `ACT`/`DOCUMENTE`/`JV2007`/`RUL`
|
||
(verificat in `modifica_date_factura`, `EXPORT:14439-14500`), nu un marcaj de audit.
|
||
|
||
**Capcana, si e miezul povestii:** editarea din #13 se face prin stergere + reemitere (S9), iar
|
||
documentul nou se scrie pe **acelasi `INSERT`** ca o creare normala (`scrie_in_vanzari`). Fara un
|
||
pas explicit, `ID_UTIL` / `DATAORA` ale documentului reemis ar deveni tacut utilizatorul si data
|
||
**modificarii**, iar informatia despre creare s-ar pierde — exact ce cere decizia 63 sa nu se
|
||
intample. **Precedentul de rezolvare exista deja in plan, pentru `ID_FACT`** (sectiunea „E.
|
||
`ID_FACT`", linia 762, si S9: se citeste din documentul vechi inainte de stergere si se impune
|
||
celui nou). **Niciun pas echivalent nu e proiectat azi pentru `ID_UTIL` / `DATAORA`** — cautare
|
||
directa in tot planul, zero mentiuni.
|
||
|
||
**Atenuare, nu solutie:** la regenerare randul vechi ramane cu `STERS = 1` si cu `ID_UTILS` /
|
||
`DATAORAS` completate — iar acea stergere **este** momentul modificarii. Cum `ID_FACT` se pastreaza
|
||
peste regenerare, lantul vechi → nou e parcurgibil, deci o parte din istoric e reconstruibila din
|
||
randurile existente, fara coloane noi. O pereche explicita pe documentul curent ramane insa
|
||
preferabila: se citeste direct, fara parcurgerea lantului.
|
||
|
||
**Complicatie reala, verificata pe cod livrat de #6:** editarea de linie
|
||
(`COMUN\programe\ofacturare_editare.prg`) scrie `id_utils` / `dataoras` pe `VANZARI_DETALII` si pe
|
||
randuri care **nu sunt sterse** — `ofacturare_editare.prg:492-494` (corect, cu `sters = 1`),
|
||
`:501-505` (odata cu `sters = 0`, pe rand viu) si `:522-525` (pe un rand proaspat inserat). Acolo
|
||
perechea de stergere e folosita ca marcaj „cine a umblat ultima data", nu strict ca „sters de/la".
|
||
**Consecinta:** un raport de audit nu poate citi `ID_UTILS` / `DATAORAS` ca „sters de/la" fara sa
|
||
puna si `STERS` in conditie. `ofacturare_editare.prg` e perimetrul lui #6, in lucru — semnalat aici,
|
||
neatins.
|
||
|
||
**Recomandare (de confirmat, nu decisa):**
|
||
1. **O singura pereche noua pe `VANZARI`**, urmand conventia casei — nume propus
|
||
`ID_UTILM` / `DATAORAM` (utilizator si data ultimei modificari). Numele e de confirmat.
|
||
2. **La regenerare (S9): `ID_UTIL` / `DATAORA` se transporta din documentul vechi in cel nou**,
|
||
exact ca `ID_FACT` — vezi nota adaugata la S9. Perechea noua de modificare primeste utilizatorul
|
||
curent si `sysdate`. Fara acest pas, creare si modificare se suprapun.
|
||
3. **Perechea de stergere nu are nevoie de nimic** — exista si e scrisa consecvent.
|
||
4. **Cere migrare de DB** (`ALTER TABLE` pe `VANZARI`) — **DB inainte de EXE**, ca la S10. Scriptul
|
||
intra in `D:\ROA\DATABASE\SCRIPTURI_CLAR\`, `versiune_db.txt` se bumpeaza.
|
||
|
||
**De decis cu Marius — AMBELE INCHISE prin decizia 65 (runda 16):**
|
||
- **(a)** Auditul e cerut numai pe antet (`VANZARI`) sau si pe linii (`VANZARI_DETALII`)? **Raspuns
|
||
prin deductie, nu spus explicit de Marius:** locul de afisare ales de el e gridul din `frm_facturi`,
|
||
care listeaza **documente** — deci auditul e pe **antet**.
|
||
- **(b)** Se afiseaza undeva in interfata (formular / lista), sau ramane doar pentru interogare?
|
||
**Da, se afiseaza** — in **gridul din `frm_facturi`**, nu in formularul facturii propriu-zise.
|
||
Prim pas de implementare: inventarul acelui grid, posibil sa existe deja coloane de audit.
|
||
|
||
*Gata cand:* documentul reemis pastreaza `ID_UTIL` / `DATAORA` ale creatiei originale; perechea noua
|
||
de modificare e completata la fiecare regenerare, cu utilizatorul si momentul curente; perechea de
|
||
stergere ramane neschimbata fata de azi; migrarea DB e aplicata inainte de EXE.
|
||
*Depinde de:* S9.
|
||
|
||
#### S13 — Diff, review, changelog, documentatie
|
||
|
||
**Atentie: S13 NU e momentul in care se face review-ul.** Conform metodei de executie, **fiecare story
|
||
isi are propriile teste, propriul diff si propriul code review, inainte de commit-ul ei** — S13 nu
|
||
strange la final ce n-a fost revizuit pe parcurs. Ce ramane aici e **inchiderea**, adica exact ce nu se
|
||
poate face per story:
|
||
|
||
- **Review de ansamblu**, pe suma povestilor: coerenta intre ele, cai ramase orfane, cod mort din
|
||
fluxul vechi care trebuia retras si n-a fost, si verificarea ca alegerea de la decizia 49 chiar
|
||
functioneaza in ambele sensuri.
|
||
- **Changelog** `:nou:`, cu mentiunile declarate explicit pe parcurs: asimetria `do_modifica`
|
||
corectata prin recalculul la cerere (decizia 45), si faptul ca `do_modifica` ramane activ pentru
|
||
multi-selectie (decizia 52).
|
||
- **Documentatie**: `COMUN\docs\tipuri_documente_facturare.md` — ce tipuri sunt regenerabile si ce
|
||
tipuri sunt **declarate explicit ca neacoperite** (48/49 si `frm_facturare_articole2`, daca se merge
|
||
pe recomandarea din S8), plus confirmarea din S11 pentru `REST_NOTE_PLATA` si `IPS_VOYAGES_VANZARI`.
|
||
- **Rularea suitei complete** — toate testele scrise per story, la un loc, nu doar cele ale ultimei
|
||
povesti.
|
||
- **Commit-urile finale**, in **ambele** repo-uri (ROAFACTURARE si COMUN), dupa aprobare.
|
||
|
||
---
|
||
|
||
## Riscuri
|
||
|
||
- ~~**Cel mai mare: perimetrul comun cu #6.**~~ **Inchis prin decizia 30** — implementarea lui #13
|
||
incepe dupa terminarea lui #6, deci nu exista doi scriitori simultan pe `ofacturare_comun.vc2` /
|
||
`ofacturare_editare.prg`. Riscul revine doar daca ordinea se schimba.
|
||
- ~~**Riscul „cod nou in `pack_facturare`" e evitat prin constructie (decizia 27-bis).**~~ **Caduc dupa
|
||
deciziile 34 si 35, si riscul revine ca risc principal.** Politica tehnica per `SCC` si scrierea in
|
||
`CRM_POLITICI_PRET_ART` nu se mai fac — deci cade si riscul ca o politica tehnica sa apara in
|
||
`caut_politici_curente_util()`. In locul lui: **`pack_facturare` se modifica** (parametru de cont +
|
||
ramura fara politica in `contabilizeaza_articol`), iar pachetul e **comun intregii suite** — ROACONT,
|
||
ROAGEST, ROACONTRACTE, ROAAUTO, ROAACNPRO. Mitigarea e structurala, nu prin inspectie: parametru
|
||
**`DEFAULT NULL` la finalul listei** si ramura inerta cand lipseste, astfel incat apelantii existenti
|
||
sa fie identici cu azi.
|
||
**MASURAT — `docs\cercetare\suprafata_regresie_contabilizeaza_articol.md`. Riscul e mai mic decat parea.**
|
||
`contabilizeaza_articol` are **trei apelanti, toti interni pachetului**, toti pozitionali cu acelasi
|
||
singur argument — **zero apelanti externi, nici PL/SQL, nici VFP, in niciunul din cele sapte produse**.
|
||
`adauga_articol_factura` e apelata **pozitional peste tot**, niciodata cu notatie pe nume (`=>`), iar
|
||
cele sapte copii `COMUN\clase\ofacturare.vc2` sunt **acelasi sit de apel duplicat**, nu sapte
|
||
implementari care ar putea diverge: fisierele difera intre ele (patru variante distincte pe MD5), dar
|
||
**textul apelului e identic cuvant cu cuvant**, doar offsetul de linie difera. Exista in plus doua
|
||
implementari proprii reale — ROAGEST (`Programe\ofactureaza.prg:264`) si ramura `_deviz` din ROAAUTO /
|
||
ROAACNPRO.
|
||
**Precedentul e activ, nu teoretic:** ROAGEST apeleaza azi `adauga_articol_factura` cu **24 din 25 de
|
||
parametri**, omitand `V_TAXCODE` si `V_LOT` tocmai pentru ca au `DEFAULT NULL`. Tiparul propus e deja
|
||
in uz in productie.
|
||
**Ce ramane:** toate cele **sapte** produse emit efectiv prin acest pachet, deci aria de regresie e
|
||
toata suita chiar daca niciun apelant nu se modifica.
|
||
- ~~**Anomalie preexistenta: `scrie_factura2` apelata cu 16 din 17 parametri.**~~ **INCHISA — fals
|
||
pozitiv, nu intra ca risc.** `oExecuta` (`COMUN\programe\oproceduri_comune.prg:121-159`) deleaga la
|
||
`oExecute` (`:173-504`), care face `SQLExec(lnHandle, lcSql, lcCursor)` (`:330`) — **textul SQL nu e
|
||
rescris**, deci al 17-lea parametru chiar n-are placeholder. Explicatia e tiparul cunoscut al
|
||
driverului ODBC Oracle: cand ultimul parametru declarat e un `REF CURSOR OUT`, driverul il ia din
|
||
catalog, nu din textul apelului, si intoarce randurile ca *result set* — captat exact de al treilea
|
||
argument al lui `SQLExec`. *Nuanta de pastrat:* mecanismul din interiorul driverului **nu poate fi
|
||
confirmat din codebase**, e verificabil doar prin comportament; dovada e indirecta, dar consistenta —
|
||
acelasi tipar in toate cele patru situri, neschimbat de la `v 2.0.13` la `v 2.0.93`, iar ecranul de
|
||
verificare depinde de acel cursor populat la fiecare emitere, deci un apel esuat s-ar fi vazut demult.
|
||
- **Decizia 35 leaga etapa II de aceeasi modificare de pachet.** Editarea prin regenerare nu mai are cale
|
||
proprie (canalul `oscrie_in_fisiere` e respins ca al doilea cod de contare), deci **un blocaj pe
|
||
parametrul deciziei 34 blocheaza si S9-S12**, nu doar etapa I. In schimb dispare riscul de divergenta
|
||
intre regula de contare de la emitere si cea de la editare.
|
||
- **`ofacturare.vc2` e in COMUN si are 843 KB / 25 de clase**, folosite de toata suita. Formularul
|
||
vechi trebuie sa ramana functional pana cand cel nou acopera toate tipurile — deci comutator, nu
|
||
inlocuire.
|
||
- **`ID_FACT` pastrat cere atingerea unui punct comun intregii suite.** `SET_IDFACT` e in
|
||
`PACK_CONTAFIN` si e chemat de fiecare scriere de note din toate produsele ROA. Comutatorul din S9
|
||
trebuie sa fie inert pentru toate celelalte cai; altfel regresia nu e in ROAFACTURARE, ci peste tot.
|
||
- **Formularul identic la introducere si la modificare taie o plasa de siguranta.** Decizia 9 o repune
|
||
**doar pe antet** — butonul protejeaza campurile de antet, nu si liniile. Pe articole nu exista niciun
|
||
semnal ca modificarea va sterge si va rescrie documentul; confirmarea de la `Termina` ramane
|
||
singurul moment in care se poate spune ce urmeaza sa se intample. De formulat cu grija.
|
||
- **Ascunderea datei de curs poate lasa un document fara curs corectabil.** `poDate.zi_curs` se
|
||
trimite neconditionat catre cursoarele de articole; daca lipseste cursul pentru acea zi, Oracle da
|
||
eroarea 20005 si se deschide formularul de curs — dar utilizatorul nu mai are unde sa corecteze data
|
||
daca i-am ascuns campul. Regula din M trebuie sa aduca inapoi campul in exact acest caz.
|
||
- **Sectiunea pliata ascunde campuri care schimba documentul.** Analiticele si datele de incasare
|
||
intra sub un panou inchis implicit. Daca un camp obligatoriu pe un anumit tip ajunge acolo,
|
||
utilizatorul primeste eroarea fara sa vada campul. Panoul trebuie sa se deschida singur cand
|
||
contine un camp necompletat si obligatoriu, si sa arate in antet ca are ceva completat.
|
||
- **Mutarea `frm_alte_date` muta si alocarea de numere.** Bonul fiscal, POS-ul si chitanta primesc
|
||
numar din masina de stari a incasarii. Daca ea ajunge sa ruleze la deschiderea formularului in loc
|
||
de la alegerea tipului de incasare, se aloca numere pentru documente care nu se mai emit.
|
||
- **`S3c` si `S4c` ating cod comun.** Parametrizarea sursei atinge `factureaza` (toata suita), iar
|
||
discountul editabil atinge listarile si eventual eFactura. Fiecare merge separat, cu regresie
|
||
proprie.
|
||
- **Reemiterea nu e idempotenta prin constructie.** Daca la reemitere pretul se re-deriva (H) sau
|
||
cursul valutar al zilei difera, documentul "nemodificat" iese cu alte sume decat originalul.
|
||
Testul din S12 (reemitere identica) exista tocmai ca sa prinda asta.
|
||
- **`verifica_total_document`** (`PACK_FACTURARE:16009+`) insereaza automat o linie de corectie cand
|
||
totalul difera de suma notelor. La regenerari repetate trebuie confirmat ca nu se acumuleaza —
|
||
aceeasi intrebare ca S7 din #6.
|
||
- **Cautarea in linie schimba un obicei.** Utilizatorii care lucreaza azi cu gridul de articole
|
||
vizibil si filtrare locala pierd vederea de ansamblu. Merita verificat pe un client inainte de a
|
||
scoate definitiv gridul vechi.
|
||
|
||
## Dependente
|
||
|
||
- **#7 (pret cu TVA pe linie)** — flagul `pret_cu_tva` pe linie apare in gridul unificat; se
|
||
pastreaza comportamentul stabilit acolo.
|
||
- **#12 (nomenclator ca lista de preturi)** — S4 construieste cautarea in linie peste politici de
|
||
preturi; daca #12 muta pretul in nomenclator, S4 se rescrie.
|
||
- **#16** — bug-ul de focus / renumerotare la revenirea din cursul valutar. Confirmat ca apare **dupa**
|
||
ce antetul s-a inchis si s-a eliberat (`ofacturare.prg:248`), la recuperarea erorii Oracle 20005.
|
||
In formularul unificat nu mai exista un antet inchis la care sa te intorci, deci **mecanismul lui
|
||
dispare** — de confirmat in S4d, nu de presupus.
|
||
- **#6** — **dependenta de calendar, nu de perimetru** (decizia 30): implementarea lui #13 incepe
|
||
dupa ce #6 se termina. Proiectarea si cercetarea merg mai departe in paralel.
|
||
|
||
## Preconditii de mediu
|
||
|
||
- Orice DDL / modificare `PACK_FACTURARE`: sursa de referinta e `MARIUSM_AUTO` pe `ROA_CENTRAL`,
|
||
nu productia (`COMUN\docs\scripturi-migrare-db.md`). Scripturi nivel Oracle 10.2, CRLF,
|
||
idempotente, `versiune_db.txt` actualizat.
|
||
- Sursa completa `PACK_FACTURARE` nu e in working copy; copia pe disc e
|
||
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql` (16 948 linii),
|
||
cu alta numerotare decat exportul din baza.
|
||
- Editarile pe `.vc2` / `.sc2` trec prin `git_sync.ps1` + `txt2vcx.ps1`, cu atentie la
|
||
`COMUN\docs\conventie_encoding_cp1252.md` (diacriticele din `.vc2` sunt cp1250 — vezi si memoria
|
||
proiectului).
|