Files
comun/programe/ofacturare_editare.prg
Marius Mutu b9eba29ebe #6 editare factura emisa: S4 runda 3 completa (pagina de articole editabila)
frm_modific2024, pgfArticole.PAGE3 - editare in memorie, fara scriere in Oracle
(aceea ramane S5).

- sub-blocul A: cantitate/pret/pret_cu_tva editabile inline, marcaj lmodificat
  pe linie, coloana valoare pe linie
- sub-blocul B: stergere logica de linii (sters/DynamicForeColor gri) si adaugare
  de linii prin frm_articol_factura, cu alegerea articolului prin caut_articol()
- sub-blocul C: bara de totaluri sub grid (total linii convertit RON la cursul
  documentului, discount de antet editabil, total net), ascunsa pe
  transfer/custodie; verdict de corelatie ACT/RUL informativ, cu 3 stari
- suma ACT: sold net debit-credit, cont pe tip de document (4111 / 418 / 461,
  iar pe rate/contract 4111, 411 sau 461)
- suma RUL: doar ID_TIP_RULAJ = 0, adica miscarile reale; perechile
  ID_TIP_RULAJ = 3 sunt virtuale (tin locul procesului verbal de schimbare de
  pret) si nu intra in suma. Corectie cu liniile nestocate, marcata "ajustat"
- adaugarea de linii pe document in valuta: dialogul primeste tip_valuta si
  cursul documentului de pe tvanz, deci pretul se introduce direct in valuta;
  ofacturare.vc2 ramane neatins
- cei 5 apelanti frm_modific2024 (afisjurcom, anaf_efactura, cele doua .sc2 de
  import) pregatesc cursorul de articole inainte de Createobject, gardat pe
  SET PROCEDURE - registrul jurnal din ROACONT/ROAGEST ramane neschimbat

Teste headless pe MARIUSM_AUTO, suite care isi descopera singure documentele:
test_page3_articole 14/2 (cele 2 = artefact de grid nematerializat headless,
acoperit pe ecran), test_incarca_vanzare_din_nota 5/0,
test_adauga_linie_articol 20/0, test_adauga_linie_valuta 16/0,
test_ui_sterge_linie 8/0, test_verdict_act_rul 26/0.

docs/todos.txt: punctele 13 si 20, scrise de Marius.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-09 20:48:42 +03:00

458 lines
16 KiB
Plaintext

*** ofacturare_editare
*!* 09.08.2026
*!* marius.mutu
*!* helpere comune pentru editarea unei facturi emise: garda eFactura, cursoarele notei si ale rulajelor,
*!* randul de vanzare corespunzator notei (inclusiv valuta documentului: in_valuta/id_valuta/nume_val),
*!* liniile de articole pentru pagina de articole factura (inclusiv in_stoc, pentru corectia verdictului
*!* RUL pe liniile nestocate), pregatirea cursorului de articole inainte de Createobject(frm_modific2024)
*!* si construirea obiectului poArticol pentru adaugarea unei linii noi prin dialogul frm_articol_factura,
*!* populat cu valuta documentului cand acesta e in valuta
*!* parametru: id_fact
*!* verifica daca factura cu id_fact dat a fost deja trimisa in eFactura (anaf_efactura)
FUNCTION EsteInEFactura
LPARAMETERS tnIdFact
LOCAL lcSql, lnEFactura, llSucces
lnEFactura = 0
lcSql = [select count(*) as lneFactura from anaf_efactura where id_fact = ] + Alltrim(Str(Nvl(m.tnIdFact,0)))
llSucces = goExecutor.oSelecteaza2Value(m.lcSql, @lnEFactura)
RETURN (Nvl(m.lnEFactura,0) > 0)
ENDFUNC && EsteInEFactura
*!* parametri: cod, an, luna, arata si randurile sterse (implicit .F.)
*!* incarca cursoarele notei (tact) si ale rulajelor (trul, trul_obinv), cu recalculul de
*!* valoare/valtva/valoarev/valtvav pe randurile goale; raman deschise READWRITE pe seama apelantului
*!* pe eroare Oracle intoarce .F. si inchide ce a deschis pana atunci
FUNCTION IncarcaCursoareModificareNota
LPARAMETERS tnCod, tnAn, tnLuna, tlAratasterse
LOCAL lcConditieSters, lcSql, lcCursor, lnSucces
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
IF Used('rul_temp')
Use In rul_temp
ENDIF
IF Used('trul')
Use In trul
ENDIF
IF Used('rul_temp_obinv')
Use In rul_temp_obinv
ENDIF
IF Used('trul_obinv')
Use In trul_obinv
ENDIF
lcConditieSters = IIF(m.tlAratasterse, [ ], [ STERS = 0 AND ])
lcSql = [select * from vact_tot where ] + lcConditieSters + [ an = ] + Transform(m.tnAn) + [ and luna = ] + Transform(m.tnLuna) + [ and cod = ] + Alltrim(Str(m.tnCod)) + [ order by id_act]
lcCursor = [v_act]
lnSucces = goExecutor.oExecute(lcSql,lcCursor)
goExecutor.oReset()
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
RETURN .F.
ENDIF
SELECT * FROM v_act INTO CURSOR actactan
SELECT .F. AS ales, T.*, CAST(0 AS N(2)) AS tipnota FROM actactan T INTO CURSOR tact READWRITE
USE IN v_act
IF lnSucces > 0
lcSql = [select * from vrul_tot where ] + lcConditieSters + [ an = ] + Transform(m.tnAn) + [ and luna = ] + Transform(m.tnLuna) + [ and cod = ] + Alltrim(Str(m.tnCod)) + [ order by id_rul]
lcCursor = [v_rul]
lnSucces = goExecutor.oExecute(lcSql,lcCursor)
goExecutor.oReset()
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
RETURN .F.
ENDIF
IF lnSucces > 0
UPDATE v_rul SET valoare = ROUND(IIF(cant<>0, cant, cante)*pret,m.gnPC) WHERE EMPTY(NVL(valoare,0))
UPDATE v_rul SET valtva = ROUND(IIF(cant<>0, cant, cante)*pret * (IIF(!EMPTY(NVL(proc_tva,0)), proc_tva, 1)-1), m.gnPC) WHERE EMPTY(NVL(valtva,0))
UPDATE v_rul SET valoarev = ROUND(IIF(cant<>0, cant, cante)*pretv,m.gnPC) WHERE EMPTY(NVL(valoarev,0))
UPDATE v_rul SET valtvav = ROUND(IIF(cant<>0, cant, cante)*pretv * (IIF(!EMPTY(NVL(proc_tvav,0)), proc_tvav, 1)-1), m.gnPC) WHERE EMPTY(NVL(valtvav,0))
SELECT *, ;
valoare + valtva AS valoarectva, ;
valoarev + valtvav AS valoarevctva ;
FROM v_rul ;
INTO CURSOR RUL_TEMP READWRITE
SELECT * FROM RUL_TEMP INTO CURSOR trul READWRITE
USE IN v_rul
lcSql = [select * from vrul_obinv_tot where ] + lcConditieSters + [ an = ] + Transform(m.tnAn) + [ and luna = ] + Transform(m.tnLuna) + [ and cod = ] + Alltrim(Str(m.tnCod)) + [ order by id_rul_obinv]
lcCursor = [v_rul_obinv]
lnSucces = goExecutor.oExecute(lcSql,lcCursor)
goExecutor.oReset()
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
IF Used('actactan')
Use In actactan
ENDIF
IF Used('tact')
Use In tact
ENDIF
IF Used('rul_temp')
Use In rul_temp
ENDIF
IF Used('trul')
Use In trul
ENDIF
RETURN .F.
ENDIF
ENDIF
IF lnSucces > 0
UPDATE v_rul_obinv SET valoare = ROUND(IIF(cant<>0, cant, cante)*pret,m.gnPC) WHERE EMPTY(NVL(valoare,0))
UPDATE v_rul_obinv SET valtva = ROUND(IIF(cant<>0, cant, cante)*pret * (IIF(!EMPTY(NVL(proc_tva,0)), proc_tva, 1)-1), m.gnPC) WHERE EMPTY(NVL(valtva,0))
UPDATE v_rul_obinv SET valoarev = ROUND(IIF(cant<>0, cant, cante)*pretv,m.gnPC) WHERE EMPTY(NVL(valoarev,0))
UPDATE v_rul_obinv SET valtvav = ROUND(IIF(cant<>0, cant, cante)*pretv * (IIF(!EMPTY(NVL(proc_tvav,0)), proc_tvav, 1)-1), m.gnPC) WHERE EMPTY(NVL(valtvav,0))
SELECT *, ;
valoare + valtva AS valoarectva, ;
valoarev + valtvav AS valoarevctva ;
FROM v_rul_obinv ;
INTO CURSOR RUL_TEMP_OBINV READWRITE
SELECT * FROM RUL_TEMP_OBINV INTO CURSOR trul_obinv READWRITE
USE IN v_rul_obinv
ENDIF
ENDIF
RETURN .T.
ENDFUNC && IncarcaCursoareModificareNota
*!* creeaza cursorul tvanz gol (structura VANZARI redusa) - fallback la eroare Oracle sau cod/data lipsa
FUNCTION CreeazaCursorTvanzGol
IF Used('tvanz')
Use In tvanz
ENDIF
CREATE CURSOR tvanz (id_vanzare I, tip I, discount N(12,2), total_fara_tva N(14,2), total_tva N(14,2), total_cu_tva N(14,2), curs N(10,4), multiplicator N(10,4), ;
in_valuta I NULL, id_valuta I NULL, nume_val C(20) NULL)
ENDFUNC && CreeazaCursorTvanzGol
*!* parametri: cod, nract, serie_act, dataact (din cursorul notei, ex. tact)
*!* incarca in tvanz randul din VANZARI al notei; cod singur nu e unic, de aceea filtrul cere tot setul
*!* tvanz ramane deschis READWRITE, cu 0 randuri daca nu s-a gasit sau la eroare Oracle
FUNCTION IncarcaVanzareNota
LPARAMETERS tnCod, tnNract, tcSerieAct, tdDataAct
LOCAL lcSql, lnSucces, lcSerieAct
IF Used('v_vanz')
Use In v_vanz
ENDIF
IF Empty(m.tnCod) OR Empty(m.tdDataAct)
CreeazaCursorTvanzGol()
RETURN .T.
ENDIF
lcSerieAct = Alltrim(Nvl(m.tcSerieAct,""))
lcSql = [select v.id_vanzare, v.tip, v.discount, v.total_fara_tva, v.total_tva, v.total_cu_tva, v.curs, v.multiplicator, ] + ;
[v.in_valuta, v.id_valuta, nv.nume_val from vanzari v left join nom_valute nv on nv.id_valuta = v.id_valuta where v.cod = ] + Transform(m.tnCod) + ;
[ and Nvl(v.numar_act,-1) = ] + Transform(Nvl(m.tnNract,-1)) + ;
[ and Nvl(v.serie_act,'') = '] + m.lcSerieAct + [' and trunc(v.data_act) = to_date('] + Dtoc(m.tdDataAct,1) + [','YYYYMMDD') and v.sters = 0]
lnSucces = goExecutor.oExecute(lcSql,[v_vanz])
goExecutor.oReset()
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
CreeazaCursorTvanzGol()
RETURN .T.
ENDIF
IF Used('tvanz')
Use In tvanz
ENDIF
SELECT * FROM v_vanz INTO CURSOR tvanz READWRITE
USE IN v_vanz
RETURN .T.
ENDFUNC && IncarcaVanzareNota
*!* parametru: alias cu randurile notei (tact), cu campurile cod/nract/serie_act/dataact/sters
*!* incearca toate combinatiile distincte (cod, nract, serie_act, dataact) din alias (sters=0) pana
*!* gaseste un rand in VANZARI; lasa workarea si pozitia curenta neschimbate, .F. cu tvanz gol daca nu gaseste
FUNCTION IncarcaVanzareDinNota
LPARAMETERS tcAliasAct
LOCAL lnAreaOrigine, lnRecnoOrigine, llGasit
lnAreaOrigine = Select()
llGasit = .F.
IF Empty(m.tcAliasAct) OR !Used(m.tcAliasAct) OR Reccount(m.tcAliasAct) = 0
CreeazaCursorTvanzGol()
IF m.lnAreaOrigine > 0
SELECT (m.lnAreaOrigine)
ENDIF
RETURN .F.
ENDIF
lnRecnoOrigine = Recno(m.tcAliasAct)
IF Used('tmp_triplete_pozvanz')
Use In tmp_triplete_pozvanz
ENDIF
*!* cod se ia tot din cursor, nu de pe randul curent - acesta poate fi la EOF dupa CalculeazaTotal
SELECT DISTINCT cod, nract, serie_act, dataact FROM (m.tcAliasAct) WHERE sters = 0 INTO CURSOR tmp_triplete_pozvanz READWRITE
SELECT tmp_triplete_pozvanz
SCAN
IncarcaVanzareNota(cod, nract, serie_act, dataact)
IF Reccount('tvanz') = 1
llGasit = .T.
EXIT
ENDIF
ENDSCAN
IF Used('tmp_triplete_pozvanz')
Use In tmp_triplete_pozvanz
ENDIF
IF !m.llGasit
CreeazaCursorTvanzGol()
ENDIF
IF Used(m.tcAliasAct)
IF m.lnRecnoOrigine > 0 AND m.lnRecnoOrigine <= Reccount(m.tcAliasAct)
Go (m.lnRecnoOrigine) In (m.tcAliasAct)
ELSE
*!* pozitia initiala era EOF (Recno() peste Reccount()) - se restaureaza tot la EOF
Go Bottom In (m.tcAliasAct)
Skip In (m.tcAliasAct)
ENDIF
ENDIF
IF m.lnAreaOrigine > 0
SELECT (m.lnAreaOrigine)
ENDIF
RETURN m.llGasit
ENDFUNC && IncarcaVanzareDinNota
*!* parametru: alias destinatie (implicit tvd)
*!* creeaza gol, sub acel alias, un cursor cu structura view-ului VVANZARI_ARTICOLE
FUNCTION CreeazaCursorArticoleGol
LPARAMETERS tcAlias
LOCAL lcAlias
lcAlias = IIF(Type('tcAlias') = 'C' AND !Empty(m.tcAlias), m.tcAlias, 'tvd')
IF Used(m.lcAlias)
Use In (m.lcAlias)
ENDIF
CREATE CURSOR (m.lcAlias) (id_vanzare I NULL, id_vanzare_det I NULL, id_articol I NULL, cantitate N(12,3) NULL, pret N(14,4) NULL, pret_cu_tva N(14,4) NULL, proc_tvav N(6,4) NULL, ;
discount_unitar N(14,4) NULL, id_gestiune I NULL, cont C(20) NULL, id_valuta I NULL, id_jtva_coloana I NULL, serie C(20) NULL, explicatie C(60) NULL, ;
taxcode I NULL, lot C(20) NULL, sters I NULL, denumire C(100) NULL, codmat C(30) NULL, nume_gestiune C(60) NULL, nume_val C(20) NULL, ;
lmodificat L, valoare N(14,2), in_stoc I NULL)
ENDFUNC && CreeazaCursorArticoleGol
*!* creeaza cursorul tvd gol, cu structura view-ului VVANZARI_ARTICOLE
FUNCTION CreeazaCursorTvdGol
CreeazaCursorArticoleGol('tvd')
ENDFUNC && CreeazaCursorTvdGol
*!* parametri: id_vanzare, alias destinatie (implicit tvd)
*!* incarca in alias liniile active (sters=0) ale vanzarii, din VVANZARI_ARTICOLE
*!* aliasul ramane deschis READWRITE, cu 0 randuri la eroare Oracle
FUNCTION IncarcaArticoleFactura
LPARAMETERS tnIdVanzare, tcAliasDestinatie
LOCAL lcSql, lnSucces, lcAlias
lcAlias = IIF(Type('tcAliasDestinatie') = 'C' AND !Empty(m.tcAliasDestinatie), m.tcAliasDestinatie, 'tvd')
IF Used('v_vd')
Use In v_vd
ENDIF
*!* in_stoc vine din NOM_ARTICOLE (viewul nu-l expune) - corectia verdictului RUL pe liniile nestocate
lcSql = [select v.*, na.in_stoc from vvanzari_articole v left join nom_articole na on na.id_articol = v.id_articol ] + ;
[where v.id_vanzare = ] + Transform(Nvl(m.tnIdVanzare,0)) + [ and v.sters = 0 order by v.id_vanzare_det]
lnSucces = goExecutor.oExecute(lcSql,[v_vd])
goExecutor.oReset()
IF lnSucces < 0
AMESSAGEBOX(goExecutor.cEroare,0+16,"Eroare")
CreeazaCursorArticoleGol(m.lcAlias)
RETURN .T.
ENDIF
IF Used(m.lcAlias)
Use In (m.lcAlias)
ENDIF
*!* valoarea cu TVA pe linie, cu discountul unitar scazut: pret_cu_tva e flag (0/1), nu pret -
*!* formula difera dupa el, ca la calculeaza_valori_articol
SELECT *, .F. AS lmodificat, ;
ROUND(NVL(cantitate,0) * IIF(NVL(pret_cu_tva,0) = 0, (NVL(pret,0) - NVL(discount_unitar,0)) * NVL(proc_tvav,1), ;
NVL(pret,0) - NVL(discount_unitar,0)), gnPC) AS valoare ;
FROM v_vd INTO CURSOR (m.lcAlias) READWRITE
USE IN v_vd
RETURN .T.
ENDFUNC && IncarcaArticoleFactura
*!* parametru: alias cu randurile notei (tact)
*!* descopera randul din VANZARI corespunzator notei (IncarcaVanzareDinNota) si, daca il gaseste,
*!* pre-incarca liniile in crsArticoleFactura - apelat inainte de Createobject([frm_modific2024]),
*!* ca Load() sa lege grid-ul o singura data pe cursorul deja plin; daca nu gaseste randul nu
*!* creeaza crsArticoleFactura, Show() ramane fallback-ul; nu strica workarea/pozitia apelantului
FUNCTION PregatesteArticoleFacturaEditare
LPARAMETERS tcAliasAct
LOCAL lnAreaOrigine, llGasit
lnAreaOrigine = Select()
llGasit = IncarcaVanzareDinNota(m.tcAliasAct)
IF m.llGasit
IncarcaArticoleFactura(tvanz.id_vanzare, 'crsArticoleFactura')
ENDIF
IF m.lnAreaOrigine > 0
SELECT (m.lnAreaOrigine)
ENDIF
RETURN m.llGasit
ENDFUNC && PregatesteArticoleFacturaEditare
*!* parametri: id_articol/codmat/denumire/um/cont, alese din nomenclator (caut_articol, fara stoc);
*!* optional, cand documentul e in valuta: in_valuta/curs/multiplicator/nume_val/id_valuta
*!* construieste obiectul poArticol gol, cu toate proprietatile citite de frm_articol_factura
*!* (Createobject/Init/inainte_de_do_termin) - articol nou, cantitate implicita 1, fara TVA aleasa
*!* (proc_tvav ramane NULL, ca Init sa aleaga singur cota standard curenta); daca in_valuta e adevarat,
*!* tip_valuta/Curs/multiplicator/nume_val/id_valuta se populeaza cu valorile documentului
FUNCTION CreeazaPoArticolNouTvd
LPARAMETERS tnIdArticol, tcCodmat, tcDenumire, tcUm, tcCont, tlInValutaDoc, tnCursDoc, tnMultDoc, tcNumeValDoc, tnIdValutaDoc
LOCAL loArticol, lnI
LOCAL ARRAY laPropN(49)
laPropN( 1)='id_articol'
laPropN( 2)='Id_Pol'
laPropN( 3)='id_gestiune'
laPropN( 4)='id_c'
laPropN( 5)='id_ctr'
laPropN( 6)='id_valuta'
laPropN( 7)='id_valuta_d'
laPropN( 8)='id_lucrare_rez'
laPropN( 9)='id_part_rez'
laPropN(10)='id_jtva_coloana'
laPropN(11)='taxcode'
laPropN(12)='opt_facturare'
laPropN(13)='gestionabil'
laPropN(14)='tip_valuta'
laPropN(15)='cantitate'
laPropN(16)='Curs'
laPropN(17)='multiplicator'
laPropN(18)='pret_achizitie'
laPropN(19)='pretv_orig'
laPropN(20)='pretd'
laPropN(21)='proc_tvav'
laPropN(22)='preturi_cu_tva'
laPropN(23)='pretftva'
laPropN(24)='pretftva_val'
laPropN(25)='pretctva'
laPropN(26)='pretctva_val'
laPropN(27)='tva'
laPropN(28)='tva_val'
laPropN(29)='discount_unitar'
laPropN(30)='discount_unitar_val'
laPropN(31)='discount_unitar_ctva'
laPropN(32)='discount_unitar_ctva_val'
laPropN(33)='valftva'
laPropN(34)='valtva'
laPropN(35)='valctva'
laPropN(36)='valdiscountftva'
laPropN(37)='valdiscounttva'
laPropN(38)='valdiscountctva'
laPropN(39)='valdiminuatftva'
laPropN(40)='valdiminuattva'
laPropN(41)='valdiminuatctva'
laPropN(42)='vvalftva'
laPropN(43)='vvaltva'
laPropN(44)='vvalctva'
laPropN(45)='vvaldiscountftva'
laPropN(46)='vvaldiscounttva'
laPropN(47)='vvaldiscountctva'
laPropN(48)='vvaldiminuatftva'
laPropN(49)='vvaldiminuattva'
LOCAL ARRAY laPropC(11)
laPropC( 1)='codmat'
laPropC( 2)='codmatf'
laPropC( 3)='denumire'
laPropC( 4)='um'
laPropC( 5)='serie'
laPropC( 6)='lot'
laPropC( 7)='explicatie'
laPropC( 8)='numar_contract'
laPropC( 9)='codbare'
laPropC(10)='nume_val'
laPropC(11)='Cont'
loArticol = Createobject('Empty')
FOR lnI = 1 TO ALEN(laPropN)
=AddProperty(loArticol, laPropN(lnI), 0)
ENDFOR
=AddProperty(loArticol, 'vvaldiminuatctva', 0)
FOR lnI = 1 TO ALEN(laPropC)
=AddProperty(loArticol, laPropC(lnI), '')
ENDFOR
loArticol.id_articol = Nvl(m.tnIdArticol, 0)
loArticol.id_ctr = .Null.
loArticol.id_gestiune = -1000
loArticol.gestionabil = 0
loArticol.tip_valuta = 0
loArticol.Curs = 1
loArticol.multiplicator = 1
loArticol.cantitate = 1
loArticol.codmat = Nvl(m.tcCodmat, '')
loArticol.denumire = Nvl(m.tcDenumire, '')
loArticol.um = Nvl(m.tcUm, '')
loArticol.Cont = Nvl(m.tcCont, '')
loArticol.preturi_cu_tva = 0
loArticol.proc_tvav = .Null.
IF m.tlInValutaDoc
loArticol.tip_valuta = 1
loArticol.Curs = m.tnCursDoc
loArticol.multiplicator = m.tnMultDoc
loArticol.nume_val = Nvl(m.tcNumeValDoc, '')
loArticol.id_valuta = m.tnIdValutaDoc
ENDIF
RETURN loArticol
ENDFUNC && CreeazaPoArticolNouTvd