From 85423cfe9402cd70722c2f4d5b4cc3f49e7e8d92 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Mon, 16 Feb 2026 14:12:03 +0200 Subject: [PATCH] perioada luna anterioara finalizata --- .env.example | 4 + CLAUDE.md | 30 ++++- config.py | 3 + main.py | 74 +++++++++-- queries.py | 345 ++++++++++++++++++++++++++++++--------------------- 5 files changed, 299 insertions(+), 157 deletions(-) diff --git a/.env.example b/.env.example index 9d1df4f..c1a145b 100644 --- a/.env.example +++ b/.env.example @@ -13,3 +13,7 @@ ORACLE_PASSWORD=PAROLA # Output settings OUTPUT_DIR=./output COMPANY_NAME=Data Intelligence Report + +# Reporting period end month (optional, default: previous complete month) +# Format: YYYY-MM. Example: 2026-01 means "report through January 2026" +# REPORT_END_MONTH=2026-01 diff --git a/CLAUDE.md b/CLAUDE.md index 01f1299..e748f68 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -14,16 +14,42 @@ python -m venv .venv source .venv/bin/activate # Linux/WSL pip install -r requirements.txt -# Run report (default: last 12 months) +# Run report (default: last 12 months, previous complete month) python main.py -# Custom period +# Custom period duration python main.py --months 6 +# Custom end month (report through January 2026) +python main.py --end-month 2026-01 + +# Combined: 6 months through December 2025 +python main.py --months 6 --end-month 2025-12 + # Docker alternative docker-compose run --rm report-generator ``` +## Configurable Reporting Period + +**Default behavior**: Reports cover data through the **last complete month** (excludes current incomplete month). +- Example: If today is 2026-02-16, default reports data through 2026-01-31 + +**Override with CLI**: +```bash +python main.py --end-month 2026-01 # Report through January 2026 +``` + +**Override with environment variable**: +```bash +export REPORT_END_MONTH=2026-01 +python main.py +``` + +**Internals**: All SQL queries receive `:data_referinta` as an Oracle DATE bind variable (= first day of month AFTER end-month). +- Ensures consistent period boundaries across all queries (sales, balances, aging, etc.) +- YoY comparisons auto-adjust based on configured period + ## Oracle Connection | Environment | ORACLE_HOST value | diff --git a/config.py b/config.py index 367e154..4d8e50b 100644 --- a/config.py +++ b/config.py @@ -26,6 +26,9 @@ def get_dsn(): OUTPUT_DIR = Path(os.getenv('OUTPUT_DIR', './output')) COMPANY_NAME = os.getenv('COMPANY_NAME', 'Data Intelligence Report') +# Reporting period - end month (YYYY-MM format, default: previous complete month) +REPORT_END_MONTH = os.getenv('REPORT_END_MONTH', None) + # Ensure output directory exists OUTPUT_DIR.mkdir(parents=True, exist_ok=True) diff --git a/main.py b/main.py index 0b77efd..b164172 100644 --- a/main.py +++ b/main.py @@ -48,11 +48,12 @@ check_dependencies() import oracledb import pandas as pd from dateutil.relativedelta import relativedelta +from datetime import timedelta from config import ( ORACLE_CONFIG, get_dsn, OUTPUT_DIR, COMPANY_NAME, ANALYSIS_MONTHS, MIN_SALES_FOR_ANALYSIS, LOW_MARGIN_THRESHOLD, - RECOMMENDATION_THRESHOLDS + RECOMMENDATION_THRESHOLDS, REPORT_END_MONTH ) from queries import QUERIES from report_generator import ( @@ -279,6 +280,41 @@ class PerformanceLogger: print(f"\n📝 Log saved to: {log_file}") +def compute_data_referinta(end_month_str: str = None) -> datetime: + """ + Compute reference date (first day of month AFTER the last reporting month). + + If end_month_str is None: default to first day of current month + (i.e., report through end of previous month). + If end_month_str is 'YYYY-MM': parse it and return first day of next month. + """ + if end_month_str: + parsed = datetime.strptime(end_month_str, '%Y-%m') + if parsed.month == 12: + return datetime(parsed.year + 1, 1, 1) + else: + return datetime(parsed.year, parsed.month + 1, 1) + else: + today = datetime.now() + return datetime(today.year, today.month, 1) + + +def resolve_dynamic_tables(sql: str, data_referinta: datetime, months: int = 12) -> str: + """ + Replace vjv2025/vjc2025 with correct year (or UNION ALL if spanning years). + """ + end_year = (data_referinta - timedelta(days=1)).year + start_year = (data_referinta - relativedelta(months=months)).year + + if start_year == end_year: + sql = sql.replace('vjv2025', f'vjv{end_year}') + sql = sql.replace('vjc2025', f'vjc{end_year}') + else: + sql = sql.replace('vjv2025', f'(SELECT * FROM vjv{start_year} UNION ALL SELECT * FROM vjv{end_year})') + sql = sql.replace('vjc2025', f'(SELECT * FROM vjc{start_year} UNION ALL SELECT * FROM vjc{end_year})') + return sql + + class OracleConnection: """Context manager for Oracle database connection""" @@ -315,6 +351,11 @@ def execute_query(connection, query_name: str, query_info: dict) -> pd.DataFrame try: sql = query_info['sql'] params = query_info.get('params', {}) + + # Resolve dynamic table names (vjv/vjc year-specific tables) + if 'data_referinta' in params: + months = params.get('months', 12) + sql = resolve_dynamic_tables(sql, params['data_referinta'], months) print(f" 📊 Executare: {query_name}...", end=" ") @@ -334,27 +375,31 @@ def execute_query(connection, query_name: str, query_info: dict) -> pd.DataFrame def generate_reports(args): """Main function to generate all reports""" - + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') excel_path = OUTPUT_DIR / f"data_intelligence_report_{timestamp}.xlsx" pdf_path = OUTPUT_DIR / f"data_intelligence_report_{timestamp}.pdf" - + + # Compute reference date + data_referinta = compute_data_referinta(args.end_month) + end_date = data_referinta - timedelta(days=1) # last day of reporting period + start_date = data_referinta - relativedelta(months=args.months) + period_str = f"Perioada: {start_date.strftime('%d.%m.%Y')} - {end_date.strftime('%d.%m.%Y')}" + print("\n" + "="*60) print(" DATA INTELLIGENCE REPORT GENERATOR") print("="*60) - print(f" Perioada: Ultimele {args.months} luni") + print(f" {period_str} ({args.months} luni)") print(f" Output: {OUTPUT_DIR}") print("="*60 + "\n") - - # Update parameters with command line arguments + + # Update parameters with command line arguments and inject data_referinta for query_info in QUERIES.values(): if 'months' in query_info.get('params', {}): query_info['params']['months'] = args.months - - # Calculate reporting period string - end_date = datetime.now() - start_date = end_date - relativedelta(months=args.months) - period_str = f"Perioada: {start_date.strftime('%d.%m.%Y')} - {end_date.strftime('%d.%m.%Y')}" + # Inject data_referinta into ALL queries + query_info.setdefault('params', {}) + query_info['params']['data_referinta'] = data_referinta # Add period to descriptions for queries with months parameter for query_name, query_info in QUERIES.items(): @@ -1101,6 +1146,13 @@ Exemple: default=ANALYSIS_MONTHS, help=f'Numărul de luni pentru analiză (default: {ANALYSIS_MONTHS})' ) + + parser.add_argument( + '--end-month', '-e', + type=str, + default=REPORT_END_MONTH, + help='Luna finala de raportare YYYY-MM (default: luna completa anterioara). Ex: 2026-01' + ) parser.add_argument( '--output-dir', '-o', diff --git a/queries.py b/queries.py index 5ae4466..045cdd6 100644 --- a/queries.py +++ b/queries.py @@ -33,7 +33,8 @@ 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta GROUP BY f.id_part, p.denumire, p.cod_fiscal ORDER BY marja_bruta DESC """ @@ -58,7 +59,8 @@ SELECT * FROM ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta 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 ) @@ -88,7 +90,8 @@ 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 f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta GROUP BY sg.id_grupa, sg.grupa, art.id_subgrupa, sg.subgrupa ORDER BY vanzari_fara_tva DESC """ @@ -115,7 +118,8 @@ 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta GROUP BY CASE WHEN d.cont IN ('341', '345') THEN 'Producție proprie' WHEN d.cont = '301' THEN 'Materii prime' @@ -145,7 +149,8 @@ WITH preturi_detalii AS ( 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 f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta AND d.pret > 0 ) SELECT @@ -184,7 +189,8 @@ WITH base_prices AS ( 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 f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta AND d.pret > 0 ), preturi_medii AS ( @@ -231,7 +237,8 @@ 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 f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta 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 @@ -247,17 +254,18 @@ 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) + SUM(CASE WHEN f.data_act >= ADD_MONTHS(:data_referinta, -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) + SUM(CASE WHEN f.data_act >= ADD_MONTHS(:data_referinta, -24) + AND f.data_act < ADD_MONTHS(:data_referinta, -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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -24) + AND f.data_act < :data_referinta GROUP BY f.id_part, p.denumire ) SELECT @@ -292,7 +300,8 @@ WITH total_vanzari AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta ), vanzari_client AS ( SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */ @@ -304,7 +313,8 @@ vanzari_client AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta GROUP BY f.id_part, p.denumire ), top_clienti AS ( @@ -357,7 +367,8 @@ 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -24) + AND f.data_act < :data_referinta GROUP BY TO_CHAR(f.data_act, 'YYYY-MM') ORDER BY luna """ @@ -379,8 +390,8 @@ SELECT 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) +WHERE s.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND s.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) 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 @@ -396,12 +407,12 @@ SELECT (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 + ROUND((:data_referinta - 1) - 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) +WHERE s.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND s.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) AND (s.cants + s.cant - s.cante) > 0 - AND (s.dataout IS NULL OR s.dataout < SYSDATE - 90) + AND (s.dataout IS NULL OR s.dataout < (:data_referinta - 1) - 90) AND (s.cants + s.cant - s.cante) * s.pret > 100 ORDER BY zile_fara_miscare DESC NULLS FIRST FETCH FIRST 100 ROWS ONLY @@ -419,7 +430,8 @@ WITH vanzari_articole AS ( 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) + AND r.dataact >= ADD_MONTHS(:data_referinta, -12) + AND r.dataact < :data_referinta GROUP BY r.id_articol ), stoc_curent AS ( @@ -429,8 +441,8 @@ stoc_curent AS ( 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) + WHERE s.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND s.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) AND (s.cants + s.cant - s.cante) > 0 GROUP BY s.id_articol, s.denumire, s.nume_gestiune ) @@ -482,7 +494,8 @@ SELECT 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) + AND r.dataact >= ADD_MONTHS(:data_referinta, -:months) + AND r.dataact < :data_referinta GROUP BY TO_CHAR(r.dataact, 'YYYY-MM'), CASE WHEN r.cont = '301' THEN 'Materii prime' WHEN r.cont = '341' THEN 'Semifabricate' @@ -506,7 +519,8 @@ WITH base_data AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -12) + AND f.data_act < :data_referinta ), aggregated AS ( SELECT @@ -586,7 +600,8 @@ 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 f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta 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 @@ -612,7 +627,8 @@ 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 f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta AND NVL(a.in_stoc, 1) = 1 GROUP BY d.id_gestiune, g.nume_gestiune ORDER BY vanzari_fara_tva DESC @@ -642,7 +658,8 @@ 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 f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta 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 @@ -665,8 +682,8 @@ SELECT 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) GROUP BY p.id_part, p.denumire, p.cod_fiscal HAVING SUM(b.solddeb - b.soldcred) <> 0 ORDER BY sold_curent DESC @@ -689,8 +706,8 @@ SELECT 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) GROUP BY p.id_part, p.denumire, p.cod_fiscal HAVING SUM(b.soldcred - b.solddeb) <> 0 ORDER BY sold_curent DESC @@ -702,7 +719,9 @@ ORDER BY sold_curent DESC # 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 + SELECT EXTRACT(YEAR FROM (:data_referinta - 1)) AS anul, + EXTRACT(MONTH FROM (:data_referinta - 1)) AS luna + FROM dual ), solduri_clienti AS ( SELECT @@ -716,8 +735,8 @@ solduri_clienti AS ( (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) + WHEN r.datascad >= :data_referinta THEN 0 + ELSE ROUND((:data_referinta - 1) - r.datascad) END AS zile_restante FROM vireg_parteneri r, ultima_luna ul WHERE (r.cont LIKE '4111%' OR r.cont LIKE '461%') @@ -744,20 +763,22 @@ ORDER BY total_sold DESC # 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 EXTRACT(YEAR FROM (:data_referinta - 1)) AS anul, + EXTRACT(MONTH FROM (:data_referinta - 1)) AS luna + FROM dual ) 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((:data_referinta - 1) - 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.datascad < :data_referinta AND r.an = ul.anul AND r.luna = ul.luna ORDER BY zile_intarziere DESC FETCH FIRST 100 ROWS ONLY @@ -770,7 +791,9 @@ FETCH FIRST 100 ROWS ONLY # 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 + SELECT EXTRACT(YEAR FROM (:data_referinta - 1)) AS anul, + EXTRACT(MONTH FROM (:data_referinta - 1)) AS luna + FROM dual ), solduri_furnizori AS ( SELECT @@ -784,8 +807,8 @@ solduri_furnizori AS ( (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) + WHEN r.datascad >= :data_referinta THEN 0 + ELSE ROUND((:data_referinta - 1) - 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%') @@ -812,20 +835,22 @@ ORDER BY total_sold DESC # 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 EXTRACT(YEAR FROM (:data_referinta - 1)) AS anul, + EXTRACT(MONTH FROM (:data_referinta - 1)) AS luna + FROM dual ) 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((:data_referinta - 1) - 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.datascad < :data_referinta AND r.an = ul.anul AND r.luna = ul.luna ORDER BY zile_intarziere DESC FETCH FIRST 100 ROWS ONLY @@ -852,8 +877,8 @@ WITH vanzari_12_luni AS ( ) 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)) + (EXTRACT(YEAR FROM ADD_MONTHS(:data_referinta, -12)) * 12 + EXTRACT(MONTH FROM ADD_MONTHS(:data_referinta, -12))) + AND (EXTRACT(YEAR FROM (:data_referinta - 1)) * 12 + EXTRACT(MONTH FROM (:data_referinta - 1))) AND EXTRACT(YEAR FROM dataireg) = an AND EXTRACT(MONTH FROM dataireg) = luna ), @@ -862,8 +887,8 @@ sold_clienti 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), achizitii_12_luni AS ( -- Achiziții fără TVA din ultimele 12 luni (jurnal cumpărări vjc2025) @@ -889,8 +914,8 @@ achizitii_12_luni AS ( ) 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)) + (EXTRACT(YEAR FROM ADD_MONTHS(:data_referinta, -12)) * 12 + EXTRACT(MONTH FROM ADD_MONTHS(:data_referinta, -12))) + AND (EXTRACT(YEAR FROM (:data_referinta - 1)) * 12 + EXTRACT(MONTH FROM (:data_referinta - 1))) AND EXTRACT(YEAR FROM dataireg) = an AND EXTRACT(MONTH FROM dataireg) = luna ), @@ -899,8 +924,8 @@ sold_furnizori 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ) SELECT 'DSO (Zile incasare clienti)' AS indicator, @@ -945,8 +970,8 @@ SELECT 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) GROUP BY b.cont HAVING SUM(b.solddeb - b.soldcred) <> 0 ORDER BY b.cont @@ -963,8 +988,8 @@ WITH metrici AS ( (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, + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1))) 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) @@ -972,13 +997,14 @@ WITH metrici AS ( 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, + AND f.data_act >= ADD_MONTHS(:data_referinta, -12) + AND f.data_act < :data_referinta) 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, + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1))) AS creante, -- Vânzări 12 luni din jurnal TVA vânzări (vjv2025) (SELECT SUM( -- Baze impozabile (ro*b) @@ -993,16 +1019,16 @@ WITH metrici AS ( 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)) + (EXTRACT(YEAR FROM ADD_MONTHS(:data_referinta, -12)) * 12 + EXTRACT(MONTH FROM ADD_MONTHS(:data_referinta, -12))) + AND (EXTRACT(YEAR FROM (:data_referinta - 1)) * 12 + EXTRACT(MONTH FROM (:data_referinta - 1))) 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, + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1))) AS datorii_furnizori, -- Achiziții 12 luni din jurnal TVA cumpărări (vjc2025) (SELECT SUM( -- Baze impozabile domestice (ro*b) @@ -1025,8 +1051,8 @@ WITH metrici AS ( 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)) + (EXTRACT(YEAR FROM ADD_MONTHS(:data_referinta, -12)) * 12 + EXTRACT(MONTH FROM ADD_MONTHS(:data_referinta, -12))) + AND (EXTRACT(YEAR FROM (:data_referinta - 1)) * 12 + EXTRACT(MONTH FROM (:data_referinta - 1))) AND EXTRACT(YEAR FROM dataireg) = an AND EXTRACT(MONTH FROM dataireg) = luna) AS achizitii_12_luni FROM dual @@ -1081,7 +1107,8 @@ WITH vanzari_detaliate AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta ), total AS ( SELECT SUM(vanzare) AS total_vanzari, SUM(marja) AS total_marja @@ -1114,7 +1141,8 @@ WITH vanzari_lunare AS ( 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(:data_referinta, -24) + AND f.data_act < :data_referinta 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 ( @@ -1155,50 +1183,55 @@ 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -3) + AND f.data_act < :data_referinta ), 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -12) + AND f.data_act < :data_referinta ), 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.data_act >= ADD_MONTHS(:data_referinta, -12) + AND f.data_act < :data_referinta 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) + AND f2.data_act < ADD_MONTHS(:data_referinta, -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.data_act >= ADD_MONTHS(:data_referinta, -24) + AND f.data_act < :data_referinta + AND f.data_act < ADD_MONTHS(:data_referinta, -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) + AND f2.data_act >= ADD_MONTHS(:data_referinta, -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.data_act >= ADD_MONTHS(:data_referinta, -6) + AND f.data_act < :data_referinta + AND f.data_act < ADD_MONTHS(:data_referinta, -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) + AND f2.data_act >= ADD_MONTHS(:data_referinta, -3) ) ) SELECT 'Clienti activi (ultimele 3 luni)' AS indicator, cnt AS valoare, 'Au cumparat recent' AS explicatie FROM clienti_activi_3_luni @@ -1228,7 +1261,8 @@ WITH frecventa_curenta AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -12) + AND f.data_act < :data_referinta GROUP BY f.id_part, p.denumire ), frecventa_anterioara AS ( @@ -1238,8 +1272,9 @@ frecventa_anterioara AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -24) + AND f.data_act < :data_referinta + AND f.data_act < ADD_MONTHS(:data_referinta, -12) GROUP BY f.id_part ) SELECT @@ -1270,7 +1305,8 @@ WITH total_vanzari AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta ), vanzari_client AS ( SELECT /*+ LEADING(f d) USE_NL(d) INDEX(f IDX_VANZARI_NR) */ @@ -1281,7 +1317,8 @@ vanzari_client AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta GROUP BY f.id_part ) SELECT @@ -1337,7 +1374,8 @@ WITH vanzari_client AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta GROUP BY f.id_part, p.denumire ) SELECT @@ -1379,7 +1417,8 @@ 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 f.data_act >= ADD_MONTHS(:data_referinta, -:months) + AND f.data_act < :data_referinta 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 @@ -1399,8 +1438,9 @@ WITH preturi_vechi AS ( 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 f.data_act >= ADD_MONTHS(:data_referinta, -12) + AND f.data_act < :data_referinta + AND f.data_act < ADD_MONTHS(:data_referinta, -6) AND d.pret > 0 GROUP BY d.id_articol, a.denumire HAVING COUNT(*) >= 5 @@ -1413,7 +1453,8 @@ preturi_noi AS ( 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 f.data_act >= ADD_MONTHS(:data_referinta, -6) + AND f.data_act < :data_referinta AND d.pret > 0 GROUP BY d.id_articol HAVING COUNT(*) >= 5 @@ -1441,8 +1482,8 @@ capitaluri AS ( 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), -- Datorii totale (16x, 40x, 42x, 44x, 46x) datorii AS ( @@ -1450,8 +1491,8 @@ datorii AS ( 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), -- Total activ (sold debitor toate conturile de activ) activ AS ( @@ -1461,8 +1502,8 @@ activ AS ( 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), -- Vanzari si profit din ultimele 12 luni vanzari_calc AS ( @@ -1473,7 +1514,8 @@ vanzari_calc AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -12) + AND f.data_act < :data_referinta ) SELECT 'Grad indatorare' AS indicator, @@ -1586,23 +1628,23 @@ 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), -- 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), -- 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) + WHERE s.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND s.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) AND (s.cants + s.cant - s.cante) > 0 ), -- Datorii curente (401, 404, 462) @@ -1610,8 +1652,8 @@ 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ) SELECT 'Lichiditate curenta' AS indicator, @@ -1692,8 +1734,8 @@ WITH datorii_scadenta AS ( (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' + WHEN r.datascad <= (:data_referinta - 1) + 30 THEN 'TERMEN_SCURT' + WHEN r.datascad <= (:data_referinta - 1) + 90 THEN 'TERMEN_MEDIU' ELSE 'TERMEN_LUNG' END AS clasificare FROM vireg_parteneri r @@ -1745,23 +1787,23 @@ 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), 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 + ROUND(SUM(CASE WHEN r.datascad <= (:data_referinta - 1) + 30 THEN (r.precdeb + r.debit) - (r.preccred + r.credit) ELSE 0 END), 0) AS incasari_30, + ROUND(SUM(CASE WHEN r.datascad <= (:data_referinta - 1) + 60 THEN (r.precdeb + r.debit) - (r.preccred + r.credit) ELSE 0 END), 0) AS incasari_60, + ROUND(SUM(CASE WHEN r.datascad <= (:data_referinta - 1) + 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 + ROUND(SUM(CASE WHEN r.datascad <= (:data_referinta - 1) + 30 THEN (r.preccred + r.credit) - (r.precdeb + r.debit) ELSE 0 END), 0) AS plati_30, + ROUND(SUM(CASE WHEN r.datascad <= (:data_referinta - 1) + 60 THEN (r.preccred + r.credit) - (r.precdeb + r.debit) ELSE 0 END), 0) AS plati_60, + ROUND(SUM(CASE WHEN r.datascad <= (:data_referinta - 1) + 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 @@ -1825,23 +1867,23 @@ 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), 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 + SUM(CASE WHEN r.datascad <= (:data_referinta - 1) + 30 THEN (r.precdeb + r.debit) - (r.preccred + r.credit) ELSE 0 END) AS incasari_30, + SUM(CASE WHEN r.datascad > (:data_referinta - 1) + 30 AND r.datascad <= (:data_referinta - 1) + 60 THEN (r.precdeb + r.debit) - (r.preccred + r.credit) ELSE 0 END) AS incasari_31_60, + SUM(CASE WHEN r.datascad > (:data_referinta - 1) + 60 AND r.datascad <= (:data_referinta - 1) + 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 + SUM(CASE WHEN r.datascad <= (:data_referinta - 1) + 30 THEN (r.preccred + r.credit) - (r.precdeb + r.debit) ELSE 0 END) AS plati_30, + SUM(CASE WHEN r.datascad > (:data_referinta - 1) + 30 AND r.datascad <= (:data_referinta - 1) + 60 THEN (r.preccred + r.credit) - (r.precdeb + r.debit) ELSE 0 END) AS plati_31_60, + SUM(CASE WHEN r.datascad > (:data_referinta - 1) + 60 AND r.datascad <= (:data_referinta - 1) + 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 @@ -1897,19 +1939,27 @@ 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 +# f.tip NOT IN (21,22,23,24,25) - excludes avizele de expeditie, si tranzactii similare non-vanzare + 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 + CASE WHEN f.data_act >= ADD_MONTHS(:data_referinta, -12) THEN 'CURENT' ELSE 'ANTERIOR' END AS perioada, + (CASE WHEN d.pret_cu_tva = 1 THEN round((ROUND(NVL(c.curs, 1) * ROUND(NVL(d.pret, 0), 4) / NVL(c.multiplicator, 1), 4)) / d.proc_tvav, 4) ELSE (ROUND(NVL(c.curs, 1) * ROUND(NVL(d.pret, 0), 4) / NVL(c.multiplicator, 1), 4)) END) AS pret_unitar_ron, + ROUND(NVL(c.curs, 1) * NVL(d.discount_unitar, 4) / NVL(c.multiplicator, 1), 4) AS discount_unitar_ron, + ((CASE WHEN d.pret_cu_tva = 1 THEN round((ROUND(NVL(c.curs, 1) * ROUND(NVL(d.pret, 0), 4) / NVL(c.multiplicator, 1), 4)) / d.proc_tvav, 4) ELSE (ROUND(NVL(c.curs, 1) * ROUND(NVL(d.pret, 0), 4) / NVL(c.multiplicator, 1), 4)) END) - ROUND(NVL(c.curs, 1) * NVL(d.discount_unitar, 4) / NVL(c.multiplicator, 1), 4)) AS pret_unitar_final, + d.cantitate * ((CASE WHEN d.pret_cu_tva = 1 THEN round((ROUND(NVL(c.curs, 1) * ROUND(NVL(d.pret, 0), 4) / NVL(c.multiplicator, 1), 4)) / d.proc_tvav, 4) ELSE (ROUND(NVL(c.curs, 1) * ROUND(NVL(d.pret, 0), 4) / NVL(c.multiplicator, 1), 4)) END) - ROUND(NVL(c.curs, 1) * NVL(d.discount_unitar, 4) / NVL(c.multiplicator, 1), 4)) AS vanzare, + d.cantitate * (((CASE WHEN d.pret_cu_tva = 1 THEN round((ROUND(NVL(c.curs, 1) * ROUND(NVL(d.pret, 0), 4) / NVL(c.multiplicator, 1), 4)) / d.proc_tvav, 4) ELSE (ROUND(NVL(c.curs, 1) * ROUND(NVL(d.pret, 0), 4) / NVL(c.multiplicator, 1), 4)) END) - ROUND(NVL(c.curs, 1) * NVL(d.discount_unitar, 4) / NVL(c.multiplicator, 1), 4)) - d.pret_achizitie) AS marja FROM VANZARI f JOIN VANZARI_DETALII d ON d.id_vanzare = f.id_vanzare + LEFT JOIN VANZARI_CURSURI c ON d.id_vanzare = c.id_vanzare + AND d.id_valuta = c.id_valuta 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) + AND f.tip > 0 AND f.tip NOT IN (21,22,23,24,25) + AND f.data_act >= ADD_MONTHS(:data_referinta, -24) + AND f.data_act < :data_referinta ), aggregated AS ( SELECT @@ -2002,27 +2052,29 @@ vanzari_curente AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -12) + AND f.data_act < :data_referinta ), 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), 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) + AND r.dataact >= ADD_MONTHS(:data_referinta, -12) + AND r.dataact < :data_referinta ), 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), -- Metrici anterioare (aproximare - vanzari an anterior) vanzari_anterioare AS ( @@ -2032,30 +2084,32 @@ vanzari_anterioare AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -24) + AND f.data_act < :data_referinta + AND f.data_act < ADD_MONTHS(:data_referinta, -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) + AND r.dataact >= ADD_MONTHS(:data_referinta, -24) + AND r.dataact < :data_referinta + AND r.dataact < ADD_MONTHS(:data_referinta, -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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) - 1 + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ), 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) + AND b.an = EXTRACT(YEAR FROM (:data_referinta - 1)) - 1 + AND b.luna = EXTRACT(MONTH FROM (:data_referinta - 1)) ) SELECT 'DSO (Zile incasare)' AS indicator, @@ -2105,7 +2159,8 @@ vanzari_curent AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -12) + AND f.data_act < :data_referinta GROUP BY f.id_part ), ranked_curent AS ( @@ -2129,8 +2184,9 @@ vanzari_anterior AS ( 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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -24) + AND f.data_act < :data_referinta + AND f.data_act < ADD_MONTHS(:data_referinta, -12) GROUP BY f.id_part ), ranked_anterior AS ( @@ -2220,14 +2276,15 @@ WITH base_data AS ( 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, + CASE WHEN f.data_act >= ADD_MONTHS(:data_referinta, -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) + AND f.data_act >= ADD_MONTHS(:data_referinta, -24) + AND f.data_act < :data_referinta ) SELECT linie_business,