diff --git a/admin/reports.php b/admin/reports.php new file mode 100644 index 0000000..e43b056 --- /dev/null +++ b/admin/reports.php @@ -0,0 +1,174 @@ +requireAdmin(); +I18n::init(); + +$db = Database::getInstance(); +$appTitle = $db->getSetting('app_title', 'UniFi Voucher System'); + +// Zeitraum (Tage) +$days = max(1, min(365, (int)($_GET['days'] ?? 30))); + +// CSV-Export +if (isset($_GET['export'])) { + $auth->requireAdmin(); + header('Content-Type: text/csv; charset=utf-8'); + $fn = 'report-' . $_GET['export'] . '-' . date('Y-m-d') . '.csv'; + header('Content-Disposition: attachment; filename="' . $fn . '"'); + $out = fopen('php://output', 'w'); + fprintf($out, "\xEF\xBB\xBF"); // UTF-8 BOM für Excel + + if ($_GET['export'] === 'per_site') { + fputcsv($out, ['Site', 'Gesamt', 'Gültig', 'Verwendet', 'Abgelaufen']); + $rows = $db->fetchAll( + "SELECT s.name, + COUNT(v.id) total, + SUM(v.status='valid') valid, + SUM(v.status='used') used, + SUM(v.status='expired') expired + FROM sites s LEFT JOIN vouchers v ON v.site_id=s.id + GROUP BY s.id ORDER BY total DESC" + ); + foreach ($rows as $r) fputcsv($out, [$r['name'], (int)$r['total'], (int)$r['valid'], (int)$r['used'], (int)$r['expired']]); + } elseif ($_GET['export'] === 'per_user') { + fputcsv($out, ['Benutzer', 'E-Mail', 'Voucher erstellt']); + $rows = $db->fetchAll( + "SELECT u.name, u.email, COUNT(v.id) c FROM users u + LEFT JOIN vouchers v ON v.user_id=u.id GROUP BY u.id ORDER BY c DESC" + ); + foreach ($rows as $r) fputcsv($out, [$r['name'], $r['email'], (int)$r['c']]); + } else { // daily + fputcsv($out, ['Datum', 'Erstellte Voucher']); + $rows = $db->fetchAll( + "SELECT DATE(created_at) d, COUNT(*) c FROM vouchers + WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL ? DAY) + GROUP BY DATE(created_at) ORDER BY d", [$days] + ); + foreach ($rows as $r) fputcsv($out, [$r['d'], (int)$r['c']]); + } + fclose($out); + exit; +} + +// Kennzahlen +$totals = $db->fetchOne( + "SELECT COUNT(*) total, + SUM(status='valid') valid, SUM(status='used') used, SUM(status='expired') expired + FROM vouchers" +); +$inPeriod = (int)($db->fetchOne( + "SELECT COUNT(*) c FROM vouchers WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL ? DAY)", [$days] +)['c'] ?? 0); + +$perSite = $db->fetchAll( + "SELECT s.name, + COUNT(v.id) total, SUM(v.status='valid') valid, SUM(v.status='used') used, SUM(v.status='expired') expired + FROM sites s LEFT JOIN vouchers v ON v.site_id=s.id GROUP BY s.id ORDER BY total DESC" +); +$perUser = $db->fetchAll( + "SELECT u.name, COUNT(v.id) c FROM users u LEFT JOIN vouchers v ON v.user_id=u.id + GROUP BY u.id HAVING c > 0 ORDER BY c DESC LIMIT 10" +); +$daily = $db->fetchAll( + "SELECT DATE(created_at) d, COUNT(*) c FROM vouchers + WHERE created_at >= DATE_SUB(CURDATE(), INTERVAL ? DAY) + GROUP BY DATE(created_at) ORDER BY d", [$days] +); +$chartLabels = array_map(fn($r) => date('d.m', strtotime($r['d'])), $daily); +$chartData = array_map(fn($r) => (int)$r['c'], $daily); + +$csrf = $auth->getCsrfToken(); +$currentPage = 'reports'; +$adminBase = ''; +?> + + + + + +Reporting – <?= htmlspecialchars($appTitle) ?> + + + + + +

📊 Reporting

+ +
+
+ + +
+ ⬇️ CSV (täglich) + ⬇️ CSV (pro Site) + ⬇️ CSV (pro Nutzer) + +
+ +
+
Vouchers gesamt
+
Gültig
+
Verwendet
+
In Tagen erstellt
+
+ +
+

Erstellte Voucher ( Tage)

+ +
+ +
+

Pro Site

+ + + + +
SiteGesamtGültigVerwendetAbgelaufen
+
+ +
+

Top-Nutzer

+ + + + + +
BenutzerVoucher erstellt
Keine Daten
+
+ + + + + + diff --git a/includes/admin_nav.php b/includes/admin_nav.php index a3588c2..93489d2 100644 --- a/includes/admin_nav.php +++ b/includes/admin_nav.php @@ -110,6 +110,9 @@ $lang = I18n::getLanguage();
  • +
  • + +
  • diff --git a/lang/de.php b/lang/de.php index 406cc9c..aab548d 100644 --- a/lang/de.php +++ b/lang/de.php @@ -7,6 +7,7 @@ return [ 'nav_vouchers' => 'Live Vouchers', 'nav_templates' => 'Voucher-Profile', 'nav_audit_log' => 'Audit-Log', + 'nav_reports' => 'Reporting', 'nav_settings' => 'Einstellungen', 'nav_api_keys' => 'API-Schlüssel', 'nav_security' => 'Sicherheit (2FA)', diff --git a/lang/en.php b/lang/en.php index 55ba900..d92a83a 100644 --- a/lang/en.php +++ b/lang/en.php @@ -7,6 +7,7 @@ return [ 'nav_vouchers' => 'Live Vouchers', 'nav_templates' => 'Voucher Profiles', 'nav_audit_log' => 'Audit Log', + 'nav_reports' => 'Reporting', 'nav_settings' => 'Settings', 'nav_api_keys' => 'API Keys', 'nav_security' => 'Security (2FA)',