357 lines
17 KiB
Twig
357 lines
17 KiB
Twig
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Zahlungsverwaltung - Webshop Admin</title>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css" rel="stylesheet">
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
</head>
|
|
<body>
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<!-- Sidebar -->
|
|
<nav class="col-md-3 col-lg-2 d-md-block bg-dark sidebar collapse">
|
|
<div class="position-sticky pt-3">
|
|
<ul class="nav flex-column">
|
|
<li class="nav-item">
|
|
<a class="nav-link text-white" href="/admin/dashboard">
|
|
<i class="bi bi-speedometer2"></i> Dashboard
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link text-white" href="/admin/products">
|
|
<i class="bi bi-box"></i> Produkte
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link text-white" href="/admin/orders">
|
|
<i class="bi bi-cart"></i> Bestellungen
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link text-white" href="/admin/customers">
|
|
<i class="bi bi-people"></i> Kunden
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link active text-white" href="/admin/payment">
|
|
<i class="bi bi-credit-card"></i> Zahlungen
|
|
</a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link text-white" href="/admin/settings">
|
|
<i class="bi bi-gear"></i> Einstellungen
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Main content -->
|
|
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4">
|
|
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
|
<h1 class="h2">Zahlungsverwaltung</h1>
|
|
<div class="btn-toolbar mb-2 mb-md-0">
|
|
<div class="btn-group me-2">
|
|
<a href="/admin/payment/transactions" class="btn btn-sm btn-outline-secondary">
|
|
<i class="bi bi-list"></i> Transaktionen
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Flash Messages -->
|
|
{% if success_messages %}
|
|
{% for message in success_messages %}
|
|
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
{% if error_messages %}
|
|
{% for message in error_messages %}
|
|
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
{% endfor %}
|
|
{% endif %}
|
|
|
|
<!-- Payment Provider Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h5 class="card-title">PayPal</h5>
|
|
<p class="card-text text-muted">Online-Zahlungen</p>
|
|
</div>
|
|
<div class="text-end">
|
|
<span class="badge {% if provider_status.paypal %}bg-success{% else %}bg-danger{% endif %}">
|
|
{% if provider_status.paypal %}Aktiv{% else %}Inaktiv{% endif %}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<a href="/admin/payment/paypal" class="btn btn-primary btn-sm">
|
|
<i class="bi bi-gear"></i> Konfigurieren
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h5 class="card-title">Stripe</h5>
|
|
<p class="card-text text-muted">Kreditkarten-Zahlungen</p>
|
|
</div>
|
|
<div class="text-end">
|
|
<span class="badge {% if provider_status.stripe %}bg-success{% else %}bg-danger{% endif %}">
|
|
{% if provider_status.stripe %}Aktiv{% else %}Inaktiv{% endif %}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<a href="/admin/payment/stripe" class="btn btn-primary btn-sm">
|
|
<i class="bi bi-gear"></i> Konfigurieren
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-4">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h5 class="card-title">SEPA-Lastschrift</h5>
|
|
<p class="card-text text-muted">Banküberweisungen</p>
|
|
</div>
|
|
<div class="text-end">
|
|
<span class="badge {% if provider_status.sepa %}bg-success{% else %}bg-danger{% endif %}">
|
|
{% if provider_status.sepa %}Aktiv{% else %}Inaktiv{% endif %}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<a href="/admin/payment/sepa" class="btn btn-primary btn-sm">
|
|
<i class="bi bi-gear"></i> Konfigurieren
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Payment Statistics -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">Zahlungsstatistiken</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<canvas id="paymentChart" width="400" height="200"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">Aktuelle Transaktionen</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Provider</th>
|
|
<th>Betrag</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for stat in statistics %}
|
|
<tr>
|
|
<td>
|
|
<span class="badge bg-primary">{{ stat.provider|upper }}</span>
|
|
</td>
|
|
<td>{{ stat.total_amount|number_format(2, ',', '.') }} €</td>
|
|
<td>
|
|
<span class="badge bg-success">{{ stat.successful_transactions }}</span>
|
|
<span class="badge bg-danger">{{ stat.failed_transactions }}</span>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">Schnellaktionen</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="row">
|
|
<div class="col-md-3">
|
|
<a href="/admin/payment/transactions" class="btn btn-outline-primary w-100 mb-2">
|
|
<i class="bi bi-list"></i> Alle Transaktionen
|
|
</a>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button class="btn btn-outline-success w-100 mb-2" onclick="testAllProviders()">
|
|
<i class="bi bi-check-circle"></i> Alle Provider testen
|
|
</button>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<a href="/admin/payment/statistics" class="btn btn-outline-info w-100 mb-2">
|
|
<i class="bi bi-graph-up"></i> Detaillierte Statistiken
|
|
</a>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<button class="btn btn-outline-warning w-100 mb-2" onclick="exportTransactions()">
|
|
<i class="bi bi-download"></i> Export
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script>
|
|
// Payment Chart
|
|
const ctx = document.getElementById('paymentChart').getContext('2d');
|
|
const paymentChart = new Chart(ctx, {
|
|
type: 'doughnut',
|
|
data: {
|
|
labels: [
|
|
{% for stat in statistics %}
|
|
'{{ stat.provider|upper }}',
|
|
{% endfor %}
|
|
],
|
|
datasets: [{
|
|
data: [
|
|
{% for stat in statistics %}
|
|
{{ stat.total_amount }},
|
|
{% endfor %}
|
|
],
|
|
backgroundColor: [
|
|
'#007bff',
|
|
'#28a745',
|
|
'#ffc107',
|
|
'#dc3545'
|
|
],
|
|
borderWidth: 2,
|
|
borderColor: '#fff'
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
position: 'bottom'
|
|
},
|
|
tooltip: {
|
|
callbacks: {
|
|
label: function(context) {
|
|
const label = context.label || '';
|
|
const value = context.parsed;
|
|
return label + ': ' + value.toFixed(2) + ' €';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Test all payment providers
|
|
function testAllProviders() {
|
|
const providers = ['paypal', 'stripe', 'sepa'];
|
|
let results = {};
|
|
|
|
providers.forEach(provider => {
|
|
fetch('/admin/payment/test-provider', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
},
|
|
body: 'provider=' + provider + '&csrf_token={{ csrf_token }}'
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
results[provider] = data.status;
|
|
updateProviderStatus(provider, data.status);
|
|
})
|
|
.catch(error => {
|
|
console.error('Fehler beim Testen von ' + provider + ':', error);
|
|
results[provider] = false;
|
|
updateProviderStatus(provider, false);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Update provider status badges
|
|
function updateProviderStatus(provider, status) {
|
|
const badge = document.querySelector(`[data-provider="${provider}"]`);
|
|
if (badge) {
|
|
badge.className = `badge ${status ? 'bg-success' : 'bg-danger'}`;
|
|
badge.textContent = status ? 'Aktiv' : 'Inaktiv';
|
|
}
|
|
}
|
|
|
|
// Export transactions
|
|
function exportTransactions() {
|
|
const date = new Date().toISOString().split('T')[0];
|
|
const filename = `transactions_${date}.csv`;
|
|
|
|
fetch('/admin/payment/export-transactions')
|
|
.then(response => response.blob())
|
|
.then(blob => {
|
|
const url = window.URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
window.URL.revokeObjectURL(url);
|
|
document.body.removeChild(a);
|
|
})
|
|
.catch(error => {
|
|
console.error('Export Fehler:', error);
|
|
alert('Fehler beim Export der Transaktionen');
|
|
});
|
|
}
|
|
|
|
// Auto-refresh statistics every 30 seconds
|
|
setInterval(() => {
|
|
fetch('/admin/payment/statistics')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
// Update chart data
|
|
paymentChart.data.labels = data.map(stat => stat.provider.toUpperCase());
|
|
paymentChart.data.datasets[0].data = data.map(stat => stat.total_amount);
|
|
paymentChart.update();
|
|
})
|
|
.catch(error => console.error('Statistik-Update Fehler:', error));
|
|
}, 30000);
|
|
</script>
|
|
</body>
|
|
</html> |