162 lines
11 KiB
Markdown
162 lines
11 KiB
Markdown
# Harta cod: adaugare/editare FACTURA si AVIZ (read-only)
|
|
|
|
Sursa: text FoxBin2Prg deja in-tree (`.vc2`/`.prg`), citit cu `Grep`/`Read` si indexat cu
|
|
`vfp_symbols.ps1` (`-CacheRoot/-ProjectRoot D:\ROA\ROAFACTURARE`,
|
|
`-IndexFile D:\ROA\_vfp_textcache\roafacturare\_symbols.tsv`). Nicio modificare de fisier.
|
|
|
|
## 1. Formulare si clase implicate
|
|
|
|
Nu exista formular `.scx` pentru factura/aviz in acest proiect (`.scx`-urile din arbore sunt
|
|
doar utilitare: `frm_borderou_facturi.scx`, `frm_import_efactura.scx` etc.). Ecranul de
|
|
adaugare/editare e o **clasa `.vcx` instantiata prin `Createobject()`**, nu un `DO FORM`:
|
|
|
|
- **`frm_facturare_articole2`** — `COMUN\clase\ofacturare.vcx` (text `COMUN\clase\ofacturare.vc2:15936-22614`).
|
|
Formularul unificat, curent, folosit in productie pentru factura SI aviz. Instantiat in
|
|
`COMUN\programe\ofacturare.prg:248` (`ofrmdetaliifactura = Createobject('frm_facturare_articole2')`)
|
|
si in `COMUN\clase\ofacturare_comun.vc2:4028`, doar cand `llFacturareNoua` e adevarat
|
|
(`COMUN\programe\ofacturare.prg:246-248`).
|
|
- **`frm_facturare_articole`** — acelasi fisier, `ofacturare.vc2:11123-15936`. Varianta mai veche;
|
|
in cod de productie nu mai e instantiata (doar in probele din
|
|
`COMUN\utile\Teste\facturare_unificat\*.prg` si `COMUN\utile\Teste\editare_factura\creeaza_documente_s8.prg:571`,
|
|
`emite_document_stoc_s93.prg:264`) — ramane in clasa dar calea curenta e `frm_facturare_articole2`.
|
|
- **Flux vechi, ne-unificat** (`llFacturareNoua = .F.`, `ofacturare.prg:255-266`) — alege un
|
|
formular de antet separat pe tip de document, fara grila unificata de articole:
|
|
- `frm_date_aviz_lucrare` — `ofacturare.vc2:7775` — pentru `tnTip` 27 sau 30.
|
|
- `frm_date_factura` — `ofacturare.vc2:8637` — pentru `tnTip < 21` sau in `(45,48,49,51,52)`.
|
|
- `frm_date_aviz` — `ofacturare.vc2:6721` — altfel (aviz).
|
|
- **`oAntetFacturare`** (`Define Class ... As Custom`) — `COMUN\programe\ofacturare_antet.prg:14`.
|
|
Logica de antet a lui `frm_facturare_articole2`: cautari (`do_cauta_*`), validare
|
|
(`valideaza_antet`), schimbarea tipului de document (`alege_tipdoc`, `schimba_tipdoc`).
|
|
Header-ul fisierului (`ofacturare_antet.prg:1-7`) spune explicit ca a fost **portata din
|
|
`frm_date_factura`/`frm_date_aviz`** cand s-a facut unificarea. Instantiata in
|
|
`frm_facturare_articole2.Init`: `This.oAntet = Createobject('oAntetFacturare')` (`ofacturare.vc2:21365`).
|
|
- **`oDateFactura`** (`poDate`) — `COMUN\programe\ofacturare_comun.prg:131`. Obiectul de stare al
|
|
documentului curent (creat in `ofacturare.prg:196`); tine `nIdTipDoc`, `nIdTipDocFactura`(=5),
|
|
`nIdTipDocAvizExpeditie`(=6), `id_gestiune_init`, `listaid`, `id_pol`, `zi_curs` etc.
|
|
- **`ofacturare_editare.prg`** (`COMUN\programe\ofacturare_editare.prg`, 1444 linii) — flux **separat**,
|
|
pentru editarea liniilor unei facturi/aviz deja emise (nu formularul de creare):
|
|
`IncarcaAntetFacturaEditare` (63), `IncarcaLiniiFacturaEditare` (209),
|
|
`PregatesteArticoleFacturaEditare` (605), `ScrieArticoleFacturaEditate` (741),
|
|
clasa `ArticoleNotaEditor As Custom` (1226). Inregistrat via
|
|
`Set Procedure To ofacturare_editare.prg Additive` (`Programe\roafacturare.prg:219`).
|
|
- **`combosql_cautare`** — clasa de baza pentru comboboxurile de cautare din grid (vezi pct. 2),
|
|
`ofacturare.vc2:407-531`, mostenind `combosql As combobox` din `COMUN\clase\_cb_base.vc2:519`.
|
|
|
|
## 2. Zona de introducere articole (cautare cod material / denumire)
|
|
|
|
In grila `grd_factura` a lui `frm_facturare_articole2`, coloanele au cate un combobox de tip
|
|
`combosql_cautare`:
|
|
|
|
- `grd_factura.cCodMat.cboCodmat` — `ADD OBJECT` la `ofacturare.vc2:17524-17537`,
|
|
`ncharcountbegin = 2`, `pcursorname = crsCodmat`, `pfieldactiv = codmat`.
|
|
- `grd_factura.cDenumire.cCboDenumire` — `ADD OBJECT` la `ofacturare.vc2:17560-17574`,
|
|
`ncharcountbegin = 2`, `pcursorname = crsDenumire`, `pfieldactiv = denumire`.
|
|
|
|
**Pragul de caractere**: logica e in `combosql_cautare.refreshdata` (`ofacturare.vc2:463-496`):
|
|
|
|
```
|
|
lnTip = Iif(Type('tnTip') = 'N', m.tnTip, 0)
|
|
If m.lnTip <> 0 And Len(Alltrim(This.cSearchString)) <= This.nCharCountBegin
|
|
Return .T. && nu cauta, iese
|
|
Endif
|
|
```
|
|
|
|
Cu `ncharcountbegin = 2` pe ambele combo-uri, filtrarea porneste abia cand
|
|
`Len(cSearchString) > 2`, adica de la **al treilea caracter tastat**.
|
|
|
|
**Interactivechange/Keypress**: nu sunt suprascrise in `combosql_cautare` — vin din parintele
|
|
`combosql` (`COMUN\clase\_cb_base.vc2:519`):
|
|
- `InteractiveChange` (linia 606-608): doar reseteaza `cSearchString`.
|
|
- `KeyPress` (linia 610-776): construieste `csearchstring` caracter cu caracter (sageti,
|
|
Del/Backspace tratate separat), apoi cheama `This.RefreshData(1)` = cautare "incepe cu"
|
|
(linia 720) sau, la Ctrl+Enter, `RefreshData(2)` = cautare "contine" (liniile 636-649).
|
|
|
|
**Filtrul/SQL aplicat**: `refreshdata` seteaza `cfiltrucod`/`cfiltruden` in functie de tip
|
|
(`ofacturare.vc2:476-489`):
|
|
```
|
|
Case lnTip = 1 (incepe cu): cfiltrucod/cfiltruden = cSearchString + '%'
|
|
Case lnTip = 2 (contine): cfiltrucod/cfiltruden = '%' + cSearchString + '%'
|
|
```
|
|
apoi `cursor_preturi_call()` (`ofacturare.vc2:446-461`) construieste apelul catre pachetul
|
|
Oracle `pack_facturare.cursor_preturi(?poDate.zi_curs,?poDate.tip,?poDate.id_valuta,
|
|
?poDate.id_gestiune_init sau ?poDate.listaid,?gnLuna,?gnAn,?gnIdUtil,?gnIdSucursala,
|
|
?pcFiltruCod,?pcFiltruDen)` (sau `pack_facturare.cursor_gestiune(...)` cand `poDate.tip = 41`),
|
|
executat prin `goExecutor.oExecuta` in `selectdata` (linia 514-529). Corpul PL/SQL al
|
|
pachetului nu e in acest repo VFP (schema Oracle) — nu l-am putut citi read-only de aici.
|
|
Proprietatile `csourcesql`/`csourcewhere` de pe `ADD OBJECT` (ex. `select codmat, denumire, ...
|
|
from vnom_articole ... where inactiv = 0`) sunt doar sablonul design-time al cursorului gol
|
|
(`creeaza_cursor_gol`, linia 426), nu interogarea reala rulata la tastare.
|
|
|
|
**Sincronizare cod<->denumire** dupa alegere: `grd_factura.cCodMat.cboCodmat.LostFocus`
|
|
(`ofacturare.vc2:22088-22109`) si perechea ei `cDenumire.cCboDenumire.LostFocus`
|
|
(22115-22136) cheama `thisform.do_adauga_articol_cautat(loArticol, loArticol.cantitate)`
|
|
si fortez re-creerea cursorului celeilalte combo (seteaza `cSearchString` cu valoarea gasita
|
|
si reseteaza `RowSource`), ca sa afiseze articolul ales in ambele coloane.
|
|
|
|
## 3. Lista de preturi / politici de pret
|
|
|
|
- `poDate.id_gestiune_init` e parametrul implicit trimis la `pack_facturare.cursor_preturi`;
|
|
cand `poDate.tip = 45` se trimite `poDate.listaid` in loc (`ofacturare.vc2:453-457`).
|
|
- De ce poate aparea un articol de mai multe ori: interogarea serverului (Oracle,
|
|
`pack_facturare.cursor_preturi`) uneste nomenclatorul de articole cu politicile de pret —
|
|
confirmarea client-side ca politicile sunt cheia vine din `modifica_lista_preturi`
|
|
(`ofacturare.vc2:21735-21837`), care interogheaza direct tabelele de politici:
|
|
`Select id_pol_art, id_venchelt, proc_tvav from crm_politici_pret_art where id_pol = ...
|
|
and id_articol = ...` (linia 21755) si scrie prin `pack_preturi.adauga_politica_pret_art`/
|
|
`pack_preturi.modifica_pret_pol_pret_art` (21779, 21792). Corpul exact al join-ului din
|
|
`cursor_preturi` e in PL/SQL, nevizibil din acest working copy VFP — afirmatia despre
|
|
"un rand per politica aplicabila" e o inferenta din tabelele folosite, nu o citire directa
|
|
a interogarii.
|
|
|
|
## 4. Zona de jos: controale de discount/totaluri
|
|
|
|
Toate sunt copii directe ale formularului `frm_facturare_articole2` (fara container
|
|
intermediar), clasa `_textbox` din `_baza.vcx`, asezate sub grila (Top ~742-792):
|
|
|
|
| Obiect | Top | Left | Width | Anchor | Note |
|
|
|---|---|---|---|---|---|
|
|
| `tx_total_baza_nat` (18123) | 745 | 17 | (implicit) | 4 | ReadOnly, `ControlSource=thisform.nbazaron` |
|
|
| `tx_total_baza_val` (18137) | 789 | 17 | (implicit) | 4 | ReadOnly, `thisform.nbazaval` |
|
|
| `tx_disc_factura_nat` (18082) | 745 | 351 | (implicit) | 4 | ReadOnly, `thisform.ndiscfactron` |
|
|
| `tx_disc_factura_procent` (18096) | 767 | 542 | 54 | 4 | editabil, `Value=0` |
|
|
| `tx_disc_factura_val` (18109) | 789 | 351 | (implicit) | 4 | ReadOnly, `thisform.ndiscfactval` |
|
|
| `tx_total_tva_nat` (18181) | 742 | 689 | (implicit) | 12 | ReadOnly, `thisform.ntvaron` |
|
|
| `tx_total_tva_val` (18195) | 792 | 689 | (implicit) | 12 | ReadOnly, `thisform.ntvaval` |
|
|
| `tx_total_factura_nat` (18151) | 742 | 833 | (implicit) | 12 | ReadOnly, FontBold, `thisform.ntotalron` |
|
|
| `tx_total_factura_val` (18166) | 792 | 835 | (implicit) | 12 | ReadOnly, FontBold, `thisform.ntotalval` |
|
|
|
|
(linii = `COMUN\clase\ofacturare.vc2`). `Anchor=4` = ancorat de Bottom (coboara odata cu
|
|
formularul); `Anchor=12` (4+8) = Bottom+Right, pe coloana totalurilor din dreapta. Niciun
|
|
`Height`/`Width` explicit pe majoritatea — mostenesc default-ul clasei `_textbox`; doar
|
|
`tx_disc_factura_procent` are `Width=54` explicit. Nu am gasit cod care repozitioneaza
|
|
aceste controale la runtime in `frm_facturare_articole2` — pozitionarea e strict design-time
|
|
+ `Anchor` (fara logica de `Resize`/`Move` pe ele; `Resize` al formularului, linia
|
|
21847-21854, nu le atinge explicit).
|
|
|
|
## 5. Diferente factura vs aviz pe `frm_facturare_articole2`
|
|
|
|
- **Discriminator unic**: `poDate.nIdTipDoc`, comparat cu `poDate.nIdTipDocFactura` (=5) /
|
|
`poDate.nIdTipDocAvizExpeditie` (=6). Helper: `oAntetFacturare.EsteAviz()`
|
|
(`ofacturare_antet.prg:16-18`): `Return poDate.nIdTipDoc = poDate.nIdTipDocAvizExpeditie`.
|
|
- **Setare initiala**, dupa `tnTip` primit la deschidere (`COMUN\programe\ofacturare.prg:196-206`):
|
|
```
|
|
Case tnTip = 27 or 30 -> nIdTipDoc = 6 (AVIZ)
|
|
Case tnTip < 21 sau tnTip in (45,48,49,51,52) -> nIdTipDoc = 5 (FACTURA)
|
|
Otherwise -> nIdTipDoc = 6 (AVIZ)
|
|
```
|
|
- **Schimbare interactiva**: combo `clb_fdoc.cboFdoc` -> `do_schimba_tipdoc`
|
|
(`ofacturare.vc2:20046-20071`) -> `oAntet.alege_tipdoc(valoare_combo)` mapeaza textul
|
|
("FACTURA"/"AVIZ"/"PROFORMA"/"BON FISCAL") pe id-ul de tip, apoi `oAntet.schimba_tipdoc(id)`
|
|
(`ofacturare_antet.prg:889-923`) actualizeaza `poDate.nIdTipDoc` si seriile. Exista o garda:
|
|
daca documentul e proforma si au fost deja adaugate articole, schimbarea tipului e blocata
|
|
cu `amessagebox` (`ofacturare.vc2:20050-20055`).
|
|
- **Ramuri `EsteAviz()` in `oAntetFacturare`** (aceleasi metode de cautare/validare servesc
|
|
ambele tipuri, dar cu cai diferite): `do_cauta_altele` (20-45), `do_cauta_client` (97-100),
|
|
`do_cauta_comanda` (240-243), `do_cauta_contract` (296-299), `do_cauta_gestiune_init`
|
|
(518-521), `do_cauta_lucrare` (553-556), `do_cauta_sectie` (633-636), `do_cauta_venchelt`
|
|
(708-711), `valideaza_antet` (762-766) — toate in `COMUN\programe\ofacturare_antet.prg`.
|
|
- **Fluxul vechi (ne-unificat)** folosea deja formulare separate per tip pentru antet
|
|
(`frm_date_factura` / `frm_date_aviz` / `frm_date_aviz_lucrare`, vezi pct. 1) — unificarea
|
|
descrisa in header-ul `ofacturare_antet.prg` a mutat logica lor comuna intr-o singura clasa,
|
|
ramura aleasa la runtime pe `poDate.nIdTipDoc`.
|