fix: configure CI database connection properly
- Add dotenv loading to Django settings - Update CI workflow to use correct environment variables - Set POSTGRES_* variables instead of DATABASE_URL - Add environment variables to all Django management commands - Fixes CI test failures due to database connection issues
This commit is contained in:
@@ -1,19 +1,228 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}Destinatärunterstützungen - Administration{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<h1 class="h3"><i class="fas fa-hand-holding-usd me-2"></i>Destinatärunterstützungen</h1>
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-outline-primary" href="?format=csv"><i class="fas fa-file-csv me-2"></i>CSV exportieren</a>
|
||||
<a class="btn btn-outline-danger" href="?format=pdf"><i class="fas fa-file-pdf me-2"></i>PDF exportieren</a>
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exportModal">
|
||||
<i class="fas fa-download me-2"></i>Exportieren
|
||||
</button>
|
||||
<a class="btn btn-outline-success" href="{% url 'stiftung:unterstuetzung_create' %}">
|
||||
<i class="fas fa-plus me-2"></i>Neue Unterstützung
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Export Modal -->
|
||||
<div class="modal fade" id="exportModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Export Optionen</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<form id="exportForm" method="post" action="{% url 'stiftung:unterstuetzungen_list' %}">
|
||||
{% csrf_token %}
|
||||
<div class="modal-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h6 class="fw-bold">Export Format</h6>
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="format" id="format_csv" value="csv" checked>
|
||||
<label class="form-check-label" for="format_csv">
|
||||
<i class="fas fa-file-csv me-2"></i>CSV (Excel-kompatibel)
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="format" id="format_pdf" value="pdf">
|
||||
<label class="form-check-label" for="format_pdf">
|
||||
<i class="fas fa-file-pdf me-2"></i>PDF (Tabelle)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h6 class="fw-bold">Export Umfang</h6>
|
||||
<div class="mb-3">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="scope" id="scope_all" value="all" checked>
|
||||
<label class="form-check-label" for="scope_all">
|
||||
Alle Einträge (<span id="total-count">{{ unterstuetzungen|length }}</span>)
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="scope" id="scope_selected" value="selected">
|
||||
<label class="form-check-label" for="scope_selected">
|
||||
Nur ausgewählte Einträge (<span id="selected-count">0</span>)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6" id="field-selection" style="max-height: 400px; overflow-y: auto;">
|
||||
<h6 class="fw-bold">Felder auswählen</h6>
|
||||
<div class="mb-2">
|
||||
<button type="button" class="btn btn-sm btn-outline-primary me-2" onclick="selectAllFields()">Alle auswählen</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="selectDefaultFields()">Standard</button>
|
||||
</div>
|
||||
|
||||
<div class="field-groups">
|
||||
<!-- Core Payment Fields -->
|
||||
<div class="mb-3">
|
||||
<h6 class="text-primary mb-2">Zahlungsdaten</h6>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="destinataer_name" id="field_destinataer_name" checked>
|
||||
<label class="form-check-label" for="field_destinataer_name">Destinatär Name</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="betrag" id="field_betrag" checked>
|
||||
<label class="form-check-label" for="field_betrag">Betrag (€)</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="faellig_am" id="field_faellig_am" checked>
|
||||
<label class="form-check-label" for="field_faellig_am">Fällig am</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="status" id="field_status" checked>
|
||||
<label class="form-check-label" for="field_status">Status</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="beschreibung" id="field_beschreibung" checked>
|
||||
<label class="form-check-label" for="field_beschreibung">Beschreibung</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="ausgezahlt_am" id="field_ausgezahlt_am">
|
||||
<label class="form-check-label" for="field_ausgezahlt_am">Ausgezahlt am</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Payment Details -->
|
||||
<div class="mb-3">
|
||||
<h6 class="text-info mb-2">Überweisungsdetails</h6>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="empfaenger_iban" id="field_empfaenger_iban" checked>
|
||||
<label class="form-check-label" for="field_empfaenger_iban">Empfänger IBAN</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="empfaenger_name" id="field_empfaenger_name" checked>
|
||||
<label class="form-check-label" for="field_empfaenger_name">Empfänger Name</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="verwendungszweck" id="field_verwendungszweck">
|
||||
<label class="form-check-label" for="field_verwendungszweck">Verwendungszweck</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Account Information -->
|
||||
<div class="mb-3">
|
||||
<h6 class="text-success mb-2">Kontoinformationen</h6>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="konto_name" id="field_konto_name">
|
||||
<label class="form-check-label" for="field_konto_name">Konto</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="konto_bank" id="field_konto_bank">
|
||||
<label class="form-check-label" for="field_konto_bank">Bank</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="konto_iban" id="field_konto_iban">
|
||||
<label class="form-check-label" for="field_konto_iban">Konto IBAN</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Destinataer Personal Info -->
|
||||
<div class="mb-3">
|
||||
<h6 class="text-warning mb-2">Destinatär Details</h6>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="familienzweig" id="field_familienzweig">
|
||||
<label class="form-check-label" for="field_familienzweig">Familienzweig</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="geburtsdatum" id="field_geburtsdatum">
|
||||
<label class="form-check-label" for="field_geburtsdatum">Geburtsdatum</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="email" id="field_email">
|
||||
<label class="form-check-label" for="field_email">E-Mail</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="telefon" id="field_telefon">
|
||||
<label class="form-check-label" for="field_telefon">Telefon</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="adresse" id="field_adresse">
|
||||
<label class="form-check-label" for="field_adresse">Adresse</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Financial Information -->
|
||||
<div class="mb-3">
|
||||
<h6 class="text-danger mb-2">Finanzinformationen</h6>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="jaehrliches_einkommen" id="field_jaehrliches_einkommen">
|
||||
<label class="form-check-label" for="field_jaehrliches_einkommen">Jährliches Einkommen</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="monatliche_bezuege" id="field_monatliche_bezuege">
|
||||
<label class="form-check-label" for="field_monatliche_bezuege">Monatliche Bezüge</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="haushaltsgroesse" id="field_haushaltsgroesse">
|
||||
<label class="form-check-label" for="field_haushaltsgroesse">Haushaltsgröße</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="vermoegen" id="field_vermoegen">
|
||||
<label class="form-check-label" for="field_vermoegen">Vermögen</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- System Fields -->
|
||||
<div class="mb-3">
|
||||
<h6 class="text-secondary mb-2">System & Verlauf</h6>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="erstellt_am" id="field_erstellt_am">
|
||||
<label class="form-check-label" for="field_erstellt_am">Erstellt am</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="ausgezahlt_von" id="field_ausgezahlt_von">
|
||||
<label class="form-check-label" for="field_ausgezahlt_von">Ausgezahlt von</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="ist_wiederkehrend" id="field_ist_wiederkehrend">
|
||||
<label class="form-check-label" for="field_ist_wiederkehrend">Wiederkehrend</label>
|
||||
</div>
|
||||
<div class="form-check form-check-sm">
|
||||
<input class="form-check-input field-checkbox" type="checkbox" name="fields" value="id" id="field_id">
|
||||
<label class="form-check-label" for="field_id">ID</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-download me-2"></i>Exportieren
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="selectAll" onchange="toggleAllCheckboxes()">
|
||||
</div>
|
||||
</th>
|
||||
<th>Destinatär</th>
|
||||
<th>Bank</th>
|
||||
<th>IBAN</th>
|
||||
@@ -28,13 +237,27 @@
|
||||
<tbody>
|
||||
{% for u in unterstuetzungen %}
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input entry-checkbox" type="checkbox" name="selected_entries" value="{{ u.id }}" onchange="updateSelectedCount()">
|
||||
</div>
|
||||
</td>
|
||||
<td>{{ u.destinataer.get_full_name }}</td>
|
||||
<td>{{ u.konto.bank_name }}</td>
|
||||
<td>{{ u.konto.iban }}</td>
|
||||
<td>€{{ u.betrag|floatformat:2 }}</td>
|
||||
<td>{{ u.konto }}</td>
|
||||
<td>{{ u.faellig_am|date:"d.m.Y" }}</td>
|
||||
<td><span class="badge bg-secondary">{{ u.get_status_display }}</span></td>
|
||||
<td>
|
||||
<span class="badge
|
||||
{% if u.status == 'ausgezahlt' %}bg-success
|
||||
{% elif u.status == 'faellig' %}bg-warning
|
||||
{% elif u.status == 'in_bearbeitung' %}bg-info
|
||||
{% elif u.status == 'storniert' %}bg-danger
|
||||
{% else %}bg-secondary{% endif %}">
|
||||
{{ u.get_status_display }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ u.beschreibung }}</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
@@ -44,12 +267,165 @@
|
||||
</td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr><td colspan="6" class="text-center text-muted">Keine Einträge</td></tr>
|
||||
<tr><td colspan="10" class="text-center text-muted">Keine Einträge</td></tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Field selection functions
|
||||
function selectAllFields() {
|
||||
document.querySelectorAll('.field-checkbox').forEach(checkbox => {
|
||||
checkbox.checked = true;
|
||||
});
|
||||
}
|
||||
|
||||
function selectDefaultFields() {
|
||||
// Uncheck all first
|
||||
document.querySelectorAll('.field-checkbox').forEach(checkbox => {
|
||||
checkbox.checked = false;
|
||||
});
|
||||
|
||||
// Check default fields
|
||||
const defaultFields = [
|
||||
'destinataer_name', 'betrag', 'faellig_am', 'status',
|
||||
'empfaenger_iban', 'empfaenger_name', 'beschreibung'
|
||||
];
|
||||
|
||||
defaultFields.forEach(fieldName => {
|
||||
const checkbox = document.getElementById('field_' + fieldName);
|
||||
if (checkbox) checkbox.checked = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Bulk selection functions
|
||||
function toggleAllCheckboxes() {
|
||||
const selectAll = document.getElementById('selectAll');
|
||||
const checkboxes = document.querySelectorAll('.entry-checkbox');
|
||||
|
||||
checkboxes.forEach(checkbox => {
|
||||
checkbox.checked = selectAll.checked;
|
||||
});
|
||||
|
||||
updateSelectedCount();
|
||||
}
|
||||
|
||||
function updateSelectedCount() {
|
||||
const selectedCheckboxes = document.querySelectorAll('.entry-checkbox:checked');
|
||||
const count = selectedCheckboxes.length;
|
||||
|
||||
document.getElementById('selected-count').textContent = count;
|
||||
|
||||
// Update the select all checkbox state
|
||||
const selectAll = document.getElementById('selectAll');
|
||||
const allCheckboxes = document.querySelectorAll('.entry-checkbox');
|
||||
|
||||
if (count === 0) {
|
||||
selectAll.indeterminate = false;
|
||||
selectAll.checked = false;
|
||||
} else if (count === allCheckboxes.length) {
|
||||
selectAll.indeterminate = false;
|
||||
selectAll.checked = true;
|
||||
} else {
|
||||
selectAll.indeterminate = true;
|
||||
}
|
||||
|
||||
// Enable/disable the "selected only" radio button
|
||||
const scopeSelected = document.getElementById('scope_selected');
|
||||
const scopeSelectedLabel = scopeSelected.parentElement.querySelector('label');
|
||||
|
||||
if (count > 0) {
|
||||
scopeSelected.disabled = false;
|
||||
scopeSelectedLabel.classList.remove('text-muted');
|
||||
} else {
|
||||
scopeSelected.disabled = true;
|
||||
scopeSelected.checked = false;
|
||||
document.getElementById('scope_all').checked = true;
|
||||
scopeSelectedLabel.classList.add('text-muted');
|
||||
}
|
||||
}
|
||||
|
||||
// Export form handling
|
||||
document.getElementById('exportForm').addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(this);
|
||||
const format = formData.get('format');
|
||||
const scope = formData.get('scope');
|
||||
|
||||
// Build query string for GET request with format
|
||||
const params = new URLSearchParams();
|
||||
params.append('format', format);
|
||||
|
||||
// Add selected fields to the URL
|
||||
formData.getAll('fields').forEach(field => {
|
||||
params.append('fields', field);
|
||||
});
|
||||
|
||||
// If scope is "selected", we need to POST the selected IDs
|
||||
if (scope === 'selected') {
|
||||
const selectedIds = [];
|
||||
document.querySelectorAll('.entry-checkbox:checked').forEach(checkbox => {
|
||||
selectedIds.push(checkbox.value);
|
||||
});
|
||||
|
||||
if (selectedIds.length === 0) {
|
||||
alert('Bitte wählen Sie mindestens einen Eintrag aus.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a temporary form for POST request
|
||||
const tempForm = document.createElement('form');
|
||||
tempForm.method = 'POST';
|
||||
tempForm.action = window.location.pathname + '?' + params.toString();
|
||||
tempForm.style.display = 'none';
|
||||
|
||||
// Add CSRF token
|
||||
const csrfToken = document.querySelector('[name=csrfmiddlewaretoken]').value;
|
||||
const csrfInput = document.createElement('input');
|
||||
csrfInput.type = 'hidden';
|
||||
csrfInput.name = 'csrfmiddlewaretoken';
|
||||
csrfInput.value = csrfToken;
|
||||
tempForm.appendChild(csrfInput);
|
||||
|
||||
// Add selected IDs
|
||||
selectedIds.forEach(id => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'selected_entries';
|
||||
input.value = id;
|
||||
tempForm.appendChild(input);
|
||||
});
|
||||
|
||||
// Add fields
|
||||
formData.getAll('fields').forEach(field => {
|
||||
const input = document.createElement('input');
|
||||
input.type = 'hidden';
|
||||
input.name = 'fields';
|
||||
input.value = field;
|
||||
tempForm.appendChild(input);
|
||||
});
|
||||
|
||||
document.body.appendChild(tempForm);
|
||||
tempForm.submit();
|
||||
document.body.removeChild(tempForm);
|
||||
} else {
|
||||
// For "all" scope, use GET request
|
||||
window.location.href = window.location.pathname + '?' + params.toString();
|
||||
}
|
||||
|
||||
// Close modal
|
||||
bootstrap.Modal.getInstance(document.getElementById('exportModal')).hide();
|
||||
});
|
||||
|
||||
// Initialize counts on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateSelectedCount();
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user