Files
stiftung-management-system/app/templates/stiftung/import_export_hub.html
SysAdmin Agent e0b377014c
Some checks failed
CI/CD Pipeline / test (push) Has been cancelled
CI/CD Pipeline / deploy (push) Has been cancelled
Code Quality / quality (push) Has been cancelled
v4.1.0: DMS email documents, category-specific Nachweis linking, version system
- Save cover email body as DMS document with new 'email' context type
- Show email body separately from attachments in email detail view
- Add per-category DMS document assignment in quarterly confirmation
  (Studiennachweis, Einkommenssituation, Vermögenssituation)
- Add VERSION file and context processor for automatic version display
- Add MCP server, agent system, import/export, and new migrations
- Update compose files and production environment template

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 18:48:52 +00:00

188 lines
10 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends 'base.html' %}
{% block title %}Daten Import & Export - Stiftungsverwaltung{% endblock %}
{% block content %}
<div class="row">
<div class="col-12">
<div class="d-flex justify-content-between align-items-center mb-4">
<h1><i class="fas fa-exchange-alt text-primary"></i> Daten Import & Export</h1>
</div>
<!-- Export Section -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-success text-white">
<h5 class="card-title mb-0">
<i class="fas fa-download"></i> CSV Export
</h5>
</div>
<div class="card-body">
<p class="text-muted mb-3">Exportieren Sie beliebige Daten als CSV-Datei (Semikolon-getrennt, UTF-8 mit BOM für Excel-Kompatibilität).</p>
<div class="row">
{% for et in export_types %}
<div class="col-md-4 col-lg-3 mb-3">
<div class="card h-100 border">
<div class="card-body text-center">
<h6 class="card-title">{{ et.label }}</h6>
<p class="text-muted small mb-2">{{ et.count }} Datensätze</p>
<a href="{% url 'stiftung:csv_export' %}?type={{ et.key }}"
class="btn btn-outline-success btn-sm {% if et.count == 0 %}disabled{% endif %}">
<i class="fas fa-download"></i> Exportieren
</a>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Import Section -->
<div class="card shadow-sm mb-4">
<div class="card-header bg-primary text-white">
<h5 class="card-title mb-0">
<i class="fas fa-upload"></i> CSV Import
</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-lg-8">
<p class="text-muted mb-3">Importieren Sie Daten aus CSV-Dateien. Im nächsten Schritt können Sie die Spalten Ihrer CSV-Datei den Datenbankfeldern zuordnen.</p>
<form method="post" action="{% url 'stiftung:csv_import_upload' %}" enctype="multipart/form-data">
{% csrf_token %}
<div class="row">
<div class="col-md-5 mb-3">
<label for="import_type" class="form-label"><strong>Import-Typ</strong></label>
<select name="import_type" id="import_type" class="form-select" required>
<option value="">Bitte wählen...</option>
{% for it in import_types %}
<option value="{{ it.key }}">{{ it.label }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-5 mb-3">
<label for="csv_file" class="form-label"><strong>CSV-Datei</strong></label>
<input type="file" name="csv_file" id="csv_file" class="form-control" accept=".csv" required>
</div>
<div class="col-md-2 mb-3 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-arrow-right"></i> Weiter
</button>
</div>
</div>
</form>
</div>
<div class="col-lg-4">
<div class="alert alert-info mb-0">
<h6><i class="fas fa-info-circle"></i> Hinweise</h6>
<ul class="small mb-0">
<li>Unterstützte Formate: CSV (Komma oder Semikolon)</li>
<li>Zeichenkodierung: UTF-8 oder Latin-1</li>
<li>Datumsformate: TT.MM.JJJJ oder JJJJ-MM-TT</li>
<li>Bestehende Datensätze werden anhand eindeutiger Felder aktualisiert</li>
<li>Im nächsten Schritt ordnen Sie CSV-Spalten den Feldern zu</li>
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Recent Imports -->
{% if recent_imports %}
<div class="card shadow-sm">
<div class="card-header bg-light">
<h5 class="card-title mb-0">
<i class="fas fa-history"></i> Letzte Imports
</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover table-sm">
<thead class="table-light">
<tr>
<th>Typ</th>
<th>Dateiname</th>
<th>Status</th>
<th>Ergebnis</th>
<th>Benutzer</th>
<th>Datum</th>
<th>Details</th>
</tr>
</thead>
<tbody>
{% for imp in recent_imports %}
<tr>
<td><span class="badge bg-primary">{{ imp.get_import_type_display }}</span></td>
<td>{{ imp.filename }}</td>
<td>
{% if imp.status == 'completed' %}
<span class="badge bg-success"><i class="fas fa-check"></i> OK</span>
{% elif imp.status == 'partial' %}
<span class="badge bg-warning"><i class="fas fa-exclamation-triangle"></i> Teilweise</span>
{% elif imp.status == 'failed' %}
<span class="badge bg-danger"><i class="fas fa-times"></i> Fehler</span>
{% elif imp.status == 'processing' %}
<span class="badge bg-info"><i class="fas fa-spinner fa-spin"></i> Läuft</span>
{% else %}
<span class="badge bg-secondary">{{ imp.get_status_display }}</span>
{% endif %}
</td>
<td>
{% if imp.total_rows > 0 %}
<small>{{ imp.imported_rows }}/{{ imp.total_rows }} importiert</small>
{% if imp.failed_rows > 0 %}
<small class="text-danger">({{ imp.failed_rows }} fehlgeschlagen)</small>
{% endif %}
{% else %}
<small class="text-muted">-</small>
{% endif %}
</td>
<td><small>{{ imp.created_by|default:"-" }}</small></td>
<td><small>{{ imp.started_at|date:"d.m.Y H:i" }}</small></td>
<td>
{% if imp.error_log %}
<button type="button" class="btn btn-outline-warning btn-sm"
data-bs-toggle="modal" data-bs-target="#errorModal{{ imp.id }}">
<i class="fas fa-eye"></i>
</button>
{% endif %}
</td>
</tr>
{% if imp.error_log %}
<div class="modal fade" id="errorModal{{ imp.id }}" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header bg-warning text-dark">
<h5 class="modal-title">
<i class="fas fa-exclamation-triangle"></i> Fehlerprotokoll {{ imp.filename }}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="alert alert-info">
<strong>{{ imp.imported_rows }}</strong> importiert,
<strong>{{ imp.failed_rows }}</strong> fehlgeschlagen
von <strong>{{ imp.total_rows }}</strong> Zeilen.
</div>
<pre class="bg-light p-3 rounded" style="max-height: 400px; overflow-y: auto;"><code>{{ imp.error_log }}</code></pre>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
</div>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endif %}
</div>
</div>
{% endblock %}