# Cercetare: editare factura emisa (netrimisa inca in eFactura) Sursa: cache text `.??2` (deja la zi, negenerate acum) + `.prg` din working copy `D:\ROA\ROAFACTURARE`. Cod Oracle (pachete `PACK_FACTURARE`, `PACK_CONTAFIN`, `PACK_DOCUMENTE`) **NU e in working copy** — doar apelurile RPC din VFP sunt vizibile; corpul PL/SQL trebuie cautat in schema Oracle, nu exista local. ## 1. Fluxul de EMITERE factura **Punct de intrare (meniu -> procedura generica `factureaza`)**, `COMUN\programe\oproceduri_facturare.prg`: - `facturare_contracte` (:130-134) -> `factureaza(2/6/52)` — pe baza de **contract** - `facturare_comenzi` (:140) -> `factureaza(3)` — pe baza de **comanda** - `facturare_avize` (:145) -> `factureaza(4)` — pe baza de **aviz** - `emitere_aviz_clienti` / `_debitori` / `_custodie` / `_transfer` (:203-275) -> `factureaza(tip)` cu tip-uri diverse pentru avize (comanda/lista preturi/contract/lucrare/NIR/retur) - `copiere_factura` (:152) -> `factureaza(toFactura.Tip, toFactura)` — copiere/modificare-inainte-de-emitere (nu e "editare dupa emitere", e o factura noua pornita din datele alteia) `factureaza` (`COMUN\programe\ofacturare.prg:90`) delegheaza imediat la **`factureaza2`** (acelasi fisier, `:170`+; bucla mare pana ~`:850`). Pasi, in ordine: 1. **Formular date antet**: `frm_date_factura` / `frm_date_aviz` / `frm_date_aviz_lucrare` (alegere dupa `tnTip`, `ofacturare.prg:220-226`) — culege client, data, delegat, ruta, incasare etc. in obiectul `poDate`. 2. **Alocare numar document**: `poGeneratorNumere.verifica_numar(...)` / `.dezaloca_numar(...)` (`:250-260`) — numerotare seriala pe tip document, alocata/deblocata aici. 3. **Populare cursor articole**, ramificat dupa `tnTip` (vezi punctul 6 mai jos) — cheama diverse `pack_facturare.cursor_*` (preturi/contract/comanda/avize/gestiune/lucrare/retur/aviz_nir) — `:266-308`. 4. **Formular articole**: `frm_facturare_articole` / `frm_facturare_articole2` / `frm_avizare_lucrare` (`COMUN\clase\ofacturare.vc2`) — user editeaza cantitati/preturi/explicatii inainte de scriere efectiva. 5. **Scriere efectiva** — metoda `do_scrie_factura` a formularului de articole (`COMUN\clase\ofacturare.vc2:14067-14360`, dublata identic in `frm_facturare_articole2` la `:18090-18370`): - **`pack_facturare.scrie_proforma(...)`** (:14071) — doar daca `poDate.eProforma=1`: scrie **doar in VANZARI**, explicit comentat in cod "*nu si in contabilitate*" (:14070). - **`pack_facturare.scrie_factura_avize(...)`** (:14103) — cand `poDate.Tip = 4` (facturare din aviz). - **`pack_facturare.scrie_factura2(...)`** (:14130, :14158) — comenzi (tip 3/21/25/28/42/47) sau alte tipuri ("otherwise": lista de preturi etc.). - Toate aceste RPC-uri scriu in **VANZARI** si intorc un **cursor de verificare** (`lcCursorVerificare`) cu liniile de nota contabila propuse: coloane `id_act, ascd, ascc (asociat cont debit/credit), id_partd, id_partc, dataactt, datairegt, datascadt, suma` (:14184-14206). - Daca exista randuri in cursorul de verificare (adica nu e proforma), se afiseaza **`Do Form verificare`** (:14189) — utilizatorul poate corecta clientul (`id_partd/id_partc`) sau explicatiile (`ascd/ascc`) inainte de a confirma nota. - **`pack_facturare.finalizeaza_scriere_verificare(...)`** (:14247, si varianta `scrie_factura_avize_retur` la :14219/:14282 pentru retur-uri) — **aici se scriu efectiv notele contabile si rulajele** in Oracle, folosind eventualele corectii din formularul de verificare (`pcSirDifAcont`, `pcSirDifPart`). 6. **Alte efecte laterale**: - Incasare/bon fiscal: `poGeneratorNumere.verifica_numar(16, poDate.nr_incasare)` (:503), `listeaza_bon_fiscal(...)` (:528) — chitanta/incasare asociata facturii, daca `poDate.incasat <> 0`. - Listare: `listeaza_ofacturare()` (:535). - Stoc: pentru facturare directa din stoc exista un flux paralel, `oscrie_vanzare_din_stoc` (`COMUN\programe\ofacturare_stoc.prg:318-412`) — apeleaza `pack_facturare.initializeaza_date_factura`, `adauga_articol_factura_stoc`, `scrie_in_vanzari`, si la final `update vanzari set id_fact = pack_contafin.get_idFact() where id_vanzare = ?` (:412) — leaga VANZARI de identificatorul notei contabile (`id_fact`). ## 2. Fluxul de EDITARE factura existenta Formular: `frm_facturi` (lista facturi emise), clasa `COMUN\clase\ofacturare_comun.vc2`. - **`frm_facturi.do_modifica`** — `ofacturare_comun.vc2:4382-4482`. - Verifica intai daca factura e deja in `anaf_efactura` (vezi punct 5) si daca `sters=0`; altfel blocheaza editarea (:4476-4478, mesaj "Nu puteti face modificari pe inregistrarile sterse sau facturile trimise in eFactura!"). - Deschide `frm_modifica_factura` (:4433) si la confirmare (`gnButon=1`) executa **`pack_facturare.modifica_date_factura(...)`** (:4443-4460) cu parametrii: `id_vanzare, id_ruta, id_delegat, id_agent, id_masina, dataora_exp, id_facturare, listare_detaliata, text_aditional, tip_saft, efactura, data_act, data_scad, numar_act, serie_act`. - **Formular `frm_modifica_factura`** (`ofacturare_comun.vc2:5096-5608`) — campurile editabile efectiv expuse in UI sunt: ruta, delegat, agent, masina, data/ora expeditie, tip facturare (`id_facturare`), listare detaliata, text aditional, tip SAFT, si (conditionat de `numar_act` nenul) data act/scadenta/numar act/serie act — vezi `Init` (:5570-5584) si handlerele `chkDataAct/chkNrAct/chkSerieAct` (:5592-5606). **NU exista pe formular campuri pentru client, data facturii, seria/numarul facturii sau articole/preturi** — acestea nu pot fi schimbate prin acest flux de editare. - **Confirmat: editarea NU atinge notele contabile si rulajele.** `modifica_date_factura` primeste doar campurile enumerate mai sus (metadate document/logistica), nu recalculeaza sume, nu scrie in tabelele de note (vezi punct 3) si nu apeleaza vreun echivalent `PACK_CONTAFIN`. Nicio referinta la `pack_contafin` in `do_modifica`. - Editarea explicatiei unui articol de pe factura: **`frm_modifica_articol_factura`** (`ofacturare_comun.vc2:5023-5095`, apelat din `frm_facturi.do_modifica_explicatie` :4484-4501) — apeleaza doar **`pack_facturare.modifica_explicatie_articol(id_vanzare_det, ...)`** (:5067) — schimba **doar textul explicatiei**, nu cantitatea/pretul/cont-ul. Nici aici nu se ating notele contabile. ## 3. Tabelele de note contabile si rulaje Nu exista schema DBC/DDL in working copy (tabelele sunt Oracle, VFP le vede via view-uri `gcs.v...`). Din codul de stergere (`ofacturare_comun.vc2:4573-4614`) rezulta 3 seturi de date, toate filtrate pe `an, luna, cod` (cod = `vanzari.cod`, identificatorul facturii): | View interogat (VFP) | Cursor local | Camp cheie randuri | Rol | |---|---|---|---| | `gcs.vact_tot` | `actactan` / cursor `v_act` | `id_act` (+ `id_set`, `id_fact`, `id_factd`, `id_factc`) | Note contabile (randuri debit/credit) | | `gcs.vrul_tot` | `rul_temp` / cursor `v_rul` | `id_rul` | Rulaje | | `gcs.vrul_obinv_tot` | `rul_temp_obinv` / cursor `v_rul_obinv` | `id_rul_obinv` | Rulaje obiecte de inventar | **Cheia de legatura factura -> nota**: `VANZARI.id_fact` — populat la emitere prin `pack_contafin.get_idFact()` (`COMUN\programe\ofacturare_stoc.prg:412`) sau intors ca parametru OUT din `scrie_factura2`/`finalizeaza_scriere_verificare` (`?@poDate.nid_vanzare` e id_vanzare, nu id_fact — id_fact pare populat separat de pachetul Oracle). Pe partea de nota, actul (`ACT`) are coloanele `id_fact`/`id_factd`/ `id_factc` folosite de `pack_documente.ReferinteDocumenteNota`/`ReferinteDocument` (`COMUN\programe\odocumente.prg:8-46`) pentru a detecta referinte incrucisate intre documente (facturi ce se storneaza/compenseaza reciproc). **Camp de provenienta pentru regenerare**: nu exista un camp explicit gen `sursa_id_vanzare` pe ACT/RUL vizibil in cod VFP; legatura se face prin **`cod` (numarul facturii) + `an` + `luna`** — vezi filtrul identic in `do_sterge` (:4573,4587,4599). Asta e mecanismul deja folosit pentru "sterge tot ce apartine facturii X": select pe `vact_tot`/`vrul_tot`/`vrul_obinv_tot where cod = and an=... and luna=...`, apoi sterge. **E si "reteta" pentru un eventual regenereaza = sterge + refa**, cu observatia ca id-urile (`id_act`, `id_set`, `id_fact`, `id_factd`) trebuie citite inainte de stergere daca se doreste refacere identica (linia 4642-4647 le extrage din `actactan` inainte de a apela stergerea). ## 4. Operatie existenta de STORNARE / STERGERE factura (cheie pentru "regenereaza") Da — **`frm_facturi.do_sterge`** (`COMUN\clase\ofacturare_comun.vc2:4503-4719`) e exact mecanismul "sterge nota + rulaje asociate unei facturi": - Blocheaza daca luna e inchisa (`glLunaInchisa`, :4518-4520) sau daca factura e deja stearsa (:4531-4534) sau daca nu e din luna curenta (:4543-4546). - **Cale proforma**: `pack_facturare.sterge_proforma(?pnIdVanzare, ?gnIdUtil)` (:4550) — nu are note, deci stergere simpla din VANZARI. - **Cale factura/aviz reala**: 1. Verifica blocaj de referinte: `ReferinteDocumenteNota(pnAn, pnLuna, lnCod)` (:4565, `COMUN\programe\odocumente.prg:8`, cheama `pack_documente.ReferinteDocumenteNota`) — daca documentul e referentiat de incasari/plati, blocheaza stergerea (:4567 mesaj "Documentul are referinte..."). 2. Interogheaza `vact_tot`/`vrul_tot`/`vrul_obinv_tot` (vezi punct 3) ca sa afle daca exista note/rulaje de sters (`llRul`). 3. Daca exista randuri in `actactan`, deschide formularul **`verificare`** (:4620-4624) pentru confirmare vizuala a ce se sterge, apoi porneste tranzactie explicita (`SQLSetprop(...,"Transactions",2)`, :4625) si: - fie ruleaza `OSCRIE_IN_FISIERE(2,.F.,llRul)` + **`pack_contafin.finalizeaza_stergere_nota(luna, an, NULL, id_set, cod, id_fact, id_factd, id_util)`** (:4642-4653) — varianta cu rulaje/fisiere multiple, - fie apeleaza direct **`pack_facturare.sterge_factura(?pnIdVanzare, ?gnLuna, ?gnAn, ?gnIdUtil)`** (:4689) daca nu exista note/rulaje de tratat special. 4. Commit/rollback explicit, apoi revine pe tranzactie automata. Asta confirma ca infrastructura "sterge + reface" exista deja pe partea de stergere completa (`sterge_factura` + `finalizeaza_stergere_nota`); un flux de "regenerare la editare" ar putea reutiliza aceste doua RPC-uri Oracle inainte de a re-emite (echivalentul pasilor de la punctul 1, pasul 5) — dar acest lant nu exista azi cablat din formularul de editare (`do_modifica`). ## 5. `anaf_efactura.id_fact` — verificare "a fost deja trimisa in eFactura" - **Citire/test**: `COMUN\clase\ofacturare_comun.vc2:4428-4432`, in `frm_facturi.do_modifica`: ``` lcSql = [select count(*) as lneFactura from anaf_efactura where id_fact = ] + ALLTRIM(STR(poRec.id_fact)) llSucces = goExecutor.oSelecteaza2Value(m.lcSql, @pneFactura) If poRec.sters = 0 AND NVL(m.pnEFactura,0) = 0 ... permite editarea ... Else amessagebox("Nu puteti face modificari pe inregistrarile sterse sau facturile trimise in eFactura!", 48, "Atentie") ``` (`pnEFactura`/`pneFactura` sunt aceeasi variabila — VFP e case-insensitive.) - Expresia de test: **exista cel putin un rand in `ANAF_EFACTURA` cu `id_fact = VANZARI.id_fact` a facturii curente** => considerata "trimisa" => editare blocata. - **Scriere**: `VANZARI.id_fact` insusi e populat la emitere (`pack_contafin.get_idFact()`, `COMUN\programe\ofacturare_stoc.prg:412`, echivalent probabil si in `scrie_factura2`/ `finalizeaza_scriere_verificare` pe partea Oracle, nevizibil in VFP). `ANAF_EFACTURA.id_fact` e populat: - la import de factura de achizitie (nu de emitere): `UpdateEFacturaIdFact` (`COMUN\programe\import_efactura.prg:229`) — `update anaf_efactura set id_fact = ?pnIdFact where id = ?pnId and NVL(id_fact,0)=0`. - manual din formular: `frm_import_efactura.importmodifica` (`anaf_efactura.vc2:12930`) — `UPDATE crsFacturi SET id_fact = m.pnIdFact WHERE id = m.lnIdEfactura`. IPOTEZA: pentru facturile **emise** (nu achizitie), popularea `anaf_efactura.id_fact` la trimitere se face probabil in clasa server `AnafeFacturaServer`/`ANAFeFactura` (`COMUN\programe\anaf_efactura.prg`, ex. `UpdateDbFactura` :2018-2155) sau in Oracle la generarea XML — nu am gasit un UPDATE explicit VFP care leaga `id_fact` la momentul trimiterii unei facturi emise; ar trebui verificat separat (posibil in PL/SQL). ## 6. Cele 4 tipuri de sursa — ramificare si diferente Ramificarea e pe **`VANZARI.tip`** (camp numeric), vazuta in doua locuri, cu acelasi grupaj: `ofacturare.prg:266-308` (populare cursor articole la pornirea emiterii) si `ofacturare.vc2:14067-14174` (`do_scrie_factura`, alegerea RPC-ului de scriere): | Sursa | `tip` (exemple) | Cursor populare articole | RPC scriere | |---|---|---|---| | **Lista de preturi** | 1,5,7,10,22,23,29,45 (si 48/49 varianta `cursor_articole_k`) | `pack_facturare.cursor_preturi(...)` | `scrie_factura2` (ramura "otherwise") | | **Contract** | 2,6,26,52 | `pack_facturare.cursor_contract(...)` | `scrie_factura2` (ramura "otherwise") | | **Comanda** | 3,21,25,28,42,47 | `pack_facturare.cursor_comanda(...)` | `scrie_factura2` (ramura explicita `Inlist(poDate.Tip,3,21,25,28,42,47)`, cu intrebare "Doriti sa se inchida comanda?" :14122) | | **Aviz** | 4 | `pack_facturare.cursor_avize(...)` | `scrie_factura_avize` (ramura `poDate.Tip = 4`, cu intrebare "Doriti sa se inregistreze si avizul de retur?" :14091) | | (alte, mentionate de completitudine) | 27 (lucrare), 30 (aviz din NIR), 41 (transfer gestiune), 8/9/24 (retur) | `cursor_lucrare`/`cursor_aviz_nir`/`cursor_gestiune`/`cursor_retur` | variante `scrie_factura_avize_retur`/`scrie_proforma` | **Ce difera intre ele ca note contabile/rulaje**: apelul final e mereu `pack_facturare.finalizeaza_scriere_verificare(...)` (sau `scrie_factura_avize_retur` pentru retururi) — adica *acelasi* punct final scrie notele, insa RPC-ul de scriere in VANZARI difera (`scrie_factura_avize` vs `scrie_factura2`), iar la comanda/aviz apar intrebari suplimentare de inchidere document sursa (comanda inchisa / aviz retur generat) care produc efecte laterale suplimentare pe langa nota standard. Diferentele fine intre `scrie_factura2` si `scrie_factura_avize` (ce conturi/rulaje difera intern) sunt in PL/SQL, deci **nu sunt vizibile in working copy**. ## 7. Blocaje deja existente la editare - **Sters**: `poRec.sters = 0` obligatoriu (`ofacturare_comun.vc2:4432`). - **Trimis in eFactura**: `anaf_efactura` are rand cu acelasi `id_fact` (punct 5), acelasi test la `:4428-4432`. - **Luna inchisa** — nu e verificat in `do_modifica` (doar in `do_sterge`, :4518-4520, `If glLunaInchisa Return`). Deci editarea (schimbare ruta/delegat/etc.) **nu e blocata de luna inchisa**, doar stergerea. IPOTEZA/ observatie pentru discutie: daca se adauga regenerare de note la editare, ar trebui adaugat si acest test. - **Nu e din luna curenta** — verificat doar la stergere (:4543-4546: `(pnAn*12)+pnLuna <> (gnAn*12)+gnLuna`), nu la editare. - **Referinte incasari/plati** — verificat doar la stergere (`ReferinteDocumenteNota`, :4565-4569), nu la editare. - **Are chitanta/incasare** — nu am gasit un blocaj explicit *la editare*; la stergere, verificarea de mai sus (`ReferinteDocumenteNota`) acopera implicit si incasarile asociate (comentariul din `odocumente.prg:5-6` mentioneaza "id_fact ... pe id_factd sau id_factc"). ## 8. Numerotare si documente legate — ce se poate schimba la editare - **Client**: NU se poate schimba din `frm_modifica_factura` (formularul nu are control pentru client/partener; vezi punct 2). Singurul loc unde apare o restrictie explicita despre client e in fluxul de **verificare la emitere** (nu la editare): `ofacturare.vc2:14198-14201` — daca diferenta de partener ar afecta un cont "41*", `amessagebox("Nu puteti modifica clientul!",48,"Atentie") / Return .F.` — asta e in timpul emiterii (formularul `verificare`), nu in editarea ulterioara. - **Data facturii / seria / numarul facturii**: NU sunt pe formularul de editare. Campurile editabile `data_act`/`numar_act`/`serie_act` (:4444-4458) sunt pentru "act" (document justificativ atasat, cu checkbox-uri de activare `chkDataAct/chkNrAct/chkSerieAct`), NU seria/numarul facturii insesi — acelea se aloca ireversibil la emitere prin `poGeneratorNumere` (punct 1, pasul 2). - **Articole**: nu se pot modifica cantitati/preturi din fluxul de editare a facturii — doar explicatia unui articol (`frm_modifica_articol_factura`, punct 2). - **Aviz consumat / comanda / contract — flag "facturat"**: Exista camp **`facturat`** pe `COMENZI` (folosit in UI: `ct_comenzi.actualizeaza_grid1` colora randurile cu `facturat=1`, `COMUN\clase\ocomenzi.vc2:1144`; verificari `loRec.facturat=1` in `do_modifica`/`do_sterge` ale comenzii, :1806, :2065 — blocheaza modificarea/stergerea comenzii deja facturate; filtru rapid `facturat=1`/`facturat=0` in criterii, :2178). Marcarea `facturat=1` se face insa pe partea Oracle (`pack_facturare.scrie_factura2` etc.), nu am gasit un `UPDATE comenzi SET facturat` direct in VFP — deci **nu e vizibil in working copy** exact unde se scrie flagul, doar ca e citit/verificat pe partea VFP. Nu am gasit camp echivalent `facturat` pe AVIZE sau CONTRACTE in codul cercetat (posibil alt nume de camp sau tot pe partea Oracle) — IPOTEZA/necesita cautare suplimentara daca devine relevant. --- ## Rezumat concluzii cheie 1. **Emiterea** (`COMUN\programe\ofacturare.prg:90` -> `factureaza2`) scrie in VANZARI via `pack_facturare.scrie_proforma/scrie_factura_avize/scrie_factura2`, apoi (daca nu e proforma) afiseaza formularul `verificare` cu liniile de nota propuse si finalizeaza notele/rulajele prin **`pack_facturare.finalizeaza_scriere_verificare`** (`COMUN\clase\ofacturare.vc2:14247`, variante retur la :14219/:14282). Ramificarea pe cele 4 surse (lista preturi/contract/comanda/aviz) e pe `VANZARI.tip`, vezi tabel la punctul 6. 2. **Editarea existenta** (`frm_facturi.do_modifica`, `COMUN\clase\ofacturare_comun.vc2:4382-4482`, via `pack_facturare.modifica_date_factura`) atinge DOAR metadate logistice (ruta/delegat/agent/masina/ dataora_exp/tip_facturare/listare_detaliata/text_aditional/tip_saft/data-numar act) — **confirmat: nu atinge notele contabile/rulajele si nu recalculeaza sume**. Nu se pot schimba client, data/serie/numar factura sau articole. 3. Notele contabile si rulajele stau in view-urile Oracle `vact_tot`/`vrul_tot`/`vrul_obinv_tot` (chei `id_act`/`id_rul`/`id_rul_obinv`), legate de factura prin **`cod`+`an`+`luna`** (identic filtru folosit si la stergere) si prin `VANZARI.id_fact` (populat de `pack_contafin.get_idFact()`). 4. **Exista deja** un flux complet de stergere-cu-note: `frm_facturi.do_sterge` (`ofacturare_comun.vc2:4503-4719`) — foloseste `pack_facturare.sterge_factura` + `pack_contafin.finalizeaza_stergere_nota`, cu verificare de referinte (`ReferinteDocumenteNota`) si confirmare vizuala (formularul `verificare`). **Aceasta e infrastructura direct reutilizabila pentru un "regenereaza = sterge + refa"** al notelor/rulajelor la editare. 5. **`anaf_efactura.id_fact`**: testul de blocare editare e `select count(*) from anaf_efactura where id_fact = ` (`ofacturare_comun.vc2:4428-4432`) — daca exista rand, factura e considerata trimisa si editarea e refuzata. Punctul exact unde se scrie `anaf_efactura.id_fact` la trimiterea unei facturi **emise** nu e vizibil in VFP (ipoteza: pe partea Oracle/XML) — cel gasit in VFP e doar pentru facturi de achizitie importate. 6. **Blocaje actuale**: editarea verifica doar `sters=0` si `netrimisa in eFactura`; NU verifica luna inchisa, NU verifica "luna curenta", NU verifica referinte incasari/plati — aceste 3 verificari exista doar pe fluxul de **stergere**, nu si pe cel de **editare** (`do_sterge` vs `do_modifica`, `ofacturare_comun.vc2:4503` vs `:4382`). 7. Cod PL/SQL Oracle (`PACK_FACTURARE`, `PACK_CONTAFIN`, `PACK_DOCUMENTE`) nu e in working copy — doar semnaturile RPC apelate din VFP sunt vizibile local.