Enhanced quarterly confirmation system with approval workflow and export improvements
Features added: - ✅ Fixed quarterly confirmation approval system with URL pattern - ✅ Added re-approval and status reset functionality for quarterly confirmations - ✅ Synchronized quarterly approval status with support payment system - ✅ Enhanced Destinataer export with missing fields (anrede, titel, mobil) - ✅ Added quarterly confirmation data and documents to export system - ✅ Fixed address field display issues in destinataer template - ✅ Added quarterly statistics dashboard to support payment lists - ✅ Implemented duplicate support payment prevention and cleanup - ✅ Added visual indicators for quarterly-linked support payments Technical improvements: - Enhanced create_quarterly_support_payment() with duplicate detection - Added get_related_support_payment() method to VierteljahresNachweis model - Improved quarterly confirmation workflow with proper status transitions - Added computed address property to Destinataer model - Fixed template field mismatches (anrede, titel, mobil vs strasse, plz, ort) - Enhanced backup system with operation tracking and cancellation Workflow enhancements: - Quarterly confirmations now properly sync with support payments - Single support payment per destinataer per quarter (no duplicates) - Approval button works for both eingereicht and geprueft status - Reset functionality allows workflow restart - Export includes complete quarterly data with uploaded documents
This commit is contained in:
@@ -101,6 +101,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Erstellt</th>
|
||||
<th>Vorgang</th>
|
||||
<th>Typ</th>
|
||||
<th>Status</th>
|
||||
<th>Größe</th>
|
||||
@@ -117,10 +118,19 @@
|
||||
<small class="text-muted">{{ backup.created_at|date:"H:i:s" }}</small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-info">{{ backup.get_backup_type_display }}</span>
|
||||
<span class="badge bg-{% if backup.operation == 'backup' %}info{% else %}warning{% endif %}">
|
||||
{% if backup.operation == 'backup' %}
|
||||
<i class="fas fa-save me-1"></i>Backup
|
||||
{% else %}
|
||||
<i class="fas fa-undo me-1"></i>Restore
|
||||
{% endif %}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-{% if backup.status == 'completed' %}success{% elif backup.status == 'failed' %}danger{% elif backup.status == 'running' %}primary{% else %}secondary{% endif %}">
|
||||
<span class="badge bg-secondary">{{ backup.get_backup_type_display }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-{% if backup.status == 'completed' %}success{% elif backup.status == 'failed' %}danger{% elif backup.status == 'running' %}primary{% elif backup.status == 'cancelled' %}warning{% else %}secondary{% endif %}">
|
||||
{{ backup.get_status_display }}
|
||||
</span>
|
||||
{% if backup.status == 'running' %}
|
||||
@@ -153,7 +163,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if backup.status == 'completed' %}
|
||||
{% if backup.status == 'completed' and backup.operation == 'backup' %}
|
||||
<a href="{% url 'stiftung:backup_download' backup.id %}" class="btn btn-outline-primary btn-sm" title="Herunterladen">
|
||||
<i class="fas fa-download"></i>
|
||||
</a>
|
||||
@@ -162,9 +172,27 @@
|
||||
<i class="fas fa-exclamation-triangle"></i>
|
||||
</button>
|
||||
{% elif backup.status == 'running' %}
|
||||
<button class="btn btn-outline-primary btn-sm" disabled title="Läuft...">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
</button>
|
||||
<div class="btn-group" role="group">
|
||||
<button class="btn btn-outline-primary btn-sm" disabled title="Läuft...">
|
||||
<i class="fas fa-spinner fa-spin"></i>
|
||||
</button>
|
||||
{% if backup.created_by == request.user or request.user.is_staff %}
|
||||
<a href="{% url 'stiftung:backup_cancel' backup.id %}"
|
||||
class="btn btn-outline-danger btn-sm"
|
||||
onclick="return confirm('Sind Sie sicher, dass Sie diesen Backup-Job abbrechen möchten?')"
|
||||
title="Abbrechen">
|
||||
<i class="fas fa-times"></i>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% elif backup.status == 'cancelled' %}
|
||||
<span class="badge bg-warning" title="Abgebrochen">
|
||||
<i class="fas fa-ban"></i> Abgebrochen
|
||||
</span>
|
||||
{% elif backup.status == 'completed' and backup.operation == 'restore' %}
|
||||
<span class="badge bg-success" title="Wiederherstellung abgeschlossen">
|
||||
<i class="fas fa-check"></i> Fertig
|
||||
</span>
|
||||
{% else %}
|
||||
<span class="text-muted">-</span>
|
||||
{% endif %}
|
||||
|
||||
@@ -198,7 +198,17 @@
|
||||
<em class="text-muted">Nicht angegeben</em>
|
||||
{% endif %}
|
||||
</span>
|
||||
<textarea name="adresse" class="form-control edit-mode" style="display: none;" rows="3" placeholder="Straße Nr. PLZ Ort">{{ destinataer.adresse }}</textarea>
|
||||
<div class="edit-mode" style="display: none;">
|
||||
<input name="strasse" class="form-control mb-2" placeholder="Straße" value="{{ destinataer.strasse|default:'' }}">
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<input name="plz" class="form-control" placeholder="PLZ" value="{{ destinataer.plz|default:'' }}">
|
||||
</div>
|
||||
<div class="col-8">
|
||||
<input name="ort" class="form-control" placeholder="Ort" value="{{ destinataer.ort|default:'' }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -592,13 +602,28 @@
|
||||
title="Bearbeiten (Vollbild)">
|
||||
<i class="fas fa-external-link-alt"></i>
|
||||
</a>
|
||||
{% if nachweis.status == 'eingereicht' and user.is_staff %}
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-success"
|
||||
onclick="approveQuarterly('{{ nachweis.id }}')"
|
||||
title="Freigeben">
|
||||
<i class="fas fa-check"></i>
|
||||
</button>
|
||||
{% if user.is_staff %}
|
||||
{% if nachweis.status == 'eingereicht' %}
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-success"
|
||||
onclick="approveQuarterly('{{ nachweis.id }}')"
|
||||
title="Freigeben">
|
||||
<i class="fas fa-check"></i>
|
||||
</button>
|
||||
{% elif nachweis.status == 'geprueft' %}
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-success"
|
||||
onclick="approveQuarterly('{{ nachweis.id }}')"
|
||||
title="Erneut freigeben / Unterstützung synchronisieren">
|
||||
<i class="fas fa-sync"></i>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="btn btn-sm btn-outline-warning"
|
||||
onclick="resetQuarterly('{{ nachweis.id }}')"
|
||||
title="Status zurücksetzen">
|
||||
<i class="fas fa-undo"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
@@ -1353,5 +1378,28 @@ function approveQuarterly(nachweisId) {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function resetQuarterly(nachweisId) {
|
||||
if (confirm('Möchten Sie den Status dieses Vierteljahresnachweis wirklich zurücksetzen?')) {
|
||||
fetch(`/quarterly-confirmations/${nachweisId}/reset/`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
location.reload(); // Reload to show updated status
|
||||
} else {
|
||||
alert('Fehler beim Zurücksetzen des Nachweises.');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Fehler beim Zurücksetzen des Nachweises.');
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -65,51 +65,79 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stats and Chart -->
|
||||
<!-- Charts Row -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-lg-6 mb-3">
|
||||
<div class="card shadow h-100">
|
||||
<!-- Usage Chart -->
|
||||
<div class="col-lg-4 mb-3">
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">
|
||||
<i class="fas fa-percentage me-2"></i>Flächennutzung (aktuelle Auswahl)
|
||||
<i class="fas fa-percentage me-2"></i>Flächennutzung
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row text-center">
|
||||
<div class="row text-center mb-3">
|
||||
<div class="col-4">
|
||||
<div class="h4 mb-0">{{ stats.pct_wald|default:0 }}%</div>
|
||||
<div class="text-muted">Wald</div>
|
||||
<div class="h6 mb-0 text-success">{{ stats.pct_wald|default:0 }}%</div>
|
||||
<div class="small text-muted">Wald</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="h4 mb-0">{{ stats.pct_acker|default:0 }}%</div>
|
||||
<div class="text-muted">Acker</div>
|
||||
<div class="h6 mb-0 text-info">{{ stats.pct_acker|default:0 }}%</div>
|
||||
<div class="small text-muted">Acker</div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div class="h4 mb-0">{{ stats.pct_gruenland|default:0 }}%</div>
|
||||
<div class="text-muted">Grünland</div>
|
||||
<div class="h6 mb-0 text-warning">{{ stats.pct_gruenland|default:0 }}%</div>
|
||||
<div class="small text-muted">Grünland</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3 small text-muted text-center">
|
||||
Gesamt (Nutzungsarten): {{ stats.sum_total_use_qm|floatformat:0 }} qm
|
||||
</div>
|
||||
<div class="mt-3" style="height:200px">
|
||||
<div style="height: 200px;">
|
||||
<canvas id="usageChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-6 mb-3">
|
||||
|
||||
<!-- Sizes Chart -->
|
||||
<div class="col-lg-4 mb-3">
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3 d-flex justify-content-between align-items-center">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">
|
||||
<i class="fas fa-chart-bar me-2"></i>Größen der Grundstücke (Top 30)
|
||||
<i class="fas fa-chart-bar me-2"></i>Größen (Top 30)
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div style="height: 140px; overflow: hidden;">
|
||||
<div id="sizesChart" style="display: flex; align-items: end; height: 100%; gap: 2px; padding: 5px;">
|
||||
<!-- Simple CSS bar chart will be populated by JavaScript -->
|
||||
<div class="text-center mb-3">
|
||||
<div class="h6 mb-0">{{ stats.total_plots }}</div>
|
||||
<div class="small text-muted">Grundstücke gesamt</div>
|
||||
</div>
|
||||
<div style="height: 200px;">
|
||||
<canvas id="sizesChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Verpachtung Chart -->
|
||||
<div class="col-lg-4 mb-3">
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">
|
||||
<i class="fas fa-handshake me-2"></i>Verpachtungsstatus
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row text-center mb-3">
|
||||
<div class="col-6">
|
||||
<div class="h6 mb-0 text-success">{{ stats.pct_verpachtet|default:0 }}%</div>
|
||||
<div class="small text-muted">Verpachtet</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="h6 mb-0 text-secondary">{{ stats.pct_unveerpachtet|default:0 }}%</div>
|
||||
<div class="small text-muted">Verfügbar</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 200px;">
|
||||
<canvas id="verpachtungChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -379,8 +407,13 @@
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: { position: 'bottom' },
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'bottom',
|
||||
labels: { padding: 10, fontSize: 12 }
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
@@ -399,50 +432,107 @@
|
||||
console.log('usageChart canvas not found');
|
||||
}
|
||||
|
||||
// Simple CSS bar chart for sizes (no Chart.js)
|
||||
const chartContainer = document.getElementById('sizesChart');
|
||||
if (chartContainer) {
|
||||
console.log('Found sizesChart container');
|
||||
// Bar chart for sizes
|
||||
const ctx = document.getElementById('sizesChart');
|
||||
if (ctx) {
|
||||
console.log('Found sizesChart canvas');
|
||||
const labels = JSON.parse('{{ size_chart_labels_json|escapejs }}');
|
||||
const dataVals = JSON.parse('{{ size_chart_values_json|escapejs }}');
|
||||
console.log('Bar chart data:', {labels: labels.length, values: dataVals.length});
|
||||
|
||||
if (dataVals.length > 0) {
|
||||
const maxValue = Math.max(...dataVals);
|
||||
new Chart(ctx, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
label: 'Größe (qm)',
|
||||
data: dataVals,
|
||||
backgroundColor: 'rgba(0, 104, 55, 0.6)',
|
||||
borderColor: '#006837',
|
||||
borderWidth: 2
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
x: { ticks: { autoSkip: true, maxTicksLimit: 8 } },
|
||||
y: { beginAtZero: true }
|
||||
},
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
tooltip: { callbacks: { label: function(ctx) { return ctx.parsed.y.toLocaleString() + ' qm'; } } }
|
||||
}
|
||||
}
|
||||
});
|
||||
console.log('Bar chart created successfully');
|
||||
} else {
|
||||
console.log('sizesChart canvas not found');
|
||||
}
|
||||
|
||||
// Doughnut chart for verpachtung
|
||||
const vctx = document.getElementById('verpachtungChart');
|
||||
if (vctx) {
|
||||
console.log('Found verpachtungChart canvas');
|
||||
|
||||
const verpachtet = {{ stats.verpachtete_plots|default:0 }};
|
||||
const verfuegbar = {{ stats.unveerpachtete_plots|default:0 }};
|
||||
|
||||
console.log('Verpachtung data:', {verpachtet: verpachtet, verfuegbar: verfuegbar});
|
||||
|
||||
if (verpachtet > 0 || verfuegbar > 0) {
|
||||
const verpachtungData = [];
|
||||
const verpachtungLabels = [];
|
||||
const verpachtungColors = [];
|
||||
|
||||
chartContainer.innerHTML = ''; // Clear container
|
||||
if (verpachtet > 0) {
|
||||
verpachtungData.push(verpachtet);
|
||||
verpachtungLabels.push('Verpachtet');
|
||||
verpachtungColors.push('rgba(40, 167, 69, 0.8)');
|
||||
}
|
||||
if (verfuegbar > 0) {
|
||||
verpachtungData.push(verfuegbar);
|
||||
verpachtungLabels.push('Verfügbar');
|
||||
verpachtungColors.push('rgba(108, 117, 125, 0.8)');
|
||||
}
|
||||
|
||||
// Create bars
|
||||
dataVals.forEach((value, index) => {
|
||||
const barHeight = (value / maxValue) * 120; // Max height 120px
|
||||
const bar = document.createElement('div');
|
||||
bar.style.cssText = `
|
||||
background-color: rgba(0, 104, 55, 0.8);
|
||||
border: 1px solid #006837;
|
||||
width: ${Math.max(100 / dataVals.length - 1, 8)}%;
|
||||
height: ${barHeight}px;
|
||||
min-height: 2px;
|
||||
display: flex;
|
||||
align-items: end;
|
||||
justify-content: center;
|
||||
font-size: 10px;
|
||||
color: white;
|
||||
text-shadow: 1px 1px 1px rgba(0,0,0,0.5);
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
// Add tooltip on hover
|
||||
bar.title = `${labels[index] || 'N/A'}: ${value.toLocaleString()} qm`;
|
||||
|
||||
chartContainer.appendChild(bar);
|
||||
new Chart(vctx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: verpachtungLabels,
|
||||
datasets: [{
|
||||
data: verpachtungData,
|
||||
backgroundColor: verpachtungColors,
|
||||
borderWidth: 2,
|
||||
borderColor: '#fff'
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
position: 'bottom',
|
||||
labels: { padding: 10, fontSize: 12 }
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(ctx) {
|
||||
const percentage = ((ctx.parsed / (verpachtet + verfuegbar)) * 100).toFixed(1);
|
||||
return ctx.label + ': ' + ctx.parsed + ' (' + percentage + '%)';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log('CSS bar chart created successfully');
|
||||
console.log('Verpachtung chart created successfully');
|
||||
} else {
|
||||
chartContainer.innerHTML = '<div style="text-align: center; color: #666; padding: 20px;">Keine Daten verfügbar</div>';
|
||||
console.log('No data for verpachtung chart');
|
||||
}
|
||||
} else {
|
||||
console.log('sizesChart container not found');
|
||||
console.log('verpachtungChart canvas not found');
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('Chart initialization error:', e);
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
|
||||
<!-- Statistics Cards -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<div class="card bg-primary text-white">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Gesamtbetrag</h5>
|
||||
@@ -197,15 +197,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-success text-white">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Durchschnitt</h5>
|
||||
<h3 class="card-text">€{{ avg_betrag|floatformat:2 }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="col-md-4">
|
||||
<div class="card bg-info text-white">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Anzahl</h5>
|
||||
@@ -213,6 +205,38 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card bg-light">
|
||||
<div class="card-body text-center">
|
||||
<h6 class="card-title text-muted mb-2">
|
||||
<i class="fas fa-chart-pie me-2"></i>Vierteljahresnachweis Status
|
||||
</h6>
|
||||
<div class="row g-1">
|
||||
<div class="col-6">
|
||||
<div class="text-primary fw-bold">{{ total_quarterly }}</div>
|
||||
<small class="text-muted">Gesamt</small>
|
||||
</div>
|
||||
{% for status_code, status_data in quarterly_stats.items %}
|
||||
{% if status_data.count > 0 %}
|
||||
<div class="col-6">
|
||||
<div class="fw-bold
|
||||
{% if status_code == 'offen' %}text-secondary
|
||||
{% elif status_code == 'teilweise' %}text-warning
|
||||
{% elif status_code == 'eingereicht' %}text-info
|
||||
{% elif status_code == 'geprueft' %}text-success
|
||||
{% elif status_code == 'nachbesserung' %}text-danger
|
||||
{% elif status_code == 'abgelehnt' %}text-dark
|
||||
{% endif %}">
|
||||
{{ status_data.count }}
|
||||
</div>
|
||||
<small class="text-muted">{{ status_data.name }}</small>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filters -->
|
||||
|
||||
@@ -212,6 +212,47 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quarterly Confirmation Statistics -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header bg-light">
|
||||
<h6 class="card-title mb-0">
|
||||
<i class="fas fa-chart-pie me-2"></i>
|
||||
Vierteljahresnachweis Status Übersicht
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body py-2">
|
||||
<div class="row text-center g-0">
|
||||
<div class="col-lg-2 col-md-3 col-4 mb-2">
|
||||
<div class="px-2">
|
||||
<div class="h5 fw-bold text-primary mb-0">{{ total_quarterly }}</div>
|
||||
<small class="text-muted">Gesamt</small>
|
||||
</div>
|
||||
</div>
|
||||
{% for status_code, status_data in quarterly_stats.items %}
|
||||
<div class="col-lg-2 col-md-3 col-4 mb-2">
|
||||
<div class="px-2">
|
||||
<div class="h6 fw-bold mb-0
|
||||
{% if status_code == 'offen' %}text-secondary
|
||||
{% elif status_code == 'teilweise' %}text-warning
|
||||
{% elif status_code == 'eingereicht' %}text-info
|
||||
{% elif status_code == 'geprueft' %}text-success
|
||||
{% elif status_code == 'nachbesserung' %}text-danger
|
||||
{% elif status_code == 'abgelehnt' %}text-dark
|
||||
{% endif %}">
|
||||
{{ status_data.count }}
|
||||
</div>
|
||||
<small class="text-muted">{{ status_data.name }}</small>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow">
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
@@ -258,7 +299,12 @@
|
||||
{{ u.get_status_display }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ u.beschreibung }}</td>
|
||||
<td>
|
||||
{{ u.beschreibung }}
|
||||
{% if "Q" in u.beschreibung and "/" in u.beschreibung %}
|
||||
<i class="fas fa-file-contract text-primary ms-2" title="Verknüpft mit Vierteljahresnachweis" data-bs-toggle="tooltip"></i>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm" role="group">
|
||||
<a href="{% url 'stiftung:unterstuetzung_edit' pk=u.pk %}" class="btn btn-outline-warning"><i class="fas fa-edit"></i></a>
|
||||
@@ -424,6 +470,12 @@ document.getElementById('exportForm').addEventListener('submit', function(e) {
|
||||
// Initialize counts on page load
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
updateSelectedCount();
|
||||
|
||||
// Initialize tooltips for quarterly confirmation indicators
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user