docs: runda 6 - cercetari, propuneri si conventia mediului Oracle
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
This commit is contained in:
327
docs/cercetare/rec_r6_buton_modificare_frm_facturi.md
Normal file
327
docs/cercetare/rec_r6_buton_modificare_frm_facturi.md
Normal file
@@ -0,0 +1,327 @@
|
||||
# R6 - butonul "Modificare articol" din frm_facturi + explicatie TVA - diagnostic
|
||||
|
||||
Raspuns la cerinta: pe formularul de facturare `frm_facturi` (lista facturi/avize/proforme, NU
|
||||
`frm_modific2024`), butonul care edita azi `explicatie`+`taxcode` sa expuna si "explicatie TVA",
|
||||
cu sincronizare automata `explicatie TVA -> taxcode`. Fiecare afirmatie e **VERIFICAT** (citit din
|
||||
sursa, `fisier:linie`) - nu apare nimic marcat NESTABILIT, tot ce s-a cerut s-a putut confirma din
|
||||
cod.
|
||||
|
||||
---
|
||||
|
||||
## A. Localizarea `frm_facturi`
|
||||
|
||||
Clasa `frm_facturi` (nu form `.scx` separat) - definita in
|
||||
`COMUN\clase\ofacturare_comun.vc2:1168`:
|
||||
|
||||
```
|
||||
DEFINE CLASS frm_facturi AS _frmbase OF "_frm_base.vcx"
|
||||
```
|
||||
|
||||
Lant de mostenire: `frm_facturi -> _frmbase (_frm_base.vc2:7) -> _form (_baza.vc2:157) -> form`.
|
||||
Instantiat din `roafacturare.prg` (meniul principal), nu are `.scx` propriu - toata definitia e in
|
||||
binarul `ofacturare_comun.vcx`.
|
||||
|
||||
---
|
||||
|
||||
## B. Butonul "Modificare articol"
|
||||
|
||||
Obiect **`But_modifica2`**, definit in `frm_facturi` la `ofacturare_comun.vc2:1436-1444`:
|
||||
|
||||
```
|
||||
ADD OBJECT 'But_modifica2' AS but_modifica WITH ;
|
||||
Anchor = 12, ;
|
||||
caction = do_modifica_explicatie, ;
|
||||
Caption = "", ;
|
||||
Left = 710, ;
|
||||
Name = "But_modifica2", ;
|
||||
TabIndex = 27, ;
|
||||
ToolTipText = "Modificare explicatie articol", ;
|
||||
Top = 341
|
||||
*< END OBJECT: ClassLib="cmd_butoane.vcx" BaseClass="commandbutton" />
|
||||
```
|
||||
|
||||
`Caption` e gol (e un buton cu picture, nu text); `ToolTipText` = "Modificare explicatie
|
||||
articol". Clasa `but_modifica` (`cmd_butoane.vc2:184-197`) nu are `Click` propriu - mosteneste
|
||||
`buton.Click` din `_cmd_base.vc2:41-71`, care e un dispatcher generic:
|
||||
|
||||
```
|
||||
PROCEDURE Click
|
||||
Local lcAction, lcCommand, lcListaParametri
|
||||
lcAction = This.cAction
|
||||
...
|
||||
If Type('this.parent') = 'O' And Pemstatus(This.Parent,lcAction,5)
|
||||
lcCommand = [this.Parent.] + lcAction + lcListaParametri
|
||||
&lcCommand
|
||||
Else
|
||||
If Type('this.parent.PARENT') = 'O' And Pemstatus(This.Parent.Parent,lcAction,5)
|
||||
lcCommand = [this.Parent.Parent.] + lcAction + lcListaParametri
|
||||
&lcCommand
|
||||
Else
|
||||
If Pemstatus(Thisform,lcAction,5)
|
||||
lcCommand = [thisform.] + lcAction + lcListaParametri
|
||||
&lcCommand
|
||||
Endif
|
||||
Endif
|
||||
Endif
|
||||
ENDPROC
|
||||
```
|
||||
|
||||
Cu `caction = do_modifica_explicatie` si parintele `But_modifica2` fiind direct `frm_facturi`
|
||||
(fara container intermediar cu aceeasi metoda), rezultatul e efectiv `thisform.do_modifica_explicatie()`.
|
||||
Corpul integral al metodei (`ofacturare_comun.vc2:4642-4659`):
|
||||
|
||||
```
|
||||
PROCEDURE do_modifica_explicatie
|
||||
If Reccount('crsDetalii') > 0
|
||||
update_saft_taxtable()
|
||||
Select crsDetalii
|
||||
Scatter Name poRec Memo
|
||||
poRec.explicatie = NVL(poRec.explicatie, ' ')
|
||||
If poRec.sters = 0
|
||||
ofrmmodificare = Createobject("frm_modifica_articol_factura")
|
||||
ofrmmodificare.Show()
|
||||
If gnButon = 1
|
||||
Thisform.actualizeaza_grid2()
|
||||
Endif
|
||||
Endif
|
||||
Endif
|
||||
ENDPROC
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## C. Ce deschide butonul
|
||||
|
||||
Un formular modal separat: **`frm_modifica_articol_factura`**
|
||||
(`ofacturare_comun.vc2:5129-5253`), clasa `AS frm_termin_renunt OF "_frm_child.vcx"` (dialog
|
||||
copil standard, cu `But_termin1`/`But_renunt1`). Titlu: `Lb_titlu_alb_b121.Caption = "Modifică
|
||||
explicație articol"` (`:5163`).
|
||||
|
||||
Campuri editabile azi, cu `ControlSource` si linii:
|
||||
|
||||
| control | tip | ControlSource | label | linie |
|
||||
|---|---|---|---|---|
|
||||
| `Ed_tx_simplu1._edbase1` | editbox | `porec.explicatie` | "Explicație" (+ "( maxim N caractere )" adaugat in `Init`) | `:5213-5223` |
|
||||
| `cbo_saft` | combobox | `poRec.taxcode` | "Cod taxa" (`lbSaft`) | `:5185-5199` |
|
||||
|
||||
`cbo_saft` e legat direct pe `poRec.taxcode` (BoundColumn=4), cu:
|
||||
|
||||
```
|
||||
RowSource = "Select taxname, tip, procent_taxa, taxcode From saft_taxtable where tva = 1 order by taxcode Into Cursor crsTaxTableX"
|
||||
```
|
||||
|
||||
adica lista tuturor codurilor SAF-T (cursor local `saft_taxtable`, populat de
|
||||
`update_saft_taxtable()` apelat inainte de deschidere) - **nu exista azi nicio legatura cu
|
||||
explicatia TVA**; userul alege direct un `taxcode` dintr-o lista plata de coduri fiscale.
|
||||
|
||||
Niciun alt camp (cantitate, pret, articol, id_jtva_coloana) nu e pe acest dialog.
|
||||
|
||||
---
|
||||
|
||||
## D. Cum se scrie inapoi - si confirmarea premisei "nu modifica valorile"
|
||||
|
||||
Salvare in `inainte_de_do_termin` (`ofacturare_comun.vc2:5225-5233`):
|
||||
|
||||
```
|
||||
PROCEDURE inainte_de_do_termin
|
||||
Local llReturn
|
||||
If amessagebox("Doriti sa salvati modificarile?",4+32,"Confirmare salvare explicatie") = 6
|
||||
lcSql = [begin pack_facturare.modifica_explicatie_articol(] + Alltrim(Str(poRec.id_vanzare_det)) + [,] + ;
|
||||
['] + Nvl(Alltrim(OracleSpecialCharacters(poRec.explicatie)),'') + [',?gnIdUtil,?poRec.taxcode); end;]
|
||||
llReturn = goExecutor.oExecuta(lcSql)
|
||||
Else
|
||||
llReturn = .F.
|
||||
Endif
|
||||
Return llReturn
|
||||
ENDPROC
|
||||
```
|
||||
|
||||
Scrierea e **direct in Oracle**, prin `pack_facturare.modifica_explicatie_articol(id_vanzare_det,
|
||||
explicatie, id_util, taxcode)`. Cercetare anterioara deja confirmase corpul acestei proceduri
|
||||
(`docs\cercetare\rec_cale_vanzari_detalii.md:195-199`, citat identic aici pentru trasabilitate):
|
||||
|
||||
```sql
|
||||
UPDATE VANZARI_DETALII SET EXPLICATIE = V_EXPLICATIE, TAXCODE = V_TAXCODE
|
||||
WHERE ID_VANZARE_DET = V_ID_VANZARE_DET
|
||||
```
|
||||
|
||||
**Confirmat: doar 2 coloane se scriu** (`explicatie`, `taxcode`). Nu se ating `cantitate`, `pret`,
|
||||
`pret_cu_tva`, `proc_tvav`, `id_jtva_coloana` si nu exista niciun apel de recalcul de totaluri
|
||||
(`gcs.vact_tot`/`vrul_tot`, note contabile, rulaje) in acest flux - premisa utilizatorului
|
||||
("campuri care nu modifica valorile") **e corecta pentru starea de azi a acestor doua campuri**.
|
||||
|
||||
---
|
||||
|
||||
## E. "Explicatie TVA" ca data + sincronizarea cu taxcode - sablonul deja aplicat in frm_modific2024
|
||||
|
||||
Campul din baza este **`id_jtva_coloana`** (nu `taxcode`) - nomenclator `vjtva_coloane`
|
||||
(`id_jtva_coloana, denumire, cota_tva`). `taxcode` e un cod SAF-T/e-Factura separat, derivat din
|
||||
`id_jtva_coloana` + context (partener, data, tip TVA), nu ales direct de nomenclatorul de
|
||||
explicatii.
|
||||
|
||||
Sablonul de sincronizare cerut de utilizator **exista deja**, aplicat in runda 5 pe
|
||||
`frm_modific2024` / `pgfArticole.PAGE3.grdArticoleFactura` (cursor `tvd`), documentat in
|
||||
`docs\raport_runda5_omodificari.md` si `docs\propunere_runda4_note_sincronizare_tva.md` (sectiunea
|
||||
5, "varianta B"). Cod citit direct din sursa curenta (`COMUN\programe\ofacturare_editare.prg`,
|
||||
`ArticoleNotaEditor.ModificaNomenclator`, `:1100-1108`):
|
||||
|
||||
```
|
||||
CASE m.lcCamp == 'id_jtva_coloana'
|
||||
*!* cota vine din explicatia aleasa, ca la randul de nota; taxcode-ul SAF-T se recoreleaza dupa ea
|
||||
REPLACE id_jtva_coloana WITH loCauta.id_jtva_coloana, ;
|
||||
proc_tvav WITH (Nvl(loCauta.cota_tva, 0) + 100) / 100
|
||||
This.oForm.UpdateExplicatieSAFTArt()
|
||||
This.oForm.calculeaza_valori_articol()
|
||||
```
|
||||
|
||||
`UpdateExplicatieSAFTArt` (`omodificari.vc2:15049-15074`) e "jumatatea taxcode" a sincronizarii -
|
||||
deriva `taxcode` din `id_jtva_coloana` prin functia comuna `GetTaxCodeIdPart`:
|
||||
|
||||
```
|
||||
PROCEDURE updateexplicatiesaftart
|
||||
IF !m.gl406
|
||||
RETURN
|
||||
ENDIF
|
||||
...
|
||||
lnIdJtva = tvd.id_jtva_coloana
|
||||
lnIdPart = Nvl(tAct.id_partc, tAct.id_partd)
|
||||
...
|
||||
lnTaxCode = GetTaxCodeIdPart(m.gnAn, m.gnLuna, m.ldDataAct, m.lnIdJtva, m.lnIdPart, m.llN50, m.llN100, m.llNeexigibil)
|
||||
Replace taxcode With m.lnTaxCode In tvd
|
||||
This.pgfArticole.PAGE3.grdArticoleFactura.cTaxcodeArt.Refresh()
|
||||
ENDPROC
|
||||
```
|
||||
|
||||
Relatia exacta explicatie TVA -> taxcode: **`id_jtva_coloana` (+ an/luna/data act/partener/steaguri
|
||||
N50-N100/neexigibil) -> `GetTaxCodeIdPart()` -> `taxcode`**. Nu e un `Do Case` simplu pe
|
||||
`id_jtva_coloana`; `GetTaxCodeIdPart` (functie globala, `COMUN\programe\oproceduri_comune.prg:6059-6125`,
|
||||
NEschimbata pentru aceasta cerere) incapsuleaza toata logica SAF-T 406.
|
||||
|
||||
**Garda `gl406`**: `UpdateExplicatieSAFTArt` (si perechile ei `Rul`/simplu) nu fac nimic daca
|
||||
`gl406 = .F.` (`COMUN\programe\oinit_optiuni.prg:524`, flag global de optiuni). Adica sincronizarea
|
||||
taxcode <- explicatie TVA e activa doar cand raportarea SAF-T 406 e activata pentru firma curenta -
|
||||
de verificat la implementare daca `frm_facturi` are acces la acelasi `gl406`.
|
||||
|
||||
---
|
||||
|
||||
## F. Cum se deschide azi nomenclatorul de explicatie TVA
|
||||
|
||||
Doua rutine **globale, refolosibile din orice formular** (nu legate de contextul lui
|
||||
`frm_modific2024`):
|
||||
|
||||
1. **`caut_explicatie_tva(tnIdJtva, tnPornire, tlDesktop, tlTipEx, tnCotaTva)`**
|
||||
(`COMUN\programe\ocautare.prg:3174-3238`) - deschide dialogul de cautare pe
|
||||
`select id_jtva_coloana, denumire, cota_tva from vjtva_coloane`, filtrat implicit pe
|
||||
`id_jtva_coloana > 0` (cand `tlTipEx` e gol) si, daca `tnCotaTva > 0`, suplimentar pe
|
||||
`cota_tva = tnCotaTva` (`:3218-3220`, filtru adaugat tot in runda asta). Returneaza obiectul
|
||||
`loCauta` din `cauta_alfa` (are `.id_jtva_coloana`, `.denumire`, `.cota_tva`).
|
||||
2. **`GetTaxCodeIdPart(an, luna, data_act, id_jtva, id_part, n50, n100, neexigibil)`**
|
||||
(`COMUN\programe\oproceduri_comune.prg:6059-6125`) - returneaza `taxcode`-ul SAF-T.
|
||||
|
||||
Apelul concret cu filtrul de cota (`ArticoleNotaEditor.CautaExplicatieTva`,
|
||||
`ofacturare_editare.prg:1142-1147`):
|
||||
|
||||
```
|
||||
PROCEDURE CautaExplicatieTva
|
||||
LOCAL lnCotaFiltru
|
||||
lnCotaFiltru = Round((Nvl(tvd.proc_tvav, 0) - 1) * 100, 2)
|
||||
RETURN caut_explicatie_tva(Nvl(tvd.id_jtva_coloana, -1), , , , m.lnCotaFiltru)
|
||||
ENDPROC
|
||||
```
|
||||
|
||||
Ambele functii sunt `.prg`-uri globale incarcate `ADDITIVE` la pornirea aplicatiei (deci apelabile
|
||||
si din `frm_facturi`) - **nu cer nicio extragere de cod**, doar apel direct.
|
||||
|
||||
---
|
||||
|
||||
## G. `frm_facturi` deja afiseaza explicatia TVA - doar needitabil
|
||||
|
||||
Grila `grid_detalii` din `frm_facturi` are deja doua coloane needitabile pentru asta
|
||||
(`ofacturare_comun.vc2:1679-1687`):
|
||||
|
||||
```
|
||||
Column24.ControlSource = "jtva_coloana", ;
|
||||
Column24.Name = "cExplicatieTVA", ;
|
||||
Column24.ReadOnly = .T., ;
|
||||
...
|
||||
Column25.ControlSource = "jtva_coloana_ex", ;
|
||||
Column25.Name = "cExplicatieTVAEx", ;
|
||||
Column25.ReadOnly = .T., ;
|
||||
```
|
||||
|
||||
cu header-ele "Explicatie TVA" / "Explicatie TVA 2" (`:1920-1946`). `jtva_coloana`/`jtva_coloana_ex`
|
||||
sunt (dupa tiparul din restul fisierului, ex. `:2107-2109`) denumirile derivate din
|
||||
`jtva_coloane`/`jtva_coloane_explicatii`, nu ID-uri brute - afisare, nu editare. Nu exista alt
|
||||
traseu in `frm_facturi` unde utilizatorul alege interactiv o explicatie TVA (nu la adaugare de
|
||||
linie - acest formular nu are adaugare de linii, e formular de listare/editare metadate, nu de
|
||||
compunere a facturii).
|
||||
|
||||
Concluzie G: campul exista deja ca **read-only** in grid; nu trebuie adaugata coloana in grid,
|
||||
doar expunerea editabila in dialogul de modificare (punctul C).
|
||||
|
||||
---
|
||||
|
||||
## H. Riscul - taxcode NU e neutru daca se copiaza tot sablonul
|
||||
|
||||
**Rezultat cheie, marcat apasat:** sablonul din E (runda 5, `frm_modific2024`) **nu e neutru
|
||||
valoric**. La alegerea unei explicatii TVA, pe langa `taxcode`, se rescrie explicit **`proc_tvav`**
|
||||
(cota TVA a liniei) si se cheama **`calculeaza_valori_articol()`**, care recalculeaza valoarea
|
||||
liniei si bara de totaluri (`docs\raport_runda5_omodificari.md`, linia 41 din tabelul de apeluri
|
||||
`ActualizeazaBaraTotaluri`, si citatul de la punctul E de mai sus). Adica in acel context,
|
||||
"explicatie TVA" **schimba** valorile documentului daca explicatia aleasa are alta cota decat cea
|
||||
curenta - filtrul de cota din `caut_explicatie_tva` (punctul F) doar restrange lista, nu blocheaza
|
||||
o alegere cu cota diferita daca userul o cauta explicit sau daca linia are `proc_tvav` gol/0
|
||||
(caz in care filtrul nu se aplica deloc, `ocautare.prg:3218`: `If ... tnCotaTva > 0`).
|
||||
|
||||
Pentru `taxcode` insusi, in fluxul actual: `taxcode` **nu e citit nicaieri in calculul
|
||||
totalurilor VFP** - cautare in `COMUN\programe\ofacturare_comun.prg` si in schema campurilor din
|
||||
`ofacturare_comun.vc2` (punctul D) nu arata `taxcode` folosit in nicio expresie de `valctva`,
|
||||
`valtva`, `total_cu_tva` sau similar; acelea se calculeaza din `proc_tvav`/`pret`/`cantitate`,
|
||||
coloane distincte. `taxcode` e strict o eticheta de raportare SAF-T/e-Factura, stocata pe linie.
|
||||
|
||||
**Deci verdictul depinde strict de ce se implementeaza:**
|
||||
|
||||
- **Daca se reface `pack_facturare.modifica_explicatie_articol` sa scrie DOAR `id_jtva_coloana`
|
||||
(nou parametru) + `taxcode` derivat, FARA sa atinga `proc_tvav`** - si daca dialogul de
|
||||
`frm_facturi` foloseste `caut_explicatie_tva` cu filtrul de cota calculat din
|
||||
`poRec.proc_tvav` curent (ca sa nu se poata alege o explicatie de alta cota) - atunci
|
||||
operatia ramane neutra valoric, exact ce cere utilizatorul. Aceasta e o **varianta redusa**
|
||||
a sablonului din E, nu o copiere 1:1.
|
||||
- **Daca se copiaza sablonul din E exact cum e** (inclusiv rescrierea `proc_tvav` +
|
||||
recalcul) - operatia **NU mai e neutra**: ar schimba cota TVA si valorile unei facturi
|
||||
**deja emise**, fara mecanismul de recalcul de totaluri/note/rulaje care exista in
|
||||
`frm_modific2024` (acolo editarea e pe cursoare locale, salvata printr-un flux dedicat de
|
||||
recalcul; `frm_facturi` nu are asa ceva - e un UPDATE punctual pe o singura linie, deja
|
||||
emisa). Risc fiscal si de coerenta (SAF-T/e-Factura ar raporta un `taxcode` care nu mai
|
||||
corespunde cu `proc_tvav`/totalurile deja emise, sau invers, daca doar taxcode se
|
||||
sincronizeaza fara proc_tvav).
|
||||
|
||||
**Recomandare de proiectare** (schita, fara cod aplicat): varianta redusa de mai sus -
|
||||
dialog `frm_modifica_articol_factura` capata un al treilea camp (combo pe explicatie TVA,
|
||||
`caut_explicatie_tva` filtrat pe cota curenta a liniei, ca in `CautaExplicatieTva`), la alegere
|
||||
se recalculeaza doar `taxcode` local (`GetTaxCodeIdPart`, acelasi apel ca `UpdateExplicatieSAFTArt`
|
||||
dar fara `REPLACE proc_tvav`), iar la salvare `pack_facturare.modifica_explicatie_articol` capata
|
||||
un parametru nou `id_jtva_coloana` (schimbare PL/SQL, in afara acestui repo VFP - de coordonat
|
||||
separat) pe langa `explicatie`/`taxcode` existente. Cod nou estimat: mic pe partea VFP (~30-40
|
||||
linii: un combo nou + un handler de alegere + un parametru in apelul SQL), dar cere **schimbare de
|
||||
pachet Oracle** (`pack_facturare.modifica_explicatie_articol`) care nu exista in acest working
|
||||
copy si trebuie facuta/aprobata separat in `DATABASE`.
|
||||
|
||||
---
|
||||
|
||||
## Rezumat surse
|
||||
|
||||
| ce | fisier:linie |
|
||||
|---|---|
|
||||
| clasa `frm_facturi` | `COMUN\clase\ofacturare_comun.vc2:1168` |
|
||||
| butonul `But_modifica2` | `COMUN\clase\ofacturare_comun.vc2:1436-1444` |
|
||||
| dispatcher `buton.Click` | `COMUN\clase\_cmd_base.vc2:41-71` |
|
||||
| `do_modifica_explicatie` | `COMUN\clase\ofacturare_comun.vc2:4642-4659` |
|
||||
| dialog `frm_modifica_articol_factura` | `COMUN\clase\ofacturare_comun.vc2:5129-5253` |
|
||||
| salvare (`inainte_de_do_termin`) | `COMUN\clase\ofacturare_comun.vc2:5225-5233` |
|
||||
| grid `cExplicatieTVA`/`cExplicatieTVAEx` (read-only) | `COMUN\clase\ofacturare_comun.vc2:1679-1687`, `:1920-1946` |
|
||||
| sablon sincronizare (runda 5) | `COMUN\programe\ofacturare_editare.prg:1100-1147`, `COMUN\clase\omodificari.vc2:15049-15074` |
|
||||
| `caut_explicatie_tva` | `COMUN\programe\ocautare.prg:3174-3238` |
|
||||
| `GetTaxCodeIdPart` | `COMUN\programe\oproceduri_comune.prg:6059-6125` |
|
||||
| `gl406` | `COMUN\programe\oinit_optiuni.prg:524` |
|
||||
| procedura Oracle (citata din cercetare anterioara) | `docs\cercetare\rec_cale_vanzari_detalii.md:195-199` |
|
||||
Reference in New Issue
Block a user