Anpassung Ladezeit Impfen + Urlaubsplaner
This commit is contained in:
+62
-37
@@ -4,6 +4,7 @@ session_start();
|
|||||||
// WICHTIG: Pfade aus /admin heraus korrekt auflösen
|
// WICHTIG: Pfade aus /admin heraus korrekt auflösen
|
||||||
require_once __DIR__ . "/../inc/config.inc.php";
|
require_once __DIR__ . "/../inc/config.inc.php";
|
||||||
require_once __DIR__ . "/../inc/functions.inc.php";
|
require_once __DIR__ . "/../inc/functions.inc.php";
|
||||||
|
require_once __DIR__ . "/../inc/company_holiday_sync.inc.php";
|
||||||
|
|
||||||
// Login prüfen
|
// Login prüfen
|
||||||
$user = check_admin_user();
|
$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') . "'>
|
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>
|
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') . "'>
|
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' value='" . htmlspecialchars($vertreteradresse, 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>";
|
echo "<input name='urlaubid[]' type='hidden' value='" . $urlaubid . "'><br>";
|
||||||
}
|
}
|
||||||
@@ -656,40 +657,64 @@ if(!check_worker()){
|
|||||||
}else if (($_POST["aktion"] ?? '') == "5") {
|
}else if (($_POST["aktion"] ?? '') == "5") {
|
||||||
// Termine in DB speichern.
|
// Termine in DB speichern.
|
||||||
$i =0;
|
$i =0;
|
||||||
foreach ($_POST['Starttime'] as $Starttime) {
|
$pdo->beginTransaction();
|
||||||
//echo $datum . "<br>";
|
try {
|
||||||
if($_POST["Starttime"][$i] != "0000-00-00"){
|
foreach ($_POST['Starttime'] as $Starttime) {
|
||||||
//echo $_POST["urlaubid"][$i] . "<br>";
|
if($_POST["Starttime"][$i] != "0000-00-00"){
|
||||||
$stmt = $pdo->prepare("
|
$vertretung = trim((string)($_POST['vertretung'][$i] ?? ''));
|
||||||
INSERT INTO urlaub
|
$vertretertelefon = trim((string)($_POST['vertretertelefon'][$i] ?? ''));
|
||||||
(urlaubid, vertretung, start, ende, vertretertelefon, vertreteradresse, vertreterurl)
|
$vertreteradresse = trim((string)($_POST['vertreteradresse'][$i] ?? ''));
|
||||||
VALUES
|
$vertreterurl = trim((string)($_POST['vertreterurl'][$i] ?? ''));
|
||||||
(: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([
|
if ($vertretung === '' || $vertretertelefon === '' || $vertreteradresse === '' || $vertreterurl === '') {
|
||||||
':urlaubid' => (int)$_POST['urlaubid'][$i], // 0 = INSERT, >0 = UPDATE
|
throw new RuntimeException("Bitte alle Vertreterinformationen fuer jeden Urlaubseintrag vollstaendig ausfuellen.");
|
||||||
':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 (!$ok) {
|
$stmt = $pdo->prepare("
|
||||||
throw new RuntimeException("Fehler beim Eintragen in der Datenbank.");
|
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>";
|
echo "Einträge wurden in der Datenbank gespeichert!<br><br>";
|
||||||
|
|
||||||
}else if (($_POST["aktion"] ?? '') == "6") {
|
}else if (($_POST["aktion"] ?? '') == "6") {
|
||||||
@@ -2023,10 +2048,10 @@ if(!check_worker()){
|
|||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
|
|
||||||
function AddneueTermine(){
|
function AddneueTermine(){
|
||||||
|
|
||||||
var div = document.getElementById('neuerUrlaub');
|
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>
|
//Public: <select name=aktiv[] id='aktiv' required ><option value='1' >Ja</option> <option value='0'>Nein</option></select>
|
||||||
|
|
||||||
//document.getElementById('neueTermine').innerHTML = div;
|
//document.getElementById('neueTermine').innerHTML = div;
|
||||||
|
|||||||
+127
-97
@@ -405,6 +405,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
SendMailMessageVorlage($pdo, '1', $tid, $mailTemplateId);
|
SendMailMessageVorlage($pdo, '1', $tid, $mailTemplateId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impfWorkflowNotificationProcess($pdo);
|
||||||
$message = count($terminIds) . " Terminanfragen wurden erstellt und versendet.";
|
$message = count($terminIds) . " Terminanfragen wurden erstellt und versendet.";
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
if ($pdo->inTransaction()) {
|
if ($pdo->inTransaction()) {
|
||||||
@@ -436,7 +437,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
if ($ok) {
|
if ($ok) {
|
||||||
|
$notificationEvents = impfWorkflowNotificationProcess($pdo);
|
||||||
$message = $msg;
|
$message = $msg;
|
||||||
|
if (!empty($notificationEvents)) {
|
||||||
|
$message .= ' ' . count($notificationEvents) . " Impfworkflow-Benachrichtigung(en) wurden versendet.";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$error = $msg;
|
$error = $msg;
|
||||||
}
|
}
|
||||||
@@ -481,7 +486,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
if ($ok) {
|
if ($ok) {
|
||||||
|
$notificationEvents = impfWorkflowNotificationProcess($pdo);
|
||||||
$message = $msg;
|
$message = $msg;
|
||||||
|
if (!empty($notificationEvents)) {
|
||||||
|
$message .= ' ' . count($notificationEvents) . " Impfworkflow-Benachrichtigung(en) wurden versendet.";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$error = $msg;
|
$error = $msg;
|
||||||
}
|
}
|
||||||
@@ -595,6 +604,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$exists = (bool)$stDelete->fetch(PDO::FETCH_ASSOC);
|
$exists = (bool)$stDelete->fetch(PDO::FETCH_ASSOC);
|
||||||
workflowDeleteWaitlistEntry($pdo, $warteid);
|
workflowDeleteWaitlistEntry($pdo, $warteid);
|
||||||
if ($exists) {
|
if ($exists) {
|
||||||
|
impfWorkflowNotificationProcess($pdo);
|
||||||
$message = "Wartelisten-Eintrag wurde gelöscht.";
|
$message = "Wartelisten-Eintrag wurde gelöscht.";
|
||||||
} else {
|
} else {
|
||||||
$error = "Wartelisten-Eintrag nicht gefunden.";
|
$error = "Wartelisten-Eintrag nicht gefunden.";
|
||||||
@@ -663,51 +673,67 @@ $eventOverview = [];
|
|||||||
$planWaitCounts = [];
|
$planWaitCounts = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$stRules = $pdo->prepare("SELECT r.impfstoff_id, r.dosen_pro_flasche, i.impfname,
|
$needsPlanData = in_array($view, ['teilnehmer', 'event-create'], true);
|
||||||
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
|
$needsEligibilityData = ($view === 'event-create');
|
||||||
FROM impfstoff_workflow r
|
$needsPersonSearch = ($view === 'teilnehmer' && $personSearch !== '');
|
||||||
INNER JOIN impfstoff i ON i.impfid = r.impfstoff_id
|
$needsWaitRows = ($view === 'warteliste');
|
||||||
WHERE (i.aktiv = 1 OR i.aktivwarteliste = 1 OR i.aktivtermin = 1 OR i.aktivgrippe = 1)
|
$needsUpcomingRows = ($view === 'event-teilnehmer');
|
||||||
ORDER BY i.impfname");
|
|
||||||
$stRules->execute();
|
|
||||||
$rules = $stRules->fetchAll(PDO::FETCH_ASSOC);
|
|
||||||
|
|
||||||
$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 = [];
|
$plans = impfGetZeitraumRows($pdo, true);
|
||||||
foreach ($plans as $p) {
|
|
||||||
foreach ($p['impfstoff_id_list'] as $impfstoffId) {
|
|
||||||
$planExistsForImpfstoff[(int)$impfstoffId] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($rules as $r) {
|
$planExistsForImpfstoff = [];
|
||||||
$iid = (int)$r['impfstoff_id'];
|
foreach ($plans as $p) {
|
||||||
$dosen = (int)$r['dosen_pro_flasche'];
|
foreach ($p['impfstoff_id_list'] as $impfstoffId) {
|
||||||
if ($dosen <= 0 || !isset($planExistsForImpfstoff[$iid])) {
|
$planExistsForImpfstoff[(int)$impfstoffId] = true;
|
||||||
continue;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$configuredImpfstoffe[] = $r;
|
foreach ($rules as $r) {
|
||||||
$hasEligiblePlan = false;
|
$iid = (int)$r['impfstoff_id'];
|
||||||
foreach ($plans as $plan) {
|
if (!isset($planExistsForImpfstoff[$iid])) {
|
||||||
if (!in_array($iid, $plan['impfstoff_id_list'] ?? [], true)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$planId = (int)$plan['zeitraum_id'];
|
$configuredImpfstoffe[] = $r;
|
||||||
$planWaitCounts[$iid][$planId] = workflowCountWaitersForPlan($pdo, $iid, $planId);
|
if (!$needsEligibilityData) {
|
||||||
if ($planWaitCounts[$iid][$planId] >= $dosen) {
|
continue;
|
||||||
$hasEligiblePlan = true;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ($hasEligiblePlan) {
|
$dosen = (int)$r['dosen_pro_flasche'];
|
||||||
$eligible[] = $r;
|
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 . '%';
|
$searchLike = '%' . $personSearch . '%';
|
||||||
$searchExactId = ctype_digit($personSearch) ? (int)$personSearch : -1;
|
$searchExactId = ctype_digit($personSearch) ? (int)$personSearch : -1;
|
||||||
$stPersons = $pdo->prepare("SELECT person_id, vorname, nachname, geburtstag, email, tele, ort, plz, strasse
|
$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);
|
$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,
|
if ($needsWaitRows) {
|
||||||
p.vorname, p.nachname, p.geburtstag, p.email, p.tele,
|
$stWait = $pdo->prepare("SELECT w.warteid, w.userid, w.checked, w.impfstoff, w.impfart, w.impfenzeitraum, w.zeitraum_id, w.letzteimpfung, w.date_created,
|
||||||
i.impfname
|
p.vorname, p.nachname, p.geburtstag, p.email, p.tele,
|
||||||
FROM warteliste w
|
i.impfname
|
||||||
INNER JOIN persons p ON p.person_id = w.userid
|
FROM warteliste w
|
||||||
LEFT JOIN impfstoff i ON i.impfid = w.impfstoff
|
INNER JOIN persons p ON p.person_id = w.userid
|
||||||
WHERE w.checked IN (0, 1)
|
LEFT JOIN impfstoff i ON i.impfid = w.impfstoff
|
||||||
ORDER BY w.checked DESC, w.date_created ASC
|
WHERE w.checked IN (0, 1)
|
||||||
LIMIT 500");
|
ORDER BY w.checked DESC, w.date_created ASC
|
||||||
$stWait->execute();
|
LIMIT 500");
|
||||||
$waitRows = $stWait->fetchAll(PDO::FETCH_ASSOC);
|
$stWait->execute();
|
||||||
|
$waitRows = $stWait->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
foreach ($waitRows as &$waitRow) {
|
$waitIds = array_map(static function (array $waitRow): int {
|
||||||
$waitRow['zeitraum_labels'] = impfGetWartelistenZeitraeumeLabels($pdo, (int)$waitRow['warteid'], false);
|
return (int)($waitRow['warteid'] ?? 0);
|
||||||
if (!empty($waitRow['zeitraum_labels'])) {
|
}, $waitRows);
|
||||||
$waitRow['impfenzeitraum'] = implode(' | ', $waitRow['zeitraum_labels']);
|
$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);
|
||||||
unset($waitRow);
|
|
||||||
|
|
||||||
$notificationEvents = impfWorkflowNotificationProcess($pdo);
|
|
||||||
if (!empty($notificationEvents)) {
|
|
||||||
$notificationText = count($notificationEvents) . " Impfworkflow-Benachrichtigung(en) wurden versendet.";
|
|
||||||
$message = ($message === '') ? $notificationText : ($message . ' ' . $notificationText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$stUpcoming = $pdo->prepare("SELECT ts.timeid, ts.date, ts.start, ts.ende, ts.impfdosen,
|
if ($needsUpcomingRows) {
|
||||||
i.impfname, o.anzeigename, o.adresse,
|
$stUpcoming = $pdo->prepare("SELECT ts.timeid, ts.date, ts.start, ts.ende, ts.impfdosen,
|
||||||
it.terminid, it.checked, it.behandelt, it.impfart,
|
i.impfname, o.anzeigename, o.adresse,
|
||||||
p.vorname, p.nachname, p.geburtstag, p.email, p.tele
|
it.terminid, it.checked, it.behandelt, it.impfart,
|
||||||
FROM timeslots ts
|
p.vorname, p.nachname, p.geburtstag, p.email, p.tele
|
||||||
INNER JOIN impfstoff i ON i.impfid = ts.impfstoff
|
FROM timeslots ts
|
||||||
LEFT JOIN impfort o ON o.ortid = ts.impfortid
|
INNER JOIN impfstoff i ON i.impfid = ts.impfstoff
|
||||||
LEFT JOIN impftermin it ON it.timeid = ts.timeid
|
LEFT JOIN impfort o ON o.ortid = ts.impfortid
|
||||||
LEFT JOIN persons p ON p.person_id = it.userid
|
LEFT JOIN impftermin it ON it.timeid = ts.timeid
|
||||||
WHERE ts.date >= :today
|
LEFT JOIN persons p ON p.person_id = it.userid
|
||||||
AND ts.aktiv = 1
|
WHERE ts.date >= :today
|
||||||
ORDER BY ts.date, ts.start, ts.ende, i.impfname, p.nachname, p.vorname");
|
AND ts.aktiv = 1
|
||||||
$stUpcoming->execute(['today' => date('Y-m-d')]);
|
ORDER BY ts.date, ts.start, ts.ende, i.impfname, p.nachname, p.vorname");
|
||||||
$upcomingRows = $stUpcoming->fetchAll(PDO::FETCH_ASSOC);
|
$stUpcoming->execute(['today' => date('Y-m-d')]);
|
||||||
|
$upcomingRows = $stUpcoming->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
foreach ($upcomingRows as $row) {
|
foreach ($upcomingRows as $row) {
|
||||||
$timeid = (int)$row['timeid'];
|
$timeid = (int)$row['timeid'];
|
||||||
if (!isset($eventOverview[$timeid])) {
|
if (!isset($eventOverview[$timeid])) {
|
||||||
$eventOverview[$timeid] = [
|
$eventOverview[$timeid] = [
|
||||||
'timeid' => $timeid,
|
'timeid' => $timeid,
|
||||||
'date' => $row['date'],
|
'date' => $row['date'],
|
||||||
'start' => $row['start'],
|
'start' => $row['start'],
|
||||||
'ende' => $row['ende'],
|
'ende' => $row['ende'],
|
||||||
'impfdosen' => (int)$row['impfdosen'],
|
'impfdosen' => (int)$row['impfdosen'],
|
||||||
'impfname' => $row['impfname'],
|
'impfname' => $row['impfname'],
|
||||||
'anzeigename' => $row['anzeigename'],
|
'anzeigename' => $row['anzeigename'],
|
||||||
'adresse' => $row['adresse'],
|
'adresse' => $row['adresse'],
|
||||||
'teilnehmer' => [],
|
'teilnehmer' => [],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if (!empty($row['terminid'])) {
|
if (!empty($row['terminid'])) {
|
||||||
$eventOverview[$timeid]['teilnehmer'][] = [
|
$eventOverview[$timeid]['teilnehmer'][] = [
|
||||||
'terminid' => (int)$row['terminid'],
|
'terminid' => (int)$row['terminid'],
|
||||||
'checked' => (int)($row['checked'] ?? 0),
|
'checked' => (int)($row['checked'] ?? 0),
|
||||||
'behandelt' => (int)($row['behandelt'] ?? 0),
|
'behandelt' => (int)($row['behandelt'] ?? 0),
|
||||||
'impfart' => (int)($row['impfart'] ?? 1),
|
'impfart' => (int)($row['impfart'] ?? 1),
|
||||||
'vorname' => (string)($row['vorname'] ?? ''),
|
'vorname' => (string)($row['vorname'] ?? ''),
|
||||||
'nachname' => (string)($row['nachname'] ?? ''),
|
'nachname' => (string)($row['nachname'] ?? ''),
|
||||||
'geburtstag' => (string)($row['geburtstag'] ?? ''),
|
'geburtstag' => (string)($row['geburtstag'] ?? ''),
|
||||||
'email' => (string)($row['email'] ?? ''),
|
'email' => (string)($row['email'] ?? ''),
|
||||||
'tele' => (string)($row['tele'] ?? ''),
|
'tele' => (string)($row['tele'] ?? ''),
|
||||||
];
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
@@ -1257,5 +1287,5 @@ try {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php include __DIR__ . "/templates/footer.inc.php"; ?>
|
<?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')) {
|
if (!function_exists('impfSetWartelistenZeitraeume')) {
|
||||||
function impfSetWartelistenZeitraeume(PDO $pdo, int $warteid, $zeitraumIds): void
|
function impfSetWartelistenZeitraeume(PDO $pdo, int $warteid, $zeitraumIds): void
|
||||||
{
|
{
|
||||||
|
|||||||
+191
-197
@@ -1,197 +1,191 @@
|
|||||||
<?php
|
<?php
|
||||||
// API: returns JSON events for FullCalendar
|
session_start();
|
||||||
session_start();
|
require_once(__DIR__ . '/../inc/config.inc.php');
|
||||||
require_once(__DIR__ . '/../inc/config.inc.php');
|
require_once(__DIR__ . '/../inc/functions.inc.php');
|
||||||
require_once(__DIR__ . '/../inc/functions.inc.php');
|
|
||||||
|
ini_set('display_errors', '1');
|
||||||
// Enable full error reporting for API debugging
|
ini_set('display_startup_errors', '1');
|
||||||
ini_set('display_errors', '1');
|
error_reporting(E_ALL);
|
||||||
ini_set('display_startup_errors', '1');
|
|
||||||
error_reporting(E_ALL);
|
$user = check_user();
|
||||||
|
$isAdmin = is_admin_user();
|
||||||
$user = check_user();
|
|
||||||
$isAdmin = is_admin_user();
|
$start = $_GET['start'] ?? null;
|
||||||
|
$end = $_GET['end'] ?? null;
|
||||||
$start = $_GET['start'] ?? null; // expected ISO date
|
$onlyApproved = isset($_GET['only_approved']) && ($_GET['only_approved'] == '1' || $_GET['only_approved'] === 'true');
|
||||||
$end = $_GET['end'] ?? null;
|
$public = isset($_GET['public']) && ($_GET['public'] == '1' || $_GET['public'] === 'true');
|
||||||
$onlyApproved = isset($_GET['only_approved']) && ($_GET['only_approved'] == '1' || $_GET['only_approved'] === 'true');
|
$includeRejected = isset($_GET['include_rejected']) && ($_GET['include_rejected'] == '1' || $_GET['include_rejected'] === 'true');
|
||||||
// public allows non-admin users to request all *approved* vacations (team view)
|
$onlyPersonal = isset($_GET['only_personal']) && ($_GET['only_personal'] == '1' || $_GET['only_personal'] === 'true');
|
||||||
$public = isset($_GET['public']) && ($_GET['public'] == '1' || $_GET['public'] === 'true');
|
$publicAll = isset($_GET['public_all']) && ($_GET['public_all'] == '1' || $_GET['public_all'] === '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');
|
if (!$start || !$end) {
|
||||||
// only_personal forces the API to return only the current user's vacations (useful even if the user is admin)
|
http_response_code(400);
|
||||||
$onlyPersonal = isset($_GET['only_personal']) && ($_GET['only_personal'] == '1' || $_GET['only_personal'] === 'true');
|
echo json_encode(['error' => 'start and end required']);
|
||||||
// public_all when used with public=1 returns all non-rejected team vacations (approved + beantragt)
|
exit;
|
||||||
$publicAll = isset($_GET['public_all']) && ($_GET['public_all'] == '1' || $_GET['public_all'] === 'true');
|
}
|
||||||
|
|
||||||
if (!$start || !$end) {
|
$events = [];
|
||||||
http_response_code(400);
|
try {
|
||||||
echo json_encode(['error' => 'start and end required']);
|
$branch = 'unknown';
|
||||||
exit;
|
$debugMode = isset($_GET['debug']) && ($_GET['debug'] == '1' || $_GET['debug'] === 'true');
|
||||||
}
|
$showEmployeeNames = $isAdmin || $public;
|
||||||
|
|
||||||
$events = [];
|
if ($onlyPersonal) {
|
||||||
try {
|
$branch = 'onlyPersonal';
|
||||||
$branch = 'unknown';
|
if ($onlyApproved) {
|
||||||
$debugMode = isset($_GET['debug']) && ($_GET['debug'] == '1' || $_GET['debug'] === 'true');
|
$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");
|
||||||
// Vacations: support a personal-only mode, admin mode, and public/team mode
|
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||||
if ($onlyPersonal) {
|
} else {
|
||||||
$branch = 'onlyPersonal';
|
if ($includeRejected) {
|
||||||
if ($onlyApproved) {
|
$branch = 'onlyPersonal_includeRejected';
|
||||||
$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 >= ? ORDER BY v.start_date");
|
||||||
$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]);
|
||||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
} else {
|
||||||
} else {
|
$branch = 'onlyPersonal_excludeRejected';
|
||||||
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.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");
|
||||||
$branch = 'onlyPersonal_includeRejected';
|
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||||
$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 {
|
} elseif ($isAdmin) {
|
||||||
$branch = 'onlyPersonal_excludeRejected';
|
$branch = 'admin';
|
||||||
$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");
|
if ($onlyApproved) {
|
||||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
$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]);
|
||||||
} elseif ($isAdmin) {
|
} else {
|
||||||
$branch = 'admin';
|
if ($includeRejected) {
|
||||||
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.start_date <= ? AND v.end_date >= ? ORDER BY v.start_date");
|
||||||
$branch = 'admin_onlyApproved';
|
$stmt->execute([$end, $start]);
|
||||||
$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");
|
} else {
|
||||||
$stmt->execute([$end, $start]);
|
$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");
|
||||||
} else {
|
$stmt->execute([$end, $start]);
|
||||||
// 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");
|
} else {
|
||||||
$stmt->execute([$end, $start]);
|
$branch = 'public_or_regular';
|
||||||
} else {
|
if ($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 (v.status IS NULL OR LOWER(TRIM(v.status)) IN ('genehmigt','beantragt')) ORDER BY v.start_date");
|
$branch = 'public_onlyApproved';
|
||||||
$stmt->execute([$end, $start]);
|
$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) {
|
||||||
} else {
|
$branch = 'public_publicAll';
|
||||||
$branch = 'public_or_regular';
|
$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");
|
||||||
if ($public && $onlyApproved) {
|
$stmt->execute([$end, $start]);
|
||||||
$branch = 'public_onlyApproved';
|
} else {
|
||||||
// public team view: show all approved vacations (read-only)
|
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.start_date <= ? AND v.end_date >= ? AND LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
$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([$end, $start]);
|
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||||
} elseif ($public && $publicAll) {
|
} else {
|
||||||
$branch = 'public_publicAll';
|
if ($includeRejected) {
|
||||||
// public team view: explicitly show only approved (genehmigt) and pending (beantragt) vacations
|
$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.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 = $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([$end, $start]);
|
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
||||||
} else {
|
} else {
|
||||||
if ($onlyApproved) {
|
$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 LOWER(TRIM(v.status)) = 'genehmigt' ORDER BY v.start_date");
|
$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]);
|
$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]);
|
try {
|
||||||
} else {
|
$vacations = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
$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");
|
if ($debugMode) {
|
||||||
$stmt->execute([$_SESSION['userid'], $end, $start]);
|
$rawStatuses = array_map(function($r){ return $r['status'] ?? null; }, $vacations);
|
||||||
}
|
$meta = [
|
||||||
}
|
'branch' => $branch,
|
||||||
}
|
'count' => count($vacations),
|
||||||
}
|
'raw_statuses' => $rawStatuses
|
||||||
|
];
|
||||||
try {
|
}
|
||||||
$vacations = $stmt->fetchAll();
|
|
||||||
|
foreach ($vacations as $v) {
|
||||||
// If debug mode is enabled, prepare meta information
|
if (isset($v['status'])) {
|
||||||
if ($debugMode) {
|
$normalized = preg_replace('/\s+/u', ' ', $v['status']);
|
||||||
$rawStatuses = array_map(function($r){ return $r['status'] ?? null; }, $vacations);
|
$status = mb_strtolower(trim($normalized));
|
||||||
$meta = [
|
} else {
|
||||||
'branch' => $branch,
|
$status = '';
|
||||||
'count' => count($vacations),
|
}
|
||||||
'raw_statuses' => $rawStatuses
|
|
||||||
];
|
if (!$isAdmin && !$includeRejected && mb_stripos($status, 'abgelehnt') !== false) {
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
foreach ($vacations as $v) {
|
|
||||||
// Normalize status: collapse whitespace (including NBSP), trim, lowercase
|
$isApproved = (mb_stripos($status, 'genehmigt') !== false);
|
||||||
if (isset($v['status'])) {
|
$employeeName = trim(($v['vorname'] ?? '') . ' ' . ($v['nachname'] ?? ''));
|
||||||
$normalized = preg_replace('/\s+/u', ' ', $v['status']);
|
if ($showEmployeeNames && $employeeName !== '') {
|
||||||
$status = mb_strtolower(trim($normalized));
|
$title = $employeeName;
|
||||||
} else {
|
if ($v['status'] !== null && $v['status'] !== '') {
|
||||||
$status = '';
|
$title .= ' (' . $v['status'] . ')';
|
||||||
}
|
}
|
||||||
// Defensive filter: do not expose rejected ('abgelehnt') entries to non-admins
|
} elseif ($isApproved) {
|
||||||
if (!$isAdmin && !$includeRejected && mb_stripos($status, 'abgelehnt') !== false) {
|
$title = 'Urlaub';
|
||||||
continue;
|
} else {
|
||||||
}
|
$title = 'Urlaubsantrag';
|
||||||
$isApproved = (mb_stripos($status, 'genehmigt') !== false);
|
}
|
||||||
if ($isAdmin) {
|
|
||||||
$title = $v['vorname'] . ' ' . $v['nachname'] . ' (' . ($v['status'] ?? 'beantragt') . ')';
|
try {
|
||||||
} else {
|
$endInclusive = (new DateTime($v['end_date']))->modify('+1 day')->format('Y-m-d');
|
||||||
$title = $isApproved ? 'Urlaub' : 'Urlaubsantrag';
|
} catch (Exception $e) {
|
||||||
}
|
$endInclusive = $v['start_date'];
|
||||||
// Safely compute end date; fallback to start_date if invalid
|
}
|
||||||
try {
|
|
||||||
$endInclusive = (new DateTime($v['end_date']))->modify('+1 day')->format('Y-m-d');
|
$events[] = [
|
||||||
} catch (Exception $e) {
|
'id' => 'vac_' . $v['id'],
|
||||||
$endInclusive = $v['start_date'];
|
'title' => $title,
|
||||||
}
|
'start' => $v['start_date'],
|
||||||
$events[] = [
|
'end' => $endInclusive,
|
||||||
'id' => 'vac_' . $v['id'],
|
'allDay' => true,
|
||||||
'title' => $title,
|
'color' => ($isApproved) ? '#28a745' : '#ffc107',
|
||||||
'start' => $v['start_date'],
|
'extendedProps' => [
|
||||||
'end' => $endInclusive,
|
'type' => 'user',
|
||||||
'allDay' => true,
|
'user_id' => $v['user_id'],
|
||||||
'color' => ($isApproved) ? '#28a745' : '#ffc107',
|
'employee_name' => $employeeName,
|
||||||
'extendedProps' => [
|
'status' => $v['status'],
|
||||||
'type' => 'user',
|
'comment' => $v['comment_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()];
|
||||||
} catch (Exception $ex) {
|
echo json_encode($payload);
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
exit;
|
||||||
$payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()];
|
}
|
||||||
echo json_encode($payload);
|
} catch (Exception $ex) {
|
||||||
exit;
|
header('Content-Type: application/json; charset=utf-8');
|
||||||
}
|
$payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()];
|
||||||
|
echo json_encode($payload);
|
||||||
} catch (Exception $ex) {
|
exit;
|
||||||
header('Content-Type: application/json; charset=utf-8');
|
}
|
||||||
$payload = ['error' => $ex->getMessage(), 'branch' => $branch, 'trace' => $ex->getTraceAsString()];
|
|
||||||
echo json_encode($payload);
|
$stmt = $pdo->prepare("SELECT * FROM company_holidays WHERE start_date <= ? AND end_date >= ? ORDER BY start_date");
|
||||||
exit;
|
$stmt->execute([$end, $start]);
|
||||||
}
|
$holidays = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
|
|
||||||
// Company holidays (visible to all)
|
foreach ($holidays as $h) {
|
||||||
$stmt = $pdo->prepare("SELECT * FROM company_holidays WHERE start_date <= ? AND end_date >= ? ORDER BY start_date");
|
$endInclusive = (new DateTime($h['end_date']))->modify('+1 day')->format('Y-m-d');
|
||||||
$stmt->execute([$end, $start]);
|
$events[] = [
|
||||||
$holidays = $stmt->fetchAll();
|
'id' => 'com_' . $h['id'],
|
||||||
|
'title' => $h['description'] ?: 'Betriebsurlaub',
|
||||||
foreach ($holidays as $h) {
|
'start' => $h['start_date'],
|
||||||
$endInclusive = (new DateTime($h['end_date']))->modify('+1 day')->format('Y-m-d');
|
'end' => $endInclusive,
|
||||||
$events[] = [
|
'allDay' => true,
|
||||||
'id' => 'com_' . $h['id'],
|
'color' => '#007bff',
|
||||||
'title' => $h['description'] ?: 'Betriebsurlaub',
|
'extendedProps' => [
|
||||||
'start' => $h['start_date'],
|
'type' => 'company',
|
||||||
'end' => $endInclusive,
|
'description' => $h['description']
|
||||||
'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);
|
||||||
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
|
<?php
|
||||||
session_start();
|
session_start();
|
||||||
require_once('inc/config.inc.php');
|
require_once('inc/config.inc.php');
|
||||||
require_once('inc/functions.inc.php');
|
require_once('inc/functions.inc.php');
|
||||||
|
require_once(__DIR__ . '/../inc/company_holiday_sync.inc.php');
|
||||||
$user = check_user();
|
|
||||||
if (!is_admin_user()) {
|
$user = check_user();
|
||||||
die('Zugriff verweigert. Nur Chefs dürfen Betriebsurlaub verwalten.');
|
if (!is_admin_user()) {
|
||||||
}
|
die('Zugriff verweigert. Nur Chefs duerfen Betriebsurlaub verwalten.');
|
||||||
|
}
|
||||||
// Create table if not exists (optional helper)
|
|
||||||
// Administrators can also run the SQL directly in DB. This is just a convenience.
|
$error = '';
|
||||||
|
$schemaError = '';
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['start_date']) && isset($_POST['end_date'])) {
|
|
||||||
$start = $_POST['start_date'];
|
try {
|
||||||
$end = $_POST['end_date'];
|
vacationSyncEnsureSchema($pdo);
|
||||||
$desc = trim($_POST['description'] ?? 'Betriebsurlaub');
|
} catch (Throwable $e) {
|
||||||
|
$schemaError = 'Die Seite konnte das Urlaubsschema nicht automatisch aktualisieren: ' . $e->getMessage();
|
||||||
$stmt = $pdo->prepare("INSERT INTO company_holidays (start_date, end_date, description, created_by) VALUES (?, ?, ?, ?)");
|
}
|
||||||
$stmt->execute([$start, $end, $desc, $_SESSION['userid']]);
|
|
||||||
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['start_date']) && isset($_POST['end_date'])) {
|
||||||
header('Location: company_holidays.php');
|
$start = trim((string)($_POST['start_date'] ?? ''));
|
||||||
exit();
|
$end = trim((string)($_POST['end_date'] ?? ''));
|
||||||
}
|
$desc = trim((string)($_POST['description'] ?? 'Betriebsurlaub'));
|
||||||
|
$vertretung = trim((string)($_POST['vertretung'] ?? ''));
|
||||||
include 'header.php';
|
$vertretertelefon = trim((string)($_POST['vertretertelefon'] ?? ''));
|
||||||
|
$vertreteradresse = trim((string)($_POST['vertreteradresse'] ?? ''));
|
||||||
$stmt = $pdo->prepare("SELECT * FROM company_holidays ORDER BY start_date DESC");
|
$vertreterurl = trim((string)($_POST['vertreterurl'] ?? ''));
|
||||||
$stmt->execute();
|
|
||||||
$holidays = $stmt->fetchAll();
|
if ($start === '' || $end === '') {
|
||||||
|
$error = 'Bitte Start- und Enddatum angeben.';
|
||||||
?>
|
} elseif ($start > $end) {
|
||||||
|
$error = 'Das Enddatum darf nicht vor dem Startdatum liegen.';
|
||||||
<div class="container">
|
} elseif ($vertretung === '' || $vertretertelefon === '' || $vertreteradresse === '' || $vertreterurl === '') {
|
||||||
<h2>Betriebsurlaub verwalten</h2>
|
$error = 'Bitte alle Vertreterinformationen vollstaendig ausfuellen.';
|
||||||
|
} elseif ($schemaError !== '') {
|
||||||
<form method="post" class="form-inline mb-3">
|
$error = $schemaError;
|
||||||
<div class="form-group mr-2">
|
} else {
|
||||||
<label>Von:</label>
|
$stmt = $pdo->prepare("
|
||||||
<input type="date" name="start_date" class="form-control" required>
|
INSERT INTO company_holidays (
|
||||||
</div>
|
start_date, end_date, description, vertretung, vertretertelefon, vertreteradresse, vertreterurl, created_by
|
||||||
<div class="form-group mr-2">
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
<label>Bis:</label>
|
");
|
||||||
<input type="date" name="end_date" class="form-control" required>
|
$stmt->execute([
|
||||||
</div>
|
$start,
|
||||||
<div class="form-group mr-2">
|
$end,
|
||||||
<label>Beschreibung:</label>
|
$desc,
|
||||||
<input type="text" name="description" class="form-control" placeholder="z. B. Betriebsurlaub Weihnachten">
|
$vertretung,
|
||||||
</div>
|
$vertretertelefon,
|
||||||
<button class="btn btn-primary">Hinzufügen</button>
|
$vertreteradresse,
|
||||||
</form>
|
$vertreterurl,
|
||||||
|
$_SESSION['userid']
|
||||||
<table class="table table-bordered">
|
]);
|
||||||
<thead>
|
vacationSyncUrlaubFromCompanyHoliday($pdo, (int)$pdo->lastInsertId());
|
||||||
<tr>
|
|
||||||
<th>Von</th>
|
header('Location: company_holidays.php');
|
||||||
<th>Bis</th>
|
exit();
|
||||||
<th>Beschreibung</th>
|
}
|
||||||
<th>Erstellt von</th>
|
}
|
||||||
<th>Aktion</th>
|
|
||||||
</tr>
|
include 'header.php';
|
||||||
</thead>
|
|
||||||
<tbody>
|
$stmt = $pdo->prepare("SELECT * FROM company_holidays ORDER BY start_date DESC");
|
||||||
<?php foreach ($holidays as $h): ?>
|
$stmt->execute();
|
||||||
<tr>
|
$holidays = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||||
<td><?php echo $h['start_date']; ?></td>
|
?>
|
||||||
<td><?php echo $h['end_date']; ?></td>
|
|
||||||
<td><?php echo htmlspecialchars($h['description']); ?></td>
|
<div class="container">
|
||||||
<td><?php
|
<h2>Betriebsurlaub verwalten</h2>
|
||||||
$s = $pdo->prepare("SELECT vorname, nachname FROM users WHERE id = ?");
|
|
||||||
$s->execute([$h['created_by']]);
|
<?php if ($error !== ''): ?>
|
||||||
$u = $s->fetch();
|
<div class="alert alert-danger"><?php echo htmlspecialchars($error); ?></div>
|
||||||
echo htmlspecialchars($u['vorname'] . ' ' . $u['nachname']);
|
<?php endif; ?>
|
||||||
?></td>
|
<?php if ($schemaError !== ''): ?>
|
||||||
<td>
|
<div class="alert alert-warning"><?php echo htmlspecialchars($schemaError); ?></div>
|
||||||
<form method="post" action="deleteCompanyHoliday.php" onsubmit="return confirm('Betriebsurlaub wirklich löschen?');">
|
<?php endif; ?>
|
||||||
<input type="hidden" name="id" value="<?php echo intval($h['id']); ?>">
|
|
||||||
<button class="btn btn-sm btn-danger">Löschen</button>
|
<form method="post" class="mb-3">
|
||||||
</form>
|
<div class="form-row">
|
||||||
</td>
|
<div class="form-group col-md-3">
|
||||||
</tr>
|
<label>Von:</label>
|
||||||
<?php endforeach; ?>
|
<input type="date" name="start_date" class="form-control" required>
|
||||||
</tbody>
|
</div>
|
||||||
</table>
|
<div class="form-group col-md-3">
|
||||||
|
<label>Bis:</label>
|
||||||
</div>
|
<input type="date" name="end_date" class="form-control" required>
|
||||||
|
</div>
|
||||||
<?php include 'footer.php';
|
<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();
|
session_start();
|
||||||
require_once('inc/config.inc.php');
|
require_once('inc/config.inc.php');
|
||||||
require_once('inc/functions.inc.php');
|
require_once('inc/functions.inc.php');
|
||||||
|
require_once(__DIR__ . '/../inc/company_holiday_sync.inc.php');
|
||||||
|
|
||||||
$user = check_user();
|
$user = check_user();
|
||||||
if (!is_admin_user()) {
|
if (!is_admin_user()) {
|
||||||
@@ -18,9 +19,10 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['id'])) {
|
|||||||
|
|
||||||
$id = intval($_POST['id']);
|
$id = intval($_POST['id']);
|
||||||
|
|
||||||
|
vacationSyncDeleteUrlaubByCompanyHoliday($pdo, $id);
|
||||||
$stmt = $pdo->prepare("DELETE FROM company_holidays WHERE id = ?");
|
$stmt = $pdo->prepare("DELETE FROM company_holidays WHERE id = ?");
|
||||||
$stmt->execute([$id]);
|
$stmt->execute([$id]);
|
||||||
|
|
||||||
header('Location: company_holidays.php');
|
header('Location: company_holidays.php');
|
||||||
exit;
|
exit;
|
||||||
?>
|
?>
|
||||||
|
|||||||
@@ -1,38 +1,34 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
session_start();
|
||||||
require_once('inc/config.inc.php');
|
require_once('inc/config.inc.php');
|
||||||
require_once('inc/functions.inc.php');
|
require_once('inc/functions.inc.php');
|
||||||
|
|
||||||
$user = check_user();
|
$user = check_user();
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['id'])) {
|
if ($_SERVER['REQUEST_METHOD'] !== 'POST' || !isset($_POST['id'])) {
|
||||||
http_response_code(400);
|
http_response_code(400);
|
||||||
die('Bad request');
|
die('Bad request');
|
||||||
}
|
}
|
||||||
|
|
||||||
$id = (int)$_POST['id'];
|
$id = (int)$_POST['id'];
|
||||||
$referer = $_POST['referer'] ?? 'urlaubsantrag.php';
|
$referer = $_POST['referer'] ?? 'urlaubsantrag.php';
|
||||||
|
|
||||||
// Fetch vacation to verify ownership
|
$stmt = $pdo->prepare("SELECT user_id, status FROM vacations WHERE id = ?");
|
||||||
$stmt = $pdo->prepare("SELECT user_id, status FROM vacations WHERE id = ?");
|
$stmt->execute([$id]);
|
||||||
$stmt->execute([$id]);
|
$vac = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
$vac = $stmt->fetch();
|
|
||||||
|
if (!$vac) {
|
||||||
if (!$vac) {
|
die('Urlaubseintrag nicht gefunden.');
|
||||||
die('Urlaubseintrag nicht gefunden.');
|
}
|
||||||
}
|
|
||||||
|
$canManageTeamVacations = can_manage_team_vacations();
|
||||||
$isAdmin = is_admin_user();
|
if (!$canManageTeamVacations && (int)$vac['user_id'] !== (int)$_SESSION['userid']) {
|
||||||
|
die('Zugriff verweigert.');
|
||||||
if (!$isAdmin && $vac['user_id'] != $_SESSION['userid']) {
|
}
|
||||||
die('Zugriff verweigert.');
|
|
||||||
}
|
$del = $pdo->prepare("DELETE FROM vacations WHERE id = ?");
|
||||||
|
$del->execute([$id]);
|
||||||
// Allow deletion for admins or owner
|
|
||||||
$del = $pdo->prepare("DELETE FROM vacations WHERE id = ?");
|
header('Location: ' . $referer);
|
||||||
$del->execute([$id]);
|
exit();
|
||||||
|
?>
|
||||||
header('Location: ' . $referer);
|
|
||||||
exit();
|
|
||||||
|
|
||||||
?>
|
|
||||||
|
|||||||
@@ -145,6 +145,15 @@ function is_admin_user() {
|
|||||||
$statement->execute(array('id' => $_SESSION['userid']));
|
$statement->execute(array('id' => $_SESSION['userid']));
|
||||||
return ($statement->rowCount() == 1);
|
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
|
* Prüft, ob der Benutzer Bearbeiter ist
|
||||||
*/
|
*/
|
||||||
@@ -187,4 +196,4 @@ function isValidSequence($sequence) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|||||||
+241
-178
@@ -1,178 +1,241 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
session_start();
|
||||||
require_once("inc/config.inc.php");
|
require_once("inc/config.inc.php");
|
||||||
require_once("inc/functions.inc.php");
|
require_once("inc/functions.inc.php");
|
||||||
|
|
||||||
$user = check_user();
|
$user = check_user();
|
||||||
|
|
||||||
if (!isset($_SESSION['userid'])) {
|
if (!isset($_SESSION['userid'])) {
|
||||||
die("Kein Benutzer angemeldet.");
|
die("Kein Benutzer angemeldet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
$user_id = $_SESSION['userid'];
|
$user_id = (int)$_SESSION['userid'];
|
||||||
$message = "";
|
$canManageTeamVacations = can_manage_team_vacations();
|
||||||
$error = "";
|
$message = "";
|
||||||
|
$error = "";
|
||||||
function calculateWorkingDays($start, $end) {
|
$selected_user_id = $user_id;
|
||||||
$start = new DateTime($start);
|
|
||||||
$end = new DateTime($end);
|
$selectableUsers = [];
|
||||||
$end->modify('+1 day');
|
if ($canManageTeamVacations) {
|
||||||
|
$stmtUsers = $pdo->prepare("
|
||||||
$interval = new DateInterval('P1D');
|
SELECT id, vorname, nachname, email
|
||||||
$period = new DatePeriod($start, $interval, $end);
|
FROM users
|
||||||
|
WHERE zeiterfassung = 1
|
||||||
$workingDays = 0;
|
ORDER BY nachname, vorname
|
||||||
|
");
|
||||||
foreach ($period as $day) {
|
$stmtUsers->execute();
|
||||||
if ($day->format('N') < 6) { // 1 (Mo) - 5 (Fr)
|
$selectableUsers = $stmtUsers->fetchAll(PDO::FETCH_ASSOC);
|
||||||
$workingDays++;
|
}
|
||||||
}
|
|
||||||
}
|
function calculateWorkingDays($start, $end) {
|
||||||
|
$start = new DateTime($start);
|
||||||
return $workingDays;
|
$end = new DateTime($end);
|
||||||
}
|
$end->modify('+1 day');
|
||||||
|
|
||||||
if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
$interval = new DateInterval('P1D');
|
||||||
|
$period = new DatePeriod($start, $interval, $end);
|
||||||
$start_date = $_POST['start_date'];
|
|
||||||
$end_date = $_POST['end_date'];
|
$workingDays = 0;
|
||||||
$comment = trim($_POST['comment']);
|
foreach ($period as $day) {
|
||||||
|
if ($day->format('N') < 6) {
|
||||||
if (empty($start_date) || empty($end_date)) {
|
$workingDays++;
|
||||||
$error = "Bitte beide Datumsfelder ausfüllen.";
|
}
|
||||||
} elseif ($start_date > $end_date) {
|
}
|
||||||
$error = "Enddatum liegt vor dem Startdatum.";
|
|
||||||
} elseif ($start_date < date("Y-m-d")) {
|
return $workingDays;
|
||||||
$error = "Urlaub kann nicht in der Vergangenheit beantragt werden.";
|
}
|
||||||
} else {
|
|
||||||
|
if ($_SERVER["REQUEST_METHOD"] === "POST") {
|
||||||
// Überschneidung prüfen
|
$start_date = trim((string)($_POST['start_date'] ?? ''));
|
||||||
$stmt = $pdo->prepare("
|
$end_date = trim((string)($_POST['end_date'] ?? ''));
|
||||||
SELECT COUNT(*) FROM vacations
|
$comment = trim((string)($_POST['comment'] ?? ''));
|
||||||
WHERE user_id = ?
|
$selected_user_id = $canManageTeamVacations ? (int)($_POST['user_id'] ?? $user_id) : $user_id;
|
||||||
AND status != 'abgelehnt'
|
|
||||||
AND (
|
$selectedUser = null;
|
||||||
(start_date BETWEEN ? AND ?)
|
if ($selected_user_id <= 0) {
|
||||||
OR (end_date BETWEEN ? AND ?)
|
$error = "Bitte einen Mitarbeiter auswaehlen.";
|
||||||
OR (? BETWEEN start_date AND end_date)
|
} else {
|
||||||
)
|
$stmtSelectedUser = $pdo->prepare("
|
||||||
");
|
SELECT id, vorname, nachname
|
||||||
$stmt->execute([$user_id, $start_date, $end_date, $start_date, $end_date, $start_date]);
|
FROM users
|
||||||
$exists = $stmt->fetchColumn();
|
WHERE id = ?
|
||||||
|
AND zeiterfassung = 1
|
||||||
if ($exists > 0) {
|
LIMIT 1
|
||||||
$error = "Der Zeitraum überschneidet sich mit einem bestehenden Antrag.";
|
");
|
||||||
} else {
|
$stmtSelectedUser->execute([$selected_user_id]);
|
||||||
|
$selectedUser = $stmtSelectedUser->fetch(PDO::FETCH_ASSOC);
|
||||||
$days = calculateWorkingDays($start_date, $end_date);
|
|
||||||
|
if (!$selectedUser) {
|
||||||
$insert = $pdo->prepare("
|
$error = "Der ausgewaehlte Mitarbeiter wurde nicht gefunden.";
|
||||||
INSERT INTO vacations (user_id, start_date, end_date, days, comment_user)
|
}
|
||||||
VALUES (?, ?, ?, ?, ?)
|
}
|
||||||
");
|
|
||||||
|
if ($error === "" && ($start_date === '' || $end_date === '')) {
|
||||||
$insert->execute([$user_id, $start_date, $end_date, $days, $comment]);
|
$error = "Bitte beide Datumsfelder ausfuellen.";
|
||||||
|
} elseif ($error === "" && $start_date > $end_date) {
|
||||||
$message = "Urlaubsantrag erfolgreich eingereicht ($days Werktage).";
|
$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(*)
|
||||||
<?php include 'header.php'; ?>
|
FROM vacations
|
||||||
|
WHERE user_id = ?
|
||||||
<div class="container">
|
AND status != 'abgelehnt'
|
||||||
<div class="row">
|
AND (
|
||||||
<div class="col-md-8 offset-md-2">
|
(start_date BETWEEN ? AND ?)
|
||||||
|
OR (end_date BETWEEN ? AND ?)
|
||||||
<h2>Urlaubsantrag</h2>
|
OR (? BETWEEN start_date AND end_date)
|
||||||
|
)
|
||||||
<?php if ($error): ?>
|
");
|
||||||
<div class="alert alert-danger"><?php echo $error; ?></div>
|
$stmt->execute([$selected_user_id, $start_date, $end_date, $start_date, $end_date, $start_date]);
|
||||||
<?php endif; ?>
|
$exists = (int)$stmt->fetchColumn();
|
||||||
|
|
||||||
<?php if ($message): ?>
|
if ($exists > 0) {
|
||||||
<div class="alert alert-success"><?php echo $message; ?></div>
|
$error = "Der Zeitraum ueberschneidet sich mit einem bestehenden Antrag.";
|
||||||
<?php endif; ?>
|
} else {
|
||||||
|
$days = calculateWorkingDays($start_date, $end_date);
|
||||||
<form method="post">
|
|
||||||
|
$insert = $pdo->prepare("
|
||||||
<div class="form-group">
|
INSERT INTO vacations (user_id, start_date, end_date, days, comment_user)
|
||||||
<label>Von:</label>
|
VALUES (?, ?, ?, ?, ?)
|
||||||
<input type="date" name="start_date" class="form-control" required>
|
");
|
||||||
</div>
|
$insert->execute([$selected_user_id, $start_date, $end_date, $days, $comment]);
|
||||||
|
|
||||||
<div class="form-group">
|
if ($selected_user_id !== $user_id && $selectedUser) {
|
||||||
<label>Bis:</label>
|
$message = "Urlaub fuer " . $selectedUser['vorname'] . " " . $selectedUser['nachname'] . " erfolgreich eingereicht ($days Werktage).";
|
||||||
<input type="date" name="end_date" class="form-control" required>
|
} else {
|
||||||
</div>
|
$message = "Urlaubsantrag erfolgreich eingereicht ($days Werktage).";
|
||||||
|
}
|
||||||
<div class="form-group">
|
}
|
||||||
<label>Kommentar (optional):</label>
|
}
|
||||||
<textarea name="comment" class="form-control"></textarea>
|
}
|
||||||
</div>
|
?>
|
||||||
|
|
||||||
<br>
|
<?php include 'header.php'; ?>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary btn-block">
|
<div class="container">
|
||||||
Urlaub beantragen
|
<div class="row">
|
||||||
</button>
|
<div class="col-md-8 offset-md-2">
|
||||||
|
|
||||||
</form>
|
<h2>Urlaubsantrag</h2>
|
||||||
|
|
||||||
<hr>
|
<?php if ($error): ?>
|
||||||
|
<div class="alert alert-danger"><?php echo htmlspecialchars($error); ?></div>
|
||||||
<h4>Meine Anträge</h4>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php
|
<?php if ($message): ?>
|
||||||
$stmt = $pdo->prepare("
|
<div class="alert alert-success"><?php echo htmlspecialchars($message); ?></div>
|
||||||
SELECT * FROM vacations
|
<?php endif; ?>
|
||||||
WHERE user_id = ?
|
|
||||||
ORDER BY created_at DESC
|
<form method="post">
|
||||||
");
|
|
||||||
$stmt->execute([$user_id]);
|
<?php if ($canManageTeamVacations): ?>
|
||||||
$antraege = $stmt->fetchAll();
|
<div class="form-group">
|
||||||
?>
|
<label>Mitarbeiter:</label>
|
||||||
|
<select name="user_id" class="form-control" required>
|
||||||
<table class="table table-bordered">
|
<?php foreach ($selectableUsers as $employee): ?>
|
||||||
<tr>
|
<?php $employeeId = (int)$employee['id']; ?>
|
||||||
<th>Von</th>
|
<option value="<?php echo $employeeId; ?>" <?php echo ($selected_user_id === $employeeId) ? 'selected' : ''; ?>>
|
||||||
<th>Bis</th>
|
<?php echo htmlspecialchars(trim($employee['nachname'] . ', ' . $employee['vorname'] . ' | ' . $employee['email'])); ?>
|
||||||
<th>Tage</th>
|
</option>
|
||||||
<th>Status</th>
|
<?php endforeach; ?>
|
||||||
<th>Aktion</th>
|
</select>
|
||||||
</tr>
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
<?php foreach ($antraege as $a): ?>
|
|
||||||
<tr>
|
<div class="form-group">
|
||||||
<td><?php echo $a['start_date']; ?></td>
|
<label>Von:</label>
|
||||||
<td><?php echo $a['end_date']; ?></td>
|
<input type="date" name="start_date" class="form-control" required>
|
||||||
<td><?php echo $a['days']; ?></td>
|
</div>
|
||||||
<td>
|
|
||||||
<?php
|
<div class="form-group">
|
||||||
if ($a['status'] == 'beantragt') {
|
<label>Bis:</label>
|
||||||
echo '<span class="badge badge-warning">Beantragt</span>';
|
<input type="date" name="end_date" class="form-control" required>
|
||||||
} elseif ($a['status'] == 'genehmigt') {
|
</div>
|
||||||
echo '<span class="badge badge-success">Genehmigt</span>';
|
|
||||||
} else {
|
<div class="form-group">
|
||||||
echo '<span class="badge badge-danger">Abgelehnt</span>';
|
<label>Kommentar (optional):</label>
|
||||||
}
|
<textarea name="comment" class="form-control"></textarea>
|
||||||
?>
|
</div>
|
||||||
</td>
|
|
||||||
<td>
|
<br>
|
||||||
<form method="post" action="deleteVacation.php" onsubmit="return confirm('Wirklich löschen?');">
|
|
||||||
<input type="hidden" name="id" value="<?php echo $a['id']; ?>">
|
<button type="submit" class="btn btn-primary btn-block">
|
||||||
<input type="hidden" name="referer" value="urlaubsantrag.php">
|
<?php echo $canManageTeamVacations ? 'Urlaub eintragen' : 'Urlaub beantragen'; ?>
|
||||||
<button type="submit" class="btn btn-sm btn-danger">Löschen</button>
|
</button>
|
||||||
</form>
|
|
||||||
</td>
|
</form>
|
||||||
</tr>
|
|
||||||
<?php endforeach; ?>
|
<hr>
|
||||||
|
|
||||||
</table>
|
<h4><?php echo $canManageTeamVacations ? 'Urlaubseintraege' : 'Meine Antraege'; ?></h4>
|
||||||
|
|
||||||
</div>
|
<?php
|
||||||
</div>
|
$listSql = "
|
||||||
</div>
|
SELECT v.*, u.vorname, u.nachname
|
||||||
|
FROM vacations v
|
||||||
<?php include 'footer.php'; ?>
|
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;
|
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); });
|
fetch(url).then(function(res){ return res.json(); }).then(function(data){ successCallback(data); }).catch(function(err){ failureCallback(err); });
|
||||||
},
|
},
|
||||||
eventClick: function(info) {
|
eventClick: function(info) {
|
||||||
var ev = info.event;
|
var ev = info.event;
|
||||||
var props = ev.extendedProps;
|
var props = ev.extendedProps;
|
||||||
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
|
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
|
||||||
if (props.type === 'user') {
|
if (props.type === 'user') {
|
||||||
html += 'Status: ' + (props.status || '') + '<br>';
|
html += 'Mitarbeiter: ' + (props.employee_name || '') + '<br>';
|
||||||
html += 'Kommentar: ' + (props.comment || '') + '<br>';
|
html += 'Status: ' + (props.status || '') + '<br>';
|
||||||
} else if (props.type === 'company') {
|
html += 'Kommentar: ' + (props.comment || '') + '<br>';
|
||||||
html += 'Beschreibung: ' + (props.description || '') + '<br>';
|
} else if (props.type === 'company') {
|
||||||
}
|
html += 'Beschreibung: ' + (props.description || '') + '<br>';
|
||||||
|
}
|
||||||
document.getElementById('detailsContent').innerHTML = html;
|
document.getElementById('detailsContent').innerHTML = html;
|
||||||
document.getElementById('eventDetails').style.display = 'block';
|
document.getElementById('eventDetails').style.display = 'block';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,59 +1,63 @@
|
|||||||
<?php
|
<?php
|
||||||
session_start();
|
session_start();
|
||||||
require_once('inc/config.inc.php');
|
require_once('inc/config.inc.php');
|
||||||
require_once('inc/functions.inc.php');
|
require_once('inc/functions.inc.php');
|
||||||
|
|
||||||
// allow any logged-in user to view the team calendar (read-only)
|
$user = check_user();
|
||||||
$user = check_user();
|
|
||||||
|
include 'header.php';
|
||||||
include 'header.php';
|
?>
|
||||||
?>
|
|
||||||
|
<div class="container">
|
||||||
<div class="container">
|
<h2>Team Urlaubskalender</h2>
|
||||||
<h2>Team Urlaubskalender</h2>
|
<div id="calendar"></div>
|
||||||
<div id="calendar"></div>
|
<br>
|
||||||
<br>
|
<div>
|
||||||
<div>
|
<span class="badge badge-success">genehmigt</span>
|
||||||
<span class="badge badge-success">genehmigt</span>
|
<span class="badge badge-warning">beantragt</span>
|
||||||
<span class="badge badge-primary">Betriebsurlaub</span>
|
<span class="badge badge-primary">Betriebsurlaub</span>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div id="eventDetails" style="display:none;">
|
<div id="eventDetails" style="display:none;">
|
||||||
<h4>Details</h4>
|
<h4>Details</h4>
|
||||||
<div id="detailsContent"></div>
|
<div id="detailsContent"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<link href='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.css' rel='stylesheet' />
|
<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 src='https://cdn.jsdelivr.net/npm/fullcalendar@5.11.3/main.min.js'></script>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
var calendarEl = document.getElementById('calendar');
|
var calendarEl = document.getElementById('calendar');
|
||||||
|
|
||||||
var calendar = new FullCalendar.Calendar(calendarEl, {
|
var calendar = new FullCalendar.Calendar(calendarEl, {
|
||||||
initialView: 'dayGridMonth',
|
initialView: 'dayGridMonth',
|
||||||
firstDay: 1,
|
firstDay: 1,
|
||||||
height: 650,
|
height: 650,
|
||||||
events: function(info, successCallback, failureCallback) {
|
events: function(info, successCallback, failureCallback) {
|
||||||
var url = 'api/vacations.php?start=' + info.startStr + '&end=' + info.endStr + '&public=1&public_all=1';
|
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); });
|
fetch(url).then(function(res){ return res.json(); }).then(function(data){ successCallback(data); }).catch(function(err){ failureCallback(err); });
|
||||||
},
|
},
|
||||||
eventClick: function(info) {
|
eventClick: function(info) {
|
||||||
var ev = info.event;
|
var ev = info.event;
|
||||||
var props = ev.extendedProps;
|
var props = ev.extendedProps;
|
||||||
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
|
var html = '<strong>' + ev.title + '</strong><br>' + ev.start.toLocaleDateString() + ' - ' + (new Date(ev.end).toLocaleDateString()) + '<br>';
|
||||||
if (props.type === 'user') {
|
if (props.type === 'user') {
|
||||||
html += 'Mitarbeiter-ID: ' + (props.user_id || '') + '<br>';
|
html += 'Mitarbeiter: ' + (props.employee_name || ev.title || '') + '<br>';
|
||||||
} else if (props.type === 'company') {
|
html += 'Status: ' + (props.status || '') + '<br>';
|
||||||
html += 'Beschreibung: ' + (props.description || '') + '<br>';
|
if (props.comment) {
|
||||||
}
|
html += 'Kommentar: ' + props.comment + '<br>';
|
||||||
document.getElementById('detailsContent').innerHTML = html;
|
}
|
||||||
document.getElementById('eventDetails').style.display = 'block';
|
} else if (props.type === 'company') {
|
||||||
}
|
html += 'Beschreibung: ' + (props.description || '') + '<br>';
|
||||||
});
|
}
|
||||||
|
document.getElementById('detailsContent').innerHTML = html;
|
||||||
calendar.render();
|
document.getElementById('eventDetails').style.display = 'block';
|
||||||
});
|
}
|
||||||
</script>
|
});
|
||||||
|
|
||||||
<?php include 'footer.php'; ?>
|
calendar.render();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<?php include 'footer.php'; ?>
|
||||||
|
|||||||
Reference in New Issue
Block a user