Folderul docs\ era pana acum in afara oricarui control de versiuni - nici git, nici SVN - desi contine planurile pe puncte, proiectarile si rapoartele de cercetare pe care se sprijina modificarile din cod. O stergere acolo era definitiva. Fisierele intermediare (handoff-uri intre sesiuni, diff-uri deja aplicate) au fost sterse inainte, nu versionate: ce era durabil in ele a intrat in antetele fisierelor de test la care se refereau. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
29 KiB
S4g — Adaugarea de articole la modificarea oricarui document (proiectare)
Proiectare, nu implementare. Zero fisiere de cod atinse, zero write-back, zero commit. Pe Oracle
doar SELECT. Continua planul docs\plan_13_unificare_formular_facturare.md liniile 2494-2530 si
cercetarile canal_cont_venit_fara_politica.md (sectiunea "Proiectarea parametrului de cont
contabil"), parametru_cont_contabilizeaza_articol.md, coresp_cont_venchelt.md,
optiune_firma_cont_debit.md.
STARE: cercetare/proiectare incheiata.
Sursa PL/SQL verificata direct in aceasta runda: D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql
(17217 linii, confirmat wc -l). Cod VFP citit: COMUN\clase\ofacturare.vc2,
COMUN\programe\ofacturare_comun.prg (ambele permise). Neatinse: COMUN\clase\ofacturare_comun.vc2,
COMUN\programe\ofacturare_editare.prg (perimetrul sesiunii #6).
0. Premisele deja decise (nu se redeschid)
- Povestea: a doua sursa de articole in meniu, "Alege din nomenclator...", disponibila si la modificarea oricarui document deja emis, inclusiv auto (tip = -12, dar livrat separat, dupa).
- Decizia 20: din nomenclator se ofera si gestionabile, si negestionabile — nu se copiaza filtrul
in_stoc = 0al lui ROAAUTO. - Decizia 21: contul de gestiune are fallback, nu NULL, nu refuz — mecanism separat de cel de aici
(priveste
id_gestiune/Contde gestiune al liniei, nu contul de venit), presupus deja rezolvat cand derivarea din sectiunea 3 porneste. - Decizia 27 (transportul inlocuit de decizia 34): contul de venit se deriva in VFP —
CORESP_CONT_VENCHELTpentru gestionabile (pe contul de gestiune al liniei),NOM_ARTICOLE.CONTdaca e 6xx/7xx pentru negestionabile, altfel704. - Decizia 34: transportul e parametru nou, direct — nu prin
id_pol/politica tehnica. Ocolul prinpack_preturi.adauga_politica_pret_arte abandonat. - Decizia 35: acelasi drum serveste si editarea prin regenerare — nu se proiecteaza a doua ruta de contare.
- Decizia 36 (noua, 10.08.2026):
SCDpe ramura fara politica nu e hardcodat'4111'literal — vine dintr-o optiune de firma (getoptiunefirma), cu4111ca implicit dublu (rand inOPTIUNI- fallback hardcodat in PL/SQL), tiparul deja folosit de
RF_CONT_INCASARE_*in acelasi pachet.
- fallback hardcodat in PL/SQL), tiparul deja folosit de
- "Alte servicii" ROAAUTO ocoleste complet
contabilizeaza_articol— exceptie, nu jumatate de mecanism. - Regula deja adoptata in #13: liniile libere nu intra deloc in
crsarticole—APPEND BLANK+combosqldirect incrsfactura, caid_csa ramana0sido_stergesa fie no-op prin constructie (verificat aici ca acelasi tipar se aplica si campuluiid_pol, sectiunea 4). - Ordine: intai ROAFACTURARE, apoi tip = -12.
1. Punctul central: parametru vs politica, cine castiga
1.1 Ce face azi codul, verificat direct pe sursa (nu preluat din rapoarte)
contabilizeaza_articol (ff_...:7173-7547) primeste un singur parametru,
detalii_articol VANZARI_DETALII_TEMP%ROWTYPE. Primul lucru pe care il face (:7275-7302):
BEGIN
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;
EXCEPTION
WHEN NO_DATA_FOUND THEN
...
RAISE_APPLICATION_ERROR(-20000, 'Articolul ... nu este definit in politica de preturi ... (FACT-024)');
END;
Daca detalii_articol.id_pol e NULL, comparatia ID_POL = NULL nu se potriveste niciodata —
NO_DATA_FOUND garantat, FACT-024 garantat. Acelasi rezultat daca id_pol e populat dar articolul
nu e in acea politica. cursor_articol (:7218-7271), care face tot lucrul real (scrie_nota,
descarca_gestiune, discount), e filtrat pe exact aceeasi cheie (A.ID_POL = detalii_articol.id_pol AND A.ID_ARTICOL = detalii_articol.id_articol, :7270-7271) — daca SELECT INTO de mai sus a picat
in NO_DATA_FOUND, cursorul ar gasi tot zero randuri (aceeasi cauza). Deci punctul de intrare in
politica e unic si dublu-verificat (o data prin exceptie explicita, o data structural prin cursor).
Design-ul deja facut (canal_cont_venit_fara_politica.md:132-138) propune sa infasoare toata
functia intr-un switch la nivel de metoda:
IF detalii_articol.cont_venit IS NOT NULL THEN
<ramura noua: SCC := cont_venit, SCD := optiune de firma (decizia 36), fara cursor, fara SELECT INTO de mai sus>
ELSE
<tot codul de azi, neschimbat, inclusiv SELECT INTO + FACT-024 + cursor_articol>
END IF;
Aceasta e deja, prin constructie, varianta "parametrul castiga necondiionat cand e populat" —
cand cont_venit nu e NULL, executia nu se mai uita deloc la id_pol/politica, indiferent daca
acestea ar fi rezolvat sau nu. Team-lead-ul cere explicit sa se decida asta ca punct de proiectare,
nu sa ramana o consecinta implicita a formei codului — mai jos analiza celor 3 variante realiste.
1.2 Cele 3 variante
A. Parametrul castiga mereu cand e populat (= design-ul existent, ca atare).
- Ce se strica: daca, dintr-un motiv oarecare (bug VFP, sau — mai realist — decizia 35: la
regenerare, daca logica de derivare a lui
cont_venitar rula necondiionat pe toate liniile documentului, inclusiv cele scrise initial prin "Cauta in lista de preturi..." cuid_polreal), o linie ajunge la Oracle cu ambele populate,SCC-ul politicii reale e inlocuit tacut cu contul derivat generic,SCDcu optiunea de firma (posibil diferita deNOTE_CONTABILE.SCDal notei reale),ASCD/ASCC/EXPLICATIE/CU_TVAcu variantele generice ale ramurii noi. Fara nicio eroare — factura se emite, dar cu alta contare decat cea configurata prin politica. Cel mai periculos tip de defect: tace si trece verificarea vizuala (suma corecta, cont plauzibil).
B. Politica castiga mereu cand id_pol e populat (indiferent daca rezolva sau nu).
- Ar cere schimbarea conditiei de switch din
cont_venit IS NOT NULLin ceva de formaid_pol IS NULL AND cont_venit IS NOT NULL— adica: daca existaid_polpe linie, mergi pe ramura veche necondiionat, chiar daca acelid_polnu rezolva (caz FACT-024 de azi). - Ce se strica: exact scenariul in care mecanismul nou ar fi cel mai util — o linie cu
id_polpopulat gresit/stale (nu neaparat imposibil, doar improbabil in fluxul normal, vezi 1.3) — ar continua sa primeasca FACT-024 desi VFP a trimis explicit un cont de rezerva. Varianta cea mai fragila: defineste "castigatorul" pe prezenta unui camp, nu pe rezolvarea lui.
C. Parametrul e folosit doar cand politica nu rezolva (fallback real, nu switch pe camp).
- Cere ca
SELECT INTO ... FROM VCRM_POLITICI_PRET_ART(1.1) sa ramana necondiionat, exact ca azi (deja rulat pe fiecare linie, cost zero suplimentar), darEXCEPTION WHEN NO_DATA_FOUNDsa verificecont_venit: daca e populat, ramura noua; daca nu,RAISE FACT-024ca azi. Semantic corect — politica, cand exista si rezolva, nu e niciodata inlocuita tacut; parametrul e strict ce a fost gandit sa fie: o plasa pentru cazul in care politica lipseste. - Cost real: restructurare interna a functiei, nu doar un
IFla inceput. Codul de dupa bloculEXCEPTIONverifica aziIF V_COMPUS = 1 THEN ... ELSE <deschide cursor_articol> END IF(:7305,7391) —V_COMPUSramaneNULLdaca s-a intrat peEXCEPTION, deci "cade" oricum pe ramuraELSEcare deschidecursor_articol(gaseste zero randuri, nu declanseaza nimic, dar nici ramura noua). Trebuie introdus un flag explicit (V_ARE_POLITICA/similar) propagat din interiorulEXCEPTIONpana la punctul de decizie, marind suprafata modificata fata de varianta A (care atinge doar granita functiei, cu restul intact).
1.3 Ar putea sa apara vreodata, in fluxul normal, ambele populate?
Verificat direct in aceasta runda (nu presupus): crsfactura (cursorul VFP din care se scrie orice
linie) are id_pol N(20) Null (COMUN\programe\ofacturare_comun.prg:1775) — camp nullable, deci la
APPEND BLANK (mecanismul liniilor libere, confirmat de S4e ca acelasi gest se foloseste si pentru
"Alege din nomenclator...") ramane .NULL. implicit, nu 0. La scriere, poArt.id_pol (scatter
din randul respectiv) ajunge in apelul RPC ca Nvl(Alltrim(Str(poArt.id_pol)),[NULL])
(ofacturare.vc2:14072, identic la :18107) — literal SQL NULL cand campul e .NULL.. O linie
"din nomenclator" trimite deci id_pol = NULL la Oracle prin constructie, nu doar prin conventie de
utilizare — cursorul de cautare al nomenclatorului (caut_articol, ocautare.prg, deja confirmat
de coresp_cont_venchelt.md sectiunea 9d) nu are coloana id_pol in output, deci nu exista niciun
punct in care combosql-ul ar putea popula acest camp cu o valoare reala pentru o astfel de linie.
Ramane un singur scenariu real de ambiguitate: regenerarea (decizia 35). La regenerare, toate
liniile documentului (cele scrise initial prin "Cauta in lista de preturi...", cu id_pol real, si
cele adaugate prin "Alege din nomenclator...", fara id_pol) trec din nou prin acelasi drum de
scriere. Daca logica VFP care calculeaza cont_venit (sectiunea 3) ar rula necondiionat pe toate
liniile din grid, in loc sa fie conditionata explicit de "linia nu are id_pol", ar produce exact
combinatia periculoasa din varianta A. Asta nu e un risc Oracle — e un risc de implementare VFP,
dar exact tipul de risc pe care design-ul Oracle trebuie sa nu-l agraveze printr-un switch care il
face invizibil.
1.4 Recomandare
Niciuna dintre cele 3 variante pure, ci varianta A (deja proiectata, cea mai simpla) plus o garda explicita pe combinatia ambigua, nu o rezolvare tacita in orice directie:
IF detalii_articol.cont_venit IS NOT NULL THEN
IF detalii_articol.id_pol IS NOT NULL THEN
RAISE_APPLICATION_ERROR(-20000,
'Articolul ' || detalii_articol.id_articol ||
' are simultan politica de pret (' || detalii_articol.id_pol ||
') si cont de venit calculat — conflict netratat (FACT-0xx)');
END IF;
<ramura noua, ca in design>
ELSE
<tot codul de azi, neschimbat>
END IF;
Motivare, in ordine:
- Combinatia nu trebuie sa apara niciodata in fluxul normal (1.3) —
id_polramaneNULLprin constructie pentru orice linie scrisa prin gestul "linie libera". Daca totusi apare, e un semnal ca ceva e stricat in populate-ul liniei (VFP a trimis ambele campuri, posibil din cauza logicii de regenerare descrisa la 1.3) — situatie de bug de investigat, nu de "rezolvat" silentios. - Variantele B si C rezolva combinatia in cate o directie fixa — ambele ascund o eroare de date in loc sa o semnaleze: B ar putea reintroduce FACT-024 pe o linie unde VFP a oferit deja o solutie; A fara garda ar inlocui tacut o politica reala. O garda explicita e singurul comportament care nu presupune ca stie mai bine decat datele ce s-a intamplat.
- Cost de implementare minim: un singur
IFsuplimentar, la intrarea in ramura deja proiectata — nu restructureaza funcia (spre deosebire de varianta C), nu schimba conditia switch-ului principal (spre deosebire de B). - Compatibilitate/regresie zero pe apelantii de azi: cand
cont_veniteNULL(toti apelantii existenti, care nu cunosc inca acest parametru), executia intra direct peELSE— garda nu se evalueaza niciodata, comportamentul e identic bit-cu-bit cu azi. Candcont_venite populat siid_poleNULL(cazul intentionat, "din nomenclator"), garda trece nevazuta, ramura noua ruleaza normal.
Numele codului de eroare (FACT-0xx in schita de mai sus) ramane de ales de Marius, distinct de
FACT-024 (care ramane, neschimbat, pentru cazul "niciuna din cele doua" — linie fara politica si
fara cont).
2. Suprafata de schimbare pe Oracle
Deja proiectata si verificata adversarial in canal_cont_venit_fara_politica.md si
parametru_cont_contabilizeaza_articol.md; rezumat + completarea cu decizia 36 si garda de la
sectiunea 1.4:
- Coloana noua:
VANZARI_DETALII_TEMP.CONT_VENIT VARCHAR2(4) NULL(faraNOT NULL, faraCHECK— acelasi tipar caACT_TEMP.SCC). Optional, recomandat pentru trasabilitate:VANZARI_DETALII.CONT_VENIT, plus extinderea listei explicite de coloane dinscrie_in_vanzari(PACK_FACTURARE:13705-13757, confirmat ca listeaza 24 coloane explicit, nuSELECT *— de extins cu o a 25-a daca se alege trasabilitatea). - Parametru nou pe
adauga_articol_factura(ff_...:4989-5015), la coada, dupaV_LOT:V_CONT_VENIT IN VARCHAR2 DEFAULT NULL— apelul VFP existent (pozitional, se opreste laV_LOT, confirmat la doua locuri,ofacturare.vc2:14069-14091si:18089-18114, doua clase distincte cu aceeasi metoda, nu o duplicare) ramane neschimbat, echivalent cu "trimite NULL". Plumbing identic cuV_CONT/V_CONT2, o coloana in plus inINSERT INTO VANZARI_DETALII_TEMP(ff_...:5222-5282). contabilizeaza_articolinsasi NU primeste parametru nou — ramaneVANZARI_DETALII_TEMP%ROWTYPE; coloana noua ajunge automat prinSELECT * BULK COLLECT INTO tab_detalii FROM VANZARI_DETALII_TEMP(:6063), fara nicio schimbare la cei 3 apelanti interni (scrie_factura2,scrie_factura_avize_retur,scrie_aviz_retur).- Ramura noua in
contabilizeaza_articol, cu garda de la sectiunea 1.4:SCC := detalii_articol.cont_venit.SCD(decizia 36):PACK_SESIUNE.getoptiunefirma('FACT_SCD_ARTFPRET'), cu fallback hardcodat'4111'cand optiunea lipseste/e goala — optiune noua in tabelulOPTIUNI(VARTYPE='CHARACTER', script de migrare idempotent, tiparul exact alRF_CONT_INCASARE_*, deja folosit in acelasi pachet,optiune_firma_cont_debit.mdsectiunea 3.4). Ramurile de aviz raman'418'/'461', neschimbate.ASCD/ASCCdinGetAnaliticByGrupUtilizatori(pack_facturare.nid_util, V_SCD/V_SCC)— acelasi fallback deja folosit necondiionat pe ramurile de aviz azi.EXPLICATIEdindetalii_articol.explicatia(parametru deja existent,V_EXPLICATIE).ID_VENCHELT/ID_SECTIEdinpack_facturare.nid_venchelt/nid_sectie_stoc(fallback de sesiune deja folosit ca prioritate azi).IN_VALUTAdinpack_facturare.nin_valuta(parametru obligatoriu, faraDEFAULT, mereu curent — nu o presupunere, sursa solida).CU_TVA: hardcodat1, cu efect colateral real si masurat, nu "inofensiv" —parametru_cont_contabilizeaza_articol.mdsectiunea 2b arata ca pe combinatia specifica "linie fallback cu TVA 0% + discount global pe factura + acea linie e prima/singura vazuta" valoarea forteazanproc_tva_max/nid_jtva_coloanapentru toata linia de discount a facturii. Ramane "de confirmat cu Marius", cu argumentul mai tare decat in propunerea initiala.- Apeluri o singura data (nu in bucla):
scrie_nota(...),descarca_gestiune(...)(garda identica,nscadere_stoc=1 AND id_gestiune<>-1000 AND in_stoc=1), discount (garda identica). - Articole compuse (
V_COMPUS=1) exclus structural — o linie faraid_polnu poate aveaID_POL_ART, deci intrebarea "e compus" nu se poate pune pe aceasta ramura (confirmat pe schema view-ului, nu presupus).
- Ordinea de deploy: DB inainte de EXE. Parametrul nou are
DEFAULT NULL, deci EXE-ul vechi ruland pe DB-ul nou functioneaza neschimbat (nu trimite parametrul). EXE-ul nou ruland pe DB-ul vechi (fara coloana/parametru) ar esua la primul apel cu al 27-lea argument — deci EXE-ul nou nu poate merge inaintea migrarii DB. Ordine standard, fara surpriza. - Regenerarea (decizia 35):
initializeaza_date_facturareseteaza starea de sesiune (DELETE FROM VANZARI_DETALII_TEMP,nid_act := 0) la fiecare emitere — nimic din ramura noua citeste vreo stare presupunand "documentul e nou". Calea Oracle e identica la regenerare, cu o exceptie separata, in alt pachet: reemiterea cu acelasiID_FACTar da aziORA-00001pePK_DOCUMENTEinPACK_CONTAFIN.SET_IDFACT— problema deja proiectata separat (idfact_refolosire_si_documente.md), nu intersecteaza si nu invalideaza design-ul de aici, dar ramane o bucata de lucru distincta, necesara pentru ca regenerarea sa fie completa. - Gol neadresat inca: ramura
ntip = 4("factura din avize",:7520-7537) apeleazascrie_fact_aviz_custodiein loc dedescarca_gestiune+discount — design-ul nu specifica ce se intampla pe fallback aici. In practica improbabil (o linie de aviz sursa fara politica n-ar fi ajuns la factura pe acest drum,adauga_articol_factura:5096cere dejaA.ID_POL = V_ID_POLpe avizul sursa), dar de exclus explicit inainte de implementare, nu de presupus tacit.
3. Derivarea contului in VFP
3.1 Sursele, in ordine (decizia 27)
- Articol gestionabil (are
id_gestiunevalid,in_stoc=1):CORESP_CONT_VENCHELT.CONT_VENIT, cautat pe contul de gestiune al liniei (poArt.Cont, camp deja gathered pepoArticolin ambele metodedo_scrie_articole, confirmat laofacturare.vc2:12945,13835si echivalentele infrm_facturare_articole2). Cheia de join e mereuCONT(nuID_GESTIUNE, nuTIP_DOC) — confirmat pe 4+ consumatori Oracle reali ai tabelului (pack_vin,pack_devize,gestiune_pack_gest_import, un raport din 2026), niciodata pentruCONT_VENITinsa — aceasta propunere ar fi primul consumator real al coloanei, desi populata din 2023 (20 conturi de gestiune uzuale: 301-303/3021-3028, 331/332, 341, 345/346/348, 361, 371, 381). View-ul VFP-safe eVCORESP_CONT_VENCHELT(STERS=0deja filtrat in view). - Articol negestionabil, sau gestionabil dar corespondenta nu rezolva (rand lipsa pentru acel
CONT):NOM_ARTICOLE.CONT, doar daca primul caracter e6sau7(verific_contnu restrange campul la o clasa, deci poate contine legitim orice cont valid, inclusiv 6xx/7xx pe un articol negestionabil). - Fallback final: literal
'704'. Fara reteta de cod deja scrisa inpack_facturarepentru aceasta valoare, dar cu un precedent independent de "704 = cont implicit client" in alt subsistem (anaf_efactura.vc2:8376,cconte = 704) — nu o inventie, dar cod nou.
3.2 Unde sta codul si cand ruleaza
Locul natural: chiar in do_scrie_articole (ambele clase, frm_facturare_articole si
frm_facturare_articole2, confirmat ca 2 locuri distincte de atins, nu 1), imediat inainte de
construirea textului RPC pentru fiecare linie, conditionat explicit de Empty(Nvl(poArt.id_pol,0))
— nu la momentul adaugarii liniei in grid. Doua motive:
- Regenerarea (decizia 35) re-parcurge toate liniile la fiecare scriere; derivarea la momentul scrierii (nu la adaugare) garanteaza ca valoarea reflecta starea curenta a corespondentelor/ nomenclatorului, nu una inghetata la momentul in care linia a fost adaugata initial in grid.
- Conditionarea explicita pe
id_polgol (nu pe "linia vine din nomenclator" ca marcaj separat) e chiar garda ceruta la sectiunea 1.3-1.4: o linie cuid_polpopulat nu trebuie sa primeasca niciodata o valoare pecont_venit, indiferent de sursa ei — un singur punct de decizie, in oglinda exacta cu conditia pe care Oracle o va verifica la randul lui (sectiunea 1.4).
3.3 Ce se intampla cand derivarea esueaza
- Corespondenta nu are rand pentru acel
CONT(gestiune fara corespondenta configurata): cade pe pasul 2 (NOM_ARTICOLE.CONT), nu pe eroare. NOM_ARTICOLE.CONTnu incepe cu 6/7 (cont de gestiune sau alt tip pe un articol negestionabil, configurare atipica): cade pe pasul 3 (704), nu pe eroare.- Niciodata
NULL/gol trimis la Oracle pentru o linie "din nomenclator" — ultimul pas e un literal, nu o interogare care poate esua. Aceasta e proprietatea care face garda de la 1.4 inofensiva pe fluxul normal:cont_venite intotdeauna populat candid_pole gol, deci ramura noua din Oracle ruleaza mereu cand ar trebui, iar FACT-024 (ramura veche) nu mai poate fi atinsa de o linie din nomenclator dupa implementare — dispare exact problema pe care povestea o rezolva. - Nu e proiectata aici (ramane de decis la implementare, in afara acestei povesti): daca vreo
validare suplimentara ar trebui sa verifice ca valorile derivate (
CONT_VENITdin corespondenta,NOM_ARTICOLE.CONT) sunt conturi valide in planul de conturi al anului curent — aziverific_contexista ca mecanism (oproceduri_comune.prg:2389-2415) dar nu e cablat automat pe acest drum nou.
4. Fluxul in formularul unificat
- Utilizatorul deschide un document deja emis la modificare (
frm_modific2024/formularul unificat, in afara perimetrului #6/omodificari.vc2, care nu se atinge aici) si alege din meniu "Alege din nomenclator..." (a doua sursa, langa "Cauta in lista de preturi...", ambele reduse la acelasi gest UI conform S4b/S4e). - Gestul UI:
Select crsfactura / APPEND BLANK(tiparul deja in productie lafrm_facturare_articole2.But_nou1.do_adauga,ofacturare.vc2:17118-17122), focus pe celula de cautare,combosqllegat pe cursorul filtrat pe nomenclator (caut_articol/echivalent, fara coloanaid_polin output — confirmat, sectiunea 1.3). crsfactura.id_cramane0(valoarea implicita a campuluiN(20)faraNull, laAPPEND BLANK) — valoare pe care Oracle nu o produce niciodata pentruid_c.do_sterge(potriveste peid_c) e no-op prin constructie pe aceasta linie, fara nicio modificare de cod — exact regula deja adoptata in #13, reconfirmata aici pentru sursa "nomenclator" (S4e o stabilise pentru sursa "lista de preturi pe comanda"; acelasi cursor de scrierecrsfactura, acelasi mecanism, doar alt cursor de cautare in fata).crsfactura.id_polramane.NULL.(campN(20) Null,ofacturare_comun.prg:1775), pentru ca sursa de cautare (nomenclator) nu are aceasta coloana in output — confirmat direct in aceasta runda (sectiunea 1.3), nu presupus.- Utilizatorul completeaza cantitate/pret (campuri editabile inline pe grid, tipar deja existent).
- La
do_scrie_articole(salvarea documentului), pentru fiecare linie cuEmpty(Nvl(poArt.id_pol,0)), se ruleaza derivarea din sectiunea 3 si se populeaza al 27-lea argument pozitional al apelului RPC catreadauga_articol_facturacu valoarea calculata; pentru restul liniilor (cele cuid_polpopulat, "din lista de preturi"), argumentul ramaneNULL— comportament identic cu azi. - Documentul se salveaza; pe Oracle,
contabilizeaza_articolruleaza ramura noua (sectiunea 1-2) pentru liniile fara politica, ramura veche neschimbata pentru restul. - Editarea (regenerare, decizia 35): acelasi
do_scrie_articole, aceeasi conditie peid_pol, acelasi rezultat — nu exista o a doua cale de contare pentru liniile deja existente pe document.
5. Ce ramane in afara (partea auto)
tip = -12(facturare auto, ROAAUTO) — livrat separat, dupa ce mecanismul de mai sus e stabil pe documentele ROAFACTURARE (ordinea deja decisa in plan).- "Alte servicii" din ROAAUTO ramane exceptia ei — ocoleste complet
contabilizeaza_articol, nu foloseste si nu va fi migrata sa foloseasca acest mecanism ca parte a acestei povesti; daca se decide vreodata unificarea, e o poveste separata. - Gridul read-only din
frm_modific2024(al #6) — S4g incepe dupa ce #6 se termina (decizia 30), nicio proiectare de aici nu presupune sau modifica acel perimetru. - Validarea de cantitate/stoc pentru o linie liberă la modificare (analogul sectiunii 6 din
s4e_lista_preturi_pe_sursa.md, dar pentru nomenclator, nu lista de preturi) — nu re-proiectata aici, acelasi gol semnalat deja de S4e se aplica identic si pe sursa "nomenclator"; de rezolvat cu acelasi mecanism (varianta (b), reutilizaredo_verifica_articolcupoArticolexplicit).
6. Teste minime
Pe langa cele deja listate in canal_cont_venit_fara_politica.md sectiunea 6 si
nota_contabila_fara_politica.md, specifice acestei povesti:
- Factura normala cu politica, parametru NULL — verifica ACT identic cu azi (regresie de baza).
- Aviz cu articol adaugat din nomenclator (fara politica) —
SCDramane'461'/'418'(ramurile de aviz raman hardcodate independent de ramura noua/veche), nugetoptiunefirma. ntip = 46(daca exista pe fluxul de modificare vizat) —scrie_notanu se cheama pe acea ramura; de confirmat ca ramura noua nu e atinsa deloc pentru acest tip.- Articol gestionabil din nomenclator, cu corespondenta configurata — un singur rand
ACT,SCC=CORESP_CONT_VENCHELT.CONT_VENITpentru contul de gestiune al liniei,SCD= optiunea de firma (sau4111daca optiunea lipseste), linie TVA scrisa separat. - Articol negestionabil din nomenclator, fara corespondenta aplicabila —
SCC=NOM_ARTICOLE.CONTdaca incepe cu 6/7, altfel'704'. - Articol negestionabil (
id_gestiune=-1000) cucont_venitpopulat —descarca_gestiuneNU ruleaza. - Discount pe o linie din nomenclator — foloseste
V_ASCD/V_CU_TVAcalculate in ramura noua. - Document in valuta (
nin_valuta=1) cu linie din nomenclator —IN_VALUTA=1pe nota,SUMA_VALcompletat. - Linie fara politica si fara cont derivat (nu ar trebui sa se poata construi prin UI, dar de testat direct pe Oracle) — FACT-024 tot apare, regresie negativa: garda nu s-a slabit.
- Linie cu ambele populate (construita direct la nivel de apel Oracle, nu prin UI — testeaza garda de la sectiunea 1.4, nu fluxul normal) — noua eroare explicita apare, nu o rezolvare tacita in nicio directie.
- Regenerare pe un document mixt (o linie din lista de preturi cu
id_pol, o linie din nomenclator faraid_pol) — dupa regenerare, prima linie tot cuSCCdin politica, a doua tot cuSCCderivat; niciuna nu trece pe ramura celeilalte. id_csido_sterge(mostenit din tiparul S4e, de re-verificat pentru sursa nomenclator): o linie din nomenclator adaugata la modificare, apoi stearsa inainte de salvare — no-op pecrsarticole, fara efect asupra vreunei linii reale a documentului.
7. Riscuri si de decis de Marius
- Garda explicita pe combinatia
id_pol+cont_venitambele populate (sectiunea 1.4) — e o recomandare de proiectare a acestui raport, nu o decizie deja luata de Marius; codul exact al erorii si numarulFACT-0xxraman de ales. CU_TVAhardcodat1— are un efect colateral masurat (nu doar teoretic), prinnproc_tva_max, pe combinatia specifica linie-scutita + discount global de factura. De confirmat explicit, nu de presupus inofensiv.- Decizia 36 (
SCDprin optiune de firma) — numele exact al cheii (FACT_SCD_ARTFPRETpropus), daca se adauga validare de cont la citire (niciun precedent existent nu valideaza), siPROGRAME(restrans la ROAFACTURARE sau extins caRF_CONT_INCASARE_*) raman decizii deschise inoptiune_firma_cont_debit.mdsectiunea 4. - Ramura
ntip=4/"factura din avize" pe fallback (sectiunea 2 punctul 7) — probabil imposibil de atins prin acest drum (avizul sursa cere dejaid_pol), dar nu exclus explicit prin cod sau test — de confirmat inainte de implementare. - Suprafata de regresie in restul suitei (ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB) pentru
adauga_articol_factura— pe baza cercetarilor existente, aceste produse folosesc proceduri separate (_deviz/_stoc) sau alt pachet complet (pack_acn), deci risc asteptat zero, dar cautarea directa inCOMUN-urile lor pentru un apel simplu laadauga_articol_factura(nu s-a terminat in nicio runda anterioara — de re-rulat inainte de implementare, nu de presupus incheiata. - Validarea de cantitate/stoc pentru linia libera la modificare (sectiunea 5) — gol mostenit de la S4e, nu inchis aici, de rezolvat cu acelasi mecanism pe ambele surse (lista de preturi si nomenclator).
- Trasabilitatea
CONT_VENITpeVANZARI_DETALII(sectiunea 2 punctul 1) — optionala pentru ca mecanismul sa functioneze, dar fara ea coloana nu se pastreaza dupa fapt; de decis daca merita extinderea listei explicite de coloane dinscrie_in_vanzari. idfact_refolosire_si_documente.md— obstacol real pentru ca regenerarea (decizia 35) sa fie completa (reemitere cu acelasiID_FACT), inPACK_CONTAFIN, nu inpack_facturare— nu blocheaza design-ul de aici, dar e o bucata de lucru separata, necesara inainte ca "editare = regenerare" sa functioneze end-to-end.
STARE / CE RAMANE
Cercetare/proiectare incheiata pentru toate cele 6 puncte cerute in brief, cu punctul central
(sectiunea 1) tratat explicit ca decizie de proiectare (nu doar consecinta implicita a codului
existent deja schitat in rundele anterioare). Nicio editare de cod, niciun git_sync.ps1/
txt2vcx.ps1, niciun commit, nicio scriere pe Oracle. Context consumat moderat in aceasta runda —
nu a fost necesara predarea de mijloc de sesiune.
Ce nu s-a putut inchide complet, de reluat separat:
- Cautarea exhaustiva a apelantilor
adauga_articol_facturasimplu in restul suitei (risc 5, sectiunea 7) — de re-rulat, nu s-a terminat in nicio runda anterioara din lipsa de timp, nu din cauza unei erori. - Confirmarea explicita a lui Marius pe hardcodarile/optiunile ramase deschise (
CU_TVA=1, numele cheii de optiune, garda de la sectiunea 1.4) — sunt recomandari argumentate, nu decizii finale.