291 lines
9.6 KiB
PHP
Executable File
291 lines
9.6 KiB
PHP
Executable File
<?php
|
||
// define('DOMILI_ALLOW_WEB', true); // Zum Testen im Browser einkommentieren
|
||
|
||
if (php_sapi_name() !== 'cli' && !defined('DOMILI_ALLOW_WEB')) {
|
||
die('Zugriff verweigert.');
|
||
}
|
||
|
||
require_once __DIR__ . '/vendor/autoload.php';
|
||
require_once __DIR__ . '/inc/db.php';
|
||
|
||
use Dompdf\Dompdf;
|
||
use Dompdf\Options;
|
||
|
||
date_default_timezone_set('Europe/Berlin');
|
||
|
||
// === 1. Berichtsmonat ===
|
||
$berichtsMonatEnde = new DateTime('last day of last month');
|
||
$berichtsMonatBeginn = new DateTime('first day of last month');
|
||
|
||
// === 2. Letzter Jahresabschluss ===
|
||
$last_closing = '2020-01-01';
|
||
$res = mysqli_query($conn, "SELECT MAX(closing_date) AS last_date FROM penalty_closings");
|
||
if ($res && ($row = mysqli_fetch_assoc($res)) && !is_null($row['last_date'])) {
|
||
$last_closing = $row['last_date'];
|
||
}
|
||
|
||
// === 3. Alle Benutzer ===
|
||
$alleBenutzer = [];
|
||
$resUsers = mysqli_query($conn, "SELECT id, username FROM users ORDER BY username");
|
||
while ($row = mysqli_fetch_assoc($resUsers)) {
|
||
$alleBenutzer[$row['id']] = $row['username'];
|
||
}
|
||
$userIds = array_keys($alleBenutzer);
|
||
|
||
// === 4. Alle relevanten Daten (nur completed + attended=1) ===
|
||
$bisDatum = $berichtsMonatEnde->format('Y-m-d');
|
||
$stmt = mysqli_prepare($conn, "
|
||
SELECT m.id AS meeting_id, m.meeting_date,
|
||
mt.user_id, mt.wore_color, mt.paid, mt.birthday_pay
|
||
FROM meetings m
|
||
LEFT JOIN meeting_teilnehmer mt ON m.id = mt.meeting_id AND mt.attended = 1
|
||
WHERE m.meeting_date <= ? AND m.is_completed = 1
|
||
ORDER BY m.meeting_date
|
||
");
|
||
mysqli_stmt_bind_param($stmt, 's', $bisDatum);
|
||
mysqli_stmt_execute($stmt);
|
||
$result = mysqli_stmt_get_result($stmt);
|
||
|
||
$alleMeetingsMitTeilnehmern = [];
|
||
while ($row = mysqli_fetch_assoc($result)) {
|
||
$alleMeetingsMitTeilnehmern[] = $row;
|
||
}
|
||
mysqli_stmt_close($stmt);
|
||
|
||
// === 5. Meetings des Berichtsmonats mit Farben ===
|
||
$stmtMeta = mysqli_prepare($conn, "
|
||
SELECT id, meeting_date, reason, color_id
|
||
FROM meetings
|
||
WHERE meeting_date >= ? AND meeting_date <= ? AND is_completed = 1
|
||
ORDER BY meeting_date
|
||
");
|
||
$startDate = $berichtsMonatBeginn->format('Y-m-d');
|
||
$endDate = $berichtsMonatEnde->format('Y-m-d');
|
||
mysqli_stmt_bind_param($stmtMeta, 'ss', $startDate, $endDate);
|
||
mysqli_stmt_execute($stmtMeta);
|
||
$resultMeta = mysqli_stmt_get_result($stmtMeta);
|
||
|
||
$berichtsMeetingsMeta = [];
|
||
while ($row = mysqli_fetch_assoc($resultMeta)) {
|
||
$color_id = (int)$row['color_id'];
|
||
$colorStmt = mysqli_prepare($conn, "SELECT name FROM colors WHERE id = ?");
|
||
mysqli_stmt_bind_param($colorStmt, 'i', $color_id);
|
||
mysqli_stmt_execute($colorStmt);
|
||
$colorRes = mysqli_stmt_get_result($colorStmt);
|
||
$colorName = '–';
|
||
if ($cRow = mysqli_fetch_assoc($colorRes)) {
|
||
$colorName = $cRow['name'];
|
||
}
|
||
mysqli_stmt_close($colorStmt);
|
||
|
||
$berichtsMeetingsMeta[] = [
|
||
'id' => $row['id'],
|
||
'meeting_date' => $row['meeting_date'],
|
||
'reason' => $row['reason'],
|
||
'color_name' => $colorName
|
||
];
|
||
}
|
||
mysqli_stmt_close($stmtMeta);
|
||
|
||
// === 6. Für jedes Meeting: alle Benutzer mit allen Werten ===
|
||
$gruppiert = [];
|
||
|
||
foreach ($berichtsMeetingsMeta as $meta) {
|
||
$mid = $meta['id'];
|
||
$meetingDatum = new DateTime($meta['meeting_date']);
|
||
|
||
$gruppiert[$mid] = [
|
||
'datum' => $meta['meeting_date'],
|
||
'reason' => $meta['reason'],
|
||
'color_name' => $meta['color_name'],
|
||
'teilnehmer' => []
|
||
];
|
||
|
||
foreach ($userIds as $uid) {
|
||
$username = $alleBenutzer[$uid];
|
||
|
||
$teilgenommen = false;
|
||
$wore_color = null;
|
||
$paid_this = false;
|
||
$paid_this_birthday = false; // NEU
|
||
|
||
// Finde Teilnahme-Daten für dieses Meeting
|
||
foreach ($alleMeetingsMitTeilnehmern as $mt) {
|
||
if ($mt['meeting_id'] == $mid && $mt['user_id'] == $uid) {
|
||
$teilgenommen = true;
|
||
$wore_color = !empty($mt['wore_color']);
|
||
$paid_this = ($mt['paid'] == 1);
|
||
$paid_this_birthday = ($mt['birthday_pay'] == 1); // Explizit prüfen
|
||
break;
|
||
}
|
||
}
|
||
|
||
// Kumulierte Werte bis zu diesem Meeting
|
||
$strafenGesamt = 0;
|
||
$offeneStrafen = 0;
|
||
$teilnahmenGesamt = 0;
|
||
$rechnungenGesamt = 0;
|
||
|
||
foreach ($alleMeetingsMitTeilnehmern as $mt) {
|
||
if ($mt['user_id'] != $uid || is_null($mt['user_id'])) continue;
|
||
$mDatum = new DateTime($mt['meeting_date']);
|
||
if ($mDatum > $meetingDatum) continue;
|
||
|
||
$teilnahmenGesamt++;
|
||
if (!$mt['wore_color']) {
|
||
$strafenGesamt++;
|
||
if ($mt['meeting_date'] >= $last_closing) {
|
||
$offeneStrafen++;
|
||
}
|
||
}
|
||
|
||
// 🔹 NUR normale Zahlungen zählen (birthday_pay = 0)
|
||
$is_paid = ($mt['paid'] == 1);
|
||
$is_birthday = ($mt['birthday_pay'] == 1);
|
||
if ($is_paid && !$is_birthday) {
|
||
$rechnungenGesamt++;
|
||
}
|
||
}
|
||
|
||
// Name mit Symbolen
|
||
$userNameAnzeige = htmlspecialchars($username);
|
||
if ($paid_this) {
|
||
$userNameAnzeige .= ' <span class="paid-symbol">€</span>';
|
||
if ($paid_this_birthday) {
|
||
$userNameAnzeige .= ' <span class="birthday-symbol">(G)</span>';
|
||
}
|
||
}
|
||
|
||
if (!$teilgenommen) {
|
||
$farbeSymbol = '–';
|
||
} else {
|
||
$farbeSymbol = $wore_color ? '✓' : '✗';
|
||
}
|
||
|
||
$gruppiert[$mid]['teilnehmer'][] = [
|
||
'username' => $userNameAnzeige,
|
||
'farbe_symbol' => $farbeSymbol,
|
||
'teilgenommen' => $teilgenommen,
|
||
'offene_strafen' => $offeneStrafen,
|
||
'strafen_gesamt' => $strafenGesamt,
|
||
'teilnahmen_gesamt' => $teilnahmenGesamt,
|
||
'rechnungen_gesamt' => $rechnungenGesamt
|
||
];
|
||
}
|
||
}
|
||
|
||
// === 7. Gesamt offene Strafen ===
|
||
$gesamtOffen = 0;
|
||
foreach ($alleMeetingsMitTeilnehmern as $mt) {
|
||
if (!is_null($mt['user_id']) && !$mt['wore_color'] && $mt['meeting_date'] >= $last_closing) {
|
||
$gesamtOffen++;
|
||
}
|
||
}
|
||
|
||
// === 8. PDF-Pfad ===
|
||
@mkdir(__DIR__ . '/backups', 0755, true);
|
||
$baseName = 'DoMiLi_Backup_' . $berichtsMonatBeginn->format('Y-m');
|
||
$counter = 0;
|
||
$outputPath = __DIR__ . '/backups/' . $baseName . '.pdf';
|
||
while (file_exists($outputPath)) {
|
||
$counter++;
|
||
$outputPath = __DIR__ . '/backups/' . $baseName . '_' . $counter . '.pdf';
|
||
}
|
||
|
||
// === 9. HTML mit allen Anforderungen ===
|
||
$html = '
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<style>
|
||
body { font-family: DejaVu Sans, Arial, sans-serif; font-size: 9pt; }
|
||
h1 { font-size: 14pt; margin-bottom: 14pt; }
|
||
h2 { font-size: 11pt; margin: 12pt 0 8pt 0; }
|
||
.strafkasse { font-weight: bold; margin: 0 0 14pt 0; padding: 6pt; background-color: #f9f9f9; border: 1px solid #ccc; }
|
||
table { width: 100%; border-collapse: collapse; margin-bottom: 12pt; }
|
||
th, td { border: 1px solid #333; padding: 4pt 6pt; text-align: left; }
|
||
th { background-color: #f0f0f0; font-weight: bold; }
|
||
.paid-symbol { color: red; font-weight: bold; }
|
||
.birthday-symbol { color: #d63384; font-size: 0.85em; }
|
||
.color-ok { color: green; }
|
||
.color-fail { color: red; }
|
||
.page-break { page-break-after: always; }
|
||
.meta { margin-top: 20pt; font-size: 8pt; color: #555; }
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<h1>DoMiLi – Monatliches Backup</h1>
|
||
<h2>Zeitraum: ' . $berichtsMonatBeginn->format('F Y') . '</h2>
|
||
<div class="strafkasse">Strafkasse: ' . $gesamtOffen . ' €</div>';
|
||
|
||
if (empty($berichtsMeetingsMeta)) {
|
||
$html .= '<p>Keine abgeschlossenen Meetings im Berichtsmonat.</p>';
|
||
} else {
|
||
$meetingCount = 0;
|
||
foreach ($gruppiert as $meeting) {
|
||
if ($meetingCount > 0 && $meetingCount % 3 === 0) {
|
||
$html .= '<div class="page-break"></div>';
|
||
}
|
||
$meetingCount++;
|
||
|
||
$meetingDatum = new DateTime($meeting['datum']);
|
||
$html .= '<h3>' . $meetingDatum->format('d.m.Y') . ' – ' . htmlspecialchars($meeting['reason']) . ' (' . htmlspecialchars($meeting['color_name']) . ')</h3>';
|
||
$html .= '<table>
|
||
<thead>
|
||
<tr>
|
||
<th>Benutzer*</th>
|
||
<th>Farbe getragen</th>
|
||
<th>offene Strafen (in €)</th>
|
||
<th>Strafen gesamt</th>
|
||
<th>Teilnahmen gesamt</th>
|
||
<th>Rechnung gesamt</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>';
|
||
|
||
foreach ($meeting['teilnehmer'] as $t) {
|
||
if ($t['farbe_symbol'] === '✓') {
|
||
$farbeHtml = '<span class="color-ok">✓</span>';
|
||
} elseif ($t['farbe_symbol'] === '✗') {
|
||
$farbeHtml = '<span class="color-fail">✗</span>';
|
||
} else {
|
||
$farbeHtml = $t['farbe_symbol'];
|
||
}
|
||
|
||
$html .= '<tr>
|
||
<td>' . $t['username'] . '</td>
|
||
<td>' . $farbeHtml . '</td>
|
||
<td>' . $t['offene_strafen'] . '</td>
|
||
<td>' . $t['strafen_gesamt'] . '</td>
|
||
<td>' . $t['teilnahmen_gesamt'] . '</td>
|
||
<td>' . $t['rechnungen_gesamt'] . '</td>
|
||
</tr>';
|
||
}
|
||
|
||
$html .= '</tbody></table>';
|
||
}
|
||
}
|
||
|
||
$html .= '
|
||
<div class="meta">
|
||
<p>Erstellt am: ' . date('d.m.Y') . '</p>
|
||
<p><em>* = "€" hat Restaurant-Rechnung bezahlt</em></p>
|
||
<p><em>(G) = Geburtstagszahlung (zählt nicht zur Rechnungsanzahl)</em></p>
|
||
</div>
|
||
|
||
</body>
|
||
</html>';
|
||
|
||
// === 10. PDF erzeugen ===
|
||
$options = new Options();
|
||
$options->set('defaultFont', 'DejaVu Sans');
|
||
$dompdf = new Dompdf($options);
|
||
$dompdf->loadHtml($html);
|
||
$dompdf->setPaper('A4', 'portrait');
|
||
$dompdf->render();
|
||
|
||
file_put_contents($outputPath, $dompdf->output());
|
||
echo "✅ PDF erfolgreich gespeichert: " . $outputPath . "\n";
|