Files
domili/kasse.php
2025-11-18 18:39:22 +01:00

453 lines
19 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// KEIN LEERZEICHEN ODER ZEILENUMBRUCH VOR DIESEM <?php!
include('inc/check_login.php');
require_once('inc/db.php');
$is_admin = ($_SESSION['role'] === 'admin');
// --- JAHRESABSCHLUSS ---
if ($is_admin && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'close_year') {
$today = date('Y-m-d');
$user_id = $_SESSION['user_id'] ?? 0;
$last_closing_date = '2020-01-01';
$result_last = mysqli_query($conn, "SELECT MAX(closing_date) AS last_date FROM penalty_closings");
if ($result_last) {
$row = mysqli_fetch_assoc($result_last);
if ($row && !is_null($row['last_date'])) {
$last_closing_date = $row['last_date'];
}
}
$check = mysqli_prepare($conn, "SELECT 1 FROM penalty_closings WHERE closing_date = ?");
mysqli_stmt_bind_param($check, "s", $today);
mysqli_stmt_execute($check);
$exists = mysqli_stmt_get_result($check)->num_rows > 0;
mysqli_stmt_close($check);
if (!$exists) {
$insert = mysqli_prepare($conn, "INSERT INTO penalty_closings (closing_date, closed_by) VALUES (?, ?)");
mysqli_stmt_bind_param($insert, "si", $today, $user_id);
mysqli_stmt_execute($insert);
mysqli_stmt_close($insert);
$penalty_summary = [];
$stmt_email = mysqli_prepare($conn, "
SELECT u.username, COUNT(*) AS penalty_count
FROM meeting_teilnehmer mt
JOIN meetings m ON mt.meeting_id = m.id
JOIN users u ON mt.user_id = u.id
WHERE m.meeting_date >= ? AND m.meeting_date <= ?
AND mt.attended = 1 AND mt.wore_color = 0 AND m.is_completed = 1
GROUP BY u.username
");
mysqli_stmt_bind_param($stmt_email, "ss", $last_closing_date, $today);
mysqli_stmt_execute($stmt_email);
$result_email = mysqli_stmt_get_result($stmt_email);
while ($row = mysqli_fetch_assoc($result_email)) {
$penalty_summary[] = $row;
}
mysqli_stmt_close($stmt_email);
$all_users = [];
$stmt_users = mysqli_prepare($conn, "SELECT id, username, email FROM users WHERE email IS NOT NULL AND email != ''");
mysqli_stmt_execute($stmt_users);
$result_users = mysqli_stmt_get_result($stmt_users);
while ($row = mysqli_fetch_assoc($result_users)) {
$all_users[] = $row;
}
mysqli_stmt_close($stmt_users);
if (!empty($all_users) && file_exists(__DIR__ . '/vendor/autoload.php')) {
require_once __DIR__ . '/vendor/autoload.php';
$today_formatted = date('d.m.Y', strtotime($today));
$last_closing_formatted = date('d.m.Y', strtotime($last_closing_date));
foreach ($all_users as $recipient) {
$recipient_email = $recipient['email'];
$recipient_name = $recipient['username'] ?? 'Benutzer';
try {
$mail = new \PHPMailer\PHPMailer\PHPMailer(true);
$mail->CharSet = 'UTF-8';
$mail->isSMTP();
$mail->Host = SMTP_HOST;
$mail->SMTPAuth = true;
$mail->Username = SMTP_USERNAME;
$mail->Password = SMTP_PASSWORD;
$mail->SMTPSecure = SMTP_ENCRYPTION;
$mail->Port = SMTP_PORT;
$mail->setFrom(MAIL_FROM_ADDRESS, MAIL_FROM_NAME);
$text_body = "Hallo $recipient_name,\n\n";
$text_body .= "Der Jahresabschluss wurde am $today_formatted durchgeführt.\n";
$text_body .= "Strafen der abgeschlossenen Periode (vom $last_closing_formatted bis $today_formatted):\n\n";
if (empty($penalty_summary)) {
$text_body .= "Keine Strafen in diesem Zeitraum.\n";
} else {
foreach ($penalty_summary as $row) {
$text_body .= "- " . $row['username'] . ": " . (int)$row['penalty_count'] . " Strafen (1 € pro Strafe)\n";
}
}
$text_body .= "\nDein DoMiLi-Admin.";
$html_table_rows = '';
if (empty($penalty_summary)) {
$html_table_rows = '<tr><td colspan="3" style="text-align:center;">Keine Strafen in diesem Zeitraum.</td></tr>';
} else {
foreach ($penalty_summary as $row) {
$html_table_rows .= sprintf(
'<tr>
<td style="padding:8px;border:1px solid #ddd;">%s</td>
<td style="padding:8px;border:1px solid #ddd;text-align:center;">%d</td>
<td style="padding:8px;border:1px solid #ddd;text-align:right;">%s</td>
</tr>',
htmlspecialchars($row['username']),
(int)$row['penalty_count'],
number_format((float)($row['penalty_count']), 2, ',', '.') . ' €'
);
}
}
$html_body = "
<p>Hallo <strong>$recipient_name</strong>,</p>
<p>der Jahresabschluss wurde am <strong>$today_formatted</strong> durchgeführt.</p>
<p><strong>Strafen der abgeschlossenen Periode</strong> (vom $last_closing_formatted bis $today_formatted):</p>
<table style=\"border-collapse:collapse;width:100%;margin:15px 0;\">
<thead>
<tr>
<th style=\"padding:8px;border:1px solid #ddd;text-align:left;background:#f2f2f2;\">Mitglied</th>
<th style=\"padding:8px;border:1px solid #ddd;text-align:center;background:#f2f2f2;\">Anzahl Strafen</th>
<th style=\"padding:8px;border:1px solid #ddd;text-align:right;background:#f2f2f2;\">Betrag</th>
</tr>
</thead>
<tbody>
$html_table_rows
</tbody>
</table>
<p><em>Dein DoMiLi-Admin.</em></p>";
$mail->isHTML(true);
$mail->Subject = "DoMiLi Jahresabschluss abgeschlossen am $today_formatted";
$mail->Body = $html_body;
$mail->AltBody = $text_body;
$mail->addAddress($recipient_email);
$mail->send();
} catch (Exception $e) {
error_log("PHPMailer Fehler: " . $mail->ErrorInfo);
}
}
}
$close_success = "Jahresabschluss erfolgreich durchgeführt!";
} else {
$close_error = "Heute wurde bereits ein Abschluss durchgeführt.";
}
}
// --- DATEN FÜR ANZEIGE ---
$last_closing_date = '2020-01-01';
$result_last = mysqli_query($conn, "SELECT MAX(closing_date) AS last_date FROM penalty_closings");
if ($result_last) {
$row = mysqli_fetch_assoc($result_last);
if ($row && !is_null($row['last_date'])) {
$last_closing_date = $row['last_date'];
}
}
$cumulative_penalties = [];
$stmt_cum = mysqli_prepare($conn, "
SELECT u.username, COUNT(*) AS total_penalty_count
FROM meeting_teilnehmer mt
JOIN meetings m ON mt.meeting_id = m.id
JOIN users u ON mt.user_id = u.id
WHERE mt.attended = 1 AND mt.wore_color = 0 AND m.is_completed = 1
GROUP BY u.username
");
mysqli_stmt_execute($stmt_cum);
$result_cum = mysqli_stmt_get_result($stmt_cum);
while ($row = mysqli_fetch_assoc($result_cum)) {
$cumulative_penalties[$row['username']] = (int)$row['total_penalty_count'];
}
mysqli_stmt_close($stmt_cum);
$open_penalties = [];
$total_open = 0;
$penalty_amount = 1;
$stmt_open = mysqli_prepare($conn, "
SELECT u.username, COUNT(*) AS open_penalty_count
FROM meeting_teilnehmer mt
JOIN meetings m ON mt.meeting_id = m.id
JOIN users u ON mt.user_id = u.id
WHERE m.meeting_date >= ? AND mt.attended = 1 AND mt.wore_color = 0 AND m.is_completed = 1
GROUP BY u.username
");
mysqli_stmt_bind_param($stmt_open, "s", $last_closing_date);
mysqli_stmt_execute($stmt_open);
$result_open = mysqli_stmt_get_result($stmt_open);
while ($row = mysqli_fetch_assoc($result_open)) {
$open_penalties[$row['username']] = (int)$row['open_penalty_count'];
$total_open += $row['open_penalty_count'];
}
mysqli_stmt_close($stmt_open);
$penalties_data = [];
$all_usernames = array_unique(array_merge(array_keys($cumulative_penalties), array_keys($open_penalties)));
foreach ($all_usernames as $username) {
$total = $cumulative_penalties[$username] ?? 0;
$open = $open_penalties[$username] ?? 0;
$penalties_data[] = [
'username' => $username,
'total_penalty_count' => $total,
'open_penalty_count' => $open
];
}
usort($penalties_data, fn($a, $b) => $b['open_penalty_count'] <=> $a['open_penalty_count']);
$total_penalties = array_sum(array_column($penalties_data, 'total_penalty_count'));
$total_due = $total_open * $penalty_amount;
$historical_table = [];
$closing_years = [];
$result_closings = mysqli_query($conn, "SELECT closing_date FROM penalty_closings ORDER BY closing_date");
while ($row = mysqli_fetch_assoc($result_closings)) {
$closing_date = new DateTime($row['closing_date']);
$year = (int)$closing_date->format('Y');
$month = (int)$closing_date->format('n');
$closed_year = ($month >= 7) ? $year : ($year - 1);
$closing_years[] = $closed_year;
}
$closing_years = array_unique($closing_years);
sort($closing_years);
if (!empty($closing_years)) {
foreach ($closing_years as $year) {
$year_start = "$year-01-01";
$year_end = "$year-12-31";
$stmt_hist = mysqli_prepare($conn, "
SELECT u.username, COUNT(*) AS penalty_count
FROM meeting_teilnehmer mt
JOIN meetings m ON mt.meeting_id = m.id
JOIN users u ON mt.user_id = u.id
WHERE m.meeting_date BETWEEN ? AND ?
AND mt.attended = 1 AND mt.wore_color = 0 AND m.is_completed = 1
GROUP BY u.username
");
mysqli_stmt_bind_param($stmt_hist, "ss", $year_start, $year_end);
mysqli_stmt_execute($stmt_hist);
$result_hist = mysqli_stmt_get_result($stmt_hist);
while ($row = mysqli_fetch_assoc($result_hist)) {
$username = $row['username'];
$count = (int)$row['penalty_count'];
if (!isset($historical_table[$username])) {
$historical_table[$username] = ['years' => [], 'total' => 0];
}
$historical_table[$username]['years'][] = $year;
$historical_table[$username]['total'] += $count;
}
mysqli_stmt_close($stmt_hist);
}
foreach ($historical_table as $username => $data) {
$historical_table[$username]['year_label'] = implode('/', $data['years']);
}
}
$paid_stats = [];
$sql_paid = "
SELECT u.username, COUNT(mt.user_id) AS paid_count
FROM meeting_teilnehmer mt
JOIN meetings m ON mt.meeting_id = m.id
JOIN users u ON mt.user_id = u.id
WHERE mt.paid = 1 AND m.is_completed = 1
GROUP BY u.username
ORDER BY paid_count DESC, u.username ASC
";
$result_paid = mysqli_query($conn, $sql_paid);
while ($row = mysqli_fetch_assoc($result_paid)) {
$paid_stats[] = $row;
}
require_once 'inc/header.php';
?>
<div class="container mt-5">
<h2 class="mb-4">Kasse</h2>
<?php if (!empty($close_success)): ?>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<?= htmlspecialchars($close_success) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<?php if (!empty($close_error)): ?>
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<?= htmlspecialchars($close_error) ?>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<?php endif; ?>
<div class="card shadow mb-4">
<div class="card-header bg-primary-subtle text-secondary d-flex justify-content-between align-items-center">
<h4 class="mb-0">Strafen</h4>
<?php if ($is_admin): ?>
<form method="POST" class="d-flex align-items-center m-0" onsubmit="return confirm('Jahresabschluss durchführen?');">
<input type="hidden" name="action" value="close_year">
<button type="submit" class="btn btn-sm d-flex align-items-center justify-content-center p-0" style="height: 24px; font-size: 0.875rem;">
Jahresabschluss
<span class="material-symbols-outlined ms-1" style="font-size: 18px; line-height: 1;">add</span>
</button>
</form>
<?php endif; ?>
</div>
<div class="card-body">
<p class="fs-5 fw-bold text-center">
Strafen gesamt: <span class="badge bg-danger"><?= $total_penalties ?></span><br>
offener Betrag: <span class="text-danger fw-bold"><?= number_format($total_due, 2, ',', '.') ?> €</span>
</p>
<?php if (empty($penalties_data)): ?>
<div class="alert alert-info text-center">Keine Strafen erfasst.</div>
<?php else: ?>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Benutzer</th>
<th>Strafen gesamt</th>
<th>offener Betrag</th>
</tr>
</thead>
<tbody>
<?php foreach ($penalties_data as $p): ?>
<tr>
<td><?= htmlspecialchars($p['username']) ?></td>
<td><?= htmlspecialchars($p['total_penalty_count']) ?></td>
<td><?= number_format($p['open_penalty_count'] * $penalty_amount, 2, ',', '.') ?> €</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endif; ?>
</div>
</div>
<div class="card shadow mb-4">
<div class="card-header bg-primary-subtle text-secondary">
<h4 class="mb-0">Historische Strafen</h4>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Benutzer</th>
<th>Jahr(e)</th>
<th>Strafen</th>
</tr>
</thead>
<tbody>
<?php if (!empty($historical_table)): ?>
<?php foreach ($historical_table as $username => $data): ?>
<tr>
<td><?= htmlspecialchars($username) ?></td>
<td><?= htmlspecialchars($data['year_label']) ?></td>
<td><?= htmlspecialchars($data['total']) ?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="3" class="text-center text-muted">—</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<div class="card shadow mb-4">
<div class="card-header bg-primary-subtle text-secondary">
<h4 class="mb-0">Rechnungen</h4>
</div>
<div class="card-body">
<h5 class="card-title text-center">Ranking Rechnung übernommen</h5>
<div style="height: 40vh;">
<canvas id="paidChart"></canvas>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
const rawLabels = <?php echo json_encode(array_column($paid_stats, 'username') ?: []); ?>;
const rawData = <?php echo json_encode(array_map('intval', array_column($paid_stats, 'paid_count') ?: [])); ?>;
const ctx = document.getElementById('paidChart').getContext('2d');
if (rawLabels.length === 0 || rawData.length === 0) {
document.getElementById('paidChart').closest('.card-body').innerHTML =
'<p class="text-muted text-center mt-3">Keine bezahlten Rechnungen erfasst.</p>';
return;
}
new Chart(ctx, {
type: 'bar',
data: {
labels: rawLabels,
datasets: [{
label: 'Gezahlte Strafen',
data: rawData,
backgroundColor: 'rgba(54, 162, 235, 0.6)',
borderColor: 'rgba(54, 162, 235, 1)',
borderWidth: 1
}]
},
options: {
indexAxis: 'y',
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: {
display: false
},
title: {
display: true,
text: 'Anzahl der bezahlten Rechnungen'
}
},
scales: {
x: {
beginAtZero: true,
ticks: {
stepSize: 1,
callback: function(value) {
return Number.isInteger(value) ? value : null;
}
}
},
y: {
ticks: {
font: {
size: 12
},
callback: function(value, index, ticks) {
const label = this.getLabelForValue(value);
return label.length > 15 ? label.substring(0, 15) + '…' : label;
}
}
}
}
}
});
});
</script>
<?php include('inc/footer.php'); ?>