bmc_hub/app/fixed_price/frontend/reports.html

286 lines
15 KiB
HTML
Raw Permalink Normal View History

{% extends "shared/frontend/base.html" %}
{% block title %}Fastpris Rapporter - BMC Hub{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<!-- Header -->
<div class="row mb-4">
<div class="col">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/fixed-price-agreements">Fastpris Aftaler</a></li>
<li class="breadcrumb-item active">Rapporter</li>
</ol>
</nav>
<h1 class="h3 mb-0">📊 Fastpris Rapporter</h1>
<p class="text-muted">Profitabilitet og performance analyse</p>
</div>
</div>
{% if error %}
<div class="alert alert-danger">
<i class="bi bi-exclamation-triangle me-2"></i>
<strong>Fejl:</strong> {{ error }}
</div>
{% endif %}
<!-- Summary Stats -->
<div class="row g-3 mb-4">
<div class="col-md-3">
<div class="card border-0 shadow-sm">
<div class="card-body">
<h6 class="text-muted mb-2">Aktive Aftaler</h6>
<h3 class="mb-0">{{ stats.active_agreements or 0 }}</h3>
<small class="text-muted">af {{ stats.total_agreements or 0 }} total</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm">
<div class="card-body">
<h6 class="text-muted mb-2">Total Omsætning</h6>
<h3 class="mb-0">{{ "{:,.0f}".format(stats.total_revenue or 0) }} kr</h3>
<small class="text-muted">Månedlig værdi</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm">
<div class="card-body">
<h6 class="text-muted mb-2">Estimeret Profit</h6>
<h3 class="mb-0">{{ "{:,.0f}".format(stats.estimated_profit or 0) }} kr</h3>
<small class="text-muted">Ved 300 kr/t kostpris</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card border-0 shadow-sm">
<div class="card-body">
<h6 class="text-muted mb-2">Profit Margin</h6>
{% set profit_margin = ((stats.estimated_profit|float / stats.total_revenue|float * 100)|round(1)) if stats.total_revenue and stats.total_revenue > 0 else 0 %}
<h3 class="mb-0">{{ profit_margin }}%</h3>
<small class="text-muted">Gennemsnitlig margin</small>
</div>
</div>
</div>
</div>
<!-- Tabs -->
<ul class="nav nav-tabs mb-3" role="tablist">
<li class="nav-item">
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#performance-tab">Performance</button>
</li>
<li class="nav-item">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#trends-tab">Trends</button>
</li>
<li class="nav-item">
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#customers-tab">Kunder</button>
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content">
<!-- Performance Tab -->
<div class="tab-pane fade show active" id="performance-tab">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white">
<h5 class="mb-0">Aftale Performance</h5>
<small class="text-muted">Sorteret efter profit margin</small>
</div>
<div class="card-body">
{% if performance %}
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th>Aftale</th>
<th>Kunde</th>
<th class="text-end">Total Timer</th>
<th class="text-end">Månedlig Værdi</th>
<th class="text-end">Profit</th>
<th class="text-end">Margin</th>
<th class="text-end">Udnyttelse</th>
</tr>
</thead>
<tbody>
{% for agr in performance %}
<tr>
<td>
<a href="/fixed-price-agreements/{{ agr.agreement_id }}">
<strong>{{ agr.agreement_number }}</strong>
</a>
</td>
<td>{{ agr.customer_name }}</td>
<td class="text-end">{{ '%.1f'|format(agr.total_used_hours or 0) }}t</td>
<td class="text-end">{{ "{:,.0f}".format(agr.total_base_revenue or 0) }} kr</td>
<td class="text-end">
{% if agr.estimated_profit and agr.estimated_profit > 0 %}
<span class="text-success">{{ "{:,.0f}".format(agr.estimated_profit) }} kr</span>
{% else %}
<span class="text-danger">{{ "{:,.0f}".format(agr.estimated_profit or 0) }} kr</span>
{% endif %}
</td>
<td class="text-end">
{% if agr.profit_margin and agr.profit_margin >= 30 %}
<span class="badge bg-success">{{ '%.1f'|format(agr.profit_margin) }}%</span>
{% elif agr.profit_margin and agr.profit_margin >= 15 %}
<span class="badge bg-warning">{{ '%.1f'|format(agr.profit_margin) }}%</span>
{% else %}
<span class="badge bg-danger">{{ '%.1f'|format(agr.profit_margin or 0) }}%</span>
{% endif %}
</td>
<td class="text-end">
{% set utilization = ((agr.total_used_hours or 0) / (agr.total_allocated_hours or 1) * 100) if agr.total_allocated_hours else 0 %}
{% if utilization >= 80 %}
<span class="badge bg-success">{{ '%.0f'|format(utilization) }}%</span>
{% elif utilization >= 50 %}
<span class="badge bg-info">{{ '%.0f'|format(utilization) }}%</span>
{% else %}
<span class="badge bg-secondary">{{ '%.0f'|format(utilization) }}%</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center text-muted py-5">
<i class="bi bi-graph-down fs-1 mb-3"></i>
<p>Ingen performance data tilgængelig</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Trends Tab -->
<div class="tab-pane fade" id="trends-tab">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white">
<h5 class="mb-0">Månedlige Trends</h5>
<small class="text-muted">Seneste 12 måneder</small>
</div>
<div class="card-body">
{% if trends %}
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th>Måned</th>
<th class="text-end">Aktive Aftaler</th>
<th class="text-end">Brugte Timer</th>
<th class="text-end">Overtid Timer</th>
<th class="text-end">Total Værdi</th>
<th class="text-end">Profit</th>
<th class="text-end">Margin</th>
</tr>
</thead>
<tbody>
{% for trend in trends %}
<tr>
<td><strong>{{ trend.period_month }}</strong></td>
<td class="text-end">{{ trend.active_agreements }}</td>
<td class="text-end">{{ '%.1f'|format(trend.total_used_hours or 0) }}t</td>
<td class="text-end">
{% if trend.total_overtime_hours and trend.total_overtime_hours > 0 %}
<span class="text-warning">{{ '%.1f'|format(trend.total_overtime_hours) }}t</span>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td class="text-end">{{ "{:,.0f}".format(trend.monthly_total_revenue or 0) }} kr</td>
<td class="text-end">
{% if trend.total_profit and trend.total_profit > 0 %}
<span class="text-success">{{ "{:,.0f}".format(trend.total_profit) }} kr</span>
{% else %}
<span class="text-danger">{{ "{:,.0f}".format(trend.total_profit or 0) }} kr</span>
{% endif %}
</td>
<td class="text-end">
{% if trend.avg_profit_margin and trend.avg_profit_margin >= 30 %}
<span class="badge bg-success">{{ '%.1f'|format(trend.avg_profit_margin) }}%</span>
{% elif trend.avg_profit_margin and trend.avg_profit_margin >= 15 %}
<span class="badge bg-warning">{{ '%.1f'|format(trend.avg_profit_margin) }}%</span>
{% else %}
<span class="badge bg-danger">{{ '%.1f'|format(trend.avg_profit_margin or 0) }}%</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center text-muted py-5">
<i class="bi bi-calendar3 fs-1 mb-3"></i>
<p>Ingen trend data tilgængelig</p>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Customers Tab -->
<div class="tab-pane fade" id="customers-tab">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white">
<h5 class="mb-0">Top Kunder</h5>
<small class="text-muted">Sorteret efter total forbrug</small>
</div>
<div class="card-body">
{% if customers %}
<div class="table-responsive">
<table class="table table-hover">
<thead class="table-light">
<tr>
<th>Kunde</th>
<th class="text-end">Aftaler</th>
<th class="text-end">Total Timer</th>
<th class="text-end">Overtid</th>
<th class="text-end">Total Værdi</th>
<th class="text-end">Avg Margin</th>
</tr>
</thead>
<tbody>
{% for customer in customers %}
<tr>
<td><strong>{{ customer.customer_name }}</strong></td>
<td class="text-end">{{ customer.agreement_count }}</td>
<td class="text-end">{{ '%.1f'|format(customer.total_used_hours or 0) }}t</td>
<td class="text-end">
{% if customer.total_overtime_hours and customer.total_overtime_hours > 0 %}
<span class="text-warning">{{ '%.1f'|format(customer.total_overtime_hours) }}t</span>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td class="text-end">{{ "{:,.0f}".format(customer.total_revenue or 0) }} kr</td>
<td class="text-end">
{% if customer.avg_profit_margin and customer.avg_profit_margin >= 30 %}
<span class="badge bg-success">{{ '%.1f'|format(customer.avg_profit_margin) }}%</span>
{% elif customer.avg_profit_margin and customer.avg_profit_margin >= 15 %}
<span class="badge bg-warning">{{ '%.1f'|format(customer.avg_profit_margin) }}%</span>
{% else %}
<span class="badge bg-danger">{{ '%.1f'|format(customer.avg_profit_margin or 0) }}%</span>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center text-muted py-5">
<i class="bi bi-people fs-1 mb-3"></i>
<p>Ingen kunde data tilgængelig</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock %}