#6 editare factura emisa: runda 6 - nomenclatoare, zecimale, aspect grid, meniu

Pagina Articole din frm_modific2024:
- DblClick pe cele cinci coloane cu nomenclator (articol, gestiune, taxcode,
  valuta, explicatie TVA). Explicatia TVA are ControlSource expresie, deci
  tastarea nu putea declansa niciodata InteractiveChange; DblClick se sprijina
  pe pccontrol si acopera uniform toate cele cinci.
- Pret si Pret cu TVA folosesc gnPPretV (precizie pret vanzare) in loc de
  gnPPret (precizie achizitie). Coloana de pret achizitie ramane pe gnPPret.
- Culori dupa conventia de pe pagina Rulaje: verde pe coloanele care se
  editeaza prin dialog, alb pe cele care se tasteaza direct.
- Serie, lot si explicatie devin editabile in celula. Garda .When ramane si
  blocheaza in continuare liniile din seturi si facturile din e-Factura.

frm_facturi: textul optiunii de editare factura din meniul contextual devine
"Editare factura (note, rulaje, articole)".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013gYCNE26G1G7UoGu2ju7aS
This commit is contained in:
2026-08-20 16:28:02 +03:00
parent 09ddeabb1c
commit b9a14bcb9c
13 changed files with 906 additions and 258 deletions

View File

@@ -11,7 +11,9 @@
*!* pentru adaugarea unei linii noi prin dialogul frm_articol_factura (populat cu valuta documentului
*!* cand acesta e in valuta), scrierea in VANZARI_DETALII a liniilor editate/adaugate/sterse, si
*!* compararea/aplicarea sincronizarii cantitate/pret intre rulaje (trul) si articolele facturii (tvd),
*!* agregate pe id_articol, in ambele sensuri (documentele in valuta raman doar semnalate, neaplicate)
*!* agregate pe id_articol, in ambele sensuri (documentele in valuta raman doar semnalate, neaplicate);
*!* pe linia de articol se poate alege si explicatia TVA (filtrata pe cota liniei), care recoreleaza
*!* codul SAF-T, iar liniile deja salvate se actualizeaza cu toate campurile pe care grila le schimba
*!* parametru: id_fact
@@ -498,8 +500,22 @@ FUNCTION ScrieArticoleFacturaEditate
SELECT (m.lcAliasArt)
lnRecnoArt = Recno()
SCAN FOR id_vanzare_det > 0 AND Nvl(sters,0) <> 1
*!* toate campurile pe care grila si nomenclatoarele le pot schimba - altfel alegerile de pe
*!* liniile deja salvate (cod TVA, explicatie TVA, gestiune, valuta, articol) s-ar pierde tacut
lcSql = [update vanzari_detalii set sters = 0, cantitate = ] + Alltrim(Str(Nvl(cantitate,0),18,3)) + ;
[, pret = ] + Alltrim(Str(Nvl(pret,0),18,4)) + [, pret_cu_tva = ] + Alltrim(Str(Nvl(pret_cu_tva,0))) + ;
[, pret_achizitie = ] + Iif(Isnull(pret_achizitie),[NULL],Alltrim(Str(pret_achizitie,18,4))) + ;
[, proc_tvav = ] + Iif(Isnull(proc_tvav),[NULL],Alltrim(Str(proc_tvav,18,4))) + ;
[, discount_unitar = ] + Iif(Isnull(discount_unitar),[NULL],Alltrim(Str(discount_unitar,18,4))) + ;
[, id_articol = ] + Iif(Isnull(id_articol),[NULL],Alltrim(Str(id_articol))) + ;
[, id_gestiune = ] + Iif(Isnull(id_gestiune),[NULL],Alltrim(Str(id_gestiune))) + ;
[, id_valuta = ] + Iif(Isnull(id_valuta),[NULL],Alltrim(Str(id_valuta))) + ;
[, id_jtva_coloana = ] + Iif(Isnull(id_jtva_coloana),[NULL],Alltrim(Str(id_jtva_coloana))) + ;
[, taxcode = ] + Iif(Isnull(taxcode),[NULL],Alltrim(Str(taxcode))) + ;
[, cont = ] + Iif(Empty(Nvl(cont,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(cont,''))) + [']) + ;
[, serie = ] + Iif(Empty(Nvl(serie,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(serie,''))) + [']) + ;
[, explicatie = ] + Iif(Empty(Nvl(explicatie,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(explicatie,''))) + [']) + ;
[, lot = ] + Iif(Empty(Nvl(lot,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(lot,''))) + [']) + ;
[, id_utils = ] + Alltrim(Str(gnIdUtil)) + [, dataoras = sysdate ] + ;
[where id_vanzare_det = ] + Alltrim(Str(id_vanzare_det)) + [ and id_vanzare = ] + Alltrim(Str(m.tnIdVanzare))
llSucces = goExecutor.oExecuta(m.lcSql)
@@ -521,16 +537,16 @@ FUNCTION ScrieArticoleFacturaEditate
SCAN FOR id_vanzare_det = 0 AND Nvl(sters,0) <> 1
lcSql = [insert into vanzari_detalii (id_vanzare, id_articol, cantitate, pret, pret_cu_tva, proc_tvav, discount_unitar, ] + ;
[id_gestiune, cont, id_valuta, id_jtva_coloana, serie, explicatie, taxcode, lot, pret_achizitie, id_utils, dataoras) values (] + ;
Alltrim(Str(m.tnIdVanzare)) + [,] + Alltrim(Str(Nvl(id_articol,0))) + [,] + Alltrim(Str(Nvl(cantitate,0),18,3)) + [,] + ;
Alltrim(Str(Nvl(pret,0),18,4)) + [,] + Alltrim(Str(Nvl(pret_cu_tva,0))) + [,] + Alltrim(Str(Nvl(proc_tvav,0),18,4)) + [,] + ;
Alltrim(Str(Nvl(discount_unitar,0),18,4)) + [,] + Iif(Isnull(id_gestiune),[NULL],Alltrim(Str(id_gestiune))) + [,] + ;
Alltrim(Str(m.tnIdVanzare)) + [,] + Iif(Isnull(id_articol),[NULL],Alltrim(Str(id_articol))) + [,] + Alltrim(Str(Nvl(cantitate,0),18,3)) + [,] + ;
Alltrim(Str(Nvl(pret,0),18,4)) + [,] + Alltrim(Str(Nvl(pret_cu_tva,0))) + [,] + Iif(Isnull(proc_tvav),[NULL],Alltrim(Str(proc_tvav,18,4))) + [,] + ;
Iif(Isnull(discount_unitar),[NULL],Alltrim(Str(discount_unitar,18,4))) + [,] + Iif(Isnull(id_gestiune),[NULL],Alltrim(Str(id_gestiune))) + [,] + ;
Iif(Empty(Nvl(cont,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(cont,''))) + [']) + [,] + ;
Iif(Isnull(id_valuta),[NULL],Alltrim(Str(id_valuta))) + [,] + Iif(Isnull(id_jtva_coloana),[NULL],Alltrim(Str(id_jtva_coloana))) + [,] + ;
Iif(Empty(Nvl(serie,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(serie,''))) + [']) + [,] + ;
Iif(Empty(Nvl(explicatie,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(explicatie,''))) + [']) + [,] + ;
Iif(Isnull(taxcode),[NULL],Alltrim(Str(taxcode))) + [,] + ;
Iif(Empty(Nvl(lot,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(lot,''))) + [']) + [,] + ;
Alltrim(Str(Nvl(pret_achizitie,0),18,4)) + [,] + Alltrim(Str(gnIdUtil)) + [, sysdate)]
Iif(Isnull(pret_achizitie),[NULL],Alltrim(Str(pret_achizitie,18,4))) + [,] + Alltrim(Str(gnIdUtil)) + [, sysdate)]
llSucces = goExecutor.oExecuta(m.lcSql)
IF !m.llSucces
EXIT
@@ -601,10 +617,11 @@ FUNCTION ConstruiestePropunereSincronizare
IF Used('agg_rul')
Use In agg_rul
ENDIF
CREATE CURSOR agg_rul (id_articol N(20), denumire C(100), codmat C(30), cant N(12,3), val N(16,4), nrand I)
CREATE CURSOR agg_rul (id_articol N(20) NULL, denumire C(100), codmat C(30), cant N(12,3), val N(16,4), nrand I)
SELECT trul
SCAN FOR Nvl(sters,0) <> 1
*!* cheia comparatiei e id_articol - o linie fara articol n-are cum sa aiba corespondent
SCAN FOR Nvl(sters,0) <> 1 AND !Isnull(id_articol)
lnCantLinie = Nvl(cant,0) + IIF(Nvl(id_tip_rulaj,0) <> 3, Nvl(cante,0), 0)
lnValLinie = Nvl(cant,0) * Nvl(pretvtva,0) + IIF(Nvl(id_tip_rulaj,0) <> 3, Nvl(cante,0) * Nvl(pretvtva,0), 0)
lcDenumireRul = Nvl(trul.denumire,'')
@@ -624,10 +641,11 @@ FUNCTION ConstruiestePropunereSincronizare
IF Used('agg_tvd')
Use In agg_tvd
ENDIF
CREATE CURSOR agg_tvd (id_articol N(20), denumire C(100), codmat C(30), cant N(12,3), val N(16,4), nrand I, in_stoc I)
CREATE CURSOR agg_tvd (id_articol N(20) NULL, denumire C(100), codmat C(30), cant N(12,3), val N(16,4), nrand I, in_stoc I)
SELECT tvd
SCAN FOR Nvl(sters,0) <> 1
*!* liniile de rata dintr-un contract n-au id_articol - se exclud, la fel ca in bucla de mai sus
SCAN FOR Nvl(sters,0) <> 1 AND !Isnull(id_articol)
lcDenumireTvd = Nvl(tvd.denumire,'')
lcCodmatTvd = Nvl(tvd.codmat,'')
SELECT agg_tvd
@@ -920,3 +938,228 @@ FUNCTION AplicaModificareTrul
ENDIF
RETURN m.llAplicat
ENDFUNC && AplicaModificareTrul
*!* editorul liniilor de articole ale notei: primeste in Init formularul frm_modific2024 si
*!* actioneaza asupra cursorului lui tvd - adaugarea unei linii prin nomenclator si dialogul
*!* frm_articol_factura, stergerea logica, duplicarea liniei si nomenclatoarele de pe coloanele
*!* articol / gestiune / valuta / cod TVA
DEFINE CLASS ArticoleNotaEditor AS Custom
oForm = .Null.
PROCEDURE Init
LPARAMETERS toForm
IF Vartype(m.toForm) <> 'O'
RETURN .F.
ENDIF
This.oForm = m.toForm
ENDPROC
*!* .T. cat timp liniile accepta modificari: documentul are articole si nu e trimis in eFactura
PROCEDURE Editabil
RETURN Used('tvd') AND This.oForm.lAreArticoleVanzari AND !This.oForm.lArticoleReadOnly
ENDPROC
*!* numele campului dintr-un ControlSource de forma alias.camp
PROCEDURE NumeCamp
LPARAMETERS tcControl
LOCAL lcCamp
lcCamp = Lower(Alltrim(Nvl(m.tcControl, '')))
IF '.' $ m.lcCamp
lcCamp = Right(m.lcCamp, Len(m.lcCamp) - At('.', m.lcCamp))
ENDIF
RETURN m.lcCamp
ENDPROC
*!* .T. daca pe coloana data se poate deschide un nomenclator
PROCEDURE AreNomenclator
LPARAMETERS tcControl
RETURN Inlist(This.NumeCamp(m.tcControl), 'denumire', 'nume_gestiune', 'nume_val', 'taxcode', 'id_jtva_coloana')
ENDPROC
*!* alege un articol din nomenclator (fara stoc, fara politica de preturi) si il adauga in tvd ca
*!* linie noua (id_vanzare_det = 0), prin dialogul frm_articol_factura; pe document in valuta
*!* dialogul primeste cursul si valuta documentului, deci pretul se introduce direct in valuta
PROCEDURE AdaugaLinie
LOCAL loArticolAles, lnIdArticol, llInValutaDoc, lnCursDoc, lnMultDoc, lcNumeValDoc, lnIdValutaDoc
LOCAL loDlg, llAdaugat
llAdaugat = .F.
IF !This.Editabil()
RETURN .F.
ENDIF
loArticolAles = caut_articol()
lnIdArticol = Nvl(loArticolAles.id_articol, 0)
IF Empty(m.lnIdArticol)
RETURN .F.
ENDIF
llInValutaDoc = Iif(Used('tvanz') And Reccount('tvanz') > 0, Nvl(tvanz.in_valuta, 0) = 1, .F.)
lnCursDoc = Iif(Used('tvanz') And Reccount('tvanz') > 0, Nvl(tvanz.curs, 1), 1)
lnMultDoc = Iif(Used('tvanz') And Reccount('tvanz') > 0, Nvl(tvanz.multiplicator, 1), 1)
lcNumeValDoc = Iif(Used('tvanz') And Reccount('tvanz') > 0, Nvl(tvanz.nume_val, ''), '')
lnIdValutaDoc = Iif(Used('tvanz') And Reccount('tvanz') > 0, tvanz.id_valuta, .Null.)
PRIVATE poArticol, poDate, gnScadereStoc
poArticol = CreeazaPoArticolNouTvd(m.lnIdArticol, loArticolAles.codmat, loArticolAles.denumire, loArticolAles.um, loArticolAles.cont, ;
m.llInValutaDoc, m.lnCursDoc, m.lnMultDoc, m.lcNumeValDoc, m.lnIdValutaDoc)
poDate = Createobject('Empty')
AddProperty(poDate, 'tip', This.oForm.nTipVanzare)
AddProperty(poDate, 'in_valuta', 0)
AddProperty(poDate, 'dataact', Iif(Used('tact') And Reccount('tact') > 0, Nvl(tact.dataact, Date()), Date()))
gnScadereStoc = 0
gnButon = 2
loDlg = Createobject('frm_articol_factura', 1, .F.)
loDlg.Show(1)
IF m.gnButon = 1
This.oForm.AdaugaLinieTvdDinArticol(poArticol)
This.RefreshGrid()
llAdaugat = .T.
ENDIF
Release loDlg
RETURN m.llAdaugat
ENDPROC
*!* comuta flagul sters pe linia curenta - stergerea e logica, linia ramane vizibila (grizata)
*!* pana la salvare
PROCEDURE ComutaSters
IF !This.Editabil() OR Reccount('tvd') = 0
RETURN .F.
ENDIF
SELECT tvd
REPLACE sters WITH Iif(Nvl(sters, 0) = 1, 0, 1), lmodificat WITH .T.
This.RefreshGrid()
This.oForm.ActualizeazaBaraTotaluri()
RETURN .T.
ENDPROC
*!* duplica linia curenta ca linie noua nesalvata, desprinsa de setul din care provenea, ca sa
*!* poata fi editata ca orice linie adaugata manual
PROCEDURE DuplicaLinie
LOCAL loLinie
IF !This.Editabil() OR Reccount('tvd') = 0
RETURN .F.
ENDIF
SELECT tvd
SCATTER NAME loLinie MEMO
loLinie.id_vanzare_det = 0
loLinie.id_vanzare_set = 0
loLinie.sters = 0
loLinie.lmodificat = .T.
APPEND BLANK
GATHER NAME loLinie MEMO
This.oForm.calculeaza_valori_articol()
This.RefreshGrid()
RETURN .T.
ENDPROC
*!* deschide nomenclatorul coloanei primite si scrie alegerea in linia curenta din tvd; liniile
*!* venite dintr-un set raman neatinse, la fel ca la editarea inline din grid
PROCEDURE ModificaNomenclator
LPARAMETERS tcControl
LOCAL lcCamp, loCauta, lcSqlValuta, lnSuccesValuta, llValutaOk
lcCamp = This.NumeCamp(m.tcControl)
IF !This.Editabil() OR Reccount('tvd') = 0 OR !This.AreNomenclator(m.lcCamp) OR Nvl(tvd.id_vanzare_set, 0) <> 0
RETURN .F.
ENDIF
DO CASE
CASE m.lcCamp == 'denumire'
loCauta = caut_articol()
CASE m.lcCamp == 'nume_gestiune'
loCauta = caut_gestiune()
CASE m.lcCamp == 'nume_val'
loCauta = caut_valuta()
CASE m.lcCamp == 'id_jtva_coloana'
loCauta = This.CautaExplicatieTva()
OTHERWISE
loCauta = This.CautaCodTva()
ENDCASE
IF gnButon <> 1
RETURN .F.
ENDIF
SELECT tvd
DO CASE
CASE m.lcCamp == 'denumire'
REPLACE denumire WITH loCauta.denumire, codmat WITH loCauta.codmat, ;
id_articol WITH loCauta.id_articol, cont WITH Nvl(loCauta.cont, '')
CASE m.lcCamp == 'nume_gestiune'
REPLACE nume_gestiune WITH loCauta.nume_gestiune, id_gestiune WITH loCauta.id_gestiune
CASE m.lcCamp == 'nume_val'
*!* valuta orfana (fara curs pe document) ar goli totalurile la recalculare - se accepta doar moneda nationala sau o valuta deja folosita pe document
IF Used('tvanz') AND Reccount('tvanz') = 1
lcSqlValuta = [select 1 as ok from dual where ] + Alltrim(Str(loCauta.id_valuta)) + [ = pack_def.GetIdMonedaNationala()] + ;
[ or exists (select 1 from vanzari_cursuri where id_vanzare = ] + Alltrim(Str(tvanz.id_vanzare)) + ;
[ and id_valuta = ] + Alltrim(Str(loCauta.id_valuta)) + [)]
lnSuccesValuta = goExecutor.oExecute(m.lcSqlValuta,[crsvalok])
goExecutor.oReset()
IF m.lnSuccesValuta < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
RETURN .F.
ENDIF
llValutaOk = Used('crsvalok') AND Reccount('crsvalok') > 0
IF Used('crsvalok')
Use In crsvalok
ENDIF
IF !m.llValutaOk
AMESSAGEBOX([Valuta aleasa nu are curs inregistrat pe acest document. Se poate alege doar o valuta deja folosita pe document sau moneda nationala.],0+48,"Atentie")
RETURN .F.
ENDIF
ENDIF
REPLACE nume_val WITH loCauta.nume_val, id_valuta WITH loCauta.id_valuta
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()
OTHERWISE
REPLACE taxcode WITH loCauta.taxcode
ENDCASE
REPLACE lmodificat WITH .T.
This.RefreshGrid()
RETURN .T.
ENDPROC
*!* explicatiile TVA, filtrate pe cota liniei curente (proc_tvav e in forma 1.21; cota 0/goala =
*!* fara filtru) - acelasi nomenclator ca pe randul de nota
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
*!* nomenclatorul de coduri TVA SAF-T, acelasi vsaft_taxtable de pe randurile notei
*!* taxname vine din view cu latimea declarata > 254 (SUBSTR nu o micsoreaza) si driverul l-ar
*!* aduce ca Memo; CAST-ul o fixeaza, iar tabela derivata pastreaza aliasul utilizabil in WHERE
PROCEDURE CautaCodTva
LOCAL lcSelect
lcSelect = [select * from (select cast(substr(taxname,1,200) as varchar2(200)) as taxname, ] + ;
[procent_taxa, taxcode from vsaft_taxtable)]
RETURN cauta_alfa(m.lcSelect, [1=2], [], [taxname], [taxname,procent_taxa], ;
[Alegeti codul de TVA], [Denumire,Procent], [], .F., [1=1], [taxname], 1, 0, [taxcode])
ENDPROC
PROCEDURE RefreshGrid
This.oForm.pgfArticole.PAGE3.grdArticoleFactura.Refresh()
ENDPROC
ENDDEFINE && ArticoleNotaEditor

View File

@@ -27,6 +27,10 @@
*!* 03.05.2022
*!* oscrie_vanzare_din_stoc - completeaza pack_facturare.adauga_articol_factura_stoc(taxcode)
*!* 18.08.2026
*!* marius.mutu
*!* oscrie_vanzare_din_stoc - pretul de achizitie si pretul in valuta se trimit cu cel putin 4 zecimale, cate pastreaza stocul
**************************************** INCEPUT: initializeaza_vanzare_din_stoc ******************************
Procedure initializeaza_vanzare_din_stoc
Lparameters tnIdSet, toActAnterior
@@ -357,8 +361,8 @@ Else
lcSql = [begin ] + gcS + [.pack_facturare.adauga_articol_factura_stoc(] + ;
Alltrim(Str(poArticol.id_articol)) + [,] + ;
['] + Strtran(Alltrim(Nvl(poArticol.serie,[])),['],['']) + [',] + ;
Alltrim(Str(poArticol.pret_achizitie,18,gnPPret)) + [,] + ;
Alltrim(Str(poArticol.pretd,18,gnPPretVal)) + [,] + ;
Alltrim(Str(poArticol.pret_achizitie,18,Max(gnPPret,4))) + [,] + ;
Alltrim(Str(poArticol.pretd,18,Max(gnPPretVal,4))) + [,] + ;
Alltrim(Str(poArticol.id_valuta_d)) + [,] + ;
Alltrim(Str(poArticol.Pret,18,Iif(poDate.in_valuta = 1,gnPVal,gnPPretV))) + [,] + ;
Iif(poDate.in_valuta=1,Alltrim(Str(poArticol.id_valuta)),[NULL]) + [,] + ;