Conflicts resolved

This commit is contained in:
Ivymaster
2026-06-15 12:47:29 +02:00
17 changed files with 679 additions and 127 deletions
+3 -1
View File
@@ -1,3 +1,5 @@
<?php
$config['send_update_mails'] = false;
$config['send_update_mails'] = false;
$config['calendar_start'] = 7;
$config['calendar_end'] = 23;
@@ -16,6 +16,7 @@ class Kalender extends FHCAPI_Controller
{
parent::__construct([
'getStunden' => self::PERM_LOGGED,
'getCalendarHours' => self::PERM_LOGGED,
'getPlan' => self::PERM_LOGGED,
'getPlanByOrt' => self::PERM_LOGGED,
'getRaumvorschlag' => self::PERM_LOGGED,
@@ -38,9 +39,11 @@ class Kalender extends FHCAPI_Controller
$this->_ci->load->library('LogLib');
$this->_ci->load->library('form_validation');
$this->_ci->load->library('KalenderLib');
$this->_ci->load->library('RaumvorschlagLib');
$this->loadPhrases([
'ui'
]);
$this->_ci->load->config('tempus');
$this->_ci->loglib->setConfigs(array(
@@ -71,6 +74,17 @@ class Kalender extends FHCAPI_Controller
$this->terminateWithSuccess($stunden);
}
public function getCalendarHours()
{
$calender_start = $this->_ci->config->item('calendar_start') ?? 7;
$calender_end = $this->_ci->config->item('calendar_end') ?? 23;
$this->terminateWithSuccess(array(
'start' => $calender_start,
'end' => $calender_end
));
}
public function getPlan()
{
$this->_ci->form_validation->set_data($_GET);
@@ -206,7 +220,7 @@ class Kalender extends FHCAPI_Controller
$result = $this->_ci->kalenderlib->updateKalenderEvent($kalender_id, $updateFields->ort_kurzbz ?? null, $updateFields->start_time ?? null, $updateFields->end_time ?? null);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithError(getError($result), $result->code);
$this->terminateWithSuccess(getData($result));
}
@@ -214,39 +228,9 @@ class Kalender extends FHCAPI_Controller
public function getRaumvorschlag()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('start_date',"start_date","required");
$this->_ci->form_validation->set_rules('end_date',"end_date","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$start_date = $this->_ci->input->get('start_date', TRUE);
$end_date = $this->_ci->input->get('end_date', TRUE);
$filter = $this->_checkFilter(self::ALLOWED_ROOM_FILTER);
if (isset($filter->lehreinheit_id))
{
$result = $this->_ci->kalenderlib->getRaumvorschlagByLehreinheitID(
$start_date,
$end_date,
$filter->lehreinheit_id
);
}
if (isset($filter->kalender_id))
{
$result = $this->_ci->kalenderlib->getRaumvorschlagByKalenderID(
$start_date,
$end_date,
$filter->kalender_id
);
}
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
$this->terminateWithSuccess($this->_ci->raumvorschlaglib->getVorschlaege($filter->kalender_id));
}
public function getHistory()
@@ -282,13 +266,13 @@ class Kalender extends FHCAPI_Controller
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess($result);
$this->terminateWithSuccess(getData($result));
}
public function sync()
{
$result = $this->_ci->kalenderlib->sync();
$this->terminateWithSuccess($result);
$this->terminateWithSuccess(getData($result));
}
public function syncToLecturer()
{
@@ -305,7 +289,7 @@ class Kalender extends FHCAPI_Controller
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess($result);
$this->terminateWithSuccess(getData($result));
}
public function syncToStudent()
{
@@ -322,7 +306,7 @@ class Kalender extends FHCAPI_Controller
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess($result);
$this->terminateWithSuccess(getData($result));
}
public function addKalenderEvent()
{
@@ -345,7 +329,7 @@ class Kalender extends FHCAPI_Controller
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess('Erfolgreich');
$this->terminateWithSuccess(getData($result));
}
public function addReservierung()
@@ -372,7 +356,7 @@ class Kalender extends FHCAPI_Controller
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess('Erfolgreich');
$this->terminateWithSuccess(getData($result));
}
private function _checkFilter($filters)
@@ -65,7 +65,7 @@ class Reservierung extends FHCAPI_Controller
$studiengaenge = $this->_ci->StudiengangModel->loadWhere(array('aktiv' => true));
if (isError($studiengaenge))
$this->terminateWithError($studiengaenge);
$this->terminateWithError(getError($studiengaenge));
$language = getUserLanguage() == 'German' ? 0 : 1;
$this->_ci->KalenderEventRolleModel->addOrder('sort');
$this->_ci->KalenderEventRolleModel->addSelect('rolle_kurzbz, array_to_json(bezeichnung_mehrsprachig::varchar[])->>'. $language. ' as bezeichnung');
@@ -193,7 +193,7 @@ class Reservierung extends FHCAPI_Controller
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess('Erfolgreich');
$this->terminateWithSuccess($result);
}
+1 -1
View File
@@ -40,7 +40,7 @@ class CollisionChecker
if (!empty($result))
{
$errors[] = $result;
$errors = array_merge($errors, $result);
}
}
+130 -57
View File
@@ -22,6 +22,7 @@ class KalenderLib
$this->_ci->load->model('organisation/Lehrverband_model', 'LehrverbandModel');
$this->_ci->load->library('CollisionChecker');
$this->_ci->load->library('PhrasesLib', array('ui'));
}
@@ -60,7 +61,27 @@ class KalenderLib
teilperson.vorname as teilnehmer_vorname,
teilperson.nachname as teilnehmer_nachname,
teilbenutzer.uid as teilnehmer_uid');
teilbenutzer.uid as teilnehmer_uid,
CASE
WHEN tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL THEN
COALESCE(
UPPER(le_studiengang.typ || le_studiengang.kurzbz) ||
COALESCE(tbl_lehreinheitgruppe.semester::varchar, \'\') ||
COALESCE(tbl_lehreinheitgruppe.verband::varchar, \'\') ||
COALESCE(tbl_lehreinheitgruppe.gruppe, \'\'),
\'\')
ELSE tbl_lehreinheitgruppe.gruppe_kurzbz
END AS lehreinheit_gruppe_bezeichnung,
tbl_lehreinheitgruppe.gruppe_kurzbz as le_gruppe_kurzbz,
tbl_lehreinheitgruppe.studiengang_kz as le_studiengang_kz,
tbl_lehreinheitgruppe.semester as le_semester,
tbl_lehreinheitgruppe.verband as le_verband,
tbl_lehreinheitgruppe.gruppe as le_gruppe,
le_gruppe.direktinskription as le_direktinskription,
');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'tbl_kalender.kalender_id = tbl_kalender_lehreinheit.kalender_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event', 'tbl_kalender.kalender_id = tbl_kalender_event.kalender_id', 'LEFT');
@@ -95,11 +116,22 @@ class KalenderLib
$this->_ci->KalenderModel->addJoin('public.tbl_benutzer resevierung_benutzer', 'reservierung_ma.mitarbeiter_uid = resevierung_benutzer.uid', 'LEFT');
$this->_ci->KalenderModel->addJoin('public.tbl_person reservierung_person', 'reservierung_person.person_id = resevierung_benutzer.person_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitgruppe', 'tbl_lehreinheit.lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('public.tbl_gruppe le_gruppe', 'tbl_lehreinheitgruppe.gruppe_kurzbz = le_gruppe.gruppe_kurzbz', 'LEFT');
$this->_ci->KalenderModel->addJoin('public.tbl_lehrverband le_lehrverband',
'tbl_lehreinheitgruppe.studiengang_kz = le_lehrverband.studiengang_kz
AND tbl_lehreinheitgruppe.semester = le_lehrverband.semester
AND TRIM(COALESCE(tbl_lehreinheitgruppe.verband::text, \'\')) = TRIM(le_lehrverband.verband::text)
AND TRIM(COALESCE(tbl_lehreinheitgruppe.gruppe::text, \'\')) = TRIM(le_lehrverband.gruppe::text)',
'LEFT'
);
$this->_ci->KalenderModel->addJoin('public.tbl_studiengang le_studiengang', 'le_lehrverband.studiengang_kz = le_studiengang.studiengang_kz', 'LEFT');
$this->_ci->KalenderModel->db->where('tbl_kalender.von >=', $start_date);
$this->_ci->KalenderModel->db->where('tbl_kalender.bis <', $end_date);
}
private function _mapEvents($data)
private function _mapEvents($data, $collisionCheck = true)
{
$stundenplan_data = [];
@@ -182,6 +214,22 @@ class KalenderLib
}
}
if ($row->lehreinheit_gruppe_bezeichnung)
{
if (!in_array($row->lehreinheit_gruppe_bezeichnung, array_column($events[$id]->gruppe, 'bezeichnung')))
{
$events[$id]->gruppe[] = [
'bezeichnung' => $row->lehreinheit_gruppe_bezeichnung,
'gruppe_kurzbz' => $row->le_gruppe_kurzbz,
'studiengang_kz' => $row->le_studiengang_kz,
'semester' => $row->le_semester,
'verband' => $row->le_verband,
'gruppe' => $row->le_gruppe,
'direktinskription' => $row->le_direktinskription,
];
}
}
if ($row->teilnehmer_uid)
{
if (!in_array($row->teilnehmer_uid, array_column($events[$id]->teilnehmer_person, 'uid')))
@@ -196,13 +244,16 @@ class KalenderLib
}
}
$kalender_ids = array_keys($events);
$collisions = $this->_ci->collisionchecker->runAll($kalender_ids);
foreach ($collisions as $kalender_id => $errors)
if ($collisionCheck)
{
if (isset($events[$kalender_id]))
$events[$kalender_id]->collisions = !empty($errors);
$kalender_ids = array_keys($events);
$collisions = $this->_ci->collisionchecker->runAll($kalender_ids);
foreach ($collisions as $kalender_id => $errors)
{
if (isset($events[$kalender_id]))
$events[$kalender_id]->collisions = !empty($errors);
}
}
return array_values($events);
@@ -217,66 +268,65 @@ class KalenderLib
return $this->_mapEvents($data);
}
public function getRaumvorschlagByLehreinheitID($start_date, $end_date, $lehreinheit_id)
public function getForRaumvorschlag($start_date, $end_date, $lektor_uids = [], $gruppen_kurzbz = [], $lehrverband_gruppen = [])
{
$start_date = date('Y-m-d', strtotime($start_date));
$end_date = date('Y-m-d', strtotime($end_date . ' +1 day'));
$lehreinheit = $this->_ci->LehreinheitModel->load(array('lehreinheit_id' => $lehreinheit_id));
if (isError($lehreinheit))
return $lehreinheit;
$this->_getBasePlan($start_date, $end_date);
if (!hasData($lehreinheit))
return error("Not found");
$this->_ci->KalenderModel->db->where('NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender nachfolger
WHERE nachfolger.vorgaenger_kalender_id = tbl_kalender.kalender_id)', null, false);
$lehreinheit = getData($lehreinheit)[0];
$this->_ci->KalenderModel->db->where_not_in('status_kurzbz', ['deleted']);
$this->_ci->KalenderModel->addDistinct('ort_kurzbz');
$this->_ci->KalenderModel->addSelect('ort_kurzbz');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'kalender_id');
$this->_ci->KalenderModel->db->where('tbl_kalender.von >=', $start_date);
$this->_ci->KalenderModel->db->where('tbl_kalender.bis <', $end_date);
$belegte_raeume = $this->_ci->KalenderModel->load();
if (isError($belegte_raeume))
return $belegte_raeume;
$belegte_orte = hasData($belegte_raeume) ? array_column(getData($belegte_raeume), 'ort_kurzbz') : [];
$vorschlaege = $this->_getFreieRaeume($lehreinheit->raumtyp, $belegte_orte);
if (isError($vorschlaege))
return $vorschlaege;
$vorschlaege = hasData($vorschlaege) ? getData($vorschlaege) : [];
if (count($vorschlaege) < 5 && !empty($lehreinheit->raumtypalternativ))
if (!empty($lektor_uids) || !empty($gruppen_kurzbz) || !empty($lehrverband_gruppen))
{
$bereits_gefunden = array_merge($belegte_orte, array_column($vorschlaege, 'ort_kurzbz'));
$this->_ci->KalenderModel->db->group_start();
$alternativ_raeume = $this->_getFreieRaeume($lehreinheit->raumtypalternativ, $bereits_gefunden);
if (!empty($lektor_uids))
$this->_ci->KalenderModel->db->where_in('tbl_lehreinheitmitarbeiter.mitarbeiter_uid', $lektor_uids);
if (!isError($alternativ_raeume) && hasData($alternativ_raeume))
$vorschlaege = array_merge($vorschlaege, getData($alternativ_raeume));
if (!empty($gruppen_kurzbz))
$this->_ci->KalenderModel->db->or_where_in('tbl_lehreinheitgruppe.gruppe_kurzbz', $gruppen_kurzbz);
foreach ($lehrverband_gruppen as $lvg)
{
$this->_ci->KalenderModel->db->or_group_start();
$this->_ci->KalenderModel->db->where('tbl_lehreinheitgruppe.studiengang_kz', $lvg['studiengang_kz']);
$this->_ci->KalenderModel->db->where('tbl_lehreinheitgruppe.semester', $lvg['semester']);
$this->_ci->KalenderModel->db->where('tbl_lehreinheitgruppe.verband', $lvg['verband']);
$this->_ci->KalenderModel->db->where('tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL', null, false);
$this->_ci->KalenderModel->db->group_end();
}
$this->_ci->KalenderModel->db->group_end();
}
return success($vorschlaege);
$data = $this->_ci->KalenderModel->load();
return $this->_mapEvents($data, false);
}
private function _getFreieRaeume($raumtyp, $belegte_orte)
public function getByKalenderId($kalender_id)
{
$this->_ci->OrtModel->addSelect('ort_kurzbz');
$this->_ci->OrtModel->addJoin('public.tbl_ortraumtyp', 'ort_kurzbz');
$this->_ci->OrtModel->db->where('raumtyp_kurzbz', $raumtyp);
$this->_ci->OrtModel->db->where('aktiv', true);
$this->_ci->OrtModel->db->where("ort_kurzbz NOT LIKE '\_%'", null, false);
$kalender_entry = $this->_ci->KalenderModel->load($kalender_id);
if (isError($kalender_entry))
return $kalender_entry;
if (!empty($belegte_orte))
$this->_ci->OrtModel->db->where_not_in('ort_kurzbz', $belegte_orte);
$this->_ci->OrtModel->addOrder('hierarchie, ort_kurzbz');
if (!hasData($kalender_entry))
return error('');
return $this->_ci->OrtModel->load();
$kalender_entry = getData($kalender_entry)[0];
$this->_getBasePlan($kalender_entry->von, $kalender_entry->bis);
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id', $kalender_entry->kalender_id);
$data = $this->_ci->KalenderModel->load();
return $this->_mapEvents($data);
}
public function getPlanForPlanner($start_date, $end_date, $ort = null, $uids = null, $stg = null)
{
$this->_getBasePlan($start_date, $end_date);
@@ -510,7 +560,13 @@ class KalenderLib
));
if (hasData($reservierung_vorhanden) && !$this->_ci->permissionlib->isBerechtigt('lehre/reservierungAdvanced'))
return error ('lvplan/bereitsReserviert');
{
return error([
'message' => $this->_ci->phraseslib->t('ui', 'already_reserved'),
'errorCode' => 'already_reserved'
]);
}
}
$this->_ci->KalenderModel->db->trans_start();
@@ -732,7 +788,12 @@ class KalenderLib
if ($kalender_entry->typ === 'lehreinheit')
{
if (in_array($kalender_entry->status_kurzbz, array('todelete', 'deleted')))
return error('Eintrag kann nicht mehr bearbeitet werden');
{
return error([
'message' => $this->_ci->phraseslib->t('ui', 'entry_not_editable'),
'errorCode' => 'entry_not_editable'
]);
}
if (in_array($kalender_entry->status_kurzbz, array('live', 'preview')))
return $this->_createHistoryEntry($kalender_entry, $start_date, $end_date);
@@ -759,7 +820,12 @@ class KalenderLib
if ($kalender_entry->typ === 'lehreinheit')
{
if (in_array($kalender_entry->status_kurzbz, array('todelete', 'deleted')))
return error('Eintrag kann nicht mehr bearbeitet werden');
{
return error([
'message' => $this->_ci->phraseslib->t('ui', 'entry_not_editable'),
'errorCode' => 'entry_not_editable'
]);
}
if (in_array($kalender_entry->status_kurzbz, array('live', 'preview')))
return $this->_createHistoryEntry($kalender_entry, null, null, $ort_kurzbz);
@@ -794,7 +860,12 @@ class KalenderLib
);
if (!isset($allowed[$kalender_entry->status_kurzbz]) || !in_array($status_kurzbz, $allowed[$kalender_entry->status_kurzbz]))
return error('Statuswechsel nicht erlaubt');
{
return error([
'message' => $this->_ci->phraseslib->t('ui', 'status_change_not_allowed'),
'errorCode' => 'status_change_not_allowed'
]);
}
$result = $this->_ci->KalenderModel->update(
array('kalender_id' => $kalender_entry->kalender_id),
@@ -864,7 +935,8 @@ class KalenderLib
$result = $this->_ci->KalenderModel->load(array('tbl_kalender.kalender_id' => $kalender_id));
if (isError($result)) return $result;
if (!hasData($result)) return error("Not found");
if (!hasData($result))
return error(['message' => 'Not found', 'errorCode' => 'not_found']);
return success(getData($result)[0]);
}
@@ -877,7 +949,8 @@ class KalenderLib
if (isError($result)) return $result;
if (!hasData($result)) return error("Not found");
if (!hasData($result))
return error(['message' => 'Not found', 'errorCode' => 'not_found']);
$entry = getData($result)[0];
+242
View File
@@ -0,0 +1,242 @@
<?php
if (! defined("BASEPATH")) exit("No direct script access allowed");
use CI3_Events as Events;
class RaumvorschlagLib
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->model('ressource/Kalender_Lehreinheit_model', 'KalenderLehreinheitModel');
$this->_ci->load->model('ressource/Kalender_Event_model', 'KalenderEventModel');
$this->_ci->load->model('ressource/Kalender_Event_Teilnehmer_model', 'KalenderEventTeilnehmerModel');
$this->_ci->load->model('ressource/Kalender_Ort_model', 'KalenderOrtModel');
$this->_ci->load->model('education/Lehreinheit_model', 'LehreinheitModel');
$this->_ci->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel');
$this->_ci->load->model('education/LehreinheitMitarbeiter_model', 'LehreinheitMitarbeiterModel');
$this->_ci->load->model('ressource/Ort_model', 'OrtModel');
$this->_ci->load->model('organisation/gruppe_model', 'GruppeModel');
$this->_ci->load->model('organisation/Lehrverband_model', 'LehrverbandModel');
$this->_ci->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel');
$this->_ci->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel');
$this->_ci->load->library('CollisionChecker');
$this->_ci->load->library('KalenderLib');
$this->_ci->load->library('PhrasesLib', array('ui'));
}
public function getVorschlaege($kalender_id)
{
$event = $this->_ci->kalenderlib->getByKalenderId($kalender_id);
$event = $event[0];
$lektor_uids = array_column($event->lektor, 'mitarbeiter_uid');
$gruppen_kurzbz = array_values(array_filter(array_column($event->gruppe, 'gruppe_kurzbz')));
$lehrverband_gruppen = array_values(array_filter($event->gruppe, function($gruppe)
{
return empty($gruppe['gruppe_kurzbz']);
}));
$tages_events = $this->_ci->kalenderlib->getForRaumvorschlag(
$event->datum,
$event->datum,
$lektor_uids,
$gruppen_kurzbz,
$lehrverband_gruppen
);
$lektor_davor = $this->_getEventDavor($tages_events, $event->isostart, $lektor_uids, 'lektor');
$gruppen_davor = $this->_getEventDavor($tages_events, $event->isostart, $gruppen_kurzbz, 'gruppe');
$lektor_davor_ort = $lektor_davor ? $this->_getOrtDetails($lektor_davor->ort_kurzbz) : null;
$gruppen_davor_ort = $gruppen_davor ? $this->_getOrtDetails($gruppen_davor->ort_kurzbz) : null;
$kandidaten = $this->_getRaumkandidaten($event);
if (empty($kandidaten)) return [];
$ratings = [];
foreach ($kandidaten as $raum)
{
$rating = ['ort_kurzbz' => $raum->ort_kurzbz, 'score' => 100, 'details' => []];
$this->_rateLektor($rating, $raum, $lektor_davor_ort);
$this->_rateGruppen($rating, $raum, $gruppen_davor_ort);
Events::trigger('room_rating',
function & () use (&$rating) {
return $rating;
},
$raum,
$event
);
$ratings[] = $rating;
}
usort($ratings, function($a, $b)
{
return $b['score'] - $a['score'];
});
return $ratings;
}
private function _getOrtDetails($ort_kurzbz)
{
$this->_ci->OrtModel->addSelect('ort_kurzbz, stockwerk, standort_id');
$this->_ci->OrtModel->db->where('ort_kurzbz', $ort_kurzbz);
$result = $this->_ci->OrtModel->load();
return hasData($result) ? getData($result)[0] : null;
}
private function _rateLektor(&$rating, $raum, $lektor_davor_ort)
{
if (!$lektor_davor_ort) return;
if ($lektor_davor_ort->ort_kurzbz === $raum->ort_kurzbz)
{
$rating['score'] += 20;
$rating['details'][] = '+20 ' . $this->_ci->phraseslib->t('ui', 'lecturer_already_here');
return;
}
if ($lektor_davor_ort->standort_id !== $raum->standort_id)
{
$rating['score'] -= 20;
$rating['details'][] = '-20 '. $this->_ci->phraseslib->t('ui', 'lecturer_building_change');
}
elseif ($lektor_davor_ort->stockwerk !== $raum->stockwerk)
{
$diff = abs($lektor_davor_ort->stockwerk - $raum->stockwerk);
$rating['score'] -= $diff * 5;
$rating['details'][] = '-' . ($diff * 5) . ' ' . $this->_ci->phraseslib->t('ui', 'lecturer_floor_change');
}
}
private function _rateGruppen(&$rating, $raum, $gruppen_davor_ort)
{
if (!$gruppen_davor_ort) return;
if ($gruppen_davor_ort->ort_kurzbz === $raum->ort_kurzbz)
{
$rating['score'] += 10;
$rating['details'][] = '+10 ' . $this->_ci->phraseslib->t('ui', 'student_already_here');
return;
}
if ($gruppen_davor_ort->standort_id !== $raum->standort_id)
{
$rating['score'] -= 20;
$rating['details'][] = '-20 '. $this->_ci->phraseslib->t('ui', 'student_building_change');
}
elseif ($gruppen_davor_ort->stockwerk !== $raum->stockwerk)
{
$diff = abs($gruppen_davor_ort->stockwerk - $raum->stockwerk);
$rating['score'] -= $diff * 5;
$rating['details'][] = '-' . ($diff * 5) . ' '. $this->_ci->phraseslib->t('ui', 'student_floor_change');
}
}
private function _getEventDavor($events, $von, $uids, $type)
{
$kandidat = null;
foreach ($events as $event)
{
if ($event->isoend > $von)
continue;
//Wenn zwischen zwei Events eine 30+ Minuten Pause liegt, wird das Event davor nicht berücksichtigt
if ((strtotime($von) - strtotime($event->isoend)) > 30 * 60)
continue;
if (empty($event->ort_kurzbz))
continue;
if ($type === 'lektor')
$event_uids = array_column($event->lektor, 'mitarbeiter_uid');
else
$event_uids = array_column($event->gruppe, 'gruppe_kurzbz');
if (empty(array_intersect($event_uids, $uids)))
continue;
if ($kandidat === null || $event->isoend > $kandidat->isoend)
$kandidat = $event;
}
return $kandidat;
}
private function _getRaumkandidaten($event)
{
$lehreinheit = $this->_ci->LehreinheitModel->load($event->lehreinheit_id[0]);
if (!hasData($lehreinheit)) return [];
$lehreinheit = getData($lehreinheit)[0];
$this->_ci->KalenderModel->addSelect('tbl_kalender_ort.ort_kurzbz');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'tbl_kalender.kalender_id = tbl_kalender_ort.kalender_id');
$this->_ci->KalenderModel->db->where('tbl_kalender.von <', $event->isoend);
$this->_ci->KalenderModel->db->where('tbl_kalender.bis >', $event->isostart);
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', ['deleted']);
$this->_ci->KalenderModel->db->where('tbl_kalender_ort.ort_kurzbz IS NOT NULL', null, false);
$belegte = $this->_ci->KalenderModel->load();
$belegte_orte = hasData($belegte) ? array_column(getData($belegte), 'ort_kurzbz') : [];
if (empty($lehreinheit->raumtyp))
{
$raeume = $this->_getFreieRaeume(null, $belegte_orte);
return hasData($raeume) ? getData($raeume) : [];
}
$vorschlaege = [];
$raeume = $this->_getFreieRaeume($lehreinheit->raumtyp, $belegte_orte);
if (hasData($raeume))
$vorschlaege = getData($raeume);
if (count($vorschlaege) < 5 && !empty($lehreinheit->raumtypalternativ))
{
$bereits_gefunden = array_merge($belegte_orte, array_column($vorschlaege, 'ort_kurzbz'));
$alternativ = $this->_getFreieRaeume($lehreinheit->raumtypalternativ, $bereits_gefunden);
if (!isError($alternativ) && hasData($alternativ))
$vorschlaege = array_merge($vorschlaege, getData($alternativ));
}
return $vorschlaege;
}
private function _getFreieRaeume($raumtyp, $belegte_orte)
{
$this->_ci->OrtModel->addSelect('ort_kurzbz, stockwerk, standort_id');
$this->_ci->OrtModel->addJoin('public.tbl_ortraumtyp', 'ort_kurzbz');
$this->_ci->OrtModel->db->where('raumtyp_kurzbz', $raumtyp);
$this->_ci->OrtModel->db->where('aktiv', true);
$this->_ci->OrtModel->db->where("ort_kurzbz NOT LIKE '\_%'", null, false);
if (!empty($belegte_orte))
$this->_ci->OrtModel->db->where_not_in('ort_kurzbz', $belegte_orte);
$this->_ci->OrtModel->addOrder('hierarchie, ort_kurzbz');
return $this->_ci->OrtModel->load();
}
}
@@ -67,8 +67,12 @@ class LectureCollisionCheck implements ICollisionCheck
);
$result = $this->_ci->KalenderModel->load();
if (!isError($result) && hasData($result))
{
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
}
$this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit current_kalender_le', 'current_kalender_le.kalender_id = tbl_kalender.kalender_id');
@@ -90,8 +94,12 @@ class LectureCollisionCheck implements ICollisionCheck
);
$result = $this->_ci->KalenderModel->load();
if (!isError($result) && hasData($result))
{
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
}
$this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit current_kalender_le', 'current_kalender_le.kalender_id = tbl_kalender.kalender_id');
@@ -111,9 +119,12 @@ class LectureCollisionCheck implements ICollisionCheck
if (!isError($result) && hasData($result))
{
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
}
return $grouped;
}
@@ -174,8 +185,12 @@ class LectureCollisionCheck implements ICollisionCheck
if (isError($result) || !hasData($result)) return [];
return array_map(function($row) {
return $this->_ci->phraseslib->t('ui', 'ma_le_kollision') . ': ' . $row->mitarbeiter_uid . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')';
return array_map(function($row)
{
return [
'message' => $this->_ci->phraseslib->t('ui', 'ma_le_kollision') . ': ' . $row->mitarbeiter_uid . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')',
'errorCode' => 'lector_collision',
];
}, getData($result));
}
@@ -206,8 +221,12 @@ class LectureCollisionCheck implements ICollisionCheck
if (isError($result) || !hasData($result)) return [];
return array_map(function($row) {
return $this->_ci->phraseslib->t('ui', 'reservierung_kollision') . ': ' . $row->uid . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')';
return array_map(function($row)
{
return [
'message' => $this->_ci->phraseslib->t('ui', 'reservierung_kollision') . ': ' . $row->uid . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')',
'errorCode' => 'reservation_collision',
];
}, getData($result));
}
@@ -227,8 +246,13 @@ class LectureCollisionCheck implements ICollisionCheck
if (isError($result) || !hasData($result)) return [];
return array_map(function($row) {
return $this->_ci->phraseslib->t('ui', 'ma_zeitsperre_kollision') . ': ' . $row->mitarbeiter_uid . ' (' . date('d.m.Y H:i', strtotime($row->vondatum . ' ' . $row->von_beginn)) . ' - ' . date('d.m.Y H:i', strtotime($row->bisdatum . ' ' . $row->bis_ende)) . ')'; }, getData($result));
return array_map(function($row)
{
return [
'message' => $this->_ci->phraseslib->t('ui', 'ma_zeitsperre_kollision') . ': ' . $row->mitarbeiter_uid . ' (' . date('d.m.Y H:i', strtotime($row->vondatum . ' ' . $row->von_beginn)) . ' - ' . date('d.m.Y H:i', strtotime($row->bisdatum . ' ' . $row->bis_ende)) . ')',
'errorCode' => 'absences_collision',
];
}, getData($result));
}
}
@@ -42,7 +42,10 @@ class RoomCollisionCheck implements ICollisionCheck
return array_map(function($row)
{
return $this->_ci->phraseslib->t('ui', 'raum_kollision') . ': ' . $row->ort_kurzbz . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')';
return [
'errorCode' => 'room_collision',
'message' => $this->_ci->phraseslib->t('ui', 'raum_kollision') . ': ' . $row->ort_kurzbz . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'
];
}, getData($result));
}
@@ -68,7 +71,9 @@ class RoomCollisionCheck implements ICollisionCheck
$grouped = [];
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
return $grouped;
}
@@ -130,12 +130,19 @@ class StudentCollisionCheck implements ICollisionCheck
if (isError($result2) || !hasData($result2)) return [];
$conflicts = [];
foreach (getData($result2) as $row) {
if (isset($curUids[$row->uid])) {
$conflicts[] = $this->_ci->phraseslib->t('ui', 'student_kollision')
. ': ' . $row->uid
. ' (' . date('d.m.Y H:i', strtotime($row->von))
. ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')';
foreach (getData($result2) as $row)
{
if (isset($curUids[$row->uid]))
{
$conflicts[] = [
'message' =>
$this->_ci->phraseslib->t('ui', 'student_kollision')
. ': ' . $row->uid
. ' (' . date('d.m.Y H:i', strtotime($row->von))
. ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')',
'errorCode' => 'student_collision'
];
}
}
@@ -231,7 +238,9 @@ class StudentCollisionCheck implements ICollisionCheck
$grouped = [];
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
return $grouped;
}
@@ -145,7 +145,12 @@ class VerbandCollisionCheck implements ICollisionCheck
if (!isError($result) && hasData($result))
{
foreach (getData($result) as $row)
$collisions[] = $this->_ci->phraseslib->t('ui', 'verband_kollision') . ': ' . $row->gruppenname . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')';
{
$collisions[] = [
'message' => $this->_ci->phraseslib->t('ui', 'verband_kollision') . ': ' . $row->gruppenname . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')',
'errorCode' => 'verband_collision',
];
}
}
}
@@ -236,7 +241,12 @@ class VerbandCollisionCheck implements ICollisionCheck
if (!isError($result) && hasData($result))
{
foreach (getData($result) as $row)
$collisions[] = $this->_ci->phraseslib->t('ui', 'reservierung_kollision') . ': ' . $row->gruppenname . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')';
{
$collisions[] = [
'errorCode' => 'reservation_collision',
'message' => $this->_ci->phraseslib->t('ui', 'reservierung_kollision') . ': ' . $row->gruppenname . ' (' . date('d.m.Y H:i', strtotime($row->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')'
];
}
}
}
@@ -342,7 +352,9 @@ class VerbandCollisionCheck implements ICollisionCheck
$grouped = [];
foreach (getData($result) as $row)
{
$grouped[$row->kalender_id][] = true;
}
return $grouped;
}
+8 -2
View File
@@ -68,6 +68,12 @@ export default {
url: '/api/frontend/v1/tempus/Kalender/getStunden',
};
},
getCalendarHours() {
return {
method: 'get',
url: '/api/frontend/v1/tempus/Kalender/getCalendarHours',
};
},
updateKalenderEvent(kalender_id, updatedInfos) {
return {
method: 'post',
@@ -82,11 +88,11 @@ export default {
params: { lehreinheit_id, ort_kurzbz, start_date, end_date}
};
},
getRaumvorschlag(start_date, end_date, lehreinheit_id) {
getRaumvorschlag(kalender_id) {
return {
method: 'get',
url: '/api/frontend/v1/tempus/Kalender/getRaumvorschlag',
params: { start_date, end_date, lehreinheit_id}
params: { kalender_id }
};
},
+2 -1
View File
@@ -37,7 +37,8 @@ app
.use(router)
.use(primevue.config.default, {
zIndex: {
overlay: 1100
overlay: 1100,
tooltip: 99999
}
})
.use(Phrasen)
+2
View File
@@ -29,6 +29,7 @@ export default {
locale: Vue.computed(() => this.locale),
timezone: Vue.computed(() => this.timezone),
timeGrid: Vue.computed(() => this.timeGrid),
hoursPlan: Vue.computed(() => this.hoursPlan),
draggableEvents: Vue.computed(() => {
if (!this.draggableEvents)
return () => false;
@@ -118,6 +119,7 @@ export default {
default: undefined
},
timeGrid: Array,
hoursPlan: Object,
draggableEvents: [Boolean, Array, Function],
dropableEvents: [Boolean, Array, Function],
resizableEvents: [Boolean, Array, Function],
@@ -13,7 +13,8 @@ export default {
},
inject: {
timeGrid: "timeGrid",
timezone: "timezone"
timezone: "timezone",
hoursPlan: { from: "hoursPlan", default: null },
},
props: {
day: {
@@ -39,8 +40,9 @@ export default {
};
});
} else {
// create 07:00-23:00
return Array.from({ length: 17 }, (e, i) => luxon.Duration.fromObject({ hours: i + 7 }));
const start = this.hoursPlan?.start ?? 7;
const end = this.hoursPlan?.end ?? 23;
return Array.from({ length: end - start + 1 }, (e, i) => luxon.Duration.fromObject({ hours: i + start }));
}
}
},
+11
View File
@@ -86,6 +86,7 @@ export default {
},
currentMode: this.mode,
teachingunits: null,
hoursplan: null,
showRaster: true,
};
},
@@ -184,6 +185,15 @@ export default {
end: el.ende
}));
});
this.$api
.call(ApiKalender.getCalendarHours())
.then(res => {
this.hoursplan = {
start: res.data.start,
end: res.data.end
};
});
},
template: /* html */`
<fhc-calendar
@@ -198,6 +208,7 @@ export default {
:events="visibleEvents || []"
:backgrounds="backgrounds"
:time-grid="showRaster ? teachingunits : null"
:hours-plan="hoursplan"
show-btns
:draggable-events="true"
:resizable-events="true"
+5 -6
View File
@@ -217,14 +217,12 @@ export default {
},
methods: {
async openRaumauswahl(orig) {
if (!orig?.lehreinheit_id)
if (!orig?.kalender_id)
return;
this.raumModal = orig;
await this.$api.call(ApiKalender.getRaumvorschlag(
orig.isostart,
orig.isoend,
orig.lehreinheit_id[0]
orig.kalender_id
)).then(result => {
this.raumVorschlaege = result.data ?? [];
@@ -956,11 +954,12 @@ export default {
<li
v-for="raum in raumVorschlaege"
:key="raum.ort_kurzbz"
class="list-group-item list-group-item-action"
class="list-group-item list-group-item-action d-flex justify-content-between align-items-center"
style="cursor:pointer"
@click="selectRaum(raum.ort_kurzbz)"
>
<i class="fa-solid fa-door-open me-2"></i>{{ raum.ort_kurzbz }}
<span><i class="fa-solid fa-door-open me-2"></i>{{ raum.ort_kurzbz }}</span>
<span class="text-muted" v-tooltip="{ value: raum.details.join('\\n'), class: 'custom-tooltip' }">{{ raum.score }}</span>
</li>
</ul>
<p v-else class="text-muted mb-0">Keine freien Räume gefunden.</p>
+180
View File
@@ -47708,6 +47708,186 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'status_change_not_allowed',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Statuswechsel nicht erlaubt',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Status change not allowed',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'already_reserved',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Bereits reserviert',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Already reserved',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'entry_not_editable',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Eintrag kann nicht mehr bearbeitet werden',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Entry can no longer be edited',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'lecturer_already_here',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'LektorIn bereits hier',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Lecturer already here',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'student_already_here',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Studierende bereits hier',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Students already here',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'lecturer_building_change',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Gebäudewechsel LektorIn',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Building change lecturer',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'student_building_change',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Gebäudewechsel Studierende',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Building change students',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'lecturer_floor_change',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Stockwerkwechsel LektorIn',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Floor change lecturer',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'student_floor_change',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Stockwerkwechsel Studierende',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Floor change students',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'abschlusspruefung',