#13: formular de facturare unificat - etapa curenta
Squash al branch-ului de lucru plan13-s2. Cod: clasa noua ofacturare_util (geometrie si utilitare de formular), inrolata in roafacturare.prg; meniul "Facturare (nou)" plat, cu reparatia literalului peste limita VFP de 255 de caractere care impiedica compilarea metodei. Livrare: changelog 2.11.19, marcajul de versiune DB pentru scripturile finale din SCRIPTURI_CLAR\2026\09, inventarul livrarii in docs/livrare_13.md si registrul de erori deschise. Documentatia de lucru a etapei (cercetare, rapoarte, handoff-uri, snapshot-uri de scripturi si backup-uri de rollback) a fost scoasa din arbore. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PkyjGyrV2S7932om4kfSiK
This commit is contained in:
@@ -1,553 +0,0 @@
|
||||
# De unde vine SCC-ul pe facturile din comandă/contract — și dacă modelul se poate refolosi pentru #13
|
||||
|
||||
Cercetare read-only, pe cod (VFP text + export `PACK_FACTURARE` curent) și pe baza vie (`MARIUSM_AUTO`
|
||||
pe `ROA_CENTRAL`, doar `SELECT`, 10.08.2026). Nu modifică nimic — nici `pack_facturare`, nici
|
||||
`ofacturare_comun.vc2`, nici `ofacturare_editare.prg`.
|
||||
|
||||
Continuă `docs\cercetare\coresp_cont_venchelt.md` (secțiunea 9) și `docs\plan_13_unificare_formular_facturare.md`
|
||||
(J-quater), care stabiliseră deja: FACT-024 verifică apartenența articolului la politica **de pe linie**,
|
||||
`id_pol` e parametru per-linie trimis de VFP (`V_ID_POL`, `adauga_articol_factura`), și pe contract
|
||||
articolul „liber" nu e de fapt fără politică — vine deja cu una atașată prin `cursor_contract`/`cursor_preturi`.
|
||||
|
||||
**Runda 2 (reformulare Marius):** prima trecere de mai jos (secțiunile D–C, păstrate ca dovadă) presupunea
|
||||
că întrebarea era „de unde vine `id_pol`". Marius a corectat premisa: el chiar emite facturi pe bază de
|
||||
document care **nu au** politică de preț și notă atașată **prin lanțul obișnuit** — ceea ce contrazicea
|
||||
concluzia inițială („`id_pol` gol → `FACT-024`, mereu"). Secțiunea 0 de mai jos reconciliază contradicția,
|
||||
pe cod și pe date reale, și e livrabilul principal al acestei runde. Sursa SQL folosită în ambele runde:
|
||||
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (823.337 octeți — fișierul
|
||||
cu același nume din `docs\` a fost șters în timpul sesiunii anterioare; numerele de linie de mai jos sunt
|
||||
verificate direct pe fișierul din `SCRIPTURI_CLAR`, nu preluate din plan).
|
||||
|
||||
---
|
||||
|
||||
## 0. Reconcilierea contradicției — Marius are dreptate, dar mecanismul nu e cel presupus în runda 1
|
||||
|
||||
**Verdict, cu citat**: `id_pol` `NULL` **tot** blochează `contabilizeaza_articol` necondiționat — asta nu
|
||||
s-a schimbat, e reconfirmat mai jos. Ce s-a stabilit greșit în runda 1 e presupunerea că **orice** linie de
|
||||
document trece prin `contabilizeaza_articol`. **Nu e adevărat**: pachetul are cel puțin **două rute
|
||||
paralele**, folosite azi în producție (confirmate pe date reale), care scriu o notă contabilă de vânzare
|
||||
**fără `id_pol` și fără `CRM_POLITICI_PRETURI`** — pentru că nu apelează deloc `contabilizeaza_articol`.
|
||||
|
||||
### 0a. Reconfirmare: `contabilizeaza_articol` nu tolerează `id_pol NULL`, în nicio ramură
|
||||
|
||||
```sql
|
||||
-- ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:7275-7302 (inceputul functiei, necondiționat)
|
||||
BEGIN
|
||||
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; -- id_pol NULL => X=NULL => NO_DATA_FOUND, mereu
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
... SELECT NUME_LISTA_PRETURI INTO lcPolitica FROM CRM_POLITICI_PRETURI WHERE id_pol = detalii_articol.id_pol;
|
||||
RAISE_APPLICATION_ERROR(-20000, '... (FACT-024)');
|
||||
```
|
||||
Nu există niciun `IF detalii_articol.id_pol IS NULL THEN ...` înainte de acest bloc — e primul lucru pe
|
||||
care funcția îl face, necondiționat, pentru orice apel. **Bonus, deja semnalat în runda 7** (`plan_13...
|
||||
md:1451-1457`, reconfirmat aici pe fișierul curent): al doilea `SELECT` din `EXCEPTION` (cel care aduce
|
||||
`lcPolitica` pentru mesaj) filtrează tot pe `id_pol = detalii_articol.id_pol`, deci și el dă `NO_DATA_FOUND`
|
||||
când `id_pol` e `NULL` — utilizatorul nu vede mesajul formatat „FACT-024", ci un `ORA-01403` brut,
|
||||
necaptat. În ambele cazuri: **eroare, tranzacție întreruptă, nimic scris**. Deci dacă o linie chiar ajunge
|
||||
la `contabilizeaza_articol` cu `id_pol` gol, nu există azi nicio cale silențioasă de succes.
|
||||
|
||||
### 0b. Ce am găsit real, pe date vii — 384 din 1113 linii `VANZARI_DETALII` active (34%) au `ID_POL` `NULL`
|
||||
|
||||
```sql
|
||||
select count(*), sum(case when id_pol is null then 1 else 0 end) from vanzari_detalii where sters=0;
|
||||
-- 1113 384
|
||||
```
|
||||
Deci liniile facturate fără `id_pol` **există masiv** în producție — nu e un caz exotic. Împărțite pe
|
||||
`VANZARI.TIP`:
|
||||
|
||||
| `TIP` | linii fără `id_pol` | din ele, rânduri `ACT` cu `SCC` populat | interpretare |
|
||||
|---|---|---|---|
|
||||
| `-12` | 97 | 588/604 | **ROAAUTO** (confirmat, `tip=-12` e explicit ROAAUTO — `plan_13...md:1710,1735`) |
|
||||
| `-1..-13` (restul) | ~140 | majoritar populat | variante storno/aviz ale documentelor de mai jos, nu cercetate individual |
|
||||
| `2` (**contract**) | 19 | populat, vezi 0c | facturare pe bază de contract, **rată/scadențar**, nu articol |
|
||||
| `1` (listă prețuri) | 1 | — | un singur caz, neexplorat separat |
|
||||
| `51` | 121 | 179/275 (cumulat) | tip necunoscut în codul VFP citit — posibil retail/POS, neidentificat |
|
||||
| **`3` (comandă, ROAFACTURARE)** | **0 din 66** | — | **niciun caz** — vezi 0d |
|
||||
|
||||
`select count(*), sum(case when id_pol is null then 1 else 0 end) from vanzari_detalii d join vanzari v on v.id_vanzare=d.id_vanzare where d.sters=0 and v.sters=0 and v.id_comanda is not null` → **66 / 0**. Pe ruta
|
||||
`COMENZI` a lui ROAFACTURARE (secțiunea A de mai jos), **`id_pol` nu e niciodată gol, pe datele disponibile.**
|
||||
Contradicția lui Marius nu se reproduce pe acest obiect precis.
|
||||
|
||||
### 0c. Mecanismul găsit: `contabilizeaza_rata` — notă contabilă direct din contract, fără politică, fără `id_pol`
|
||||
|
||||
Contractele cu facturare pe **rate/scadențar** (`CONTRACTE.OPT_FACTURARE IN (1,2)`) nu trec liniile prin
|
||||
`contabilizeaza_articol` — trec prin o funcție **separată**, `contabilizeaza_rata`:
|
||||
```sql
|
||||
-- ff_...:7549-7597
|
||||
FUNCTION contabilizeaza_rata(detalii_rata VANZARI_DETALII_TEMP%ROWTYPE) RETURN NUMBER IS
|
||||
BEGIN
|
||||
BEGIN
|
||||
SELECT NVL(B.ID_VENCHELT, pack_facturare.nid_venchelt), ..., C.SCD, C.ASCD, C.SCC, C.ASCC, C.CU_TVA, C.IN_VALUTA
|
||||
INTO ...
|
||||
FROM CONTRACTE A
|
||||
LEFT JOIN CRM_NOTE_VANZARI B ON A.ID_NOTA = B.ID_NOTA -- <- nota vine din CONTRACTE.ID_NOTA, NU din id_pol
|
||||
LEFT JOIN NOTE_CONTABILE C ON B.ID_SET = C.ID_SET
|
||||
WHERE A.STERS = 0 AND A.ID_CTR = detalii_rata.id_ctr AND B.STERS = 0;
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND THEN
|
||||
RAISE_APPLICATION_ERROR(-20000, 'Nu sunt configurate notele de vanzare pentru acest contract!');
|
||||
END;
|
||||
...
|
||||
V_INCASAT_CALCUL := V_INCASAT_CALCUL + pack_facturare.scrie_nota(..., V_SCD, V_ASCD, V_SCC, V_ASCC, ...);
|
||||
```
|
||||
`CONTRACTE` are coloană proprie `ID_NOTA` (confirmat pe schema vie: `NUMBER`, nullable) — **contractul însuși
|
||||
duce nota contabilă**, ales o singură dată la configurarea lui, independent de orice `id_pol`/politică de
|
||||
preț per articol. Confirmă exact tiparul din `cursor_contract` (secțiunea B mai jos, ramura „rată" a
|
||||
cursorului, `ff_...:2837-2893`): `NULL as id_articol, ..., NULL AS ID_POL` — liniile de rată **nu au
|
||||
niciodată `id_pol`, prin construcție**, pentru că nu sunt articole din nomenclator, sunt rate de scadențar.
|
||||
|
||||
**Confirmat pe o factură reală** (`MARIUSM_AUTO`, 10.08.2026):
|
||||
```sql
|
||||
-- id_vanzare 360, tip 2 (contract), linia din VANZARI_DETALII: id_articol NULL, id_pol NULL
|
||||
-- ACT pentru id_fact=5039903:
|
||||
-- ID_ACT SCD ASCD SCC ASCC SUMA EXPLICATIA
|
||||
-- 102204 4111 11 704 300 RATA 1
|
||||
-- 102205 4111 11 4427 57 TVA RATA 1
|
||||
```
|
||||
O factură reală, cu o linie fără `id_articol` și fără `id_pol`, **cu notă contabilă scrisă corect** (`SCD
|
||||
4111`, `SCC 704`) — exact dovada cerută. Mecanismul: **nota nu vine prin politică deloc**, vine direct din
|
||||
`CONTRACTE.ID_NOTA`, o singură dată per contract, la configurare — un tipar „un document duce o notă fixă",
|
||||
nu „fiecare linie duce o politică de preț".
|
||||
|
||||
### 0d. De ce nu se reproduce pe `COMENZI` (ROAFACTURARE): tabelul nu are echivalentul lui `ID_NOTA`
|
||||
|
||||
```sql
|
||||
select column_name from user_tab_columns where table_name='COMENZI';
|
||||
-- ID_COMANDA, NR_COMANDA, DATA_COMANDA, ID_PART, ID_GESTIUNE, ID_SECTIE, ID_SECTIE2, ID_CTR, ... (29 coloane)
|
||||
-- nicio ID_NOTA, nicio ID_POL, nicio coloana de contabilizare
|
||||
```
|
||||
`COMENZI` (antetul) nu duce nicio informație contabilă — singura legătură posibilă e `ID_CTR` (dacă
|
||||
comanda vine dintr-un contract). `COMENZI_ELEMENTE.ID_POL` rămâne singurul canal, și e `NOT NULL` (secțiunea
|
||||
A). Deci pe **acest** obiect, mecanismul „notă fără politică" descris de Marius **nu există** — dacă
|
||||
experiența lui vine de aici, ar însemna fie (a) o versiune de bază/schemă diferită de `MARIUSM_AUTO`, fie
|
||||
(b) o factură pe care a facturat-o efectiv prin ruta **contract cu rate** (secțiunea 0c) sau prin **ROAAUTO**
|
||||
(`tip -12`, deviz — tipar deja documentat în `coresp_cont_venchelt.md` §9b: `adauga_articol_factura_deviz`
|
||||
→ `scrie_in_vanzari`, fără `contabilizeaza_articol`, cu notă scrisă separat de fiecare produs), și a numit-o
|
||||
generic „factură pe bază de comandă". **Nu pot decide între aceste ipoteze fără să întreb** — dovada de cod
|
||||
și de date arată clar CARE mecanisme există și niciunul nu e pe `COMENZI` propriu-zis.
|
||||
|
||||
### 0e. Variantele din brief, verdict pe fiecare
|
||||
|
||||
- *„liniile de comandă primesc totuși un `id_pol` de undeva"* — **confirmat, dar nu ascuns**: da, primesc,
|
||||
documentat deja în secțiunea A/D veche, e vizibil în UI (`v_articole`), nu explică „fără politică".
|
||||
- *„`contabilizeaza_articol` nu e apelată pe ruta comandă, ci altă procedură"* — **fals pentru `COMENZI`**
|
||||
(`ofacturare.prg:292-293` → `cursor_comanda` → `crsarticole` → `do_scrie_articole` → `adauga_articol_factura`
|
||||
→ `contabilizeaza_articol`, ruta normală); **adevărat pentru contract-cu-rate** (`contabilizeaza_rata`) și
|
||||
pentru ROAAUTO/ROAACNPRO (proceduri proprii, deja documentate).
|
||||
- *„există o ramură de fallback în `contabilizeaza_articol` care ajunge la notă fără politică"* — **fals**,
|
||||
reconfirmat la 0a; funcția nu are asemenea ramură, blochează necondiționat.
|
||||
- *„FACT-024 se ridică doar când `id_pol` e nenul dar articolul nu e membru, `id_pol` nul merge pe alt
|
||||
drum"* — **fals ca „alt drum în aceeași funcție"**; **adevărat ca „alt drum = altă funcție"** (0c/0d).
|
||||
|
||||
---
|
||||
|
||||
## D. Răspunsul la întrebarea lui Marius, în cinci rânduri (actualizat după reconciliere)
|
||||
|
||||
**Depinde care „comandă".** Pe obiectul `COMENZI`/`COMENZI_ELEMENTE` al ROAFACTURARE (facturare „pe bază
|
||||
de comandă", tip 3), SCC-ul vine tot din `NOTE_CONTABILE.SCC` prin `id_pol` — **`id_pol` nu lipsește
|
||||
niciodată**, e coloană `NOT NULL` (confirmat pe schemă și pe date: 0 din 6868/66 linii fără el), populată la
|
||||
adăugarea articolului dintr-o listă deja restrânsă la o singură politică (`v_articole`/`com_vpreturi_utilizator`),
|
||||
politică aleasă o dată pe comandă. **Dacă experiența lui Marius vine din facturarea contractelor cu rate
|
||||
(scadențar, `OPT_FACTURARE IN (1,2)`) sau din ROAAUTO**, atunci da, există o rută reală, azi în producție,
|
||||
care scrie nota **fără nicio politică de preț**: pe contracte-cu-rate, nota vine direct din
|
||||
`CONTRACTE.ID_NOTA` (o coloană pe contract, aleasă o singură dată la configurarea lui, independentă de orice
|
||||
`id_pol` per linie) — `contabilizeaza_rata`, nu `contabilizeaza_articol`. Pe ROAAUTO/ROAACNPRO, nota o scrie
|
||||
o procedură proprie a produsului (`pack_acn.salveaza_regdoc` etc.), tot în afara lanțului `CRM_POLITICI_PRETURI`.
|
||||
**Aceste rute nu sunt „`id_pol` gol tratat cu grijă" — sunt căi care nu ating deloc `id_pol`/`contabilizeaza_articol`.**
|
||||
Pe contract-cu-**articole** (nu rate), tiparul rămâne cel din runda 1: `CTR_ARTICOLE.ID_POL_ART` → membru
|
||||
al unei politici reale, ca și pe comandă.
|
||||
|
||||
## E. Se poate refolosi „același model" pentru articolul ad-hoc din #13?
|
||||
|
||||
**Parțial. Mecanismul de jos (RPC + „apartenența e garantată prin construcția listei") e direct
|
||||
transplantabil — dar e deja exact ce propune rețeta în 4 pași din J-quater, nu o alternativă mai simplă
|
||||
la ea. Partea care ar simplifica cu adevărat lucrurile — „ia pur și simplu politica curentă și adaugă
|
||||
articolul în ea" — e decizia 24, deja retrasă de Marius, din motive care rămân valabile.**
|
||||
|
||||
Detaliat:
|
||||
|
||||
1. **Ce arată comandă/contract, tehnic**: operatorul nu alege niciodată `id_pol` pentru un articol anume —
|
||||
alege **o politică** (una dintre cele la care are drept, via `UTILIZATORI_ROL_INTERN` →
|
||||
`POLITICI_GRUPURI` → `CRM_POLITICI_PRETURI`), iar din acel moment orice articol afișat spre alegere e
|
||||
deja membru al ei (`com_vpreturi_utilizator`/`cPol_pret_art` filtrează `id_pol_art`/`id_pol IS NOT NULL`
|
||||
la sursă). Verificarea FACT-024 „trece" pe comandă/contract **nu pentru că ar exista un fallback** — ci
|
||||
pentru că nu există cale, în UI, de a ajunge la un articol care nu e deja membru. E o garanție de
|
||||
construcție a listei, nu o validare separată.
|
||||
2. **Acest tipar exact e deja documentat, ca fezabil, în `coresp_cont_venchelt.md` secțiunea „e)" / J-quater
|
||||
punctul 3** — RPC `pack_preturi.adauga_politica_pret_art` (deja folosit în producție,
|
||||
`ofacturare.vc2:15551-15587`) pentru „asigură apartenența", plus trimiterea lui `id_pol` neschimbat la
|
||||
`adauga_articol_factura`. Nu e nimic nou de inventat aici — comanda/contractul confirmă că tiparul
|
||||
„RPC + listă pre-filtrată" funcționează în producție de multă vreme, dar **planul A din J-quater deja îl
|
||||
folosește**. Refolosirea nu elimină pasul, îl confirmă.
|
||||
3. **Ce NU rezolvă modelul comandă/contract e alegerea SCC-ului corect per articol** — pe comandă/contract
|
||||
politica e **una singură, fixă**, aleasă pentru tot documentul/sesiunea, cu un singur `SCC` (orice ar
|
||||
fi el) pentru toate articolele adăugate așa. Aplicat identic pe `caut_articol` (restricționează
|
||||
rezultatele căutării din nomenclator la politica curentă a operatorului), rezultatul ar fi
|
||||
**exact ceea ce există deja azi ca „Cauta in lista de preturi…"** — nu rezolvă cazul pe care S4g/#13 îl
|
||||
cere explicit: un articol care **nu e membru al niciunei politici** (`plan_13...md:1711-1716`: „din
|
||||
nomenclator se oferă și articole gestionabile, și negestionabile"; „un articol fără `ID_POL` nu ajunge
|
||||
la cont gol, ci la eroare").
|
||||
4. **„Alege o politică fixă și pune articolul în ea" e literalmente decizia 24, deja retrasă**
|
||||
(`plan_13...md:926-930`): *„Decizia 24: articolul ales din nomenclator primește `id_pol`-ul unei
|
||||
politici de pret implicite. RETRASĂ în runda 8... prețul lui era o întrebare de configurare cu
|
||||
contabilul (care politică, cu ce `SCC`, una sau mai multe) și un cont de venit uniform pentru orice
|
||||
articol adăugat așa. Marius a ales în loc derivarea contului. Nu se reintroduce."* Motivul retragerii
|
||||
nu s-a schimbat: o politică unică (fie ea „a operatorului", ca pe comandă) dă un **singur** cont de
|
||||
venit oricărui articol, indiferent de natura lui (marfă/producție/serviciu) — exact opusul deciziei 27,
|
||||
care cere `SCC` diferențiat după clasa contului de gestiune al articolului (`707`/`711`/`702`/`703`/
|
||||
`7015`/`7018`/`704`).
|
||||
5. **Deci ce rămâne de făcut e exact pasul central din rețeta în 4 pași**: nu „cum trimit un `id_pol`
|
||||
valid la Oracle fără să ating `pack_facturare`" (asta e deja rezolvat, și demonstrat funcțional de
|
||||
comandă/contract) — ci „**care** politică, cu **care** `SCC`, pentru **acest** articol anume" — acolo
|
||||
comanda/contractul nu ajută, pentru că ele nu rezolvă niciodată această întrebare: politica le vine
|
||||
gata aleasă, de operator, o singură dată, nu calculată per articol.
|
||||
|
||||
**Verdict la „mă gândeam la același model" (dacă modelul e comandă/contract-cu-articole)**: da, la nivel de
|
||||
mecanism (RPC de inserare + membership garantat prin listă filtrată) — dar acel nivel era deja acoperit de
|
||||
planul A/decizia 27-bis. Nu, la nivelul la care ar simplifica ceva („nu mai calculăm SCC per articol, luăm
|
||||
politica gata aleasă") — pentru că acela e exact decizia 24, respinsă cu un motiv care rămâne valabil.
|
||||
|
||||
### E-bis. Dar există un al treilea model, mai simplu — cel din `contabilizeaza_rata` (secțiunea 0c)
|
||||
|
||||
Reconcilierea de la secțiunea 0 arată un tipar pe care raportul din runda 1 nu-l luase în calcul: **un
|
||||
document poate duce el însuși o notă contabilă fixă, complet în afara `CRM_POLITICI_PRETURI`, iar
|
||||
`pack_facturare` are deja o funcție care face exact asta** (`contabilizeaza_rata`, sursa `CONTRACTE.ID_NOTA`).
|
||||
Aplicat la #13, ideea ar fi: nu mai deriva `SCC` per articol și nu mai caut/construi o politică tehnică — scrie
|
||||
nota direct, cu conturile calculate în VFP (regula deciziei 27: `CORESP_CONT_VENCHELT`/`NOM_ARTICOLE.CONT`/
|
||||
`704`), printr-o cale de scriere **paralelă**, ca și pentru rate.
|
||||
|
||||
**De ce nu se poate fără să ating `pack_facturare`, și asta contează, dat fiind decizia 27-bis**:
|
||||
- `contabilizeaza_rata` există deja, dar e legată strict de `VANZARI_DETALII_TEMP` cu semantică de „rată de
|
||||
contract" (`detalii_rata.id_ctr` obligatoriu în interogare) — nu e apelabilă pentru un rând de articol
|
||||
obișnuit (`id_articol` populat, `id_pol` gol) fără o funcție **nouă**, analogă, în `pack_facturare`.
|
||||
- Sursa notei la rată e `CONTRACTE.ID_NOTA` — o coloană pe un document care **există deja** și **se
|
||||
configurează o dată** (la crearea contractului). Pentru articolul ad-hoc de pe formularul unificat nu
|
||||
există azi un asemenea „document-sursă cu notă fixă" — ar trebui inventat (ex. o coloană similară pe
|
||||
antetul facturii, sau parametru nou la `adauga_articol_factura`) — tot cod nou în `PACK_FACTURARE`.
|
||||
- **Constrângerea „pack_facturare rămâne neatins" (decizia 27-bis) exclude explicit acest drum.** Dacă
|
||||
Marius e dispus s-o relaxeze, tiparul `contabilizeaza_rata` e un precedent real, mai simplu decât rețeta
|
||||
în 4 pași — pentru că elimină complet nevoia unei „politici tehnice" și a RPC-ului de apartenență
|
||||
(`pack_preturi.adauga_politica_pret_art`): SCC-ul ar merge direct în `scrie_nota`, fără ocolul prin
|
||||
`CRM_POLITICI_PRET_ART`. Dacă nu, rămâne exact ce spunea verdictul din runda 1: rețeta în 4 pași (planul
|
||||
A, tot în VFP) rămâne singura variantă compatibilă cu constrângerea.
|
||||
|
||||
**Verdict final, actualizat**: modelul comandă/contract (runda 1) nu ajută, motivele rămân cele deja arătate.
|
||||
Dar există un al doilea model real, comandă**-rate**/contract-rate, care **ar** ajuta — cu prețul de a
|
||||
renunța la „`pack_facturare` neatins". E o decizie de produs pentru Marius, nu o concluzie tehnică unică —
|
||||
raportul pune ambele opțiuni pe masă, cu costul lor exact.
|
||||
|
||||
**Corecție importantă, din verificarea independentă de mai jos („Completare de la sesiunea principală"):**
|
||||
politica `7 DISCOUNT` (870 linii de comandă, `SCD=667`/`SCC=4111`, notă `2 DISCOUNT`) e deja, în producție,
|
||||
o **politică tehnică folosită doar ca rutare contabilă**, nu ca listă comercială — exact tiparul „o politică
|
||||
per scop contabil" pe care planul A/decizia 27-bis îl propune (nu decizia 24, care era o politică unică
|
||||
pentru *orice* articol ad-hoc, indiferent de natură). Deci precedentul operațional pentru „politică tehnică,
|
||||
una per destinație contabilă" **există deja pe ruta comandă** — mai puternic decât `gnId_pol_pret_stoc`
|
||||
(care e un singur cont pentru tot stocul). **Dar** aceeași verificare arată că garanția „apartenență prin
|
||||
construcția listei" (punctul 1 de mai sus) **nu e etanșă pe date**: 37 din 6868 linii active de comandă au
|
||||
un articol care nu (mai) e membru al politicii înregistrate pe linie — verificare, cauză și comportament la
|
||||
facturare, deschise, vezi secțiunea finală.
|
||||
|
||||
---
|
||||
|
||||
## A. Ruta COMANDĂ
|
||||
|
||||
### A.1 — `cursor_comanda` selectează `ID_POL`? Da, direct de pe linia comenzii
|
||||
|
||||
```sql
|
||||
-- D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:2996-3054 (ramura factură)
|
||||
OPEN V_CURSOR FOR
|
||||
SELECT ROWNUM as id_c,
|
||||
A.ID_ARTICOL,
|
||||
NULL AS LOT,
|
||||
NULL as SERIE,
|
||||
A.ID_POL, -- <- direct din COMENZI_ELEMENTE, nu derivat
|
||||
A.ID_VALUTA, ...
|
||||
FROM COMENZI_ELEMENTE A
|
||||
LEFT JOIN CRM_POLITICI_PRET_ART B
|
||||
ON A.ID_POL = B.ID_POL AND A.ID_ARTICOL = B.ID_ARTICOL
|
||||
...
|
||||
WHERE A.STERS = 0 AND A.ID_COMANDA = V_ID_COMANDA ...
|
||||
```
|
||||
(identic la `:3084-3140` pentru ramura aviz, `V_TIP > 20`). `A.ID_POL` e coloană directă pe
|
||||
`COMENZI_ELEMENTE` — `LEFT JOIN CRM_POLITICI_PRET_ART B` de mai jos **nu** derivă `id_pol`, doar aduce
|
||||
`DISCOUNT_UNITAR`/`PROC_TVAV` pentru acea combinație `(id_pol, id_articol)`.
|
||||
|
||||
### A.2 — Unde e stocat: `COMENZI_ELEMENTE.ID_POL`, coloană `NOT NULL`
|
||||
|
||||
Confirmat pe schema vie (`MARIUSM_AUTO`, `ROA_CENTRAL`, 10.08.2026):
|
||||
```sql
|
||||
select column_name, data_type, nullable from user_tab_columns where table_name='COMENZI_ELEMENTE';
|
||||
-- ID_POL NUMBER N <- NOT NULL
|
||||
select count(*), sum(case when id_pol is null then 1 else 0 end) from comenzi_elemente where sters=0;
|
||||
-- 6868 0
|
||||
```
|
||||
**`ID_POL` e obligatoriu la nivel de constrângere de tabel**, nu doar „de obicei populat" — și cele 6868
|
||||
linii active din baza vie confirmă 0 excepții. E o coloană de **linie**, nu de antet (nu există `ID_POL`
|
||||
pe `COMENZI`).
|
||||
|
||||
### A.3 — Cine îl pune acolo la crearea comenzii
|
||||
|
||||
Nu e o alegere liberă per articol — e moștenit dintr-o **politică aleasă o singură dată pe comandă**:
|
||||
|
||||
```
|
||||
COMUN\clase\ocomenzi.vc2:1849-1870 (do_modifica, la deschiderea/crearea comenzii)
|
||||
Do Case
|
||||
Case Inlist(loRec.interna,2,5)
|
||||
If lnTip = 0 And Reccount('crscomanda_curenta')>0
|
||||
lnIdPol = id_pol && preia politica de pe comanda existenta
|
||||
Else
|
||||
loCauta = caut_politici_curente_utilizator() && cautare manuala, comanda noua
|
||||
If !Empty(Nvl(loCauta.id_pol,0))
|
||||
lnIdPol = loCauta.id_pol
|
||||
Else
|
||||
Return
|
||||
Endif
|
||||
Endif
|
||||
update_articole_politica(lnIdPol)
|
||||
Case loRec.interna = 3
|
||||
update_articole_politica_comenzi([IDPOLITICAPRET]) && optiune implicita globala
|
||||
Otherwise
|
||||
update_articole_politica_comenzi([ID_LISTA_PRETURI_PV]) && optiune implicita globala
|
||||
Endcase
|
||||
```
|
||||
Deci: pentru un tip de comandă (`interna` 2/5) operatorul **caută explicit** o politică
|
||||
(`caut_politici_curente_utilizator`); pentru celelalte tipuri, politica vine dintr-o **opțiune globală**
|
||||
(`gnIdPoliticaPret`/`gnId_lista_preturi_PV`, citite în `extrage_optiuni_firma`,
|
||||
`update_comenzi.prg:16-29`). Nu se moștenește de la client.
|
||||
|
||||
Politica aleasă filtrează lista de articole disponibile de adăugat:
|
||||
```
|
||||
COMUN\programe\update_comenzi.prg:31-60 (update_articole_politica)
|
||||
select p.id_articol,p.id_pol,p.pret,... from com_vpreturi_utilizator p ...
|
||||
where p.id_util = <<gnIdUtil>> and p.id_pol = <<tnIdPol>>
|
||||
```
|
||||
```sql
|
||||
-- D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\01\ff_2026_01_21_01_FACTURARE.sql:3-30
|
||||
create or replace view com_vpreturi_utilizator as
|
||||
select a.id_util, b.id_politica as id_pol, ..., d.id_articol, d.pret, ...
|
||||
from utilizatori_rol_intern a
|
||||
left join politici_grupuri b on a.id_grup = b.id_grup
|
||||
left join crm_politici_preturi c on b.id_politica = c.id_pol
|
||||
left join crm_politici_pret_art d on c.id_pol = d.id_pol
|
||||
left join nom_articole e on d.id_articol = e.id_articol
|
||||
where a.sters = 0 and b.sters = 0 and ... and d.id_pol is not null and ...
|
||||
```
|
||||
`v_articole` (grid-ul de adăugare articole pe comandă, `ocomenzi.vc2:4005-4014`,
|
||||
`RecordSource = "v_articole"`) e populat strict din acest view, **filtrat `d.id_pol IS NOT NULL`** — deci
|
||||
orice articol afișat spre alegere e deja membru garantat. La alegere (`do_adauga`,
|
||||
`ocomenzi.vc2:4645-4702`) și la salvare (`do_scrie_articole`, `:4864-4899`):
|
||||
```
|
||||
ocomenzi.vc2:4885-4893
|
||||
Scatter Name poArticol
|
||||
...
|
||||
lcSql = [begin pack_comenzi.adauga_articol_comanda(] + Alltrim(Str(This.nId)) + [,] + ;
|
||||
Alltrim(Str(poArticol.id_articol)) + [,] + Alltrim(Str(poArticol.id_pol)) + [,] + ...
|
||||
```
|
||||
`poArticol.id_pol` (scatter din `v_articole`) merge neschimbat în `COMENZI_ELEMENTE.ID_POL`. Nu există în
|
||||
`ocomenzi.vc2` niciun al doilea punct de adăugare a articolelor pe comandă (nicio cale către `caut_articol`
|
||||
de nomenclator liber) — `v_articole` e singura sursă.
|
||||
|
||||
### A.4 — Ce se întâmplă când linia de comandă are `ID_POL` gol la facturare
|
||||
|
||||
**Nu se poate întâmpla, prin construcție dublă**: (a) `COMENZI_ELEMENTE.ID_POL` e `NOT NULL` la nivel de
|
||||
Oracle — un `INSERT` cu `id_pol` gol ar da `ORA-01400`, nu ajunge niciodată să fie facturat; (b) singurul
|
||||
punct de inserare din VFP (`pack_comenzi.adauga_articol_comanda`, apelat cu `poArticol.id_pol` din
|
||||
`v_articole`) nu poate produce `id_pol` gol, pentru că sursa (`com_vpreturi_utilizator`) filtrează deja
|
||||
`id_pol IS NOT NULL`. Verificat pe date reale: 0 din 6868 linii active. Spre deosebire de nomenclator
|
||||
(`caut_articol`, unde coloana `id_pol` **nu există deloc** în SELECT), pe comandă întrebarea „ce se
|
||||
întâmplă la gol" nu are un răspuns de cod (fallback/eroare) pentru că premisa nu apare niciodată.
|
||||
|
||||
---
|
||||
|
||||
## B. Ruta CONTRACT
|
||||
|
||||
Produsul e separat, **`D:\ROA\ROACONTRACTE`** (există în arbore, alături de `ROAFACTURARE`).
|
||||
|
||||
### B.1 — Cursorul de facturare selectează `ID_POL`? Da, dar prin `ID_POL_ART`, nu direct
|
||||
|
||||
```sql
|
||||
-- D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:2718-2836 (cursor_contract, V_CURSOR2 = grd_contracte)
|
||||
SELECT ..., id_pol, ...
|
||||
FROM (SELECT A.ID_CTR, C.ID_ARTICOL, NULL as id_rata, C.ID_POL, ...
|
||||
FROM CONTRACTE A
|
||||
LEFT JOIN CTR_ARTICOLE B ON A.ID_CTR = B.ID_CTR
|
||||
LEFT JOIN CRM_POLITICI_PRET_ART C ON B.ID_POL_ART = C.ID_POL_ART -- <- cheia stocata e ID_POL_ART
|
||||
LEFT JOIN NOM_ARTICOLE E ON C.ID_ARTICOL = E.ID_ARTICOL ...
|
||||
```
|
||||
Grid-ul principal de adăugare articole pe contract (`crsarticole`, folosit pentru „adăugare liberă") **nu**
|
||||
vine din acest cursor — vine dintr-un apel separat, în interiorul aceleiași proceduri:
|
||||
```sql
|
||||
-- ff_...:2940-2948
|
||||
pack_facturare.cursor_preturi(V_DATA_CURS, V_TIP, V_ID_VALUTA, V_ID_GESTIUNE_INIT,
|
||||
V_LUNA, V_AN, V_ID_UTIL, V_ID_SUCURSALA, V_CURSOR);
|
||||
```
|
||||
adică **exact aceeași sursă ca „lista de prețuri" (secțiunea C)** — confirmă din nou concluzia din runda
|
||||
anterioară (`retur_si_lista_preturi.md` B7): grid-ul „liber" de pe contract nu e liber de politică, e lista
|
||||
de prețuri normală a operatorului.
|
||||
|
||||
### B.2 — Unde e stocat pe contract: `CTR_ARTICOLE.ID_POL_ART` (linie, nullable)
|
||||
|
||||
```sql
|
||||
select column_name, nullable from user_tab_columns where table_name='CTR_ARTICOLE';
|
||||
-- ID_POL_ART Y <- nullable, spre deosebire de COMENZI_ELEMENTE.ID_POL
|
||||
select count(*), sum(case when id_pol_art is null then 1 else 0 end) from ctr_articole;
|
||||
-- 27 6
|
||||
```
|
||||
Spre deosebire de comandă, contractul stochează **`ID_POL_ART`** — FK direct la rândul din
|
||||
`CRM_POLITICI_PRET_ART` (articol+politică), nu la politică ca atare — și coloana **e nullable**, fără
|
||||
constrângere de tabel. Pe datele reale (bază de dezvoltare, eșantion mic — 27 rânduri în total, deci
|
||||
**nu extrapolez procentul la producție**), 6 din 27 rânduri nu au `id_pol_art`. Dacă un asemenea rând ar
|
||||
ajunge selectat spre facturare prin `V_CURSOR2`/`grd_contracte` (nu prin `crsarticole`, care e mereu lista
|
||||
de prețuri), `LEFT JOIN ... ON B.ID_POL_ART = C.ID_POL_ART` nu găsește nimic, `id_pol` iese `NULL` în
|
||||
cursor — același drum spre FACT-024 ca la nomenclator. **Neverificat**: dacă UI-ul (`grd_contracte`) permite
|
||||
efectiv selecția unei asemenea linii spre facturare sau o filtrează/dezactivează — nu am urmărit acel cod
|
||||
de grid, în afara bugetului acestei runde.
|
||||
|
||||
### B.3 — Cine îl pune acolo la crearea contractului
|
||||
|
||||
`D:\ROA\ROACONTRACTE\Clase\ferestre_contracte.vc2`, `PROCEDURE do_adauga_obiectul` (`:9454+`):
|
||||
```
|
||||
:9464-9470
|
||||
Case gnParametru_prog = 1 && clienti
|
||||
lcSel = [{call pack_crm.get_politici_grup(] + Alltrim(Str(gnIdUtil)) + [,] + ;
|
||||
Alltrim(Str(goContract.id_valuta)) + [,?gnIdSucursala)}]
|
||||
... INTO Cursor crsPoliticiGrup1 ...
|
||||
```
|
||||
```
|
||||
:9486-9500
|
||||
fpp = Createobject("frm_politica_preturi") && operatorul alege O politica dintre cele la care are drept
|
||||
fpp.Show(1)
|
||||
...
|
||||
Select *, PRETFTVA As pret_unitar, 1 As cant, ... FROM cPol_pret_art With (Buffering = .T.) ;
|
||||
WHERE ales = 1 INTO Cursor cAles && articolele bifate, deja membre ale politicii alese
|
||||
```
|
||||
`pack_crm.get_politici_grup` e echivalentul ROACONTRACTE al lanțului
|
||||
`UTILIZATORI_ROL_INTERN → POLITICI_GRUPURI → CRM_POLITICI_PRETURI` folosit și de comandă/factură normală —
|
||||
operatorul primește lista politicilor lui, alege una, `cPol_pret_art` (bind pe `CRM_POLITICI_PRET_ART`
|
||||
pentru politica aleasă) afișează articolele ei, iar rândurile bifate (`ales=1`) devin linii `CTR_ARTICOLE`
|
||||
cu `id_pol_art` = `ID_POL_ART`-ul din acel rând. Din nou: **nu se alege un articol liber, se alege dintr-o
|
||||
listă deja restrânsă la politică.**
|
||||
|
||||
### B.4 — Ce se întâmplă cu `ID_POL_ART` gol la facturare
|
||||
|
||||
Vezi B.2 — spre deosebire de comandă, **nu e imposibil prin constrângere de schemă** (coloana e nullable),
|
||||
și există cazuri reale (6/27) în baza de dezvoltare. Comportamentul la facturare (dacă acea linie ajunge
|
||||
selectată) urmează același `NULL → FACT-024` ca la nomenclator — **neconfirmat direct pe o factură reală**,
|
||||
dedus din structura JOIN a cursorului (B.1).
|
||||
|
||||
---
|
||||
|
||||
## C. Ruta LISTĂ DE PREȚURI (tip 1/5/7/10/22/29/45), ca termen de comparație
|
||||
|
||||
**Corectare față de premisa din brief**: `id_pol` pe această rută **nu vine din alegerea operatorului pe
|
||||
document** pentru majoritatea tipurilor — vine automat din rolul operatorului logat, exact ca pe comandă,
|
||||
dar fără nicio interacțiune UI.
|
||||
|
||||
`ofacturare.prg:279-282` (apelul cursorului pentru tip 1,5,7,10,22,23,29):
|
||||
```
|
||||
lcSqlCursor = [{call pack_facturare.cursor_preturi(?poDate.zi_curs,?poDate.tip,?poDate.id_valuta,] + ;
|
||||
[?poDate.id_gestiune_init,?gnLuna,?gnAn,?gnIdUtil,?gnIdSucursala)}]
|
||||
```
|
||||
`poDate.id_pol` **nu e printre parametri**. `cursor_preturi` (`ff_...:2138-2354`) derivă `A.ID_POL` intern:
|
||||
```sql
|
||||
-- ff_...:2222-2251 (V_TIP IN (1,2)) / 2330-2354 identic ca structura, tot fara parametru id_pol
|
||||
FROM (select a1.id_util, a3.id_pol, ...
|
||||
from utilizatori_rol_intern a1
|
||||
left join politici_grupuri a2 on a1.id_grup = a2.id_grup
|
||||
left join crm_politici_preturi a3 on a2.id_politica = a3.id_pol
|
||||
...
|
||||
where a1.id_util = V_ID_UTIL
|
||||
and NVL(a1.ID_SUCURSALA,-99) = NVL(V_ID_SUCURSALA,-99)
|
||||
and <data curentă între valabilitatea politicii>) A
|
||||
LEFT JOIN CRM_POLITICI_PRET_ART B ON A.ID_POL = B.ID_POL
|
||||
```
|
||||
Adică `id_pol` per linie vine din rolul de utilizator (`UTILIZATORI_ROL_INTERN.ID_UTIL = V_ID_UTIL`) și
|
||||
sucursală — **niciodată dintr-o alegere pe documentul curent**, pentru tip 1/2/5/7/10/22/29/45.
|
||||
|
||||
Câmpul de căutare vizibil pe antet există, dar e **inert pentru aceste tipuri**:
|
||||
```
|
||||
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, ...
|
||||
```
|
||||
`poDate.id_pol` e citit efectiv (trimis la Oracle) **doar** pentru `cursor_gestiune`, tip 41/23
|
||||
(`ofacturare.prg:297,777`); e validat ca obligatoriu **doar** pentru aceleași două tipuri
|
||||
(`ofacturare.vc2:7334-7337`: *„Nu ati ales politica de preturi!"*). Pe factura normală din listă de
|
||||
prețuri, câmpul poate rămâne gol fără nicio consecință — nu alimentează nimic.
|
||||
|
||||
**Concluzie C**: „lista de preț pe document" nu există ca mecanism activ pentru rutele principale — e „lista
|
||||
de preț a operatorului logat", determinată automat de rolul lui în `UTILIZATORI_ROL_INTERN`. Fiecare linie
|
||||
din `crsarticole` vine deja cu propriul `A.ID_POL` din acest join; dacă operatorul are mai multe grupuri de
|
||||
politici active simultan, teoretic același articol ar putea apărea de mai multe ori cu `id_pol` diferit —
|
||||
**neverificat pe date reale**, în afara bugetului acestei runde.
|
||||
|
||||
---
|
||||
|
||||
## Ce nu s-a putut stabili și de ce
|
||||
|
||||
- **B.4, comportamentul exact la facturare a unei linii de contract cu `ID_POL_ART` gol** — dedus din
|
||||
structura JOIN a `cursor_contract`, nu confirmat pe o factură reală emisă din contract cu o asemenea
|
||||
linie (ar necesita un contract de test cu o linie fără politică, apoi o încercare de facturare — în
|
||||
afara bugetului read-only al acestei runde).
|
||||
- **Dacă `grd_contracte` (UI) permite selecția/afișarea unei linii cu `id_pol_art` gol** — nu am urmărit
|
||||
codul de grid din `ROACONTRACTE`/`ofacturare.vc2` pentru acest caz specific.
|
||||
- **Dacă un operator cu mai multe grupuri de politici active poate primi articole duplicate cu `id_pol`
|
||||
diferit în `crsarticole`** (secțiunea C) — plauzibil din structura JOIN-ului (fără `DISTINCT` pe
|
||||
`a1.id_util`), neverificat pe date reale.
|
||||
- **Eșantionul `CTR_ARTICOLE` e mic (27 rânduri) în baza de dezvoltare** — raportul 6/27 fără
|
||||
`id_pol_art` e o dovadă reală, dar nu extrapolabilă direct la volumul de producție; merită o verificare
|
||||
separată pe o bază cu volum de producție dacă decizia depinde de frecvența cazului.
|
||||
- **Cele 37 de linii de comandă active cu articol ne-membru al politicii de pe linie** (semnalate în
|
||||
„Completare de la sesiunea principală") — cauza (import? editare ulterioară a politicii? ștergere din
|
||||
`CRM_POLITICI_PRET_ART` după ce comanda a fost creată?) nu e stabilită, și nici comportamentul real la
|
||||
facturare (`FACT-024`/`ORA-01403` așteptat pe cod, neconfirmat pe o încercare reală). E cea mai
|
||||
importantă verificare rămasă înainte de S4g — dacă garanția „membership prin construcția listei" se sparge
|
||||
și pe alte linii similare, tot raționamentul din secțiunea E (paragraful 1) trebuie recalibrat.
|
||||
- **`VANZARI.TIP = 51`** — 121 de linii fără `id_pol`, cu 179/275 rânduri `ACT` cu `SCC` populat cumulat pe
|
||||
documentele aferente — nu am identificat ce tip de document e (nu apare în `Do Case` din
|
||||
`ofacturare.prg:266-308`); posibil vânzare retail/POS sau un tip specific altui produs ROA. Neexplorat.
|
||||
- **Restul tipurilor negative (`-1`…`-13`, în afară de `-12`=ROAAUTO)** — nu au fost identificate individual;
|
||||
presupun variante storno/aviz ale rutelor deja documentate, dar nu s-a verificat pe cod care produs le
|
||||
generează.
|
||||
- **Dacă experiența lui Marius vine efectiv din contract-cu-rate, din ROAAUTO, sau din altă rută
|
||||
neidentificată (`51`, negative)** — nu s-a putut stabili fără să-l întrebăm direct; secțiunea 0d
|
||||
enumeră ipotezele plauzibile, cu dovezi pentru fiecare, dar nu poate alege între ele.
|
||||
|
||||
---
|
||||
|
||||
## Completare de la sesiunea principala (confirmare pe schema, 10.08.2026)
|
||||
|
||||
Verdictul de mai sus a fost verificat independent, pentru ca **contrazice o afirmatie a lui Marius**
|
||||
(„fac facturi pe baza de comanda care nu au politica de pret"). Confirmat:
|
||||
|
||||
- `COMENZI_ELEMENTE.ID_POL` — `nullable = N`, constrangerea `SYS_C0015376` (`"ID_POL" IS NOT NULL`) plus
|
||||
`FK_COMENZI_ELEMENTE_002`. In date: **7108 randuri total, 0 cu `ID_POL` nul, 0 cu `ID_POL` = 0**, 9
|
||||
politici distincte in uz. Pe liniile active (`STERS = 0`): 6868, tot 0 nule.
|
||||
- `CTR_ARTICOLE.ID_POL_ART` — `nullable = Y`. Confirmata asimetria semnalata in raport.
|
||||
- Toate cele 9 politici folosite pe linii de comanda au `ID_NOTA` si ajung la un `SCC`.
|
||||
|
||||
**Doua observatii noi, care nu erau in raport:**
|
||||
|
||||
1. **Politica `7 DISCOUNT` e o politica tehnica de rutare contabila, folosita in producție.** Apare pe
|
||||
**870 de linii de comanda** si trimite la nota `2 DISCOUNT` (`SCD = 667`, `SCC = 4111`). Nu e o lista
|
||||
comerciala de preturi — e o politica existenta doar ca sa duca linia la o nota contabila anume. **E
|
||||
precedentul de care are nevoie decizia 27**, si e mai apropiat de ce cere #13 decat
|
||||
`gnId_pol_pret_stoc` (care e o singura politica pentru tot stocul). Tiparul „politica tehnica per scop
|
||||
contabil" nu trebuie inventat: exista.
|
||||
2. **Garantia „apartenenta prin construcția listei" nu e etanșă in date.** Din 6868 de linii active de
|
||||
comanda, **37 au un articol care nu e membru al politicii de pe linie**
|
||||
(`NOT EXISTS (SELECT 1 FROM crm_politici_pret_art WHERE id_pol = e.id_pol AND id_articol = e.id_articol)`).
|
||||
Adica 37 de linii care, la facturare, ar trebui sa cada cu `FACT-024`. Cauza nu e stabilita — import,
|
||||
sau editarea / stergerea articolului din politica dupa introducerea comenzii. **Punctul 1 al secțiunii E
|
||||
(„nu exista cale, in UI, de a ajunge la un articol care nu e deja membru") e corect despre UI, dar nu
|
||||
despre starea datelor.** De verificat inainte de S4g: daca acele 37 de linii se factureaza fara eroare,
|
||||
exista o cale nedescoperita si intrebarea deciziei 32 se redeschide.
|
||||
|
||||
Interogarile: schema `MARIUSM_AUTO` pe `ROA_CENTRAL`, doar `SELECT`.
|
||||
Reference in New Issue
Block a user