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
438 lines
29 KiB
Markdown
438 lines
29 KiB
Markdown
# 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 = 0` al lui ROAAUTO.
|
|
- Decizia 21: contul de gestiune are fallback, nu NULL, nu refuz — mecanism separat de cel de aici
|
|
(priveste `id_gestiune`/`Cont` de 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_VENCHELT` pentru gestionabile (pe contul de gestiune al liniei), `NOM_ARTICOLE.CONT`
|
|
daca e 6xx/7xx pentru negestionabile, altfel `704`.
|
|
- Decizia 34: transportul e parametru nou, direct — nu prin `id_pol`/politica tehnica. Ocolul prin
|
|
`pack_preturi.adauga_politica_pret_art` e abandonat.
|
|
- Decizia 35: acelasi drum serveste si editarea prin regenerare — nu se proiecteaza a doua ruta de
|
|
contare.
|
|
- Decizia 36 (noua, 10.08.2026): `SCD` pe ramura fara politica nu e hardcodat `'4111'` literal —
|
|
vine dintr-o optiune de firma (`getoptiunefirma`), cu `4111` ca implicit dublu (rand in `OPTIUNI`
|
|
+ fallback hardcodat in PL/SQL), tiparul deja folosit de `RF_CONT_INCASARE_*` in acelasi pachet.
|
|
- "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` +
|
|
`combosql` direct in `crsfactura`, ca `id_c` sa ramana `0` si `do_sterge` sa fie no-op prin
|
|
constructie (verificat aici ca acelasi tipar se aplica si campului `id_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`):
|
|
|
|
```sql
|
|
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_venit` ar rula necondiionat pe toate liniile
|
|
documentului, inclusiv cele scrise initial prin "Cauta in lista de preturi..." cu `id_pol` real),
|
|
o linie ajunge la Oracle cu **ambele** populate, `SCC`-ul politicii reale e inlocuit tacut cu
|
|
contul derivat generic, `SCD` cu optiunea de firma (posibil diferita de `NOTE_CONTABILE.SCD` al
|
|
notei reale), `ASCD`/`ASCC`/`EXPLICATIE`/`CU_TVA` cu 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 NULL` in ceva de forma
|
|
`id_pol IS NULL AND cont_venit IS NOT NULL` — adica: daca exista `id_pol` pe linie, mergi pe
|
|
ramura veche necondiionat, chiar daca acel `id_pol` nu rezolva (caz FACT-024 de azi).
|
|
- *Ce se strica*: exact scenariul in care mecanismul nou ar fi cel mai util — o linie cu `id_pol`
|
|
populat 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), dar `EXCEPTION WHEN NO_DATA_FOUND` sa
|
|
verifice `cont_venit`: daca e populat, ramura noua; daca nu, `RAISE FACT-024` ca 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 `IF` la inceput. Codul de dupa blocul
|
|
`EXCEPTION` verifica azi `IF V_COMPUS = 1 THEN ... ELSE <deschide cursor_articol> END IF`
|
|
(`:7305,7391`) — `V_COMPUS` ramane `NULL` daca s-a intrat pe `EXCEPTION`, deci "cade" oricum pe
|
|
ramura `ELSE` care deschide `cursor_articol` (gaseste zero randuri, nu declanseaza nimic, dar nici
|
|
ramura noua). Trebuie introdus un flag explicit (`V_ARE_POLITICA`/similar) propagat din interiorul
|
|
`EXCEPTION` pana 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:
|
|
|
|
```sql
|
|
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:
|
|
1. **Combinatia nu trebuie sa apara niciodata in fluxul normal** (1.3) — `id_pol` ramane `NULL` prin
|
|
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.
|
|
2. **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.
|
|
3. **Cost de implementare minim**: un singur `IF` suplimentar, la intrarea in ramura deja proiectata
|
|
— nu restructureaza funcia (spre deosebire de varianta C), nu schimba conditia switch-ului
|
|
principal (spre deosebire de B).
|
|
4. **Compatibilitate/regresie zero pe apelantii de azi**: cand `cont_venit` e `NULL` (toti apelantii
|
|
existenti, care nu cunosc inca acest parametru), executia intra direct pe `ELSE` — garda nu se
|
|
evalueaza niciodata, comportamentul e identic bit-cu-bit cu azi. Cand `cont_venit` e populat si
|
|
`id_pol` e `NULL` (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:
|
|
|
|
1. **Coloana noua**: `VANZARI_DETALII_TEMP.CONT_VENIT VARCHAR2(4) NULL` (fara `NOT NULL`, fara
|
|
`CHECK` — acelasi tipar ca `ACT_TEMP.SCC`). Optional, recomandat pentru trasabilitate:
|
|
`VANZARI_DETALII.CONT_VENIT`, plus extinderea listei explicite de coloane din
|
|
`scrie_in_vanzari` (`PACK_FACTURARE:13705-13757`, confirmat ca listeaza 24 coloane explicit, nu
|
|
`SELECT *` — de extins cu o a 25-a daca se alege trasabilitatea).
|
|
2. **Parametru nou pe `adauga_articol_factura`** (`ff_...:4989-5015`), la coada, dupa `V_LOT`:
|
|
`V_CONT_VENIT IN VARCHAR2 DEFAULT NULL` — apelul VFP existent (pozitional, se opreste la
|
|
`V_LOT`, confirmat la doua locuri, `ofacturare.vc2:14069-14091` si `:18089-18114`, doua clase
|
|
distincte cu aceeasi metoda, nu o duplicare) ramane neschimbat, echivalent cu "trimite NULL".
|
|
Plumbing identic cu `V_CONT`/`V_CONT2`, o coloana in plus in `INSERT INTO VANZARI_DETALII_TEMP`
|
|
(`ff_...:5222-5282`).
|
|
3. **`contabilizeaza_articol` insasi NU primeste parametru nou** — ramane `VANZARI_DETALII_TEMP%ROWTYPE`;
|
|
coloana noua ajunge automat prin `SELECT * 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`).
|
|
4. **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 tabelul `OPTIUNI`
|
|
(`VARTYPE='CHARACTER'`, script de migrare idempotent, tiparul exact al `RF_CONT_INCASARE_*`,
|
|
deja folosit in acelasi pachet, `optiune_firma_cont_debit.md` sectiunea 3.4). Ramurile de aviz
|
|
raman `'418'`/`'461'`, neschimbate.
|
|
- `ASCD`/`ASCC` din `GetAnaliticByGrupUtilizatori(pack_facturare.nid_util, V_SCD/V_SCC)` — acelasi
|
|
fallback deja folosit necondiionat pe ramurile de aviz azi.
|
|
- `EXPLICATIE` din `detalii_articol.explicatia` (parametru deja existent, `V_EXPLICATIE`).
|
|
- `ID_VENCHELT`/`ID_SECTIE` din `pack_facturare.nid_venchelt`/`nid_sectie_stoc` (fallback de
|
|
sesiune deja folosit ca prioritate azi).
|
|
- `IN_VALUTA` din `pack_facturare.nin_valuta` (parametru obligatoriu, fara `DEFAULT`, mereu
|
|
curent — nu o presupunere, sursa solida).
|
|
- `CU_TVA`: hardcodat `1`, **cu efect colateral real si masurat, nu "inofensiv"** —
|
|
`parametru_cont_contabilizeaza_articol.md` sectiunea 2b arata ca pe combinatia specifica "linie
|
|
fallback cu TVA 0% + discount global pe factura + acea linie e prima/singura vazuta" valoarea
|
|
forteaza `nproc_tva_max`/`nid_jtva_coloana` pentru 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 fara `id_pol` nu poate avea
|
|
`ID_POL_ART`, deci intrebarea "e compus" nu se poate pune pe aceasta ramura (confirmat pe
|
|
schema view-ului, nu presupus).
|
|
5. **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.
|
|
6. **Regenerarea (decizia 35)**: `initializeaza_date_factura` reseteaza 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 acelasi `ID_FACT` ar da azi `ORA-00001` pe
|
|
`PK_DOCUMENTE` in `PACK_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.
|
|
7. **Gol neadresat inca**: ramura `ntip = 4` ("factura din avize", `:7520-7537`) apeleaza
|
|
`scrie_fact_aviz_custodie` in loc de `descarca_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:5096` cere deja `A.ID_POL = V_ID_POL` pe
|
|
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)
|
|
|
|
1. **Articol gestionabil** (are `id_gestiune` valid, `in_stoc=1`): `CORESP_CONT_VENCHELT.CONT_VENIT`,
|
|
cautat pe **contul de gestiune al liniei** (`poArt.Cont`, camp deja gathered pe `poArticol` in
|
|
ambele metode `do_scrie_articole`, confirmat la `ofacturare.vc2:12945,13835` si echivalentele in
|
|
`frm_facturare_articole2`). Cheia de join e mereu `CONT` (nu `ID_GESTIUNE`, nu `TIP_DOC`) —
|
|
confirmat pe 4+ consumatori Oracle reali ai tabelului (`pack_vin`, `pack_devize`,
|
|
`gestiune_pack_gest_import`, un raport din 2026), niciodata pentru `CONT_VENIT` insa — 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 e
|
|
`VCORESP_CONT_VENCHELT` (`STERS=0` deja filtrat in view).
|
|
2. **Articol negestionabil**, sau gestionabil dar corespondenta nu rezolva (rand lipsa pentru acel
|
|
`CONT`): `NOM_ARTICOLE.CONT`, **doar daca** primul caracter e `6` sau `7` (`verific_cont` nu
|
|
restrange campul la o clasa, deci poate contine legitim orice cont valid, inclusiv 6xx/7xx pe un
|
|
articol negestionabil).
|
|
3. **Fallback final**: literal `'704'`. Fara reteta de cod deja scrisa in `pack_facturare` pentru
|
|
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_pol` gol** (nu pe "linia vine din nomenclator" ca marcaj separat)
|
|
e chiar garda ceruta la sectiunea 1.3-1.4: o linie cu `id_pol` populat nu trebuie sa primeasca
|
|
niciodata o valoare pe `cont_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.CONT` nu 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_venit` e *intotdeauna* populat cand `id_pol` e 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_VENIT` din corespondenta,
|
|
`NOM_ARTICOLE.CONT`) sunt conturi valide in planul de conturi al anului curent — azi
|
|
`verific_cont` exista ca mecanism (`oproceduri_comune.prg:2389-2415`) dar nu e cablat automat pe
|
|
acest drum nou.
|
|
|
|
---
|
|
|
|
## 4. Fluxul in formularul unificat
|
|
|
|
1. 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).
|
|
2. Gestul UI: `Select crsfactura / APPEND BLANK` (tiparul deja in productie la
|
|
`frm_facturare_articole2.But_nou1.do_adauga`, `ofacturare.vc2:17118-17122`), focus pe celula de
|
|
cautare, `combosql` legat pe cursorul filtrat pe nomenclator (`caut_articol`/echivalent, fara
|
|
coloana `id_pol` in output — confirmat, sectiunea 1.3).
|
|
3. **`crsfactura.id_c` ramane `0`** (valoarea implicita a campului `N(20)` fara `Null`, la
|
|
`APPEND BLANK`) — valoare pe care Oracle nu o produce niciodata pentru `id_c`. `do_sterge`
|
|
(potriveste pe `id_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 scriere `crsfactura`, acelasi
|
|
mecanism, doar alt cursor de cautare in fata).
|
|
4. **`crsfactura.id_pol` ramane `.NULL.`** (camp `N(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.
|
|
5. Utilizatorul completeaza cantitate/pret (campuri editabile inline pe grid, tipar deja existent).
|
|
6. La `do_scrie_articole` (salvarea documentului), pentru fiecare linie cu `Empty(Nvl(poArt.id_pol,0))`,
|
|
se ruleaza derivarea din sectiunea 3 si se populeaza al 27-lea argument pozitional al apelului RPC
|
|
catre `adauga_articol_factura` cu valoarea calculata; pentru restul liniilor (cele cu `id_pol`
|
|
populat, "din lista de preturi"), argumentul ramane `NULL` — comportament identic cu azi.
|
|
7. Documentul se salveaza; pe Oracle, `contabilizeaza_articol` ruleaza ramura noua (sectiunea 1-2)
|
|
pentru liniile fara politica, ramura veche neschimbata pentru restul.
|
|
8. **Editarea** (regenerare, decizia 35): acelasi `do_scrie_articole`, aceeasi conditie pe `id_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), reutilizare `do_verifica_articol` cu `poArticol` explicit).
|
|
|
|
---
|
|
|
|
## 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:
|
|
|
|
1. **Factura normala cu politica, parametru NULL** — verifica ACT identic cu azi (regresie de baza).
|
|
2. **Aviz cu articol adaugat din nomenclator (fara politica)** — `SCD` ramane `'461'`/`'418'`
|
|
(ramurile de aviz raman hardcodate independent de ramura noua/veche), nu `getoptiunefirma`.
|
|
3. **`ntip = 46`** (daca exista pe fluxul de modificare vizat) — `scrie_nota` nu se cheama pe acea
|
|
ramura; de confirmat ca ramura noua nu e atinsa deloc pentru acest tip.
|
|
4. **Articol gestionabil din nomenclator, cu corespondenta configurata** — un singur rand `ACT`,
|
|
`SCC` = `CORESP_CONT_VENCHELT.CONT_VENIT` pentru contul de gestiune al liniei, `SCD` = optiunea
|
|
de firma (sau `4111` daca optiunea lipseste), linie TVA scrisa separat.
|
|
5. **Articol negestionabil din nomenclator, fara corespondenta aplicabila** — `SCC` = `NOM_ARTICOLE.CONT`
|
|
daca incepe cu 6/7, altfel `'704'`.
|
|
6. **Articol negestionabil** (`id_gestiune=-1000`) cu `cont_venit` populat — `descarca_gestiune` NU
|
|
ruleaza.
|
|
7. **Discount pe o linie din nomenclator** — foloseste `V_ASCD`/`V_CU_TVA` calculate in ramura noua.
|
|
8. **Document in valuta** (`nin_valuta=1`) cu linie din nomenclator — `IN_VALUTA=1` pe nota,
|
|
`SUMA_VAL` completat.
|
|
9. **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.
|
|
10. **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.
|
|
11. **Regenerare pe un document mixt** (o linie din lista de preturi cu `id_pol`, o linie din
|
|
nomenclator fara `id_pol`) — dupa regenerare, prima linie tot cu `SCC` din politica, a doua tot
|
|
cu `SCC` derivat; niciuna nu trece pe ramura celeilalte.
|
|
12. **`id_c` si `do_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 pe
|
|
`crsarticole`, fara efect asupra vreunei linii reale a documentului.
|
|
|
|
---
|
|
|
|
## 7. Riscuri si de decis de Marius
|
|
|
|
1. **Garda explicita pe combinatia `id_pol` + `cont_venit` ambele populate** (sectiunea 1.4) — e o
|
|
recomandare de proiectare a acestui raport, nu o decizie deja luata de Marius; codul exact al
|
|
erorii si numarul `FACT-0xx` raman de ales.
|
|
2. **`CU_TVA` hardcodat `1`** — are un efect colateral masurat (nu doar teoretic), prin
|
|
`nproc_tva_max`, pe combinatia specifica linie-scutita + discount global de factura. De confirmat
|
|
explicit, nu de presupus inofensiv.
|
|
3. **Decizia 36 (`SCD` prin optiune de firma)** — numele exact al cheii (`FACT_SCD_ARTFPRET` propus),
|
|
daca se adauga validare de cont la citire (niciun precedent existent nu valideaza), si
|
|
`PROGRAME` (restrans la ROAFACTURARE sau extins ca `RF_CONT_INCASARE_*`) raman decizii deschise
|
|
in `optiune_firma_cont_debit.md` sectiunea 4.
|
|
4. **Ramura `ntip=4`/"factura din avize" pe fallback** (sectiunea 2 punctul 7) — probabil imposibil
|
|
de atins prin acest drum (avizul sursa cere deja `id_pol`), dar nu exclus explicit prin cod sau
|
|
test — de confirmat inainte de implementare.
|
|
5. **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 in `COMUN`-urile lor pentru un apel simplu la `adauga_articol_factura(` nu s-a
|
|
terminat in nicio runda anterioara — de re-rulat inainte de implementare, nu de presupus incheiata.
|
|
6. **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).
|
|
7. **Trasabilitatea `CONT_VENIT` pe `VANZARI_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 din `scrie_in_vanzari`.
|
|
8. **`idfact_refolosire_si_documente.md`** — obstacol real pentru ca regenerarea (decizia 35) sa fie
|
|
completa (reemitere cu acelasi `ID_FACT`), in `PACK_CONTAFIN`, nu in `pack_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_factura` simplu 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.
|