Files
roafacturare/docs/cercetare/rec_editare_factura.md
2026-09-09 22:19:22 +03:00

20 KiB

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 = <cod factura> 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 = <vanzari.id_fact_curent> (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.