- Updated core.py, init.py, mysql.ddl.sql - Added __init__.py - Added API files: dashboard_kpi, report_list - Added UI files: base.ui, dashboard.ui, reports.ui
85 lines
3.5 KiB
Python
85 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""Dashboard KPI and chart data API"""
|
|
import json
|
|
|
|
result = {'success': False, 'rows': [], 'total': 0}
|
|
|
|
try:
|
|
kpi_type = params_kw.get('type', '').strip()
|
|
|
|
if kpi_type == 'sales_funnel':
|
|
dbname = get_module_dbname('opportunity_management')
|
|
async with DBPools().sqlorContext(dbname) as sor:
|
|
stages = await sor.sqlExe("SELECT id, stage_name, stage_order FROM sales_stages ORDER BY stage_order ASC")
|
|
funnel_data = []
|
|
for stage in stages:
|
|
rows = await sor.sqlExe("SELECT COUNT(*) as cnt, COALESCE(SUM(estimated_amount),0) as amt FROM opportunities WHERE current_stage = ${stage_id}$", {'stage_id': stage['id']})
|
|
funnel_data.append({
|
|
'stage': stage['stage_name'],
|
|
'count': rows[0]['cnt'] if rows else 0,
|
|
'amount': float(rows[0]['amt'] or 0) if rows else 0
|
|
})
|
|
result['rows'] = funnel_data
|
|
result['total'] = len(funnel_data)
|
|
result['success'] = True
|
|
|
|
elif kpi_type == 'recent_opportunities':
|
|
dbname = get_module_dbname('opportunity_management')
|
|
async with DBPools().sqlorContext(dbname) as sor:
|
|
rows = await sor.sqlExe("SELECT customer_name, estimated_amount, current_stage FROM opportunities ORDER BY created_at DESC LIMIT 10")
|
|
result['rows'] = [dict(r) for r in (rows or [])]
|
|
result['total'] = len(result['rows'])
|
|
result['success'] = True
|
|
|
|
elif kpi_type == 'kpi_summary':
|
|
# Aggregate KPIs from all modules
|
|
kpis = {}
|
|
|
|
# Customer count
|
|
try:
|
|
dbname = get_module_dbname('customer_management')
|
|
async with DBPools().sqlorContext(dbname) as sor:
|
|
rows = await sor.sqlExe("SELECT COUNT(*) as cnt FROM customers")
|
|
kpis['total_customers'] = rows[0]['cnt'] if rows else 0
|
|
except:
|
|
kpis['total_customers'] = 0
|
|
|
|
# Active opportunities
|
|
try:
|
|
dbname = get_module_dbname('opportunity_management')
|
|
async with DBPools().sqlorContext(dbname) as sor:
|
|
rows = await sor.sqlExe("SELECT COUNT(*) as cnt FROM opportunities WHERE status = 'active'")
|
|
kpis['active_opportunities'] = rows[0]['cnt'] if rows else 0
|
|
except:
|
|
kpis['active_opportunities'] = 0
|
|
|
|
# Contract count
|
|
try:
|
|
dbname = get_module_dbname('contract_management')
|
|
async with DBPools().sqlorContext(dbname) as sor:
|
|
rows = await sor.sqlExe("SELECT COUNT(*) as cnt FROM contract")
|
|
kpis['total_contracts'] = rows[0]['cnt'] if rows else 0
|
|
except:
|
|
kpis['total_contracts'] = 0
|
|
|
|
# Total receivables
|
|
try:
|
|
dbname = get_module_dbname('financial_management')
|
|
async with DBPools().sqlorContext(dbname) as sor:
|
|
rows = await sor.sqlExe("SELECT COALESCE(SUM(receivable_amount),0) as total FROM receivables")
|
|
kpis['total_receivables'] = float(rows[0]['total'] or 0) if rows else 0
|
|
except:
|
|
kpis['total_receivables'] = 0
|
|
|
|
result['success'] = True
|
|
result['data'] = kpis
|
|
|
|
else:
|
|
result['error'] = f'Unknown KPI type: {kpi_type}'
|
|
|
|
except Exception as e:
|
|
result['error'] = str(e)
|
|
|
|
return json.dumps(result, ensure_ascii=False, default=str)
|