Files
roafacturare/docs/cercetare/coresp_cont_venchelt.md
Marius Mutu b5a7108f34 docs: cercetarile comune trec in COMUN, reziduul #6 dispare, progres.md la zi
Curatenie ceruta dupa inchiderea lui #6. Folderul cercetare\ NU se putea sterge
in bloc: plan_13 se sprijina pe el cu 85 de trimiteri, deci e baza de dovezi a
planului aflat in lucru. Impartirea:

- 14 cercetari trans-proiect trec in COMUN\docs\cercetare\ - valuta si curs,
  TVA/VANZARI, consumatorii VANZARI din toata suita, integrarile #10/#11/#12,
  watchdog VFP, proiectarea Oracle a lui S5, view-ul VVANZARI_ARTICOLE. Nu sunt
  ale ROAFACTURARE, iar #10/#11/#12 se reiau chiar din ele.
- 20 de rapoarte de executie ale lui #6, nereferite de nimic viu, sterse.
- 91 raman, neatinse.

Trimiterile catre handoff-urile si diff-urile intermediare deja desfiintate au
fost curatate peste tot (39 de fisiere): 50 catre handoff-uri, 37 catre diff-uri
aplicate, plus caile celor mutate in COMUN. Zero trimiteri rupte ramase.

progres.md preia rolul de predare: ce ramane din #6 (cele sase documente
parazite, cele doua esecuri reale din S8 pe factura din aviz), cifrele de test
citite din log, si cele doua capcane de mediu platite - .FXP vechi executat in
locul .prg-ului, si GETFONT() care atarna un formular instantiat fara goApp.

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

53 KiB

CORESP_CONT_VENCHELT ca sursa de cont de venit pentru articole fara politica de pret (decizia 27)

Cercetare pe cod, read-only, fara modificari. Continua cont_venit_articol_fara_politica.md si cont_venit_corespondente.md (care stabilisera ca SCC vine azi din NOTE_CONTABILE prin lantul politicii de pret) si nota_contabila_fara_politica.md (care stabilise ca contabilizeaza_articol ridica FACT-024 si opreste tranzactia cand nu exista politica).

9. Intrebarea care putea rasturna tot: "in ROAACNPRO si pe factura din comanda/contract se adauga articole fara politica de preturi — de ce nu si aici?"

Raspuns scurt, verificat pe cod: impresia e explicabila, dar niciunul din cele doua exemple nu e de fapt un articol fara politica trecut cu bine prin contabilizeaza_articol. FACT-024 ramane blocantul real — nu exista azi, in productie, niciun flux in care un articol ajunge la contabilizeaza_articol fara sa fie membru al unei politici si sa treaca fara eroare.

9a) Ce verifica de fapt FACT-024 — apartenenta articolului la politica liniei, nu "id_pol e gol"

Blocul (D:\ROA\ROAFACTURARE\docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:7278-7302, citat integral la sectiunea 6) face:

SELECT COMPUS, ID_POL_ART
  INTO V_COMPUS, V_ID_POL_ART
  FROM VCRM_POLITICI_PRET_ART
 WHERE ID_ARTICOL = detalii_articol.id_articol
   AND ID_POL = detalii_articol.id_pol;

Mesajul confirma exact asta: 'Articolul ' || ... || ' nu este definit in politica de preturi ' || ... — verifica apartenenta articolului la politica id_pol care a ajuns pe linie, nu doar "exista vreun id_pol". Insa id_pol nu e derivat de Oracle din client/contract/tip document — e parametru de intrare explicit (V_ID_POL IN NUMBER, adauga_articol_factura, ff_...:4993, citat integral la sectiunea 8a), trimis de VFP pe fiecare linie. Deci sunt doua cauze distincte care duc la aceeasi eroare:

  1. id_pol e NULL/gol pe linie (articolul a fost ales dintr-o cautare care nu are deloc coloana id_pol — cazul caut_articol, sectiunea 9d) — NO_DATA_FOUND trivial (X = NULL nu se potriveste niciodata).
  2. id_pol e o valoare reala, dar articolul nu e in lista acelei politici — la fel NO_DATA_FOUND, cu acelasi mesaj. Ambele cauze converg spre FACT-024; codul nu le distinge in eroare. Formularea din intrebarea lui Marius ("nu se cauta politica articolului, ci apartenenta articolului la politica documentului") e partial corecta: verificarea e de apartenenta, dar id_pol nu vine din "antetul documentului" ca o singura valoare fixa — vine per-linie, de la formularul de adaugare a articolului (sectiunea 9d).

9b) ROAACNPRO — importul Roris/Contracte NU trece deloc prin contabilizeaza_articol

Verificat direct in D:\ROA\ROAACNPRO\Programe\proceduri_acnpro.prg (read-only). Cautare pack_facturare\.|pack_acn\.|pack_contafin\. in tot fisierul — apelurile de la salvarea facturii (factura_salvare_db, :3331-3467) sunt:

proceduri_acnpro.prg:3332  lcSql = [begin pack_facturare.initializeaza_scriere_actrul(NULL,1); end;]
proceduri_acnpro.prg:3343  lcSql = [begin pack_facturare.initializeaza_date_factura(...
proceduri_acnpro.prg:3382  lcSql = [begin pack_facturare.adauga_articol_factura_deviz(...
proceduri_acnpro.prg:3412  lcSql = [begin pack_facturare.scrie_in_vanzari(0,...
proceduri_acnpro.prg:3430  lcSql = [begin pack_acn.salveaza_regdoc(?.id, ?.id_vanzare, ?.tip, ...

Exact tiparul deja documentat pentru ROAAUTO "Alte servicii" in nota_contabila_fara_politica.md: adauga_articol_factura_deviz (insereaza doar in VANZARI_DETALII_TEMP, fara ID_POL — semnatura n-are acest parametru) urmat de scrie_in_vanzari (copiaza in VANZARI_DETALII, fara sa scrie vreo nota contabila de venit) — contabilizeaza_articol nu apare deloc in acest fisier (cautare directa contabilizeaza_articol in proceduri_acnpro.prg: zero rezultate). Nota contabila a documentului ACN o scrie pack_acn.salveaza_regdoc, o procedura complet separata, specifica ACN, apelata cu parametri proprii (?.id_articol, ?.id_locatia, ?.id_valuta, ?.id_client, ?.id_contract, ?.pret, ?.curs, ?.cantitate, ?.valval, ?.tvaval, ?.totval, ...) — fara id_pol in lista de parametri. Confirmat si de raportul deja existent COMUN\docs\cercetare\import_roris_roaacnpro.md (sectiunea 3): "nicio procedura Oracle stocata (pack_*) nu e apelata in etapa de import ... acestea sunt apelate abia la salvarea finala", si articolele/preturile vin din dialoage de calcul tarife proprii ACN (frm_calcul_tranzit, vctr_articole2), nu din CRM_POLITICI_PRET_ART.

Concluzie 9b: ROAACNPRO nu e un exemplu de "articol fara politica trecut cu bine prin contabilizeaza_articol" — e un produs care nu foloseste deloc acest mecanism de contabilizare pentru facturile lui. Impresia lui Marius e intemeiata pe experienta ("acolo merge fara sa aleg vreo politica"), dar explicatia e alta decat "FACT-024 se poate evita" — e ca acel flux nu ruleaza deloc codul care ar putea da FACT-024.

9c) Factura din comanda/contract in ROAFACTURARE — articolul "liber" e de fapt din lista de preturi

Deja cercetat, cu dovezi, in docs\cercetare\retur_si_lista_preturi.md sectiunea B (citit integral aici, nu doar rezumat). Punctul central (retur_si_lista_preturi.md sectiunea B7):

  • Contract (tip 2,6,26,52): crsarticole (grila principala de articole, folosita si pentru adaugare "libera") e populat de pack_facturare.cursor_contract(...), care da lista de preturi completa, nerestrictionata la continutul contractului — "azi se poate deja adauga liber din lista de preturi pe un document contract".
  • Comanda (tip 3): crsarticole e populat de cursor_comanda, doar articolele comenzii — nu exista adaugare libera in fluxul normal (doar prin copiere de document, care re-adauga tot din cursor_preturi).

Verificat aici, suplimentar, ca cursor_preturi (folosit si de cursor_contract, structura identica) selecteaza explicit A.ID_POL ca coloana de output:

-- ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:2162-2167 (cursor_preturi, ramura V_TIP = 45, tipic pentru toate ramurile CASE)
OPEN V_CURSOR FOR
  SELECT rownum as id_c,
         B.ID_ARTICOL,
         NULL AS LOT,
         NULL as SERIE,
         A.ID_POL,
         ...

si ca cursorul insusi porneste, la fiecare apel, prin pack_facturare.completare_politica_stoc() (ff_...:2151), care garanteaza deja randuri in CRM_POLITICI_PRET_ART pentru toate articolele IN_STOC=1 (procedura citata integral la sectiunea 8c2). Deci fiecare articol afisat in grila "lista de preturi"/"contract" vine deja cu un id_pol valid, dintr-o politica reala, exact pentru ca e extras printr-un join pe CRM_POLITICI_PRETURI/CRM_POLITICI_PRET_ART. "Adaugare libera pe contract" nu inseamna "articol fara politica" — inseamna "orice articol din lista de preturi, nu doar cele din contract", dar tot cu politica ceruta, doar aleasa implicit prin cursor, nu prin dialogul manual do_cauta_politica.

Concluzie 9c: nu e un contraexemplu la FACT-024 — e acelasi mecanism (articol + politica), livrat printr-o alta grila de selectie (crsarticole populat de cursor_contract in loc de caut_articol), care intampla sa nu ceara utilizatorului sa caute manual politica pentru ca cursorul o aduce deja atasata pe fiecare rand.

9d) Ce diferentiaza de fapt "adaugare din nomenclator" (cazul #13) de "adaugare din lista de preturi/contract" (cazul care merge azi)

Diferenta e cursorul sursa al gridului de articole, nu tipul de document:

  • caut_articol (COMUN\programe\ocautare.prg:1636-1735, folosit pentru cautare libera in nomenclator) — SELECT-ul confirmat la ocautare.prg:1671-1689 (vnom_articole_crm/vnom_articole): nu are coloana id_pol in nicio ramura (tlCRM sau nu). Un articol ales prin acest dialog ajunge in poArticol (scatter din crsarticole, ofacturare.vc2:12850-12851) fara id_pol — exact cazul care da FACT-024 azi, si exact cazul cerut de povestea #13 ("adaugat direct din nomenclator").
  • cursor_preturi/cursor_contract (Oracle, sectiunea 9c) — id_pol e parte din rezultat, pentru ca interogarea porneste de la politica de pret, nu de la nomenclator.

Deci povestea #13 cere exact ce nu exista azi: un articol ales prin cautarea de nomenclator (fara trecere prin vreo politica), caruia i se cere totusi sa treaca prin contabilizeaza_articol fara eroare. Niciunul din exemplele lui Marius (ROAACNPRO, contract) nu demonstreaza ca asta functioneaza deja undeva — primul nu foloseste deloc functia, al doilea nu e de fapt "fara politica".

Verdict 9

FACT-024 ramane blocantul real, confirmand (nu contrazicand) analiza din sectiunile 6-8. Nu exista azi, pe niciun flux de productie cercetat, un caz in care un articol trece prin pack_facturare.contabilizeaza_articol fara sa fie membru al unei politici de pret si nu cade cu eroare. Impresia lui Marius e intemeiata pe doua experiente reale, dar explicatia lor e alta:

  • ROAACNPRO: alt produs, alta procedura de contabilizare (pack_acn.salveaza_regdoc), niciodata contabilizeaza_articol;
  • Contract in ROAFACTURARE: articolul PARE liber, dar e adus printr-un cursor care il livreaza deja cu o politica reala atasata (cursor_contract/cursor_preturi + completare_politica_stoc).

Asta nu inseamna ca planul A (sectiunea 8, VFP alege singur un id_pol) sau planul B (sectiunea 6, fallback in pachet) sunt de abandonat — arata insa ca niciuna din cele doua nu se poate simplifica la "nu faceti nimic, functioneaza deja": mecanismul de protectie e real si consecvent, nu un artefact uitat.

Constrangere noua (Marius, aparuta in timpul cercetarii): pack_facturare e plan B

Marius prefera sa nu se scrie cod nou in pack_facturare — e pachetul comun folosit de toata suita, si orice ramura noua acolo e risc peste tot, nu doar in ROAFACTURARE. Sectiunea 6 (punctul de injectie in pachet) ramane in raport ca informatie, dar devine plan B. Intrebarea reala, tratata in sectiunea 8 de mai jos: se poate obtine acelasi rezultat din VFP, alegand singur un id_pol potrivit, fara sa se modifice pack_facturare? Raspuns scurt: da, ingredientele exista deja, dar solutia nu e "zero cod" — e cod VFP nou (nu Oracle), care se sprijina pe 3 mecanisme deja functionale in productie. Detalii in sectiunea 8.

Concluzie: fezabil cu conditii, si conditiile sunt mai mari decat pare din formularea deciziei 27

  1. Verificare prioritara (sectiunea 9, ceruta de Marius in timpul cercetarii): FACT-024 ramane blocantul real. Nu exista azi niciun flux de productie in care un articol trece prin contabilizeaza_articol fara sa fie membru al unei politici de pret si nu cade cu eroare. ROAACNPRO nu e un contraexemplu — nu foloseste deloc contabilizeaza_articol (alta procedura de contabilizare, pack_acn.salveaza_regdoc). Contractul in ROAFACTURARE nu e un contraexemplu — articolele "libere" vin din cursor_contract/cursor_preturi, care le ataseaza deja o politica reala. Detalii complete in sectiunea 9.
  2. Tabelul exista, e populat cu date reale si e folosit activ in productie — dar niciodata pentru CONT_VENIT. Toti consumatorii gasiti (pack_vin, pack_devize, gestiune_pack_gest_import, gestiune_rapoarte) citesc CONT_CHELT (sau CONT_APROVIZIONARE), niciunul CONT_VENIT. Coloana CONT_VENIT e completata cu date reale (o migrare din 2023 acopera 20 de conturi de gestiune), dar n-are niciun consumator — nici Oracle, nici VFP. Cititul ei pentru facturare ar fi un consumator nou, nu o reteta deja rulata in productie.
  3. Cheia de join e stabila si testata: mereu CONT (contul de gestiune al liniei), cu filtru STERS = 0, prin LEFT JOIN. Pattern-ul se poate copia identic pentru CONT_VENIT.
  4. Punctul care schimba verdictul de la "fezabil simplu" la "fezabil cu conditii mari": in contabilizeaza_articol, ramura "articol simplu" nu executa nimic (nici scrie_nota, nici descarca_gestiune) daca cursor_articol (care citeste din CRM_POLITICI_PRET_ART) nu gaseste niciun rand — si nu gaseste niciun rand exact in cazurile in care azi se ridica FACT-024. Un simplu "prinde exceptia si continua" ar produce o linie facturata fara nota contabila si fara descarcare de gestiune, fara nicio eroare — mai rau decat blocajul actual. Fallback-ul cere o ramura noua, paralela cursorului, nu doar inlocuirea unei valori.
  5. Chiar cu ramura noua, CU_TVA si IN_VALUTA (cota TVA inclusa in pret / linie in valuta) nu au nicio sursa alternativa in afara NOTE_CONTABILE. Corespondentele si NOM_ARTICOLE.CONT dau doar un cont, nu aceste doua semnale de interpretare a pretului — ele trebuie fie hardcodate (risc de calcul gresit al bazei/TVA), fie cerute ca intrare noua de la utilizator/articol.
  6. 704 ca literal de fallback are un precedent real in suita, dar in alt subsistem: proprietatea cconte = 704 ("cont implicit articol client") din frm_configurare_efactura (COMUN\clase\anaf_efactura.vc2:8376), folosita la import eFactura, nu in pack_facturare. Nu e o reteta gata scrisa pentru facturare, dar arata ca alegerea lui Marius nu e arbitrara in suita.

1. CORESP_CONT_VENCHELT exista? Structura, DDL, consumatori

Exista. Nu are CREATE TABLE in arhiva D:\ROA\DATABASE\SCRIPTURI_CLAR (arhiva incepe 2009-2010, tabelul e mai vechi — acelasi motiv pentru care NOTE_CONTABILE/CRM_NOTE_VANZARI nu au CREATE TABLE in arhiva, documentat deja in cont_venit_corespondente.md).

Coloane confirmate din ALTER TABLE + CREATE OR REPLACE VIEW (cronologic):

  • CONT, CONT_CHELT, CONT_VENIT, STERS — preexistente arhivei (folosite direct in view-ul din 2010 fara ALTER TABLE premergator vizibil).
  • CONT_APROVIZIONARE varchar2(4) — adaugata 19.02.2010 (D:\ROA\DATABASE\SCRIPTURI_CLAR\2010\02\ff_2010_02_19_03_GESTIUNI.sql:9: alter table CORESP_CONT_VENCHELT add CONT_APROVIZIONARE varchar2(4);).
  • CONT_DIFERENTE varchar2(4) — adaugata 05.02.2015 (D:\ROA\DATABASE\SCRIPTURI_CLAR\2015\02\ff_2015_02_05_01_GESTIUNE.sql:6-7: alter table coresp_cont_venchelt add cont_diferente varchar2(4); + comment on column CORESP_CONT_VENCHELT.cont_diferente is 'cont diferente de pret pe NIR fata de pretul din factura de achizitie (ex: 6588 = 401 sau 308 = 401)';).
  • Nu am gasit ID_CCV/DATAORAS in DDL-ul cercetat (cautare directa, zero rezultate in SCRIPTURI_CLAR) — interogarea din decizia 27 (select id_ccv, cont, cont_chelt, cont_venit, sters, dataoras, cont_aprovizionare, cont_diferente from coresp_cont_venchelt) le presupune, dar tabelul fiind pre-arhiva, DDL-ul complet nu e in cod static. Ramane de verificat pe baza vie (vezi sectiunea finala) — probabil ID_CCV e cheia surogat (PK) si DATAORAS un timestamp tehnic, tipar comun in suita ROA pentru tabelele de configurare, dar neconfirmat din DDL.
  • Toate coloanele CONT* sunt varchar2(4) (confirmat din ALTER TABLE explicit pentru CONT_APROVIZIONARE/CONT_DIFERENTE; consistent cu tratarea lor ca cod de cont in tot codul citit).

View-ul consumat de VFP, VCORESP_CONT_VENCHELT, filtreaza deja STERS = 0 (deci VFP nu mai trebuie sa filtreze separat):

-- D:\ROA\DATABASE\SCRIPTURI_CLAR\2015\02\ff_2015_02_05_01_GESTIUNE.sql:10-13
create or replace view vcoresp_cont_venchelt as
select cont, cont_chelt, cont_venit, cont_aprovizionare, cont_diferente
  from coresp_cont_venchelt
 where sters = 0;

Populare cu date reale — CONT_VENIT e completat, nu doar declarat. Migrare dedicata 23.02.2023 (D:\ROA\DATABASE\SCRIPTURI_CLAR\2023\02\ff_2023_02_23_01_COMUN.sql:1-21, titlul chiar din fisier: -- Completare cont venit pe corespondenta 3xx - 6xx/7xx):

update CORESP_CONT_VENCHELT set cont_venit = '707' where cont = '301';
update CORESP_CONT_VENCHELT set cont_venit = '707' where cont = '302';
update CORESP_CONT_VENCHELT set cont_venit = '707' where cont = '3021';
... (3022,3023,3024,3025,3026,3028, 303 -> tot '707')
update CORESP_CONT_VENCHELT set cont_venit = '711' where cont = '331';
update CORESP_CONT_VENCHELT set cont_venit = '711' where cont = '332';
update CORESP_CONT_VENCHELT set cont_venit = '702' where cont = '341';
update CORESP_CONT_VENCHELT set cont_venit = '7015' where cont = '345';
update CORESP_CONT_VENCHELT set cont_venit = '703' where cont = '346';
update CORESP_CONT_VENCHELT set cont_venit = '7015' where cont = '348';
update CORESP_CONT_VENCHELT set cont_venit = '7018' where cont = '361';
update CORESP_CONT_VENCHELT set cont_venit = '707' where cont = '371';
update CORESP_CONT_VENCHELT set cont_venit = '707' where cont = '381';

Deci pentru conturile de gestiune uzuale (marfuri 371/381, materii prime 301-303/3021-3028, produse finite 345/348, semifabricate 341, animale 346, ambalaje 381) exista deja o valoare CONT_VENIT configurata in Oracle, de 3 ani. Datele exista — intrebarea e doar cine le citeste.

Ecran de configurare in VFP: NU exista. Cautare exhaustiva CORESP_CONT_VENCHELT (case-insensitive) in D:\ROA\ROAFACTURARE\COMUN -> exact 3 fisiere, niciunul un formular de editare:

  • COMUN\clase\ointroduceri.vc2:2 — un comentariu de istoric (19.02.2010, mentioneaza crsconfigcvc (coresp_cont_venchelt)), nu cod.
  • COMUN\programe\ointroduceri.prg:733 (procedura update_corespondente_cvc, citata integral mai jos) — un SELECT care reincarca un cursor local, nu scrie in tabel.
  • COMUN\programe\updateserver.prg:733 — acelasi SELECT, alt loc de apel.
-- COMUN\programe\ointroduceri.prg:727-743
Procedure update_corespondente_cvc
	If Used('crsconfigcvc')
		Use In crsconfigcvc
	Endif
	*!* 19.02.2010
	lcSql = [select cont,cont_chelt,cont_venit, cont_aprovizionare, cont_diferente from vcoresp_cont_venchelt order by cont]
	*!* 19.02.2010 ^
	lnSucces = goExecutor.oExecute(lcSql,[crsconfigcvc])
	If lnSucces < 0
		amessagebox(goExecutor.cEroare,16,"Eroare")
	Endif
	goExecutor.oReset()
	Return lnSucces
Endproc

Deci tabelul e intretinut exclusiv prin scripturi SQL manuale (cele din SCRIPTURI_CLAR, rulate de un DBA/dezvoltator la nevoie), nu printr-un formular VFP — la fel ca alte tabele tehnice de configurare mai vechi din suita. Nu exista niciun INSERT INTO CORESP_CONT_VENCHELT in arhiva (randurile de baza, CONT/CONT_CHELT/CONT_VENIT, predateaza arhiva); doar UPDATE/ALTER TABLE pentru coloanele adaugate ulterior (CONT_APROVIZIONARE in 2010, CONT_DIFERENTE in 2015, valorile CONT_VENIT in 2023).

2. Cheia de cautare

CONT = contul de gestiune al liniei, mereu. Confirmat prin 4 exemple reale de JOIN, in module diferite:

  • pack_vin (D:\ROA\DATABASE\SCRIPTURI_CLAR\2023\07\ff_2023_07_18_02_VIN_PACK_VIN.sql:1579-1589, procedura inregistreaza_materiale):
    FROM (SELECT SUM(...) as suma, A.CONT as SCC, A.ACONT as ASCC, A.ID_GESTIUNE
            FROM VIN_RULAJE_TEMP A WHERE A.TIP = V_TIP
           GROUP BY A.ID_GESTIUNE, A.CONT, A.ACONT) A
      LEFT JOIN CORESP_CONT_VENCHELT B
        ON A.SCC = B.CONT
       AND B.STERS = 0;
    
    aici A.SCC e de fapt contul de gestiune (aliasul SCC vine din contextul rulajului de stoc, nu din NOTE_CONTABILE) — deci join-ul e tot cont_gestiune = B.CONT.
  • pack_devize (14+ aparitii identice intre 2013-2014, ex. D:\ROA\DATABASE\SCRIPTURI_CLAR\2014\01\ff_2014_01_22_01_DEVIZE_PACK_DEVIZE.sql:3214-3217):
    from rul_temp a
    left join coresp_cont_venchelt b
      on a.cont = b.cont
     and b.sters = 0
    
    rul_temp.cont e contul de gestiune al articolului din rulajul de stoc.
  • gestiune_pack_gest_import (5+ aparitii 2013-2017, ex. D:\ROA\DATABASE\SCRIPTURI_CLAR\2017\05\ff_2017_05_31_01_GESTIUNE_PACK_GEST_IMPORT.sql:512): left join coresp_cont_venchelt b — pe a.cont = b.cont (acelasi tipar).
  • Raport recent, 2026 (D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\07\ff_2026_07_23_01_GESTIUNE_RAPOARTE.sql:25-29, view VRUL_ACT_CHELTUIELI):
    iesiri AS (
      SELECT R.*, CC.CONT_CHELT AS CONT_CHELT_CORESP
        FROM VRUL_TOT R
        LEFT JOIN CORESP_CONT_VENCHELT CC ON CC.CONT = R.CONT AND CC.STERS = 0
       WHERE R.STERS = 0 AND R.CANTE <> 0
    )
    
    cel mai recent consumator gasit (23.07.2026), deci tabelul e inca "viu" in productie — dar CONT_CHELT_CORESP calculat aici nici nu apare in SELECT-ul final al view-ului (e calculat si abandonat), semn ca tiparul de "join pe CONT, ia campul de care ai nevoie" e suficient de standard incat sa fie reutilizat fara alta discutie de design.
  • In VFP: Select crsconfigcvc; Locate For Cont = Upper(Alltrim(...)) — vezi sectiunea 3, mereu aceeasi cheie CONT.

Nu am gasit nicio discriminare suplimentara pe gestiune/tip document. Toate JOIN-urile/LOCATE sunt strict pe CONT (+ STERS = 0), fara ID_GESTIUNE, fara TIP_DOC. ID_CCV nu apare folosit ca FK in niciun cod cercetat — pare o simpla cheie surogata a tabelului, neexpusa in VCORESP_CONT_VENCHELT (view-ul nu o include).

Ambiguitate / mai multe randuri active pentru acelasi CONT: nu exista UNIQUE/PRIMARY KEY vizibil in cod (DDL-ul e pre-arhiva), dar toate cele ~20 de utilizari reale presupun un singur rand activ per CONT — niciun cod cercetat foloseste DISTINCT, ROW_NUMBER(), MAX(...) sau alt mecanism de dezambiguizare pe rezultatul join-ului. Daca ar exista doua randuri active cu acelasi CONT, LEFT JOIN-ul ar multiplica randurile din interogarea principala (risc de dublare de suma in pack_vin/pack_devize) — nu exista protectie in cod contra acestui caz. Presupunerea de unicitate e implicita in tot codul care exista deja, nu doar in propunerea lui Marius.

3. Cine il foloseste azi — CONT_CHELT are 4 module consumatoare, CONT_VENIT are zero

Consumator Fisier Coloana citita
pack_vin.inregistreaza_materiale ff_2023_07_18_02_VIN_PACK_VIN.sql:1567 (si variante 2010/2012/2014) CONT_CHELT
pack_devize (procedura de calcul cost material, 14+ export-uri 2013-2014) ff_2014_01_22_01_DEVIZE_PACK_DEVIZE.sql:3222 (si altele) CONT_CHELT (in GROUP BY, folosit ca SCD)
pack_gest_import (5+ export-uri 2013-2017) ff_2017_05_31_01_GESTIUNE_PACK_GEST_IMPORT.sql:512 CONT_CHELT (deductie din context, tipar identic)
VRUL_ACT_CHELTUIELI (raport, 2026) ff_2026_07_23_01_GESTIUNE_RAPOARTE.sql:26 CONT_CHELT (calculat, needatat in output final)
VFP ointroduceri.vc2 (bon consum, finalizare aprovizionare, transfer) :5476-5490 (oinventar.vc2), :14663-14681, :15327-15332 CONT_CHELT, CONT_APROVIZIONARE
VFP ointroduceri.vc2 (diferente NIR vs factura) :15395-15403 (bloc dezactivat IF .F.) CONT_DIFERENTE (cod comentat/mort, nu ruleaza azi)

Niciun consumator pentru CONT_VENIT — cautare directa CONT_VENIT (case-insensitive) in tot D:\ROA\DATABASE\SCRIPTURI_CLAR (arhiva completa 2009-2026): doar 3 fisiere, toate deja citate (2 view-uri care includ coloana in SELECT fara sa o consume, 1 script de populare cu date). In VFP, cautare cont_venit (case-insensitive) in COMUN si ROAGEST: un singur hit, SELECT ... cont_venit ... in update_corespondente_cvc/updateserver.prg (fetch in cursor), zero utilizari ale campului dupa fetch (nicio referinta .cont_venit/crsconfigcvc.cont_venit gasita).

Concluzie: propunerea lui Marius ar fi primul consumator real al CONT_VENIT in toata suita, desi coloana e populata din 2023. Reteta "citeste corespondenta pe cont de gestiune" e deja rulata in productie de 10+ ani, dar mereu pentru latura CONT_CHELT (cheltuiala la consum de stoc), niciodata pentru CONT_VENIT (venit la vanzare). Riscul tehnic al join-ului (cheie, filtru STERS, tipul LEFT JOIN) e deja validat de utilizarea existenta; riscul de date (daca valorile CONT_VENIT completate in 2023 sunt corecte/complete pentru toate conturile de gestiune folosite azi in facturare, nu doar cele 20 acoperite explicit) e nou si neverificat pe baza vie.

4. Semantica coloanelor

Dedusa din utilizari reale, nu din nume:

  • CONT: contul de gestiune/stoc al liniei (clasa 3xx: 301-303, 331/332, 341, 345/346/348, 361, 371, 381) — cheia de cautare in toate cazurile vazute (sectiunea 2).
  • CONT_CHELT: contul de cheltuiala (6xx) care se debiteaza cand marfa/materialul iese din gestiune (consum, bon de consum, productie) — confirmat de toti cei 4+ consumatori din sectiunea 3, unde e folosit mereu ca SCD (debit) pe o nota de tip "iesire din gestiune".
  • CONT_VENIT: prin simetrie de nume si migrarea din 2023 ("cont venit pe corespondenta 3xx-7xx"), e menit sa fie contul de venit (7xx) corespunzator vanzarii aceluiasi cont de gestiune — dar nu are niciun consumator care sa confirme comportamentul in executie (nicio ramura de cod care sa arate ce se intampla la NULL, la vanzare partiala, la retur). Semantica e dedusa din nume + date, nu din utilizare, contrar regulii "nu presupune semantica dupa nume" — de aceea marchez ca ipoteza, nu fapt verificat pe comportament.
  • CONT_APROVIZIONARE: contul folosit la operatia "finalizare aprovizionare" (ID_SET 264/265), cand se transfera valoarea din contul de tranzit (401 sau alt cont de gestiune) intr-un cont de gestiune specific de tranzit intern (32x) — confirmat de comentariul din DDL 2010 si de utilizarea in ointroduceri.vc2:15323-15332 (Case Alltrim(Upper(oSet.explicatia)) = 'FINALIZARE APROVIZIONARE' ... lcContC = Alltrim(cont_aprovizionare)).
  • CONT_DIFERENTE: contul folosit pentru diferentele de pret intre NIR si factura de achizitie — confirmat de comentariul DDL 2015 ("cont diferente de pret pe NIR fata de pretul din factura de achizitie, ex: 6588 = 401 sau 308 = 401") si de codul ointroduceri.vc2:15394-15403, dar acel bloc e dezactivat (IF .F. THEN ... ENDIF), deci in executia curenta ramane mereu fallback-ul hardcodat '6588' — dovada ca chiar si un camp cu semantica clara si comentariu explicit poate ajunge neutilizat in productie, ceea ce intareste incertitudinea despre CONT_VENIT.
  • STERS: flag boolean soft-delete, filtrat explicit = 0 in toate utilizarile gasite (view-ul VCORESP_CONT_VENCHELT il filtreaza deja la nivel de view; join-urile Oracle directe pe tabel il filtreaza explicit AND B.STERS = 0/AND CC.STERS = 0). Niciun cod cercetat citeste randuri cu STERS = 1.
  • DATAORAS: nu apare in niciun cod cercetat (Oracle sau VFP) — nu am gasit nicio referinta directa la aceasta coloana in afara interogarii propuse in decizia 27. Tipic in suita ROA e un timestamp tehnic de audit (data ultimei modificari a randului), dar neconfirmat aici — ramane de verificat pe schema vie.
  • Ambiguitate pe CONT: vezi sectiunea 2 — niciun cod nu trateaza cazul "mai multe randuri active pentru acelasi CONT"; presupunerea de unicitate e implicita, nu impusa de o constrangere vizibila.

5. NOM_ARTICOLE.CONT pentru articole negestionabile si fallback pe 704

  • NOM_ARTICOLE.CONT nu e restrans la clasa 3 — reconfirmat (vezi deja cont_venit_corespondente.md sectiunea 2): validarea verific_cont (COMUN\programe\oproceduri_comune.prg:2389-2415) verifica doar ca contul exista in planul de conturi al anului, fara filtru de clasa; niciun CHECK CONSTRAINT in DDL. Deci campul poate contine legitim un cont 6xx/7xx pentru un articol negestionabil, exact cum presupune decizia 27.
  • Niciun fallback pe 704 existent in pack_facturare — cautare '704' (literal SQL) in D:\ROA\ROAFACTURARE\docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql (17000+ linii, exportul curent al pachetului): zero rezultate. Cautare in tot D:\ROA\DATABASE\SCRIPTURI_CLAR\2026 (toate scripturile din 2026): zero rezultate. Fallback-ul pe 704 propus de Marius ar fi cod nou, nu o reteta deja scrisa in pack_facturare.
  • Exista totusi un precedent independent pentru 704 ca "cont implicit de venit", in alt subsistem:
    COMUN\clase\anaf_efactura.vc2:8370-8376  (clasa "frm_configurare_efactura")
    *p: cconte		&& cont implicit articol client
    *p: ccontp		&& cont implicit articol furnizor
    ...
    cconte = 704
    ccontp = 628
    
    E o proprietate cu valoare implicita 704 ("cont implicit articol client", deci un cont de venit implicit pentru liniile generate la import eFactura) intr-un ecran de configurare a modulului ANAF eFactura. Nu am gasit cod care sa citeasca explicit .cconte (cautare \.cconte\b in tot COMUN: zero rezultate) — proprietatea e definita cu valoare implicita, dar consumatorul ei concret n-a fost gasit in timpul alocat (posibil legat generic la un camp de configurare cu acelasi nume, tipar comun in suita, dar neconfirmat aici). Ce arata cu certitudine: alegerea 704 ca implicit pentru "cont articol client" nu e o inventie a acestei cereri — a mai fost aleasa o data, independent, de altcineva din echipa (sau de Marius insusi, in alt moment), pentru un scop asemanator. Nu e insa o reteta de cod reutilizabila direct in pack_facturare — e in alt pachet/clasa, alt flux (import, nu emitere).

6. Punctul de injectie in contabilizeaza_articol

Sursa: D:\ROA\ROAFACTURARE\docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql (exportul curent al pachetului, 17548+ linii). Numerotarea de mai jos e din acest fisier, verificata prin citire directa (difera cu cateva linii fata de exportul mai vechi citat in rapoartele anterioare, care avea FACT-024 la 7301 in loc de 7311 — normal, fisierul a mai fost actualizat intre timp).

Structura exacta a blocului care ridica FACT-024 (:7275-7302, inceputul functiei):

7275  BEGIN
7276
7277    -- 05.07.2011
7278    BEGIN
7279      SELECT COMPUS, ID_POL_ART
7280        INTO V_COMPUS, V_ID_POL_ART
7281        FROM VCRM_POLITICI_PRET_ART
7282       WHERE ID_ARTICOL = detalii_articol.id_articol
7283         AND ID_POL = detalii_articol.id_pol;
7284    EXCEPTION
7285      WHEN NO_DATA_FOUND THEN
7286        SELECT DENUMIRE
7287          INTO lcArticol
7288          FROM NOM_ARTICOLE
7289         where id_articol = detalii_articol.id_articol;
7290
7291        SELECT NUME_LISTA_PRETURI
7292          INTO lcPolitica
7293          FROM CRM_POLITICI_PRETURI
7294         where id_pol = detalii_articol.id_pol;
7295
7296        RAISE_APPLICATION_ERROR(-20000,
7297                                'Articolul ' || detalii_articol.id_articol || '|' ||
7298                                lcArticol ||
7299                                ' nu este definit in politica de preturi ' ||
7300                                detalii_articol.id_pol || '|' || lcPolitica ||
7301                                '! (FACT-024)');
7302    END;

Acesta e locul unde s-ar decide "articolul nu are politica" — dar NU e suficient sa se schimbe doar acest bloc. Motivul, cu citate exacte:

  1. Dupa acest bloc, codul verifica IF V_COMPUS = 1 THEN (articol compus, :7305, ridica alta eroare, FACT-016) ELSE (:7391) — ramura "articol simplu" care e cea relevanta pentru cazul cerut.
  2. Ramura "articol simplu" deschide un cursor nou, cursor_articol (definit la :7218-7271), filtrat exact pe aceeasi cheie care a dat NO_DATA_FOUND mai sus:
    7261  FROM CRM_POLITICI_PRET_ART A
    ...
    7268   WHERE
    7269  -- A.STERS = 0 AND
    7270  A.ID_POL = detalii_articol.id_pol
    7271  AND A.ID_ARTICOL = detalii_articol.id_articol;
    
  3. Tot corpul de lucru real (calculul V_SCD/V_ASCD/V_SCC/V_ASCC/V_EXPLICATIE, apelul pack_facturare.scrie_nota(...) la :7443-7467, apelul pack_facturare.descarca_gestiune(...) la :7476-7498, scrierea discountului la :7501-7518) e in interiorul WHILE cursor_articol%FOUND LOOP (:7396-7541). Daca articolul nu are politica de pret, acest cursor nu returneaza niciun rand (e exact aceeasi conditie care a dat NO_DATA_FOUND la pasul 1, pe acelasi (id_pol, id_articol)), deci bucla ruleaza zero iteratii.

Concluzia tehnica: daca s-ar modifica doar blocul EXCEPTION WHEN NO_DATA_FOUND (pasul 1) ca sa nu mai ridice RAISE_APPLICATION_ERROR si sa lase V_COMPUS := 0 implicit, executia ar trece la ramura "articol simplu", ar deschide cursor_articol, acesta ar gasi tot zero randuri (aceeasi cauza), bucla nu ar rula deloc, si functia ar reveni RETURN V_INCASAT_CALCUL cu valoarea initiala 0 (declarata la :7178), fara sa scrie nicio nota contabila si fara sa descarce gestiunea — silentios, fara nicio eroare. Asta e o regresie mai grava decat FACT-024: azi tranzactia se opreste vizibil; cu un fallback naiv, factura s-ar emite fara inregistrare contabila si fara descarcare de stoc, nedetectabil fara audit manual.

Ce ar cere de fapt fallback-ul, pentru a pastra comportamentul actual cand politica exista:

  • Blocul de la pasul 1 ar trebui sa distinga explicit cazul "politica lipseste" (continua cu fallback) de cazul "articol compus fara politica" (probabil tot eroare, nu e in scopul cerut) — posibil punand un flag local (V_ARE_POLITICA := FALSE) in loc de RAISE_APPLICATION_ERROR.
  • Ar trebui adaugata o ramura noua, in afara/inainte de bucla cursor_articol, activa doar cand V_ARE_POLITICA = FALSE, care sa:
    • calculeze V_SCD/V_ASCD reutilizand CASE-ul existent pe tip document (:7398-7423 — acesta nu depinde de cursor_articol, poate fi extras/reutilizat identic);
    • calculeze V_SCC din sursa noua (corespondente pentru articol gestionabil / NOM_ARTICOLE.CONT sau 704 pentru negestionabil) — doar acest pas e cel descris de decizia 27;
    • decida un V_ASCC (azi vine din NVL(crs_rand_articol.ascc, GetAnaliticByGrupUtilizatori(...)) — fara rand din cursor, ar trebui sa cada direct pe GetAnaliticByGrupUtilizatori(...), posibil fara modificare, pentru ca aceasta functie nu depinde de cursor);
    • decida V_EXPLICATIE, ID_VENCHELT, ID_SECTIE, CU_TVA, IN_VALUTA — vezi sectiunea 7, aici e gaura reala, nu doar cod de rescris.
    • apeleze explicit pack_facturare.scrie_nota(...) si, conditionat, descarca_gestiune(...), cu parametrii calculati mai sus, duplicand (nu reutilizand) logica din interiorul buclei existente.

Asta confirma exact avertismentul din decizia 27 insasi ("modificare in COMUN, cu impact peste toata suita") — nu e un IF adaugat pe o linie, e o ramura noua de ~40-60 linii care trebuie sa reproduca o parte din logica ramurii existente, cu surse diferite pentru fiecare camp.

7. Ce se pierde fata de lantul complet CRM_POLITICI_PRET_ART -> ... -> NOTE_CONTABILE

Aceasta e partea centrala a raspunsului: fallback-ul pe cont de venit (corespondente + nomenclator + 704) acopera doar SCC, nu si restul campurilor pe care lantul de politica de pret le aduce azi din NOTE_CONTABILE fara efort. Campurile aduse azi de D.EXPLICATIE, D.SCD, D.ASCD, D.SCC, D.ASCC, D.CU_TVA, D.IN_VALUTA (cursor_articol, :7248-7253, 7259-7260) si ce se intampla cu fiecare fara politica:

  • SCD/ASCD (contul debitor si analiticul lui): nu se pierde — V_SCD se calculeaza deja independent de NOTE_CONTABILE, dintr-un CASE pe tipul de document (:7398-7423, ex. 461 pt aviz catre debitori, 418 pt aviz simplu, crs_rand_articol.scd doar pt factura normala — dar acesta din urma tot vine din NOTE_CONTABILE.SCD prin cursor, deci pt factura normala SCD s-ar pierde la fel ca SCC). Corectie necesara fata de formularea initiala a intrebarii: nu doar SCC vine din NOTE_CONTABILE pt factura normala — si SCD (contul de creante, tipic 411) vine de acolo. Decizia 27 vorbeste doar de "cont de venit", nu de contul debitor — inseamna ca si sursa lui V_SCD pentru factura normala ar trebui rezolvata (probabil un cont fix, gen 411/4111, dar nu e in scopul deciziei 27 asa cum e formulata azi).
  • CU_TVA: se pierde, fara alta sursa in cod. Controleaza daca pretul de pe linie e interpretat cu sau fara TVA la scrierea sumei (pack_facturare.scrie_nota(...), parametru crs_rand_articol.cu_tva la :7463). Nu exista nicio coloana echivalenta in CORESP_CONT_VENCHELT sau NOM_ARTICOLE. Fara ea, fallback-ul trebuie sa aleaga o valoare hardcodata sau sa o deriveze din alt camp deja disponibil pe detalii_articol (ex. pret_cu_tva, vazut ca parametru separat la :7447 — posibil suficient, dar necesita verificare separata, nu facuta aici).
  • IN_VALUTA: se pierde, fara alta sursa. Controleaza daca linia e tratata ca fiind in valuta la nivel de nota contabila (V_IN_VALUTA := crs_rand_articol.in_valuta; la :7470, folosit apoi la discount :7507). La fel ca CU_TVA, nicio coloana echivalenta in corespondente/nomenclator.
  • EXPLICATIE: se pierde ca sablon configurat, dar are deja fallback partial in cod — V_EXPLICATIE e calculat cu un CASE pe tipul de operatie (:7430-7439, ex. concateneaza pack_facturare.cdescriere pt facturi tip 7) folosind crs_rand_articol.explicatie ca baza; fara cursor, baza ar fi goala/NULL, dar structura CASE insasi nu depinde de cursor — impact moderat, nu blocant.
  • ID_VENCHELT: are deja un fallback la nivel de sesiune — NVL(pack_facturare.nid_venchelt, NVL(A.ID_VENCHELT, C.ID_VENCHELT)) (:7244-7245) — daca pack_facturare.nid_venchelt e setat global (parametru de sesiune), fallback-ul functioneaza deja fara politica; daca nu e setat, ramane NULL (fara eroare in cod, dar posibil relevant pentru rapoarte care folosesc aceasta dimensiune, neverificat).
  • ID_SECTIE: acelasi tipar — NVL(pack_facturare.nid_sectie_stoc, C.ID_SECTIE) (:7246), cu fallback pe variabila de sesiune.
  • ID_SET (identificatorul setului de nota folosit la scriere): nu se pierde — parametrul trimis efectiv la scrie_nota e pack_facturare.nid_set (variabila de sesiune, :7462), nu crs_rand_articol.id_set din cursor (acel camp e citit la :7247 dar nu e folosit la apelul de scriere in ramura articol simplu — verificat direct in cod). Deci acest camp special nu depinde de politica de pret.

Rezumat sectiunea 7: din cele 7 campuri aduse de lantul politicii de pret, 2 (ID_VENCHELT, ID_SECTIE) au deja fallback pe variabile de sesiune si ar functiona fara politica; EXPLICATIE are impact moderat (structura de calcul ramane, doar baza se pierde); ID_SET nu depinde deloc de politica in ramura articol simplu; dar CU_TVA si IN_VALUTA nu au nicio sursa alternativa — sunt gaura reala pe care simpla adaugare a unui cont de venit din corespondente/nomenclator nu o umple. Confirmarea finala a intrebarii din cerere: da, fallback-ul pe cont de venit e insuficient pentru o nota contabila completa — nu pentru ca "SCC" ar fi gresit, ci pentru ca doua campuri de control (TVA, valuta) raman fara sursa.

8. Varianta VFP, fara sa se atinga pack_facturare (plan A, cerut de Marius)

Ideea de verificat: daca contabilizeaza_articol deriva SCC din id_pol, VFP ar putea sa aleaga singur, inainte de a trimite articolul, un id_pol a carui nota are deja SCC = contul de venit calculat dupa regula lui Marius — pachetul ar rula neschimbat. Raspunsul, punct cu punct:

a) id_pol vine din VFP? Da — e trimis explicit, pe fiecare linie

Semnatura efectiva a procedurii apelate pe fluxul principal (verificat direct in export, nu presupus):

D:\ROA\ROAFACTURARE\docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:4989-5015
PROCEDURE adauga_articol_factura(V_ID_TEMP             IN NUMBER,
                                 V_ID_ARTICOL          IN NUMBER,
                                 V_SERIE               IN VARCHAR2,
                                 V_EXPLICATIE          IN VARCHAR2,
                                 V_ID_POL              IN NUMBER,
                                 V_ID_GESTIUNE         IN NUMBER,
                                 ...
                                 V_CONT                IN VARCHAR2,
                                 ...

V_ID_POL e parametru de intrare explicit — Oracle nu il deriva din client/contract/tip document, il primeste ca atare de la VFP. Niciun alt parametru din aceasta lista nu ofera un canal pentru SCC/id_set (raspuns si la punctul d — vezi mai jos).

De unde il ia azi VFP: din controlul de cautare obligatoriu al formularului frm_articol_factura (clasa ofacturare.vc2):

COMUN\clase\ofacturare.vc2:6822-6825
ADD OBJECT 'Ct_clb_politici_preturi' AS ct_clb_cautare WITH ;
    cconditie = ISNULL(poDate.id_pol) or EMPTY(poDate.id_pol), ;
    cprocedura = thisform.do_cauta_politica, ;
    cvar_afisata = poDate.nume_politica, ...
COMUN\clase\ofacturare.vc2:7167-7182
PROCEDURE do_cauta_politica
    Local loCauta
    loCauta = caut_politici_curente_util()
    If !Isnull(loCauta) And !Empty(Nvl(loCauta.id_pol,0))
        poDate.id_pol = loCauta.id_pol
        poDate.nume_politica = loCauta.nume
        ...

cconditie = ISNULL(poDate.id_pol) or EMPTY(poDate.id_pol) e exact starea "articol fara politica" din cererea #13 — controlul UI cere explicit utilizatorului sa caute o politica cand campul e gol. VFP controleaza integral valoarea: azi vine din alegerea utilizatorului, dar nimic tehnic nu impiedica sa fie setata programatic, fara interactiune, la un id_pol calculat.

b) Drumul invers e interogabil? Da — e simetricul exact al cursorului deja documentat la sectiunea 6

Cursorul din contabilizeaza_articol (ff_...:7261-7267) merge CRM_POLITICI_PRET_ART -> CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI -> NOTE_CONTABILE prin A.ID_POL = B.ID_POL, B.ID_NOTA = C.ID_NOTA, C.ID_SET = D.ID_SET. Interogarea inversa, plecand de la un SCC dorit catre id_pol-urile candidate, foloseste aceleasi coloane de legatura, doar fara filtrul pe articol:

SELECT DISTINCT PP.ID_POL
  FROM CRM_POLITICI_PRETURI PP
  JOIN CRM_NOTE_VANZARI NV ON NV.ID_NOTA = PP.ID_NOTA
  JOIN NOTE_CONTABILE NC   ON NC.ID_SET  = NV.ID_SET
 WHERE NC.SCC = :cont_venit_calculat;   -- '707'/'711'/'702'/'703'/'7015'/'7018' (gestionabil) sau valoarea din NOM_ARTICOLE.CONT/'704' (negestionabil)

E o interogare noua (nu am gasit-o deja scrisa nicaieri in cod), dar foloseste exclusiv coloane si relatii deja confirmate ca existente si corecte (sectiunea 1 din cont_venit_corespondente.md + citirea directa a cursor_articol la sectiunea 6 a acestui raport). Neverificat pe date reale: cate randuri returneaza pentru fiecare SCC candidat — zero (nicio politica configurata cu acel SCC azi), unul (cazul ideal) sau mai multe (ambiguitate: care id_pol se alege?). Interogarea de rulat pe baza vie e chiar cea de mai sus, cu :cont_venit_calculat inlocuit pe rand cu 707, 711, 702, 703, 7015, 7018, 704.

c) Se poate insera din VFP un rand in CRM_POLITICI_PRET_ART? Da — cod existent, functional, deja rulat in productie

Doua mecanisme distincte, ambele reale:

c1. RPC direct, apelabil din VFP azi — pack_preturi.adauga_politica_pret_art, apelat din ofacturare.vc2 in procedura de modificare a listei de preturi la NIR (ID_SET = 231):

COMUN\clase\ofacturare.vc2:15551-15587
*!* verific daca exista articolul in politica de preturi
lcSql = [Select id_pol_art, id_venchelt, proc_tvav from crm_politici_pret_art where id_pol = ] + Alltrim(Str(tnIdPol)) + [ and id_articol = ] + Alltrim(Str(tnIdArticol))
lnSucces = goExecutor.oExecute(m.lcSql, "cPoliticiPretArt")
...
If Nvl(loPoliticaPretArt.id_pol_art,0) = 0
    lcSql = [begin pack_preturi.adauga_politica_pret_art(] + ;
        ALLTRIM(Str(tnIdPol)) + [,] + ;          && id_pol
        Alltrim(Str(tnIdArticol)) + [,] + ;      && id_articol
        Alltrim(Str(tnPretLista,20,4)) + [,] + ; && pret
        Alltrim(Str(tnPretftvaLista,20,4)) + [,] + ;  && pretftva
        Alltrim(Str(tnPretvtvaLista ,20,4)) + [,] + ; && pretctva
        [NULL, ] + ;                              && id_valuta
        Alltrim(Str(tnProcTvav,20,4)) + [,] + ;   && proc_tvav
        [NULL, ] + ;                               && procent
        [NULL, ] + ;                               && id_venchelt
        Alltrim(Str(gnIdUtil)) + ;                 && id_util
        [); end;]

Verifica intai daca exista deja un rand (id_pol, id_articol), si daca nu, insereaza unul nou prin RPC existent — exact tiparul necesar pentru punctul (c): "adauga articolul X in politica de pret Y", apelabil din VFP fara nicio modificare de pachet (pack_preturi nu e pack_facturare).

c2. Auto-populare in masa, deja existenta in pack_facturare insusi, dar fara parametru nou — o procedura care nu ar necesita nicio modificare de cod pentru ca deja exista si e apelabila ca atare:

D:\ROA\ROAFACTURARE\docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:2093-2120
PROCEDURE completare_politica_stoc IS
BEGIN
  IF pack_facturare.nid_politica_stoc IS NOT NULL THEN
    MERGE INTO CRM_POLITICI_PRET_ART A
    USING (SELECT ID_ARTICOL FROM NOM_ARTICOLE
            WHERE STERS = 0 AND INACTIV = 0 AND IN_STOC = 1) B
    ON (A.ID_POL = pack_facturare.nid_politica_stoc AND A.ID_ARTICOL = B.ID_ARTICOL)
    WHEN NOT MATCHED THEN
      INSERT (ID_POL, ID_ARTICOL, ID_VALUTA)
      VALUES (pack_facturare.nid_politica_stoc, B.ID_ARTICOL, pack_facturare.nid_moneda_nationala);
    ...
  END IF;
END completare_politica_stoc;

Aceasta e o functie existenta, apelabila fara nicio modificare, care garanteaza deja un rand in CRM_POLITICI_PRET_ART pentru orice articol cu IN_STOC = 1 sub o singura politica "de stoc" (pack_facturare.nid_politica_stoc). Acest id_pol e la randul lui o optiune de configurare controlata din VFP:

COMUN\clase\ofacturare.vc2:21733-21734  (Init-ul ecranului de optiuni facturare)
actualizeaza_politica_pret(23,@gnId_pol_pret_tr,@lcPolPretTr)
actualizeaza_politica_pret(1,@gnId_pol_pret_stoc,@lcPolPretStoc)
...
COMUN\clase\ofacturare.vc2:21753
This.nidpolpretstoc = Nvl(gnId_pol_pret_stoc,0)

gnId_pol_pret_stoc e o optiune globala (ID_POL_PRET_STOC, salvata/citita prin actualizeaza_politica_pret), care alimenteaza pack_facturare.nid_politica_stoc la initializarea sesiunii Oracle. Avertisment: aceasta politica pare deja folosita azi pentru un scop specific (vanzare/evaluare la pret de stoc — nin_valuta, nTipVanzareRetail sunt tratate diferentiat pentru ea la ff_...:7223-7260), cu o singura nota/SCC configurata pentru toate articolele IN_STOC=1. Nu e direct reutilizabila pentru reteta pe 6 conturi diferite (707/711/702/703/7015/7018) ceruta de decizia 27 — dar arata modelul exact ("o politica tehnica, configurata o singura data, populata automat"), model care se poate replica de cate ori e nevoie (o politica tehnica per SCC distinct), fara sa se toate cod in pack_facturare.

d) Alte cai de bypass la nivel de parametru — cautate explicit, nu gasite

Semnatura completa a adauga_articol_factura (sectiunea a) si a variantelor _deviz/_stoc (deja citate in cont_venit_articol_fara_politica.md) nu au niciun parametru pentru cont de venit sau id_set direct — singurul levier disponibil la nivelul acestui apel e V_ID_POL. Nu exista un parametru V_SCC/V_ID_SET/V_COD_VENIT pe nicio varianta citita. Concluzie: id_pol e singura cale de influenta din VFP asupra contului de venit, exact premisa din care a pornit intrebarea.

e) Verdict onest

Cale VFP posibila, dar nu "zero cod" si nu fara pasi de configurare o singura data:

  1. VFP calculeaza SCC-ul dorit exact ca in decizia 27 (interogare simpla, deja tipul de cod scris in update_corespondente_cvc — sectiunea 1 a acestui raport): CORESP_CONT_VENCHELT.CONT_VENIT pe contul de gestiune pentru articol gestionabil, NOM_ARTICOLE.CONT (daca e 6xx/7xx) sau '704' pentru negestionabil.
  2. VFP cauta (interogarea de la punctul b) o id_pol existenta a carei nota are deja acel SCC. Daca gaseste una (plauzibil pentru conturile comune 707/711/702/703, care probabil se folosesc deja in politici de pret reale ale firmei) — trece la pasul 3 direct, fara nicio configurare noua.
  3. VFP se asigura (RPC pack_preturi.adauga_politica_pret_art, punctul c1, deja existent) ca exista un rand CRM_POLITICI_PRET_ART pentru (acel id_pol, articolul curent) — insereaza unul cu pretul tastat manual de utilizator (tnPretLista = pretul liniei) daca nu exista.
  4. VFP trimite acel id_pol in adauga_articol_factura, exact ca pe fluxul actual (cu politica). contabilizeaza_articol ruleaza neschimbat — si, bonus fata de varianta plan B (sectiunea 7), campurile CU_TVA/IN_VALUTA/EXPLICATIE/ASCD/ASCC vin corect din nota reala configurata, nu raman goale ca in fallback-ul partial din pachet.

Ce nu e gratuit:

  • Pasul 2 poate rata (nicio politica existenta cu acel SCC) — pentru un SCC fara precedent (de ex. 704, pentru care nu am gasit nicio nota configurata azi, sectiunea 5), ar trebui creat manual, o singura data, un lant nou CRM_POLITICI_PRETURI + CRM_NOTE_VANZARI + NOTE_CONTABILE (contabilul configureaza nota din frm_config_note_contabile[2007], deja documentat in cont_venit_corespondente.md sectiunea 1) — asta e configurare (ecran existent), nu cod nou, dar e un pas manual, nu automat.
  • Efect lateral real: o "politica tehnica" (creata special pentru acest mecanism) ar aparea in ecranul de cautare politici al utilizatorului (caut_politici_curente_util(), aceeasi functie folosita la cautarea normala) — trebuie fie exclusa explicit din acel cursor de cautare (filtru pe un flag/prefix dedicat), fie acceptata ca vizibila, cu riscul ca un utilizator sa o aleaga din greseala pentru o factura normala. Nu am verificat daca caut_politici_curente_util() are deja un filtru care ar exclude automat politici fara preturi reale/marcate altfel.
  • Ambiguitatea de la pasul 2 (mai multe id_pol cu acelasi SCC) ar cere o regula de departajare (cea mai recenta? prima gasita? o marcare explicita "politica implicita pentru SCC X"?) — neverificat pe date reale, vezi sectiunea "Ramas de verificat".
  • Aceasta varianta schimba id_pol-ul scris pe linie (azi NULL/gol pentru articol fara politica, ar deveni id-ul politicii tehnice) — orice raport/ecran care azi presupune "id_pol gol = articol fara politica" (de ex. eventuale filtre in rapoarte de vanzari) ar vedea un id_pol populat; nu am gasit cod care sa faca aceasta presupunere explicit, dar nici n-am cautat-o exhaustiv (in afara bugetului).

Concluzie e): nu e nevoie de "niciuna dintre cai" pentru un "nu" — exista o cale VFP verificabila si construita din piese deja functionale in productie (RPC de inserare in politica de pret, plus o interogare de cautare inversa noua dar directa). E fezabila, probabil mai completa decat plan B (rezolva si CU_TVA/IN_VALUTA, nu doar SCC), dar cere: (i) o interogare noua de cautare id_pol pe SCC, (ii) reutilizarea unui RPC existent pentru inserarea articolului in politica, (iii) potential configurare manuala o singura data (nota noua) pentru SCC-urile fara precedent, (iv) o decizie explicita despre cum se exclude/trateaza politica tehnica in ecranele de cautare vizibile utilizatorului.

Ramas de verificat pe baza de date vie

  • Structura completa DDL a CORESP_CONT_VENCHELT (DESC coresp_cont_venchelt sau echivalent): confirmarea coloanelor ID_CCV (probabil PK surogat) si DATAORAS (probabil timestamp tehnic), tipurile exacte, nullability, si daca exista o constrangere UNIQUE/index pe CONT (relevant pentru ambiguitatea discutata in sectiunea 2 si 4) — DDL-ul nu e in arhiva SCRIPTURI_CLAR (tabel pre-2009). Interogare de verificat: SELECT column_name, data_type, nullable FROM user_tab_columns WHERE table_name = 'CORESP_CONT_VENCHELT' ORDER BY column_id; si SELECT index_name, uniqueness FROM user_indexes WHERE table_name = 'CORESP_CONT_VENCHELT';.
  • Continutul complet al CONT_VENIT — migrarea din 2023 acopera 20 de conturi de gestiune; ramane de verificat daca acopera toate conturile de gestiune folosite azi in NOM_ARTICOLE.CONT/STOC.CONT in productie (altfel fallback-ul ar produce CONT_VENIT = NULL pentru conturi de gestiune neacoperite). Interogare: SELECT DISTINCT cont FROM (SELECT cont FROM nom_articole UNION SELECT cont FROM stoc) WHERE cont NOT IN (SELECT cont FROM coresp_cont_venchelt WHERE sters = 0);.
  • Daca exista mai mult de un rand activ (STERS = 0) pentru acelasi CONT — cod critic pentru join-uri fara dezambiguizare. Interogare: SELECT cont, COUNT(*) FROM coresp_cont_venchelt WHERE sters = 0 GROUP BY cont HAVING COUNT(*) > 1;.
  • Valorile reale din NOM_ARTICOLE.CONT pentru articole negestionabile — cate au deja un cont 6xx/7xx explicit vs. cate au un cont 3xx "gresit" (articol marcat negestionabil dar cu cont de gestiune ramas din import) vs. cate au NULL/gol, ceea ce ar decide cat de des s-ar folosi de fapt fallback-ul pe 704. Interogare: SELECT SUBSTR(cont,1,1) AS clasa, COUNT(*) FROM nom_articole WHERE gestionabil = 0 GROUP BY SUBSTR(cont,1,1); (numele exact al coloanei gestionabil de verificat pe schema). Verificat si numele exact al coloanei NOM_ARTICOLE.CONT — vezi si cont_venit_articol_fara_politica.md.
  • Cine citeste efectiv proprietatea cconte din frm_configurare_efactura — nu am gasit consumatorul in codul static cercetat (\.cconte\b, zero rezultate in COMUN); posibil legata generic la o configuratie pe nume de camp, tipar comun in suita, dar neconfirmat.
  • Comportamentul scrie_nota/ACT_TEMP la SCD/SCC NULL sau la CU_TVA/IN_VALUTA NULL — codul PL/SQL nu are validare (confirmat in nota_contabila_fara_politica.md, sectiunea 2), dar constrangerile reale de tabel (ACT/ACT_TEMP, NOT NULL?) nu au fost verificate — ar decide daca o implementare pe jumatate facuta a fallback-ului ar da eroare Oracle explicita (ORA-01400) sau ar trece silentios.