"""Command Center - Dashboard Routes"""
from flask import Blueprint, render_template, redirect, url_for, flash, request, jsonify
from flask_login import login_required, current_user
from datetime import datetime, timezone, timedelta
from ..models import (
db, Company, Project, KPIValue, Forecast, Goal, GoalMetric,
OptimizationMove, CoachingAssignment, CoachingScorecard,
ActivityLog, AuditLog, Notification, UserCompany,
)
from ..services.forecast_service import get_forecast_data, calculate_run_rate
from ..services.kpi_service import get_kpi_dashboard, get_revenue_kpis, get_operational_kpis
from ..utils.tenancy import resolve_company_id, require_company_access
dashboard_bp = Blueprint('dashboard', __name__, url_prefix='/dashboard')
def get_user_companies(user_id):
"""Get all companies associated with the current user."""
return Company.query.join(
UserCompany, Company.id == UserCompany.company_id
).filter(
UserCompany.user_id == user_id
).all()
@dashboard_bp.route('/')
@login_required
def index():
"""Main dashboard overview."""
companies = get_user_companies(current_user.id)
if not companies:
return redirect(url_for('dashboard.companies_route'))
default_company = companies[0]
# Get run rate
run_rate = calculate_run_rate(default_company.id)
# Get recent KPIs
kpis = get_kpi_dashboard(default_company.id)
# Get recent forecasts
recent_forecasts = Forecast.query.filter_by(
company_id=default_company.id
).order_by(Forecast.period_start.desc()).limit(6).all()
# Get active projects count
active_projects = Project.query.filter_by(
company_id=default_company.id,
status='active'
).count()
# Get active goals
active_goals = Goal.query.filter_by(
company_id=default_company.id,
status='active'
).order_by(Goal.end_date).limit(5).all()
# Get recent coaching sessions
recent_sessions = CoachingAssignment.query.filter_by(
company_id=default_company.id
).order_by(CoachingAssignment.start_date.desc()).limit(3).all()
# Get notifications
notifications = Notification.query.filter_by(
user_id=current_user.id,
is_read=False
).order_by(Notification.created_at.desc()).limit(5).all()
return render_template(
'dashboard/index.html',
company=default_company,
companies=companies,
run_rate=run_rate,
kpis=kpis,
recent_forecasts=recent_forecasts,
active_projects=active_projects,
active_goals=active_goals,
recent_sessions=recent_sessions,
notifications=notifications,
)
@dashboard_bp.route('/forecast')
@login_required
def forecast():
"""Revenue forecast page."""
companies = get_user_companies(current_user.id)
if not companies:
return redirect(url_for('dashboard.index'))
company_id = resolve_company_id(default=companies[0].id)
forecast_data = get_forecast_data(company_id)
run_rate = calculate_run_rate(company_id)
return render_template(
'dashboard/forecast.html',
company_id=company_id,
companies=companies,
forecast_data=forecast_data,
run_rate=run_rate,
)
@dashboard_bp.route('/goals')
@login_required
def goals():
"""Goals and milestones page."""
companies = get_user_companies(current_user.id)
if not companies:
return redirect(url_for('dashboard.index'))
company_id = resolve_company_id(default=companies[0].id)
goals = Goal.query.filter_by(
company_id=company_id
).order_by(Goal.end_date).all()
# Get goal metrics
goal_ids = [g.id for g in goals]
metrics = GoalMetric.query.filter(
GoalMetric.goal_id.in_(goal_ids)
).all()
metrics_map = {}
for m in metrics:
if m.goal_id not in metrics_map:
metrics_map[m.goal_id] = []
metrics_map[m.goal_id].append(m)
return render_template(
'dashboard/goals.html',
company_id=company_id,
companies=companies,
goals=goals,
metrics_map=metrics_map,
)
@dashboard_bp.route('/companies')
@login_required
def companies_route():
"""Company management page."""
companies = get_user_companies(current_user.id)
return render_template(
'dashboard/companies.html',
companies=companies,
)
@dashboard_bp.route('/projects')
@login_required
def projects():
"""Project management page."""
companies = get_user_companies(current_user.id)
if not companies:
return redirect(url_for('dashboard.companies_route'))
company_id = resolve_company_id(default=companies[0].id)
projects = Project.query.filter_by(company_id=company_id).all()
return render_template(
'dashboard/projects.html',
company_id=company_id,
companies=companies,
projects=projects,
)
@dashboard_bp.route('/optimization')
@login_required
def optimization():
"""Optimization recommendations page."""
companies = get_user_companies(current_user.id)
if not companies:
return redirect(url_for('dashboard.index'))
company_id = resolve_company_id(default=companies[0].id)
optimizations = OptimizationMove.query.filter_by(
company_id=company_id
).order_by(OptimizationMove.created_at.desc()).all()
return render_template(
'dashboard/optimization.html',
company_id=company_id,
companies=companies,
optimizations=optimizations,
)
@dashboard_bp.route('/coaching')
@login_required
def coaching():
"""Coaching sessions page."""
companies = get_user_companies(current_user.id)
if not companies:
return redirect(url_for('dashboard.index'))
company_id = resolve_company_id(default=companies[0].id)
sessions = CoachingAssignment.query.filter_by(
company_id=company_id
).order_by(CoachingAssignment.start_date.desc()).all()
scorecards = CoachingScorecard.query.filter(
CoachingScorecard.company_id == company_id
).order_by(CoachingScorecard.evaluation_date.desc()).limit(5).all()
return render_template(
'dashboard/coaching.html',
company_id=company_id,
companies=companies,
sessions=sessions,
scorecards=scorecards,
)
@dashboard_bp.route('/settings')
@login_required
def settings():
"""User settings page."""
return render_template(
'dashboard/settings.html',
user=current_user,
)
@dashboard_bp.route('/api/kpis/<company_id>')
@login_required
@require_company_access
def api_kpis(company_id):
"""API endpoint for KPI data."""
kpis = get_kpi_dashboard(company_id)
return jsonify(kpis)
@dashboard_bp.route('/api/forecast/<company_id>')
@login_required
@require_company_access
def api_forecast(company_id):
"""API endpoint for forecast data."""
forecast_data = get_forecast_data(company_id)
run_rate = calculate_run_rate(company_id)
return jsonify({
'forecast': forecast_data,
'run_rate': run_rate,
})