407 lines
20 KiB
HTML
407 lines
20 KiB
HTML
{% extends 'base.html' %}
|
|
{% load humanize %}
|
|
|
|
{% block title %}Ausgaben - {{ rentmeister.get_full_name }} - van Hees-Theyssen-Vogel'sche Stiftung{% endblock %}
|
|
|
|
{% block content %}
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="d-sm-flex align-items-center justify-content-between mb-4">
|
|
<h1 class="h3 mb-0 text-gray-800">
|
|
<i class="fas fa-file-invoice-dollar me-2"></i>Ausgaben - {{ rentmeister.get_full_name }}
|
|
</h1>
|
|
<div class="btn-group" role="group">
|
|
<a href="{% url 'stiftung:rentmeister_detail' rentmeister.pk %}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-arrow-left me-1"></i>Zurück zu Details
|
|
</a>
|
|
<a href="{% url 'stiftung:verwaltungskosten_create' %}?rentmeister={{ rentmeister.pk }}" class="btn btn-success">
|
|
<i class="fas fa-plus me-1"></i>Neue Ausgabe
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Statistiken -->
|
|
<div class="row mb-4">
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card border-left-secondary shadow h-100 py-2">
|
|
<div class="card-body">
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-secondary text-uppercase mb-1">Gesamt</div>
|
|
<div class="h5 mb-0 font-weight-bold text-gray-800">{{ stats.total_count|default:0 }}</div>
|
|
<div class="small text-success">€{{ stats.total_amount|default:0|floatformat:2 }}</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<i class="fas fa-file-invoice fa-2x text-gray-300"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card border-left-warning shadow h-100 py-2">
|
|
<div class="card-body">
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-warning text-uppercase mb-1">Geplant</div>
|
|
<div class="h5 mb-0 font-weight-bold text-gray-800">{{ stats.geplant_count|default:0 }}</div>
|
|
<div class="small text-warning">€{{ stats.geplant_amount|default:0|floatformat:2 }}</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<i class="fas fa-clock fa-2x text-gray-300"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card border-left-primary shadow h-100 py-2">
|
|
<div class="card-body">
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-primary text-uppercase mb-1">In Bearbeitung</div>
|
|
<div class="h5 mb-0 font-weight-bold text-gray-800">{{ stats.in_bearbeitung_count|default:0 }}</div>
|
|
<div class="small text-primary">€{{ stats.in_bearbeitung_amount|default:0|floatformat:2 }}</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<i class="fas fa-cogs fa-2x text-gray-300"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card border-left-success shadow h-100 py-2">
|
|
<div class="card-body">
|
|
<div class="row no-gutters align-items-center">
|
|
<div class="col mr-2">
|
|
<div class="text-xs font-weight-bold text-success text-uppercase mb-1">Bezahlt</div>
|
|
<div class="h5 mb-0 font-weight-bold text-gray-800">{{ stats.bezahlt_count|default:0 }}</div>
|
|
<div class="small text-success">€{{ stats.bezahlt_amount|default:0|floatformat:2 }}</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<i class="fas fa-check-circle fa-2x text-gray-300"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<form method="post" id="expenseForm">
|
|
{% csrf_token %}
|
|
|
|
<!-- Geplante Ausgaben -->
|
|
{% if ausgaben_by_status.geplant.ausgaben %}
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card shadow">
|
|
<div class="card-header py-3 d-flex justify-content-between align-items-center">
|
|
<h6 class="m-0 font-weight-bold text-warning">
|
|
<i class="fas fa-clock me-2"></i>Geplante Ausgaben ({{ ausgaben_by_status.geplant.ausgaben.count }})
|
|
</h6>
|
|
<div>
|
|
<span class="badge bg-warning">€{{ ausgaben_by_status.geplant.total|floatformat:2 }}</span>
|
|
<button type="button" class="btn btn-sm btn-outline-warning ms-2" onclick="toggleSection('geplant')">
|
|
<i class="fas fa-eye"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body" id="section-geplant">
|
|
<div class="mb-3 d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<button type="button" class="btn btn-sm btn-outline-primary" onclick="selectAll('geplant')">
|
|
<i class="fas fa-check-square me-1"></i>Alle auswählen
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="deselectAll('geplant')">
|
|
<i class="fas fa-square me-1"></i>Abwählen
|
|
</button>
|
|
</div>
|
|
<button type="submit" name="export_pdf" class="btn btn-primary" onclick="return validateSelection()">
|
|
<i class="fas fa-file-pdf me-1"></i>Ausgewählte für Zahlung exportieren
|
|
</button>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th width="30">
|
|
<input type="checkbox" class="form-check-input" onchange="toggleAllInStatus('geplant', this.checked)">
|
|
</th>
|
|
<th>Datum</th>
|
|
<th>Bezeichnung</th>
|
|
<th>Kategorie</th>
|
|
<th>Betrag</th>
|
|
<th>Lieferant</th>
|
|
<th>Aktionen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for ausgabe in ausgaben_by_status.geplant.ausgaben %}
|
|
<tr>
|
|
<td>
|
|
<input type="checkbox" name="selected_expenses" value="{{ ausgabe.pk }}"
|
|
class="form-check-input expense-checkbox status-geplant">
|
|
</td>
|
|
<td>{{ ausgabe.datum|date:"d.m.Y" }}</td>
|
|
<td>
|
|
<strong>{{ ausgabe.bezeichnung }}</strong>
|
|
{% if ausgabe.beschreibung %}
|
|
<br><small class="text-muted">{{ ausgabe.beschreibung|truncatechars:50 }}</small>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-secondary">{{ ausgabe.get_kategorie_display }}</span>
|
|
</td>
|
|
<td class="text-end">
|
|
<strong>€{{ ausgabe.betrag|floatformat:2 }}</strong>
|
|
</td>
|
|
<td>{{ ausgabe.lieferant_firma|default:"-" }}</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm">
|
|
<a href="{% url 'stiftung:verwaltungskosten_edit' ausgabe.pk %}"
|
|
class="btn btn-outline-warning" title="Bearbeiten">
|
|
<i class="fas fa-edit"></i>
|
|
</a>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- In Bearbeitung -->
|
|
{% if ausgaben_by_status.in_bearbeitung.ausgaben %}
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card shadow">
|
|
<div class="card-header py-3 d-flex justify-content-between align-items-center">
|
|
<h6 class="m-0 font-weight-bold text-primary">
|
|
<i class="fas fa-cogs me-2"></i>In Bearbeitung ({{ ausgaben_by_status.in_bearbeitung.ausgaben.count }})
|
|
</h6>
|
|
<div>
|
|
<span class="badge bg-primary">€{{ ausgaben_by_status.in_bearbeitung.total|floatformat:2 }}</span>
|
|
<button type="button" class="btn btn-sm btn-outline-primary ms-2" onclick="toggleSection('in_bearbeitung')">
|
|
<i class="fas fa-eye"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body" id="section-in_bearbeitung" style="display: none;">
|
|
<div class="alert alert-info">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
Diese Ausgaben wurden bereits für die Zahlung exportiert und befinden sich in Bearbeitung.
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Datum</th>
|
|
<th>Bezeichnung</th>
|
|
<th>Kategorie</th>
|
|
<th>Betrag</th>
|
|
<th>Status</th>
|
|
<th>Aktionen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for ausgabe in ausgaben_by_status.in_bearbeitung.ausgaben %}
|
|
<tr>
|
|
<td>{{ ausgabe.datum|date:"d.m.Y" }}</td>
|
|
<td>
|
|
<strong>{{ ausgabe.bezeichnung }}</strong>
|
|
{% if ausgabe.beschreibung %}
|
|
<br><small class="text-muted">{{ ausgabe.beschreibung|truncatechars:50 }}</small>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-secondary">{{ ausgabe.get_kategorie_display }}</span>
|
|
</td>
|
|
<td class="text-end">
|
|
<strong>€{{ ausgabe.betrag|floatformat:2 }}</strong>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-primary">In Bearbeitung</span>
|
|
</td>
|
|
<td>
|
|
<div class="btn-group btn-group-sm">
|
|
<button type="button" class="btn btn-outline-success"
|
|
onclick="markAsPaid('{{ ausgabe.pk }}')"
|
|
title="Als bezahlt markieren">
|
|
<i class="fas fa-check"></i>
|
|
</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Bezahlte Ausgaben -->
|
|
{% if ausgaben_by_status.bezahlt.ausgaben %}
|
|
<div class="row mb-4">
|
|
<div class="col-12">
|
|
<div class="card shadow">
|
|
<div class="card-header py-3 d-flex justify-content-between align-items-center">
|
|
<h6 class="m-0 font-weight-bold text-success">
|
|
<i class="fas fa-check-circle me-2"></i>Bezahlte Ausgaben ({{ ausgaben_by_status.bezahlt.ausgaben.count }})
|
|
</h6>
|
|
<div>
|
|
<span class="badge bg-success">€{{ ausgaben_by_status.bezahlt.total|floatformat:2 }}</span>
|
|
<button type="button" class="btn btn-sm btn-outline-success ms-2" onclick="toggleSection('bezahlt')">
|
|
<i class="fas fa-eye"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="card-body" id="section-bezahlt" style="display: none;">
|
|
<div class="table-responsive">
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr>
|
|
<th>Datum</th>
|
|
<th>Bezeichnung</th>
|
|
<th>Kategorie</th>
|
|
<th>Betrag</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for ausgabe in ausgaben_by_status.bezahlt.ausgaben %}
|
|
<tr>
|
|
<td>{{ ausgabe.datum|date:"d.m.Y" }}</td>
|
|
<td>
|
|
<strong>{{ ausgabe.bezeichnung }}</strong>
|
|
{% if ausgabe.beschreibung %}
|
|
<br><small class="text-muted">{{ ausgabe.beschreibung|truncatechars:50 }}</small>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-secondary">{{ ausgabe.get_kategorie_display }}</span>
|
|
</td>
|
|
<td class="text-end">
|
|
<strong>€{{ ausgabe.betrag|floatformat:2 }}</strong>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-success">Bezahlt</span>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Keine Ausgaben -->
|
|
{% if not ausgaben_by_status.geplant.ausgaben and not ausgaben_by_status.in_bearbeitung.ausgaben and not ausgaben_by_status.bezahlt.ausgaben %}
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card shadow">
|
|
<div class="card-body text-center py-5">
|
|
<i class="fas fa-file-invoice fa-3x text-muted mb-3"></i>
|
|
<h5 class="text-muted">Noch keine Ausgaben vorhanden</h5>
|
|
<p class="text-muted">Legen Sie die erste Ausgabe für {{ rentmeister.get_full_name }} an.</p>
|
|
<a href="{% url 'stiftung:verwaltungskosten_create' %}?rentmeister={{ rentmeister.pk }}" class="btn btn-primary">
|
|
<i class="fas fa-plus me-1"></i>Erste Ausgabe anlegen
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</form>
|
|
|
|
|
|
<script>
|
|
function toggleSection(statusId) {
|
|
const section = document.getElementById('section-' + statusId);
|
|
if (section.style.display === 'none') {
|
|
section.style.display = 'block';
|
|
} else {
|
|
section.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
function selectAll(status) {
|
|
const checkboxes = document.querySelectorAll('.status-' + status);
|
|
checkboxes.forEach(cb => cb.checked = true);
|
|
}
|
|
|
|
function deselectAll(status) {
|
|
const checkboxes = document.querySelectorAll('.status-' + status);
|
|
checkboxes.forEach(cb => cb.checked = false);
|
|
}
|
|
|
|
function toggleAllInStatus(status, checked) {
|
|
const checkboxes = document.querySelectorAll('.status-' + status);
|
|
checkboxes.forEach(cb => cb.checked = checked);
|
|
}
|
|
|
|
function validateSelection() {
|
|
const selected = document.querySelectorAll('input[name="selected_expenses"]:checked');
|
|
if (selected.length === 0) {
|
|
alert('Bitte wählen Sie mindestens eine Ausgabe für den Export aus.');
|
|
return false;
|
|
}
|
|
|
|
const confirmed = confirm(`${selected.length} Ausgaben werden für die Zahlung exportiert und auf "In Bearbeitung" gesetzt. Fortfahren?`);
|
|
return confirmed;
|
|
}
|
|
|
|
function markAsPaid(expenseId) {
|
|
if (confirm('Diese Ausgabe als bezahlt markieren?')) {
|
|
// Create a form to mark as paid
|
|
const form = document.createElement('form');
|
|
form.method = 'POST';
|
|
form.action = '{% url "stiftung:mark_expense_paid" %}';
|
|
|
|
const csrfToken = document.createElement('input');
|
|
csrfToken.type = 'hidden';
|
|
csrfToken.name = 'csrfmiddlewaretoken';
|
|
csrfToken.value = document.querySelector('[name=csrfmiddlewaretoken]').value;
|
|
|
|
const expenseInput = document.createElement('input');
|
|
expenseInput.type = 'hidden';
|
|
expenseInput.name = 'expense_id';
|
|
expenseInput.value = expenseId;
|
|
|
|
form.appendChild(csrfToken);
|
|
form.appendChild(expenseInput);
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
}
|
|
}
|
|
|
|
// Show geplant section by default
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const geplantSection = document.getElementById('section-geplant');
|
|
if (geplantSection) {
|
|
geplantSection.style.display = 'block';
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|
|
|