Added detailed calculation formulas with accounting references for managers to understand and verify financial indicators: - INDICATORI_GENERALI (6 formulas): grad indatorare, autonomie financiara, rata datoriilor, marja neta, ROA, rotatia activelor - INDICATORI_LICHIDITATE (4 formulas): lichiditate curenta, quick ratio, cash ratio, fond de rulment - CICLU_CONVERSIE_CASH (4 formulas): DIO, DSO, DPO, CCC - DSO_DPO (2 formulas): DSO, DPO with detailed sources Each formula includes: - Mathematical calculation (e.g., "Datorii / Capital Propriu") - Account references (e.g., "cont 16x,40x,42x,44x,46x / cont 10x,11x,12x,117") - Data sources for verification (e.g., "jurnal vanzari vjv2025") Also fixed ORA-32039 error by renaming CTE 'vanzari' to 'vanzari_calc' to avoid conflict with table name. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2532 lines
111 KiB
Python
2532 lines
111 KiB
Python
"""
|
|
SQL Queries for Data Intelligence Report
|
|
OPTIMIZED: All queries use base tables (vanzari, vanzari_detalii) with Oracle hints
|
|
for index usage (IDX_VANZARI_NR) instead of views (fact_vfacturi2, fact_vfacturi_detalii).
|
|
Other views: vstoc, vrul are still used where appropriate.
|
|
|
|
IMPORTANT: Price calculation considers pret_cu_tva flag:
|
|
- If pret_cu_tva = 1: price includes VAT, must divide by (1 + proc_tvav/100)
|
|
- If pret_cu_tva = 0: price is already without VAT
|
|
Formula: CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 1. MARJA PER CLIENT (OPTIMIZAT - folosește tabele de bază + indexuri)
|
|
# =============================================================================
|
|
MARJA_PER_CLIENT = """
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
f.id_part,
|
|
p.denumire AS client,
|
|
p.cod_fiscal,
|
|
COUNT(DISTINCT f.id_vanzare) AS nr_facturi,
|
|
ROUND(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 2) AS vanzari_fara_tva,
|
|
ROUND(SUM(d.cantitate * d.pret_achizitie), 2) AS cost_total,
|
|
ROUND(SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)), 2) AS marja_bruta,
|
|
ROUND(
|
|
CASE WHEN SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) > 0
|
|
THEN SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) * 100.0 / SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END)
|
|
ELSE 0 END
|
|
, 2) AS procent_marja
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_parteneri p ON f.id_part = p.id_part
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0
|
|
AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -:months)
|
|
GROUP BY f.id_part, p.denumire, p.cod_fiscal
|
|
ORDER BY marja_bruta DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 2. CLIENȚI CU MARJĂ MICĂ (sub prag) - OPTIMIZAT
|
|
# =============================================================================
|
|
CLIENTI_MARJA_MICA = """
|
|
SELECT * FROM (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
p.denumire AS client,
|
|
p.cod_fiscal,
|
|
ROUND(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 2) AS vanzari_fara_tva,
|
|
ROUND(SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)), 2) AS marja_bruta,
|
|
ROUND(
|
|
CASE WHEN SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) > 0
|
|
THEN SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) * 100.0 / SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END)
|
|
ELSE 0 END
|
|
, 2) AS procent_marja
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_parteneri p ON f.id_part = p.id_part
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -:months)
|
|
GROUP BY f.id_part, p.denumire, p.cod_fiscal
|
|
HAVING SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) > :min_sales
|
|
)
|
|
WHERE procent_marja < :margin_threshold
|
|
ORDER BY vanzari_fara_tva DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 3. MARJA PER CATEGORIE (Grupă + Subgrupă) - OPTIMIZAT
|
|
# =============================================================================
|
|
MARJA_PER_CATEGORIE = """
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
NVL(sg.grupa, 'NECLASIFICAT') AS grupa,
|
|
NVL(sg.subgrupa, 'NECLASIFICAT') AS subgrupa,
|
|
COUNT(DISTINCT f.id_vanzare) AS nr_facturi,
|
|
ROUND(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 2) AS vanzari_fara_tva,
|
|
ROUND(SUM(d.cantitate * d.pret_achizitie), 2) AS cost_total,
|
|
ROUND(SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)), 2) AS marja_bruta,
|
|
ROUND(
|
|
CASE WHEN SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) > 0
|
|
THEN SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) * 100.0 / SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END)
|
|
ELSE 0 END
|
|
, 2) AS procent_marja
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_articole art ON d.id_articol = art.id_articol
|
|
LEFT JOIN vgest_art_sbgr sg ON art.id_subgrupa = sg.id_subgrupa
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -:months)
|
|
GROUP BY sg.id_grupa, sg.grupa, art.id_subgrupa, sg.subgrupa
|
|
ORDER BY vanzari_fara_tva DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 4. PRODUCȚIE PROPRIE vs MARFĂ REVÂNDUTĂ - OPTIMIZAT
|
|
# =============================================================================
|
|
PRODUCTIE_VS_REVANZARE = """
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
CASE
|
|
WHEN d.cont IN ('341', '345') THEN 'Producție proprie'
|
|
WHEN d.cont = '301' THEN 'Materii prime'
|
|
ELSE 'Marfă revândută'
|
|
END AS tip_produs,
|
|
ROUND(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 2) AS vanzari_fara_tva,
|
|
ROUND(SUM(d.cantitate * d.pret_achizitie), 2) AS cost_total,
|
|
ROUND(SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)), 2) AS marja_bruta,
|
|
ROUND(
|
|
CASE WHEN SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) > 0
|
|
THEN SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) * 100.0 / SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END)
|
|
ELSE 0 END
|
|
, 2) AS procent_marja
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -:months)
|
|
GROUP BY CASE
|
|
WHEN d.cont IN ('341', '345') THEN 'Producție proprie'
|
|
WHEN d.cont = '301' THEN 'Materii prime'
|
|
ELSE 'Marfă revândută'
|
|
END
|
|
ORDER BY vanzari_fara_tva DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 5. DISPERSIA PREȚURILOR PER PRODUS
|
|
# =============================================================================
|
|
DISPERSIE_PRETURI = """
|
|
WITH preturi_detalii AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
d.id_articol,
|
|
a.denumire,
|
|
g.subgrupa,
|
|
f.id_part,
|
|
p.denumire as client,
|
|
CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END AS pret_fara_tva,
|
|
d.cantitate,
|
|
MIN(CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) OVER (PARTITION BY d.id_articol) AS pret_min_global
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_parteneri p ON f.id_part = p.id_part
|
|
LEFT JOIN nom_articole a ON d.id_articol = a.id_articol
|
|
LEFT JOIN gest_art_sbgr g ON a.id_subgrupa = g.id_subgrupa
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -:months)
|
|
AND d.pret > 0
|
|
)
|
|
SELECT
|
|
denumire AS produs,
|
|
NVL(subgrupa, 'NECLASIFICAT') AS subgrupa,
|
|
COUNT(DISTINCT id_part) AS nr_clienti,
|
|
COUNT(*) AS nr_tranzactii,
|
|
ROUND(MIN(pret_fara_tva), 2) AS pret_minim,
|
|
ROUND(MAX(pret_fara_tva), 2) AS pret_maxim,
|
|
ROUND(AVG(pret_fara_tva), 2) AS pret_mediu,
|
|
ROUND((MAX(pret_fara_tva) - MIN(pret_fara_tva)) * 100.0 / NULLIF(AVG(pret_fara_tva), 0), 2) AS variatie_procent,
|
|
SUM(CASE WHEN pret_fara_tva = pret_min_global THEN 1 ELSE 0 END) AS nr_la_pret_min,
|
|
MAX(CASE WHEN pret_fara_tva = pret_min_global THEN client END) AS client_pret_min
|
|
FROM preturi_detalii
|
|
GROUP BY id_articol, denumire, subgrupa
|
|
HAVING COUNT(DISTINCT id_part) >= 3
|
|
AND MAX(pret_fara_tva) > MIN(pret_fara_tva) * 1.2
|
|
ORDER BY variatie_procent DESC
|
|
FETCH FIRST 50 ROWS ONLY
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 6. CLIENȚI CARE CUMPĂRĂ SUB MEDIE
|
|
# =============================================================================
|
|
# OPTIMIZED: Single base CTE scans once, derives both aggregations from it
|
|
CLIENTI_SUB_MEDIE = """
|
|
WITH base_prices AS (
|
|
SELECT
|
|
d.id_articol,
|
|
f.id_part,
|
|
p.denumire AS client,
|
|
CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END AS pret_fara_tva,
|
|
d.cantitate
|
|
FROM VANZARI f
|
|
JOIN VANZARI_DETALII d ON d.id_vanzare = f.id_vanzare
|
|
JOIN NOM_PARTENERI p ON f.id_part = p.id_part
|
|
WHERE f.sters = 0 AND d.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -:months)
|
|
AND d.pret > 0
|
|
),
|
|
preturi_medii AS (
|
|
SELECT id_articol, AVG(pret_fara_tva) AS pret_mediu
|
|
FROM base_prices
|
|
GROUP BY id_articol
|
|
),
|
|
preturi_client AS (
|
|
SELECT id_articol, id_part, client, AVG(pret_fara_tva) AS pret_client, SUM(cantitate) AS cantitate_totala
|
|
FROM base_prices
|
|
GROUP BY id_articol, id_part, client
|
|
)
|
|
SELECT
|
|
a.denumire AS produs,
|
|
pc.client,
|
|
ROUND(pc.pret_client, 2) AS pret_platit,
|
|
ROUND(pm.pret_mediu, 2) AS pret_mediu,
|
|
ROUND((pm.pret_mediu - pc.pret_client) * 100.0 / pm.pret_mediu, 2) AS discount_vs_medie,
|
|
pc.cantitate_totala
|
|
FROM preturi_client pc
|
|
JOIN preturi_medii pm ON pm.id_articol = pc.id_articol
|
|
JOIN NOM_ARTICOLE a ON a.id_articol = pc.id_articol
|
|
WHERE pc.pret_client < pm.pret_mediu * 0.85
|
|
ORDER BY discount_vs_medie DESC
|
|
FETCH FIRST 100 ROWS ONLY
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 7. VÂNZĂRI SUB COST (ALERTĂ CRITICĂ) - OPTIMIZAT
|
|
# =============================================================================
|
|
VANZARI_SUB_COST = """
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
f.data_act,
|
|
f.serie_act || ' ' || f.numar_act AS factura,
|
|
p.denumire AS client,
|
|
NVL2(d.id_articol, art.denumire, d.explicatie) AS produs,
|
|
d.cantitate,
|
|
ROUND(CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END, 2) AS pret_vanzare,
|
|
ROUND(d.pret_achizitie, 2) AS cost,
|
|
ROUND((CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie) * d.cantitate, 2) AS pierdere
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_parteneri p ON f.id_part = p.id_part
|
|
LEFT JOIN nom_articole art ON d.id_articol = art.id_articol
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -:months)
|
|
AND d.pret_achizitie > 0
|
|
AND d.pret > 0
|
|
AND CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END < d.pret_achizitie
|
|
ORDER BY pierdere ASC
|
|
FETCH FIRST 100 ROWS ONLY
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 8. TRENDING CLIENȚI YoY
|
|
# =============================================================================
|
|
TRENDING_CLIENTI = """
|
|
WITH vanzari_perioade AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
f.id_part,
|
|
p.denumire AS client,
|
|
SUM(CASE WHEN f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
THEN d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END ELSE 0 END) AS vanzari_an_curent,
|
|
SUM(CASE WHEN f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
AND f.data_act < ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
THEN d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END ELSE 0 END) AS vanzari_an_trecut
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_parteneri p ON f.id_part = p.id_part
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
GROUP BY f.id_part, p.denumire
|
|
)
|
|
SELECT
|
|
client,
|
|
ROUND(vanzari_an_curent, 2) AS vanzari_12_luni,
|
|
ROUND(vanzari_an_trecut, 2) AS vanzari_an_anterior,
|
|
ROUND(
|
|
CASE WHEN vanzari_an_trecut > 0
|
|
THEN (vanzari_an_curent - vanzari_an_trecut) * 100.0 / vanzari_an_trecut
|
|
ELSE NULL END
|
|
, 2) AS variatie_procent,
|
|
CASE
|
|
WHEN vanzari_an_trecut = 0 AND vanzari_an_curent > 0 THEN 'CLIENT NOU'
|
|
WHEN vanzari_an_curent = 0 AND vanzari_an_trecut > 0 THEN 'PIERDUT'
|
|
WHEN vanzari_an_curent > vanzari_an_trecut * 1.2 THEN 'CREȘTERE'
|
|
WHEN vanzari_an_curent < vanzari_an_trecut * 0.8 THEN 'SCĂDERE'
|
|
ELSE 'STABIL'
|
|
END AS trend
|
|
FROM vanzari_perioade
|
|
WHERE vanzari_an_curent > 0 OR vanzari_an_trecut > 0
|
|
ORDER BY variatie_procent DESC NULLS LAST
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 9. CONCENTRARE CLIENȚI (TOP 30 + REST)
|
|
# =============================================================================
|
|
CONCENTRARE_CLIENTI = """
|
|
WITH total_vanzari AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS total
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -:months)
|
|
),
|
|
vanzari_client AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
p.denumire AS client,
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS vanzari,
|
|
ROW_NUMBER() OVER (ORDER BY SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) DESC) AS rn
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_parteneri p ON f.id_part = p.id_part
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -:months)
|
|
GROUP BY f.id_part, p.denumire
|
|
),
|
|
top_clienti AS (
|
|
SELECT
|
|
vc.client,
|
|
ROUND(vc.vanzari, 2) AS vanzari,
|
|
ROUND(vc.vanzari * 100.0 / tv.total, 2) AS procent_din_total,
|
|
vc.rn
|
|
FROM vanzari_client vc
|
|
CROSS JOIN total_vanzari tv
|
|
WHERE vc.rn <= 30
|
|
),
|
|
rest_clienti AS (
|
|
SELECT
|
|
'ALȚI CLIENȚI' AS client,
|
|
ROUND(SUM(vc.vanzari), 2) AS vanzari,
|
|
ROUND(SUM(vc.vanzari) * 100.0 / tv.total, 2) AS procent_din_total,
|
|
31 AS rn
|
|
FROM vanzari_client vc
|
|
CROSS JOIN total_vanzari tv
|
|
WHERE vc.rn > 30
|
|
GROUP BY tv.total
|
|
HAVING SUM(vc.vanzari) > 0
|
|
)
|
|
SELECT
|
|
client,
|
|
vanzari,
|
|
procent_din_total,
|
|
SUM(procent_din_total) OVER (ORDER BY rn) AS procent_cumulat
|
|
FROM (
|
|
SELECT * FROM top_clienti
|
|
UNION ALL
|
|
SELECT * FROM rest_clienti
|
|
)
|
|
ORDER BY rn
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 10. VÂNZĂRI LUNARE (SEZONALITATE)
|
|
# =============================================================================
|
|
# OPTIMIZED: Use base tables instead of views (removes 29 unnecessary JOINs)
|
|
VANZARI_LUNARE = """
|
|
SELECT
|
|
TO_CHAR(f.data_act, 'YYYY-MM') AS luna,
|
|
ROUND(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 2) AS vanzari_fara_tva,
|
|
ROUND(SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)), 2) AS marja_bruta,
|
|
COUNT(DISTINCT f.id_vanzare) AS nr_facturi,
|
|
COUNT(DISTINCT f.id_part) AS nr_clienti
|
|
FROM VANZARI f
|
|
JOIN VANZARI_DETALII d ON d.id_vanzare = f.id_vanzare
|
|
WHERE f.sters = 0 AND d.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
GROUP BY TO_CHAR(f.data_act, 'YYYY-MM')
|
|
ORDER BY luna
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 11. STOC CURENT PER GESTIUNE
|
|
# =============================================================================
|
|
STOC_CURENT = """
|
|
SELECT
|
|
s.nume_gestiune,
|
|
CASE WHEN g.nr_pag = 7 THEN 'Marfă preț vânzare' ELSE 'Marfă preț achiziție' END AS tip_gestiune,
|
|
s.grupa,
|
|
s.subgrupa,
|
|
COUNT(DISTINCT s.id_articol) AS nr_articole,
|
|
ROUND(SUM((s.cants + s.cant - s.cante) * s.pret), 2) AS valoare_stoc_achizitie,
|
|
CASE
|
|
WHEN g.nr_pag = 7 THEN ROUND(SUM((s.cants + s.cant - s.cante) * s.pretv), 2)
|
|
ELSE NULL
|
|
END AS valoare_stoc_vanzare
|
|
FROM vstoc s
|
|
JOIN nom_gestiuni g ON s.id_gestiune = g.id_gestiune
|
|
WHERE s.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND s.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
AND (s.cants + s.cant - s.cante) > 0
|
|
GROUP BY s.id_gestiune, s.nume_gestiune, g.nr_pag, s.id_grupa, s.grupa, s.id_subgrupa, s.subgrupa
|
|
ORDER BY valoare_stoc_achizitie DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 12. STOC LENT (fără mișcare > 90 zile)
|
|
# =============================================================================
|
|
STOC_LENT = """
|
|
SELECT
|
|
s.denumire AS produs,
|
|
s.nume_gestiune,
|
|
(s.cants + s.cant - s.cante) AS cantitate,
|
|
ROUND((s.cants + s.cant - s.cante) * s.pret, 2) AS valoare,
|
|
s.dataout AS ultima_iesire,
|
|
ROUND(SYSDATE - NVL(s.dataout, s.datain)) AS zile_fara_miscare
|
|
FROM vstoc s
|
|
WHERE s.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND s.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
AND (s.cants + s.cant - s.cante) > 0
|
|
AND (s.dataout IS NULL OR s.dataout < SYSDATE - 90)
|
|
AND (s.cants + s.cant - s.cante) * s.pret > 100
|
|
ORDER BY zile_fara_miscare DESC NULLS FIRST
|
|
FETCH FIRST 100 ROWS ONLY
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 13. ROTAȚIE STOCURI
|
|
# =============================================================================
|
|
ROTATIE_STOCURI = """
|
|
WITH vanzari_articole AS (
|
|
SELECT
|
|
r.id_articol,
|
|
SUM(ABS(r.cante) * r.pret) AS valoare_vanzari
|
|
FROM vrul r
|
|
JOIN vanzari v ON r.id_fact = v.id_fact
|
|
WHERE r.id_tip_rulaj = 0
|
|
AND r.cante <> 0
|
|
AND r.dataact >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
GROUP BY r.id_articol
|
|
),
|
|
stoc_curent AS (
|
|
SELECT
|
|
s.id_articol,
|
|
s.denumire,
|
|
s.nume_gestiune,
|
|
SUM((s.cants + s.cant - s.cante) * s.pret) AS valoare_stoc
|
|
FROM vstoc s
|
|
WHERE s.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND s.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
AND (s.cants + s.cant - s.cante) > 0
|
|
GROUP BY s.id_articol, s.denumire, s.nume_gestiune
|
|
)
|
|
SELECT
|
|
sc.denumire AS produs,
|
|
sc.nume_gestiune,
|
|
ROUND(sc.valoare_stoc, 2) AS valoare_stoc,
|
|
ROUND(NVL(va.valoare_vanzari, 0), 2) AS vanzari_12_luni,
|
|
ROUND(
|
|
CASE WHEN sc.valoare_stoc > 0
|
|
THEN NVL(va.valoare_vanzari, 0) / sc.valoare_stoc
|
|
ELSE 0 END
|
|
, 2) AS rotatie,
|
|
ROUND(
|
|
CASE WHEN NVL(va.valoare_vanzari, 0) > 0
|
|
THEN sc.valoare_stoc * 365 / va.valoare_vanzari
|
|
ELSE 9999 END
|
|
, 0) AS zile_stoc
|
|
FROM stoc_curent sc
|
|
LEFT JOIN vanzari_articole va ON va.id_articol = sc.id_articol
|
|
WHERE sc.valoare_stoc > 500
|
|
ORDER BY rotatie ASC NULLS FIRST
|
|
FETCH FIRST 100 ROWS ONLY
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 14. ANALIZĂ PRĂJITORIE - MATERII PRIME vs OUTPUT
|
|
# =============================================================================
|
|
ANALIZA_PRAJITORIE = """
|
|
SELECT
|
|
TO_CHAR(r.dataact, 'YYYY-MM') AS luna,
|
|
CASE
|
|
WHEN r.cont = '301' THEN 'Materii prime'
|
|
WHEN r.cont = '341' THEN 'Semifabricate'
|
|
WHEN r.cont = '345' THEN 'Produse finite'
|
|
ELSE 'Altele'
|
|
END AS tip,
|
|
-- Intrari: cantitate > 0 AND cante = 0
|
|
ROUND(SUM(CASE WHEN r.cant > 0 AND NVL(r.cante, 0) = 0 THEN r.cant ELSE 0 END), 2) AS cantitate_intrari,
|
|
ROUND(SUM(CASE WHEN r.cant > 0 AND NVL(r.cante, 0) = 0 THEN r.cant * NVL(r.pret, 0) ELSE 0 END), 2) AS valoare_intrari,
|
|
-- Iesiri: cant = 0 AND cante > 0
|
|
ROUND(SUM(CASE WHEN NVL(r.cant, 0) = 0 AND r.cante > 0 THEN r.cante ELSE 0 END), 2) AS cantitate_iesiri,
|
|
ROUND(SUM(CASE WHEN NVL(r.cant, 0) = 0 AND r.cante > 0 THEN r.cante * NVL(r.pret, 0) ELSE 0 END), 2) AS valoare_iesiri,
|
|
-- Transformari: cant > 0 AND cante > 0 (intrare si iesire simultan)
|
|
ROUND(SUM(CASE WHEN r.cant > 0 AND r.cante > 0 THEN r.cant ELSE 0 END), 2) AS cantitate_transformari_in,
|
|
ROUND(SUM(CASE WHEN r.cant > 0 AND r.cante > 0 THEN r.cante ELSE 0 END), 2) AS cantitate_transformari_out,
|
|
-- Sold net
|
|
ROUND(SUM(NVL(r.cant, 0) - NVL(r.cante, 0)), 2) AS sold_net_cantitate,
|
|
ROUND(SUM((NVL(r.cant, 0) - NVL(r.cante, 0)) * NVL(r.pret, 0)), 2) AS sold_net_valoare
|
|
FROM vrul r
|
|
WHERE r.cont IN ('301', '341', '345')
|
|
AND r.dataact >= ADD_MONTHS(TRUNC(SYSDATE), -:months)
|
|
GROUP BY TO_CHAR(r.dataact, 'YYYY-MM'),
|
|
CASE WHEN r.cont = '301' THEN 'Materii prime'
|
|
WHEN r.cont = '341' THEN 'Semifabricate'
|
|
WHEN r.cont = '345' THEN 'Produse finite'
|
|
ELSE 'Altele' END
|
|
ORDER BY luna, tip
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 15. SUMAR EXECUTIV - KPIs
|
|
# =============================================================================
|
|
# OPTIMIZED: Single CTE scans base tables once instead of 6 separate view scans (29 JOINs each)
|
|
SUMAR_EXECUTIV = """
|
|
WITH base_data AS (
|
|
SELECT
|
|
f.id_vanzare,
|
|
f.id_part,
|
|
d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END AS vanzare_fara_tva,
|
|
d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie) AS marja
|
|
FROM VANZARI f
|
|
JOIN VANZARI_DETALII d ON d.id_vanzare = f.id_vanzare
|
|
WHERE f.sters = 0 AND d.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
),
|
|
aggregated AS (
|
|
SELECT
|
|
SUM(vanzare_fara_tva) AS total_vanzari,
|
|
SUM(marja) AS total_marja,
|
|
COUNT(DISTINCT id_vanzare) AS nr_facturi,
|
|
COUNT(DISTINCT id_part) AS nr_clienti
|
|
FROM base_data
|
|
)
|
|
SELECT
|
|
'Vânzări totale (fără TVA)' AS indicator,
|
|
TO_CHAR(ROUND(total_vanzari, 0), '999,999,999') AS valoare,
|
|
'RON' AS um
|
|
FROM aggregated
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
'Marja brută totală' AS indicator,
|
|
TO_CHAR(ROUND(total_marja, 0), '999,999,999') AS valoare,
|
|
'RON' AS um
|
|
FROM aggregated
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
'Procent marjă medie' AS indicator,
|
|
TO_CHAR(ROUND(total_marja * 100.0 / NULLIF(total_vanzari, 0), 2), '990.99') AS valoare,
|
|
'%' AS um
|
|
FROM aggregated
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
'Număr facturi' AS indicator,
|
|
TO_CHAR(nr_facturi, '999,999') AS valoare,
|
|
'buc' AS um
|
|
FROM aggregated
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
'Număr clienți activi' AS indicator,
|
|
TO_CHAR(nr_clienti, '999,999') AS valoare,
|
|
'buc' AS um
|
|
FROM aggregated
|
|
|
|
UNION ALL
|
|
|
|
SELECT
|
|
'Valoare stoc total' AS indicator,
|
|
TO_CHAR(ROUND(SUM(s.cant * s.pret), 0), '999,999,999') AS valoare,
|
|
'RON' AS um
|
|
FROM vstoc s
|
|
WHERE s.cant > 0
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 16. TOP PRODUSE DUPĂ VÂNZĂRI
|
|
# =============================================================================
|
|
TOP_PRODUSE = """
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
NVL2(d.id_articol, a.denumire, d.explicatie) AS produs,
|
|
NVL(g.subgrupa, 'NECLASIFICAT') AS subgrupa,
|
|
a.um,
|
|
ROUND(SUM(d.cantitate), 2) AS cantitate_vanduta,
|
|
ROUND(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 2) AS valoare_vanzari,
|
|
ROUND(SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)), 2) AS marja_bruta,
|
|
ROUND(
|
|
CASE WHEN SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) > 0
|
|
THEN SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) * 100.0 / SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END)
|
|
ELSE 0 END
|
|
, 2) AS procent_marja
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_articole a ON d.id_articol = a.id_articol
|
|
LEFT JOIN gest_art_sbgr g ON a.id_subgrupa = g.id_subgrupa
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -:months)
|
|
GROUP BY d.id_articol, NVL2(d.id_articol, a.denumire, d.explicatie), g.subgrupa, a.um
|
|
ORDER BY valoare_vanzari DESC
|
|
FETCH FIRST 50 ROWS ONLY
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 17. MARJA PER GESTIUNE (doar articole gestionabile) - OPTIMIZAT
|
|
# =============================================================================
|
|
MARJA_PER_GESTIUNE = """
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
g.nume_gestiune,
|
|
COUNT(DISTINCT f.id_vanzare) AS nr_facturi,
|
|
ROUND(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 2) AS vanzari_fara_tva,
|
|
ROUND(SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)), 2) AS marja_bruta,
|
|
ROUND(
|
|
CASE WHEN SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) > 0
|
|
THEN SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) * 100.0 / SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END)
|
|
ELSE 0 END
|
|
, 2) AS procent_marja
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_gestiuni g ON d.id_gestiune = g.id_gestiune
|
|
JOIN nom_articole a ON d.id_articol = a.id_articol
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -:months)
|
|
AND NVL(a.in_stoc, 1) = 1
|
|
GROUP BY d.id_gestiune, g.nume_gestiune
|
|
ORDER BY vanzari_fara_tva DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 18. ARTICOLE NEGESTIONABILE (servicii, etc.) - OPTIMIZAT
|
|
# =============================================================================
|
|
ARTICOLE_NEGESTIONABILE = """
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
NVL(art.denumire, d.explicatie) AS denumire,
|
|
NVL(sg.subgrupa, 'NECLASIFICAT') AS subgrupa,
|
|
art.um,
|
|
COUNT(DISTINCT f.id_vanzare) AS nr_facturi,
|
|
ROUND(SUM(d.cantitate), 2) AS cantitate_vanduta,
|
|
ROUND(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 2) AS vanzari_fara_tva,
|
|
ROUND(SUM(d.cantitate * d.pret_achizitie), 2) AS cost_total,
|
|
ROUND(SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)), 2) AS marja_bruta,
|
|
ROUND(
|
|
CASE WHEN SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) > 0
|
|
THEN SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) * 100.0 / SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END)
|
|
ELSE 0 END
|
|
, 2) AS procent_marja
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_articole art ON d.id_articol = art.id_articol
|
|
LEFT JOIN vgest_art_sbgr sg ON art.id_subgrupa = sg.id_subgrupa
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -:months)
|
|
AND NVL(art.in_stoc, 0) = 0
|
|
GROUP BY d.id_articol, art.denumire, d.explicatie, sg.subgrupa, art.um
|
|
ORDER BY vanzari_fara_tva DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 19. SOLDURI CLIENTI (Creanțe din cont 4111)
|
|
# =============================================================================
|
|
SOLDURI_CLIENTI = """
|
|
SELECT
|
|
p.denumire AS client,
|
|
p.cod_fiscal,
|
|
-- Sold direct: pozitiv = creanta, negativ = avans/storno/retur
|
|
ROUND(SUM(b.solddeb - b.soldcred), 2) AS sold_curent,
|
|
CASE
|
|
WHEN SUM(b.solddeb - b.soldcred) > 0 THEN 'Creanta'
|
|
WHEN SUM(b.solddeb - b.soldcred) < 0 THEN 'Avans/Storno'
|
|
ELSE 'Sold zero'
|
|
END AS tip_sold
|
|
FROM vbalanta_parteneri b
|
|
JOIN vnom_parteneri p ON b.id_part = p.id_part
|
|
WHERE b.cont LIKE '4111%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
GROUP BY p.id_part, p.denumire, p.cod_fiscal
|
|
HAVING SUM(b.solddeb - b.soldcred) <> 0
|
|
ORDER BY sold_curent DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 20. SOLDURI FURNIZORI (Datorii din cont 401)
|
|
# =============================================================================
|
|
SOLDURI_FURNIZORI = """
|
|
SELECT
|
|
p.denumire AS furnizor,
|
|
p.cod_fiscal,
|
|
-- Sold direct: pozitiv = datorie, negativ = avans/storno
|
|
ROUND(SUM(b.soldcred - b.solddeb), 2) AS sold_curent,
|
|
CASE
|
|
WHEN SUM(b.soldcred - b.solddeb) > 0 THEN 'Datorie'
|
|
WHEN SUM(b.soldcred - b.solddeb) < 0 THEN 'Avans/Storno'
|
|
ELSE 'Sold zero'
|
|
END AS tip_sold
|
|
FROM vbalanta_parteneri b
|
|
JOIN vnom_parteneri p ON b.id_part = p.id_part
|
|
WHERE b.cont LIKE '401%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
GROUP BY p.id_part, p.denumire, p.cod_fiscal
|
|
HAVING SUM(b.soldcred - b.solddeb) <> 0
|
|
ORDER BY sold_curent DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 21. AGING CREANTE (Buckets pentru creanțe - din vireg_parteneri)
|
|
# =============================================================================
|
|
# FIX: Filter by last closed calendar period to avoid duplicate invoices
|
|
AGING_CREANTE = """
|
|
WITH ultima_luna AS (
|
|
SELECT anul, luna FROM calendar ORDER BY anul DESC, luna DESC FETCH FIRST 1 ROW ONLY
|
|
),
|
|
solduri_clienti AS (
|
|
SELECT
|
|
r.id_part,
|
|
r.nume AS client,
|
|
r.serie_act || ' ' || r.nract AS nr_factura,
|
|
r.dataact AS data_factura,
|
|
r.datascad,
|
|
(r.precdeb + r.debit) AS valoare_factura,
|
|
(r.preccred + r.credit) AS valoare_achitata,
|
|
(r.precdeb + r.debit) - (r.preccred + r.credit) AS sold_ramas,
|
|
CASE
|
|
WHEN r.datascad IS NULL THEN 0
|
|
WHEN r.datascad >= TRUNC(SYSDATE) THEN 0
|
|
ELSE ROUND(TRUNC(SYSDATE) - r.datascad)
|
|
END AS zile_restante
|
|
FROM vireg_parteneri r, ultima_luna ul
|
|
WHERE (r.cont LIKE '4111%' OR r.cont LIKE '461%')
|
|
AND (r.precdeb + r.debit) - (r.preccred + r.credit) <> 0
|
|
AND r.an = ul.anul AND r.luna = ul.luna
|
|
)
|
|
SELECT
|
|
client,
|
|
ROUND(SUM(CASE WHEN zile_restante <= 0 THEN sold_ramas ELSE 0 END), 2) AS neajuns_scadenta,
|
|
ROUND(SUM(CASE WHEN zile_restante > 0 AND zile_restante <= 30 THEN sold_ramas ELSE 0 END), 2) AS zile_1_30,
|
|
ROUND(SUM(CASE WHEN zile_restante > 30 AND zile_restante <= 60 THEN sold_ramas ELSE 0 END), 2) AS zile_31_60,
|
|
ROUND(SUM(CASE WHEN zile_restante > 60 AND zile_restante <= 90 THEN sold_ramas ELSE 0 END), 2) AS zile_61_90,
|
|
ROUND(SUM(CASE WHEN zile_restante > 90 THEN sold_ramas ELSE 0 END), 2) AS peste_90_zile,
|
|
ROUND(SUM(sold_ramas), 2) AS total_sold
|
|
FROM solduri_clienti
|
|
GROUP BY id_part, client
|
|
HAVING SUM(sold_ramas) <> 0
|
|
ORDER BY total_sold DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 22. FACTURI RESTANTE CLIENTI (Depășite scadența - din vireg_parteneri)
|
|
# =============================================================================
|
|
# FIX: Filter by last closed calendar period to avoid duplicate invoices
|
|
FACTURI_RESTANTE = """
|
|
WITH ultima_luna AS (
|
|
SELECT anul, luna FROM calendar ORDER BY anul DESC, luna DESC FETCH FIRST 1 ROW ONLY
|
|
)
|
|
SELECT
|
|
r.nume AS client,
|
|
r.serie_act || ' ' || r.nract AS nr_factura,
|
|
r.dataact AS data_factura,
|
|
r.datascad AS data_scadenta,
|
|
ROUND(TRUNC(SYSDATE) - r.datascad) AS zile_intarziere,
|
|
ROUND((r.precdeb + r.debit) - (r.preccred + r.credit), 2) AS suma_restanta
|
|
FROM vireg_parteneri r, ultima_luna ul
|
|
WHERE (r.cont LIKE '4111%' OR r.cont LIKE '461%')
|
|
AND (r.precdeb + r.debit) - (r.preccred + r.credit) <> 0
|
|
AND r.datascad IS NOT NULL
|
|
AND r.datascad < TRUNC(SYSDATE)
|
|
AND r.an = ul.anul AND r.luna = ul.luna
|
|
ORDER BY zile_intarziere DESC
|
|
FETCH FIRST 100 ROWS ONLY
|
|
"""
|
|
|
|
|
|
# =============================================================================
|
|
# 22b. AGING DATORII FURNIZORI (din vireg_parteneri)
|
|
# =============================================================================
|
|
# FIX: Filter by last closed calendar period to avoid duplicate invoices
|
|
AGING_DATORII = """
|
|
WITH ultima_luna AS (
|
|
SELECT anul, luna FROM calendar ORDER BY anul DESC, luna DESC FETCH FIRST 1 ROW ONLY
|
|
),
|
|
solduri_furnizori AS (
|
|
SELECT
|
|
r.id_part,
|
|
r.nume AS furnizor,
|
|
r.serie_act || ' ' || r.nract AS nr_factura,
|
|
r.dataact AS data_factura,
|
|
r.datascad,
|
|
(r.preccred + r.credit) AS valoare_factura,
|
|
(r.precdeb + r.debit) AS valoare_achitata,
|
|
(r.preccred + r.credit) - (r.precdeb + r.debit) AS sold_ramas,
|
|
CASE
|
|
WHEN r.datascad IS NULL THEN 0
|
|
WHEN r.datascad >= TRUNC(SYSDATE) THEN 0
|
|
ELSE ROUND(TRUNC(SYSDATE) - r.datascad)
|
|
END AS zile_restante
|
|
FROM vireg_parteneri r, ultima_luna ul
|
|
WHERE (r.cont LIKE '401%' OR r.cont LIKE '404%' OR r.cont LIKE '462%')
|
|
AND (r.preccred + r.credit) - (r.precdeb + r.debit) <> 0
|
|
AND r.an = ul.anul AND r.luna = ul.luna
|
|
)
|
|
SELECT
|
|
furnizor,
|
|
ROUND(SUM(CASE WHEN zile_restante <= 0 THEN sold_ramas ELSE 0 END), 2) AS neajuns_scadenta,
|
|
ROUND(SUM(CASE WHEN zile_restante > 0 AND zile_restante <= 30 THEN sold_ramas ELSE 0 END), 2) AS zile_1_30,
|
|
ROUND(SUM(CASE WHEN zile_restante > 30 AND zile_restante <= 60 THEN sold_ramas ELSE 0 END), 2) AS zile_31_60,
|
|
ROUND(SUM(CASE WHEN zile_restante > 60 AND zile_restante <= 90 THEN sold_ramas ELSE 0 END), 2) AS zile_61_90,
|
|
ROUND(SUM(CASE WHEN zile_restante > 90 THEN sold_ramas ELSE 0 END), 2) AS peste_90_zile,
|
|
ROUND(SUM(sold_ramas), 2) AS total_sold
|
|
FROM solduri_furnizori
|
|
GROUP BY id_part, furnizor
|
|
HAVING SUM(sold_ramas) <> 0
|
|
ORDER BY total_sold DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 22c. FACTURI RESTANTE FURNIZORI (Depășite scadența)
|
|
# =============================================================================
|
|
# FIX: Filter by last closed calendar period to avoid duplicate invoices
|
|
FACTURI_RESTANTE_FURNIZORI = """
|
|
WITH ultima_luna AS (
|
|
SELECT anul, luna FROM calendar ORDER BY anul DESC, luna DESC FETCH FIRST 1 ROW ONLY
|
|
)
|
|
SELECT
|
|
r.nume AS furnizor,
|
|
r.serie_act || ' ' || r.nract AS nr_factura,
|
|
r.dataact AS data_factura,
|
|
r.datascad AS data_scadenta,
|
|
ROUND(TRUNC(SYSDATE) - r.datascad) AS zile_intarziere,
|
|
ROUND((r.preccred + r.credit) - (r.precdeb + r.debit), 2) AS suma_restanta
|
|
FROM vireg_parteneri r, ultima_luna ul
|
|
WHERE (r.cont LIKE '401%' OR r.cont LIKE '404%' OR r.cont LIKE '462%')
|
|
AND (r.preccred + r.credit) - (r.precdeb + r.debit) <> 0
|
|
AND r.datascad IS NOT NULL
|
|
AND r.datascad < TRUNC(SYSDATE)
|
|
AND r.an = ul.anul AND r.luna = ul.luna
|
|
ORDER BY zile_intarziere DESC
|
|
FETCH FIRST 100 ROWS ONLY
|
|
"""
|
|
# =============================================================================
|
|
# 23. DSO / DPO (Zile medii încasare/plată)
|
|
# Folosește jurnalele de TVA pentru vânzări/achiziții fără TVA
|
|
# =============================================================================
|
|
DSO_DPO = """
|
|
WITH vanzari_12_luni AS (
|
|
-- Vânzări fără TVA din ultimele 12 luni (jurnal vânzări vjv2025)
|
|
-- Filtrare: an/luna în interval + dataireg în anul/luna respectivă
|
|
SELECT SUM(
|
|
-- Baze impozabile cu TVA (ro*b)
|
|
NVL(ro24b, 0) + NVL(ro21b, 0) + NVL(ro20b, 0) + NVL(ro19b, 0) +
|
|
NVL(ro11b, 0) + NVL(ro9b, 0) + NVL(ro5b, 0) +
|
|
-- Baze neimpozabile (ro*nb)
|
|
NVL(ro24nb, 0) + NVL(ro21nb, 0) + NVL(ro20nb, 0) + NVL(ro19nb, 0) +
|
|
NVL(ro11nb, 0) + NVL(ro9nb, 0) + NVL(ro5nb, 0) +
|
|
-- Operațiuni fără TVA
|
|
NVL(roti, 0) + NVL(cescdd1, 0) + NVL(cescdd2, 0) + NVL(ceoptr, 0) +
|
|
NVL(cesvdd, 0) + NVL(cesvfdd, 0) + NVL(cesvfs, 0) +
|
|
NVL(wrscdd, 0) + NVL(fodd, 0) + NVL(fofdd, 0) + NVL(wrscfdd, 0) + NVL(wrn, 0)
|
|
) AS total_vanzari
|
|
FROM vjv2025
|
|
WHERE (an * 12 + luna) BETWEEN
|
|
(EXTRACT(YEAR FROM ADD_MONTHS(SYSDATE, -12)) * 12 + EXTRACT(MONTH FROM ADD_MONTHS(SYSDATE, -12)))
|
|
AND (EXTRACT(YEAR FROM SYSDATE) * 12 + EXTRACT(MONTH FROM SYSDATE))
|
|
AND EXTRACT(YEAR FROM dataireg) = an
|
|
AND EXTRACT(MONTH FROM dataireg) = luna
|
|
),
|
|
sold_clienti AS (
|
|
-- Sold creanțe clienți (cont 4111)
|
|
SELECT SUM(CASE WHEN b.solddeb > b.soldcred THEN b.solddeb - b.soldcred ELSE 0 END) AS total_creante
|
|
FROM vbalanta_parteneri b
|
|
WHERE b.cont LIKE '4111%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
achizitii_12_luni AS (
|
|
-- Achiziții fără TVA din ultimele 12 luni (jurnal cumpărări vjc2025)
|
|
SELECT SUM(
|
|
-- Baze impozabile domestice (ro*b)
|
|
NVL(ro24b, 0) + NVL(ro21b, 0) + NVL(ro20b, 0) + NVL(ro19b, 0) +
|
|
NVL(ro11b, 0) + NVL(ro09b, 0) + NVL(ro05b, 0) +
|
|
-- Baze neimpozabile (ro*nb)
|
|
NVL(ro24nb, 0) + NVL(ro21nb, 0) + NVL(ro20nb, 0) + NVL(ro19nb, 0) +
|
|
NVL(ro11nb, 0) + NVL(ro9nb, 0) + NVL(ro5nb, 0) +
|
|
-- Furnizori (fo*b)
|
|
NVL(fo24b, 0) + NVL(fo21b, 0) + NVL(fo20b, 0) + NVL(fo19b, 0) +
|
|
NVL(fo11b, 0) + NVL(fo09b, 0) +
|
|
-- Taxare inversă (ti*b)
|
|
NVL(ti24b, 0) + NVL(ti21b, 0) + NVL(ti20b, 0) + NVL(ti19b, 0) +
|
|
NVL(ti11b, 0) + NVL(ti09b, 0) +
|
|
-- Achiziții intracomunitare (ce*b)
|
|
NVL(ceb, 0) + NVL(cebb, 0) + NVL(cesb, 0) +
|
|
-- Cross-border (xx*tib)
|
|
NVL(xx19tib, 0) + NVL(xx21tib, 0) + NVL(xx11tib, 0) + NVL(xx9tib, 0) +
|
|
-- Fără TVA
|
|
NVL(cen, 0)
|
|
) AS total_achizitii
|
|
FROM vjc2025
|
|
WHERE (an * 12 + luna) BETWEEN
|
|
(EXTRACT(YEAR FROM ADD_MONTHS(SYSDATE, -12)) * 12 + EXTRACT(MONTH FROM ADD_MONTHS(SYSDATE, -12)))
|
|
AND (EXTRACT(YEAR FROM SYSDATE) * 12 + EXTRACT(MONTH FROM SYSDATE))
|
|
AND EXTRACT(YEAR FROM dataireg) = an
|
|
AND EXTRACT(MONTH FROM dataireg) = luna
|
|
),
|
|
sold_furnizori AS (
|
|
-- Sold datorii furnizori (cont 401)
|
|
SELECT SUM(CASE WHEN b.soldcred > b.solddeb THEN b.soldcred - b.solddeb ELSE 0 END) AS total_datorii
|
|
FROM vbalanta_parteneri b
|
|
WHERE b.cont LIKE '401%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
)
|
|
SELECT
|
|
'DSO (Zile incasare clienti)' AS indicator,
|
|
ROUND(NVL(sc.total_creante, 0) * 365 / NULLIF(v.total_vanzari, 0), 0) AS zile,
|
|
'(Creante clienti x 365) / Vanzari anuale (cont 4111 x 365 / jurnal vanzari vjv2025)' AS formula,
|
|
CASE
|
|
WHEN NVL(sc.total_creante, 0) * 365 / NULLIF(v.total_vanzari, 0) > 60 THEN 'ALERTA'
|
|
WHEN NVL(sc.total_creante, 0) * 365 / NULLIF(v.total_vanzari, 0) > 45 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status
|
|
FROM vanzari_12_luni v, sold_clienti sc
|
|
UNION ALL
|
|
SELECT
|
|
'DPO (Zile plata furnizori)' AS indicator,
|
|
ROUND(NVL(sf.total_datorii, 0) * 365 / NULLIF(a.total_achizitii, 0), 0) AS zile,
|
|
'(Datorii furnizori x 365) / Achizitii anuale (cont 401 x 365 / jurnal cumparari vjc2025)' AS formula,
|
|
CASE
|
|
WHEN NVL(sf.total_datorii, 0) * 365 / NULLIF(a.total_achizitii, 0) < 15 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status
|
|
FROM achizitii_12_luni a, sold_furnizori sf
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 24. POZITIA CASH (Conturi 5121, 5311)
|
|
# =============================================================================
|
|
POZITIA_CASH = """
|
|
SELECT
|
|
b.cont,
|
|
CASE
|
|
WHEN b.cont LIKE '5121%' THEN 'Conturi la banci in lei'
|
|
WHEN b.cont LIKE '5124%' THEN 'Conturi la banci in valuta'
|
|
WHEN b.cont LIKE '5311%' THEN 'Casa in lei'
|
|
WHEN b.cont LIKE '5314%' THEN 'Casa in valuta'
|
|
ELSE 'Alte disponibilitati'
|
|
END AS descriere,
|
|
ROUND(SUM(b.solddeb - b.soldcred), 2) AS sold_curent,
|
|
CASE
|
|
WHEN b.cont LIKE '512%' OR b.cont LIKE '531%' THEN 'RON'
|
|
WHEN b.cont LIKE '5124%' OR b.cont LIKE '5314%' THEN 'VALUTA'
|
|
ELSE 'RON'
|
|
END AS valuta
|
|
FROM vbal b
|
|
WHERE (b.cont LIKE '512%' OR b.cont LIKE '531%')
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
GROUP BY b.cont
|
|
HAVING SUM(b.solddeb - b.soldcred) <> 0
|
|
ORDER BY b.cont
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 25. CICLU CONVERSIE CASH (DIO + DSO - DPO)
|
|
# Folosește vbal clasa 3xx pentru stoc, jurnale TVA pentru vânzări/achiziții
|
|
# =============================================================================
|
|
CICLU_CONVERSIE_CASH = """
|
|
WITH metrici AS (
|
|
SELECT
|
|
-- Stoc curent din balanța de verificare, clasa 3xx
|
|
(SELECT SUM(b.solddeb - b.soldcred)
|
|
FROM vbal b
|
|
WHERE b.cont LIKE '3%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)) AS stoc_curent,
|
|
-- COGS din facturi (preț achiziție articole vândute)
|
|
(SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
SUM(d.cantitate * d.pret_achizitie)
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12)) AS cogs_12_luni,
|
|
-- Creanțe clienți
|
|
(SELECT SUM(CASE WHEN b.solddeb > b.soldcred THEN b.solddeb - b.soldcred ELSE 0 END)
|
|
FROM vbalanta_parteneri b
|
|
WHERE b.cont LIKE '4111%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)) AS creante,
|
|
-- Vânzări 12 luni din jurnal TVA vânzări (vjv2025)
|
|
(SELECT SUM(
|
|
-- Baze impozabile (ro*b)
|
|
NVL(ro24b, 0) + NVL(ro21b, 0) + NVL(ro20b, 0) + NVL(ro19b, 0) +
|
|
NVL(ro11b, 0) + NVL(ro9b, 0) + NVL(ro5b, 0) +
|
|
-- Baze neimpozabile (ro*nb)
|
|
NVL(ro24nb, 0) + NVL(ro21nb, 0) + NVL(ro20nb, 0) + NVL(ro19nb, 0) +
|
|
NVL(ro11nb, 0) + NVL(ro9nb, 0) + NVL(ro5nb, 0) +
|
|
-- Operațiuni fără TVA
|
|
NVL(roti, 0) + NVL(cescdd1, 0) + NVL(cescdd2, 0) + NVL(ceoptr, 0) +
|
|
NVL(cesvdd, 0) + NVL(cesvfdd, 0) + NVL(cesvfs, 0) +
|
|
NVL(wrscdd, 0) + NVL(fodd, 0) + NVL(fofdd, 0) + NVL(wrscfdd, 0) + NVL(wrn, 0))
|
|
FROM vjv2025
|
|
WHERE (an * 12 + luna) BETWEEN
|
|
(EXTRACT(YEAR FROM ADD_MONTHS(SYSDATE, -12)) * 12 + EXTRACT(MONTH FROM ADD_MONTHS(SYSDATE, -12)))
|
|
AND (EXTRACT(YEAR FROM SYSDATE) * 12 + EXTRACT(MONTH FROM SYSDATE))
|
|
AND EXTRACT(YEAR FROM dataireg) = an
|
|
AND EXTRACT(MONTH FROM dataireg) = luna) AS vanzari_12_luni,
|
|
-- Datorii furnizori
|
|
(SELECT SUM(CASE WHEN b.soldcred > b.solddeb THEN b.soldcred - b.solddeb ELSE 0 END)
|
|
FROM vbalanta_parteneri b
|
|
WHERE b.cont LIKE '401%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)) AS datorii_furnizori,
|
|
-- Achiziții 12 luni din jurnal TVA cumpărări (vjc2025)
|
|
(SELECT SUM(
|
|
-- Baze impozabile domestice (ro*b)
|
|
NVL(ro24b, 0) + NVL(ro21b, 0) + NVL(ro20b, 0) + NVL(ro19b, 0) +
|
|
NVL(ro11b, 0) + NVL(ro09b, 0) + NVL(ro05b, 0) +
|
|
-- Baze neimpozabile (ro*nb)
|
|
NVL(ro24nb, 0) + NVL(ro21nb, 0) + NVL(ro20nb, 0) + NVL(ro19nb, 0) +
|
|
NVL(ro11nb, 0) + NVL(ro9nb, 0) + NVL(ro5nb, 0) +
|
|
-- Furnizori (fo*b)
|
|
NVL(fo24b, 0) + NVL(fo21b, 0) + NVL(fo20b, 0) + NVL(fo19b, 0) +
|
|
NVL(fo11b, 0) + NVL(fo09b, 0) +
|
|
-- Taxare inversă (ti*b)
|
|
NVL(ti24b, 0) + NVL(ti21b, 0) + NVL(ti20b, 0) + NVL(ti19b, 0) +
|
|
NVL(ti11b, 0) + NVL(ti09b, 0) +
|
|
-- Achiziții intracomunitare (ce*b)
|
|
NVL(ceb, 0) + NVL(cebb, 0) + NVL(cesb, 0) +
|
|
-- Cross-border (xx*tib)
|
|
NVL(xx19tib, 0) + NVL(xx21tib, 0) + NVL(xx11tib, 0) + NVL(xx9tib, 0) +
|
|
-- Fără TVA
|
|
NVL(cen, 0))
|
|
FROM vjc2025
|
|
WHERE (an * 12 + luna) BETWEEN
|
|
(EXTRACT(YEAR FROM ADD_MONTHS(SYSDATE, -12)) * 12 + EXTRACT(MONTH FROM ADD_MONTHS(SYSDATE, -12)))
|
|
AND (EXTRACT(YEAR FROM SYSDATE) * 12 + EXTRACT(MONTH FROM SYSDATE))
|
|
AND EXTRACT(YEAR FROM dataireg) = an
|
|
AND EXTRACT(MONTH FROM dataireg) = luna) AS achizitii_12_luni
|
|
FROM dual
|
|
)
|
|
SELECT
|
|
'DIO (Zile stoc)' AS indicator,
|
|
ROUND(NVL(m.stoc_curent, 0) * 365 / NULLIF(m.cogs_12_luni, 0), 0) AS zile,
|
|
'(Stoc x 365) / Cost marfuri vandute (clasa 3xx x 365 / cost achizitie 12 luni)' AS formula,
|
|
'Zile medii pentru transformarea stocului in vanzare' AS explicatie
|
|
FROM metrici m
|
|
UNION ALL
|
|
SELECT
|
|
'DSO (Zile incasare)' AS indicator,
|
|
ROUND(NVL(m.creante, 0) * 365 / NULLIF(m.vanzari_12_luni, 0), 0) AS zile,
|
|
'(Creante x 365) / Vanzari anuale (cont 4111 x 365 / jurnal vanzari vjv2025)' AS formula,
|
|
'Zile medii pentru incasarea creantelor' AS explicatie
|
|
FROM metrici m
|
|
UNION ALL
|
|
SELECT
|
|
'DPO (Zile plata)' AS indicator,
|
|
ROUND(NVL(m.datorii_furnizori, 0) * 365 / NULLIF(m.achizitii_12_luni, 0), 0) AS zile,
|
|
'(Datorii furnizori x 365) / Achizitii anuale (cont 401 x 365 / jurnal cumparari vjc2025)' AS formula,
|
|
'Zile medii pentru plata furnizorilor' AS explicatie
|
|
FROM metrici m
|
|
UNION ALL
|
|
SELECT
|
|
'CCC (Ciclu conversie cash)' AS indicator,
|
|
ROUND(
|
|
NVL(m.stoc_curent, 0) * 365 / NULLIF(m.cogs_12_luni, 0) +
|
|
NVL(m.creante, 0) * 365 / NULLIF(m.vanzari_12_luni, 0) -
|
|
NVL(m.datorii_furnizori, 0) * 365 / NULLIF(m.achizitii_12_luni, 0)
|
|
, 0) AS zile,
|
|
'DIO + DSO - DPO (zile de la plata furnizor pana la incasare client)' AS formula,
|
|
'DIO + DSO - DPO = zile de la plata furnizor pana la incasare client' AS explicatie
|
|
FROM metrici m
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 26. INDICATORI AGREGATI VENITURI (Revenue mix per linie de business) - OPTIMIZAT
|
|
# =============================================================================
|
|
INDICATORI_AGREGATI_VENITURI = """
|
|
WITH vanzari_detaliate AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
CASE
|
|
WHEN d.cont IN ('341', '345') THEN 'Productie proprie'
|
|
WHEN d.cont = '301' THEN 'Materii prime'
|
|
ELSE 'Marfa revanduta'
|
|
END AS linie_business,
|
|
d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END AS vanzare,
|
|
d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie) AS marja
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -:months)
|
|
),
|
|
total AS (
|
|
SELECT SUM(vanzare) AS total_vanzari, SUM(marja) AS total_marja
|
|
FROM vanzari_detaliate
|
|
)
|
|
SELECT
|
|
v.linie_business,
|
|
ROUND(SUM(v.vanzare), 2) AS vanzari_ron,
|
|
ROUND(SUM(v.vanzare) * 100 / t.total_vanzari, 2) AS procent_venituri,
|
|
ROUND(SUM(v.marja), 2) AS marja_ron,
|
|
ROUND(SUM(v.marja) * 100 / NULLIF(SUM(v.vanzare), 0), 2) AS procent_marja,
|
|
ROUND(SUM(v.marja) * 100 / NULLIF(t.total_marja, 0), 2) AS contributie_profit
|
|
FROM vanzari_detaliate v
|
|
CROSS JOIN total t
|
|
GROUP BY v.linie_business, t.total_vanzari, t.total_marja
|
|
ORDER BY vanzari_ron DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 27. SEZONALITATE LUNARA (Analiza 24 luni)
|
|
# =============================================================================
|
|
SEZONALITATE_LUNARA = """
|
|
WITH vanzari_lunare AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
EXTRACT(MONTH FROM f.data_act) AS nr_luna,
|
|
TO_CHAR(f.data_act, 'Month', 'NLS_DATE_LANGUAGE=ROMANIAN') AS luna,
|
|
EXTRACT(YEAR FROM f.data_act) AS an,
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS vanzari
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
GROUP BY EXTRACT(MONTH FROM f.data_act), TO_CHAR(f.data_act, 'Month', 'NLS_DATE_LANGUAGE=ROMANIAN'), EXTRACT(YEAR FROM f.data_act)
|
|
),
|
|
statistici_luna AS (
|
|
SELECT
|
|
nr_luna,
|
|
TRIM(luna) AS luna,
|
|
ROUND(AVG(vanzari), 2) AS medie_vanzari,
|
|
ROUND(MIN(vanzari), 2) AS min_vanzari,
|
|
ROUND(MAX(vanzari), 2) AS max_vanzari,
|
|
ROUND(STDDEV(vanzari), 2) AS deviere_std
|
|
FROM vanzari_lunare
|
|
GROUP BY nr_luna, TRIM(luna)
|
|
),
|
|
media_globala AS (
|
|
SELECT AVG(vanzari) AS medie_globala FROM vanzari_lunare
|
|
)
|
|
SELECT
|
|
s.luna,
|
|
s.medie_vanzari,
|
|
s.min_vanzari,
|
|
s.max_vanzari,
|
|
ROUND((s.medie_vanzari - m.medie_globala) * 100 / m.medie_globala, 2) AS deviere_procent,
|
|
CASE
|
|
WHEN s.medie_vanzari > m.medie_globala * 1.15 THEN 'LUNA PUTERNICA'
|
|
WHEN s.medie_vanzari < m.medie_globala * 0.85 THEN 'LUNA SLABA'
|
|
ELSE 'NORMAL'
|
|
END AS clasificare
|
|
FROM statistici_luna s
|
|
CROSS JOIN media_globala m
|
|
ORDER BY s.nr_luna
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 28. PORTOFOLIU CLIENTI (Sănătatea portofoliului)
|
|
# =============================================================================
|
|
PORTOFOLIU_CLIENTI = """
|
|
WITH clienti_activi_3_luni AS (
|
|
SELECT /*+ INDEX(f IDX_VANZARI_NR) */ COUNT(DISTINCT f.id_part) AS cnt
|
|
FROM vanzari f
|
|
WHERE f.sters = 0 AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -3)
|
|
),
|
|
clienti_activi_12_luni AS (
|
|
SELECT /*+ INDEX(f IDX_VANZARI_NR) */ COUNT(DISTINCT f.id_part) AS cnt
|
|
FROM vanzari f
|
|
WHERE f.sters = 0 AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
),
|
|
clienti_noi AS (
|
|
SELECT /*+ INDEX(f IDX_VANZARI_NR) */ COUNT(DISTINCT f.id_part) AS cnt
|
|
FROM vanzari f
|
|
WHERE f.sters = 0 AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
AND f.id_part NOT IN (
|
|
SELECT /*+ INDEX(f2 IDX_VANZARI_NR) */ DISTINCT f2.id_part
|
|
FROM vanzari f2
|
|
WHERE f2.sters = 0 AND f2.tip > 0 AND f2.tip NOT IN (7, 8, 9, 24)
|
|
AND f2.data_act < ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
)
|
|
),
|
|
clienti_pierduti AS (
|
|
SELECT /*+ INDEX(f IDX_VANZARI_NR) */ COUNT(DISTINCT f.id_part) AS cnt
|
|
FROM vanzari f
|
|
WHERE f.sters = 0 AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
AND f.data_act < ADD_MONTHS(TRUNC(SYSDATE), -6)
|
|
AND f.id_part NOT IN (
|
|
SELECT /*+ INDEX(f2 IDX_VANZARI_NR) */ DISTINCT f2.id_part
|
|
FROM vanzari f2
|
|
WHERE f2.sters = 0 AND f2.tip > 0 AND f2.tip NOT IN (7, 8, 9, 24)
|
|
AND f2.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -6)
|
|
)
|
|
),
|
|
clienti_inactivi AS (
|
|
SELECT /*+ INDEX(f IDX_VANZARI_NR) */ COUNT(DISTINCT f.id_part) AS cnt
|
|
FROM vanzari f
|
|
WHERE f.sters = 0 AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -6)
|
|
AND f.data_act < ADD_MONTHS(TRUNC(SYSDATE), -3)
|
|
AND f.id_part NOT IN (
|
|
SELECT /*+ INDEX(f2 IDX_VANZARI_NR) */ DISTINCT f2.id_part
|
|
FROM vanzari f2
|
|
WHERE f2.sters = 0 AND f2.tip > 0 AND f2.tip NOT IN (7, 8, 9, 24)
|
|
AND f2.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -3)
|
|
)
|
|
)
|
|
SELECT 'Clienti activi (ultimele 3 luni)' AS indicator, cnt AS valoare, 'Au cumparat recent' AS explicatie FROM clienti_activi_3_luni
|
|
UNION ALL
|
|
SELECT 'Clienti activi (ultimele 12 luni)' AS indicator, cnt AS valoare, 'Au cumparat in ultimul an' AS explicatie FROM clienti_activi_12_luni
|
|
UNION ALL
|
|
SELECT 'Clienti noi (ultimele 12 luni)' AS indicator, cnt AS valoare, 'Prima achizitie in ultimul an' AS explicatie FROM clienti_noi
|
|
UNION ALL
|
|
SELECT 'Clienti pierduti (>6 luni inactivi)' AS indicator, cnt AS valoare, 'Nu au mai cumparat de 6+ luni' AS explicatie FROM clienti_pierduti
|
|
UNION ALL
|
|
SELECT 'Clienti inactivi (3-6 luni)' AS indicator, cnt AS valoare, 'Risc de pierdere' AS explicatie FROM clienti_inactivi
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 29. FRECVENTA CLIENTI (Frecvența comenzilor și evoluție YoY)
|
|
# =============================================================================
|
|
FRECVENTA_CLIENTI = """
|
|
WITH frecventa_curenta AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
f.id_part,
|
|
p.denumire AS client,
|
|
COUNT(DISTINCT f.id_vanzare) AS comenzi_12_luni,
|
|
ROUND(COUNT(DISTINCT f.id_vanzare) / 12.0, 2) AS comenzi_pe_luna,
|
|
ROUND(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 2) AS valoare_12_luni
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_parteneri p ON f.id_part = p.id_part
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
GROUP BY f.id_part, p.denumire
|
|
),
|
|
frecventa_anterioara AS (
|
|
SELECT /*+ INDEX(f IDX_VANZARI_NR) */
|
|
f.id_part,
|
|
COUNT(DISTINCT f.id_vanzare) AS comenzi_an_anterior
|
|
FROM vanzari f
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
AND f.data_act < ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
GROUP BY f.id_part
|
|
)
|
|
SELECT
|
|
fc.client,
|
|
fc.comenzi_12_luni,
|
|
fc.comenzi_pe_luna,
|
|
fc.valoare_12_luni,
|
|
ROUND(fc.valoare_12_luni / NULLIF(fc.comenzi_12_luni, 0), 2) AS valoare_medie_comanda,
|
|
ROUND(
|
|
CASE WHEN fa.comenzi_an_anterior > 0
|
|
THEN (fc.comenzi_12_luni - fa.comenzi_an_anterior) * 100.0 / fa.comenzi_an_anterior
|
|
ELSE NULL END
|
|
, 2) AS evolutie_frecventa_yoy
|
|
FROM frecventa_curenta fc
|
|
LEFT JOIN frecventa_anterioara fa ON fa.id_part = fc.id_part
|
|
WHERE fc.valoare_12_luni > 5000
|
|
ORDER BY fc.valoare_12_luni DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 30. CONCENTRARE RISC (Risc de concentrare)
|
|
# =============================================================================
|
|
CONCENTRARE_RISC = """
|
|
WITH total_vanzari AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS total
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -:months)
|
|
),
|
|
vanzari_client AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
f.id_part,
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS vanzari,
|
|
ROW_NUMBER() OVER (ORDER BY SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) DESC) AS rn
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -:months)
|
|
GROUP BY f.id_part
|
|
)
|
|
SELECT
|
|
'Top 1 client' AS indicator,
|
|
ROUND(SUM(CASE WHEN vc.rn <= 1 THEN vc.vanzari ELSE 0 END) * 100 / tv.total, 2) AS procent,
|
|
CASE
|
|
WHEN SUM(CASE WHEN vc.rn <= 1 THEN vc.vanzari ELSE 0 END) * 100 / tv.total > 25 THEN 'RISC MARE'
|
|
WHEN SUM(CASE WHEN vc.rn <= 1 THEN vc.vanzari ELSE 0 END) * 100 / tv.total > 15 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status
|
|
FROM vanzari_client vc
|
|
CROSS JOIN total_vanzari tv
|
|
GROUP BY tv.total
|
|
UNION ALL
|
|
SELECT
|
|
'Top 5 clienti' AS indicator,
|
|
ROUND(SUM(CASE WHEN vc.rn <= 5 THEN vc.vanzari ELSE 0 END) * 100 / tv.total, 2) AS procent,
|
|
CASE
|
|
WHEN SUM(CASE WHEN vc.rn <= 5 THEN vc.vanzari ELSE 0 END) * 100 / tv.total > 60 THEN 'RISC MARE'
|
|
WHEN SUM(CASE WHEN vc.rn <= 5 THEN vc.vanzari ELSE 0 END) * 100 / tv.total > 40 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status
|
|
FROM vanzari_client vc
|
|
CROSS JOIN total_vanzari tv
|
|
GROUP BY tv.total
|
|
UNION ALL
|
|
SELECT
|
|
'Top 10 clienti' AS indicator,
|
|
ROUND(SUM(CASE WHEN vc.rn <= 10 THEN vc.vanzari ELSE 0 END) * 100 / tv.total, 2) AS procent,
|
|
CASE
|
|
WHEN SUM(CASE WHEN vc.rn <= 10 THEN vc.vanzari ELSE 0 END) * 100 / tv.total > 80 THEN 'RISC MARE'
|
|
WHEN SUM(CASE WHEN vc.rn <= 10 THEN vc.vanzari ELSE 0 END) * 100 / tv.total > 60 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status
|
|
FROM vanzari_client vc
|
|
CROSS JOIN total_vanzari tv
|
|
GROUP BY tv.total
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 31. CLIENTI RANKING PROFIT (Ranking după profit, nu venituri)
|
|
# =============================================================================
|
|
CLIENTI_RANKING_PROFIT = """
|
|
WITH vanzari_client AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
f.id_part,
|
|
p.denumire AS client,
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS vanzari_fara_tva,
|
|
SUM(d.cantitate * d.pret_achizitie) AS cost_total,
|
|
SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) AS profit_brut
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_parteneri p ON f.id_part = p.id_part
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -:months)
|
|
GROUP BY f.id_part, p.denumire
|
|
)
|
|
SELECT
|
|
client,
|
|
ROUND(vanzari_fara_tva, 2) AS vanzari_fara_tva,
|
|
ROUND(cost_total, 2) AS cost_total,
|
|
ROUND(profit_brut, 2) AS profit_brut,
|
|
ROUND(profit_brut * 100 / NULLIF(vanzari_fara_tva, 0), 2) AS procent_marja,
|
|
RANK() OVER (ORDER BY profit_brut DESC) AS rang_profit,
|
|
RANK() OVER (ORDER BY vanzari_fara_tva DESC) AS rang_vanzari
|
|
FROM vanzari_client
|
|
WHERE vanzari_fara_tva > 1000
|
|
ORDER BY profit_brut DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 32. MARJA CLIENT CATEGORIE (Marjă per categorie per client) - OPTIMIZAT
|
|
# =============================================================================
|
|
MARJA_CLIENT_CATEGORIE = """
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
p.denumire AS client,
|
|
NVL(sg.grupa, 'NECLASIFICAT') AS categoria,
|
|
ROUND(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 2) AS vanzari,
|
|
ROUND(SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)), 2) AS marja,
|
|
ROUND(
|
|
SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) * 100.0 /
|
|
NULLIF(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 0)
|
|
, 2) AS procent_marja,
|
|
CASE
|
|
WHEN SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) < 0 THEN 'PIERDERE'
|
|
WHEN SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) * 100.0 /
|
|
NULLIF(SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END), 0) < 15 THEN 'MARJA MICA'
|
|
ELSE 'OK'
|
|
END AS status_marja
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_parteneri p ON f.id_part = p.id_part
|
|
LEFT JOIN nom_articole art ON d.id_articol = art.id_articol
|
|
LEFT JOIN vgest_art_sbgr sg ON art.id_subgrupa = sg.id_subgrupa
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE, 'MM'), -:months)
|
|
GROUP BY f.id_part, p.denumire, sg.id_grupa, sg.grupa
|
|
HAVING SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) > 1000
|
|
ORDER BY p.denumire, vanzari DESC
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 33. EVOLUTIE DISCOUNT (Discount creep - evoluția prețului în timp)
|
|
# =============================================================================
|
|
EVOLUTIE_DISCOUNT = """
|
|
WITH preturi_vechi AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
d.id_articol,
|
|
a.denumire,
|
|
AVG(CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS pret_mediu_vechi
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
LEFT JOIN nom_articole a ON d.id_articol = a.id_articol
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
AND f.data_act < ADD_MONTHS(TRUNC(SYSDATE), -6)
|
|
AND d.pret > 0
|
|
GROUP BY d.id_articol, a.denumire
|
|
HAVING COUNT(*) >= 5
|
|
),
|
|
preturi_noi AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
d.id_articol,
|
|
AVG(CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS pret_mediu_nou
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -6)
|
|
AND d.pret > 0
|
|
GROUP BY d.id_articol
|
|
HAVING COUNT(*) >= 5
|
|
)
|
|
SELECT
|
|
pv.denumire AS produs,
|
|
ROUND(pv.pret_mediu_vechi, 2) AS pret_initial,
|
|
ROUND(pn.pret_mediu_nou, 2) AS pret_actual,
|
|
ROUND((pn.pret_mediu_nou - pv.pret_mediu_vechi) * 100 / pv.pret_mediu_vechi, 2) AS variatie_pret_procent
|
|
FROM preturi_vechi pv
|
|
JOIN preturi_noi pn ON pn.id_articol = pv.id_articol
|
|
WHERE ABS(pn.pret_mediu_nou - pv.pret_mediu_vechi) / pv.pret_mediu_vechi > 0.05
|
|
ORDER BY variatie_pret_procent ASC
|
|
FETCH FIRST 50 ROWS ONLY
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 34. INDICATORI GENERALI DE BUSINESS
|
|
# =============================================================================
|
|
INDICATORI_GENERALI = """
|
|
WITH
|
|
-- Capital propriu (conturi 10x, 11x, 12x, 117)
|
|
capitaluri AS (
|
|
SELECT SUM(b.soldcred - b.solddeb) AS capital_propriu
|
|
FROM vbal b
|
|
WHERE (b.cont LIKE '101%' OR b.cont LIKE '104%' OR b.cont LIKE '105%'
|
|
OR b.cont LIKE '106%' OR b.cont LIKE '117%' OR b.cont LIKE '121%')
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
-- Datorii totale (16x, 40x, 42x, 44x, 46x)
|
|
datorii AS (
|
|
SELECT SUM(b.soldcred - b.solddeb) AS datorii_totale
|
|
FROM vbal b
|
|
WHERE (b.cont LIKE '16%' OR b.cont LIKE '40%' OR b.cont LIKE '42%'
|
|
OR b.cont LIKE '44%' OR b.cont LIKE '46%')
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
-- Total activ (sold debitor toate conturile de activ)
|
|
activ AS (
|
|
SELECT SUM(b.solddeb - b.soldcred) AS total_activ
|
|
FROM vbal b
|
|
WHERE (b.cont LIKE '1%' OR b.cont LIKE '2%' OR b.cont LIKE '3%'
|
|
OR b.cont LIKE '4%' OR b.cont LIKE '5%')
|
|
AND b.cont NOT LIKE '16%' AND b.cont NOT LIKE '40%' AND b.cont NOT LIKE '42%'
|
|
AND b.cont NOT LIKE '44%' AND b.cont NOT LIKE '46%' AND b.cont NOT LIKE '47%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
-- Vanzari si profit din ultimele 12 luni
|
|
vanzari_calc AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS total_vanzari,
|
|
SUM(d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie)) AS profit_brut
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
)
|
|
SELECT
|
|
'Grad indatorare' AS indicator,
|
|
ROUND(NVL(dt.datorii_totale, 0) / NULLIF(cp.capital_propriu, 0), 2) AS valoare,
|
|
CASE
|
|
WHEN NVL(dt.datorii_totale, 0) / NULLIF(cp.capital_propriu, 0) > 2 THEN 'ALERTA'
|
|
WHEN NVL(dt.datorii_totale, 0) / NULLIF(cp.capital_propriu, 0) > 1 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status,
|
|
'Datorii / Capital Propriu (cont 16x,40x,42x,44x,46x / cont 10x,11x,12x,117)' AS formula,
|
|
'< 1 = bine, > 2 = risc' AS interpretare,
|
|
CASE
|
|
WHEN NVL(dt.datorii_totale, 0) / NULLIF(cp.capital_propriu, 0) > 2 THEN 'Reduceti datoriile sau cresteti capitalul propriu'
|
|
WHEN NVL(dt.datorii_totale, 0) / NULLIF(cp.capital_propriu, 0) > 1 THEN 'Monitorizati nivelul datoriilor'
|
|
ELSE 'Situatie financiara solida'
|
|
END AS recomandare
|
|
FROM capitaluri cp, datorii dt
|
|
UNION ALL
|
|
SELECT
|
|
'Grad autonomie financiara' AS indicator,
|
|
ROUND(NVL(cp.capital_propriu, 0) / NULLIF(ac.total_activ, 0), 2) AS valoare,
|
|
CASE
|
|
WHEN NVL(cp.capital_propriu, 0) / NULLIF(ac.total_activ, 0) < 0.3 THEN 'ALERTA'
|
|
WHEN NVL(cp.capital_propriu, 0) / NULLIF(ac.total_activ, 0) < 0.5 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status,
|
|
'Capital Propriu / Total Active (cont 10x,11x,12x,117 / Active clasa 1-5)' AS formula,
|
|
'> 0.5 = bine, < 0.3 = risc' AS interpretare,
|
|
CASE
|
|
WHEN NVL(cp.capital_propriu, 0) / NULLIF(ac.total_activ, 0) < 0.3 THEN 'Dependenta prea mare de creditori'
|
|
WHEN NVL(cp.capital_propriu, 0) / NULLIF(ac.total_activ, 0) < 0.5 THEN 'Cresteti capitalul propriu'
|
|
ELSE 'Autonomie financiara buna'
|
|
END AS recomandare
|
|
FROM capitaluri cp, activ ac
|
|
UNION ALL
|
|
SELECT
|
|
'Rata datoriilor' AS indicator,
|
|
ROUND(NVL(dt.datorii_totale, 0) / NULLIF(ac.total_activ, 0), 2) AS valoare,
|
|
CASE
|
|
WHEN NVL(dt.datorii_totale, 0) / NULLIF(ac.total_activ, 0) > 0.7 THEN 'ALERTA'
|
|
WHEN NVL(dt.datorii_totale, 0) / NULLIF(ac.total_activ, 0) > 0.5 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status,
|
|
'Datorii / Total Active (cont 16x,40x,42x,44x,46x / Active clasa 1-5)' AS formula,
|
|
'< 0.5 = bine, > 0.7 = risc' AS interpretare,
|
|
CASE
|
|
WHEN NVL(dt.datorii_totale, 0) / NULLIF(ac.total_activ, 0) > 0.7 THEN 'Risc de insolventa - reduceti datoriile'
|
|
WHEN NVL(dt.datorii_totale, 0) / NULLIF(ac.total_activ, 0) > 0.5 THEN 'Atentie la capacitatea de plata'
|
|
ELSE 'Nivel acceptabil al datoriilor'
|
|
END AS recomandare
|
|
FROM datorii dt, activ ac
|
|
UNION ALL
|
|
SELECT
|
|
'Marja neta (%)' AS indicator,
|
|
ROUND(NVL(v.profit_brut, 0) * 100 / NULLIF(v.total_vanzari, 0), 2) AS valoare,
|
|
CASE
|
|
WHEN NVL(v.profit_brut, 0) * 100 / NULLIF(v.total_vanzari, 0) < 3 THEN 'ALERTA'
|
|
WHEN NVL(v.profit_brut, 0) * 100 / NULLIF(v.total_vanzari, 0) < 5 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status,
|
|
'(Profit Brut / Vanzari) x 100 (din facturi ultimele 12 luni)' AS formula,
|
|
'> 5% = bine, < 3% = risc' AS interpretare,
|
|
CASE
|
|
WHEN NVL(v.profit_brut, 0) * 100 / NULLIF(v.total_vanzari, 0) < 3 THEN 'Marja periculoasa - revizuiti preturile si costurile'
|
|
WHEN NVL(v.profit_brut, 0) * 100 / NULLIF(v.total_vanzari, 0) < 5 THEN 'Optimizati costurile sau cresteti preturile'
|
|
ELSE 'Marja acceptabila'
|
|
END AS recomandare
|
|
FROM vanzari_calc v
|
|
UNION ALL
|
|
SELECT
|
|
'ROA - Rentabilitatea activelor (%)' AS indicator,
|
|
ROUND(NVL(v.profit_brut, 0) * 100 / NULLIF(ac.total_activ, 0), 2) AS valoare,
|
|
CASE
|
|
WHEN NVL(v.profit_brut, 0) * 100 / NULLIF(ac.total_activ, 0) < 2 THEN 'ALERTA'
|
|
WHEN NVL(v.profit_brut, 0) * 100 / NULLIF(ac.total_activ, 0) < 5 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status,
|
|
'(Profit Brut / Total Active) x 100 (facturi 12 luni / balanta)' AS formula,
|
|
'> 5% = bine, < 2% = slab' AS interpretare,
|
|
CASE
|
|
WHEN NVL(v.profit_brut, 0) * 100 / NULLIF(ac.total_activ, 0) < 2 THEN 'Activele nu genereaza profit suficient - optimizati utilizarea'
|
|
WHEN NVL(v.profit_brut, 0) * 100 / NULLIF(ac.total_activ, 0) < 5 THEN 'Cresteti eficienta utilizarii activelor'
|
|
ELSE 'Activele sunt utilizate eficient'
|
|
END AS recomandare
|
|
FROM vanzari_calc v, activ ac
|
|
UNION ALL
|
|
SELECT
|
|
'Rotatia activelor' AS indicator,
|
|
ROUND(NVL(v.total_vanzari, 0) / NULLIF(ac.total_activ, 0), 2) AS valoare,
|
|
CASE
|
|
WHEN NVL(v.total_vanzari, 0) / NULLIF(ac.total_activ, 0) < 0.5 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status,
|
|
'Vanzari / Total Active (facturi 12 luni / balanta)' AS formula,
|
|
'> 1 = eficient' AS interpretare,
|
|
CASE
|
|
WHEN NVL(v.total_vanzari, 0) / NULLIF(ac.total_activ, 0) < 0.5 THEN 'Active subutilizate - cresteti vanzarile'
|
|
ELSE 'Activele genereaza vanzari eficient'
|
|
END AS recomandare
|
|
FROM vanzari_calc v, activ ac
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 35. INDICATORI LICHIDITATE
|
|
# =============================================================================
|
|
INDICATORI_LICHIDITATE = """
|
|
WITH
|
|
-- Cash (conturi 5121, 5124, 5311, 5314)
|
|
cash AS (
|
|
SELECT SUM(b.solddeb - b.soldcred) AS cash_total
|
|
FROM vbal b
|
|
WHERE (b.cont LIKE '512%' OR b.cont LIKE '531%')
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
-- Creante (cont 4111)
|
|
creante AS (
|
|
SELECT SUM(CASE WHEN b.solddeb > b.soldcred THEN b.solddeb - b.soldcred ELSE 0 END) AS creante_total
|
|
FROM vbalanta_parteneri b
|
|
WHERE b.cont LIKE '4111%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
-- Stocuri
|
|
stocuri AS (
|
|
SELECT SUM((s.cants + s.cant - s.cante) * s.pret) AS stoc_total
|
|
FROM vstoc s
|
|
WHERE s.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND s.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
AND (s.cants + s.cant - s.cante) > 0
|
|
),
|
|
-- Datorii curente (401, 404, 462)
|
|
datorii_curente AS (
|
|
SELECT SUM(CASE WHEN b.soldcred > b.solddeb THEN b.soldcred - b.solddeb ELSE 0 END) AS datorii_total
|
|
FROM vbalanta_parteneri b
|
|
WHERE (b.cont LIKE '401%' OR b.cont LIKE '404%' OR b.cont LIKE '462%')
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
)
|
|
SELECT
|
|
'Lichiditate curenta' AS indicator,
|
|
ROUND((NVL(c.cash_total, 0) + NVL(cr.creante_total, 0) + NVL(st.stoc_total, 0)) / NULLIF(dc.datorii_total, 0), 2) AS valoare,
|
|
CASE
|
|
WHEN (NVL(c.cash_total, 0) + NVL(cr.creante_total, 0) + NVL(st.stoc_total, 0)) / NULLIF(dc.datorii_total, 0) < 1.0 THEN 'ALERTA'
|
|
WHEN (NVL(c.cash_total, 0) + NVL(cr.creante_total, 0) + NVL(st.stoc_total, 0)) / NULLIF(dc.datorii_total, 0) < 1.5 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status,
|
|
'(Cash + Creante + Stoc) / Datorii curente (cont 512x,531x + 4111 + vstoc / cont 401x,404x,462x)' AS formula,
|
|
'>= 1.5 ideal, >= 1.0 acceptabil' AS interpretare,
|
|
CASE
|
|
WHEN (NVL(c.cash_total, 0) + NVL(cr.creante_total, 0) + NVL(st.stoc_total, 0)) / NULLIF(dc.datorii_total, 0) < 1.0 THEN 'Risc de lichiditate - nu puteti acoperi datoriile curente'
|
|
WHEN (NVL(c.cash_total, 0) + NVL(cr.creante_total, 0) + NVL(st.stoc_total, 0)) / NULLIF(dc.datorii_total, 0) < 1.5 THEN 'Mentineti rezerve suplimentare'
|
|
ELSE 'Lichiditate buna'
|
|
END AS recomandare
|
|
FROM cash c, creante cr, stocuri st, datorii_curente dc
|
|
UNION ALL
|
|
SELECT
|
|
'Lichiditate rapida (Quick Ratio)' AS indicator,
|
|
ROUND((NVL(c.cash_total, 0) + NVL(cr.creante_total, 0)) / NULLIF(dc.datorii_total, 0), 2) AS valoare,
|
|
CASE
|
|
WHEN (NVL(c.cash_total, 0) + NVL(cr.creante_total, 0)) / NULLIF(dc.datorii_total, 0) < 0.7 THEN 'ALERTA'
|
|
WHEN (NVL(c.cash_total, 0) + NVL(cr.creante_total, 0)) / NULLIF(dc.datorii_total, 0) < 1.0 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status,
|
|
'(Cash + Creante) / Datorii curente - fara stocuri (cont 512x,531x + 4111 / cont 401x,404x,462x)' AS formula,
|
|
'>= 1.0 ideal, >= 0.7 acceptabil' AS interpretare,
|
|
CASE
|
|
WHEN (NVL(c.cash_total, 0) + NVL(cr.creante_total, 0)) / NULLIF(dc.datorii_total, 0) < 0.7 THEN 'Dependenta de stocuri pentru plata datoriilor'
|
|
WHEN (NVL(c.cash_total, 0) + NVL(cr.creante_total, 0)) / NULLIF(dc.datorii_total, 0) < 1.0 THEN 'Accelerati incasarile'
|
|
ELSE 'Lichiditate rapida buna'
|
|
END AS recomandare
|
|
FROM cash c, creante cr, datorii_curente dc
|
|
UNION ALL
|
|
SELECT
|
|
'Rata de cash (Cash Ratio)' AS indicator,
|
|
ROUND(NVL(c.cash_total, 0) / NULLIF(dc.datorii_total, 0), 2) AS valoare,
|
|
CASE
|
|
WHEN NVL(c.cash_total, 0) / NULLIF(dc.datorii_total, 0) < 0.1 THEN 'ALERTA'
|
|
WHEN NVL(c.cash_total, 0) / NULLIF(dc.datorii_total, 0) < 0.2 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status,
|
|
'Cash / Datorii curente (cont 512x,531x / cont 401x,404x,462x)' AS formula,
|
|
'>= 0.2 ideal, >= 0.1 minim' AS interpretare,
|
|
CASE
|
|
WHEN NVL(c.cash_total, 0) / NULLIF(dc.datorii_total, 0) < 0.1 THEN 'Cash insuficient - risc la plati urgente'
|
|
WHEN NVL(c.cash_total, 0) / NULLIF(dc.datorii_total, 0) < 0.2 THEN 'Cresteti rezervele de cash'
|
|
ELSE 'Rezerve de cash suficiente'
|
|
END AS recomandare
|
|
FROM cash c, datorii_curente dc
|
|
UNION ALL
|
|
SELECT
|
|
'Fond de rulment (RON)' AS indicator,
|
|
ROUND((NVL(c.cash_total, 0) + NVL(cr.creante_total, 0) + NVL(st.stoc_total, 0)) - NVL(dc.datorii_total, 0), 0) AS valoare,
|
|
CASE
|
|
WHEN (NVL(c.cash_total, 0) + NVL(cr.creante_total, 0) + NVL(st.stoc_total, 0)) - NVL(dc.datorii_total, 0) < 0 THEN 'ALERTA'
|
|
ELSE 'OK'
|
|
END AS status,
|
|
'Active curente - Datorii curente (Cash + Creante + Stoc - Datorii furnizori)' AS formula,
|
|
'Pozitiv = OK, Negativ = probleme' AS interpretare,
|
|
CASE
|
|
WHEN (NVL(c.cash_total, 0) + NVL(cr.creante_total, 0) + NVL(st.stoc_total, 0)) - NVL(dc.datorii_total, 0) < 0 THEN 'Fond de rulment negativ - necesita finantare'
|
|
ELSE 'Capital de lucru pozitiv'
|
|
END AS recomandare
|
|
FROM cash c, creante cr, stocuri st, datorii_curente dc
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 36. CLASIFICARE DATORII PE TERMENE
|
|
# =============================================================================
|
|
CLASIFICARE_DATORII = """
|
|
WITH datorii_scadenta AS (
|
|
SELECT
|
|
r.id_part,
|
|
r.nume AS furnizor,
|
|
r.datascad,
|
|
(r.preccred + r.credit) - (r.precdeb + r.debit) AS sold_ramas,
|
|
CASE
|
|
WHEN r.datascad IS NULL THEN 'TERMEN_NEDEFINIT'
|
|
WHEN r.datascad <= TRUNC(SYSDATE) + 30 THEN 'TERMEN_SCURT'
|
|
WHEN r.datascad <= TRUNC(SYSDATE) + 90 THEN 'TERMEN_MEDIU'
|
|
ELSE 'TERMEN_LUNG'
|
|
END AS clasificare
|
|
FROM vireg_parteneri r
|
|
WHERE (r.cont LIKE '401%' OR r.cont LIKE '404%' OR r.cont LIKE '462%')
|
|
AND (r.preccred + r.credit) - (r.precdeb + r.debit) <> 0
|
|
)
|
|
SELECT
|
|
'Datorii termen scurt (<= 30 zile)' AS categorie,
|
|
ROUND(SUM(CASE WHEN clasificare = 'TERMEN_SCURT' THEN sold_ramas ELSE 0 END), 0) AS valoare,
|
|
COUNT(CASE WHEN clasificare = 'TERMEN_SCURT' THEN 1 END) AS nr_facturi,
|
|
'Prioritate INALTA - de platit urgent' AS observatie
|
|
FROM datorii_scadenta
|
|
UNION ALL
|
|
SELECT
|
|
'Datorii termen mediu (31-90 zile)' AS categorie,
|
|
ROUND(SUM(CASE WHEN clasificare = 'TERMEN_MEDIU' THEN sold_ramas ELSE 0 END), 0) AS valoare,
|
|
COUNT(CASE WHEN clasificare = 'TERMEN_MEDIU' THEN 1 END) AS nr_facturi,
|
|
'Prioritate MEDIE - planificati plata' AS observatie
|
|
FROM datorii_scadenta
|
|
UNION ALL
|
|
SELECT
|
|
'Datorii termen lung (> 90 zile)' AS categorie,
|
|
ROUND(SUM(CASE WHEN clasificare = 'TERMEN_LUNG' THEN sold_ramas ELSE 0 END), 0) AS valoare,
|
|
COUNT(CASE WHEN clasificare = 'TERMEN_LUNG' THEN 1 END) AS nr_facturi,
|
|
'Prioritate SCAZUTA' AS observatie
|
|
FROM datorii_scadenta
|
|
UNION ALL
|
|
SELECT
|
|
'Datorii fara scadenta definita' AS categorie,
|
|
ROUND(SUM(CASE WHEN clasificare = 'TERMEN_NEDEFINIT' THEN sold_ramas ELSE 0 END), 0) AS valoare,
|
|
COUNT(CASE WHEN clasificare = 'TERMEN_NEDEFINIT' THEN 1 END) AS nr_facturi,
|
|
'Verificati datele de scadenta' AS observatie
|
|
FROM datorii_scadenta
|
|
UNION ALL
|
|
SELECT
|
|
'TOTAL DATORII' AS categorie,
|
|
ROUND(SUM(sold_ramas), 0) AS valoare,
|
|
COUNT(*) AS nr_facturi,
|
|
'Suma totala de platit' AS observatie
|
|
FROM datorii_scadenta
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 37. GRAD ACOPERIRE DATORII (Cash + Incasari vs Datorii scadente)
|
|
# =============================================================================
|
|
GRAD_ACOPERIRE_DATORII = """
|
|
WITH
|
|
cash_curent AS (
|
|
SELECT SUM(b.solddeb - b.soldcred) AS cash_total
|
|
FROM vbal b
|
|
WHERE (b.cont LIKE '512%' OR b.cont LIKE '531%')
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
incasari_asteptate AS (
|
|
SELECT
|
|
ROUND(SUM(CASE WHEN r.datascad <= TRUNC(SYSDATE) + 30 THEN (r.precdeb + r.debit) - (r.preccred + r.credit) ELSE 0 END), 0) AS incasari_30,
|
|
ROUND(SUM(CASE WHEN r.datascad <= TRUNC(SYSDATE) + 60 THEN (r.precdeb + r.debit) - (r.preccred + r.credit) ELSE 0 END), 0) AS incasari_60,
|
|
ROUND(SUM(CASE WHEN r.datascad <= TRUNC(SYSDATE) + 90 THEN (r.precdeb + r.debit) - (r.preccred + r.credit) ELSE 0 END), 0) AS incasari_90
|
|
FROM vireg_parteneri r
|
|
WHERE (r.cont LIKE '4111%' OR r.cont LIKE '461%')
|
|
AND (r.precdeb + r.debit) - (r.preccred + r.credit) <> 0
|
|
),
|
|
plati_scadente AS (
|
|
SELECT
|
|
ROUND(SUM(CASE WHEN r.datascad <= TRUNC(SYSDATE) + 30 THEN (r.preccred + r.credit) - (r.precdeb + r.debit) ELSE 0 END), 0) AS plati_30,
|
|
ROUND(SUM(CASE WHEN r.datascad <= TRUNC(SYSDATE) + 60 THEN (r.preccred + r.credit) - (r.precdeb + r.debit) ELSE 0 END), 0) AS plati_60,
|
|
ROUND(SUM(CASE WHEN r.datascad <= TRUNC(SYSDATE) + 90 THEN (r.preccred + r.credit) - (r.precdeb + r.debit) ELSE 0 END), 0) AS plati_90
|
|
FROM vireg_parteneri r
|
|
WHERE (r.cont LIKE '401%' OR r.cont LIKE '404%' OR r.cont LIKE '462%')
|
|
AND (r.preccred + r.credit) - (r.precdeb + r.debit) <> 0
|
|
)
|
|
SELECT
|
|
'Cash disponibil' AS indicator,
|
|
NVL(c.cash_total, 0) AS valoare,
|
|
'-' AS acoperire,
|
|
'Disponibil imediat' AS explicatie
|
|
FROM cash_curent c
|
|
UNION ALL
|
|
SELECT
|
|
'Incasari asteptate 30 zile' AS indicator,
|
|
NVL(i.incasari_30, 0) AS valoare,
|
|
'-' AS acoperire,
|
|
'Facturi clienti scadente in 30 zile' AS explicatie
|
|
FROM incasari_asteptate i
|
|
UNION ALL
|
|
SELECT
|
|
'Plati scadente 30 zile' AS indicator,
|
|
NVL(p.plati_30, 0) AS valoare,
|
|
'-' AS acoperire,
|
|
'Facturi furnizori de platit in 30 zile' AS explicatie
|
|
FROM plati_scadente p
|
|
UNION ALL
|
|
SELECT
|
|
'GRAD ACOPERIRE 30 ZILE' AS indicator,
|
|
ROUND((NVL(c.cash_total, 0) + NVL(i.incasari_30, 0)) / NULLIF(p.plati_30, 0), 2) AS valoare,
|
|
CASE
|
|
WHEN (NVL(c.cash_total, 0) + NVL(i.incasari_30, 0)) / NULLIF(p.plati_30, 0) < 1 THEN 'DEFICIT'
|
|
WHEN (NVL(c.cash_total, 0) + NVL(i.incasari_30, 0)) / NULLIF(p.plati_30, 0) < 1.2 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS acoperire,
|
|
CASE
|
|
WHEN (NVL(c.cash_total, 0) + NVL(i.incasari_30, 0)) / NULLIF(p.plati_30, 0) < 1 THEN 'NECESITA FINANTARE'
|
|
ELSE 'Acoperiti platile'
|
|
END AS explicatie
|
|
FROM cash_curent c, incasari_asteptate i, plati_scadente p
|
|
UNION ALL
|
|
SELECT
|
|
'NECESAR FINANTARE 30 ZILE' AS indicator,
|
|
CASE
|
|
WHEN NVL(p.plati_30, 0) - (NVL(c.cash_total, 0) + NVL(i.incasari_30, 0)) > 0
|
|
THEN NVL(p.plati_30, 0) - (NVL(c.cash_total, 0) + NVL(i.incasari_30, 0))
|
|
ELSE 0
|
|
END AS valoare,
|
|
CASE
|
|
WHEN NVL(p.plati_30, 0) - (NVL(c.cash_total, 0) + NVL(i.incasari_30, 0)) > 0 THEN 'NECESAR'
|
|
ELSE 'NU E NECESAR'
|
|
END AS acoperire,
|
|
'Suma de obtinut pentru acoperirea deficitului' AS explicatie
|
|
FROM cash_curent c, incasari_asteptate i, plati_scadente p
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 38. PROIECTIE LICHIDITATE 30/60/90 ZILE
|
|
# =============================================================================
|
|
PROIECTIE_LICHIDITATE = """
|
|
WITH
|
|
cash_curent AS (
|
|
SELECT SUM(b.solddeb - b.soldcred) AS cash_total
|
|
FROM vbal b
|
|
WHERE (b.cont LIKE '512%' OR b.cont LIKE '531%')
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
incasari_programate AS (
|
|
SELECT
|
|
SUM(CASE WHEN r.datascad <= TRUNC(SYSDATE) + 30 THEN (r.precdeb + r.debit) - (r.preccred + r.credit) ELSE 0 END) AS incasari_30,
|
|
SUM(CASE WHEN r.datascad > TRUNC(SYSDATE) + 30 AND r.datascad <= TRUNC(SYSDATE) + 60 THEN (r.precdeb + r.debit) - (r.preccred + r.credit) ELSE 0 END) AS incasari_31_60,
|
|
SUM(CASE WHEN r.datascad > TRUNC(SYSDATE) + 60 AND r.datascad <= TRUNC(SYSDATE) + 90 THEN (r.precdeb + r.debit) - (r.preccred + r.credit) ELSE 0 END) AS incasari_61_90
|
|
FROM vireg_parteneri r
|
|
WHERE (r.cont LIKE '4111%' OR r.cont LIKE '461%')
|
|
AND (r.precdeb + r.debit) - (r.preccred + r.credit) <> 0
|
|
),
|
|
plati_programate AS (
|
|
SELECT
|
|
SUM(CASE WHEN r.datascad <= TRUNC(SYSDATE) + 30 THEN (r.preccred + r.credit) - (r.precdeb + r.debit) ELSE 0 END) AS plati_30,
|
|
SUM(CASE WHEN r.datascad > TRUNC(SYSDATE) + 30 AND r.datascad <= TRUNC(SYSDATE) + 60 THEN (r.preccred + r.credit) - (r.precdeb + r.debit) ELSE 0 END) AS plati_31_60,
|
|
SUM(CASE WHEN r.datascad > TRUNC(SYSDATE) + 60 AND r.datascad <= TRUNC(SYSDATE) + 90 THEN (r.preccred + r.credit) - (r.precdeb + r.debit) ELSE 0 END) AS plati_61_90
|
|
FROM vireg_parteneri r
|
|
WHERE (r.cont LIKE '401%' OR r.cont LIKE '404%' OR r.cont LIKE '462%')
|
|
AND (r.preccred + r.credit) - (r.precdeb + r.debit) <> 0
|
|
)
|
|
SELECT
|
|
'Sold initial (azi)' AS perioada,
|
|
ROUND(NVL(c.cash_total, 0), 0) AS sold_proiectat,
|
|
0 AS incasari,
|
|
0 AS plati,
|
|
0 AS flux_net,
|
|
'OK' AS status
|
|
FROM cash_curent c
|
|
UNION ALL
|
|
SELECT
|
|
'Proiectie 30 zile' AS perioada,
|
|
ROUND(NVL(c.cash_total, 0) + NVL(i.incasari_30, 0) - NVL(p.plati_30, 0), 0) AS sold_proiectat,
|
|
ROUND(NVL(i.incasari_30, 0), 0) AS incasari,
|
|
ROUND(NVL(p.plati_30, 0), 0) AS plati,
|
|
ROUND(NVL(i.incasari_30, 0) - NVL(p.plati_30, 0), 0) AS flux_net,
|
|
CASE
|
|
WHEN NVL(c.cash_total, 0) + NVL(i.incasari_30, 0) - NVL(p.plati_30, 0) < 0 THEN 'ALERTA'
|
|
WHEN NVL(c.cash_total, 0) + NVL(i.incasari_30, 0) - NVL(p.plati_30, 0) < NVL(c.cash_total, 0) * 0.2 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status
|
|
FROM cash_curent c, incasari_programate i, plati_programate p
|
|
UNION ALL
|
|
SELECT
|
|
'Proiectie 60 zile' AS perioada,
|
|
ROUND(NVL(c.cash_total, 0) + NVL(i.incasari_30, 0) + NVL(i.incasari_31_60, 0) - NVL(p.plati_30, 0) - NVL(p.plati_31_60, 0), 0) AS sold_proiectat,
|
|
ROUND(NVL(i.incasari_31_60, 0), 0) AS incasari,
|
|
ROUND(NVL(p.plati_31_60, 0), 0) AS plati,
|
|
ROUND(NVL(i.incasari_31_60, 0) - NVL(p.plati_31_60, 0), 0) AS flux_net,
|
|
CASE
|
|
WHEN NVL(c.cash_total, 0) + NVL(i.incasari_30, 0) + NVL(i.incasari_31_60, 0) - NVL(p.plati_30, 0) - NVL(p.plati_31_60, 0) < 0 THEN 'ALERTA'
|
|
ELSE 'OK'
|
|
END AS status
|
|
FROM cash_curent c, incasari_programate i, plati_programate p
|
|
UNION ALL
|
|
SELECT
|
|
'Proiectie 90 zile' AS perioada,
|
|
ROUND(NVL(c.cash_total, 0) + NVL(i.incasari_30, 0) + NVL(i.incasari_31_60, 0) + NVL(i.incasari_61_90, 0) - NVL(p.plati_30, 0) - NVL(p.plati_31_60, 0) - NVL(p.plati_61_90, 0), 0) AS sold_proiectat,
|
|
ROUND(NVL(i.incasari_61_90, 0), 0) AS incasari,
|
|
ROUND(NVL(p.plati_61_90, 0), 0) AS plati,
|
|
ROUND(NVL(i.incasari_61_90, 0) - NVL(p.plati_61_90, 0), 0) AS flux_net,
|
|
CASE
|
|
WHEN NVL(c.cash_total, 0) + NVL(i.incasari_30, 0) + NVL(i.incasari_31_60, 0) + NVL(i.incasari_61_90, 0) - NVL(p.plati_30, 0) - NVL(p.plati_31_60, 0) - NVL(p.plati_61_90, 0) < 0 THEN 'ALERTA'
|
|
ELSE 'OK'
|
|
END AS status
|
|
FROM cash_curent c, incasari_programate i, plati_programate p
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 39. SUMAR EXECUTIV YoY (cu comparatie an anterior)
|
|
# =============================================================================
|
|
# OPTIMIZED: Single 24-month scan with CASE-based period partitioning instead of 2 separate view scans
|
|
SUMAR_EXECUTIV_YOY = """
|
|
WITH base_data AS (
|
|
SELECT
|
|
f.id_vanzare,
|
|
f.id_part,
|
|
CASE WHEN f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12) THEN 'CURENT' ELSE 'ANTERIOR' END AS perioada,
|
|
d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END AS vanzare,
|
|
d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie) AS marja
|
|
FROM VANZARI f
|
|
JOIN VANZARI_DETALII d ON d.id_vanzare = f.id_vanzare
|
|
WHERE f.sters = 0 AND d.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
),
|
|
aggregated AS (
|
|
SELECT
|
|
SUM(CASE WHEN perioada = 'CURENT' THEN vanzare ELSE 0 END) AS vanzari_curente,
|
|
SUM(CASE WHEN perioada = 'ANTERIOR' THEN vanzare ELSE 0 END) AS vanzari_anterioare,
|
|
SUM(CASE WHEN perioada = 'CURENT' THEN marja ELSE 0 END) AS marja_curenta,
|
|
SUM(CASE WHEN perioada = 'ANTERIOR' THEN marja ELSE 0 END) AS marja_anterioara,
|
|
COUNT(DISTINCT CASE WHEN perioada = 'CURENT' THEN id_vanzare END) AS facturi_curente,
|
|
COUNT(DISTINCT CASE WHEN perioada = 'ANTERIOR' THEN id_vanzare END) AS facturi_anterioare,
|
|
COUNT(DISTINCT CASE WHEN perioada = 'CURENT' THEN id_part END) AS clienti_curenti,
|
|
COUNT(DISTINCT CASE WHEN perioada = 'ANTERIOR' THEN id_part END) AS clienti_anteriori
|
|
FROM base_data
|
|
)
|
|
SELECT
|
|
'Vanzari totale (RON)' AS indicator,
|
|
ROUND(vanzari_curente, 0) AS valoare_curenta,
|
|
ROUND(vanzari_anterioare, 0) AS valoare_anterioara,
|
|
ROUND(vanzari_curente - vanzari_anterioare, 0) AS variatie_absoluta,
|
|
ROUND((vanzari_curente - vanzari_anterioare) * 100 / NULLIF(vanzari_anterioare, 0), 2) AS variatie_procent,
|
|
CASE
|
|
WHEN vanzari_curente > vanzari_anterioare * 1.05 THEN 'CRESTERE'
|
|
WHEN vanzari_curente < vanzari_anterioare * 0.95 THEN 'SCADERE'
|
|
ELSE 'STABIL'
|
|
END AS trend
|
|
FROM aggregated
|
|
UNION ALL
|
|
SELECT
|
|
'Marja bruta (RON)' AS indicator,
|
|
ROUND(marja_curenta, 0) AS valoare_curenta,
|
|
ROUND(marja_anterioara, 0) AS valoare_anterioara,
|
|
ROUND(marja_curenta - marja_anterioara, 0) AS variatie_absoluta,
|
|
ROUND((marja_curenta - marja_anterioara) * 100 / NULLIF(marja_anterioara, 0), 2) AS variatie_procent,
|
|
CASE
|
|
WHEN marja_curenta > marja_anterioara * 1.05 THEN 'CRESTERE'
|
|
WHEN marja_curenta < marja_anterioara * 0.95 THEN 'SCADERE'
|
|
ELSE 'STABIL'
|
|
END AS trend
|
|
FROM aggregated
|
|
UNION ALL
|
|
SELECT
|
|
'Procent marja (%)' AS indicator,
|
|
ROUND(marja_curenta * 100 / NULLIF(vanzari_curente, 0), 2) AS valoare_curenta,
|
|
ROUND(marja_anterioara * 100 / NULLIF(vanzari_anterioare, 0), 2) AS valoare_anterioara,
|
|
ROUND(marja_curenta * 100 / NULLIF(vanzari_curente, 0) - marja_anterioara * 100 / NULLIF(vanzari_anterioare, 0), 2) AS variatie_absoluta,
|
|
NULL AS variatie_procent,
|
|
CASE
|
|
WHEN marja_curenta * 100 / NULLIF(vanzari_curente, 0) > marja_anterioara * 100 / NULLIF(vanzari_anterioare, 0) + 1 THEN 'CRESTERE'
|
|
WHEN marja_curenta * 100 / NULLIF(vanzari_curente, 0) < marja_anterioara * 100 / NULLIF(vanzari_anterioare, 0) - 1 THEN 'SCADERE'
|
|
ELSE 'STABIL'
|
|
END AS trend
|
|
FROM aggregated
|
|
UNION ALL
|
|
SELECT
|
|
'Numar facturi' AS indicator,
|
|
facturi_curente AS valoare_curenta,
|
|
facturi_anterioare AS valoare_anterioara,
|
|
facturi_curente - facturi_anterioare AS variatie_absoluta,
|
|
ROUND((facturi_curente - facturi_anterioare) * 100 / NULLIF(facturi_anterioare, 0), 2) AS variatie_procent,
|
|
CASE
|
|
WHEN facturi_curente > facturi_anterioare * 1.05 THEN 'CRESTERE'
|
|
WHEN facturi_curente < facturi_anterioare * 0.95 THEN 'SCADERE'
|
|
ELSE 'STABIL'
|
|
END AS trend
|
|
FROM aggregated
|
|
UNION ALL
|
|
SELECT
|
|
'Numar clienti activi' AS indicator,
|
|
clienti_curenti AS valoare_curenta,
|
|
clienti_anteriori AS valoare_anterioara,
|
|
clienti_curenti - clienti_anteriori AS variatie_absoluta,
|
|
ROUND((clienti_curenti - clienti_anteriori) * 100 / NULLIF(clienti_anteriori, 0), 2) AS variatie_procent,
|
|
CASE
|
|
WHEN clienti_curenti > clienti_anteriori THEN 'CRESTERE'
|
|
WHEN clienti_curenti < clienti_anteriori THEN 'SCADERE'
|
|
ELSE 'STABIL'
|
|
END AS trend
|
|
FROM aggregated
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 40. DSO DPO YoY (comparatie an anterior)
|
|
# =============================================================================
|
|
DSO_DPO_YOY = """
|
|
WITH
|
|
-- Metrici curente
|
|
vanzari_curente AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS total_vanzari
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
),
|
|
sold_clienti_curent AS (
|
|
SELECT SUM(CASE WHEN b.solddeb > b.soldcred THEN b.solddeb - b.soldcred ELSE 0 END) AS total_creante
|
|
FROM vbalanta_parteneri b
|
|
WHERE b.cont LIKE '4111%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
achizitii_curente AS (
|
|
SELECT SUM(ABS(r.cant * r.pret)) AS total_achizitii
|
|
FROM vrul r
|
|
WHERE r.id_tip_rulaj = 1 AND r.cant > 0
|
|
AND r.dataact >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
),
|
|
sold_furnizori_curent AS (
|
|
SELECT SUM(CASE WHEN b.soldcred > b.solddeb THEN b.soldcred - b.solddeb ELSE 0 END) AS total_datorii
|
|
FROM vbalanta_parteneri b
|
|
WHERE b.cont LIKE '401%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE)
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
-- Metrici anterioare (aproximare - vanzari an anterior)
|
|
vanzari_anterioare AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS total_vanzari
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
AND f.data_act < ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
),
|
|
achizitii_anterioare AS (
|
|
SELECT SUM(ABS(r.cant * r.pret)) AS total_achizitii
|
|
FROM vrul r
|
|
WHERE r.id_tip_rulaj = 1 AND r.cant > 0
|
|
AND r.dataact >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
AND r.dataact < ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
),
|
|
-- Solduri anterioare (aproximare - luna curenta anul trecut)
|
|
sold_clienti_anterior AS (
|
|
SELECT SUM(CASE WHEN b.solddeb > b.soldcred THEN b.solddeb - b.soldcred ELSE 0 END) AS total_creante
|
|
FROM vbalanta_parteneri b
|
|
WHERE b.cont LIKE '4111%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE) - 1
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
),
|
|
sold_furnizori_anterior AS (
|
|
SELECT SUM(CASE WHEN b.soldcred > b.solddeb THEN b.soldcred - b.solddeb ELSE 0 END) AS total_datorii
|
|
FROM vbalanta_parteneri b
|
|
WHERE b.cont LIKE '401%'
|
|
AND b.an = EXTRACT(YEAR FROM SYSDATE) - 1
|
|
AND b.luna = EXTRACT(MONTH FROM SYSDATE)
|
|
)
|
|
SELECT
|
|
'DSO (Zile incasare)' AS indicator,
|
|
ROUND(NVL(scc.total_creante, 0) * 365 / NULLIF(vc.total_vanzari, 0), 0) AS valoare_curenta,
|
|
ROUND(NVL(sca.total_creante, 0) * 365 / NULLIF(va.total_vanzari, 0), 0) AS valoare_anterioara,
|
|
ROUND(NVL(scc.total_creante, 0) * 365 / NULLIF(vc.total_vanzari, 0) - NVL(sca.total_creante, 0) * 365 / NULLIF(va.total_vanzari, 0), 0) AS variatie_zile,
|
|
CASE
|
|
WHEN NVL(scc.total_creante, 0) * 365 / NULLIF(vc.total_vanzari, 0) < NVL(sca.total_creante, 0) * 365 / NULLIF(va.total_vanzari, 0) THEN 'IMBUNATATIRE'
|
|
WHEN NVL(scc.total_creante, 0) * 365 / NULLIF(vc.total_vanzari, 0) > NVL(sca.total_creante, 0) * 365 / NULLIF(va.total_vanzari, 0) + 5 THEN 'DETERIORARE'
|
|
ELSE 'STABIL'
|
|
END AS trend,
|
|
CASE
|
|
WHEN NVL(scc.total_creante, 0) * 365 / NULLIF(vc.total_vanzari, 0) > 60 THEN 'ALERTA'
|
|
WHEN NVL(scc.total_creante, 0) * 365 / NULLIF(vc.total_vanzari, 0) > 45 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status
|
|
FROM vanzari_curente vc, sold_clienti_curent scc, vanzari_anterioare va, sold_clienti_anterior sca
|
|
UNION ALL
|
|
SELECT
|
|
'DPO (Zile plata)' AS indicator,
|
|
ROUND(NVL(sfc.total_datorii, 0) * 365 / NULLIF(ac.total_achizitii, 0), 0) AS valoare_curenta,
|
|
ROUND(NVL(sfa.total_datorii, 0) * 365 / NULLIF(aa.total_achizitii, 0), 0) AS valoare_anterioara,
|
|
ROUND(NVL(sfc.total_datorii, 0) * 365 / NULLIF(ac.total_achizitii, 0) - NVL(sfa.total_datorii, 0) * 365 / NULLIF(aa.total_achizitii, 0), 0) AS variatie_zile,
|
|
CASE
|
|
WHEN NVL(sfc.total_datorii, 0) * 365 / NULLIF(ac.total_achizitii, 0) > NVL(sfa.total_datorii, 0) * 365 / NULLIF(aa.total_achizitii, 0) THEN 'IMBUNATATIRE'
|
|
WHEN NVL(sfc.total_datorii, 0) * 365 / NULLIF(ac.total_achizitii, 0) < NVL(sfa.total_datorii, 0) * 365 / NULLIF(aa.total_achizitii, 0) - 5 THEN 'DETERIORARE'
|
|
ELSE 'STABIL'
|
|
END AS trend,
|
|
CASE
|
|
WHEN NVL(sfc.total_datorii, 0) * 365 / NULLIF(ac.total_achizitii, 0) < 15 THEN 'ATENTIE'
|
|
ELSE 'OK'
|
|
END AS status
|
|
FROM achizitii_curente ac, sold_furnizori_curent sfc, achizitii_anterioare aa, sold_furnizori_anterior sfa
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 41. CONCENTRARE RISC YoY (comparatie an anterior)
|
|
# =============================================================================
|
|
CONCENTRARE_RISC_YOY = """
|
|
WITH
|
|
-- Single scan for current year: compute total + per-client with ranking
|
|
vanzari_curent AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
f.id_part,
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS vanzari
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
GROUP BY f.id_part
|
|
),
|
|
ranked_curent AS (
|
|
SELECT vanzari, ROW_NUMBER() OVER (ORDER BY vanzari DESC) AS rn
|
|
FROM vanzari_curent
|
|
),
|
|
metrics_curent AS (
|
|
SELECT
|
|
SUM(vanzari) AS total,
|
|
SUM(CASE WHEN rn <= 1 THEN vanzari ELSE 0 END) AS top1,
|
|
SUM(CASE WHEN rn <= 5 THEN vanzari ELSE 0 END) AS top5,
|
|
SUM(CASE WHEN rn <= 10 THEN vanzari ELSE 0 END) AS top10
|
|
FROM ranked_curent
|
|
),
|
|
-- Single scan for previous year
|
|
vanzari_anterior AS (
|
|
SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */
|
|
f.id_part,
|
|
SUM(d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END) AS vanzari
|
|
FROM vanzari f
|
|
JOIN vanzari_detalii d ON d.id_vanzare = f.id_vanzare AND d.sters = 0
|
|
WHERE f.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
AND f.data_act < ADD_MONTHS(TRUNC(SYSDATE), -12)
|
|
GROUP BY f.id_part
|
|
),
|
|
ranked_anterior AS (
|
|
SELECT vanzari, ROW_NUMBER() OVER (ORDER BY vanzari DESC) AS rn
|
|
FROM vanzari_anterior
|
|
),
|
|
-- Raw metrics for anterior (may have NULL if no data)
|
|
metrics_anterior_raw AS (
|
|
SELECT
|
|
SUM(vanzari) AS total,
|
|
SUM(CASE WHEN rn <= 1 THEN vanzari ELSE 0 END) AS top1,
|
|
SUM(CASE WHEN rn <= 5 THEN vanzari ELSE 0 END) AS top5,
|
|
SUM(CASE WHEN rn <= 10 THEN vanzari ELSE 0 END) AS top10
|
|
FROM ranked_anterior
|
|
),
|
|
-- Fallback to 0 for NULL values (when no anterior data exists)
|
|
metrics_anterior AS (
|
|
SELECT
|
|
NVL(total, 0) AS total,
|
|
NVL(top1, 0) AS top1,
|
|
NVL(top5, 0) AS top5,
|
|
NVL(top10, 0) AS top10
|
|
FROM metrics_anterior_raw
|
|
),
|
|
-- Final metrics: just 1 row each, no cartesian product
|
|
combined AS (
|
|
SELECT
|
|
ROUND(mc.top1 * 100.0 / NULLIF(mc.total, 0), 2) AS pct_curent_1,
|
|
CASE WHEN ma.total = 0 THEN NULL ELSE ROUND(ma.top1 * 100.0 / ma.total, 2) END AS pct_anterior_1,
|
|
ROUND(mc.top5 * 100.0 / NULLIF(mc.total, 0), 2) AS pct_curent_5,
|
|
CASE WHEN ma.total = 0 THEN NULL ELSE ROUND(ma.top5 * 100.0 / ma.total, 2) END AS pct_anterior_5,
|
|
ROUND(mc.top10 * 100.0 / NULLIF(mc.total, 0), 2) AS pct_curent_10,
|
|
CASE WHEN ma.total = 0 THEN NULL ELSE ROUND(ma.top10 * 100.0 / ma.total, 2) END AS pct_anterior_10,
|
|
CASE WHEN ma.total > 0 THEN 1 ELSE 0 END AS has_anterior
|
|
FROM metrics_curent mc
|
|
CROSS JOIN metrics_anterior ma
|
|
)
|
|
SELECT
|
|
'Top 1 client' AS indicator,
|
|
pct_curent_1 AS procent_curent,
|
|
pct_anterior_1 AS procent_anterior,
|
|
CASE WHEN has_anterior = 1 THEN ROUND(pct_curent_1 - pct_anterior_1, 2) ELSE NULL END AS variatie,
|
|
CASE
|
|
WHEN has_anterior = 0 THEN 'FARA DATE YOY'
|
|
WHEN pct_curent_1 < pct_anterior_1 THEN 'DIVERSIFICARE'
|
|
WHEN pct_curent_1 > pct_anterior_1 + 5 THEN 'CONCENTRARE'
|
|
ELSE 'STABIL'
|
|
END AS trend
|
|
FROM combined
|
|
UNION ALL
|
|
SELECT
|
|
'Top 5 clienti' AS indicator,
|
|
pct_curent_5 AS procent_curent,
|
|
pct_anterior_5 AS procent_anterior,
|
|
CASE WHEN has_anterior = 1 THEN ROUND(pct_curent_5 - pct_anterior_5, 2) ELSE NULL END AS variatie,
|
|
CASE
|
|
WHEN has_anterior = 0 THEN 'FARA DATE YOY'
|
|
WHEN pct_curent_5 < pct_anterior_5 THEN 'DIVERSIFICARE'
|
|
WHEN pct_curent_5 > pct_anterior_5 + 5 THEN 'CONCENTRARE'
|
|
ELSE 'STABIL'
|
|
END AS trend
|
|
FROM combined
|
|
UNION ALL
|
|
SELECT
|
|
'Top 10 clienti' AS indicator,
|
|
pct_curent_10 AS procent_curent,
|
|
pct_anterior_10 AS procent_anterior,
|
|
CASE WHEN has_anterior = 1 THEN ROUND(pct_curent_10 - pct_anterior_10, 2) ELSE NULL END AS variatie,
|
|
CASE
|
|
WHEN has_anterior = 0 THEN 'FARA DATE YOY'
|
|
WHEN pct_curent_10 < pct_anterior_10 THEN 'DIVERSIFICARE'
|
|
WHEN pct_curent_10 > pct_anterior_10 + 5 THEN 'CONCENTRARE'
|
|
ELSE 'STABIL'
|
|
END AS trend
|
|
FROM combined
|
|
"""
|
|
|
|
# =============================================================================
|
|
# 42. INDICATORI AGREGATI VENITURI YoY
|
|
# =============================================================================
|
|
# OPTIMIZED: Single 24-month scan with CASE-based period partitioning, no FULL OUTER JOIN needed
|
|
INDICATORI_AGREGATI_VENITURI_YOY = """
|
|
WITH base_data AS (
|
|
SELECT
|
|
CASE
|
|
WHEN d.cont IN ('341', '345') THEN 'Productie proprie'
|
|
WHEN d.cont = '301' THEN 'Materii prime'
|
|
ELSE 'Marfa revanduta'
|
|
END AS linie_business,
|
|
CASE WHEN f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -12) THEN 'CURENT' ELSE 'ANTERIOR' END AS perioada,
|
|
d.cantitate * CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END AS vanzare,
|
|
d.cantitate * (CASE WHEN d.pret_cu_tva = 1 THEN d.pret / (1 + d.proc_tvav/100) ELSE d.pret END - d.pret_achizitie) AS marja
|
|
FROM VANZARI f
|
|
JOIN VANZARI_DETALII d ON d.id_vanzare = f.id_vanzare
|
|
WHERE f.sters = 0 AND d.sters = 0
|
|
AND f.tip > 0 AND f.tip NOT IN (7, 8, 9, 24)
|
|
AND f.data_act >= ADD_MONTHS(TRUNC(SYSDATE), -24)
|
|
)
|
|
SELECT
|
|
linie_business,
|
|
ROUND(SUM(CASE WHEN perioada = 'CURENT' THEN vanzare ELSE 0 END), 0) AS vanzari_curente,
|
|
ROUND(SUM(CASE WHEN perioada = 'ANTERIOR' THEN vanzare ELSE 0 END), 0) AS vanzari_anterioare,
|
|
ROUND(SUM(CASE WHEN perioada = 'CURENT' THEN vanzare ELSE 0 END) - SUM(CASE WHEN perioada = 'ANTERIOR' THEN vanzare ELSE 0 END), 0) AS variatie_vanzari,
|
|
ROUND((SUM(CASE WHEN perioada = 'CURENT' THEN vanzare ELSE 0 END) - SUM(CASE WHEN perioada = 'ANTERIOR' THEN vanzare ELSE 0 END)) * 100 / NULLIF(SUM(CASE WHEN perioada = 'ANTERIOR' THEN vanzare ELSE 0 END), 0), 2) AS variatie_procent,
|
|
ROUND(SUM(CASE WHEN perioada = 'CURENT' THEN marja ELSE 0 END) * 100 / NULLIF(SUM(CASE WHEN perioada = 'CURENT' THEN vanzare ELSE 0 END), 0), 2) AS marja_curenta_pct,
|
|
ROUND(SUM(CASE WHEN perioada = 'ANTERIOR' THEN marja ELSE 0 END) * 100 / NULLIF(SUM(CASE WHEN perioada = 'ANTERIOR' THEN vanzare ELSE 0 END), 0), 2) AS marja_anterioara_pct,
|
|
CASE
|
|
WHEN SUM(CASE WHEN perioada = 'CURENT' THEN vanzare ELSE 0 END) > SUM(CASE WHEN perioada = 'ANTERIOR' THEN vanzare ELSE 0 END) * 1.05 THEN 'CRESTERE'
|
|
WHEN SUM(CASE WHEN perioada = 'CURENT' THEN vanzare ELSE 0 END) < SUM(CASE WHEN perioada = 'ANTERIOR' THEN vanzare ELSE 0 END) * 0.95 THEN 'SCADERE'
|
|
ELSE 'STABIL'
|
|
END AS trend
|
|
FROM base_data
|
|
GROUP BY linie_business
|
|
ORDER BY SUM(CASE WHEN perioada = 'CURENT' THEN vanzare ELSE 0 END) DESC
|
|
"""
|
|
|
|
# Dictionary mapping query names to queries and their parameters
|
|
QUERIES = {
|
|
'sumar_executiv': {
|
|
'sql': SUMAR_EXECUTIV,
|
|
'params': {},
|
|
'title': 'Sumar Executiv - KPIs',
|
|
'description': 'Indicatori cheie de performanță pentru ultimele 12 luni'
|
|
},
|
|
'marja_per_client': {
|
|
'sql': MARJA_PER_CLIENT,
|
|
'params': {'months': 12},
|
|
'title': 'Marja per Client',
|
|
'description': 'Analiza profitabilității per client'
|
|
},
|
|
'clienti_marja_mica': {
|
|
'sql': CLIENTI_MARJA_MICA,
|
|
'params': {'months': 12, 'min_sales': 5000, 'margin_threshold': 15},
|
|
'title': '⚠️ ALERTĂ: Clienți cu Marjă Mică',
|
|
'description': 'Clienți cu marjă sub 15% și vânzări peste 5000 RON'
|
|
},
|
|
'vanzari_sub_cost': {
|
|
'sql': VANZARI_SUB_COST,
|
|
'params': {'months': 12},
|
|
'title': '🚨 ALERTĂ CRITICĂ: Vânzări sub Cost',
|
|
'description': 'Produse vândute sub prețul de achiziție'
|
|
},
|
|
'marja_per_categorie': {
|
|
'sql': MARJA_PER_CATEGORIE,
|
|
'params': {'months': 12},
|
|
'title': 'Marja per Categorie',
|
|
'description': 'Profitabilitate per grupă și subgrupă de produse'
|
|
},
|
|
'productie_vs_revanzare': {
|
|
'sql': PRODUCTIE_VS_REVANZARE,
|
|
'params': {'months': 12},
|
|
'title': 'Producție Proprie vs Revânzare',
|
|
'description': 'Comparație marjă: producție proprie vs marfă cumpărată'
|
|
},
|
|
'top_produse': {
|
|
'sql': TOP_PRODUSE,
|
|
'params': {'months': 12},
|
|
'title': 'Top 50 Produse',
|
|
'description': 'Cele mai vândute produse după valoare'
|
|
},
|
|
'marja_per_gestiune': {
|
|
'sql': MARJA_PER_GESTIUNE,
|
|
'params': {'months': 12},
|
|
'title': 'Marja per Gestiune',
|
|
'description': 'Profitabilitate per gestiune/depozit (doar articole gestionabile)'
|
|
},
|
|
'articole_negestionabile': {
|
|
'sql': ARTICOLE_NEGESTIONABILE,
|
|
'params': {'months': 12},
|
|
'title': 'Articole Negestionabile',
|
|
'description': 'Vânzări articole care nu se țin pe stoc (servicii, etc.)'
|
|
},
|
|
'dispersie_preturi': {
|
|
'sql': DISPERSIE_PRETURI,
|
|
'params': {'months': 12},
|
|
'title': 'Dispersia Prețurilor',
|
|
'description': 'Produse vândute la prețuri foarte diferite între clienți'
|
|
},
|
|
'clienti_sub_medie': {
|
|
'sql': CLIENTI_SUB_MEDIE,
|
|
'params': {'months': 12},
|
|
'title': 'Clienți cu Prețuri sub Medie',
|
|
'description': 'Clienți care cumpără cu >15% sub prețul mediu'
|
|
},
|
|
'trending_clienti': {
|
|
'sql': TRENDING_CLIENTI,
|
|
'params': {},
|
|
'title': 'Trending Clienți YoY',
|
|
'description': 'Evoluția vânzărilor per client: an curent vs an trecut'
|
|
},
|
|
'concentrare_clienti': {
|
|
'sql': CONCENTRARE_CLIENTI,
|
|
'params': {'months': 12},
|
|
'title': 'Concentrare Clienți (Top 30)',
|
|
'description': 'Dependența de clienții mari (top 30 + restul)'
|
|
},
|
|
'vanzari_lunare': {
|
|
'sql': VANZARI_LUNARE,
|
|
'params': {},
|
|
'title': 'Vânzări Lunare (24 luni)',
|
|
'description': 'Evoluția vânzărilor și marjei pe luni'
|
|
},
|
|
'stoc_curent': {
|
|
'sql': STOC_CURENT,
|
|
'params': {},
|
|
'title': 'Stoc Curent per Gestiune',
|
|
'description': 'Valoarea stocului actual'
|
|
},
|
|
'stoc_lent': {
|
|
'sql': STOC_LENT,
|
|
'params': {},
|
|
'title': '⚠️ Stoc Lent (>90 zile)',
|
|
'description': 'Produse fără mișcare de peste 90 de zile'
|
|
},
|
|
'rotatie_stocuri': {
|
|
'sql': ROTATIE_STOCURI,
|
|
'params': {},
|
|
'title': 'Rotație Stocuri',
|
|
'description': 'Viteza de rotație a stocurilor'
|
|
},
|
|
'analiza_prajitorie': {
|
|
'sql': ANALIZA_PRAJITORIE,
|
|
'params': {'months': 12},
|
|
'title': 'Analiză Prăjitorie',
|
|
'description': 'Fluxul materiilor prime și producției'
|
|
},
|
|
# =========================================================================
|
|
# NEW: Financial Queries
|
|
# =========================================================================
|
|
'solduri_clienti': {
|
|
'sql': SOLDURI_CLIENTI,
|
|
'params': {},
|
|
'title': 'Solduri Clienți (Creanțe)',
|
|
'description': 'Creanțe din cont 4111 - bani de încasat de la clienți'
|
|
},
|
|
'solduri_furnizori': {
|
|
'sql': SOLDURI_FURNIZORI,
|
|
'params': {},
|
|
'title': 'Solduri Furnizori (Datorii)',
|
|
'description': 'Datorii din cont 401 - bani de plătit către furnizori'
|
|
},
|
|
'aging_creante': {
|
|
'sql': AGING_CREANTE,
|
|
'params': {},
|
|
'title': 'Aging Creanțe',
|
|
'description': 'Vechimea creanțelor pe intervale: <30, 31-60, 61-90, >90 zile'
|
|
},
|
|
'facturi_restante': {
|
|
'sql': FACTURI_RESTANTE,
|
|
'params': {},
|
|
'title': '⚠️ Facturi Restante Clienți',
|
|
'description': 'Facturi clienți depășite ca scadență - necesită urmărire'
|
|
},
|
|
'aging_datorii': {
|
|
'sql': AGING_DATORII,
|
|
'params': {},
|
|
'title': 'Aging Datorii Furnizori',
|
|
'description': 'Vechimea datoriilor către furnizori pe intervale: <30, 31-60, 61-90, >90 zile'
|
|
},
|
|
'facturi_restante_furnizori': {
|
|
'sql': FACTURI_RESTANTE_FURNIZORI,
|
|
'params': {},
|
|
'title': '⚠️ Facturi Restante Furnizori',
|
|
'description': 'Facturi furnizori depășite ca scadență - de plătit urgent'
|
|
},
|
|
'dso_dpo': {
|
|
'sql': DSO_DPO,
|
|
'params': {},
|
|
'title': 'DSO / DPO',
|
|
'description': 'Zile medii încasare clienți (DSO) și plată furnizori (DPO)'
|
|
},
|
|
'pozitia_cash': {
|
|
'sql': POZITIA_CASH,
|
|
'params': {},
|
|
'title': 'Poziția Cash',
|
|
'description': 'Disponibilități în bancă și casă'
|
|
},
|
|
'ciclu_conversie_cash': {
|
|
'sql': CICLU_CONVERSIE_CASH,
|
|
'params': {},
|
|
'title': 'Ciclu Conversie Cash',
|
|
'description': 'CCC = DIO + DSO - DPO (zile de la plată furnizor la încasare client)'
|
|
},
|
|
# =========================================================================
|
|
# NEW: Aggregated Indicators
|
|
# =========================================================================
|
|
'indicatori_agregati_venituri': {
|
|
'sql': INDICATORI_AGREGATI_VENITURI,
|
|
'params': {'months': 12},
|
|
'title': 'Indicatori Agregați Venituri',
|
|
'description': 'Revenue mix per linie de business cu contribuție la profit'
|
|
},
|
|
'sezonalitate_lunara': {
|
|
'sql': SEZONALITATE_LUNARA,
|
|
'params': {},
|
|
'title': 'Sezonalitate Lunară',
|
|
'description': 'Analiza sezonalității pe 24 luni istoric'
|
|
},
|
|
'portofoliu_clienti': {
|
|
'sql': PORTOFOLIU_CLIENTI,
|
|
'params': {},
|
|
'title': 'Portofoliu Clienți',
|
|
'description': 'Sănătatea portofoliului: activi, noi, pierduți, inactivi'
|
|
},
|
|
'frecventa_clienti': {
|
|
'sql': FRECVENTA_CLIENTI,
|
|
'params': {},
|
|
'title': 'Frecvența Clienți',
|
|
'description': 'Frecvența comenzilor și evoluție YoY'
|
|
},
|
|
'concentrare_risc': {
|
|
'sql': CONCENTRARE_RISC,
|
|
'params': {'months': 12},
|
|
'title': 'Concentrare Risc',
|
|
'description': 'Risc concentrare: Top 1/5/10 clienți ca % din total'
|
|
},
|
|
# =========================================================================
|
|
# NEW: Improved Margin Analysis
|
|
# =========================================================================
|
|
'clienti_ranking_profit': {
|
|
'sql': CLIENTI_RANKING_PROFIT,
|
|
'params': {'months': 12},
|
|
'title': 'Clienți Ranking Profit',
|
|
'description': 'Ranking clienți după PROFIT (nu venituri)'
|
|
},
|
|
'marja_client_categorie': {
|
|
'sql': MARJA_CLIENT_CATEGORIE,
|
|
'params': {'months': 12},
|
|
'title': 'Marjă Client/Categorie',
|
|
'description': 'Marjă per categorie PER CLIENT (același client poate fi profitabil/neprofitabil pe categorii diferite)'
|
|
},
|
|
'evolutie_discount': {
|
|
'sql': EVOLUTIE_DISCOUNT,
|
|
'params': {},
|
|
'title': 'Evoluție Discount',
|
|
'description': 'Discount creep - evoluția prețului în timp (alerte scăderi)'
|
|
},
|
|
# =========================================================================
|
|
# NEW: Indicatori Generali și Lichiditate (PLAN_INDICATORI_LICHIDITATE_YOY)
|
|
# =========================================================================
|
|
'indicatori_generali': {
|
|
'sql': INDICATORI_GENERALI,
|
|
'params': {},
|
|
'title': 'Indicatori Generali de Business',
|
|
'description': 'Grad îndatorare, autonomie financiară, ROA, marjă netă'
|
|
},
|
|
'indicatori_lichiditate': {
|
|
'sql': INDICATORI_LICHIDITATE,
|
|
'params': {},
|
|
'title': 'Indicatori de Lichiditate',
|
|
'description': 'Lichiditate curentă, rapidă, cash ratio, fond de rulment'
|
|
},
|
|
'clasificare_datorii': {
|
|
'sql': CLASIFICARE_DATORII,
|
|
'params': {},
|
|
'title': 'Clasificare Datorii pe Termene',
|
|
'description': 'Datorii termen scurt (<30z), mediu (31-90z), lung (>90z)'
|
|
},
|
|
'grad_acoperire_datorii': {
|
|
'sql': GRAD_ACOPERIRE_DATORII,
|
|
'params': {},
|
|
'title': 'Grad Acoperire Datorii',
|
|
'description': 'Cash + încasări așteptate vs datorii scadente, necesar finanțare'
|
|
},
|
|
'proiectie_lichiditate': {
|
|
'sql': PROIECTIE_LICHIDITATE,
|
|
'params': {},
|
|
'title': 'Proiecție Lichiditate 30/60/90 zile',
|
|
'description': 'Sold cash proiectat pe orizonturi de 30, 60 și 90 zile'
|
|
},
|
|
# =========================================================================
|
|
# NEW: Comparații YoY
|
|
# =========================================================================
|
|
'sumar_executiv_yoy': {
|
|
'sql': SUMAR_EXECUTIV_YOY,
|
|
'params': {},
|
|
'title': 'Sumar Executiv YoY',
|
|
'description': 'KPI-uri cu comparație an curent vs an anterior'
|
|
},
|
|
'dso_dpo_yoy': {
|
|
'sql': DSO_DPO_YOY,
|
|
'params': {},
|
|
'title': 'DSO/DPO YoY',
|
|
'description': 'Evoluție zile încasare/plată vs an anterior'
|
|
},
|
|
'concentrare_risc_yoy': {
|
|
'sql': CONCENTRARE_RISC_YOY,
|
|
'params': {},
|
|
'title': 'Concentrare Risc YoY',
|
|
'description': 'Evoluție concentrare Top 1/5/10 clienți vs an anterior'
|
|
},
|
|
'indicatori_agregati_venituri_yoy': {
|
|
'sql': INDICATORI_AGREGATI_VENITURI_YOY,
|
|
'params': {},
|
|
'title': 'Indicatori Agregați Venituri YoY',
|
|
'description': 'Linii de business comparate cu anul anterior'
|
|
},
|
|
}
|