Raport stocuri marfa 371 pe vechimi (dosar credit banca)

Sectiune dedicata pentru banca cu sumar pe grupe x bucket vechime
(0-6 luni, 6-12 luni, 1-2 ani, 2-3 ani, >3 ani), detaliu articole
si reconciliere contra sold contabil 371 din balanta (vbal).

- queries.py: STOCURI_371_SUMAR (ROLLUP grupa/subgrupa), STOCURI_371_DETALIU,
  STOCURI_371_SOLD_CONTABIL (sold sintetic din vbal, an/luna snapshot).
  Filtru stoc (cants+cant-cante) <> 0 pentru acoperire cu soldul contabil.
- main.py: CLI --aging-dates pentru evolutie multi-data a stocului >3 ani,
  pagina PDF dedicata cu nota metodologica + reconciliere (marker la diff >1%).
- recommendations.py: alerta CONCENTRARE cand stoc 371 >3 ani depaseste prag.
- config.py: threshold aged_stock_371_pct (default 15%).
- run.bat: header documentar cu argumentele disponibile + exemple.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-04-23 15:34:14 +00:00
parent 3f410c3fb8
commit 7afacd6664
5 changed files with 343 additions and 10 deletions

View File

@@ -440,6 +440,96 @@ ORDER BY zile_fara_miscare DESC NULLS FIRST
FETCH FIRST 100 ROWS ONLY
"""
# =============================================================================
# 12b. STOCURI MARFĂ 371 — SUMAR PE VECHIMI (pentru dosar credit bancă)
# =============================================================================
STOCURI_371_SUMAR = """
-- NOTĂ: :data_referinta = prima zi a lunii URMĂTOARE end-month (convenție proiect).
-- (:data_referinta - 1) = ultima zi a lunii de raport — folosit pentru:
-- (a) filtru snapshot vstoc: an=YEAR(data_ref-1), luna=MONTH(data_ref-1)
-- (b) calcul vechime: (data_ref - 1) - NVL(dataout, datain)
WITH s AS (
SELECT
s.id_grupa, s.grupa, s.id_subgrupa, s.subgrupa,
(s.cants + s.cant - s.cante) * s.pret AS val,
ROUND((:data_referinta - 1) - NVL(s.dataout, s.datain)) AS zile
FROM vstoc s
WHERE s.an = EXTRACT(YEAR FROM (:data_referinta - 1))
AND s.luna = EXTRACT(MONTH FROM (:data_referinta - 1))
AND s.cont = '371'
AND (s.cants + s.cant - s.cante) <> 0
)
SELECT
NVL(grupa, 'NECLASIFICAT') AS grupa,
NVL(subgrupa, '-') AS subgrupa,
GROUPING_ID(grupa, subgrupa) AS grouping_level,
ROUND(SUM(val), 2) AS valoare_total,
ROUND(SUM(CASE WHEN zile <= 180 THEN val ELSE 0 END), 2) AS val_0_6_luni,
ROUND(SUM(CASE WHEN zile > 180 AND zile <= 365 THEN val ELSE 0 END), 2) AS val_6_12_luni,
ROUND(SUM(CASE WHEN zile > 365 AND zile <= 730 THEN val ELSE 0 END), 2) AS val_1_2_ani,
ROUND(SUM(CASE WHEN zile > 730 AND zile <= 1095 THEN val ELSE 0 END), 2) AS val_2_3_ani,
ROUND(SUM(CASE WHEN zile > 1095 THEN val ELSE 0 END), 2) AS val_peste_3_ani
FROM s
GROUP BY ROLLUP(grupa, subgrupa)
ORDER BY GROUPING_ID(grupa, subgrupa), grupa, subgrupa
"""
# =============================================================================
# 12c. STOCURI MARFĂ 371 — DETALIU ARTICOLE
# =============================================================================
STOCURI_371_DETALIU = """
-- Vezi NOTA de la STOCURI_371_SUMAR.
SELECT
s.codmat AS cod_articol,
s.denumire,
s.nume_gestiune,
NVL(s.grupa, 'NECLASIFICAT') AS grupa,
NVL(s.subgrupa, '-') AS subgrupa,
s.um,
(s.cants + s.cant - s.cante) AS cantitate,
ROUND(s.pret, 4) AS pret_unitar,
ROUND((s.cants + s.cant - s.cante) * s.pret, 2) AS valoare,
s.datain AS data_intrare,
s.dataout AS data_ultima_iesire,
ROUND((:data_referinta - 1) - NVL(s.dataout, s.datain)) AS zile_vechime,
ROUND(((:data_referinta - 1) - NVL(s.dataout, s.datain)) / 365, 2) AS ani_vechime,
CASE
WHEN ROUND((:data_referinta - 1) - NVL(s.dataout, s.datain)) <= 180 THEN '0-6 luni'
WHEN ROUND((:data_referinta - 1) - NVL(s.dataout, s.datain)) <= 365 THEN '6-12 luni'
WHEN ROUND((:data_referinta - 1) - NVL(s.dataout, s.datain)) <= 730 THEN '1-2 ani'
WHEN ROUND((:data_referinta - 1) - NVL(s.dataout, s.datain)) <= 1095 THEN '2-3 ani'
ELSE '>3 ani'
END AS bucket_vechime,
s.lot,
s.adata_expirare AS data_expirare,
s.furnizor
FROM vstoc s
WHERE s.an = EXTRACT(YEAR FROM (:data_referinta - 1))
AND s.luna = EXTRACT(MONTH FROM (:data_referinta - 1))
AND s.cont = '371'
AND (s.cants + s.cant - s.cante) <> 0
ORDER BY zile_vechime DESC, valoare DESC
"""
# =============================================================================
# 12d. SOLD CONTABIL 371 (reconciliere cu raport)
# =============================================================================
STOCURI_371_SOLD_CONTABIL = """
-- Sold contabil 371 la finalul lunii de raportare, din balanta de verificare (vbal).
-- Filtrul (an, luna) = ultima luna raportata, identic cu vstoc:
-- an = EXTRACT(YEAR FROM (:data_referinta - 1))
-- luna= EXTRACT(MONTH FROM (:data_referinta - 1))
-- 371 este cont de activ => sold debitor. Folosim (solddeb - soldcred) ca sa fie
-- robust daca exista inregistrari cu sold credit (corectii). Se aduna pe toate
-- sucursalele (id_sucursala), pentru ca raportul vstoc acopera toate gestiunile.
SELECT
ROUND(SUM(NVL(b.solddeb, 0) - NVL(b.soldcred, 0)), 2) AS sold_371
FROM vbal b
WHERE b.cont = '371'
AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1))
AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1))
"""
# =============================================================================
# 13. ROTAȚIE STOCURI
# =============================================================================
@@ -2496,6 +2586,24 @@ QUERIES = {
'title': '⚠️ Stoc Lent (>90 zile)',
'description': 'Produse fără mișcare de peste 90 de zile'
},
'stocuri_371_sumar': {
'sql': STOCURI_371_SUMAR,
'params': {},
'title': 'Stocuri Marfă 371 — Sumar Vechimi (pentru bancă)',
'description': 'Valoarea stocului cont 371 pe grupe și buckets de vechime la data de referință'
},
'stocuri_371_detaliu': {
'sql': STOCURI_371_DETALIU,
'params': {},
'title': 'Stocuri Marfă 371 — Detaliu Articole',
'description': 'Lista completă articole cont 371 cu vechime și valoare'
},
'stocuri_371_sold_contabil': {
'sql': STOCURI_371_SOLD_CONTABIL,
'params': {},
'title': 'Stocuri Marfă 371 — Sold Contabil (reconciliere)',
'description': 'Sold 371 din rulaje la data ref pentru cross-check'
},
'rotatie_stocuri': {
'sql': ROTATIE_STOCURI,
'params': {},