Files
calminer/templates/reports/project_summary.html
zwitschi acf6f50bbd
Some checks failed
CI / lint (push) Successful in 15s
CI / build (push) Has been skipped
CI / test (push) Failing after 17s
CI / deploy (push) Has been skipped
feat: Add NPV comparison and distribution charts to reporting
- Implemented NPV comparison chart generation using Plotly in ReportingService.
- Added distribution histogram for Monte Carlo results.
- Updated reporting templates to include new charts and improved layout.
- Created new settings and currencies management pages.
- Enhanced sidebar navigation with dynamic URL handling.
- Improved CSS styles for chart containers and overall layout.
- Added new simulation and theme settings pages with placeholders for future features.
2025-11-12 19:39:27 +01:00

249 lines
7.7 KiB
HTML

{% extends "base.html" %} {% block title %}Project Summary | CalMiner{% endblock
%} {% block content %} {% include "partials/reports_header.html" %} {% include
"partials/reports/options_card.html" %} {% include
"partials/reports/filters_card.html" %}
<section class="report-overview">
<div class="report-grid">
<article class="report-card">
<h2>Project Details</h2>
<dl class="definition-list">
<div>
<dt>Name</dt>
<dd>{{ project.name }}</dd>
</div>
<div>
<dt>Location</dt>
<dd>{{ project.location or "—" }}</dd>
</div>
<div>
<dt>Operation Type</dt>
<dd>{{ project.operation_type | replace("_", " ") | title }}</dd>
</div>
<div>
<dt>Scenarios</dt>
<dd>{{ scenario_count }}</dd>
</div>
<div>
<dt>Created</dt>
<dd>{{ project.created_at | format_datetime }}</dd>
</div>
<div>
<dt>Updated</dt>
<dd>{{ project.updated_at | format_datetime }}</dd>
</div>
</dl>
</article>
<article class="report-card">
<h2>Financial Summary</h2>
<ul class="metric-list">
<li>
<span>Total Inflows</span>
<strong
>{{ aggregates.financials.total_inflows |
currency_display(project.currency) }}</strong
>
</li>
<li>
<span>Total Outflows</span>
<strong
>{{ aggregates.financials.total_outflows |
currency_display(project.currency) }}</strong
>
</li>
<li>
<span>Net Cash Flow</span>
<strong
>{{ aggregates.financials.total_net |
currency_display(project.currency) }}</strong
>
</li>
</ul>
</article>
<article class="report-card">
<h2>Deterministic Metrics</h2>
{% if aggregates.deterministic_metrics %}
<table class="metrics-table">
<thead>
<tr>
<th scope="col">Metric</th>
<th scope="col">Average</th>
<th scope="col">Best</th>
<th scope="col">Worst</th>
</tr>
</thead>
<tbody>
{% for key, metric in aggregates.deterministic_metrics.items() %}
<tr>
<th scope="row">{{ key | replace("_", " ") | title }}</th>
<td>{{ metric.average | format_metric(key, project.currency) }}</td>
<td>{{ metric.maximum | format_metric(key, project.currency) }}</td>
<td>{{ metric.minimum | format_metric(key, project.currency) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p class="muted">
Deterministic metrics are unavailable for the current filters.
</p>
{% endif %}
</article>
</div>
</section>
<section class="report-section">
<header class="section-header">
<h2>NPV Comparison</h2>
<p class="section-subtitle">
Visual comparison of Net Present Value across scenarios.
</p>
</header>
<div id="npv-chart" class="chart-container"></div>
</section>
<section class="report-section">
<header class="section-header">
<h2>Scenario Breakdown</h2>
<p class="section-subtitle">
Deterministic metrics and Monte Carlo summaries for each scenario.
</p>
</header>
{% if scenarios %} {% for item in scenarios %}
<article class="scenario-card">
<div class="scenario-card-header">
<div>
<h3>{{ item.scenario.name }}</h3>
<p class="muted">
{{ item.scenario.status | title }} · {{ item.scenario.primary_resource
or "No primary resource" }}
</p>
</div>
<div class="scenario-meta">
<span class="meta-label">Currency</span>
<span class="meta-value"
>{{ item.scenario.currency or project.currency or "—" }}</span
>
</div>
{% include "partials/reports/scenario_actions.html" %}
</div>
<div class="scenario-grid">
<section class="scenario-panel">
<h4>Financial Totals</h4>
<ul class="metric-list compact">
<li>
<span>Inflows</span>
<strong
>{{ item.financials.inflows |
currency_display(item.scenario.currency or project.currency)
}}</strong
>
</li>
<li>
<span>Outflows</span>
<strong
>{{ item.financials.outflows |
currency_display(item.scenario.currency or project.currency)
}}</strong
>
</li>
<li>
<span>Net</span>
<strong
>{{ item.financials.net | currency_display(item.scenario.currency
or project.currency) }}</strong
>
</li>
</ul>
<h5>By Category</h5>
{% if item.financials.by_category %}
<ul class="metric-list compact">
{% for label, value in item.financials.by_category.items() %}
<li>
<span>{{ label | replace("_", " ") | title }}</span>
<strong
>{{ value | currency_display(item.scenario.currency or
project.currency) }}</strong
>
</li>
{% endfor %}
</ul>
{% else %}
<p class="muted">No financial inputs recorded.</p>
{% endif %}
</section>
<section class="scenario-panel">
<h4>Deterministic Metrics</h4>
<table class="metrics-table">
<tbody>
<tr>
<th scope="row">Discount Rate</th>
<td>{{ item.metrics.discount_rate | percentage_display }}</td>
</tr>
<tr>
<th scope="row">NPV</th>
<td>
{{ item.metrics.npv | currency_display(item.scenario.currency or
project.currency) }}
</td>
</tr>
<tr>
<th scope="row">IRR</th>
<td>{{ item.metrics.irr | percentage_display }}</td>
</tr>
<tr>
<th scope="row">Payback Period</th>
<td>{{ item.metrics.payback_period | period_display }}</td>
</tr>
</tbody>
</table>
{% if item.metrics.notes %}
<ul class="note-list">
{% for note in item.metrics.notes %}
<li>{{ note }}</li>
{% endfor %}
</ul>
{% endif %}
</section>
<section class="scenario-panel">
<h4>Monte Carlo Summary</h4>
{% if item.monte_carlo and item.monte_carlo.available %}
<p class="muted">
Iterations: {{ item.monte_carlo.iterations }} {% if percentiles %} ·
Percentiles: {% for percentile in percentiles %} {{ '%g' % percentile
}}{% if not loop.last %}, {% endif %} {% endfor %} {% endif %}
</p>
{% include "partials/reports/monte_carlo_table.html" %} {% else %}
<p class="muted">
Monte Carlo metrics are unavailable for this scenario.
</p>
{% if item.monte_carlo and item.monte_carlo.notes %}
<ul class="note-list">
{% for note in item.monte_carlo.notes %}
<li>{{ note }}</li>
{% endfor %}
</ul>
{% endif %} {% endif %}
</section>
</div>
</article>
{% endfor %} {% else %}
<p class="muted">No scenarios match the current filters.</p>
{% endif %}
</section>
{% endblock %} {% block scripts %}
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script>
const chartData = {{ chart_data | safe }};
if (chartData && chartData.data) {
Plotly.newPlot('npv-chart', chartData.data, chartData.layout);
}
</script>
{% endblock %}