Kalender, Terminliste, Terminformular und Terminzettel laufen ueber db_abfrage() mit Platzhaltern; das Anlegen einer mehrtaegigen Terminreihe liegt in einer Transaktion. Die Logik steckt jetzt in incs/termin.php, sites/termin*.php rufen sie nur noch auf. Dabei behoben: - SQL-Injektion ueber die Suchbegriffe der Terminliste, ueber die Mehrfachauswahl (Ankreuzfelder del<N>/erl<N> gingen roh in DELETE bzw. UPDATE), ueber die Wiedervorlage-Tage (INTERVAL $folgedays DAY) und ueber ?action=terminshow&id=... in maketerminarray(), maketerminadresse(), maketelnrn() und makegooglestring() - gespeichertes XSS: Beschreibung, Notiz, Termintyp, Ort, Kundenname und Mitarbeiterfarbe im Kalender, in der Terminliste und im Formular - "or $err=error(...)" stand innerhalb des Abfrage-Strings, dadurch wurden die Nebenzeilen einer Terminreihe beim Loeschen nie entfernt - die Abfrage zum Folgetermin las eine Spalte typ_id, die es in termin nicht gibt; Typ und Wiedervorlage fehlten deshalb beim Bearbeiten - ein Folgetermin wurde mit termtime='' und termdauer='' angelegt, ein Termin ohne Folgetermin mit followed_by='' - im strikten Modus Fehler - ein Termin ohne Datum landete auf dem 01.01.1970 und gab dabei "NICHTTERMINIERT!!" mitten in die Seite aus - die Ueberschneidungspruefung verglich ab dem zweiten Tag gegen das Ende des ersten Tages - eine unbekannte Registerkarte der Terminliste ergab ein leeres WHERE und damit einen SQL-Fehler; jetzt gilt die Standardansicht - terminshow.php pruefte den Typ mit = statt == - der Kalender haengt nicht mehr an der Locale de_DE (strftime) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
555 lines
20 KiB
PHP
555 lines
20 KiB
PHP
<?php
|
|
/*
|
|
* Termine: Kalenderansicht, Terminliste, Anlegen, Ändern und Löschen.
|
|
*
|
|
* Ein Termin über mehrere Tage wird als Reihe einzelner Zeilen gespeichert,
|
|
* die alle dasselbe `main_id` tragen - die id der ersten Zeile. Der Kalender
|
|
* zeigt die Zeilen einzeln, die Liste fasst sie über `main_id` zusammen.
|
|
*
|
|
* Urlaub und Krankheit sind Termine ohne Kunden. Ihre Typ-ids stehen seit
|
|
* jeher fest im Code (auch in `incs/users.php` bei der Urlaubsberechnung und
|
|
* in `templates/addtermin.tpl`).
|
|
*/
|
|
require_once(__DIR__."/db.php");
|
|
require_once(__DIR__."/saveNchange.php");
|
|
|
|
define("TERMTYP_URLAUB", 0);
|
|
define("TERMTYP_KRANKHEIT", 5);
|
|
|
|
/* Ganztägige Termine bekommen diese Dauer; die Terminliste filtert darauf */
|
|
define("TERMIN_GANZTAG", "24:00:00");
|
|
|
|
/* Leerwerte der NOT-NULL-Spalten - der strikte Modus lehnt '' dort ab */
|
|
define("TERMIN_KEIN_DATUM", "0000-00-00 00:00:00");
|
|
define("TERMIN_KEINE_DAUER", "00:00:00");
|
|
|
|
/* Urlaub und Krankheit laufen immer über ganze Tage */
|
|
function terminIstGanztaegig($typ)
|
|
{
|
|
return $typ == TERMTYP_URLAUB || $typ == TERMTYP_KRANKHEIT;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* Formularwerte
|
|
* ------------------------------------------------------------------ */
|
|
|
|
/*
|
|
* Die Felder aus addtermin.tpl. `datetime_start` und `datetime_end` kommen
|
|
* in deutscher Schreibweise ("24.12.2026 um 09:30") und werden hier schon
|
|
* in das Datenbankformat gebracht.
|
|
*/
|
|
function terminFormularwerte()
|
|
{
|
|
return array(
|
|
"head" => formularText("head"),
|
|
"text" => formularText("text"),
|
|
"typ" => formularGanzzahl("typ"),
|
|
"done" => formularGanzzahl("done") ? 1 : 0,
|
|
"user" => formularGanzzahl("user"),
|
|
"user2" => formularGanzzahl("user2"),
|
|
"user3" => formularGanzzahl("user3"),
|
|
"user4" => formularGanzzahl("user4"),
|
|
"folge" => formularGanzzahl("folge") ? 1 : 0,
|
|
"folgetyp" => formularGanzzahl("folgetyp"),
|
|
"folgedays" => formularGanzzahl("folgedays"),
|
|
"start" => dispdate_to_mysql_date(formularText("datetime_start"), 0),
|
|
"ende" => dispdate_to_mysql_date(formularText("datetime_end"), 1),
|
|
);
|
|
}
|
|
|
|
/*
|
|
* Verteilt einen Termin auf Tage. Länger als zwölf Stunden oder Urlaub und
|
|
* Krankheit werden zu ganzen Tagen: Rückgabe ist
|
|
* array(erster Tag, Dauer je Tag, Anzahl Tage).
|
|
*/
|
|
function terminTageUndDauer($werte)
|
|
{
|
|
$start = $werte["start"];
|
|
$dauer = mysql_dauer($start, $werte["ende"]);
|
|
$stunden = (int)strtok($dauer, ":");
|
|
if($stunden <= 12 && !terminIstGanztaegig($werte["typ"]))
|
|
return array($start, $dauer, 1);
|
|
|
|
// ceil() rechnet mit der Stundenzahl, nicht mit dem ganzen Zeitstring
|
|
$tage = max(1, (int)ceil($stunden / 24));
|
|
if($start != TERMIN_KEIN_DATUM)
|
|
$start = substr($start, 0, 11)."00:00:00";
|
|
return array($start, TERMIN_GANZTAG, $tage);
|
|
}
|
|
|
|
/* Der $i-te Tag einer Terminreihe, ohne Datum bleibt es ohne Datum */
|
|
function terminTag($start, $i)
|
|
{
|
|
if($start == TERMIN_KEIN_DATUM)
|
|
return TERMIN_KEIN_DATUM;
|
|
return date("Y-m-d H:i:s", strtotime("+".$i." day", strtotime($start)));
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* Überschneidungen
|
|
* ------------------------------------------------------------------ */
|
|
|
|
/*
|
|
* Sucht einen Termin, bei dem $benutzer schon zwischen $start und $ende
|
|
* eingetragen ist. $ausserMain schließt die gerade bearbeitete Reihe aus.
|
|
* Gibt die id des kollidierenden Termins zurück, sonst null (false bei
|
|
* Fehlern).
|
|
*/
|
|
function terminUeberschneidung($dbconn, $benutzer, $start, $ende, $ausserMain)
|
|
{
|
|
if(!$benutzer || $start == TERMIN_KEIN_DATUM)
|
|
return null;
|
|
$params = array(TERMIN_KEIN_DATUM, $benutzer, $benutzer, $benutzer, $benutzer);
|
|
// eine main_id von 0 gibt es nur bei Altdaten, dann darf nichts ausgenommen werden
|
|
$eigene = "";
|
|
if($ausserMain > 0)
|
|
{
|
|
$eigene = " AND main_id != ?";
|
|
$params[] = (int)$ausserMain;
|
|
}
|
|
array_push($params, $start, $start, $ende, $ende, $start, $ende);
|
|
$sql = "SELECT id FROM
|
|
(SELECT id, main_id, user, user2, user3, user4, termtime,
|
|
DATE_ADD(termtime, INTERVAL CONCAT(HOUR(termdauer),' ',MINUTE(termdauer)) HOUR_MINUTE) AS termend
|
|
FROM termin WHERE termtime != ? AND done = 0) AS belegt
|
|
WHERE (user = ? OR user2 = ? OR user3 = ? OR user4 = ?)$eigene
|
|
AND ((? >= termtime AND ? < termend)
|
|
OR (? > termtime AND ? <= termend)
|
|
OR (? <= termtime AND ? >= termend))
|
|
LIMIT 1";
|
|
return db_wert($dbconn, $sql, $params);
|
|
}
|
|
|
|
/*
|
|
* Prüft alle vier Mitarbeiter eines Termins für jeden Tag der Reihe.
|
|
* Rückgabe 0, wenn nichts kollidiert, sonst die Fehlermeldung.
|
|
*/
|
|
function pruefeUeberschneidungen($dbconn, $werte, $start, $dauer, $tage, $ausserMain)
|
|
{
|
|
foreach(range(0, $tage - 1) as $i)
|
|
{
|
|
$tagStart = terminTag($start, $i);
|
|
$tagEnde = dauer_to_date($tagStart, $dauer);
|
|
foreach(array("user", "user2", "user3", "user4") as $feld)
|
|
{
|
|
$treffer = terminUeberschneidung($dbconn, $werte[$feld], $tagStart, $tagEnde, $ausserMain);
|
|
if($treffer === false)
|
|
return error("Fehler beim überprüfen von Überlappungen:<br />".mysqli_error($dbconn));
|
|
if($treffer !== null)
|
|
return error("Dieser Mitarbeiter hat zu der Zeit bereits einen Termin, er kann nicht an zwei Orten gleichzeitig sein.");
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* Speichern
|
|
* ------------------------------------------------------------------ */
|
|
|
|
/*
|
|
* Legt einen Folgetermin an: gleicher Kopf und dieselben Mitarbeiter, aber
|
|
* ohne Datum und mit einem Wiedervorlagedatum in $tage Tagen. Gibt dessen
|
|
* id zurück oder false.
|
|
*/
|
|
function legeFolgeterminAn($dbconn, $werte, $adressid)
|
|
{
|
|
$sql = "INSERT INTO termin SET head = ?, text = '', adresse_id = ?, typ = ?,
|
|
changetime = NOW(), datetime = NOW(), done = 0,
|
|
termtime = ?, termdauer = ?, followed_by = 0,
|
|
user = ?, user2 = ?, user3 = ?, user4 = ?, changeuser = ?,
|
|
act_date = DATE_ADD(CURDATE(), INTERVAL ? DAY)";
|
|
$params = array($werte["head"], $adressid, $werte["folgetyp"],
|
|
TERMIN_KEIN_DATUM, TERMIN_KEINE_DAUER,
|
|
$werte["user"], $werte["user2"], $werte["user3"], $werte["user4"],
|
|
$_SESSION["user"], $werte["folgedays"]);
|
|
if(!db_abfrage($dbconn, $sql, $params))
|
|
{
|
|
error("Fehler beim anlegen des Folgetermins:<br />".mysqli_error($dbconn));
|
|
return false;
|
|
}
|
|
$id = mysqli_insert_id($dbconn);
|
|
// Ein Termin ohne eigene Reihe ist sein eigener Hauptsatz
|
|
db_abfrage($dbconn, "UPDATE termin SET main_id = ? WHERE id = ?", array($id, $id));
|
|
if(saveLog($dbconn, db_sql_text($dbconn, $sql, $params)." [folgetermin, hat ID $id]",
|
|
"DELETE FROM termin WHERE id = $id", "anlegen"))
|
|
return false;
|
|
return $id;
|
|
}
|
|
|
|
/*
|
|
* Legt einen Termin an oder ändert ihn. $terminid ist die id der Reihe
|
|
* (0 = neu), $adressid die Kundenadresse (0 bei Urlaub und Krankheit).
|
|
*
|
|
* Wird aus einem eintägigen Termin ein mehrtägiger, wird die alte Reihe
|
|
* verworfen und neu angelegt - anders lässt sich die Reihe nicht umbauen.
|
|
*/
|
|
function speichereTermin($dbconn, $terminid, $adressid)
|
|
{
|
|
$werte = terminFormularwerte();
|
|
list($start, $dauer, $tage) = terminTageUndDauer($werte);
|
|
|
|
beginneSpeichern($dbconn);
|
|
|
|
$neuAnlegen = !$terminid;
|
|
if($terminid && $tage > 1)
|
|
{
|
|
// aus einem Einzeltermin wird eine Reihe: alte Zeilen verwerfen
|
|
$err = loescheTerminreihe($dbconn, $terminid);
|
|
if($err)
|
|
return beendeSpeichern($dbconn, $err);
|
|
$neuAnlegen = true;
|
|
$terminid = 0;
|
|
}
|
|
elseif($terminid)
|
|
{
|
|
// Zeilen der bisherigen Reihe bis auf die erste entfernen
|
|
$sql = "DELETE FROM termin WHERE main_id = ? AND id != ?";
|
|
db_abfrage($dbconn, $sql, array($terminid, $terminid))
|
|
or $err = error("Konnte Nebentermine nicht löschen:<br />".mysqli_error($dbconn));
|
|
if(!empty($err))
|
|
return beendeSpeichern($dbconn, $err);
|
|
}
|
|
|
|
if(!$werte["done"])
|
|
{
|
|
$err = pruefeUeberschneidungen($dbconn, $werte, $start, $dauer, $tage, $terminid);
|
|
if($err)
|
|
return beendeSpeichern($dbconn, $err);
|
|
}
|
|
|
|
$alt = null;
|
|
if(!$neuAnlegen)
|
|
{
|
|
$alt = db_zeile($dbconn, "SELECT * FROM termin WHERE id = ?", array($terminid));
|
|
if($alt === false)
|
|
return beendeSpeichern($dbconn, error("Fehler beim ermitteln des Termins:<br />".mysqli_error($dbconn)));
|
|
if(!$alt)
|
|
return beendeSpeichern($dbconn, error("Dieser Termin existiert nicht!"));
|
|
}
|
|
|
|
// Folgetermin nur einmal und nur, wenn der Termin gerade erledigt wird
|
|
$folgeId = $alt ? (int)$alt["followed_by"] : 0;
|
|
if($werte["done"] && $werte["folge"] && !$folgeId)
|
|
{
|
|
$folgeId = legeFolgeterminAn($dbconn, $werte, $adressid);
|
|
if($folgeId === false)
|
|
return beendeSpeichern($dbconn, 1);
|
|
}
|
|
|
|
$felder = array(
|
|
"head" => $werte["head"],
|
|
"text" => $werte["text"],
|
|
"adresse_id" => $adressid,
|
|
"typ" => $werte["typ"],
|
|
"done" => $werte["done"],
|
|
"termdauer" => $dauer,
|
|
"changeuser" => $_SESSION["user"],
|
|
"user" => $werte["user"],
|
|
"user2" => $werte["user2"],
|
|
"user3" => $werte["user3"],
|
|
"user4" => $werte["user4"],
|
|
"followed_by" => $folgeId,
|
|
);
|
|
$zuweisung = array();
|
|
foreach(array_keys($felder) as $spalte)
|
|
$zuweisung[] = "`$spalte` = ?";
|
|
$set = implode(", ", $zuweisung);
|
|
$err = 0;
|
|
|
|
if(!$neuAnlegen)
|
|
{
|
|
$sql = "UPDATE termin SET $set, termtime = ?, changetime = NOW() WHERE id = ?";
|
|
$params = array_merge(array_values($felder), array(terminTag($start, 0), $terminid));
|
|
if(!db_abfrage($dbconn, $sql, $params))
|
|
return beendeSpeichern($dbconn, error("Fehler beim ändern des Termins:<br />".mysqli_error($dbconn)));
|
|
$altWerte = array();
|
|
foreach(array_keys($felder) as $spalte)
|
|
$altWerte[] = $alt[$spalte];
|
|
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $params)." [termin change]",
|
|
db_sql_text($dbconn, $sql, array_merge($altWerte, array($alt["termtime"], $terminid))), "ändern");
|
|
}
|
|
else
|
|
{
|
|
$mainId = 0;
|
|
foreach(range(0, $tage - 1) as $i)
|
|
{
|
|
if($err)
|
|
break;
|
|
$sql = "INSERT INTO termin SET $set, termtime = ?, main_id = ?, changetime = NOW(), datetime = NOW()";
|
|
$params = array_merge(array_values($felder), array(terminTag($start, $i), $mainId));
|
|
if(!db_abfrage($dbconn, $sql, $params))
|
|
{
|
|
$err = error("Fehler beim anlegen des Termins:<br />".mysqli_error($dbconn));
|
|
break;
|
|
}
|
|
$id = mysqli_insert_id($dbconn);
|
|
if(!$mainId)
|
|
{
|
|
// der erste Tag ist der Hauptsatz der Reihe
|
|
$mainId = $id;
|
|
db_abfrage($dbconn, "UPDATE termin SET main_id = ? WHERE id = ?", array($id, $id))
|
|
or $err = error("Fehler beim verknüpfen der Terminreihe:<br />".mysqli_error($dbconn));
|
|
}
|
|
if(!$err)
|
|
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $params)." [termin add, hat ID $id]",
|
|
"DELETE FROM termin WHERE id = $id", "anlegen");
|
|
}
|
|
}
|
|
return beendeSpeichern($dbconn, $err);
|
|
}
|
|
|
|
/* Löscht eine Terminreihe samt Nebenzeilen */
|
|
function loescheTerminreihe($dbconn, $id)
|
|
{
|
|
beginneSpeichern($dbconn);
|
|
$err = 0;
|
|
$beschreibung = db_wert($dbconn, "SELECT head FROM termin WHERE id = ?", array($id));
|
|
if($beschreibung === false)
|
|
return beendeSpeichern($dbconn, error("Fehler beim ermitteln des Termins:<br />".mysqli_error($dbconn)));
|
|
if($beschreibung === null)
|
|
return beendeSpeichern($dbconn, error("Dieser Termin existiert nicht!"));
|
|
|
|
// erst die Nebenzeilen, dann der Hauptsatz - sonst verliert main_id den Bezug
|
|
$sql = "DELETE FROM termin WHERE main_id = ? AND id != ?";
|
|
db_abfrage($dbconn, $sql, array($id, $id))
|
|
or $err = error("Konnte Nebentermine nicht löschen:<br />".mysqli_error($dbconn));
|
|
if(!$err)
|
|
{
|
|
$sql = "DELETE FROM termin WHERE id = ?";
|
|
db_abfrage($dbconn, $sql, array($id))
|
|
or $err = error("Konnte Haupttermin nicht löschen:<br />".mysqli_error($dbconn));
|
|
}
|
|
if(!$err)
|
|
$err = saveLog($dbconn, db_sql_text($dbconn, "DELETE FROM termin WHERE main_id = ?", array($id))." [$beschreibung]", "", "löschen");
|
|
return beendeSpeichern($dbconn, $err);
|
|
}
|
|
|
|
/* Markiert eine Terminreihe als erledigt ($erledigt = 1) oder offen (0) */
|
|
function setzeTerminErledigt($dbconn, $id, $erledigt)
|
|
{
|
|
$erledigt = $erledigt ? 1 : 0;
|
|
$vorhanden = db_wert($dbconn, "SELECT id FROM termin WHERE id = ?", array($id));
|
|
if($vorhanden === false)
|
|
return error("Fehler beim ermitteln des Termins:<br />".mysqli_error($dbconn));
|
|
if($vorhanden === null)
|
|
return error("Dieser Termin existiert nicht!");
|
|
|
|
beginneSpeichern($dbconn);
|
|
$err = 0;
|
|
$sql = "UPDATE termin SET done = ?, changetime = NOW(), changeuser = ? WHERE main_id = ? OR id = ?";
|
|
$params = array($erledigt, $_SESSION["user"], $id, $id);
|
|
db_abfrage($dbconn, $sql, $params)
|
|
or $err = error("Konnte den Termin nicht umstellen:<br />".mysqli_error($dbconn));
|
|
if(!$err)
|
|
$err = saveLog($dbconn, db_sql_text($dbconn, $sql, $params)." [termin erledigt]", "", "ändern");
|
|
return beendeSpeichern($dbconn, $err);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* Lesen
|
|
* ------------------------------------------------------------------ */
|
|
|
|
/*
|
|
* Der Termin für das Formular: die Reihe zu einer Hauptsatz-id wird zu
|
|
* einem Eintrag zusammengefasst, Anfang und Gesamtdauer eingeschlossen.
|
|
*/
|
|
function terminZumBearbeiten($dbconn, $id)
|
|
{
|
|
$res = db_zeile($dbconn, "SELECT MIN(termtime) AS termtime,
|
|
SEC_TO_TIME(SUM(TIME_TO_SEC(termdauer))) AS termdauer,
|
|
head, followed_by, MIN(id) AS id, main_id, typ, adresse_id,
|
|
done, user, user2, user3, user4, changeuser, act_date, text
|
|
FROM termin WHERE main_id = ? GROUP BY main_id", array($id));
|
|
if($res === false)
|
|
{
|
|
error("Fehler beim ermitteln des Termins:<br />".mysqli_error($dbconn));
|
|
return null;
|
|
}
|
|
if(!$res)
|
|
return null;
|
|
|
|
if($res["followed_by"] > 0)
|
|
{
|
|
$folge = db_zeile($dbconn, "SELECT DATE_FORMAT(act_date,'%Y-%m-%d') AS act_date, typ FROM termin WHERE id = ?",
|
|
array($res["followed_by"]));
|
|
if($folge)
|
|
{
|
|
$res["folgetyp"] = $folge["typ"];
|
|
$tage = (strtotime($folge["act_date"]) - strtotime(date("Y-m-d"))) / 86400;
|
|
if($tage > 0)
|
|
{
|
|
$res["folge"] = 1;
|
|
$res["folgedays"] = (int)$tage;
|
|
}
|
|
}
|
|
}
|
|
$res["termend"] = dauer_to_date($res["termtime"], $res["termdauer"]);
|
|
if(str_contains($res["termend"], "00:00:00"))
|
|
$res["termend"] = date("Y-m-d H:i:s", strtotime("-1 minutes", strtotime($res["termend"])));
|
|
return $res;
|
|
}
|
|
|
|
/* Die Auswahllisten des Terminformulars */
|
|
function terminAuswahllisten($dbconn, $smarty)
|
|
{
|
|
list($typids, $typs) = auswahlliste($dbconn, "SELECT id, typ FROM termtyp WHERE id > 0");
|
|
$smarty->assign("typids", $typids);
|
|
$smarty->assign("typs", $typs);
|
|
|
|
$benutzer = db_zeilen($dbconn, "SELECT id, vname, nname FROM user WHERE blocked = 0 AND id > 0 ORDER BY nname, vname");
|
|
$ids = array();
|
|
$namen = array();
|
|
foreach((array)$benutzer as $b)
|
|
{
|
|
$ids[] = $b["id"];
|
|
$namen[] = trim($b["vname"]." ".$b["nname"]);
|
|
}
|
|
$smarty->assign("userids", $ids);
|
|
$smarty->assign("users", $namen);
|
|
$ids[] = 0;
|
|
$namen[] = "Keiner";
|
|
$smarty->assign("optuserids", $ids);
|
|
$smarty->assign("optusers", $namen);
|
|
|
|
$smarty->assign("days", range(0, 40));
|
|
|
|
list($urlaubIds, $urlaubNamen) = auswahlliste($dbconn, "SELECT id, typ FROM termtyp WHERE typ = 'Urlaub' OR typ = 'Krankheit'");
|
|
$smarty->assign("vac_types_id", $urlaubIds);
|
|
$smarty->assign("vac_types_name", $urlaubNamen);
|
|
}
|
|
|
|
/* Die Adresse, an der ein Termin stattfindet - leer, wenn es keine gibt */
|
|
function terminAdresse($dbconn, $adressid)
|
|
{
|
|
$res = db_zeile($dbconn, "SELECT plz, ortsteil, ort, str, hnr, vname, partner_id, nname, vname2, nname2,
|
|
firma, adresse.id, land, anrede_id, titel_id, anrede2_id, titel2_id
|
|
FROM adresse
|
|
LEFT JOIN strasse ON str_id = strasse.id
|
|
LEFT JOIN ort ON ort_id = ort.id
|
|
LEFT JOIN land ON land_id = land.id
|
|
WHERE adresse.id = ?", array($adressid));
|
|
if($res === false)
|
|
{
|
|
error("Fehler beim abrufen der Daten:<br />".mysqli_error($dbconn));
|
|
return array();
|
|
}
|
|
return $res ? $res : array();
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* Kalender
|
|
* ------------------------------------------------------------------ */
|
|
|
|
/* Deutsche Wochentagsnamen - unabhängig davon, ob die Locale vorhanden ist */
|
|
function wochentag($zeitpunkt)
|
|
{
|
|
$namen = array("Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag");
|
|
return $namen[(int)date("w", $zeitpunkt)];
|
|
}
|
|
|
|
/*
|
|
* Die Termine eines Tages. $ganztags trennt die ganztägigen (Dauer über
|
|
* zwölf Stunden) von den übrigen.
|
|
*/
|
|
function kalenderTermine($dbconn, $tag, $ganztags)
|
|
{
|
|
$vergleich = $ganztags ? ">" : "<";
|
|
$sql = "SELECT termin.id, termtyp.typ, termin.head, termtime, termdauer,
|
|
user, user2, user3, user4, done, partner_id, main_id,
|
|
str, ort, ortsteil, plz, hnr, adresse.vname AS vname, adresse.nname AS nname,
|
|
user.vname AS uservname, user.nname AS usernname,
|
|
user2.vname AS uservname2, user2.nname AS usernname2,
|
|
user3.vname AS uservname3, user3.nname AS usernname3,
|
|
user4.vname AS uservname4, user4.nname AS usernname4,
|
|
firma, vname2, nname2
|
|
FROM termin
|
|
LEFT JOIN termtyp ON termin.typ = termtyp.id
|
|
LEFT JOIN adresse ON termin.adresse_id = adresse.id
|
|
LEFT JOIN partner ON adresse.partner_id = partner.id
|
|
LEFT JOIN strasse ON adresse.str_id = strasse.id
|
|
LEFT JOIN ort ON strasse.ort_id = ort.id
|
|
LEFT JOIN user ON termin.user = user.id
|
|
LEFT JOIN user AS user2 ON termin.user2 = user2.id
|
|
LEFT JOIN user AS user3 ON termin.user3 = user3.id
|
|
LEFT JOIN user AS user4 ON termin.user4 = user4.id
|
|
WHERE DATE(termtime) = ? AND termdauer $vergleich '12:00:00'
|
|
ORDER BY termtime ASC";
|
|
return db_zeilen($dbconn, $sql, array($tag)) ?: array();
|
|
}
|
|
|
|
/* Die an einem Tag gebuchten Arbeiten aus der Projektverwaltung */
|
|
function kalenderArbeiten($dbconn, $tag)
|
|
{
|
|
$sql = "SELECT work.id, project.id AS projectid, work.bezeichn AS head, work.rechn AS done,
|
|
project.name AS projectname, work.datetime AS termtime, work.std AS termdauer,
|
|
project.changeuser AS user, project.partner_id,
|
|
adresse.vname AS vname, adresse.nname AS nname, adresse.firma AS firma
|
|
FROM work
|
|
LEFT JOIN project ON work.project_id = project.id
|
|
LEFT JOIN partner ON project.partner_id = partner.id
|
|
LEFT JOIN adresse ON adresse.partner_id = partner.id
|
|
LEFT JOIN user ON work.changeuser = user.id
|
|
WHERE adresse.typ_id = 1 AND DATE(work.datetime) = ?
|
|
ORDER BY work.datetime ASC";
|
|
return db_zeilen($dbconn, $sql, array($tag)) ?: array();
|
|
}
|
|
|
|
/* Wer an einem Tag gestempelt hat und ob der Tag abgeschlossen ist */
|
|
function kalenderAnwesenheit($dbconn, $tag)
|
|
{
|
|
$sql = "SELECT user.vname, user.nname, user.color,
|
|
CASE MAX(zeiten.gehen) WHEN MAX(zeiten.kommen) THEN 0 ELSE 1 END AS complete
|
|
FROM user
|
|
LEFT JOIN zeiten ON user.id = zeiten.ma_id
|
|
WHERE DATE(kommen) = ?
|
|
GROUP BY user.id ORDER BY user.nname ASC";
|
|
return db_zeilen($dbconn, $sql, array($tag)) ?: array();
|
|
}
|
|
|
|
/*
|
|
* Die acht Tage einer Kalenderseite, beginnend einen Tag vor dem
|
|
* Seitenanfang (so ist der Vortag immer sichtbar).
|
|
*/
|
|
function kalenderTage($dbconn, $seite)
|
|
{
|
|
$heute = strtotime("today");
|
|
$tage = array();
|
|
for($i = $seite * 8 - 1; $i < $seite * 8 + 7; $i++)
|
|
{
|
|
$zeitpunkt = strtotime("+".$i." day", $heute);
|
|
$datum = date("Y-m-d", $zeitpunkt);
|
|
$feiertag = feiertag_bayern((int)date("d", $zeitpunkt), (int)date("m", $zeitpunkt), (int)date("Y", $zeitpunkt));
|
|
$termine = array();
|
|
if(($_SESSION["firma"] ?? "") == "Ingenieurbüro Wagner")
|
|
$termine = kalenderArbeiten($dbconn, $datum);
|
|
$termine = array_merge($termine, kalenderTermine($dbconn, $datum, false));
|
|
|
|
$tage[] = array(
|
|
// am Feiertag steht der Name des Feiertags statt des Wochentags
|
|
"weekday" => ($feiertag ? date("d.m.Y", $zeitpunkt)."<br/>" : wochentag($zeitpunkt)."<br/>".date("d.m.Y", $zeitpunkt)),
|
|
"date" => date("Ymd", $zeitpunkt),
|
|
"termine" => $termine,
|
|
"fulldaytermine" => kalenderTermine($dbconn, $datum, true),
|
|
"numfulldaytermine" => 0,
|
|
"ma_check" => kalenderAnwesenheit($dbconn, $datum),
|
|
"feiertag" => $feiertag ? $feiertag : "",
|
|
);
|
|
}
|
|
return $tage;
|
|
}
|
|
|
|
/* Die Mitarbeiter der Kalenderspalte samt Resturlaub */
|
|
function kalenderBenutzer($dbconn)
|
|
{
|
|
$users = array();
|
|
$zeilen = db_zeilen($dbconn, "SELECT id, vname, nname, color FROM user WHERE blocked = 0 AND nick != 'ALL'");
|
|
foreach((array)$zeilen as $res)
|
|
{
|
|
$res["openvacation"] = urlaub_remaining($dbconn, $res["id"]);
|
|
$users[$res["id"]] = $res;
|
|
}
|
|
return $users;
|
|
}
|
|
|
|
?>
|