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

16 KiB

Corespondenta cont de stoc (3xx) -> cont de venit (7xx): ce exista in cod

Context: continuare a cont_venit_articol_fara_politica.md, care stabilise ca VANZARI_DETALII.CONT e un cont de gestiune/stoc (371, 301-303, 357), fara sa gaseasca un cont de venit pe linia de factura in pack_facturare, si lasase neverificat unde se genereaza efectiv contul de venit. Cercetarea de fata raspunde la cele 4 intrebari, cu corectii fata de raportul anterior.

Raspuns scurt

  1. Nu exista un tabel de corespondenta "3xx -> 7xx" (nume de forma CORESPONDENTA*, NOM_CONTURI*, CONT_VENIT*, ARTICOLE_CONTABILE*) nicaieri in SCRIPTURI_CLAR. In schimb exista un mecanism echivalent functional, dar configurat manual, nu derivat automat din contul de stoc: tabelul NOTE_CONTABILE (coloane SCD/ASCD = cont+analitic debitor, SCC/ASCC = cont+analitic creditor), legat de politica de pret a articolului prin CRM_POLITICI_PRETURI.ID_NOTA -> CRM_NOTE_VANZARI.ID_SET -> NOTE_CONTABILE. Un contabil configureaza acest tabel dintr-un ecran dedicat (frm_config_note_contabile[2007]), nu se calculeaza din NOM_ARTICOLE.CONT/STOC.CONT.
  2. NOM_ARTICOLE.CONT NU e restrans la conturi de stoc (clasa 3). Validarea la editare (verific_cont) verifica doar ca respectivul cod exista in planul de conturi al anului curent (vplcont_sintetic), fara filtru pe clasa. UI-ul trimite explicit catre "Planul de conturi" (buton de help general), nu catre un subset de conturi de stoc. Asta confirma afirmatia lui Marius: campul accepta orice cont, inclusiv 6xx/7xx.
  3. Nota contabila a vanzarii SE genereaza in pack_facturare — raportul anterior a cautat literalii 707/704/706/708 (care nu apar hardcodati nicaieri, corect) si a conchis gresit ca lipseste mecanismul. El exista, dar e indirect: pack_facturare.contabilizeaza_articol (ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7182-7556) ia SCD/SCC din NOTE_CONTABILE (via politica de pret a articolului) si scrie nota cu pack_facturare.scrie_nota(...). SCC (contul creditor) e contul de venit efectiv al liniei — nu vine din VANZARI_DETALII.CONT (care ramane contul de gestiune, folosit separat, doar pentru descarcarea de gestiune, in descarca_gestiune).
  4. ID_VENCHELT/NOM_VENIT_CHELTUIELI nu are coloana de cont (nicio ALTER TABLE NOM_VENIT_CHELTUIELI ADD ... CONT in SCRIPTURI_CLAR). E o dimensiune analitica separata (clasificare venituri/cheltuieli, posibil pentru raportare/buget), transmisa ca parametru propriu catre scrie_nota, in paralel cu SCD/SCC — nu e sursa contului.

1. Nu exista tabel de corespondenta 3xx->7xx; exista NOTE_CONTABILE + politica de pret

Cautare tabel dedicat — negativa

Cautari in D:\ROA\DATABASE\SCRIPTURI_CLAR (CREATE TABLE/ALTER TABLE, case-insensitive) pentru CORESPONDENT*, NOM_CONTURI*, CONT_VENIT*, PLAN_CONTURI*, ARTICOLE_CONTABILE*: niciun rezultat relevant — singurele hituri pe CORESPONDENT sunt cuvantul romanesc generic ("banca corespondenta" etc.) in sute de fisiere fara legatura, iar CONT_VENIT nu apare deloc ca nume de tabel/coloana.

Mecanismul real: lant de 4 tabele, configurat pe politica de pret

pack_facturare.contabilizeaza_articol (ff_...:7227-7280) foloseste acest cursor pentru a afla contul debitor/creditor al liniei de vanzare:

CURSOR cursor_articol IS
  SELECT A.ID_POL_ART, A.ID_POL, A.ID_ARTICOL, A.PRET, ...
         NVL(pack_facturare.nid_venchelt, NVL(A.ID_VENCHELT, C.ID_VENCHELT)) AS ID_VENCHELT,
         NVL(pack_facturare.nid_sectie_stoc, C.ID_SECTIE) as ID_SECTIE,
         C.ID_SET, D.EXPLICATIE, D.SCD, D.ASCD, D.SCC, D.ASCC, D.CU_TVA, ...
    FROM CRM_POLITICI_PRET_ART A
    LEFT JOIN CRM_POLITICI_PRETURI B ON A.ID_POL = B.ID_POL
    LEFT JOIN CRM_NOTE_VANZARI C ON B.ID_NOTA = C.ID_NOTA
    LEFT JOIN NOTE_CONTABILE D ON C.ID_SET = D.ID_SET
   WHERE A.ID_POL = detalii_articol.id_pol AND A.ID_ARTICOL = detalii_articol.id_articol;

(ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7227-7280)

Lantul e: articol + politica de pret (CRM_POLITICI_PRET_ART, deja documentat in raportul anterior ca avand PRET/PROC_TVAV/ID_VALUTA, fara CONT) -> antetul politicii de pret (CRM_POLITICI_PRETURI.ID_POL, care are ID_NOTA) -> nota de vanzare CRM (CRM_NOTE_VANZARI.ID_NOTA, care are ID_SET) -> sablonul de nota contabila (NOTE_CONTABILE.ID_SET, care are SCD/ASCD/SCC/ASCC/EXPLICATIE/CU_TVA/IN_VALUTA).

Apoi, la scriere (ff_...:7405-7437):

CASE
  WHEN pack_facturare.ntip <= 20 or pack_facturare.ntip IN (...) THEN
    -- factura, factura roahotel
    V_SCD  := crs_rand_articol.scd;
    V_ASCD := NVL(crs_rand_articol.ascd, PACK_FACTURARE.GetAnaliticByGrupUtilizatori(...));
  WHEN pack_facturare.ntip in (28, 29) THEN
    -- aviz catre clienti debitori
    V_SCD  := '461'; ...
  ELSE
    -- aviz
    V_SCD  := '418'; ...
END CASE;

V_SCC  := crs_rand_articol.scc;
V_ASCC := NVL(crs_rand_articol.ascc, PACK_FACTURARE.GetAnaliticByGrupUtilizatori(...));

(ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7407-7437)

Pentru o factura normala (ntip <= 20), V_SCD e contul debitor din nota (tipic un cont de creante, 411/etc.), iar V_SCC e contul creditor din nota — acesta e efectiv contul de venit al liniei (707/704/706/708, in functie de cum a configurat contabilul nota respectiva), preluat direct din NOTE_CONTABILE.SCC, fara nicio derivare din contul de stoc al articolului. Perechea V_SCD/V_SCC (plus ID_VENCHELT, ID_SECTIE, EXPLICATIE, cota TVA) e trimisa la pack_facturare.scrie_nota(...) (ff_...:7452-7476), care scrie randul in nota contabila efectiva a vanzarii.

Concluzie fata de ipoteza lui Marius: mecanismul exista si rezolva exact problema — "de unde stiu contul de venit al unei linii de vanzare, indiferent daca articolul e gestionabil sau nu" — dar nu e o corespondenta automata cont-stoc -> cont-venit. E o configurare manuala per politica de pret: fiecare politica de pret (CRM_POLITICI_PRETURI) e legata la o "nota de vanzare" CRM (CRM_NOTE_VANZARI), care la randul ei e legata la un sablon de nota contabila (NOTE_CONTABILE) cu perechea SCD/SCC fixata de un contabil. Politica de pret aplicata articolului decide, indirect, contul de venit — nu clasa/valoarea contului de gestiune al articolului.

Ecranul de configurare (unde se seteaza SCD/SCC)

D:\ROA\ROAFACTURARE\COMUN\ferestre\frm_config_note_contabile.sc2 (+ varianta frm_config_note_contabile2007.sc2 pentru anii >= 2007, selectata in COMUN\programe\omeniu_initializari.prg:257-282) e formularul din meniu "Configurare note contabile". Clasa e onote_contabile.vc2, cu un grid gridInregistrari avand coloanele cScd/cAscd/cScc/cAscc (onote_contabile.vc2:2401-2435) legate direct de cnote_contab.scd/.scc/.ascd/.ascc, si salvare prin INSERT/UPDATE direct pe note_contabile(explicatie,scd,ascd,scc,ascc,ordine,cu_tva,ptva,id_set,in_valuta,...) (onote_contabile.vc2:315-322, :486-493). Deci contabilul e cel care scrie manual perechea SCD/SCC (inclusiv contul de venit SCC) pentru fiecare id_set/nota, nu exista automatism care sa deriveze SCC din contul de gestiune al articolului.

2. NOM_ARTICOLE.CONT — nu e restrans la clasa 3

  • Camp: Clb_tx_cont.Text_simplu1.ControlSource = "porec.cont", MaxLength = 4, eticheta "Cont*" (obligatoriu), buton de help cu tooltip "Help - Planul de conturi (CTRL+ H)" — COMUN\clase\onom_articole.vc2:1058-1087. Trimiterea catre "Planul de conturi" (nu catre un subset "conturi de stoc") sugereaza ca formularul asteapta orice cont valid, nu doar clasa 3.
  • Validare la Valid() al campului (in alt formular generic de conturi, onomenclatoare.vc2, nu in cel de articole, dar foloseste aceeasi functie globala):
    PROCEDURE clb_cont.Text_simplu1.Valid
        IF !EMPTY(this.Value)
            lnVerificat = verific_cont(thisform.orec.cont)
            IF lnVerificat < 0
                RETURN 0
            ENDIF
        ENDIF
    ENDPROC
    
    (COMUN\clase\onomenclatoare.vc2:3251-3258)
  • verific_cont (COMUN\programe\oproceduri_comune.prg:2389-2415):
    Procedure verific_cont
        Parameters tcCont, tlNoMessage
        lcSel = [SELECT cont from ] + GCS + [.vplcont_sintetic WHERE TRIM(cont) = ?pcCont and an = ?gnAn ]
        ...
        If Reccount('crs_verific') = 0
            lnSucces = -1
        Endif
        If lnSucces < 0 And !tlNoMessage
            amessagebox('Acest cont nu este definit in planul de conturi!', 0 + 48, 'Atentie')
        Endif
    Endproc
    
    Singura conditie e ca cont sa existe in vplcont_sintetic (planul de conturi sintetic al anului curent, gnAn) — fara LIKE '3%', fara SUBSTR(cont,1,1) = '3', fara nicio alta restrictie de clasa. O varianta identica exista si in COMUN\programe\ooperatii_comune.prg:1307 (nu am comparat corp cu corp, dar semnatura e aceeasi).
  • Nu exista CHECK CONSTRAINT pe NOM_ARTICOLE.CONT in SCRIPTURI_CLAR (cautare CHECK.*CONT/constraint.*CONT.*check — zero rezultate relevante), deci nici la nivel de baza de date nu exista o restrictie de clasa.
  • Nu am gasit nicaieri in COMUN sau ROAFACTURARE o ramificare pe Left(cont,1)/ SUBSTR(cont,1,1) aplicata specific campului NOM_ARTICOLE.CONT (cautare in D:\ROA\ROAFACTURARE si D:\ROA\ROAFACTURARE\COMUN) — singurul loc cu SUBSTR(cont,1,1) gasit e in onomenclatoare.vc2:3647, un filtru de grid pe planul de conturi general (tab-uri "1", "2", "3"... pentru navigare in plan), fara legatura cu articolele.

Concluzie: campul e validat generic (orice cont din planul de conturi al anului), fara restrictie de clasa la nivel de UI sau DB. Asta confirma ce a spus Marius: un articol negestionabil poate avea legitim un cont 6xx/7xx in NOM_ARTICOLE.CONT.

3. Unde se genereaza efectiv nota contabila a vanzarii

Raportul anterior cauta gresit literalii 707/704/706/708 (niciunul nu apare hardcodat — corect) si a conchis ca nu exista mecanism in pack_facturare. De fapt exista, dar e in pack_facturare, nu intr-un pachet separat de contabilitate:

  • Functia: pack_facturare.contabilizeaza_articol(detalii_articol VANZARI_DETALII_TEMP%ROWTYPE) (ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql:7182-7556), apelata pe fiecare rand din VANZARI_DETALII_TEMP — vezi apelul V_INCASAT_CALCUL := V_INCASAT_CALCUL + pack_facturare.contabilizeaza_articol(tab_detalii(i)); in scrie_aviz_retur (ff_...:7148-7150); acelasi tipar se repeta si in fluxul principal de facturare (nu doar in aviz-retur — semnatura si structura functiei arata ca acopera si ntip <= 20, adica factura propriu-zisa, prin CASE ... WHEN pack_facturare.ntip <= 20 ... la ff_...:7409-7421).
  • Sursa SCD/SCC: vezi sectiunea 1 — cursorul cursor_articol (ff_...:7227-7280), pe baza politicii de pret a articolului (detalii_articol.id_pol), nu pe VANZARI_DETALII.CONT.
  • VANZARI_DETALII.CONT ramane folosit separat, doar pentru gestiune: in aceeasi functie, descarca_gestiune(...) primeste explicit detalii_articol.cont ca parametru (ff_...:7485-7507, apelat cand nscadere_stoc = 1 AND id_gestiune <> -1000 AND in_stoc = 1) — acesta e contul de gestiune/stoc (371/301-303/357 etc., documentat in raportul anterior), folosit pentru randul de descarcare de gestiune (marfa iesita din stoc), complet independent de V_SCD/V_SCC calculate mai sus pentru randul de venit al vanzarii. Cele doua conturi coexista pe aceeasi linie de vanzare, cu surse complet diferite: unul (gestiune) vine din NOM_ARTICOLE.CONT/STOC.CONT/NOM_GESTIUNI.CONT (cf. raport anterior), celalalt (venit) vine din NOTE_CONTABILE.SCC via politica de pret.
  • Nu exista fallback/hardcodare pentru SCC: daca NOTE_CONTABILE nu are un rand pentru ID_SET-ul politicii, LEFT JOIN-urile din cursor_articol produc NULL pe SCC/SCD (fara eroare explicita in acest cursor — spre deosebire de cazul V_COMPUS/politica lipsa la ff_...:7293-7311, care ridica FACT-024).

4. ID_VENCHELT / NOM_VENIT_CHELTUIELI

  • Nu are coloana de cont: nicio ALTER TABLE NOM_VENIT_CHELTUIELI ADD ... CONT in SCRIPTURI_CLAR (cautare directa, zero rezultate) si nicio CREATE TABLE NOM_VENIT_CHELTUIELI in arhiva (tabelul predateaza 2009, inceputul arhivei SCRIPTURI_CLAR — la fel ca NOTE_CONTABILE, CRM_NOTE_VANZARI, CRM_POLITICI_PRETURI, pentru care nu exista CREATE TABLE in arhiva din acelasi motiv).
  • Structura vazuta din uz: NOM_VENIT_CHELTUIELI.ID_VENCHELT%TYPE (tip declarat repetat in pack_facturare, ex. ff_...:191) si ACT.ID_VENCHELT%TYPE (ff_...:6725) — deci ID_VENCHELT e o coloana FK pe ACT (tabelul de note contabile efective) si pe CRM_NOTE_VANZARI / CRM_POLITICI_PRET_ART (vezi NVL(B.ID_VENCHELT, D.ID_VENCHELT) la ff_...:7205, unde B = CRM_POLITICI_PRET_ART, D = CRM_NOTE_VANZARI in cursorul comentat din pachet).
  • Cine il consuma: pack_facturare.contabilizeaza_articol il rezolva cu prioritate similara contului: NVL(pack_facturare.nid_venchelt, NVL(A.ID_VENCHELT, C.ID_VENCHELT)) (override global de sesiune -> articol/politica -> nota de vanzare) si il trimite ca parametru propriu catre scrie_nota(...) (ff_...:7461), separat de SCD/SCC. E deci o a treia dimensiune (clasificare venituri/cheltuieli) atasata randului de nota contabila, nu sursa contului insusi — raportul anterior avea dreptate sa il caracterizeze ca "o clasificare, nu un cont", desi nu urmarise consumatorul pana la capat.
  • Numele NOM_VENIT_CHELTUIELI si folosirea alaturi de SCD/SCC/ID_SECTIE sugereaza un centru de venituri/cheltuieli pentru raportare (posibil situatii financiare pe sectii/centre de cost), nu un mecanism alternativ de determinare a contului 7xx.

Neverificat

  • Structura completa (toate coloanele) a NOTE_CONTABILE, CRM_NOTE_VANZARI, CRM_POLITICI_PRETURI si NOM_VENIT_CHELTUIELI: niciuna nu are CREATE TABLE in SCRIPTURI_CLAR (arhiva incepe 2009, tabelele sunt mai vechi). Coloanele folosite in cod sunt confirmate (SCD/ASCD/SCC/ASCC/EXPLICATIE/CU_TVA/IN_VALUTA/ID_SET pe NOTE_CONTABILE; ID_NOTA/ID_SET pe CRM_NOTE_VANZARI; ID_NOTA/ID_POL pe CRM_POLITICI_PRETURI; ID_VENCHELT pe NOM_VENIT_CHELTUIELI), dar lista completa ar necesita interogarea schemei Oracle live (DESC NOTE_CONTABILE etc.) sau un export DDL mai vechi decat 2009, in afara bugetului acestei cercetari.
  • Continutul efectiv al NOTE_CONTABILE.SCC pentru notele configurate curent (adica ce conturi 707/704/706/708 sunt de fapt setate, si daca fiecare politica de pret are o nota configurata) — ar necesita interogarea datelor din schema Oracle live, nu doar codul static.
  • Daca contabilizeaza_articol e chiar apelata pe fluxul principal de facturare (nu doar din scrie_aviz_retur) — am dedus asta din CASE ... ntip <= 20 ... (factura normala tratata explicit in functie), dar nu am urmarit toti apelantii ei in fisier (fisierul are 17000+ linii; cautarea pack_facturare.contabilizeaza_articol ar trebui repetata exhaustiv daca se doreste certitudine completa pe toate punctele de intrare — facturare avans, deviz, retail etc.).
  • Comportamentul cand NOTE_CONTABILE/CRM_NOTE_VANZARI lipsesc pentru o politica de pret: cursorul foloseste LEFT JOIN, deci SCD/SCC ar ajunge NULL fara eroare explicita in acest punct — nu am verificat daca exista o validare ulterioara (la scrie_nota sau la commit-ul notei) care sa blocheze o nota cu cont NULL.