# 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: ```sql 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: ```sql -- 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 0. **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. 1. **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. 2. **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`. 3. **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. 4. **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. 5. **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): ```sql -- 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`): ```sql 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`): ```sql 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`): ```sql 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`): ```sql 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: ```sql 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.