Files
roafacturare/docs/cercetare/rec_r6_buton_modificare_frm_facturi.md
Marius Mutu ca3c5d7eea 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
2026-08-20 16:35:03 +03:00

15 KiB

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):

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