Merge branch 'main' of https://git.ctb-it.de/clemens/praxis-creutzburg-web
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
*.otf binary
|
||||
@@ -25,3 +25,9 @@
|
||||
/app/Config/database.php
|
||||
/vendors/*
|
||||
|
||||
# Local editor/deploy configuration
|
||||
/.vscode/ftp-sync.json
|
||||
/.vscode/sftp.json
|
||||
|
||||
.vscode/ftp-sync.json
|
||||
.vscode/sftp.json
|
||||
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"remotePath": "./",
|
||||
"host": "your-host",
|
||||
"username": "your-username",
|
||||
"password": "your-password",
|
||||
"port": 21,
|
||||
"secure": true,
|
||||
"protocol": "ftp",
|
||||
"uploadOnSave": false,
|
||||
"passive": false,
|
||||
"debug": false,
|
||||
"privateKeyPath": null,
|
||||
"passphrase": null,
|
||||
"agent": null,
|
||||
"allow": [],
|
||||
"ignore": [
|
||||
"\\.vscode",
|
||||
"\\.git",
|
||||
"\\.DS_Store"
|
||||
],
|
||||
"generatedFiles": {
|
||||
"extensionsToInclude": [
|
||||
""
|
||||
],
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "Project Deployment",
|
||||
"host": "your-host",
|
||||
"protocol": "ftp",
|
||||
"port": 21,
|
||||
"username": "your-username",
|
||||
"password": "your-password",
|
||||
"remotePath": "/",
|
||||
"secure": true,
|
||||
"uploadOnSave": false,
|
||||
"useTempFile": false,
|
||||
"openSsh": false
|
||||
}
|
||||
+62
-37
@@ -4,6 +4,7 @@ session_start();
|
||||
// WICHTIG: Pfade aus /admin heraus korrekt auflösen
|
||||
require_once __DIR__ . "/../inc/config.inc.php";
|
||||
require_once __DIR__ . "/../inc/functions.inc.php";
|
||||
require_once __DIR__ . "/../inc/company_holiday_sync.inc.php";
|
||||
|
||||
// Login prüfen
|
||||
$user = check_admin_user();
|
||||
@@ -624,12 +625,12 @@ if(!check_worker()){
|
||||
|
||||
echo "Start: <input class='form-control' name='Starttime[]' type='date' value='" . htmlspecialchars($start, ENT_QUOTES, 'UTF-8') . "'>
|
||||
Ende: <input class='form-control' name='Endetime[]' type='date' value='" . htmlspecialchars($ende, ENT_QUOTES, 'UTF-8') . "'><br>
|
||||
Vertretung: <input class='form-control' name='vertretung[]' type='text' value='" . htmlspecialchars($vertretung, ENT_QUOTES, 'UTF-8') . "'>";
|
||||
Vertretung: <input class='form-control' name='vertretung[]' type='text' required value='" . htmlspecialchars($vertretung, ENT_QUOTES, 'UTF-8') . "'>";
|
||||
|
||||
echo "<br>Vertretung Telefon: <input class='form-control' name='vertretertelefon[]' type='text' value='" . htmlspecialchars($vertretertelefon, ENT_QUOTES, 'UTF-8') . "'>
|
||||
<br>Vertretung Adresse: <input class='form-control' name='vertreteradresse[]' type='text' value='" . htmlspecialchars($vertreteradresse, ENT_QUOTES, 'UTF-8') . "'>";
|
||||
echo "<br>Vertretung Telefon: <input class='form-control' name='vertretertelefon[]' type='text' required value='" . htmlspecialchars($vertretertelefon, ENT_QUOTES, 'UTF-8') . "'>
|
||||
<br>Vertretung Adresse: <input class='form-control' name='vertreteradresse[]' type='text' required value='" . htmlspecialchars($vertreteradresse, ENT_QUOTES, 'UTF-8') . "'>";
|
||||
|
||||
echo "<br>Vertretung Webseite: <input class='form-control' name='vertreterurl[]' type='text' value='" . htmlspecialchars($vertreterurl, ENT_QUOTES, 'UTF-8') . "'>";
|
||||
echo "<br>Vertretung Webseite: <input class='form-control' name='vertreterurl[]' type='text' required value='" . htmlspecialchars($vertreterurl, ENT_QUOTES, 'UTF-8') . "'>";
|
||||
|
||||
echo "<input name='urlaubid[]' type='hidden' value='" . $urlaubid . "'><br>";
|
||||
}
|
||||
@@ -656,40 +657,64 @@ if(!check_worker()){
|
||||
}else if (($_POST["aktion"] ?? '') == "5") {
|
||||
// Termine in DB speichern.
|
||||
$i =0;
|
||||
foreach ($_POST['Starttime'] as $Starttime) {
|
||||
//echo $datum . "<br>";
|
||||
if($_POST["Starttime"][$i] != "0000-00-00"){
|
||||
//echo $_POST["urlaubid"][$i] . "<br>";
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO urlaub
|
||||
(urlaubid, vertretung, start, ende, vertretertelefon, vertreteradresse, vertreterurl)
|
||||
VALUES
|
||||
(:urlaubid, :vertretung, :start, :ende, :telefon, :adresse, :url)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
vertretung = VALUES(vertretung),
|
||||
start = VALUES(start),
|
||||
ende = VALUES(ende),
|
||||
vertretertelefon = VALUES(vertretertelefon),
|
||||
vertreteradresse = VALUES(vertreteradresse),
|
||||
vertreterurl = VALUES(vertreterurl)
|
||||
");
|
||||
$pdo->beginTransaction();
|
||||
try {
|
||||
foreach ($_POST['Starttime'] as $Starttime) {
|
||||
if($_POST["Starttime"][$i] != "0000-00-00"){
|
||||
$vertretung = trim((string)($_POST['vertretung'][$i] ?? ''));
|
||||
$vertretertelefon = trim((string)($_POST['vertretertelefon'][$i] ?? ''));
|
||||
$vertreteradresse = trim((string)($_POST['vertreteradresse'][$i] ?? ''));
|
||||
$vertreterurl = trim((string)($_POST['vertreterurl'][$i] ?? ''));
|
||||
|
||||
$ok = $stmt->execute([
|
||||
':urlaubid' => (int)$_POST['urlaubid'][$i], // 0 = INSERT, >0 = UPDATE
|
||||
':vertretung' => $_POST['vertretung'][$i],
|
||||
':start' => $_POST['Starttime'][$i],
|
||||
':ende' => $_POST['Endetime'][$i],
|
||||
':telefon' => $_POST['vertretertelefon'][$i],
|
||||
':adresse' => $_POST['vertreteradresse'][$i],
|
||||
':url' => $_POST['vertreterurl'][$i],
|
||||
]);
|
||||
if ($vertretung === '' || $vertretertelefon === '' || $vertreteradresse === '' || $vertreterurl === '') {
|
||||
throw new RuntimeException("Bitte alle Vertreterinformationen fuer jeden Urlaubseintrag vollstaendig ausfuellen.");
|
||||
}
|
||||
|
||||
if (!$ok) {
|
||||
throw new RuntimeException("Fehler beim Eintragen in der Datenbank.");
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO urlaub
|
||||
(urlaubid, vertretung, start, ende, vertretertelefon, vertreteradresse, vertreterurl)
|
||||
VALUES
|
||||
(:urlaubid, :vertretung, :start, :ende, :telefon, :adresse, :url)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
vertretung = VALUES(vertretung),
|
||||
start = VALUES(start),
|
||||
ende = VALUES(ende),
|
||||
vertretertelefon = VALUES(vertretertelefon),
|
||||
vertreteradresse = VALUES(vertreteradresse),
|
||||
vertreterurl = VALUES(vertreterurl)
|
||||
");
|
||||
|
||||
$ok = $stmt->execute([
|
||||
':urlaubid' => (int)$_POST['urlaubid'][$i], // 0 = INSERT, >0 = UPDATE
|
||||
':vertretung' => $vertretung,
|
||||
':start' => $_POST['Starttime'][$i],
|
||||
':ende' => $_POST['Endetime'][$i],
|
||||
':telefon' => $vertretertelefon,
|
||||
':adresse' => $vertreteradresse,
|
||||
':url' => $vertreterurl,
|
||||
]);
|
||||
|
||||
if (!$ok) {
|
||||
throw new RuntimeException("Fehler beim Eintragen in der Datenbank.");
|
||||
}
|
||||
|
||||
$urlaubId = (int)$_POST['urlaubid'][$i];
|
||||
if ($urlaubId <= 0) {
|
||||
$urlaubId = (int)$pdo->lastInsertId();
|
||||
}
|
||||
if ($urlaubId > 0) {
|
||||
vacationSyncCompanyHolidayFromUrlaub($pdo, $urlaubId, $internUserId);
|
||||
}
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$pdo->commit();
|
||||
} catch (Throwable $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
$pdo->rollBack();
|
||||
}
|
||||
throw $e;
|
||||
}
|
||||
echo "Einträge wurden in der Datenbank gespeichert!<br><br>";
|
||||
|
||||
}else if (($_POST["aktion"] ?? '') == "6") {
|
||||
@@ -2023,10 +2048,10 @@ if(!check_worker()){
|
||||
<script type="text/javascript">
|
||||
|
||||
function AddneueTermine(){
|
||||
|
||||
|
||||
var div = document.getElementById('neuerUrlaub');
|
||||
|
||||
div.innerHTML += "Start: <input name=Starttime[] type=date class='form-control' > Ende: <input name=Endetime[] type=date class='form-control' >Vertretung: <input type=text name=vertretung[] weight=100 class='form-control'> Vertretung Telefon: <input type=text name=vertretertelefon[] weight=100 class='form-control'> Vertretung Adresse: <input type=text name=vertreteradresse[] weight=100 class='form-control'> Vertretung Webseite: <input type=text name=vertreterurl[] weight=100 class='form-control'> <input name=urlaubid[] type=hidden value='0'> <br>";
|
||||
|
||||
div.innerHTML += "Start: <input name=Starttime[] type=date class='form-control' > Ende: <input name=Endetime[] type=date class='form-control' >Vertretung: <input type=text name=vertretung[] weight=100 class='form-control' required> Vertretung Telefon: <input type=text name=vertretertelefon[] weight=100 class='form-control' required> Vertretung Adresse: <input type=text name=vertreteradresse[] weight=100 class='form-control' required> Vertretung Webseite: <input type=text name=vertreterurl[] weight=100 class='form-control' required> <input name=urlaubid[] type=hidden value='0'> <br>";
|
||||
//Public: <select name=aktiv[] id='aktiv' required ><option value='1' >Ja</option> <option value='0'>Nein</option></select>
|
||||
|
||||
//document.getElementById('neueTermine').innerHTML = div;
|
||||
|
||||
+127
-97
@@ -405,6 +405,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
SendMailMessageVorlage($pdo, '1', $tid, $mailTemplateId);
|
||||
}
|
||||
|
||||
impfWorkflowNotificationProcess($pdo);
|
||||
$message = count($terminIds) . " Terminanfragen wurden erstellt und versendet.";
|
||||
} catch (Throwable $e) {
|
||||
if ($pdo->inTransaction()) {
|
||||
@@ -436,7 +437,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
1
|
||||
);
|
||||
if ($ok) {
|
||||
$notificationEvents = impfWorkflowNotificationProcess($pdo);
|
||||
$message = $msg;
|
||||
if (!empty($notificationEvents)) {
|
||||
$message .= ' ' . count($notificationEvents) . " Impfworkflow-Benachrichtigung(en) wurden versendet.";
|
||||
}
|
||||
} else {
|
||||
$error = $msg;
|
||||
}
|
||||
@@ -481,7 +486,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
1
|
||||
);
|
||||
if ($ok) {
|
||||
$notificationEvents = impfWorkflowNotificationProcess($pdo);
|
||||
$message = $msg;
|
||||
if (!empty($notificationEvents)) {
|
||||
$message .= ' ' . count($notificationEvents) . " Impfworkflow-Benachrichtigung(en) wurden versendet.";
|
||||
}
|
||||
} else {
|
||||
$error = $msg;
|
||||
}
|
||||
@@ -595,6 +604,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$exists = (bool)$stDelete->fetch(PDO::FETCH_ASSOC);
|
||||
workflowDeleteWaitlistEntry($pdo, $warteid);
|
||||
if ($exists) {
|
||||
impfWorkflowNotificationProcess($pdo);
|
||||
$message = "Wartelisten-Eintrag wurde gelöscht.";
|
||||
} else {
|
||||
$error = "Wartelisten-Eintrag nicht gefunden.";
|
||||
@@ -663,51 +673,67 @@ $eventOverview = [];
|
||||
$planWaitCounts = [];
|
||||
|
||||
try {
|
||||
$stRules = $pdo->prepare("SELECT r.impfstoff_id, r.dosen_pro_flasche, i.impfname,
|
||||
COALESCE((SELECT COUNT(DISTINCT w.userid) FROM warteliste w WHERE w.checked = 1 AND (w.impfstoff = r.impfstoff_id OR w.impfstoff = 0)),0) AS wartende
|
||||
FROM impfstoff_workflow r
|
||||
INNER JOIN impfstoff i ON i.impfid = r.impfstoff_id
|
||||
WHERE (i.aktiv = 1 OR i.aktivwarteliste = 1 OR i.aktivtermin = 1 OR i.aktivgrippe = 1)
|
||||
ORDER BY i.impfname");
|
||||
$stRules->execute();
|
||||
$rules = $stRules->fetchAll(PDO::FETCH_ASSOC);
|
||||
$needsPlanData = in_array($view, ['teilnehmer', 'event-create'], true);
|
||||
$needsEligibilityData = ($view === 'event-create');
|
||||
$needsPersonSearch = ($view === 'teilnehmer' && $personSearch !== '');
|
||||
$needsWaitRows = ($view === 'warteliste');
|
||||
$needsUpcomingRows = ($view === 'event-teilnehmer');
|
||||
|
||||
$plans = impfGetZeitraumRows($pdo, true);
|
||||
if ($needsPlanData) {
|
||||
$stRules = $pdo->prepare("SELECT r.impfstoff_id, r.dosen_pro_flasche, i.impfname,
|
||||
COALESCE((SELECT COUNT(DISTINCT w.userid) FROM warteliste w WHERE w.checked = 1 AND (w.impfstoff = r.impfstoff_id OR w.impfstoff = 0)),0) AS wartende
|
||||
FROM impfstoff_workflow r
|
||||
INNER JOIN impfstoff i ON i.impfid = r.impfstoff_id
|
||||
WHERE (i.aktiv = 1 OR i.aktivwarteliste = 1 OR i.aktivtermin = 1 OR i.aktivgrippe = 1)
|
||||
ORDER BY i.impfname");
|
||||
$stRules->execute();
|
||||
$rules = $stRules->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
$planExistsForImpfstoff = [];
|
||||
foreach ($plans as $p) {
|
||||
foreach ($p['impfstoff_id_list'] as $impfstoffId) {
|
||||
$planExistsForImpfstoff[(int)$impfstoffId] = true;
|
||||
}
|
||||
}
|
||||
$plans = impfGetZeitraumRows($pdo, true);
|
||||
|
||||
foreach ($rules as $r) {
|
||||
$iid = (int)$r['impfstoff_id'];
|
||||
$dosen = (int)$r['dosen_pro_flasche'];
|
||||
if ($dosen <= 0 || !isset($planExistsForImpfstoff[$iid])) {
|
||||
continue;
|
||||
$planExistsForImpfstoff = [];
|
||||
foreach ($plans as $p) {
|
||||
foreach ($p['impfstoff_id_list'] as $impfstoffId) {
|
||||
$planExistsForImpfstoff[(int)$impfstoffId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$configuredImpfstoffe[] = $r;
|
||||
$hasEligiblePlan = false;
|
||||
foreach ($plans as $plan) {
|
||||
if (!in_array($iid, $plan['impfstoff_id_list'] ?? [], true)) {
|
||||
foreach ($rules as $r) {
|
||||
$iid = (int)$r['impfstoff_id'];
|
||||
if (!isset($planExistsForImpfstoff[$iid])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$planId = (int)$plan['zeitraum_id'];
|
||||
$planWaitCounts[$iid][$planId] = workflowCountWaitersForPlan($pdo, $iid, $planId);
|
||||
if ($planWaitCounts[$iid][$planId] >= $dosen) {
|
||||
$hasEligiblePlan = true;
|
||||
$configuredImpfstoffe[] = $r;
|
||||
if (!$needsEligibilityData) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasEligiblePlan) {
|
||||
$eligible[] = $r;
|
||||
$dosen = (int)$r['dosen_pro_flasche'];
|
||||
if ($dosen <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hasEligiblePlan = false;
|
||||
foreach ($plans as $plan) {
|
||||
if (!in_array($iid, $plan['impfstoff_id_list'] ?? [], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$planId = (int)$plan['zeitraum_id'];
|
||||
$planWaitCounts[$iid][$planId] = workflowCountWaitersForPlan($pdo, $iid, $planId);
|
||||
if ($planWaitCounts[$iid][$planId] >= $dosen) {
|
||||
$hasEligiblePlan = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($hasEligiblePlan) {
|
||||
$eligible[] = $r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($personSearch !== '') {
|
||||
if ($needsPersonSearch) {
|
||||
$searchLike = '%' . $personSearch . '%';
|
||||
$searchExactId = ctype_digit($personSearch) ? (int)$personSearch : -1;
|
||||
$stPersons = $pdo->prepare("SELECT person_id, vorname, nachname, geburtstag, email, tele, ort, plz, strasse
|
||||
@@ -726,74 +752,78 @@ try {
|
||||
$personResults = $stPersons->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
$stWait = $pdo->prepare("SELECT w.warteid, w.userid, w.checked, w.impfstoff, w.impfart, w.impfenzeitraum, w.zeitraum_id, w.letzteimpfung, w.date_created,
|
||||
p.vorname, p.nachname, p.geburtstag, p.email, p.tele,
|
||||
i.impfname
|
||||
FROM warteliste w
|
||||
INNER JOIN persons p ON p.person_id = w.userid
|
||||
LEFT JOIN impfstoff i ON i.impfid = w.impfstoff
|
||||
WHERE w.checked IN (0, 1)
|
||||
ORDER BY w.checked DESC, w.date_created ASC
|
||||
LIMIT 500");
|
||||
$stWait->execute();
|
||||
$waitRows = $stWait->fetchAll(PDO::FETCH_ASSOC);
|
||||
if ($needsWaitRows) {
|
||||
$stWait = $pdo->prepare("SELECT w.warteid, w.userid, w.checked, w.impfstoff, w.impfart, w.impfenzeitraum, w.zeitraum_id, w.letzteimpfung, w.date_created,
|
||||
p.vorname, p.nachname, p.geburtstag, p.email, p.tele,
|
||||
i.impfname
|
||||
FROM warteliste w
|
||||
INNER JOIN persons p ON p.person_id = w.userid
|
||||
LEFT JOIN impfstoff i ON i.impfid = w.impfstoff
|
||||
WHERE w.checked IN (0, 1)
|
||||
ORDER BY w.checked DESC, w.date_created ASC
|
||||
LIMIT 500");
|
||||
$stWait->execute();
|
||||
$waitRows = $stWait->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($waitRows as &$waitRow) {
|
||||
$waitRow['zeitraum_labels'] = impfGetWartelistenZeitraeumeLabels($pdo, (int)$waitRow['warteid'], false);
|
||||
if (!empty($waitRow['zeitraum_labels'])) {
|
||||
$waitRow['impfenzeitraum'] = implode(' | ', $waitRow['zeitraum_labels']);
|
||||
$waitIds = array_map(static function (array $waitRow): int {
|
||||
return (int)($waitRow['warteid'] ?? 0);
|
||||
}, $waitRows);
|
||||
$waitLabelsById = impfGetWartelistenZeitraeumeLabelsMap($pdo, $waitIds, false);
|
||||
|
||||
foreach ($waitRows as &$waitRow) {
|
||||
$warteid = (int)($waitRow['warteid'] ?? 0);
|
||||
$waitRow['zeitraum_labels'] = $waitLabelsById[$warteid] ?? [];
|
||||
if (!empty($waitRow['zeitraum_labels'])) {
|
||||
$waitRow['impfenzeitraum'] = implode(' | ', $waitRow['zeitraum_labels']);
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($waitRow);
|
||||
|
||||
$notificationEvents = impfWorkflowNotificationProcess($pdo);
|
||||
if (!empty($notificationEvents)) {
|
||||
$notificationText = count($notificationEvents) . " Impfworkflow-Benachrichtigung(en) wurden versendet.";
|
||||
$message = ($message === '') ? $notificationText : ($message . ' ' . $notificationText);
|
||||
unset($waitRow);
|
||||
}
|
||||
|
||||
$stUpcoming = $pdo->prepare("SELECT ts.timeid, ts.date, ts.start, ts.ende, ts.impfdosen,
|
||||
i.impfname, o.anzeigename, o.adresse,
|
||||
it.terminid, it.checked, it.behandelt, it.impfart,
|
||||
p.vorname, p.nachname, p.geburtstag, p.email, p.tele
|
||||
FROM timeslots ts
|
||||
INNER JOIN impfstoff i ON i.impfid = ts.impfstoff
|
||||
LEFT JOIN impfort o ON o.ortid = ts.impfortid
|
||||
LEFT JOIN impftermin it ON it.timeid = ts.timeid
|
||||
LEFT JOIN persons p ON p.person_id = it.userid
|
||||
WHERE ts.date >= :today
|
||||
AND ts.aktiv = 1
|
||||
ORDER BY ts.date, ts.start, ts.ende, i.impfname, p.nachname, p.vorname");
|
||||
$stUpcoming->execute(['today' => date('Y-m-d')]);
|
||||
$upcomingRows = $stUpcoming->fetchAll(PDO::FETCH_ASSOC);
|
||||
if ($needsUpcomingRows) {
|
||||
$stUpcoming = $pdo->prepare("SELECT ts.timeid, ts.date, ts.start, ts.ende, ts.impfdosen,
|
||||
i.impfname, o.anzeigename, o.adresse,
|
||||
it.terminid, it.checked, it.behandelt, it.impfart,
|
||||
p.vorname, p.nachname, p.geburtstag, p.email, p.tele
|
||||
FROM timeslots ts
|
||||
INNER JOIN impfstoff i ON i.impfid = ts.impfstoff
|
||||
LEFT JOIN impfort o ON o.ortid = ts.impfortid
|
||||
LEFT JOIN impftermin it ON it.timeid = ts.timeid
|
||||
LEFT JOIN persons p ON p.person_id = it.userid
|
||||
WHERE ts.date >= :today
|
||||
AND ts.aktiv = 1
|
||||
ORDER BY ts.date, ts.start, ts.ende, i.impfname, p.nachname, p.vorname");
|
||||
$stUpcoming->execute(['today' => date('Y-m-d')]);
|
||||
$upcomingRows = $stUpcoming->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($upcomingRows as $row) {
|
||||
$timeid = (int)$row['timeid'];
|
||||
if (!isset($eventOverview[$timeid])) {
|
||||
$eventOverview[$timeid] = [
|
||||
'timeid' => $timeid,
|
||||
'date' => $row['date'],
|
||||
'start' => $row['start'],
|
||||
'ende' => $row['ende'],
|
||||
'impfdosen' => (int)$row['impfdosen'],
|
||||
'impfname' => $row['impfname'],
|
||||
'anzeigename' => $row['anzeigename'],
|
||||
'adresse' => $row['adresse'],
|
||||
'teilnehmer' => [],
|
||||
];
|
||||
}
|
||||
if (!empty($row['terminid'])) {
|
||||
$eventOverview[$timeid]['teilnehmer'][] = [
|
||||
'terminid' => (int)$row['terminid'],
|
||||
'checked' => (int)($row['checked'] ?? 0),
|
||||
'behandelt' => (int)($row['behandelt'] ?? 0),
|
||||
'impfart' => (int)($row['impfart'] ?? 1),
|
||||
'vorname' => (string)($row['vorname'] ?? ''),
|
||||
'nachname' => (string)($row['nachname'] ?? ''),
|
||||
'geburtstag' => (string)($row['geburtstag'] ?? ''),
|
||||
'email' => (string)($row['email'] ?? ''),
|
||||
'tele' => (string)($row['tele'] ?? ''),
|
||||
];
|
||||
foreach ($upcomingRows as $row) {
|
||||
$timeid = (int)$row['timeid'];
|
||||
if (!isset($eventOverview[$timeid])) {
|
||||
$eventOverview[$timeid] = [
|
||||
'timeid' => $timeid,
|
||||
'date' => $row['date'],
|
||||
'start' => $row['start'],
|
||||
'ende' => $row['ende'],
|
||||
'impfdosen' => (int)$row['impfdosen'],
|
||||
'impfname' => $row['impfname'],
|
||||
'anzeigename' => $row['anzeigename'],
|
||||
'adresse' => $row['adresse'],
|
||||
'teilnehmer' => [],
|
||||
];
|
||||
}
|
||||
if (!empty($row['terminid'])) {
|
||||
$eventOverview[$timeid]['teilnehmer'][] = [
|
||||
'terminid' => (int)$row['terminid'],
|
||||
'checked' => (int)($row['checked'] ?? 0),
|
||||
'behandelt' => (int)($row['behandelt'] ?? 0),
|
||||
'impfart' => (int)($row['impfart'] ?? 1),
|
||||
'vorname' => (string)($row['vorname'] ?? ''),
|
||||
'nachname' => (string)($row['nachname'] ?? ''),
|
||||
'geburtstag' => (string)($row['geburtstag'] ?? ''),
|
||||
'email' => (string)($row['email'] ?? ''),
|
||||
'tele' => (string)($row['tele'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable $e) {
|
||||
@@ -1257,5 +1287,5 @@ try {
|
||||
</div>
|
||||
|
||||
<?php include __DIR__ . "/templates/footer.inc.php"; ?>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
<?php
|
||||
|
||||
if (!function_exists('vacationSyncTableExists')) {
|
||||
function vacationSyncTableExists(PDO $pdo, string $table): bool
|
||||
{
|
||||
$stmt = $pdo->prepare("SHOW TABLES LIKE :table_name");
|
||||
$stmt->execute(['table_name' => $table]);
|
||||
return (bool)$stmt->fetchColumn();
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('vacationSyncTableHasColumn')) {
|
||||
function vacationSyncTableHasColumn(PDO $pdo, string $table, string $column): bool
|
||||
{
|
||||
$stmt = $pdo->prepare("SHOW COLUMNS FROM `" . $table . "` LIKE :column_name");
|
||||
$stmt->execute(['column_name' => $column]);
|
||||
return (bool)$stmt->fetch(PDO::FETCH_ASSOC);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('vacationSyncEnsureSchema')) {
|
||||
function vacationSyncEnsureSchema(PDO $pdo): void
|
||||
{
|
||||
$urlaubExists = vacationSyncTableExists($pdo, 'urlaub');
|
||||
$companyHolidaysExists = vacationSyncTableExists($pdo, 'company_holidays');
|
||||
|
||||
if (!$urlaubExists && !$companyHolidaysExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($urlaubExists && !vacationSyncTableHasColumn($pdo, 'urlaub', 'company_holiday_id')) {
|
||||
$pdo->exec("ALTER TABLE urlaub ADD COLUMN company_holiday_id INT NULL AFTER vertreterurl");
|
||||
}
|
||||
|
||||
if (!$companyHolidaysExists) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vacationSyncTableHasColumn($pdo, 'company_holidays', 'urlaub_id')) {
|
||||
$pdo->exec("ALTER TABLE company_holidays ADD COLUMN urlaub_id INT NULL AFTER created_by");
|
||||
}
|
||||
|
||||
if (!vacationSyncTableHasColumn($pdo, 'company_holidays', 'vertretung')) {
|
||||
$pdo->exec("ALTER TABLE company_holidays ADD COLUMN vertretung VARCHAR(255) NOT NULL DEFAULT '' AFTER description");
|
||||
}
|
||||
|
||||
if (!vacationSyncTableHasColumn($pdo, 'company_holidays', 'vertretertelefon')) {
|
||||
$pdo->exec("ALTER TABLE company_holidays ADD COLUMN vertretertelefon VARCHAR(255) NOT NULL DEFAULT '' AFTER vertretung");
|
||||
}
|
||||
|
||||
if (!vacationSyncTableHasColumn($pdo, 'company_holidays', 'vertreteradresse')) {
|
||||
$pdo->exec("ALTER TABLE company_holidays ADD COLUMN vertreteradresse VARCHAR(1000) NOT NULL DEFAULT '' AFTER vertretertelefon");
|
||||
}
|
||||
|
||||
if (!vacationSyncTableHasColumn($pdo, 'company_holidays', 'vertreterurl')) {
|
||||
$pdo->exec("ALTER TABLE company_holidays ADD COLUMN vertreterurl VARCHAR(255) NOT NULL DEFAULT '' AFTER vertreteradresse");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('vacationSyncFindCompanyHolidayIdForUrlaub')) {
|
||||
function vacationSyncFindCompanyHolidayIdForUrlaub(PDO $pdo, int $urlaubId): int
|
||||
{
|
||||
if ($urlaubId <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vacationSyncTableExists($pdo, 'urlaub') || !vacationSyncTableExists($pdo, 'company_holidays')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
vacationSyncEnsureSchema($pdo);
|
||||
|
||||
$stmt = $pdo->prepare("SELECT company_holiday_id FROM urlaub WHERE urlaubid = :urlaub_id LIMIT 1");
|
||||
$stmt->execute(['urlaub_id' => $urlaubId]);
|
||||
$linkedId = (int)($stmt->fetchColumn() ?: 0);
|
||||
if ($linkedId > 0) {
|
||||
return $linkedId;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT id FROM company_holidays WHERE urlaub_id = :urlaub_id LIMIT 1");
|
||||
$stmt->execute(['urlaub_id' => $urlaubId]);
|
||||
$linkedId = (int)($stmt->fetchColumn() ?: 0);
|
||||
if ($linkedId > 0) {
|
||||
return $linkedId;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT start, ende FROM urlaub WHERE urlaubid = :urlaub_id LIMIT 1");
|
||||
$stmt->execute(['urlaub_id' => $urlaubId]);
|
||||
$urlaub = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$urlaub) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT id
|
||||
FROM company_holidays
|
||||
WHERE start_date = :start_date
|
||||
AND end_date = :end_date
|
||||
ORDER BY id ASC
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([
|
||||
'start_date' => $urlaub['start'],
|
||||
'end_date' => $urlaub['ende'],
|
||||
]);
|
||||
return (int)($stmt->fetchColumn() ?: 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('vacationSyncFindUrlaubIdForCompanyHoliday')) {
|
||||
function vacationSyncFindUrlaubIdForCompanyHoliday(PDO $pdo, int $companyHolidayId): int
|
||||
{
|
||||
if ($companyHolidayId <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vacationSyncTableExists($pdo, 'urlaub') || !vacationSyncTableExists($pdo, 'company_holidays')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
vacationSyncEnsureSchema($pdo);
|
||||
|
||||
$stmt = $pdo->prepare("SELECT urlaub_id FROM company_holidays WHERE id = :company_holiday_id LIMIT 1");
|
||||
$stmt->execute(['company_holiday_id' => $companyHolidayId]);
|
||||
$linkedId = (int)($stmt->fetchColumn() ?: 0);
|
||||
if ($linkedId > 0) {
|
||||
return $linkedId;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT urlaubid FROM urlaub WHERE company_holiday_id = :company_holiday_id LIMIT 1");
|
||||
$stmt->execute(['company_holiday_id' => $companyHolidayId]);
|
||||
$linkedId = (int)($stmt->fetchColumn() ?: 0);
|
||||
if ($linkedId > 0) {
|
||||
return $linkedId;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT start_date, end_date FROM company_holidays WHERE id = :company_holiday_id LIMIT 1");
|
||||
$stmt->execute(['company_holiday_id' => $companyHolidayId]);
|
||||
$holiday = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$holiday) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT urlaubid
|
||||
FROM urlaub
|
||||
WHERE start = :start_date
|
||||
AND ende = :end_date
|
||||
ORDER BY urlaubid ASC
|
||||
LIMIT 1
|
||||
");
|
||||
$stmt->execute([
|
||||
'start_date' => $holiday['start_date'],
|
||||
'end_date' => $holiday['end_date'],
|
||||
]);
|
||||
return (int)($stmt->fetchColumn() ?: 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('vacationSyncCompanyHolidayFromUrlaub')) {
|
||||
function vacationSyncCompanyHolidayFromUrlaub(PDO $pdo, int $urlaubId, ?int $createdBy = null): int
|
||||
{
|
||||
if ($urlaubId <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vacationSyncTableExists($pdo, 'urlaub') || !vacationSyncTableExists($pdo, 'company_holidays')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
vacationSyncEnsureSchema($pdo);
|
||||
|
||||
$stmtUrlaub = $pdo->prepare("
|
||||
SELECT urlaubid, start, ende, vertretung, vertretertelefon, vertreteradresse, vertreterurl, company_holiday_id
|
||||
FROM urlaub
|
||||
WHERE urlaubid = :urlaub_id
|
||||
LIMIT 1
|
||||
");
|
||||
$stmtUrlaub->execute(['urlaub_id' => $urlaubId]);
|
||||
$urlaub = $stmtUrlaub->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$urlaub) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$companyHolidayId = (int)($urlaub['company_holiday_id'] ?? 0);
|
||||
if ($companyHolidayId <= 0) {
|
||||
$companyHolidayId = vacationSyncFindCompanyHolidayIdForUrlaub($pdo, $urlaubId);
|
||||
}
|
||||
|
||||
$description = 'Betriebsurlaub';
|
||||
if ($companyHolidayId > 0) {
|
||||
$stmtExisting = $pdo->prepare("SELECT description FROM company_holidays WHERE id = :company_holiday_id LIMIT 1");
|
||||
$stmtExisting->execute(['company_holiday_id' => $companyHolidayId]);
|
||||
$existingDescription = $stmtExisting->fetchColumn();
|
||||
if ($existingDescription !== false && trim((string)$existingDescription) !== '') {
|
||||
$description = (string)$existingDescription;
|
||||
}
|
||||
}
|
||||
|
||||
if ($companyHolidayId > 0) {
|
||||
$stmtUpdate = $pdo->prepare("
|
||||
UPDATE company_holidays
|
||||
SET start_date = :start_date,
|
||||
end_date = :end_date,
|
||||
vertretung = :vertretung,
|
||||
vertretertelefon = :vertretertelefon,
|
||||
vertreteradresse = :vertreteradresse,
|
||||
vertreterurl = :vertreterurl,
|
||||
urlaub_id = :urlaub_id
|
||||
WHERE id = :company_holiday_id
|
||||
");
|
||||
$stmtUpdate->execute([
|
||||
'start_date' => $urlaub['start'],
|
||||
'end_date' => $urlaub['ende'],
|
||||
'vertretung' => (string)$urlaub['vertretung'],
|
||||
'vertretertelefon' => (string)$urlaub['vertretertelefon'],
|
||||
'vertreteradresse' => (string)$urlaub['vertreteradresse'],
|
||||
'vertreterurl' => (string)$urlaub['vertreterurl'],
|
||||
'urlaub_id' => $urlaubId,
|
||||
'company_holiday_id' => $companyHolidayId,
|
||||
]);
|
||||
} else {
|
||||
$stmtInsert = $pdo->prepare("
|
||||
INSERT INTO company_holidays (
|
||||
start_date, end_date, description, vertretung, vertretertelefon, vertreteradresse, vertreterurl, created_by, urlaub_id
|
||||
)
|
||||
VALUES (
|
||||
:start_date, :end_date, :description, :vertretung, :vertretertelefon, :vertreteradresse, :vertreterurl, :created_by, :urlaub_id
|
||||
)
|
||||
");
|
||||
$stmtInsert->execute([
|
||||
'start_date' => $urlaub['start'],
|
||||
'end_date' => $urlaub['ende'],
|
||||
'description' => $description,
|
||||
'vertretung' => (string)$urlaub['vertretung'],
|
||||
'vertretertelefon' => (string)$urlaub['vertretertelefon'],
|
||||
'vertreteradresse' => (string)$urlaub['vertreteradresse'],
|
||||
'vertreterurl' => (string)$urlaub['vertreterurl'],
|
||||
'created_by' => $createdBy,
|
||||
'urlaub_id' => $urlaubId,
|
||||
]);
|
||||
$companyHolidayId = (int)$pdo->lastInsertId();
|
||||
}
|
||||
|
||||
if ($companyHolidayId > 0) {
|
||||
$stmtLink = $pdo->prepare("UPDATE urlaub SET company_holiday_id = :company_holiday_id WHERE urlaubid = :urlaub_id");
|
||||
$stmtLink->execute([
|
||||
'company_holiday_id' => $companyHolidayId,
|
||||
'urlaub_id' => $urlaubId,
|
||||
]);
|
||||
}
|
||||
|
||||
return $companyHolidayId;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('vacationSyncUrlaubFromCompanyHoliday')) {
|
||||
function vacationSyncUrlaubFromCompanyHoliday(PDO $pdo, int $companyHolidayId): int
|
||||
{
|
||||
if ($companyHolidayId <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!vacationSyncTableExists($pdo, 'company_holidays') || !vacationSyncTableExists($pdo, 'urlaub')) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
vacationSyncEnsureSchema($pdo);
|
||||
|
||||
$stmtHoliday = $pdo->prepare("
|
||||
SELECT id, start_date, end_date, vertretung, vertretertelefon, vertreteradresse, vertreterurl, urlaub_id
|
||||
FROM company_holidays
|
||||
WHERE id = :company_holiday_id
|
||||
LIMIT 1
|
||||
");
|
||||
$stmtHoliday->execute(['company_holiday_id' => $companyHolidayId]);
|
||||
$holiday = $stmtHoliday->fetch(PDO::FETCH_ASSOC);
|
||||
if (!$holiday) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$urlaubId = (int)($holiday['urlaub_id'] ?? 0);
|
||||
if ($urlaubId <= 0) {
|
||||
$urlaubId = vacationSyncFindUrlaubIdForCompanyHoliday($pdo, $companyHolidayId);
|
||||
}
|
||||
|
||||
if ($urlaubId > 0) {
|
||||
$stmtUpdate = $pdo->prepare("
|
||||
UPDATE urlaub
|
||||
SET start = :start_date,
|
||||
ende = :end_date,
|
||||
vertretung = :vertretung,
|
||||
vertretertelefon = :vertretertelefon,
|
||||
vertreteradresse = :vertreteradresse,
|
||||
vertreterurl = :vertreterurl,
|
||||
company_holiday_id = :company_holiday_id
|
||||
WHERE urlaubid = :urlaub_id
|
||||
");
|
||||
$stmtUpdate->execute([
|
||||
'start_date' => $holiday['start_date'],
|
||||
'end_date' => $holiday['end_date'],
|
||||
'vertretung' => (string)$holiday['vertretung'],
|
||||
'vertretertelefon' => (string)$holiday['vertretertelefon'],
|
||||
'vertreteradresse' => (string)$holiday['vertreteradresse'],
|
||||
'vertreterurl' => (string)$holiday['vertreterurl'],
|
||||
'company_holiday_id' => $companyHolidayId,
|
||||
'urlaub_id' => $urlaubId,
|
||||
]);
|
||||
} else {
|
||||
$stmtInsert = $pdo->prepare("
|
||||
INSERT INTO urlaub
|
||||
(vertretung, start, ende, vertretertelefon, vertreteradresse, vertreterurl, company_holiday_id)
|
||||
VALUES
|
||||
(:vertretung, :start_date, :end_date, :vertretertelefon, :vertreteradresse, :vertreterurl, :company_holiday_id)
|
||||
");
|
||||
$stmtInsert->execute([
|
||||
'vertretung' => (string)$holiday['vertretung'],
|
||||
'start_date' => $holiday['start_date'],
|
||||
'end_date' => $holiday['end_date'],
|
||||
'vertretertelefon' => (string)$holiday['vertretertelefon'],
|
||||
'vertreteradresse' => (string)$holiday['vertreteradresse'],
|
||||
'vertreterurl' => (string)$holiday['vertreterurl'],
|
||||
'company_holiday_id' => $companyHolidayId,
|
||||
]);
|
||||
$urlaubId = (int)$pdo->lastInsertId();
|
||||
}
|
||||
|
||||
if ($urlaubId > 0) {
|
||||
$stmtLink = $pdo->prepare("UPDATE company_holidays SET urlaub_id = :urlaub_id WHERE id = :company_holiday_id");
|
||||
$stmtLink->execute([
|
||||
'urlaub_id' => $urlaubId,
|
||||
'company_holiday_id' => $companyHolidayId,
|
||||
]);
|
||||
}
|
||||
|
||||
return $urlaubId;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('vacationSyncDeleteCompanyHolidayByUrlaub')) {
|
||||
function vacationSyncDeleteCompanyHolidayByUrlaub(PDO $pdo, int $urlaubId): void
|
||||
{
|
||||
if (!vacationSyncTableExists($pdo, 'urlaub') || !vacationSyncTableExists($pdo, 'company_holidays')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$companyHolidayId = vacationSyncFindCompanyHolidayIdForUrlaub($pdo, $urlaubId);
|
||||
if ($companyHolidayId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("DELETE FROM company_holidays WHERE id = :company_holiday_id");
|
||||
$stmt->execute(['company_holiday_id' => $companyHolidayId]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('vacationSyncDeleteUrlaubByCompanyHoliday')) {
|
||||
function vacationSyncDeleteUrlaubByCompanyHoliday(PDO $pdo, int $companyHolidayId): void
|
||||
{
|
||||
if (!vacationSyncTableExists($pdo, 'urlaub') || !vacationSyncTableExists($pdo, 'company_holidays')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$urlaubId = vacationSyncFindUrlaubIdForCompanyHoliday($pdo, $companyHolidayId);
|
||||
if ($urlaubId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("DELETE FROM urlaub WHERE urlaubid = :urlaub_id");
|
||||
$stmt->execute(['urlaub_id' => $urlaubId]);
|
||||
}
|
||||
}
|
||||
@@ -550,6 +550,100 @@ if (!function_exists('impfGetWartelistenZeitraeumeLabels')) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('impfGetWartelistenZeitraeumeLabelsMap')) {
|
||||
function impfGetWartelistenZeitraeumeLabelsMap(PDO $pdo, array $warteids, bool $onlyActive = false): array
|
||||
{
|
||||
$warteids = array_values(array_unique(array_filter(array_map('intval', $warteids), static function (int $warteid): bool {
|
||||
return $warteid > 0;
|
||||
})));
|
||||
|
||||
if (empty($warteids) || !impfTableExists($pdo, 'warteliste_zeitraum')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($warteids as $warteid) {
|
||||
$result[$warteid] = [];
|
||||
}
|
||||
|
||||
$placeholders = [];
|
||||
$params = [];
|
||||
foreach ($warteids as $index => $warteid) {
|
||||
$key = 'wid' . $index;
|
||||
$placeholders[] = ':' . $key;
|
||||
$params[$key] = $warteid;
|
||||
}
|
||||
$inList = implode(', ', $placeholders);
|
||||
|
||||
$sql = "SELECT wz.warteid, z.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at,
|
||||
o.anzeigename, o.adresse
|
||||
FROM warteliste_zeitraum wz
|
||||
INNER JOIN impf_zeitraum z ON z.zeitraum_id = wz.zeitraum_id
|
||||
LEFT JOIN impfort o ON o.ortid = z.impfortid
|
||||
WHERE wz.warteid IN (" . $inList . ")";
|
||||
if ($onlyActive) {
|
||||
$sql .= " AND z.aktiv = 1";
|
||||
}
|
||||
$sql .= " ORDER BY wz.warteid, z.wochentag, z.start, z.ende, z.bezeichnung, z.zeitraum_id";
|
||||
|
||||
$st = $pdo->prepare($sql);
|
||||
$st->execute($params);
|
||||
$rows = $st->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$warteid = (int)($row['warteid'] ?? 0);
|
||||
if ($warteid <= 0) {
|
||||
continue;
|
||||
}
|
||||
$row['label'] = impfZeitraumLabel($row);
|
||||
$result[$warteid][] = (string)$row['label'];
|
||||
}
|
||||
|
||||
$missing = array_values(array_filter($warteids, static function (int $warteid) use ($result): bool {
|
||||
return empty($result[$warteid]);
|
||||
}));
|
||||
|
||||
if (empty($missing)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$fallbackPlaceholders = [];
|
||||
$fallbackParams = [];
|
||||
foreach ($missing as $index => $warteid) {
|
||||
$key = 'f_wid' . $index;
|
||||
$fallbackPlaceholders[] = ':' . $key;
|
||||
$fallbackParams[$key] = $warteid;
|
||||
}
|
||||
$fallbackInList = implode(', ', $fallbackPlaceholders);
|
||||
|
||||
$fallbackSql = "SELECT w.warteid, w.zeitraum_id, z.bezeichnung, z.wochentag, z.start, z.ende, z.impfortid, z.aktiv, z.created_at,
|
||||
o.anzeigename, o.adresse
|
||||
FROM warteliste w
|
||||
LEFT JOIN impf_zeitraum z ON z.zeitraum_id = w.zeitraum_id
|
||||
LEFT JOIN impfort o ON o.ortid = z.impfortid
|
||||
WHERE w.warteid IN (" . $fallbackInList . ")
|
||||
AND w.zeitraum_id IS NOT NULL";
|
||||
if ($onlyActive) {
|
||||
$fallbackSql .= " AND z.aktiv = 1";
|
||||
}
|
||||
|
||||
$stFallback = $pdo->prepare($fallbackSql);
|
||||
$stFallback->execute($fallbackParams);
|
||||
$fallbackRows = $stFallback->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($fallbackRows as $row) {
|
||||
$warteid = (int)($row['warteid'] ?? 0);
|
||||
if ($warteid <= 0) {
|
||||
continue;
|
||||
}
|
||||
$row['label'] = impfZeitraumLabel($row);
|
||||
$result[$warteid] = [(string)$row['label']];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('impfSetWartelistenZeitraeume')) {
|
||||
function impfSetWartelistenZeitraeume(PDO $pdo, int $warteid, $zeitraumIds): void
|
||||
{
|
||||
|
||||
+191
-197
@@ -1,197 +1,191 @@
|
||||
<?php
|
||||
// API: returns JSON events for FullCalendar
|
||||
session_start();
|
||||
require_once(__DIR__ . '/../inc/config.inc.php');
|
||||
require_once(__DIR__ . '/../inc/functions.inc.php');
|
||||
|
||||
// Enable full error reporting for API debugging
|
||||
ini_set('display_errors', '1');
|
||||
ini_set('display_startup_errors', '1');
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$user = check_user();
|
||||
$isAdmin = is_admin_user();
|
||||
|
||||
$start = $_GET['start'] ?? null; // expected ISO date
|
||||
$end = $_GET['end'] ?? null;
|
||||
$onlyApproved = isset($_GET['only_approved']) && ($_GET['only_approved'] == '1' || $_GET['only_approved'] === 'true');
|
||||
// public allows non-admin users to request all *approved* vacations (team view)
|
||||
$public = isset($_GET['public']) && ($_GET['public'] == '1' || $_GET['public'] === 'true');
|
||||
// include_rejected if set to 1 will return rejected entries; default behavior: do not return rejected for regular users
|
||||
$includeRejected = isset($_GET['include_rejected']) && ($_GET['include_rejected'] == '1' || $_GET['include_rejected'] === 'true');
|
||||
// only_personal forces the API to return only the current user's vacations (useful even if the user is admin)
|
||||
$onlyPersonal = isset($_GET['only_personal']) && ($_GET['only_personal'] == '1' || $_GET['only_personal'] === 'true');
|
||||
// public_all when used with public=1 returns all non-rejected team vacations (approved + beantragt)
|
||||
$publicAll = isset($_GET['public_all']) && ($_GET['public_all'] == '1' || $_GET['public_all'] === 'true');
|
||||
|
||||
if (!$start || !$end) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'start and end required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$events = [];
|
||||
try {
|
||||
$branch = 'unknown';
|
||||
$debugMode = isset($_GET['debug']) && ($_GET['debug'] == '1' || $_GET['debug'] === 'true');
|
||||
|
||||
// Vacations: support a personal-only mode, admin mode, and public/team mode
|
||||
if ($onlyPersonal) {
|
||||
$branch = 'onlyPersonal';
|
||||
if ($onlyApproved) {
|
||||
$branch = 'onlyPersonal_onlyApproved';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
} else {
|
||||
if ($includeRejected) {
|
||||
$branch = 'onlyPersonal_includeRejected';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
} else {
|
||||
$branch = 'onlyPersonal_excludeRejected';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) != 'abgelehnt') ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
}
|
||||
}
|
||||
} elseif ($isAdmin) {
|
||||
$branch = 'admin';
|
||||
if ($onlyApproved) {
|
||||
$branch = 'admin_onlyApproved';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
} else {
|
||||
// By default admins see genehmigt + beantragt; include_rejected=1 can override
|
||||
if ($includeRejected) {
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
} else {
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) IN ('genehmigt','beantragt')) ORDER BY v.start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$branch = 'public_or_regular';
|
||||
if ($public && $onlyApproved) {
|
||||
$branch = 'public_onlyApproved';
|
||||
// public team view: show all approved vacations (read-only)
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
} elseif ($public && $publicAll) {
|
||||
$branch = 'public_publicAll';
|
||||
// public team view: explicitly show only approved (genehmigt) and pending (beantragt) vacations
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) IN ('genehmigt','beantragt')) ORDER BY v.start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
} else {
|
||||
if ($onlyApproved) {
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
} else {
|
||||
// By default exclude rejected ('abgelehnt') for regular users; include if include_rejected=1
|
||||
if ($includeRejected) {
|
||||
$branch = 'regular_includeRejected';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
} else {
|
||||
$branch = 'regular_excludeRejected';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) != 'abgelehnt') ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$vacations = $stmt->fetchAll();
|
||||
|
||||
// If debug mode is enabled, prepare meta information
|
||||
if ($debugMode) {
|
||||
$rawStatuses = array_map(function($r){ return $r['status'] ?? null; }, $vacations);
|
||||
$meta = [
|
||||
'branch' => $branch,
|
||||
'count' => count($vacations),
|
||||
'raw_statuses' => $rawStatuses
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($vacations as $v) {
|
||||
// Normalize status: collapse whitespace (including NBSP), trim, lowercase
|
||||
if (isset($v['status'])) {
|
||||
$normalized = preg_replace('/\s+/u', ' ', $v['status']);
|
||||
$status = mb_strtolower(trim($normalized));
|
||||
} else {
|
||||
$status = '';
|
||||
}
|
||||
// Defensive filter: do not expose rejected ('abgelehnt') entries to non-admins
|
||||
if (!$isAdmin && !$includeRejected && mb_stripos($status, 'abgelehnt') !== false) {
|
||||
continue;
|
||||
}
|
||||
$isApproved = (mb_stripos($status, 'genehmigt') !== false);
|
||||
if ($isAdmin) {
|
||||
$title = $v['vorname'] . ' ' . $v['nachname'] . ' (' . ($v['status'] ?? 'beantragt') . ')';
|
||||
} else {
|
||||
$title = $isApproved ? 'Urlaub' : 'Urlaubsantrag';
|
||||
}
|
||||
// Safely compute end date; fallback to start_date if invalid
|
||||
try {
|
||||
$endInclusive = (new DateTime($v['end_date']))->modify('+1 day')->format('Y-m-d');
|
||||
} catch (Exception $e) {
|
||||
$endInclusive = $v['start_date'];
|
||||
}
|
||||
$events[] = [
|
||||
'id' => 'vac_' . $v['id'],
|
||||
'title' => $title,
|
||||
'start' => $v['start_date'],
|
||||
'end' => $endInclusive,
|
||||
'allDay' => true,
|
||||
'color' => ($isApproved) ? '#28a745' : '#ffc107',
|
||||
'extendedProps' => [
|
||||
'type' => 'user',
|
||||
'user_id' => $v['user_id'],
|
||||
'status' => $v['status'],
|
||||
'comment' => $v['comment_user'] ?? ''
|
||||
]
|
||||
];
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
$payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()];
|
||||
echo json_encode($payload);
|
||||
exit;
|
||||
}
|
||||
|
||||
} catch (Exception $ex) {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
$payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()];
|
||||
echo json_encode($payload);
|
||||
exit;
|
||||
}
|
||||
|
||||
// Company holidays (visible to all)
|
||||
$stmt = $pdo->prepare("SELECT * FROM company_holidays WHERE start_date <= ? AND end_date >= ? ORDER BY start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
$holidays = $stmt->fetchAll();
|
||||
|
||||
foreach ($holidays as $h) {
|
||||
$endInclusive = (new DateTime($h['end_date']))->modify('+1 day')->format('Y-m-d');
|
||||
$events[] = [
|
||||
'id' => 'com_' . $h['id'],
|
||||
'title' => $h['description'] ?: 'Betriebsurlaub',
|
||||
'start' => $h['start_date'],
|
||||
'end' => $endInclusive,
|
||||
'allDay' => true,
|
||||
'color' => '#007bff',
|
||||
'extendedProps' => [
|
||||
'type' => 'company',
|
||||
'description' => $h['description']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
if ($debugMode) {
|
||||
echo json_encode(['events' => $events, 'meta' => $meta]);
|
||||
} else {
|
||||
echo json_encode($events);
|
||||
}
|
||||
|
||||
?>
|
||||
<?php
|
||||
session_start();
|
||||
require_once(__DIR__ . '/../inc/config.inc.php');
|
||||
require_once(__DIR__ . '/../inc/functions.inc.php');
|
||||
|
||||
ini_set('display_errors', '1');
|
||||
ini_set('display_startup_errors', '1');
|
||||
error_reporting(E_ALL);
|
||||
|
||||
$user = check_user();
|
||||
$isAdmin = is_admin_user();
|
||||
|
||||
$start = $_GET['start'] ?? null;
|
||||
$end = $_GET['end'] ?? null;
|
||||
$onlyApproved = isset($_GET['only_approved']) && ($_GET['only_approved'] == '1' || $_GET['only_approved'] === 'true');
|
||||
$public = isset($_GET['public']) && ($_GET['public'] == '1' || $_GET['public'] === 'true');
|
||||
$includeRejected = isset($_GET['include_rejected']) && ($_GET['include_rejected'] == '1' || $_GET['include_rejected'] === 'true');
|
||||
$onlyPersonal = isset($_GET['only_personal']) && ($_GET['only_personal'] == '1' || $_GET['only_personal'] === 'true');
|
||||
$publicAll = isset($_GET['public_all']) && ($_GET['public_all'] == '1' || $_GET['public_all'] === 'true');
|
||||
|
||||
if (!$start || !$end) {
|
||||
http_response_code(400);
|
||||
echo json_encode(['error' => 'start and end required']);
|
||||
exit;
|
||||
}
|
||||
|
||||
$events = [];
|
||||
try {
|
||||
$branch = 'unknown';
|
||||
$debugMode = isset($_GET['debug']) && ($_GET['debug'] == '1' || $_GET['debug'] === 'true');
|
||||
$showEmployeeNames = $isAdmin || $public;
|
||||
|
||||
if ($onlyPersonal) {
|
||||
$branch = 'onlyPersonal';
|
||||
if ($onlyApproved) {
|
||||
$branch = 'onlyPersonal_onlyApproved';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
} else {
|
||||
if ($includeRejected) {
|
||||
$branch = 'onlyPersonal_includeRejected';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
} else {
|
||||
$branch = 'onlyPersonal_excludeRejected';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) != 'abgelehnt') ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
}
|
||||
}
|
||||
} elseif ($isAdmin) {
|
||||
$branch = 'admin';
|
||||
if ($onlyApproved) {
|
||||
$branch = 'admin_onlyApproved';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
} else {
|
||||
if ($includeRejected) {
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
} else {
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) IN ('genehmigt','beantragt')) ORDER BY v.start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$branch = 'public_or_regular';
|
||||
if ($public && $onlyApproved) {
|
||||
$branch = 'public_onlyApproved';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
} elseif ($public && $publicAll) {
|
||||
$branch = 'public_publicAll';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) IN ('genehmigt','beantragt')) ORDER BY v.start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
} else {
|
||||
if ($onlyApproved) {
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
} else {
|
||||
if ($includeRejected) {
|
||||
$branch = 'regular_includeRejected';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
} else {
|
||||
$branch = 'regular_excludeRejected';
|
||||
$stmt = $pdo->prepare("SELECT v.*, u.vorname, u.nachname FROM vacations v JOIN users u ON v.user_id = u.id WHERE v.user_id = ? AND v.start_date <= ? AND v.end_date >= ? AND (v.status IS NULL OR LOWER(TRIM(v.status)) != 'abgelehnt') ORDER BY v.start_date");
|
||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$vacations = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($debugMode) {
|
||||
$rawStatuses = array_map(function($r){ return $r['status'] ?? null; }, $vacations);
|
||||
$meta = [
|
||||
'branch' => $branch,
|
||||
'count' => count($vacations),
|
||||
'raw_statuses' => $rawStatuses
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($vacations as $v) {
|
||||
if (isset($v['status'])) {
|
||||
$normalized = preg_replace('/\s+/u', ' ', $v['status']);
|
||||
$status = mb_strtolower(trim($normalized));
|
||||
} else {
|
||||
$status = '';
|
||||
}
|
||||
|
||||
if (!$isAdmin && !$includeRejected && mb_stripos($status, 'abgelehnt') !== false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$isApproved = (mb_stripos($status, 'genehmigt') !== false);
|
||||
$employeeName = trim(($v['vorname'] ?? '') . ' ' . ($v['nachname'] ?? ''));
|
||||
if ($showEmployeeNames && $employeeName !== '') {
|
||||
$title = $employeeName;
|
||||
if ($v['status'] !== null && $v['status'] !== '') {
|
||||
$title .= ' (' . $v['status'] . ')';
|
||||
}
|
||||
} elseif ($isApproved) {
|
||||
$title = 'Urlaub';
|
||||
} else {
|
||||
$title = 'Urlaubsantrag';
|
||||
}
|
||||
|
||||
try {
|
||||
$endInclusive = (new DateTime($v['end_date']))->modify('+1 day')->format('Y-m-d');
|
||||
} catch (Exception $e) {
|
||||
$endInclusive = $v['start_date'];
|
||||
}
|
||||
|
||||
$events[] = [
|
||||
'id' => 'vac_' . $v['id'],
|
||||
'title' => $title,
|
||||
'start' => $v['start_date'],
|
||||
'end' => $endInclusive,
|
||||
'allDay' => true,
|
||||
'color' => ($isApproved) ? '#28a745' : '#ffc107',
|
||||
'extendedProps' => [
|
||||
'type' => 'user',
|
||||
'user_id' => $v['user_id'],
|
||||
'employee_name' => $employeeName,
|
||||
'status' => $v['status'],
|
||||
'comment' => $v['comment_user'] ?? ''
|
||||
]
|
||||
];
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
$payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()];
|
||||
echo json_encode($payload);
|
||||
exit;
|
||||
}
|
||||
} catch (Exception $ex) {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
$payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()];
|
||||
echo json_encode($payload);
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM company_holidays WHERE start_date <= ? AND end_date >= ? ORDER BY start_date");
|
||||
$stmt->execute([$end, $start]);
|
||||
$holidays = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
foreach ($holidays as $h) {
|
||||
$endInclusive = (new DateTime($h['end_date']))->modify('+1 day')->format('Y-m-d');
|
||||
$events[] = [
|
||||
'id' => 'com_' . $h['id'],
|
||||
'title' => $h['description'] ?: 'Betriebsurlaub',
|
||||
'start' => $h['start_date'],
|
||||
'end' => $endInclusive,
|
||||
'allDay' => true,
|
||||
'color' => '#007bff',
|
||||
'extendedProps' => [
|
||||
'type' => 'company',
|
||||
'description' => $h['description']
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
if ($debugMode) {
|
||||
echo json_encode(['events' => $events, 'meta' => $meta]);
|
||||
} else {
|
||||
echo json_encode($events);
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,90 +1,159 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once('inc/config.inc.php');
|
||||
require_once('inc/functions.inc.php');
|
||||
|
||||
$user = check_user();
|
||||
if (!is_admin_user()) {
|
||||
die('Zugriff verweigert. Nur Chefs dürfen Betriebsurlaub verwalten.');
|
||||
}
|
||||
|
||||
// Create table if not exists (optional helper)
|
||||
// Administrators can also run the SQL directly in DB. This is just a convenience.
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['start_date']) && isset($_POST['end_date'])) {
|
||||
$start = $_POST['start_date'];
|
||||
$end = $_POST['end_date'];
|
||||
$desc = trim($_POST['description'] ?? 'Betriebsurlaub');
|
||||
|
||||
$stmt = $pdo->prepare("INSERT INTO company_holidays (start_date, end_date, description, created_by) VALUES (?, ?, ?, ?)");
|
||||
$stmt->execute([$start, $end, $desc, $_SESSION['userid']]);
|
||||
|
||||
header('Location: company_holidays.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
include 'header.php';
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM company_holidays ORDER BY start_date DESC");
|
||||
$stmt->execute();
|
||||
$holidays = $stmt->fetchAll();
|
||||
|
||||
?>
|
||||
|
||||
<div class="container">
|
||||
<h2>Betriebsurlaub verwalten</h2>
|
||||
|
||||
<form method="post" class="form-inline mb-3">
|
||||
<div class="form-group mr-2">
|
||||
<label>Von:</label>
|
||||
<input type="date" name="start_date" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group mr-2">
|
||||
<label>Bis:</label>
|
||||
<input type="date" name="end_date" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group mr-2">
|
||||
<label>Beschreibung:</label>
|
||||
<input type="text" name="description" class="form-control" placeholder="z. B. Betriebsurlaub Weihnachten">
|
||||
</div>
|
||||
<button class="btn btn-primary">Hinzufügen</button>
|
||||
</form>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Von</th>
|
||||
<th>Bis</th>
|
||||
<th>Beschreibung</th>
|
||||
<th>Erstellt von</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($holidays as $h): ?>
|
||||
<tr>
|
||||
<td><?php echo $h['start_date']; ?></td>
|
||||
<td><?php echo $h['end_date']; ?></td>
|
||||
<td><?php echo htmlspecialchars($h['description']); ?></td>
|
||||
<td><?php
|
||||
$s = $pdo->prepare("SELECT vorname, nachname FROM users WHERE id = ?");
|
||||
$s->execute([$h['created_by']]);
|
||||
$u = $s->fetch();
|
||||
echo htmlspecialchars($u['vorname'] . ' ' . $u['nachname']);
|
||||
?></td>
|
||||
<td>
|
||||
<form method="post" action="deleteCompanyHoliday.php" onsubmit="return confirm('Betriebsurlaub wirklich löschen?');">
|
||||
<input type="hidden" name="id" value="<?php echo intval($h['id']); ?>">
|
||||
<button class="btn btn-sm btn-danger">Löschen</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<?php include 'footer.php';
|
||||
|
||||
?>
|
||||
<?php
|
||||
session_start();
|
||||
require_once('inc/config.inc.php');
|
||||
require_once('inc/functions.inc.php');
|
||||
require_once(__DIR__ . '/../inc/company_holiday_sync.inc.php');
|
||||
|
||||
$user = check_user();
|
||||
if (!is_admin_user()) {
|
||||
die('Zugriff verweigert. Nur Chefs duerfen Betriebsurlaub verwalten.');
|
||||
}
|
||||
|
||||
$error = '';
|
||||
$schemaError = '';
|
||||
|
||||
try {
|
||||
vacationSyncEnsureSchema($pdo);
|
||||
} catch (Throwable $e) {
|
||||
$schemaError = 'Die Seite konnte das Urlaubsschema nicht automatisch aktualisieren: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['start_date']) && isset($_POST['end_date'])) {
|
||||
$start = trim((string)($_POST['start_date'] ?? ''));
|
||||
$end = trim((string)($_POST['end_date'] ?? ''));
|
||||
$desc = trim((string)($_POST['description'] ?? 'Betriebsurlaub'));
|
||||
$vertretung = trim((string)($_POST['vertretung'] ?? ''));
|
||||
$vertretertelefon = trim((string)($_POST['vertretertelefon'] ?? ''));
|
||||
$vertreteradresse = trim((string)($_POST['vertreteradresse'] ?? ''));
|
||||
$vertreterurl = trim((string)($_POST['vertreterurl'] ?? ''));
|
||||
|
||||
if ($start === '' || $end === '') {
|
||||
$error = 'Bitte Start- und Enddatum angeben.';
|
||||
} elseif ($start > $end) {
|
||||
$error = 'Das Enddatum darf nicht vor dem Startdatum liegen.';
|
||||
} elseif ($vertretung === '' || $vertretertelefon === '' || $vertreteradresse === '' || $vertreterurl === '') {
|
||||
$error = 'Bitte alle Vertreterinformationen vollstaendig ausfuellen.';
|
||||
} elseif ($schemaError !== '') {
|
||||
$error = $schemaError;
|
||||
} else {
|
||||
$stmt = $pdo->prepare("
|
||||
INSERT INTO company_holidays (
|
||||
start_date, end_date, description, vertretung, vertretertelefon, vertreteradresse, vertreterurl, created_by
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
");
|
||||
$stmt->execute([
|
||||
$start,
|
||||
$end,
|
||||
$desc,
|
||||
$vertretung,
|
||||
$vertretertelefon,
|
||||
$vertreteradresse,
|
||||
$vertreterurl,
|
||||
$_SESSION['userid']
|
||||
]);
|
||||
vacationSyncUrlaubFromCompanyHoliday($pdo, (int)$pdo->lastInsertId());
|
||||
|
||||
header('Location: company_holidays.php');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
include 'header.php';
|
||||
|
||||
$stmt = $pdo->prepare("SELECT * FROM company_holidays ORDER BY start_date DESC");
|
||||
$stmt->execute();
|
||||
$holidays = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
|
||||
<div class="container">
|
||||
<h2>Betriebsurlaub verwalten</h2>
|
||||
|
||||
<?php if ($error !== ''): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($schemaError !== ''): ?>
|
||||
<div class="alert alert-warning"><?php echo htmlspecialchars($schemaError); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post" class="mb-3">
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-3">
|
||||
<label>Von:</label>
|
||||
<input type="date" name="start_date" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group col-md-3">
|
||||
<label>Bis:</label>
|
||||
<input type="date" name="end_date" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label>Beschreibung:</label>
|
||||
<input type="text" name="description" class="form-control" placeholder="z. B. Betriebsurlaub Weihnachten">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-6">
|
||||
<label>Vertretung:</label>
|
||||
<input type="text" name="vertretung" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group col-md-6">
|
||||
<label>Vertretung Telefon:</label>
|
||||
<input type="text" name="vertretertelefon" class="form-control" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-row">
|
||||
<div class="form-group col-md-8">
|
||||
<label>Vertretung Adresse:</label>
|
||||
<input type="text" name="vertreteradresse" class="form-control" required>
|
||||
</div>
|
||||
<div class="form-group col-md-4">
|
||||
<label>Vertretung Webseite:</label>
|
||||
<input type="text" name="vertreterurl" class="form-control" required>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-primary">Hinzufuegen</button>
|
||||
</form>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Von</th>
|
||||
<th>Bis</th>
|
||||
<th>Beschreibung</th>
|
||||
<th>Vertretung</th>
|
||||
<th>Kontakt</th>
|
||||
<th>Erstellt von</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($holidays as $h): ?>
|
||||
<tr>
|
||||
<td><?php echo htmlspecialchars((string)$h['start_date']); ?></td>
|
||||
<td><?php echo htmlspecialchars((string)$h['end_date']); ?></td>
|
||||
<td><?php echo htmlspecialchars((string)$h['description']); ?></td>
|
||||
<td><?php echo htmlspecialchars((string)$h['vertretung']); ?></td>
|
||||
<td>
|
||||
<?php echo htmlspecialchars((string)$h['vertretertelefon']); ?><br>
|
||||
<?php echo htmlspecialchars((string)$h['vertreteradresse']); ?><br>
|
||||
<?php echo htmlspecialchars((string)$h['vertreterurl']); ?>
|
||||
</td>
|
||||
<td><?php
|
||||
$s = $pdo->prepare("SELECT vorname, nachname FROM users WHERE id = ?");
|
||||
$s->execute([$h['created_by']]);
|
||||
$u = $s->fetch(PDO::FETCH_ASSOC);
|
||||
echo htmlspecialchars(trim(($u['vorname'] ?? '') . ' ' . ($u['nachname'] ?? '')));
|
||||
?></td>
|
||||
<td>
|
||||
<form method="post" action="deleteCompanyHoliday.php" onsubmit="return confirm('Betriebsurlaub wirklich loeschen?');">
|
||||
<input type="hidden" name="id" value="<?php echo (int)$h['id']; ?>">
|
||||
<button class="btn btn-sm btn-danger">Loeschen</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
session_start();
|
||||
require_once('inc/config.inc.php');
|
||||
require_once('inc/functions.inc.php');
|
||||
require_once(__DIR__ . '/../inc/company_holiday_sync.inc.php');
|
||||
|
||||
$user = check_user();
|
||||
if (!is_admin_user()) {
|
||||
@@ -18,9 +19,10 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['id'])) {
|
||||
|
||||
$id = intval($_POST['id']);
|
||||
|
||||
vacationSyncDeleteUrlaubByCompanyHoliday($pdo, $id);
|
||||
$stmt = $pdo->prepare("DELETE FROM company_holidays WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
|
||||
header('Location: company_holidays.php');
|
||||
exit;
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -1,38 +1,34 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once('inc/config.inc.php');
|
||||
require_once('inc/functions.inc.php');
|
||||
|
||||
$user = check_user();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['id'])) {
|
||||
http_response_code(400);
|
||||
die('Bad request');
|
||||
}
|
||||
|
||||
$id = (int)$_POST['id'];
|
||||
$referer = $_POST['referer'] ?? 'urlaubsantrag.php';
|
||||
|
||||
// Fetch vacation to verify ownership
|
||||
$stmt = $pdo->prepare("SELECT user_id, status FROM vacations WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$vac = $stmt->fetch();
|
||||
|
||||
if (!$vac) {
|
||||
die('Urlaubseintrag nicht gefunden.');
|
||||
}
|
||||
|
||||
$isAdmin = is_admin_user();
|
||||
|
||||
if (!$isAdmin && $vac['user_id'] != $_SESSION['userid']) {
|
||||
die('Zugriff verweigert.');
|
||||
}
|
||||
|
||||
// Allow deletion for admins or owner
|
||||
$del = $pdo->prepare("DELETE FROM vacations WHERE id = ?");
|
||||
$del->execute([$id]);
|
||||
|
||||
header('Location: ' . $referer);
|
||||
exit();
|
||||
|
||||
?>
|
||||
<?php
|
||||
session_start();
|
||||
require_once('inc/config.inc.php');
|
||||
require_once('inc/functions.inc.php');
|
||||
|
||||
$user = check_user();
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['id'])) {
|
||||
http_response_code(400);
|
||||
die('Bad request');
|
||||
}
|
||||
|
||||
$id = (int)$_POST['id'];
|
||||
$referer = $_POST['referer'] ?? 'urlaubsantrag.php';
|
||||
|
||||
$stmt = $pdo->prepare("SELECT user_id, status FROM vacations WHERE id = ?");
|
||||
$stmt->execute([$id]);
|
||||
$vac = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$vac) {
|
||||
die('Urlaubseintrag nicht gefunden.');
|
||||
}
|
||||
|
||||
$canManageTeamVacations = can_manage_team_vacations();
|
||||
if (!$canManageTeamVacations && (int)$vac['user_id'] !== (int)$_SESSION['userid']) {
|
||||
die('Zugriff verweigert.');
|
||||
}
|
||||
|
||||
$del = $pdo->prepare("DELETE FROM vacations WHERE id = ?");
|
||||
$del->execute([$id]);
|
||||
|
||||
header('Location: ' . $referer);
|
||||
exit();
|
||||
?>
|
||||
|
||||
@@ -145,6 +145,15 @@ function is_admin_user() {
|
||||
$statement->execute(array('id' => $_SESSION['userid']));
|
||||
return ($statement->rowCount() == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when the user may manage vacations for the team.
|
||||
* In the current Zeiterfassung, team leads are represented by the
|
||||
* existing admin role.
|
||||
*/
|
||||
function can_manage_team_vacations() {
|
||||
return is_admin_user();
|
||||
}
|
||||
/**
|
||||
* Prüft, ob der Benutzer Bearbeiter ist
|
||||
*/
|
||||
@@ -187,4 +196,4 @@ function isValidSequence($sequence) {
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
+241
-178
@@ -1,178 +1,241 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once("inc/config.inc.php");
|
||||
require_once("inc/functions.inc.php");
|
||||
|
||||
$user = check_user();
|
||||
|
||||
if (!isset($_SESSION['userid'])) {
|
||||
die("Kein Benutzer angemeldet.");
|
||||
}
|
||||
|
||||
$user_id = $_SESSION['userid'];
|
||||
$message = "";
|
||||
$error = "";
|
||||
|
||||
function calculateWorkingDays($start, $end) {
|
||||
$start = new DateTime($start);
|
||||
$end = new DateTime($end);
|
||||
$end->modify('+1 day');
|
||||
|
||||
$interval = new DateInterval('P1D');
|
||||
$period = new DatePeriod($start, $interval, $end);
|
||||
|
||||
$workingDays = 0;
|
||||
|
||||
foreach ($period as $day) {
|
||||
if ($day->format('N') < 6) { // 1 (Mo) - 5 (Fr)
|
||||
$workingDays++;
|
||||
}
|
||||
}
|
||||
|
||||
return $workingDays;
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
||||
|
||||
$start_date = $_POST['start_date'];
|
||||
$end_date = $_POST['end_date'];
|
||||
$comment = trim($_POST['comment']);
|
||||
|
||||
if (empty($start_date) || empty($end_date)) {
|
||||
$error = "Bitte beide Datumsfelder ausfüllen.";
|
||||
} elseif ($start_date > $end_date) {
|
||||
$error = "Enddatum liegt vor dem Startdatum.";
|
||||
} elseif ($start_date < date("Y-m-d")) {
|
||||
$error = "Urlaub kann nicht in der Vergangenheit beantragt werden.";
|
||||
} else {
|
||||
|
||||
// Überschneidung prüfen
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT COUNT(*) FROM vacations
|
||||
WHERE user_id = ?
|
||||
AND status != 'abgelehnt'
|
||||
AND (
|
||||
(start_date BETWEEN ? AND ?)
|
||||
OR (end_date BETWEEN ? AND ?)
|
||||
OR (? BETWEEN start_date AND end_date)
|
||||
)
|
||||
");
|
||||
$stmt->execute([$user_id, $start_date, $end_date, $start_date, $end_date, $start_date]);
|
||||
$exists = $stmt->fetchColumn();
|
||||
|
||||
if ($exists > 0) {
|
||||
$error = "Der Zeitraum überschneidet sich mit einem bestehenden Antrag.";
|
||||
} else {
|
||||
|
||||
$days = calculateWorkingDays($start_date, $end_date);
|
||||
|
||||
$insert = $pdo->prepare("
|
||||
INSERT INTO vacations (user_id, start_date, end_date, days, comment_user)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
");
|
||||
|
||||
$insert->execute([$user_id, $start_date, $end_date, $days, $comment]);
|
||||
|
||||
$message = "Urlaubsantrag erfolgreich eingereicht ($days Werktage).";
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php include 'header.php'; ?>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 offset-md-2">
|
||||
|
||||
<h2>Urlaubsantrag</h2>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger"><?php echo $error; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-success"><?php echo $message; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Von:</label>
|
||||
<input type="date" name="start_date" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Bis:</label>
|
||||
<input type="date" name="end_date" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Kommentar (optional):</label>
|
||||
<textarea name="comment" class="form-control"></textarea>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-block">
|
||||
Urlaub beantragen
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h4>Meine Anträge</h4>
|
||||
|
||||
<?php
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT * FROM vacations
|
||||
WHERE user_id = ?
|
||||
ORDER BY created_at DESC
|
||||
");
|
||||
$stmt->execute([$user_id]);
|
||||
$antraege = $stmt->fetchAll();
|
||||
?>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<th>Von</th>
|
||||
<th>Bis</th>
|
||||
<th>Tage</th>
|
||||
<th>Status</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
|
||||
<?php foreach ($antraege as $a): ?>
|
||||
<tr>
|
||||
<td><?php echo $a['start_date']; ?></td>
|
||||
<td><?php echo $a['end_date']; ?></td>
|
||||
<td><?php echo $a['days']; ?></td>
|
||||
<td>
|
||||
<?php
|
||||
if ($a['status'] == 'beantragt') {
|
||||
echo '<span class="badge badge-warning">Beantragt</span>';
|
||||
} elseif ($a['status'] == 'genehmigt') {
|
||||
echo '<span class="badge badge-success">Genehmigt</span>';
|
||||
} else {
|
||||
echo '<span class="badge badge-danger">Abgelehnt</span>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" action="deleteVacation.php" onsubmit="return confirm('Wirklich löschen?');">
|
||||
<input type="hidden" name="id" value="<?php echo $a['id']; ?>">
|
||||
<input type="hidden" name="referer" value="urlaubsantrag.php">
|
||||
<button type="submit" class="btn btn-sm btn-danger">Löschen</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
<?php
|
||||
session_start();
|
||||
require_once("inc/config.inc.php");
|
||||
require_once("inc/functions.inc.php");
|
||||
|
||||
$user = check_user();
|
||||
|
||||
if (!isset($_SESSION['userid'])) {
|
||||
die("Kein Benutzer angemeldet.");
|
||||
}
|
||||
|
||||
$user_id = (int)$_SESSION['userid'];
|
||||
$canManageTeamVacations = can_manage_team_vacations();
|
||||
$message = "";
|
||||
$error = "";
|
||||
$selected_user_id = $user_id;
|
||||
|
||||
$selectableUsers = [];
|
||||
if ($canManageTeamVacations) {
|
||||
$stmtUsers = $pdo->prepare("
|
||||
SELECT id, vorname, nachname, email
|
||||
FROM users
|
||||
WHERE zeiterfassung = 1
|
||||
ORDER BY nachname, vorname
|
||||
");
|
||||
$stmtUsers->execute();
|
||||
$selectableUsers = $stmtUsers->fetchAll(PDO::FETCH_ASSOC);
|
||||
}
|
||||
|
||||
function calculateWorkingDays($start, $end) {
|
||||
$start = new DateTime($start);
|
||||
$end = new DateTime($end);
|
||||
$end->modify('+1 day');
|
||||
|
||||
$interval = new DateInterval('P1D');
|
||||
$period = new DatePeriod($start, $interval, $end);
|
||||
|
||||
$workingDays = 0;
|
||||
foreach ($period as $day) {
|
||||
if ($day->format('N') < 6) {
|
||||
$workingDays++;
|
||||
}
|
||||
}
|
||||
|
||||
return $workingDays;
|
||||
}
|
||||
|
||||
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||
$start_date = trim((string)($_POST['start_date'] ?? ''));
|
||||
$end_date = trim((string)($_POST['end_date'] ?? ''));
|
||||
$comment = trim((string)($_POST['comment'] ?? ''));
|
||||
$selected_user_id = $canManageTeamVacations ? (int)($_POST['user_id'] ?? $user_id) : $user_id;
|
||||
|
||||
$selectedUser = null;
|
||||
if ($selected_user_id <= 0) {
|
||||
$error = "Bitte einen Mitarbeiter auswaehlen.";
|
||||
} else {
|
||||
$stmtSelectedUser = $pdo->prepare("
|
||||
SELECT id, vorname, nachname
|
||||
FROM users
|
||||
WHERE id = ?
|
||||
AND zeiterfassung = 1
|
||||
LIMIT 1
|
||||
");
|
||||
$stmtSelectedUser->execute([$selected_user_id]);
|
||||
$selectedUser = $stmtSelectedUser->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if (!$selectedUser) {
|
||||
$error = "Der ausgewaehlte Mitarbeiter wurde nicht gefunden.";
|
||||
}
|
||||
}
|
||||
|
||||
if ($error === "" && ($start_date === '' || $end_date === '')) {
|
||||
$error = "Bitte beide Datumsfelder ausfuellen.";
|
||||
} elseif ($error === "" && $start_date > $end_date) {
|
||||
$error = "Enddatum liegt vor dem Startdatum.";
|
||||
} elseif ($error === "" && $start_date < date("Y-m-d")) {
|
||||
$error = "Urlaub kann nicht in der Vergangenheit beantragt werden.";
|
||||
} elseif ($error === "") {
|
||||
$stmt = $pdo->prepare("
|
||||
SELECT COUNT(*)
|
||||
FROM vacations
|
||||
WHERE user_id = ?
|
||||
AND status != 'abgelehnt'
|
||||
AND (
|
||||
(start_date BETWEEN ? AND ?)
|
||||
OR (end_date BETWEEN ? AND ?)
|
||||
OR (? BETWEEN start_date AND end_date)
|
||||
)
|
||||
");
|
||||
$stmt->execute([$selected_user_id, $start_date, $end_date, $start_date, $end_date, $start_date]);
|
||||
$exists = (int)$stmt->fetchColumn();
|
||||
|
||||
if ($exists > 0) {
|
||||
$error = "Der Zeitraum ueberschneidet sich mit einem bestehenden Antrag.";
|
||||
} else {
|
||||
$days = calculateWorkingDays($start_date, $end_date);
|
||||
|
||||
$insert = $pdo->prepare("
|
||||
INSERT INTO vacations (user_id, start_date, end_date, days, comment_user)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
");
|
||||
$insert->execute([$selected_user_id, $start_date, $end_date, $days, $comment]);
|
||||
|
||||
if ($selected_user_id !== $user_id && $selectedUser) {
|
||||
$message = "Urlaub fuer " . $selectedUser['vorname'] . " " . $selectedUser['nachname'] . " erfolgreich eingereicht ($days Werktage).";
|
||||
} else {
|
||||
$message = "Urlaubsantrag erfolgreich eingereicht ($days Werktage).";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<?php include 'header.php'; ?>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-8 offset-md-2">
|
||||
|
||||
<h2>Urlaubsantrag</h2>
|
||||
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger"><?php echo htmlspecialchars($error); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-success"><?php echo htmlspecialchars($message); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="post">
|
||||
|
||||
<?php if ($canManageTeamVacations): ?>
|
||||
<div class="form-group">
|
||||
<label>Mitarbeiter:</label>
|
||||
<select name="user_id" class="form-control" required>
|
||||
<?php foreach ($selectableUsers as $employee): ?>
|
||||
<?php $employeeId = (int)$employee['id']; ?>
|
||||
<option value="<?php echo $employeeId; ?>" <?php echo ($selected_user_id === $employeeId) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars(trim($employee['nachname'] . ', ' . $employee['vorname'] . ' | ' . $employee['email'])); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Von:</label>
|
||||
<input type="date" name="start_date" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Bis:</label>
|
||||
<input type="date" name="end_date" class="form-control" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Kommentar (optional):</label>
|
||||
<textarea name="comment" class="form-control"></textarea>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
|
||||
<button type="submit" class="btn btn-primary btn-block">
|
||||
<?php echo $canManageTeamVacations ? 'Urlaub eintragen' : 'Urlaub beantragen'; ?>
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
<hr>
|
||||
|
||||
<h4><?php echo $canManageTeamVacations ? 'Urlaubseintraege' : 'Meine Antraege'; ?></h4>
|
||||
|
||||
<?php
|
||||
$listSql = "
|
||||
SELECT v.*, u.vorname, u.nachname
|
||||
FROM vacations v
|
||||
JOIN users u ON u.id = v.user_id
|
||||
";
|
||||
|
||||
if ($canManageTeamVacations) {
|
||||
$listSql .= " ORDER BY v.created_at DESC";
|
||||
$stmt = $pdo->prepare($listSql);
|
||||
$stmt->execute();
|
||||
} else {
|
||||
$listSql .= " WHERE v.user_id = ? ORDER BY v.created_at DESC";
|
||||
$stmt = $pdo->prepare($listSql);
|
||||
$stmt->execute([$user_id]);
|
||||
}
|
||||
|
||||
$antraege = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
?>
|
||||
|
||||
<table class="table table-bordered">
|
||||
<tr>
|
||||
<?php if ($canManageTeamVacations): ?>
|
||||
<th>Mitarbeiter</th>
|
||||
<?php endif; ?>
|
||||
<th>Von</th>
|
||||
<th>Bis</th>
|
||||
<th>Tage</th>
|
||||
<th>Status</th>
|
||||
<th>Aktion</th>
|
||||
</tr>
|
||||
|
||||
<?php foreach ($antraege as $a): ?>
|
||||
<tr>
|
||||
<?php if ($canManageTeamVacations): ?>
|
||||
<td><?php echo htmlspecialchars(trim($a['vorname'] . ' ' . $a['nachname'])); ?></td>
|
||||
<?php endif; ?>
|
||||
<td><?php echo htmlspecialchars((string)$a['start_date']); ?></td>
|
||||
<td><?php echo htmlspecialchars((string)$a['end_date']); ?></td>
|
||||
<td><?php echo (int)$a['days']; ?></td>
|
||||
<td>
|
||||
<?php
|
||||
if ($a['status'] === 'beantragt' || $a['status'] === null || $a['status'] === '') {
|
||||
echo '<span class="badge badge-warning">Beantragt</span>';
|
||||
} elseif ($a['status'] === 'genehmigt') {
|
||||
echo '<span class="badge badge-success">Genehmigt</span>';
|
||||
} else {
|
||||
echo '<span class="badge badge-danger">Abgelehnt</span>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<form method="post" action="deleteVacation.php" onsubmit="return confirm('Wirklich loeschen?');">
|
||||
<input type="hidden" name="id" value="<?php echo (int)$a['id']; ?>">
|
||||
<input type="hidden" name="referer" value="urlaubsantrag.php">
|
||||
<button type="submit" class="btn btn-sm btn-danger">Loeschen</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
|
||||
@@ -41,16 +41,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
var url = 'api/vacations.php?start=' + info.startStr + '&end=' + info.endStr;
|
||||
fetch(url).then(function(res){ return res.json(); }).then(function(data){ successCallback(data); }).catch(function(err){ failureCallback(err); });
|
||||
},
|
||||
eventClick: function(info) {
|
||||
var ev = info.event;
|
||||
var props = ev.extendedProps;
|
||||
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
|
||||
if (props.type === 'user') {
|
||||
html += 'Status: ' + (props.status || '') + '<br>';
|
||||
html += 'Kommentar: ' + (props.comment || '') + '<br>';
|
||||
} else if (props.type === 'company') {
|
||||
html += 'Beschreibung: ' + (props.description || '') + '<br>';
|
||||
}
|
||||
eventClick: function(info) {
|
||||
var ev = info.event;
|
||||
var props = ev.extendedProps;
|
||||
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
|
||||
if (props.type === 'user') {
|
||||
html += 'Mitarbeiter: ' + (props.employee_name || '') + '<br>';
|
||||
html += 'Status: ' + (props.status || '') + '<br>';
|
||||
html += 'Kommentar: ' + (props.comment || '') + '<br>';
|
||||
} else if (props.type === 'company') {
|
||||
html += 'Beschreibung: ' + (props.description || '') + '<br>';
|
||||
}
|
||||
document.getElementById('detailsContent').innerHTML = html;
|
||||
document.getElementById('eventDetails').style.display = 'block';
|
||||
}
|
||||
|
||||
@@ -1,59 +1,63 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once('inc/config.inc.php');
|
||||
require_once('inc/functions.inc.php');
|
||||
|
||||
// allow any logged-in user to view the team calendar (read-only)
|
||||
$user = check_user();
|
||||
|
||||
include 'header.php';
|
||||
?>
|
||||
|
||||
<div class="container">
|
||||
<h2>Team Urlaubskalender</h2>
|
||||
<div id="calendar"></div>
|
||||
<br>
|
||||
<div>
|
||||
<span class="badge badge-success">genehmigt</span>
|
||||
<span class="badge badge-primary">Betriebsurlaub</span>
|
||||
</div>
|
||||
<br>
|
||||
<div id="eventDetails" style="display:none;">
|
||||
<h4>Details</h4>
|
||||
<div id="detailsContent"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css' rel='stylesheet' />
|
||||
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.js'></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var calendarEl = document.getElementById('calendar');
|
||||
|
||||
var calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
initialView: 'dayGridMonth',
|
||||
firstDay: 1,
|
||||
height: 650,
|
||||
events: function(info, successCallback, failureCallback) {
|
||||
var url = 'api/vacations.php?start=' + info.startStr + '&end=' + info.endStr + '&public=1&public_all=1';
|
||||
fetch(url).then(function(res){ return res.json(); }).then(function(data){ successCallback(data); }).catch(function(err){ failureCallback(err); });
|
||||
},
|
||||
eventClick: function(info) {
|
||||
var ev = info.event;
|
||||
var props = ev.extendedProps;
|
||||
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
|
||||
if (props.type === 'user') {
|
||||
html += 'Mitarbeiter-ID: ' + (props.user_id || '') + '<br>';
|
||||
} else if (props.type === 'company') {
|
||||
html += 'Beschreibung: ' + (props.description || '') + '<br>';
|
||||
}
|
||||
document.getElementById('detailsContent').innerHTML = html;
|
||||
document.getElementById('eventDetails').style.display = 'block';
|
||||
}
|
||||
});
|
||||
|
||||
calendar.render();
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
<?php
|
||||
session_start();
|
||||
require_once('inc/config.inc.php');
|
||||
require_once('inc/functions.inc.php');
|
||||
|
||||
$user = check_user();
|
||||
|
||||
include 'header.php';
|
||||
?>
|
||||
|
||||
<div class="container">
|
||||
<h2>Team Urlaubskalender</h2>
|
||||
<div id="calendar"></div>
|
||||
<br>
|
||||
<div>
|
||||
<span class="badge badge-success">genehmigt</span>
|
||||
<span class="badge badge-warning">beantragt</span>
|
||||
<span class="badge badge-primary">Betriebsurlaub</span>
|
||||
</div>
|
||||
<br>
|
||||
<div id="eventDetails" style="display:none;">
|
||||
<h4>Details</h4>
|
||||
<div id="detailsContent"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css' rel='stylesheet' />
|
||||
<script src='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.js'></script>
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var calendarEl = document.getElementById('calendar');
|
||||
|
||||
var calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
initialView: 'dayGridMonth',
|
||||
firstDay: 1,
|
||||
height: 650,
|
||||
events: function(info, successCallback, failureCallback) {
|
||||
var url = 'api/vacations.php?start=' + info.startStr + '&end=' + info.endStr + '&public=1&public_all=1';
|
||||
fetch(url).then(function(res){ return res.json(); }).then(function(data){ successCallback(data); }).catch(function(err){ failureCallback(err); });
|
||||
},
|
||||
eventClick: function(info) {
|
||||
var ev = info.event;
|
||||
var props = ev.extendedProps;
|
||||
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
|
||||
if (props.type === 'user') {
|
||||
html += 'Mitarbeiter: ' + (props.employee_name || ev.title || '') + '<br>';
|
||||
html += 'Status: ' + (props.status || '') + '<br>';
|
||||
if (props.comment) {
|
||||
html += 'Kommentar: ' + props.comment + '<br>';
|
||||
}
|
||||
} else if (props.type === 'company') {
|
||||
html += 'Beschreibung: ' + (props.description || '') + '<br>';
|
||||
}
|
||||
document.getElementById('detailsContent').innerHTML = html;
|
||||
document.getElementById('eventDetails').style.display = 'block';
|
||||
}
|
||||
});
|
||||
|
||||
calendar.render();
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php include 'footer.php'; ?>
|
||||
|
||||
Reference in New Issue
Block a user