#6 editare factura emisa: S5 - scrierea sumelor editate in Oracle

La salvarea unei facturi deja emise, modificarile facute liniilor de articole
se scriu acum real in VANZARI_DETALII, in aceeasi tranzactie cu restul salvarii,
si totalurile documentului se recalculeaza din liniile efectiv salvate.

- ofacturare_editare.prg: helper nou ScrieArticoleFacturaEditate. Idiomul e
  "marcheaza tot sters, invie ce ramane", nu delta, pentru ca
  actualizeaza_vanzari face UPDATE ... SET STERS = 0 pe tot documentul, fara
  garda; o scriere delta ar lasa liniile sterse sa reinvie la fiecare salvare.
  Cursor gol = no-op, ca o eroare la incarcare sa nu goleasca factura.
- comun.vc2, ofacturare_comun.vc2: agatarea apelului dupa
  finalizeaza_modificare_nota si inainte de inchiderea tranzactiei, in ambele
  puncte de intrare.
- omodificari.vc2: coloana Pret achizitie in grid, editabila doar pe liniile
  noi; liniile de set devin needitabile, cu marcaj; cinci validari la salvare.
- teste: cinci suite noi (validari, grid UI, scriere reala, discount/valuta,
  rollback, al doilea punct de intrare) si asteptari actualizate in
  test_page3_articole.
- docs: oracle_export.md - exportul all_source cere linesize 32767, altfel
  rupe liniile lungi prin mijlocul identificatorilor; scripturi-migrare-db.md -
  UpdateVersiune adauga singur extensia .sql.

Cere scripturile ff_2026_08_09_01 (PACK_FACTURARE) si ff_2026_08_09_02
(VVANZARI_ARTICOLE).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
This commit is contained in:
2026-08-10 01:37:12 +03:00
parent b9eba29ebe
commit 1c42ae0af4
13 changed files with 3408 additions and 60 deletions

View File

@@ -4,10 +4,11 @@
*!* 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
*!* liniile de articole pentru pagina de articole factura (inclusiv in_stoc si id_vanzare_set/pret_achizitie,
*!* pentru corectia verdictului RUL pe liniile nestocate si pentru liniile din seturi), pregatirea
*!* cursorului de articole inainte de Createobject(frm_modific2024), construirea obiectului poArticol
*!* pentru adaugarea unei linii noi prin dialogul frm_articol_factura (populat cu valuta documentului
*!* cand acesta e in valuta) si scrierea in VANZARI_DETALII a liniilor editate/adaugate/sterse
*!* parametru: id_fact
@@ -271,7 +272,7 @@ FUNCTION CreeazaCursorArticoleGol
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, ;
taxcode I NULL, lot C(20) NULL, sters I NULL, id_vanzare_set I NULL, pret_achizitie N(14,4) 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
@@ -455,3 +456,100 @@ FUNCTION CreeazaPoArticolNouTvd
RETURN loArticol
ENDFUNC && CreeazaPoArticolNouTvd
*!* parametri: id_vanzare (din tvanz.id_vanzare), alias articole (implicit tvd), alias vanzare (implicit tvanz)
*!* scrie in VANZARI_DETALII liniile editate ale notei, ca diferenta fata de starea persistata: marcheaza
*!* sters tot documentul, invie/actualizeaza liniile pastrate din alias, insereaza liniile noi, apoi
*!* recalculeaza totalurile documentului (cu discountul din alias vanzare, ca sa nu poata diverge de
*!* liniile scrise); ruleaza in tranzactia manuala deja deschisa de apelant, dupa finalizeaza_modificare_nota
*!* - nu da COMMIT/ROLLBACK, nu inchide cursoare, salveaza si restaureaza workarea/pozitia curenta
*!* retur logic: .T. daca a mers tot sau nu era nimic de facut, .F. la primul esec Oracle (se opreste acolo)
FUNCTION ScrieArticoleFacturaEditate
LPARAMETERS tnIdVanzare, tcAliasArticole, tcAliasVanzare
LOCAL lcAliasArt, lcAliasVanz, lnAreaOrigine, lnRecnoArt, llSucces, lcSql, lnDiscount, llDiscountNul
lcAliasArt = IIF(Type('tcAliasArticole') = 'C' AND !Empty(m.tcAliasArticole), m.tcAliasArticole, 'tvd')
lcAliasVanz = IIF(Type('tcAliasVanzare') = 'C' AND !Empty(m.tcAliasVanzare), m.tcAliasVanzare, 'tvanz')
*!* cursor gol de articole nu inseamna "document fara linii" - poate fi si un esec de incarcare (IncarcaArticoleFactura intoarce .T. cu cursor gol la eroare Oracle); fara ancora, ar goli tacut factura
IF Nvl(m.tnIdVanzare,0) <= 0 OR !Used(m.lcAliasArt) OR !Used(m.lcAliasVanz) OR Reccount(m.lcAliasVanz) <> 1 OR Reccount(m.lcAliasArt) = 0
RETURN .T.
ENDIF
lnAreaOrigine = Select()
llSucces = .T.
SELECT (m.lcAliasVanz)
GO TOP
llDiscountNul = Isnull(discount)
lnDiscount = Nvl(discount,0)
*!* marcheaza sters tot documentul - perechea reset-ului STERS=0 din actualizeaza_vanzari
lcSql = [update vanzari_detalii set sters = 1, id_utils = ] + Alltrim(Str(gnIdUtil)) + [, dataoras = sysdate ] + ;
[where id_vanzare = ] + Alltrim(Str(m.tnIdVanzare)) + [ and sters = 0]
llSucces = goExecutor.oExecuta(m.lcSql)
*!* invie si actualizeaza liniile pastrate - toate cele active din alias, nu doar lmodificat, pasul de mai sus le-a marcat pe toate
IF m.llSucces
SELECT (m.lcAliasArt)
lnRecnoArt = Recno()
SCAN FOR id_vanzare_det > 0 AND Nvl(sters,0) <> 1
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))) + ;
[, 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)
IF !m.llSucces
EXIT
ENDIF
ENDSCAN
TRY
GO m.lnRecnoArt IN (m.lcAliasArt)
CATCH
GO TOP IN (m.lcAliasArt)
ENDTRY
ENDIF
*!* insereaza liniile noi - fara id_vanzare_det, il genereaza trigger-ul TRG_VANZARI_DET_BEFOINS
IF m.llSucces
SELECT (m.lcAliasArt)
lnRecnoArt = Recno()
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))) + [,] + ;
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)]
llSucces = goExecutor.oExecuta(m.lcSql)
IF !m.llSucces
EXIT
ENDIF
ENDSCAN
TRY
GO m.lnRecnoArt IN (m.lcAliasArt)
CATCH
GO TOP IN (m.lcAliasArt)
ENDTRY
ENDIF
*!* recalculul totalurilor, cu discountul documentului dat ca parametru - .NULL. pastreaza discountul curent
IF m.llSucces
lcSql = [begin pack_facturare.recalculeaza_totaluri_vanzari(] + Alltrim(Str(m.tnIdVanzare)) + [,] + ;
Iif(m.llDiscountNul,[NULL],Alltrim(Str(m.lnDiscount,18,4))) + [); end;]
llSucces = goExecutor.oExecuta(m.lcSql)
ENDIF
IF m.lnAreaOrigine > 0
SELECT (m.lnAreaOrigine)
ENDIF
RETURN m.llSucces
ENDFUNC && ScrieArticoleFacturaEditate