reports: add PDF generation infra (fpdf2); Phone Book CSV/PDF export; Payments - Detailed report with preview and PDF grouped by deposit date; update Dockerfile for deps; smoke-tested in Docker

This commit is contained in:
HotSwapp
2025-10-07 17:30:50 -05:00
parent a4f47fce4f
commit f649b3c4f1
8 changed files with 346 additions and 1 deletions

View File

@@ -0,0 +1,73 @@
{% extends "base.html" %}
{% block title %}Payments - Detailed · Delphi Database{% endblock %}
{% block content %}
<div class="row g-3 align-items-center mb-3">
<div class="col-auto">
<h2 class="mb-0">Payments - Detailed</h2>
</div>
<div class="col ms-auto">
<form class="row g-2" method="get">
<div class="col-md-3">
<input type="date" class="form-control" name="from_date" value="{{ from_date or '' }}" placeholder="From">
</div>
<div class="col-md-3">
<input type="date" class="form-control" name="to_date" value="{{ to_date or '' }}" placeholder="To">
</div>
<div class="col-md-3">
<input type="text" class="form-control" name="file_no" value="{{ file_no or '' }}" placeholder="File #">
</div>
<div class="col-auto">
<button class="btn btn-outline-primary" type="submit"><i class="bi bi-search me-1"></i>Filter</button>
</div>
</form>
</div>
<div class="col-12 d-flex justify-content-end gap-2">
<a class="btn btn-outline-secondary btn-sm" href="/reports/payments-detailed?format=pdf{% if from_date %}&from_date={{ from_date }}{% endif %}{% if to_date %}&to_date={{ to_date }}{% endif %}{% if file_no %}&file_no={{ file_no | urlencode }}{% endif %}"><i class="bi bi-file-earmark-pdf me-1"></i>Download PDF</a>
</div>
</div>
{% if groups and groups|length > 0 %}
{% for group in groups %}
<div class="card mb-3">
<div class="card-header d-flex align-items-center">
<div class="fw-semibold">Deposit Date: {{ group.date }}</div>
<div class="ms-auto">Daily total: ${{ '%.2f'|format(group.total) }}</div>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-sm align-middle mb-0">
<thead class="table-light">
<tr>
<th style="width: 140px;">File #</th>
<th>Client</th>
<th style="width: 120px;">Type</th>
<th>Description</th>
<th class="text-end" style="width: 160px;">Amount</th>
</tr>
</thead>
<tbody>
{% for p in group.items %}
<tr>
<td>{{ p.case.file_no if p.case else '' }}</td>
<td>{% set client = p.case.client if p.case else None %}{% if client %}{{ client.last_name }}, {{ client.first_name }}{% else %}<span class="text-muted"></span>{% endif %}</td>
<td>{{ p.payment_type or '' }}</td>
<td>{{ p.description or '' }}</td>
<td class="text-end">${{ '%.2f'|format(p.amount or 0) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endfor %}
<div class="text-end fw-semibold">Overall total: ${{ '%.2f'|format(overall_total or 0) }}</div>
{% else %}
<div class="text-muted">No payments for selected filters.</div>
{% endif %}
{% endblock %}