Compare commits

..

77 Commits

Author SHA1 Message Date
Harald Bamberger 862bdd94d7 add endpoints getRoomsWithEmployeesAssigned and getEmployeesWithRoomAssigned 2026-05-12 11:22:57 +02:00
Harald Bamberger bbb4f8a01c Merge branch 'bug-76146/studvw_karteireiter_dokumente_akzeptiert_eintraege_ohne_vorhandenes_dokument' 2026-05-06 16:13:50 +02:00
Harald Bamberger fdbb93a5c5 bugfix download booking receipt failed. only fetch oehbeitrag from bis.tbl_oehbeitrag if a user is logged in 2026-05-05 14:36:07 +02:00
Harald Bamberger b7e48633ab Merge branch 'master' into bug-76146/studvw_karteireiter_dokumente_akzeptiert_eintraege_ohne_vorhandenes_dokument 2026-05-05 13:33:38 +02:00
Harald Bamberger 04dc1eb07b Merge branch 'bug-76519/StudVW_Messages_Table_column_Stati' 2026-05-05 13:04:58 +02:00
Harald Bamberger 50b229090b prefetch phrases and then render filter component instead of redrawing the table 2026-05-05 13:04:11 +02:00
Harald Bamberger 2d27a998c4 Merge branch 'bug-76109/VVW_Details_und_Status_not_Loading' 2026-05-05 11:17:49 +02:00
Harald Bamberger 090e535466 add header filters, increase height of tables, use correct category for phrase lehreinheit_id 2026-05-05 11:04:48 +02:00
Harald Bamberger c4d35181db Merge branch 'master' into bug-76109/VVW_Details_und_Status_not_Loading 2026-05-05 09:01:49 +02:00
Harald Bamberger 0ac6ef4599 Merge branch 'feature-62607/konto_oh_beitrag_betrag_aus_eigener_tabelle' 2026-05-05 08:46:22 +02:00
Harald Bamberger cb60ddcc94 Merge branch 'master' into feature-62607/konto_oh_beitrag_betrag_aus_eigener_tabelle 2026-05-04 15:41:52 +02:00
Harald Bamberger bd4ced9559 bugfix: comma as decimal separator prevents saving booking, bugfix messages tinymce not resizeable 2026-05-04 14:39:19 +02:00
Andreas Österreicher a04d2acb86 Fixed Blank on Phrase for Abgabetool 2026-05-04 10:49:33 +02:00
Harald Bamberger de2aabf00b readd dokument preview link to api response 2026-05-04 09:30:16 +02:00
ma0068 685fc69e5d update css and add provisional height 2026-04-30 18:02:38 +02:00
Andreas Österreicher 552faefa51 Merge branch 'feature-76108/microdegree_abschlussurkunde' 2026-04-27 08:55:08 +02:00
Harald Bamberger 954397f028 Merge branch 'feature-70376/Lohnguide' 2026-04-22 18:52:51 +02:00
Harald Bamberger 80faa61c91 Merge branch 'master' into feature-70376/Lohnguide 2026-04-22 18:46:57 +02:00
Werner Masik 961ede66a9 lohnguide db update changed 2026-04-22 18:40:22 +02:00
Andreas Österreicher 6fec8382b5 Merge branch 'feature-76554/Personalmeldung_alt_bei_Lehre_nicht_melderelevant_rausfiltern' 2026-04-22 09:15:23 +02:00
Andreas Österreicher 4eb076d115 Fixed Saving of Entwicklungsteam 2026-04-21 17:34:36 +02:00
Harald Bamberger 7427aa87ea Merge branch 'feature-76545/findAbgabenNewOrUpdatedSinceByAbgabedatumFixTimestampDateComparison' 2026-04-21 17:01:04 +02:00
Johann Hoffmann 85043e57db added missing parenthesis 2026-04-21 17:00:07 +02:00
Johann Hoffmann 5beddbccb4 changed the where clause to a simpler = CURRENT_DATE comparison -> works the same if the job runs daily and fetches updates of one day/date; has to be changed back in case we want to find updates in a range larger than 1 day in an interval larger than 1 day; 2026-04-21 14:18:45 +02:00
kindlm e2ae9b88c8 Merge remote-tracking branch 'origin/master' 2026-04-21 12:56:30 +02:00
kindlm ca3abf9154 Small Style-Fix in Testtool
To make headings stand out more clearly from the buttons
2026-04-21 12:56:02 +02:00
Alexei Karpenko f863c6d728 personalmeldung legacy system: melderelevant is checked for lehre, bugfix: lehre is correctly added if studiengang already has sws 2026-04-20 18:24:30 +02:00
Harald Bamberger 92a2053b42 Merge branch 'feature-40870/BUG_Studstatus_unpause_order_should_be_DESC' 2026-04-20 17:30:14 +02:00
kindlm 70602be54e SaveSort und Filter-Reset in RaumÜbersicht 2026-04-20 11:30:17 +02:00
kindlm dac71f597a Spalte Anmeldedatum in RT-Übersicht
Spalte Frage_ID in RT-Administration
JQuery und Tabelsorter aus Include in Service_Uebersicht
2026-04-20 11:24:59 +02:00
Johann Hoffmann 3a646ffe77 adapt AbgabeJob relevant queries so they compare with the pgsql date function CURRENT_DATE instead of NOW() to avoid the cutoff from uploads the happened "yesterday but more than 24 hours ago"; also added another "abgabedatum < CURRENT_DATE" condition, to avoid sending this exact case as updates 2 days in a row; 2026-04-20 11:06:06 +02:00
ma0068 26db4a5e7a adding redraw tabulator and fallback to avoid empty column 2026-04-20 09:31:52 +02:00
Harald Bamberger 98a10a2f55 Merge branch 'feature-69389/AbmeldungSTGL_Anzeige_mit_Studiengangskuerzel' 2026-04-17 12:37:49 +02:00
Harald Bamberger e48b94b858 studiengangskuerzel statt kurzbzlang 2026-04-17 12:35:55 +02:00
Andreas Österreicher 0ff29ba6af Merge branch 'epic-56039/LV-Evaluierung' 2026-04-16 13:22:40 +02:00
Harald Bamberger ba543448ae Merge branch 'bug-76260/StudVW_Messages_TinyMCE_Cursor_Jumping_TextInput' 2026-04-16 11:26:32 +02:00
Harald Bamberger f121f9b5a2 deactivate pagination - since potentially msg threads are not shown completely 2026-04-16 11:23:57 +02:00
Harald Bamberger 88b22f5490 revert to v-if to not render element when not necessary and use Vue.nextTick for dependent code 2026-04-15 17:02:58 +02:00
Harald Bamberger 4b7ee9abe1 Merge branch 'feature-70376/Lohnguide' 2026-04-15 15:52:12 +02:00
Cristina d499619cf3 Added phrase endedatumMussInZukunftLiegen 2026-04-15 13:39:06 +02:00
Cristina f489153ff3 Merge branch 'master' into epic-56039/LV-Evaluierung 2026-04-15 12:25:05 +02:00
Cristina 9b79a07fa2 Merge branch 'master' of https://github.com/FH-Complete/FHC-Core 2026-04-15 12:24:44 +02:00
Harald Bamberger 6ce14a25d7 Merge branch 'master' into feature-70376/Lohnguide 2026-04-15 11:49:26 +02:00
Werner Masik c701d92779 fix db_update 2026-04-15 11:15:10 +02:00
Werner Masik 73e03ba901 Gehaltstyp Überstundenpauschale und Sachbezug PKW 2026-04-15 10:44:03 +02:00
ma0068 95a7797ae9 delete unused apicall for mode modal
add editor.setContent to function getReplyData
readd loadReplyData and use v-show for visibleDiv for mode inSamePage
2026-04-14 15:46:34 +02:00
ma0048 3ce3eff022 fehlendes mapping hinzugefuegt 2026-04-14 09:30:45 +02:00
ma0048 21d80905a2 akzeptierte dokumente anzeigen, auch wenn kein dokument vorhanden ist 2026-04-13 13:04:46 +02:00
Andreas Österreicher 3a91b12f31 Merge branch 'epic-56039/LV-Evaluierung' 2026-04-13 10:39:00 +02:00
ma0048 ea0a249612 micro degree abschlussdokumente hinzugefuegt 2026-04-13 09:14:27 +02:00
ma0068 843894405e changes for NewDiv
remove Watcher for formData Fields
add predefault settings for tabulator fields
add setContent for Editor
change text for closing window/tab
show alertSuccess for sending Message just in case of inSamePage
2026-04-10 13:03:24 +02:00
ma0068 8fddbc3a32 delete watcher for formData fields, add setContent for loading Vorlage 2026-04-10 09:15:34 +02:00
Harald Bamberger b2538075ee use STV_TAGS_ENABLED config when preparing sql statement for students list to query tags only if enabled 2026-04-07 10:35:06 +02:00
Werner Masik 5c463c0866 add vordienstzeit to lohnguide 2026-04-06 22:25:13 +02:00
Werner Masik 423bbd95a6 add vordienstzeit to lohnguide 2026-04-06 22:25:12 +02:00
Cristina 386cc779bf Merge branch 'master' into epic-56039/LV-Evaluierung 2026-04-02 15:49:20 +02:00
Cristina 08c6d58a50 Merge branch 'master' of https://github.com/FH-Complete/FHC-Core 2026-04-02 14:24:39 +02:00
Cristina 3f53c5feba Added: method getKFLByUID to get Kompetenzfeldleitung by UID 2026-04-02 14:23:59 +02:00
ma0068 298dbbf400 use context vm for tabulator event, refactor function toggleRowClick, delete unused commented sections 2026-04-02 10:58:49 +02:00
Andreas Österreicher 2c057aad58 Updated Startup Dump to Final 3.3 Version 2026-04-01 13:00:50 +02:00
Harald Bamberger 627a52e3d1 Merge branch 'master' into feature-70376/Lohnguide 2026-03-25 09:36:27 +01:00
Harald Bamberger 059b13938e Merge branch 'master' into feature-70376/Lohnguide 2026-03-18 11:46:27 +01:00
Werner Masik 6b816def31 add lohnguide to vertragsbestandteil SQL 2026-03-05 15:34:51 +01:00
Werner Masik 5fbcf588ed fix vertragsbestandteil lohnguide 2026-03-05 14:29:56 +01:00
Werner Masik 41b2a6d1d4 added db migration for lohnguide 2026-03-04 10:53:30 +01:00
Werner Masik e054f1222b basic model and factory for lohnguide 2026-03-03 11:50:45 +01:00
Cristina c57eb1b8de Adapted method getLvLeitung: filter Dummy and allow only active Benutzer/Person 2026-03-02 11:00:05 +01:00
Cristina d1015956d1 Merge branch 'master' into epic-56039/LV-Evaluierung 2026-02-25 10:54:29 +01:00
Cristina 726fce9fac Merge branch 'master' of https://github.com/FH-Complete/FHC-Core 2026-02-25 10:52:50 +01:00
Cristina 27a91de5f6 Added app lvevaluierung to system.tbl_app 2026-01-22 15:51:05 +01:00
Cristina 7ccc26c878 Added lvevaluierung phrasen for STGL Übersichtsseite 2026-01-22 15:41:25 +01:00
Cristina 9ebc847e8e Added lvevaluierung phrasen for Lektoren Übersichtsseite 2026-01-22 14:59:00 +01:00
Cristina 511b04c1f8 Merge branch 'master' into epic-56039/LV-Evaluierung 2026-01-21 18:01:55 +01:00
Cristina ec90d35e02 Merge branch 'master' of https://github.com/FH-Complete/FHC-Core 2026-01-21 18:01:24 +01:00
ma0068 38e8f91fdf add kurzbzlang to studentDropdown suggestion 2025-11-25 10:48:57 +01:00
ma0048 ba6224bc78 oeh betrag aus der eigener tabelle holen
studentenverwaltung bei jedem studiensemester wechsel
fas nur einmalig ueber die variable
2025-09-02 11:18:24 +02:00
cgfhtw d542cf7720 s&d 2024-08-14 16:20:47 +02:00
123 changed files with 8464 additions and 8961 deletions
-22
View File
@@ -33,27 +33,5 @@ Events::on('loadRenderers', function ($renderers) {
);
});
//Tempus Renderers:
Events::on('loadTempusRenderers', function ($renderers) {
$fhc_core_renderers =& $renderers();
$fhc_core_renderers["reservierung"] = array(
'calendarEvent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/calendarEvent.js'),
'modalTitle' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/modalTitle.js'),
'modalContent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Reservierungen/modalContent.js'),
'calendarEventStyles' => APP_ROOT . 'public/css/Cis4/CoreCalendarEvents.css'
);
});
Events::on('loadTempusRenderers', function ($renderers) {
$fhc_core_renderers =& $renderers();
$fhc_core_renderers["lehreinheit"] = array(
'calendarEvent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Lehreinheit/calendarEvent.js'),
'modalTitle' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Lehreinheit/modalTitle.js'),
'modalContent' => absoluteJsImportUrl('public/js/components/Tempus/Renderer/Lehreinheit/modalContent.js'),
'calendarEventStyles' => APP_ROOT . 'public/css/Cis4/CoreCalendarEvents.css'
);
});
-3
View File
@@ -1,3 +0,0 @@
<?php
$config['send_update_mails'] = false;
-40
View File
@@ -1,40 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
*
*/
class Tempus extends Auth_Controller
{
public function __construct()
{
$permissions = [];
$router = load_class('Router');
$permissions[$router->method] = ['admin:r', 'assistenz:r'];
parent::__construct($permissions);
// Load Libraries
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
// Load Config
$this->load->config('calendar');
}
/**
* @return void
*/
public function _remap()
{
$this->load->view('Tempus', [
'permissions' => [
'admin' => $this->permissionlib->isBerechtigt('admin')
],
'variables' => [
'semester_aktuell' => $this->variablelib->getVar('semester_aktuell'),
'timezone' => $this->config->item('timezone')
]
]);
}
}
@@ -36,7 +36,9 @@ class Ort extends FHCAPI_Controller
'ContentID' => self::PERM_LOGGED,
'getOrtKurzbzContent' => self::PERM_LOGGED,
'getRooms' => self::PERM_LOGGED,
'getTypes' => self::PERM_LOGGED
'getTypes' => self::PERM_LOGGED,
'getRoomsWithEmployeesAssigned' => 'basis/ort:r',
'getEmployeesWithRoomAssigned' => 'basis/ort:r'
]);
$this->load->model('ressource/Ort_model', 'OrtModel');
@@ -174,5 +176,42 @@ class Ort extends FHCAPI_Controller
$this->terminateWithSuccess($content);
}
public function getRoomsWithEmployeesAssigned($ort_kurzbz=null)
{
$res = $this->OrtModel->getRoomsWithEmployeesAssigned($ort_kurzbz);
if (isError($res))
{
$this->terminateWithError(getError($res));
}
$data = hasData($res) ? getData($res) : [];
$this->json_decode_db_res($data);
$this->terminateWithSuccess($data);
}
public function getEmployeesWithRoomAssigned($mitarbeiter_uid=null)
{
$res = $this->OrtModel->getEmployeesWithRoomAssigned($mitarbeiter_uid);
if (isError($res))
{
$this->terminateWithError(getError($res));
}
$data = hasData($res) ? getData($res) : [];
$this->json_decode_db_res($data);
$this->terminateWithSuccess($data);
}
protected function json_decode_db_res(&$data)
{
array_walk($data, function($item, $key) {
isset($item->employees) && $item->employees = json_decode($item->employees);
isset($item->employee) && $item->employee = json_decode($item->employee);
isset($item->room) && $item->room = json_decode($item->room);
});
}
}
@@ -31,7 +31,7 @@ class RendererLoader extends FHCAPI_Controller
parent::__construct([
'GetRenderers' => self::PERM_LOGGED,
'GetTempusRenderers' => self::PERM_LOGGED,
]);
$this->load->library('LogLib');
@@ -66,26 +66,6 @@ class RendererLoader extends FHCAPI_Controller
$this->terminateWithSuccess($renderer_paths);
}
public function GetTempusRenderers(){
$renderer_paths = [];
Events::trigger(
'loadRenderers',
function & () use (&$renderer_paths)
{
return $renderer_paths;
}
);
Events::trigger(
'loadTempusRenderers',
function & () use (&$renderer_paths)
{
return $renderer_paths;
}
);
$this->terminateWithSuccess($renderer_paths);
}
@@ -118,17 +118,54 @@ class Gruppe extends FHCAPI_Controller
$query_words = explode(' ', $query);
$gruppen_result = $this->_ci->GruppeModel->search($query_words);
$this->_ci->GruppeModel->addSelect('gruppe_kurzbz,
studiengang_kz,
semester,
bezeichnung,
gid,
\'false\' as lehrverband');
$this->_ci->GruppeModel->db->where(array('sichtbar' => true, 'aktiv' => true, 'lehre' => true, 'direktinskription' => false, 'semester IS NOT NULL' => null));
$this->_ci->GruppeModel->db->group_start();
foreach ($query_words as $word)
{
$this->_ci->GruppeModel->db->group_start();
$this->_ci->GruppeModel->db->where('gruppe_kurzbz ILIKE', "%" . $word . "%");
$this->_ci->GruppeModel->db->or_where('bezeichnung ILIKE', "%" . $word . "%");
$this->_ci->GruppeModel->db->group_end();
}
$this->_ci->GruppeModel->db->group_end();
$gruppen_result = $this->_ci->GruppeModel->load();
$gruppen_array = array();
if (isError($gruppen_result))
$this->terminateWithError(getError($gruppen_result), self::ERROR_TYPE_GENERAL);
$gruppen_array = array();
if (hasData($gruppen_result))
$gruppen_array = getData($gruppen_result);
$lehrverband_result = $this->_ci->LehrverbandModel->search($query_words);
$this->_ci->LehrverbandModel->addSelect('CONCAT(UPPER(CONCAT(typ, kurzbz)), \'\', semester, verband, COALESCE(gruppe,\'\')) as gruppe_kurzbz,
studiengang_kz,
semester,
tbl_lehrverband.bezeichnung,
gid,
\'true\' as lehrverband');
$this->_ci->LehrverbandModel->addJoin('public.tbl_studiengang', 'studiengang_kz');
$this->_ci->LehrverbandModel->addOrder('verband');
$this->_ci->LehrverbandModel->addOrder('gruppe');
$this->_ci->LehrverbandModel->db->where(array('tbl_lehrverband.aktiv' => true));
$this->_ci->LehrverbandModel->db->group_start();
foreach ($query_words as $word)
{
$this->_ci->LehrverbandModel->db->group_start();
$this->_ci->LehrverbandModel->db->where('CONCAT(CONCAT(typ, kurzbz), \'\', semester, verband, COALESCE(gruppe,\'\')) ILIKE', "%" . $word . "%");
$this->_ci->LehrverbandModel->db->or_where('tbl_lehrverband.bezeichnung ILIKE', "%" . $word . "%");
$this->_ci->LehrverbandModel->db->group_end();
}
$this->_ci->LehrverbandModel->db->group_end();
$lehrverband_result = $this->_ci->LehrverbandModel->load();
$lehrverband_array = array();
@@ -42,14 +42,22 @@ class Messages extends FHCAPI_Controller
]);
}
public function getMessages($id, $type_id, $size, $page)
public function getMessages($id, $type_id, $size=null, $page=null)
{
if($type_id != 'person_id'){
$id = $this->_getPersonId($id, $type_id);
}
$offset = $size * ($page - 1);
$limit = $size;
if(!(is_null($size) && is_null($page)))
{
$offset = $size * ($page - 1);
$limit = $size;
}
else
{
$offset = null;
$limit = null;
}
$result = $this->MessageModel->getMessagesForTable($id, $offset, $limit);
@@ -78,52 +78,32 @@ class Dokumente extends FHCAPI_Controller
$this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Studiengang_kz']), self::ERROR_TYPE_GENERAL);
$resultPreDoc = $this->_getPrestudentDokumente($prestudent_id);
$arrayAccepted = [];
$person_id = $this->_getPersonId($prestudent_id);
$docNames = array_map(function ($item) {
return $item->dokument_kurzbz;
}, $resultPreDoc);
$mergedArray = [];
foreach($docNames as $doc)
foreach ($resultPreDoc as $pre)
{
$result = $this->AkteModel->getAktenFAS($person_id, $doc, $studiengang_kz, $prestudent_id, true);
$result = $this->AkteModel->getAktenFAS($person_id, $pre->dokument_kurzbz, $studiengang_kz, $prestudent_id, true);
if (isError($result))
{
return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL);
}
if (hasData($result))
{
$data = getData($result);
foreach ($data as $value)
foreach (getData($result) as $doc)
{
array_push($arrayAccepted, $value);
$merged = clone $doc;
$merged->docdatum = $pre->docdatum;
$merged->insertvonma = $pre->insertvonma;
$merged->bezeichnung = $pre->bezeichnung;
$mergedArray[] = $merged;
}
}
}
//Mapping with document_kurzbz
$preDocMap = [];
foreach ($resultPreDoc as $pre) {
$preDocMap[$pre->dokument_kurzbz] = $pre;
}
$mergedArray = [];
foreach ($arrayAccepted as $doc) {
$merged = clone $doc;
if (isset($preDocMap[$doc->dokument_kurzbz])) {
$merged->docdatum = $preDocMap[$doc->dokument_kurzbz]->docdatum;
$merged->insertvonma = $preDocMap[$doc->dokument_kurzbz]->insertvonma;
$merged->bezeichnung = $preDocMap[$doc->dokument_kurzbz]->bezeichnung;
} else {
$merged->akzeptiertdatum = null;
$merged->akzeptiertvon = null;
else
{
$mergedArray[] = $pre;
}
$mergedArray[] = $merged;
}
$this->terminateWithSuccess($mergedArray);
@@ -48,7 +48,8 @@ class Konto extends FHCAPI_Controller
// Load language phrases
$this->loadPhrases([
'konto'
'konto',
'lehre'
]);
}
@@ -112,7 +113,7 @@ class Konto extends FHCAPI_Controller
*
* @return void
*/
public function getBuchungstypen()
public function getBuchungstypen($studiensemester_kurzbz = null)
{
$this->load->model('crm/Buchungstyp_model', 'BuchungstypModel');
@@ -122,6 +123,7 @@ class Konto extends FHCAPI_Controller
$data = $this->getDataOrTerminateWithError($result);
$this->_getOEHBeitrag($data, $studiensemester_kurzbz);
$this->terminateWithSuccess($data);
}
@@ -494,4 +496,43 @@ class Konto extends FHCAPI_Controller
$this->terminateWithSuccess();
}
private function _getOEHBeitrag(&$data, $studiensemester_kurzbz = null)
{
if (is_null($studiensemester_kurzbz))
{
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
$studiensemester_akt = $this->variablelib->getVar('semester_aktuell');
}
else
{
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
if ($this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
$studiensemester_akt = $studiensemester_kurzbz;
else
$this->terminateWithError($this->p->t('lehre', 'error_noStudiensemester'));
}
$this->load->model('codex/Oehbeitrag_model', 'OehbeitragModel');
$oehBeitrag = $this->OehbeitragModel->getByStudiensemester($studiensemester_akt);
$oehStandardbetrag = null;
if (hasData($oehBeitrag))
{
$oeh = getData($oehBeitrag)[0];
$summe = ($oeh->studierendenbeitrag + $oeh->versicherung) * -1;
$oehStandardbetrag = number_format((float)$summe, 2, '.', '');
}
if ($oehStandardbetrag !== null)
{
$data = array_map(function ($buchungstyp) use ($oehStandardbetrag) {
if (isset($buchungstyp->buchungstyp_kurzbz) && (strtolower($buchungstyp->buchungstyp_kurzbz) === 'oeh'))
{
$buchungstyp->standardbetrag = $oehStandardbetrag;
}
return $buchungstyp;
}, $data);
}
}
}
@@ -626,7 +626,7 @@ class Students extends FHCAPI_Controller
$this->addFilter($studiensemester_kurzbz);
$result = $this->PrestudentModel->loadWhere($where);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
@@ -851,40 +851,44 @@ class Students extends FHCAPI_Controller
$stdsemEsc = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL';
$this->load->config('stv');
$tags = $this->config->item('stv_prestudent_tags');
$whereTags = '';
if (is_array($tags) && !isEmptyArray($tags)) {
$tags = array_keys($tags);
if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
{
$tags = $this->config->item('stv_prestudent_tags');
foreach ($tags as $key => $tag) {
$tags[$key] = $this->db->escape($tag);
$whereTags = '';
if (is_array($tags) && !isEmptyArray($tags)) {
$tags = array_keys($tags);
foreach ($tags as $key => $tag) {
$tags[$key] = $this->db->escape($tag);
}
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")";
}
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")";
$subQueryTag = "
(
SELECT
tag.prestudent_id,
COALESCE(json_agg(tag ORDER BY tag.done), '[]'::json) AS tags
FROM (
SELECT DISTINCT ON (n.notiz_id)
n.notiz_id AS id,
nt.typ_kurzbz,
array_to_json(nt.bezeichnung_mehrsprachig)->>0 AS beschreibung,
n.text AS notiz,
nt.style,
n.erledigt AS done,
nz.prestudent_id
FROM public.tbl_notizzuordnung AS nz
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz "
. $whereTags .
"
) AS tag
GROUP BY tag.prestudent_id
) AS tag_data_agg
";
}
$subQueryTag = "
(
SELECT
tag.prestudent_id,
COALESCE(json_agg(tag ORDER BY tag.done), '[]'::json) AS tags
FROM (
SELECT DISTINCT ON (n.notiz_id)
n.notiz_id AS id,
nt.typ_kurzbz,
array_to_json(nt.bezeichnung_mehrsprachig)->>0 AS beschreibung,
n.text AS notiz,
nt.style,
n.erledigt AS done,
nz.prestudent_id
FROM public.tbl_notizzuordnung AS nz
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz "
. $whereTags .
"
) AS tag
GROUP BY tag.prestudent_id
) AS tag_data_agg
";
$this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT');
$this->PrestudentModel->addJoin('public.tbl_person p', 'person_id');
@@ -907,11 +911,17 @@ class Students extends FHCAPI_Controller
AND ps.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')
AND ps.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')', 'LEFT');
$this->PrestudentModel->addJoin($subQueryTag, 'tag_data_agg.prestudent_id = tbl_prestudent.prestudent_id', 'LEFT');
if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
{
$this->PrestudentModel->addJoin($subQueryTag, 'tag_data_agg.prestudent_id = tbl_prestudent.prestudent_id', 'LEFT');
}
$this->PrestudentModel->addSelect("b.uid");
$this->PrestudentModel->addSelect('tag_data_agg.tags');
if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
{
$this->PrestudentModel->addSelect('tag_data_agg.tags');
}
$this->PrestudentModel->addSelect('titelpre');
$this->PrestudentModel->addSelect('nachname');
$this->PrestudentModel->addSelect('vorname');
@@ -1,116 +0,0 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class Config extends FHCAPI_Controller
{
private $_ci;
public function __construct()
{
parent::__construct([
'get' => ['admin:r', 'assistenz:r'],
'getHeader' => ['admin:r', 'assistenz:r'],
'set' => ['admin:r', 'assistenz:r'],
]);
// Load Phrases
$this->loadPhrases([
'ui',
]);
$this->_ci = &get_instance();
$this->_ci->load->model('ressource/Kalenderstatus_model', 'KalenderStatusModel');
}
public function get()
{
$this->_ci->load->model('system/Variable_model', 'VariableModel');
$config = [];
$result = $this->_ci->VariableModel->getVariables(getAuthUID(), ['ignore_kollision', 'kollision_student', 'ignore_reservierung', 'ignore_zeitsperre']);
$data = $this->getDataOrTerminateWithError($result);
$config['ignore_kollision'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'ignore_kollision'),
"value" => ($data['ignore_kollision'] ?? 'false') === 'true'
];
$config['kollision_student'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'kollision_student'),
"value" => ($data['kollision_student'] ?? 'false') === 'true'
];
$config['ignore_reservierung'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'ignore_reservierung'),
"value" => ($data['ignore_reservierung'] ?? 'false') === 'true'
];
$config['ignore_zeitsperre'] = [
"type" => "checkbox",
"label" => $this->p->t('ui', 'ignore_zeitsperre'),
"value" => ($data['ignore_zeitsperre'] ?? 'false') === 'true'
];
$this->terminateWithSuccess($config);
}
public function getHeader()
{
$language = getUserLanguage() == 'German' ? 0 : 1;
$this->_ci->KalenderStatusModel->addSelect('*, array_to_json(bezeichnung_mehrsprachig::varchar[])->>' . $language .' AS status');
$this->_ci->KalenderStatusModel->addOrder('sort');
$this->_ci->KalenderStatusModel->db->where_not_in('status_kurzbz', array('archived', 'deleted'));
$visible_status = $this->_ci->KalenderStatusModel->load();
$visible_status = getData($visible_status);
$config['visible_status']['all'] = 'Alle';
foreach ($visible_status as $status)
{
$config['visible_status'][$status->status_kurzbz] = $status->status;
}
$this->terminateWithSuccess($config);
}
public function set()
{
$this->_ci->load->model('system/Variable_model', 'VariableModel');
$this->_ci->VariableModel->setVariable(
getAuthUID(),
'ignore_kollision',
$this->input->post('ignore_kollision') === true ? 'true' : 'false'
);
$this->_ci->VariableModel->setVariable(
getAuthUID(),
'kollision_student',
$this->input->post('kollision_student') === true ? 'true' : 'false'
);
$this->_ci->VariableModel->setVariable(
getAuthUID(),
'ignore_reservierung',
$this->input->post('ignore_reservierung') === true ? 'true' : 'false'
);
$this->_ci->VariableModel->setVariable(
getAuthUID(),
'ignore_zeitsperre',
$this->input->post('ignore_zeitsperre') === true ? 'true' : 'false'
);
$this->terminateWithSuccess();
}
}
@@ -1,254 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Coursepicker extends FHCAPI_Controller
{
private $_ci;
public function __construct()
{
parent::__construct([
'search' => self::PERM_LOGGED,
'getByStg' => self::PERM_LOGGED
]);
$this->_ci = &get_instance();
$this->load->library('form_validation');
$this->_ci->load->model('education/lehreinheit_model', 'LehreinheitModel');
$this->_ci->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel');
$this->loadPhrases(['ui']);
}
public function search()
{
$query = $this->input->get('query');
if (is_null($query))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$query_words = explode(' ', $query);
//TODO Where weiter anpassen z.B. Fachbereich
$this->_ci->LehreinheitModel->addSelect('tbl_lehreinheit.lehreinheit_id,
tbl_lehreinheit.unr,
tbl_lehreinheit.lvnr,
tbl_lehreinheit.lehrfach_id,
lehrfach.kurzbz AS lehrfach,
lehrfach.bezeichnung AS lehrfach_bez,
lehrfach.farbe AS lehrfach_farbe,
tbl_lehreinheit.lehrform_kurzbz AS lehrform,
lema.mitarbeiter_uid AS lektor_uid,
tbl_mitarbeiter.kurzbz AS lektor,
tbl_studiengang.studiengang_kz,
upper(tbl_studiengang.typ::character varying::text || tbl_studiengang.kurzbz::text) AS studiengang,
lvb.semester,
lvb.verband,
lvb.gruppe,
lvb.gruppe_kurzbz,
tbl_lehreinheit.raumtyp,
tbl_lehreinheit.raumtypalternativ,
tbl_lehreinheit.stundenblockung,
tbl_lehreinheit.wochenrythmus,
lema.semesterstunden,
lema.planstunden,
tbl_lehreinheit.start_kw,
tbl_lehreinheit.anmerkung,
tbl_lehreinheit.studiensemester_kurzbz');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehreinheitmitarbeiter lema', 'tbl_lehreinheit.lehreinheit_id = lema.lehreinheit_id');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehreinheitgruppe lvb', 'tbl_lehreinheit.lehreinheit_id = lvb.lehreinheit_id');
$this->_ci->LehreinheitModel->addJoin('public.tbl_studiengang', 'lvb.studiengang_kz = tbl_studiengang.studiengang_kz');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrveranstaltung lehrfach', 'tbl_lehreinheit.lehrfach_id = lehrfach.lehrveranstaltung_id');
$this->_ci->LehreinheitModel->addJoin('public.tbl_mitarbeiter', 'lema.mitarbeiter_uid = tbl_mitarbeiter.mitarbeiter_uid');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrform', 'tbl_lehrform.lehrform_kurzbz = tbl_lehreinheit.lehrform_kurzbz');
$this->_ci->MitarbeiterModel->db->group_start();
foreach ($query_words as $word)
{
$this->_ci->LehreinheitModel->db->group_start();
$this->_ci->LehreinheitModel->db->where('lema.mitarbeiter_uid ILIKE', "%" . $word . "%");
$this->_ci->LehreinheitModel->db->or_where('lvb.gruppe_kurzbz ILIKE', "%" . $word . "%");
$this->_ci->LehreinheitModel->db->or_where('tbl_studiengang.kurzbzlang ILIKE', "%" . $word . "%");
$this->_ci->LehreinheitModel->db->or_where('lvb.verband ILIKE', "%" . $word . "%");
$this->_ci->LehreinheitModel->db->or_where('lvb.gruppe ILIKE', "%" . $word . "%");
$this->_ci->LehreinheitModel->db->or_where('lehrfach.bezeichnung ILIKE', "%" . $word . "%");
if (is_numeric($word))
{
$this->_ci->LehreinheitModel->db->or_where('tbl_studiengang.studiengang_kz', $word);
$this->_ci->LehreinheitModel->db->or_where('lvb.semester', $word);
}
$this->_ci->LehreinheitModel->db->group_end();
}
$this->_ci->LehreinheitModel->db->group_end();
$this->_ci->LehreinheitModel->db->where('tbl_lehreinheit.studiensemester_kurzbz = \'SS2025\'');
$this->_ci->LehreinheitModel->db->where(array('tbl_lehrform.verplanen' => true));
$result = $this->_ci->LehreinheitModel->load();
$this->terminateWithSuccess(hasData($result) ? getData($result) : array());
}
public function getByStg()
{
//TODO check einbauen ob studiensemester und stg vorhanden ist
$stg = $this->input->get('stg');
$studiensemester_kurzbz = $this->input->get('studiensemester_kurzbz');
if (is_null($stg) || is_null($studiensemester_kurzbz))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$this->_ci->LehreinheitModel->addSelect('
tbl_lehreinheit.lehreinheit_id,
tbl_lehreinheit.unr,
tbl_lehreinheit.lvnr,
tbl_lehreinheit.lehrfach_id,
lehrfach.kurzbz AS lehrfach,
lehrfach.bezeichnung AS lehrfach_bez,
lehrfach.farbe AS lehrfach_farbe,
tbl_lehreinheit.lehrform_kurzbz AS lehrform,
lema.mitarbeiter_uid AS lektor_uid,
ma.kurzbz AS lektor,
tbl_person.vorname,
tbl_person.nachname,
tbl_studiengang.studiengang_kz,
upper(tbl_studiengang.typ::character varying::text || tbl_studiengang.kurzbz::text) AS studiengang,
lvb.semester,
lvb.verband,
lvb.gruppe,
lvb.gruppe_kurzbz,
tbl_lehreinheit.raumtyp,
tbl_lehreinheit.raumtypalternativ,
tbl_lehreinheit.stundenblockung,
tbl_lehreinheit.wochenrythmus,
lema.semesterstunden,
lema.planstunden,
tbl_lehreinheit.start_kw,
tbl_lehreinheit.anmerkung,
tbl_lehreinheit.studiensemester_kurzbz
');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehreinheitmitarbeiter lema', 'tbl_lehreinheit.lehreinheit_id = lema.lehreinheit_id');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehreinheitgruppe lvb', 'tbl_lehreinheit.lehreinheit_id = lvb.lehreinheit_id');
$this->_ci->LehreinheitModel->addJoin('public.tbl_studiengang', 'lvb.studiengang_kz = tbl_studiengang.studiengang_kz');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrveranstaltung lehrfach', 'tbl_lehreinheit.lehrfach_id = lehrfach.lehrveranstaltung_id');
$this->_ci->LehreinheitModel->addJoin('public.tbl_mitarbeiter ma', 'lema.mitarbeiter_uid = ma.mitarbeiter_uid');
$this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrform', 'tbl_lehrform.lehrform_kurzbz = tbl_lehreinheit.lehrform_kurzbz');
$this->_ci->LehreinheitModel->addJoin('public.tbl_benutzer', 'ma.mitarbeiter_uid = tbl_benutzer.uid');
$this->_ci->LehreinheitModel->addJoin('public.tbl_person', 'tbl_benutzer.person_id = tbl_person.person_id');
$result = $this->_ci->LehreinheitModel->loadWhere(array(
'tbl_lehrform.verplanen' => true,
'tbl_studiengang.studiengang_kz' => $stg,
'tbl_lehreinheit.studiensemester_kurzbz' => $studiensemester_kurzbz
));
$result = hasData($result) ? getData($result) : array();
$grouped = array();
foreach ($result as $row)
{
$unr = $row->unr;
if (!isset($grouped[$unr]))
{
$grouped[$unr] = (object)array(
'unr' => $row->unr,
'lehrfach_id' => $row->lehrfach_id,
'lehrfach_bez' => $row->lehrfach_bez,
'lehrfach_farbe' => $row->lehrfach_farbe,
'studiengang_kz' => $row->studiengang_kz,
'studiengang' => $row->studiengang,
'semester' => $row->semester,
'verband' => $row->verband,
'gruppe' => $row->gruppe,
'gruppe_kurzbz' => $row->gruppe_kurzbz,
'raumtyp' => $row->raumtyp,
'raumtypalternativ' => $row->raumtypalternativ,
'anmerkung' => $row->anmerkung,
'studiensemester_kurzbz' => $row->studiensemester_kurzbz,
'fachbereich_kurzbz' => isset($row->fachbereich_kurzbz) ? $row->fachbereich_kurzbz : null,
'lektoren' => array(),
'lehreinheit_id' => array(),
'lvnr' => array(),
'lehrfach' => array(),
'lehrform' => array(),
'stundenblockung' => array(),
'wochenrythmus' => array(),
'planstunden' => array(),
'start_kw' => array(),
'verplant' => array(),
'offenestunden' => array(),
'lehrverband' => array(),
'lem' => array(),
'verplant_gesamt' => 0,
);
}
$group = $grouped[$unr];
$group->lektoren[$row->lektor_uid] = (object)array(
'uid' => $row->lektor_uid,
'kurzbz' => trim($row->lektor),
'name' => $row->vorname . ' ' . $row->nachname,
);
$group->lehreinheit_id[] = $row->lehreinheit_id;
$group->lvnr[] = $row->lvnr;
$group->lehrfach[] = $row->lehrfach;
$group->lehrform[] = $row->lehrform;
$group->stundenblockung[] = $row->stundenblockung;
$group->wochenrythmus[] = $row->wochenrythmus;
$group->planstunden[] = $row->planstunden;
$group->start_kw[] = $row->start_kw;
$group->verplant[] = isset($row->verplant) ? $row->verplant : 0;
$group->offenestunden[] = isset($row->offenestunden) ? $row->offenestunden : 0;
$group->verplant_gesamt += isset($row->verplant) ? $row->verplant : 0;
$lvb = $row->studiengang . '-' . $row->semester;
if ($row->verband != '' && $row->verband != ' ' && $row->verband != '0' && $row->verband != null)
$lvb .= $row->verband;
if ($row->gruppe != '' && $row->gruppe != ' ' && $row->gruppe != '0' && $row->gruppe != null)
$lvb .= $row->gruppe;
$group->lehrverband[] = ($row->gruppe_kurzbz != '' && $row->gruppe_kurzbz != null) ? $row->gruppe_kurzbz : $lvb;
$group->lem[] = array(
'lehreinheit_id' => $row->lehreinheit_id,
'mitarbeiter_uid' => $row->lektor_uid,
);
}
foreach ($grouped as $group)
{
$group->lektoren = array_values($group->lektoren);
$group->lehrverband = array_values(array_unique($group->lehrverband));
$group->lehrfach = $this->_formatArr($group->lehrfach);
$group->lehrform = $this->_formatArr($group->lehrform);
$group->stundenblockung = $this->_formatArr($group->stundenblockung);
$group->wochenrythmus = $this->_formatArr($group->wochenrythmus);
$group->planstunden = $this->_formatArr($group->planstunden);
$group->start_kw = $this->_formatArr($group->start_kw);
$group->verplant = $this->_formatArr($group->verplant);
$group->offenestunden = $this->_formatArr($group->offenestunden);
}
$this->terminateWithSuccess(array_values($grouped));
}
private function _formatArr($arr)
{
$values = array_values(array_unique($arr));
$formatted = implode(' ', $values);
if (count($formatted) > 1)
$formatted .= ' ?';
return $formatted;
}
}
@@ -1,416 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Kalender extends FHCAPI_Controller
{
private $_ci;
const ALLOWED_PLAN_FILTER = ['ort', 'uid', 'stg'];
const ALLOWED_ROOM_FILTER = ['lehreinheit_id', 'kalender_id'];
const ALLOWED_TO_UPDATE = ['start_time', 'end_time', 'ort_kurzbz'];
/**
* Object initialization
*/
public function __construct()
{
parent::__construct([
'getStunden' => self::PERM_LOGGED,
'getPlan' => self::PERM_LOGGED,
'getPlanByOrt' => self::PERM_LOGGED,
'getRaumvorschlag' => self::PERM_LOGGED,
'getHistory' => 'lehre/lvplan:rw',
'deleteEntry' => 'lehre/lvplan:rw',
'syncToLecturer' => 'lehre/lvplan:rw',
'syncToStudent' => 'lehre/lvplan:rw',
'getPlanLecturer' =>'lehre/lvplan:rw',
'getPlanStudent' => 'lehre/lvplan:rw',
'getZeitwuensche' => self::PERM_LOGGED,
'getZeitsperren' => self::PERM_LOGGED,
'updateKalenderEvent' => 'lehre/lvplan:rw',
'addKalenderEvent' => 'lehre/lvplan:rw',
'addReservierung' => 'lehre/lvplan:rw',
'sync' => 'lehre/lvplan:rw',
]);
$this->_ci =& get_instance();
$this->_ci->load->library('LogLib');
$this->_ci->load->library('form_validation');
$this->_ci->load->library('KalenderLib');
$this->loadPhrases([
'ui'
]);
$this->_ci->loglib->setConfigs(array(
'classIndex' => 5,
'functionIndex' => 5,
'lineIndex' => 4,
'dbLogType' => 'API', // required
'dbExecuteUser' => 'RESTful API'
));
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
/**
* fetches Stunden layout from database
* @access public
*
*/
public function getStunden()
{
$this->load->model('ressource/Stunde_model', 'StundeModel');
$this->_ci->StundeModel->addOrder('stunde', 'ASC');
$stunden = $this->_ci->StundeModel->load();
$stunden = $this->getDataOrTerminateWithError($stunden);
$this->terminateWithSuccess($stunden);
}
public function getPlan()
{
$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_PLAN_FILTER);
$stundenplan_data = $this->_ci->kalenderlib->getPlanForPlanner(
$start_date,
$end_date,
isset($filter->ort) ? $filter->ort : null,
isset($filter->uid) ? $filter->uid : null,
isset($filter->stg) ? $filter->stg : null
);
$this->terminateWithSuccess($stundenplan_data);
}
public function getPlanStudent()
{
$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);
$stundenplan_data = $this->_ci->kalenderlib->getPlanForStudent(
$start_date,
$end_date
);
$this->terminateWithSuccess($stundenplan_data);
}
public function getPlanLecturer()
{
$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);
$stundenplan_data = $this->_ci->kalenderlib->getPlanForLecturer(
$start_date,
$end_date
);
$this->terminateWithSuccess($stundenplan_data);
}
public function getPlanByOrt($start_date = null, $end_date = null, $ort = null)
{
if (!isset($start_date) || !isset($end_date) || !isset($ort))
{
$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");
$this->_ci->form_validation->set_rules('ort',"ort","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);
$ort = $this->_ci->input->get('ort', TRUE);
}
$this->terminateWithSuccess($this->_ci->kalenderlib->getPlanByOrt($start_date, $end_date, $ort));
}
public function getZeitsperren()
{
$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");
$this->_ci->form_validation->set_rules('emp',"emp","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);
$emp = $this->_ci->input->get('emp', TRUE);
$stundenplan_data = $this->_ci->kalenderlib->getZeitsperren($start_date, $end_date, $emp);
$this->terminateWithSuccess($stundenplan_data);
}
public function getZeitwuensche()
{
$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");
$this->_ci->form_validation->set_rules('emp',"emp","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);
$emp = $this->_ci->input->get('emp', TRUE);
$stundenplan_data = $this->_ci->kalenderlib->getZeitwuensche($start_date, $end_date, $emp);
$this->terminateWithSuccess($stundenplan_data);
}
public function updateKalenderEvent()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('kalender_id',"kalender_id","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$updateFields = $this->_checkUpdate($this->_ci->input->post('updatedInfos', TRUE));
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
$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->terminateWithSuccess('Erfolgreich');
}
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));
}
public function getHistory()
{
$this->_ci->form_validation->set_data($_GET);
$this->_ci->form_validation->set_rules('kalender_id',"kalender_id","required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_id = $this->_ci->input->get('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->getHistory($kalender_id);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess(getData($result));
}
public function deleteEntry()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('kalender_id', "kalender_id", "required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->deleteEntry($kalender_id);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess($result);
}
public function sync()
{
$result = $this->_ci->kalenderlib->sync();
$this->terminateWithSuccess($result);
}
public function syncToLecturer()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('kalender_id', "kalender_id", "required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->updateStatus($kalender_id, 'sync_preview');
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess($result);
}
public function syncToStudent()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('kalender_id', "kalender_id", "required");
if($this->_ci->form_validation->run() === FALSE)
$this->terminateWithValidationErrors($this->_ci->form_validation->error_array());
$kalender_id = $this->_ci->input->post('kalender_id', TRUE);
$result = $this->_ci->kalenderlib->updateStatus($kalender_id, 'sync_live');
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess($result);
}
public function addKalenderEvent()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('lehreinheit_id',"lehreinheit_id","required");
$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());
$lehreinheit_id = $this->_ci->input->post('lehreinheit_id', TRUE);
$ort_kurzbz = $this->_ci->input->post('ort_kurzbz', TRUE);
$start_date = $this->_ci->input->post('start_date', TRUE);
$end_date = $this->_ci->input->post('end_date', TRUE);
$result = $this->_ci->kalenderlib->addKalenderEvent($start_date, $end_date, $lehreinheit_id, $ort_kurzbz);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess('Erfolgreich');
}
public function addReservierung()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('titel',"titel","required");
$this->_ci->form_validation->set_rules('beschreibung',"beschreibung","required");
$this->_ci->form_validation->set_rules('ort_kurzbz',"ort_kurzbz","required");
$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());
$titel = $this->_ci->input->post('titel', TRUE);
$beschreibung = $this->_ci->input->post('beschreibung', TRUE);
$ort_kurzbz = $this->_ci->input->post('ort_kurzbz', TRUE);
$start_date = $this->_ci->input->post('start_date', TRUE);
$end_date = $this->_ci->input->post('end_date', TRUE);
$result = $this->_ci->kalenderlib->addReservierung($titel, $beschreibung, $ort_kurzbz, $start_date, $end_date);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess('Erfolgreich');
}
private function _checkFilter($filters)
{
$filter_valid = true;
$filter_object = new stdClass();
foreach ($filters as $filter)
{
if ($this->_ci->input->get($filter))
{
$filter_valid = true;
$filter_object->$filter = $this->_ci->input->get($filter);
}
}
if (!$filter_valid)
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
return $filter_object;
}
private function _checkUpdate($updateInfos)
{
$update_valid = false;
$update_object = new stdClass();
foreach (self::ALLOWED_TO_UPDATE as $filter)
{
if (isset($updateInfos[$filter]))
{
$update_valid = true;
$update_object->$filter = $updateInfos[$filter];
}
}
if (!$update_valid)
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
return $update_object;
}
}
@@ -1,231 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Reservierung extends FHCAPI_Controller
{
private $_ci;
/**
* Object initialization
*/
public function __construct()
{
parent::__construct([
'addReservierung' => 'lehre/lvplan:rw',
'getRollen' => 'lehre/lvplan:rw',
'getInformation' => 'lehre/lvplan:rw',
'getLektor' => 'lehre/lvplan:rw',
'searchGroup' => 'lehre/lvplan:rw',
]);
$this->_ci =& get_instance();
$this->_ci->load->library('LogLib');
$this->_ci->load->library('form_validation');
$this->_ci->load->library('KalenderLib');
$this->_ci->load->model('ressource/Ort_model', 'OrtModel');
$this->_ci->load->model('ressource/Kalender_Event_Rolle_model', 'KalenderEventRolleModel');
$this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->_ci->load->model('organisation/gruppe_model', 'GruppeModel');
$this->loadPhrases([
'ui'
]);
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
public function getInformation()
{
$return_array = array('berechtigt' => false, 'studiengaenge' => []);
$this->_ci->OrtModel->db->join("
(select ort,standort_id,strasse, plz
FROM public.tbl_standort
LEFT JOIN public.tbl_adresse USING(adresse_id)
) standort", "standort_id", "LEFT", false);
$raeume = $this->_ci->OrtModel->loadWhere(array('aktiv' => true, 'reservieren' => true));
$return_array['raeume'] = hasData($raeume) ? getData($raeume) : [];
if (!$this->_ci->permissionlib->isBerechtigt('lehre/reservierung'))
$this->terminateWithSuccess($return_array);
$stg_berechtigungen = $this->_ci->permissionlib->getSTG_isEntitledFor('lehre/reservierung');
if (isEmptyArray($stg_berechtigungen))
$this->terminateWithSuccess($return_array);
$this->_ci->StudiengangModel->addSelect('studiengang_kz, UPPER(CONCAT(typ, kurzbz)) as kuerzel, kurzbzlang');
$this->_ci->StudiengangModel->addOrder('typ, kurzbz');
$this->_ci->StudiengangModel->db->where_in('studiengang_kz', $stg_berechtigungen);
$studiengaenge = $this->_ci->StudiengangModel->loadWhere(array('aktiv' => true));
if (isError($studiengaenge))
$this->terminateWithError($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');
$rollen = $this->_ci->KalenderEventRolleModel->load();
$this->_ci->StudiensemesterModel->addOrder('start', 'DESC');
$studiensemester = $this->_ci->StudiensemesterModel->load();
$return_array['studiengaenge'] = hasData($studiengaenge) ? getData($studiengaenge) : [];
$return_array['berechtigt'] = true;
$return_array['rollen'] = hasData($rollen) ? getData($rollen) : [];
$return_array['studiensemester'] = hasData($studiensemester) ? getData($studiensemester) : [];
$this->terminateWithSuccess($return_array);
}
public function getRaeume()
{
$this->_ci->OrtModel->db->join("
(select ort,standort_id,strasse, plz
FROM public.tbl_standort
LEFT JOIN public.tbl_adresse USING(adresse_id)
) standort", "standort_id", "LEFT", false);
$result = $this->_ci->OrtModel->loadWhere(array('aktiv' => true, 'reservieren' => true));
$this->terminateWithSuccess(hasData($result) ? getData($result) : []);
}
public function searchGroup()
{
$query = $this->input->get('query');
if (is_null($query))
$this->terminateWithError($this->_ci->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$stg_berechtigungen = $this->_ci->permissionlib->getSTG_isEntitledFor('lehre/reservierung');
if (isEmptyArray($stg_berechtigungen))
$this->terminateWithSuccess([]);
$query_words = explode(' ', urldecode($query));
$gruppen_result = $this->_ci->GruppeModel->search($query_words);
if (isError($gruppen_result))
$this->terminateWithError(getError($gruppen_result), self::ERROR_TYPE_GENERAL);
$gruppen_array = array();
if (hasData($gruppen_result))
$gruppen_array = getData($gruppen_result);
$lehrverband_result = $this->_ci->LehrverbandModel->search($query_words);
$lehrverband_array = array();
if (isError($lehrverband_result))
$this->terminateWithError(getError($lehrverband_result), self::ERROR_TYPE_GENERAL);
if (hasData($lehrverband_result))
$lehrverband_array = getData($lehrverband_result);
$all_gruppen = array_merge($gruppen_array, $lehrverband_array);
$gefilterte_gruppen = array_filter($all_gruppen, function($gruppe) use ($stg_berechtigungen)
{
return in_array($gruppe->studiengang_kz, $stg_berechtigungen);
});
$this->terminateWithSuccess($gefilterte_gruppen);
}
public function getRollen()
{
$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');
$result = $this->_ci->KalenderEventRolleModel->load();
$this->terminateWithSuccess(hasData($result) ? getData($result) : []);
}
public function addReservierung()
{
$this->_ci->form_validation->set_data($_POST);
$this->_ci->form_validation->set_rules('titel',"titel","required");
$this->_ci->form_validation->set_rules('beschreibung',"beschreibung","required");
$this->_ci->form_validation->set_rules('ort_kurzbz',"ort_kurzbz","required");
$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());
$titel = $this->_ci->input->post('titel', TRUE);
$beschreibung = $this->_ci->input->post('beschreibung', TRUE);
$ort_kurzbz = $this->_ci->input->post('ort_kurzbz', TRUE);
$start_date = $this->_ci->input->post('start_date', TRUE);
$end_date = $this->_ci->input->post('end_date', TRUE);
$teilnehmer = $this->_ci->input->post('teilnehmer', TRUE);
$specialGroups = $this->_ci->input->post('specialGroups', TRUE);
$specialFinalGroups = $this->_ci->input->post('specialFinalGroups', TRUE);
$groups = $this->_ci->input->post('groups', TRUE);
if ($this->_ci->permissionlib->isBerechtigt('lehre/reservierung'))
{
if (empty($teilnehmer) || !is_array($teilnehmer))
{
$teilnehmer[] = array('uid' => getAuthUID(), 'rolle' => 'organisator');
}
}
else
$teilnehmer[] = array('uid' => getAuthUID(), 'rolle' => 'organisator');
$result = $this->_ci->kalenderlib->addReservierung($titel, $beschreibung, $ort_kurzbz, $start_date, $end_date, $teilnehmer, $specialFinalGroups, $specialGroups, $groups);
if (isError($result))
$this->terminateWithError(getError($result));
$this->terminateWithSuccess('Erfolgreich');
}
public function getLektor()
{
$query = $this->input->get('query');
if (is_null($query))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$query_words = explode(' ', $query);
$this->_ci->MitarbeiterModel->addSelect('uid, person_id, vorname, nachname');
$this->_ci->MitarbeiterModel->addJoin('public.tbl_benutzer', 'uid = mitarbeiter_uid');
$this->_ci->MitarbeiterModel->addJoin('public.tbl_person', 'person_id');
$this->_ci->MitarbeiterModel->db->where('public.tbl_benutzer.aktiv', true);
$this->_ci->MitarbeiterModel->db->group_start();
foreach ($query_words as $word)
{
$this->_ci->MitarbeiterModel->db->group_start();
$this->_ci->MitarbeiterModel->db->where('tbl_person.vorname ILIKE', "%" . $word . "%");
$this->_ci->MitarbeiterModel->db->or_where('tbl_person.nachname ILIKE', "%" . $word . "%");
$this->_ci->MitarbeiterModel->db->or_where('uid ILIKE', "%" . $word . "%");
$this->_ci->MitarbeiterModel->db->group_end();
}
$this->_ci->MitarbeiterModel->db->group_end();
$this->_ci->MitarbeiterModel->addOrder('nachname');
$this->_ci->MitarbeiterModel->addOrder('vorname');
$result = $this->_ci->MitarbeiterModel->load();
$this->terminateWithSuccess(hasData($result) ? getData($result) : array());
}
}
@@ -1,27 +0,0 @@
<?php
if (!defined("BASEPATH")) exit("No direct script access allowed");
class TempusJob extends JOB_Controller
{
private $_ci;
public function __construct()
{
parent::__construct();
$this->_ci =& get_instance();
$this->_ci->load->helper('hlp_sancho_helper');
$this->_ci->load->library('KalenderLib');
}
public function sync()
{
$this->_ci->logInfo('Start job FHC-Core->Tempus->sync');
$this->_ci->kalenderlib->sync();
$this->_ci->logInfo('End job FHC-Core->Tempus->sync');
}
}
@@ -1,562 +0,0 @@
<?php
/*
* Job zur einmaligen Migration des Stundenplans
*
* Aufruf
* php index.ci.php system/MigrateKalender
*/
if (! defined('BASEPATH')) exit('No direct script access allowed');
class MigrateKalender extends Auth_Controller
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(array(
'migrateStundenplan' => ['admin:rw'],
'migrateReservierung' => ['admin:rw'],
));
$this->load->model('ressource/Kalender_model', 'KalenderModel');
$this->load->model('ressource/Kalender_Lehreinheit_model', 'KalenderLehreinheitModel');
$this->load->model('ressource/Kalender_Ort_model', 'KalenderOrtModel');
$this->load->model('ressource/Stundenplandev_Kalender_model', 'SyncModel');
$this->load->model('ressource/Reservierung_Kalender_model', 'SyncReservierungModel');
$this->load->model('ressource/Kalender_Event_Teilnehmer_model', 'KalenderEventTeilnehmerModel');
$this->load->model('ressource/Kalender_Event_model', 'KalenderEventModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->load->model('person/Benutzer_model', 'BenutzerModel');
}
/**
* Everything has a beginning
*/
public function migrateStundenplan($von = null, $bis = null, $studiengang_kz = null)
{
$db = new DB_Model();
$stpldevsql = '
WITH eindeutige_stunden AS (
SELECT DISTINCT unr, datum, stunde
FROM lehre.tbl_stundenplandev
WHERE datum >= ? AND datum <= ?';
$params = [$von, $bis];
if (!is_null($studiengang_kz))
{
$stpldevsql .= ' AND studiengang_kz = ?';
$params[] = $studiengang_kz;
}
$stpldevsql .= '),
block_keys AS (
SELECT
unr,
datum,
stunde,
stunde - ROW_NUMBER() OVER (PARTITION BY unr, datum ORDER BY stunde) AS block_nr
FROM eindeutige_stunden
),
blocks AS (
SELECT
bk.unr,
bk.datum,
bk.block_nr,
MIN(bk.stunde) AS stunde_von,
MAX(bk.stunde) AS stunde_bis,
MIN(sp.lehreinheit_id) AS lehreinheit_id,
MIN(sp.ort_kurzbz) AS ort_kurzbz,
array_agg(sp.stundenplandev_id ORDER BY bk.stunde) AS stundenplandev_ids,
MIN(sp.insertamum) AS insertamum,
(array_agg(sp.insertvon ORDER BY sp.insertamum ASC))[1] AS insertvon,
MAX(sp.updateamum) AS updateamum,
(array_agg(sp.updatevon ORDER BY sp.updateamum DESC))[1] AS updatevon
FROM block_keys bk JOIN lehre.tbl_stundenplandev sp ON sp.unr = bk.unr AND sp.datum = bk.datum AND sp.stunde = bk.stunde
WHERE sp.datum >= ? AND sp.datum <= ?
GROUP BY bk.unr, bk.datum, bk.block_nr
)
SELECT
b.stundenplandev_ids,
b.unr,
b.datum,
b.block_nr,
b.lehreinheit_id,
b.ort_kurzbz,
b.datum + stundevon.beginn AS von,
b.datum + stundebis.ende AS bis,
b.insertamum,
b.insertvon,
b.updateamum,
b.updatevon
FROM blocks b
JOIN lehre.tbl_stunde stundevon ON stundevon.stunde = b.stunde_von
JOIN lehre.tbl_stunde stundebis ON stundebis.stunde = b.stunde_bis
ORDER BY b.datum, b.unr, b.block_nr;';
array_push($params, $von, $bis);
$stpldev = $db->execReadOnlyQuery($stpldevsql, $params);
if (hasData($stpldev))
{
// Pruefen ob der Eintrag schon in Sync Tabelle vorhanden ist
// Wenn neuere Änderungen vorhanden dann Update
// Wenn keine Änderungen seit leztem Sync dann Ueberspringen
// Wenn noch nicht vorhanden neu anlegen
// Danach ggf pruefen welceh Eintraege in der zwischenzeit geloescht wurden und
// in der neuen Tabelle auch archivieren oder loeschen
$data = getData($stpldev);
foreach($data as $block)
{
$ids = is_array($block->stundenplandev_ids) ? $block->stundenplandev_ids : explode(',', $block->stundenplandev_ids);
/*$ids = array_map('intval', $ids);*/
$this->SyncModel->db->where('stundenplandev_id IN (' . implode(',', $ids) . ')');
$sync_result = $this->SyncModel->load();
if (!hasData($sync_result))
{
$kalender_id = $this->_insertKalender($block, 'lehreinheit');
if ($kalender_id)
{
$this->_insertSync($block->stundenplandev_ids, $kalender_id);
}
}
else
{
$syncData = getData($sync_result);
$kalender_id = $syncData[0]->kalender_id;
$last_sync = $syncData[0]->lastupdate;
$synced_ids = array_column($syncData, 'stundenplandev_id');
if ($block->updateamum > $last_sync)
{
$this->_updateKalender($kalender_id, $block);
$this->_updateSync($synced_ids, $kalender_id);
}
$fehlende = array_diff($block->stundenplandev_ids, $synced_ids);
if (!empty($fehlende))
{
$this->_insertSync($fehlende, $kalender_id);
}
}
/*if(hasData($SyncResult))
{
//bereits vorhanden
// TODO Update
}
else
{
// Neuen Eintrag anlegen
$von = $rowstpl->datum.' '.$rowstpl->beginn;
$bis = $rowstpl->datum.' '.$rowstpl->ende;
$typ = 'lehreinheit';
$status = 'live';
$insertamum = $rowstpl->insertamum;
$insertvon = $rowstpl->insertvon;
$updateamum = $rowstpl->updateamum;
$updatevon = $rowstpl->updatevon;
$resultKalenderInsert = $this->KalenderModel->insert(
array(
'von' => $von,
'bis' => $bis,
'typ' => $typ,
'status_kurzbz' => $status,
'vorgaenger_kalender_id' => null,
'insertamum' => $insertamum,
'insertvon' => $insertvon,
'updateamum' => $updateamum,
'updatevon' => $updatevon
)
);
if(isSuccess($resultKalenderInsert))
{
$kalender_id = getData($resultKalenderInsert);
$resultKalenderInsert = $this->KalenderLehreinheitModel->insert(
array(
'kalender_id' => $kalender_id,
'lehreinheit_id' => $rowstpl->lehreinheit_id,
)
);
$resultKalenderInsert = $this->KalenderOrtModel->insert(
array(
'kalender_id' => $kalender_id,
'ort_kurzbz' => $rowstpl->ort_kurzbz,
)
);
$resultSyncInsert = $this->SyncModel->insert(
array(
'stundenplandev_id' => $rowstpl->stundenplandev_id,
'kalender_id' => $kalender_id,
'lastupdate' => date('Y-m-d H:i:s')
)
);
}
}*/
}
}
}
public function migrateReservierung($von = null, $bis = null, $ort_kurzbz = null)
{
$db = new DB_Model();
$qry = "WITH eindeutige_stunden AS (
SELECT DISTINCT titel, beschreibung, datum, stunde
FROM campus.tbl_reservierung
WHERE datum >= ? AND datum <= ?";
$params = array($von, $bis);
if (!is_null($ort_kurzbz))
{
$qry .= " AND ort_kurzbz = ?";
$params[] = $ort_kurzbz;
}
$qry .= "),
block_keys AS (
SELECT
titel, beschreibung, datum, stunde,
stunde - ROW_NUMBER() OVER (PARTITION BY titel, beschreibung, datum ORDER BY stunde) AS block_nr
FROM eindeutige_stunden
),
blocks AS (
SELECT
bk.titel,
bk.beschreibung,
bk.datum,
bk.block_nr,
MIN(bk.stunde) AS stunde_von,
MAX(bk.stunde) AS stunde_bis,
array_agg(DISTINCT r.reservierung_id::text) AS reservierung_ids,
array_agg(DISTINCT r.uid) AS uids,
array_agg(DISTINCT r.gruppe_kurzbz) AS gruppen_kurzbz,
array_agg(DISTINCT ROW(r.semester, r.verband, r.gruppe)::text) AS svg_kombis,
MIN(r.ort_kurzbz) AS ort_kurzbz,
MIN(r.studiengang_kz) AS studiengang_kz,
MIN(r.veranstaltung_id) AS veranstaltung_id,
MIN(r.reservierung_id) AS reservierung_id,
MAX(r.insertamum) AS insertamum,
(array_agg(r.insertvon ORDER BY r.insertamum ASC))[1] AS insertvon
FROM block_keys bk
JOIN campus.tbl_reservierung r
ON r.titel = bk.titel AND r.beschreibung = bk.beschreibung AND r.datum = bk.datum AND r.stunde = bk.stunde
WHERE r.datum >= ? AND r.datum <= ?
GROUP BY bk.titel, bk.beschreibung, bk.datum, bk.block_nr
)
SELECT
b.*,
(b.datum + s_von.beginn) AS von,
(b.datum + s_bis.ende) AS bis
FROM blocks b
JOIN lehre.tbl_stunde s_von ON s_von.stunde = b.stunde_von
JOIN lehre.tbl_stunde s_bis ON s_bis.stunde = b.stunde_bis
ORDER BY b.reservierung_id DESC;";
/*$qry = "WITH per_stunde AS (
SELECT
datum,
titel,
beschreibung, ort_kurzbz, studiengang_kz, stunde,
veranstaltung_id,
array_agg(DISTINCT uid) AS uids,
array_agg(DISTINCT reservierung_id::text) AS reservierung_ids,
array_agg(DISTINCT ROW(semester, verband, gruppe)::text) AS svg_kombis,
array_agg(DISTINCT gruppe_kurzbz) AS gruppen_kurzbz,
MIN(reservierung_id) AS reservierung_id,
MAX(insertamum) AS insertamum,
MAX(insertvon) AS insertvon
FROM campus.tbl_reservierung
WHERE datum >= ? AND datum <= ?
GROUP BY datum, titel, beschreibung, ort_kurzbz, studiengang_kz, stunde, veranstaltung_id
),
numbered AS (
SELECT
per_stunde.*,
stunde - ROW_NUMBER() OVER (PARTITION BY datum, titel, beschreibung, ort_kurzbz, studiengang_kz, veranstaltung_id ORDER BY stunde) AS grp
FROM per_stunde
),
grouped AS (
SELECT
MIN(reservierung_id) AS reservierung_id,
ort_kurzbz, studiengang_kz, datum,
MIN(stunde) AS stunde_von,
MAX(stunde) AS stunde_bis,
titel, beschreibung,
array_agg(DISTINCT gruppe_kurzbz_elem) AS gruppen_kurzbz,
array_agg(DISTINCT uid_elem) AS uids,
array_agg(DISTINCT res_id) AS reservierung_ids,
array_agg(DISTINCT svg_elem) AS svg_kombis,
veranstaltung_id,
MAX(insertamum) AS insertamum,
MAX(insertvon) AS insertvon
FROM numbered,
unnest(uids) AS uid_elem,
unnest(reservierung_ids) AS res_id,
unnest(gruppen_kurzbz) AS gruppe_kurzbz_elem,
unnest(svg_kombis) AS svg_elem
GROUP BY datum, titel, beschreibung, ort_kurzbz, studiengang_kz, veranstaltung_id, grp
)
SELECT
grouped.*,
(datum + s_von.beginn) AS von,
(datum + s_bis.ende) AS bis
FROM grouped
JOIN lehre.tbl_stunde s_von ON s_von.stunde = grouped.stunde_von
JOIN lehre.tbl_stunde s_bis ON s_bis.stunde = grouped.stunde_bis
ORDER BY grouped.reservierung_id DESC";*/
array_push($params, $von, $bis);
$reservierung_data = $db->execReadOnlyQuery($qry, $params);
if (hasData($reservierung_data))
{
$data = getData($reservierung_data);
foreach($data as $block)
{
$ids = is_array($block->reservierung_ids) ? $block->reservierung_ids : explode(',', $block->reservierung_ids);
$this->SyncReservierungModel->db->where('reservierung_id IN (' . implode(',', $ids) . ')');
$sync_result = $this->SyncReservierungModel->load();
if (!hasData($sync_result))
{
$kalender_id = $this->_insertKalender($block, 'reservierung');
if ($kalender_id)
{
$this->_insertReservierungSync($block->reservierung_ids, $kalender_id);
}
}
else
{
$syncData = getData($sync_result);
$kalender_id = $syncData[0]->kalender_id;
$last_sync = $syncData[0]->lastupdate;
$synced_ids = array_column($syncData, 'reservierung_id');
if ($block->insertamum > $last_sync)
{
$this->_updateKalender($kalender_id, $block);
$this->_updateReservierungSync($synced_ids, $kalender_id);
}
$fehlende = array_diff($block->reservierung_ids, $synced_ids);
if (!empty($fehlende))
{
$this->_insertReservierungSync($fehlende, $kalender_id);
}
}
}
}
}
private function _insertKalender($block, $typ)
{
$result = $this->KalenderModel->insert(
array (
'von' => $block->von,
'bis' => $block->bis,
'typ' => $typ,
'status_kurzbz'=> 'live',
'insertamum' => $block->insertamum,
'insertvon' => $block->insertvon,
'updateamum' => $block->updateamum ?? null,
'updatevon' => $block->updatevon ?? null
)
);
if(!isSuccess($result))
return null;
$kalender_id = getData($result);
if ($typ === 'lehreinheit')
{
$this->KalenderLehreinheitModel->insert(
array (
'kalender_id' => $kalender_id,
'lehreinheit_id'=> $block->lehreinheit_id
)
);
}
else if ($typ === 'reservierung')
{
$this->KalenderEventModel->insert(array(
'kalender_id' => $kalender_id,
'titel' => $block->titel,
'beschreibung' => $block->beschreibung
));
if ($block->insertvon)
{
$user = $this->BenutzerModel->load(array('uid' => $block->insertvon));
if (hasData($user))
{
$this->KalenderEventTeilnehmerModel->insert(array(
'kalender_id' => $kalender_id,
'uid' => getData($user)[0]->uid,
'rolle_kurzbz' => 'organisator'
));
}
}
$uids = is_array($block->uids) ? $block->uids : explode(',', $block->uids);
foreach ($uids as $uid)
{
$this->KalenderEventTeilnehmerModel->insert(array(
'kalender_id' => $kalender_id,
'uid' => $uid,
'rolle_kurzbz' => 'teilnehmer'
));
}
$semester_range = $this->StudiensemesterModel->getByDateRange($block->von, $block->bis);
if (isError($semester_range)) return $semester_range;
$studiensemester_kurzbz = getData($semester_range)[0]->studiensemester_kurzbz ?? null;
$gruppen = is_array($block->gruppen_kurzbz) ? $block->gruppen_kurzbz : explode(',', $block->gruppen_kurzbz ?? '');
foreach ($gruppen as $gruppe_kurzbz)
{
$gruppe_kurzbz = trim($gruppe_kurzbz);
if (!empty($gruppe_kurzbz))
{
$this->KalenderEventTeilnehmerModel->insert(array(
'kalender_id' => $kalender_id,
'gruppe_kurzbz' => $gruppe_kurzbz,
'studiengang_kz' => $block->studiengang_kz,
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'rolle_kurzbz' => 'teilnehmer'
));
}
}
foreach ($block->svg_kombis as $kombi_str)
{
$kombi_str = trim($kombi_str, '()');
list($sem, $verb, $grp) = explode(',', $kombi_str);
$sem = trim($sem) === '' ? null : trim($sem);
$verb = trim($verb) === '' ? null : trim($verb);
$grp = trim($grp) === '' ? null : trim($grp);
if (is_null($sem) && is_null($verb) && is_null($grp))
continue;
$this->KalenderEventTeilnehmerModel->insert(array(
'kalender_id' => $kalender_id,
'studiengang_kz' => $block->studiengang_kz,
'semester' => $sem,
'verband' => $verb,
'gruppe' => $grp,
'studiensemester_kurzbz' => $studiensemester_kurzbz,
'rolle_kurzbz' => 'teilnehmer'
));
}
}
$this->KalenderOrtModel->insert(
array (
'kalender_id' => $kalender_id,
'ort_kurzbz' => $block->ort_kurzbz
)
);
return $kalender_id;
}
private function _insertSync($ids, $kalender_id)
{
foreach($ids as $id)
{
$this->SyncModel->insert(
array (
'stundenplandev_id' => $id,
'kalender_id' => $kalender_id,
'lastupdate' => date('Y-m-d H:i:s')
)
);
}
}
private function _insertReservierungSync($ids, $kalender_id)
{
foreach($ids as $id)
{
$this->SyncReservierungModel->insert(
array (
'reservierung_id' => $id,
'kalender_id' => $kalender_id,
'lastupdate' => date('Y-m-d H:i:s')
)
);
}
}
private function _updateKalender($kalender_id, $block)
{
$this->KalenderModel->update(
array (
'kalender_id' => $kalender_id
),
array (
'von' => $block->von,
'bis' => $block->bis,
'updateamum'=> $block->updateamum,
'updatevon' => $block->updatevon
)
);
}
private function _updateSync($ids, $kalender_id)
{
foreach($ids as $id)
{
$this->SyncModel->update(
array (
'stundenplandev_id' => $id,
'kalender_id' => $kalender_id
),
array (
'lastupdate' => date('Y-m-d H:i:s')
)
);
}
}
private function _updateReservierungSync($ids, $kalender_id)
{
foreach($ids as $id)
{
$this->SyncReservierungModel->update(
array (
'reservierung_id' => $id,
'kalender_id' => $kalender_id
),
array (
'lastupdate' => date('Y-m-d H:i:s')
)
);
}
}
}
-10
View File
@@ -1,10 +0,0 @@
<?php
interface ICollisionCheck
{
public function getName();
public function check($data);
public function checkAll($kalender_ids);
}
+1
View File
@@ -417,6 +417,7 @@ abstract class Notiz_Controller extends FHCAPI_Controller
$notiz_id = $this->input->post('notiz_id');
$this->NotizModel->addSelect('campus.tbl_dms_version.*');
$this->NotizModel->addSelect($this->NotizModel->escape(base_url('content/notizdokdownload.php?id=')) . ' || public.tbl_notiz_dokument.dms_id AS preview');
$this->NotizModel->addJoin('public.tbl_notiz_dokument', 'ON (public.tbl_notiz_dokument.notiz_id = public.tbl_notiz.notiz_id)');
$this->NotizModel->addJoin('campus.tbl_dms_version', 'ON (public.tbl_notiz_dokument.dms_id = campus.tbl_dms_version.dms_id)');
+1 -1
View File
@@ -128,7 +128,7 @@ class AntragLib
return $this->_ci->StudierendenantragstatusModel->resumeAntraegeForAbmeldungStgl($antrag_id);
}
// NOTE(chris): get last status that is not pause
$this->_ci->StudierendenantragstatusModel->addOrder('insertamum');
$this->_ci->StudierendenantragstatusModel->addOrder('insertamum', 'DESC');
$this->_ci->StudierendenantragstatusModel->addLimit(1);
$result = $this->_ci->StudierendenantragstatusModel->loadWhere([
'studierendenantrag_id' => $antrag_id,
@@ -1,65 +0,0 @@
<?php
defined('BASEPATH') || exit('No direct script access allowed');
use CI3_Events as Events;
class CollisionChecker
{
private $_checks = [];
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->library('collision/checks/RoomCollisionCheck');
$this->_ci->load->library('collision/checks/LectureCollisionCheck');
$this->_ci->load->library('collision/checks/VerbandCollisionCheck');
$this->_ci->load->library('collision/checks/StudentCollisionCheck');
$this->register($this->_ci->roomcollisioncheck);
$this->register($this->_ci->lecturecollisioncheck);
$this->register($this->_ci->verbandcollisioncheck);
$this->register($this->_ci->studentcollisioncheck);
Events::trigger('collision_register', $this);
}
public function register(ICollisionCheck $check)
{
$this->_checks[$check->getName()] = $check;
}
public function run($data)
{
$errors = [];
foreach ($this->_checks as $check)
{
$result = $check->check($data);
if (!empty($result))
{
$errors[] = $result;
}
}
return $errors;
}
public function runAll($kalender_ids)
{
$results = array_fill_keys($kalender_ids, []);
foreach ($this->_checks as $check)
{
$batchResult = $check->checkAll($kalender_ids);
foreach ($batchResult as $kalender_id => $errors)
{
$results[$kalender_id] = array_merge($results[$kalender_id], $errors);
}
}
return $results;
}
}
File diff suppressed because it is too large Load Diff
@@ -1,170 +0,0 @@
<?php
if (! defined("BASEPATH")) exit("No direct script access allowed");
class KalenderNotificationLib
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->library('MailLib');
$this->_ci->load->config('tempus');
}
public function sendMails($mail_infos)
{
if (!$this->_ci->config->item('send_update_mails'))
return true;
$lektor_added = array();
$lektor_changed = array();
$lektor_deleted = array();
$student_added = array();
$student_changed = array();
$student_deleted = array();
foreach ($mail_infos as $info)
{
$entry = $info['entry'];
$new_status = $info['new_status'];
$notify = $info['notify'];
$old_entry = null;
if ($entry->vorgaenger_kalender_id)
{
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'tbl_kalender.kalender_id = tbl_kalender_ort.kalender_id', 'LEFT');
$vorgaenger = $this->_ci->KalenderModel->load(array('tbl_kalender.kalender_id' => $entry->vorgaenger_kalender_id));
if (hasData($vorgaenger))
$old_entry = getData($vorgaenger)[0];
}
if ($new_status === 'deleted')
$row = $this->_buildMailDeleted($entry);
else if ($old_entry)
$row = $this->_buildMailChanged($old_entry, $entry);
else
$row = $this->_buildMailNew($entry);
if (in_array('lektor', $notify))
{
if ($new_status === 'deleted')
$lektor_deleted[] = $row;
else if ($old_entry)
$lektor_changed[] = $row;
else
$lektor_added[] = $row;
}
if (in_array('student', $notify))
{
if ($new_status === 'deleted')
$student_deleted[] = $row;
else if ($old_entry)
$student_changed[] = $row;
else
$student_added[] = $row;
}
}
$lektor_entries = '';
$student_entries = '';
if (!empty($lektor_added))
$lektor_entries .= $this->_addToList($lektor_added, 'hinzugefügt') . '<hr/>';
if (!empty($lektor_changed))
$lektor_entries .= $this->_addToList($lektor_changed, 'geändert') . '<hr/>';
if (!empty($lektor_deleted))
$lektor_entries .= $this->_addToList($lektor_deleted, 'gelöscht') . '<hr/>';
if (!empty($student_added))
$student_entries .= $this->_addToList($student_added, 'hinzugefügt') . '<hr/>';
if (!empty($student_changed))
$student_entries .= $this->_addToList($student_changed, 'geändert') . '<hr/>';
if (!empty($student_deleted))
$student_entries .= $this->_addToList($student_deleted, 'gelöscht') . '<hr/>';
if (!empty($lektor_entries))
$this->_ci->maillib->send('', 'ma0048@technikum-wien.at', 'Lektor Tempus Update', $lektor_entries);
if (!empty($student_entries))
$this->_ci->maillib->send('', 'ma0048@technikum-wien.at', 'Student Tempus Update', $student_entries);
}
private function _addToList($entries, $status)
{
return 'Folgende Einträge wurden <b>'. $status .'</b>: <ul>' . implode('', $entries) . '</ul>';
}
private function _buildMailNew($entry)
{
$von = date('d.m.Y H:i', strtotime($entry->von));
$bis = date('H:i', strtotime($entry->bis));
return '<li>
<b>Kalender ID ' . ($entry->kalender_id ?? '-') . '</b>
<ul>
<li><b>Uhrzeit:</b> ' . $von . ' - ' . $bis . '</li>
<li><b>Ort:</b> ' . ($entry->ort_kurzbz ?? '-') . '</li>
</ul>
</li>';
}
private function _buildMailChanged($old_entry, $new_entry)
{
$old_von = date('d.m.Y H:i', strtotime($old_entry->von));
$old_bis = date('H:i', strtotime($old_entry->bis));
$new_von = date('d.m.Y H:i', strtotime($new_entry->von));
$new_bis = date('H:i', strtotime($new_entry->bis));
$old_ort = $old_entry->ort_kurzbz ?? '-';
$new_ort = $new_entry->ort_kurzbz ?? '-';
$uhrzeit_changed = ($old_von . $old_bis) !== ($new_von . $new_bis);
$ort_changed = $old_ort !== $new_ort;
$changes = '';
if ($uhrzeit_changed)
{
$changes .= '<li>
<b>Uhrzeit:</b>
<s style="color:red;">' . $old_von . ' - ' . $old_bis . '</s>
<span style="color:green;">' . $new_von . ' - ' . $new_bis . '</span>
</li>';
}
if ($ort_changed)
{
$changes .= '<li>
<b>Ort:</b>
<s style="color:red;">' . $old_ort . '</s>
<span style="color:green;">' . $new_ort . '</span>
</li>';
}
return '<li>
<b>Kalender ID ' . ($new_entry->kalender_id ?? '-') . '</b>
<ul>' . $changes . '</ul>
</li>';
}
private function _buildMailDeleted($entry)
{
$von = date('d.m.Y H:i', strtotime($entry->von));
$bis = date('H:i', strtotime($entry->bis));
return '<li style="color:red;">
<b><s>Kalender ID ' . ($entry->kalender_id ?? '-') . '</s></b>
<ul>
<li><s>' . $von . ' - ' . $bis . '</s></li>
<li><s>' . ($entry->ort_kurzbz ?? '-') . '</s></li>
</ul>
</li>';
}
}
@@ -1,226 +0,0 @@
<?php
class LectureCollisionCheck implements ICollisionCheck
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->model('ressource/zeitsperre_model', 'ZeitsperreModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
public function getName()
{
return 'lecture';
}
public function check($data)
{
if (!isset($data->von, $data->bis, $data->kalender_id)) return [];
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
$uids = $this->_getUids($data->kalender_id);
if (empty($uids)) return [];
$collisions = [];
$collisions = array_merge($collisions, $this->_checkLehreinheit($uids, $data));
$collisions = array_merge($collisions, $this->_checkReservierung($uids, $data));
$collisions = array_merge($collisions, $this->_checkZeitsperre($uids, $data));
return $collisions;
}
public function checkAll($kalender_ids)
{
if (empty($kalender_ids)) return [];
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$grouped = [];
$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');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit current_lehreinheit', 'current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter current_lehreinheit_ma', 'current_lehreinheit_ma.lehreinheit_id = current_lehreinheit.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter other_lehreinheithreinheit_ma', 'other_lehreinheithreinheit_ma.mitarbeiter_uid = current_lehreinheit_ma.mitarbeiter_uid');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit other_lehreinheit', 'other_lehreinheit.lehreinheit_id = other_lehreinheithreinheit_ma.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit other_kalender_le', 'other_kalender_le.lehreinheit_id = other_lehreinheit.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.kalender_id = other_kalender_le.kalender_id');
$this->_ci->KalenderModel->db->where('other_kalender.kalender_id != tbl_kalender.kalender_id', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.von < tbl_kalender.bis', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.bis > tbl_kalender.von', null, false);
$this->_ci->KalenderModel->db->where_not_in('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']);
$this->_ci->KalenderModel->db->where_not_in('current_lehreinheit_ma.mitarbeiter_uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids);
$this->_ci->KalenderModel->db->where(
'other_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)',
null, false
);
$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');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit current_lehreinheit', 'current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter current_lehreinheit_ma', 'current_lehreinheit_ma.lehreinheit_id = current_lehreinheit.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer other_t', 'other_t.uid = current_lehreinheit_ma.mitarbeiter_uid');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event other_e', 'other_e.kalender_id = other_t.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.kalender_id = other_e.kalender_id');
$this->_ci->KalenderModel->db->where('other_kalender.kalender_id != tbl_kalender.kalender_id', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.von < tbl_kalender.bis', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.bis > tbl_kalender.von', null, false);
$this->_ci->KalenderModel->db->where_not_in('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']);
$this->_ci->KalenderModel->db->where_not_in('current_lehreinheit_ma.mitarbeiter_uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids);
$this->_ci->KalenderModel->db->where(
'other_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)',
null, false
);
$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');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit current_lehreinheit', 'current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter current_lehreinheit_ma', 'current_lehreinheit_ma.lehreinheit_id = current_lehreinheit.lehreinheit_id');
$this->_ci->KalenderModel->addJoin('campus.tbl_zeitsperre z',
"z.mitarbeiter_uid = current_lehreinheit_ma.mitarbeiter_uid AND z.zeitsperretyp_kurzbz != 'ZVerfueg' AND z.vondatum < tbl_kalender.bis AND z.bisdatum > tbl_kalender.von");
$this->_ci->KalenderModel->db->where_not_in('current_lehreinheit_ma.mitarbeiter_uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids);
$result = $this->_ci->KalenderModel->load();
if (!isError($result) && hasData($result))
foreach (getData($result) as $row)
$grouped[$row->kalender_id][] = true;
return $grouped;
}
private function _getUids($kalender_id)
{
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$this->_ci->KalenderModel->addDistinct('mitarbeiter_uid, tbl_kalender_event_teilnehmer.uid');
$this->_ci->KalenderModel->addSelect('mitarbeiter_uid, tbl_kalender_event_teilnehmer.uid');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'kalender_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter', 'lehreinheit_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event', 'kalender_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer', 'tbl_kalender_event.kalender_id = tbl_kalender_event_teilnehmer.kalender_id', 'LEFT');
$this->_ci->KalenderModel->db->where_not_in('mitarbeiter_uid', $kollisionsfreie_user);
$result = $this->_ci->KalenderModel->loadWhere(array(
'tbl_kalender.kalender_id' => $kalender_id
));
if (isError($result) || !hasData($result)) return [];
$data = getData($result);
$mitarbeiter_uids = array_filter(array_column($data, 'mitarbeiter_uid'));
$event_teilnehmer = array_filter(array_column($data, 'uid'));
return array_unique(array_merge($mitarbeiter_uids, $event_teilnehmer));
}
private function _checkLehreinheit($uids, $data)
{
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$this->_ci->KalenderModel->addDistinct('mitarbeiter_uid, tbl_kalender.von, tbl_kalender.bis');
$this->_ci->KalenderModel->addSelect('mitarbeiter_uid, tbl_kalender.von, tbl_kalender.bis');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_lehreinheit', 'kalender_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_lehreinheitmitarbeiter', 'lehreinheit_id', 'LEFT');
$this->_ci->KalenderModel->db->where_in('mitarbeiter_uid', $uids);
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $data->kalender_id);
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete'));
$this->_ci->KalenderModel->db->where_not_in('mitarbeiter_uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->where(
'tbl_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)',
null, false
);
$result = $this->_ci->KalenderModel->loadWhere(array(
'von <' => $data->bis,
'bis >' => $data->von,
));
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)) . ')';
}, getData($result));
}
private function _checkReservierung($uids, $data)
{
if ($this->_ci->variablelib->getVar('ignore_reservierung') === 'true') return [];
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$this->_ci->KalenderModel->addDistinct('tbl_kalender_event_teilnehmer.uid, tbl_kalender.von, tbl_kalender.bis');
$this->_ci->KalenderModel->addSelect('tbl_kalender_event_teilnehmer.uid, tbl_kalender.von, tbl_kalender.bis');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event', 'kalender_id', 'LEFT');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_event_teilnehmer', 'tbl_kalender_event.kalender_id = tbl_kalender_event_teilnehmer.kalender_id', 'LEFT');
$this->_ci->KalenderModel->db->where_in('tbl_kalender_event_teilnehmer.uid', $uids);
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $data->kalender_id);
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', array('archived', 'deleted', 'to_delete'));
$this->_ci->KalenderModel->db->where_not_in('uid', $kollisionsfreie_user);
$this->_ci->KalenderModel->db->where(
'tbl_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)',
null, false
);
$result = $this->_ci->KalenderModel->loadWhere(array(
'von <' => $data->bis,
'bis >' => $data->von,
));
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)) . ')';
}, getData($result));
}
private function _checkZeitsperre($uids, $data)
{
if ($this->_ci->variablelib->getVar('ignore_zeitsperre') === 'true') return [];
$this->_ci->ZeitsperreModel->addSelect('mitarbeiter_uid, vondatum as von, bisdatum as bis');
$this->_ci->ZeitsperreModel->db->where('zeitsperretyp_kurzbz !=', 'ZVerfueg');
$this->_ci->ZeitsperreModel->db->where_in('mitarbeiter_uid', $uids);
$result = $this->_ci->ZeitsperreModel->loadWhere(array(
'vondatum <' => date('Y-m-d', strtotime($data->von)),
'bisdatum >' => date('Y-m-d', strtotime($data->bis)),
));
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->von)) . ' - ' . date('d.m.Y H:i', strtotime($row->bis)) . ')';
}, getData($result));
}
}
@@ -1,75 +0,0 @@
<?php
class RoomCollisionCheck implements ICollisionCheck
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
public function getName()
{
return 'room';
}
public function check($data)
{
if (!isset($data->ort_kurzbz, $data->von, $data->bis, $data->kalender_id)) return [];
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
$this->_ci->KalenderModel->addSelect('kalender_id, ort_kurzbz, von, bis');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort', 'kalender_id');
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id !=', $data->kalender_id);
$this->_ci->KalenderModel->db->where('tbl_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', null, false);
$this->_ci->KalenderModel->db->where_not_in('tbl_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']);
$result = $this->_ci->KalenderModel->loadWhere(array(
'von <' => $data->bis,
'bis >' => $data->von,
'ort_kurzbz' => $data->ort_kurzbz,
));
if (isError($result)) return [];
if (!hasData($result)) return [];
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)) . ')';
}, getData($result));
}
public function checkAll($kalender_ids)
{
if (empty($kalender_ids)) return [];
$this->_ci->KalenderModel->addSelect('DISTINCT ON (tbl_kalender.kalender_id) tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort current_ort', 'current_ort.kalender_id = tbl_kalender.kalender_id');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender_ort other_ort', 'other_ort.ort_kurzbz = current_ort.ort_kurzbz');
$this->_ci->KalenderModel->addJoin('lehre.tbl_kalender other_kalender', 'other_kalender.kalender_id = other_ort.kalender_id');
$this->_ci->KalenderModel->db->where('other_kalender.kalender_id != tbl_kalender.kalender_id', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.von < tbl_kalender.bis', null, false);
$this->_ci->KalenderModel->db->where('other_kalender.bis > tbl_kalender.von', null, false);
$this->_ci->KalenderModel->db->where_not_in('other_kalender.status_kurzbz', ['archived', 'deleted', 'to_delete']);
$this->_ci->KalenderModel->db->where_in('tbl_kalender.kalender_id', $kalender_ids);
$this->_ci->KalenderModel->db->where('other_kalender.kalender_id NOT IN (SELECT vorgaenger_kalender_id FROM lehre.tbl_kalender WHERE vorgaenger_kalender_id IS NOT NULL)', null, false);
$result = $this->_ci->KalenderModel->load();
if (isError($result) || !hasData($result)) return [];
$grouped = [];
foreach (getData($result) as $row)
$grouped[$row->kalender_id][] = true;
return $grouped;
}
}
@@ -1,238 +0,0 @@
<?php
class StudentCollisionCheck implements ICollisionCheck
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
public function getName()
{
return 'student';
}
public function check($data)
{
if (!isset($data->von, $data->bis, $data->kalender_id)) return [];
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
if ($this->_ci->variablelib->getVar('kollision_student') !== 'true') return [];
$kollisionsfreie_user = unserialize(KOLLISIONSFREIE_USER);
$placeholders = implode(',', array_fill(0, count($kollisionsfreie_user), '?'));
$dbModel = new DB_Model();
$qry1 = "
SELECT DISTINCT tbl_benutzergruppe.uid
FROM lehre.tbl_kalender
JOIN lehre.tbl_kalender_lehreinheit USING(kalender_id)
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
JOIN public.tbl_gruppe
ON tbl_gruppe.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND tbl_gruppe.semester = tbl_lehreinheitgruppe.semester
AND tbl_gruppe.gruppe_kurzbz = tbl_lehreinheitgruppe.gruppe_kurzbz
JOIN public.tbl_benutzergruppe ON tbl_benutzergruppe.gruppe_kurzbz = tbl_gruppe.gruppe_kurzbz
AND tbl_benutzergruppe.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz
WHERE tbl_kalender.kalender_id = ?
AND tbl_benutzergruppe.uid NOT IN ($placeholders)
UNION ALL
SELECT DISTINCT tbl_studentlehrverband.student_uid AS uid
FROM lehre.tbl_kalender
JOIN lehre.tbl_kalender_lehreinheit USING(kalender_id)
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
JOIN public.tbl_studentlehrverband
ON tbl_studentlehrverband.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND tbl_studentlehrverband.semester = tbl_lehreinheitgruppe.semester
AND tbl_studentlehrverband.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz
AND (tbl_lehreinheitgruppe.verband = tbl_studentlehrverband.verband OR tbl_lehreinheitgruppe.verband IS NULL OR btrim(tbl_lehreinheitgruppe.verband::text) = '' OR tbl_studentlehrverband.verband IS NULL)
AND (tbl_lehreinheitgruppe.gruppe = tbl_studentlehrverband.gruppe OR tbl_lehreinheitgruppe.gruppe IS NULL OR btrim(tbl_lehreinheitgruppe.gruppe::text) = '' OR tbl_studentlehrverband.gruppe IS NULL)
WHERE tbl_kalender.kalender_id = ?
AND tbl_studentlehrverband.student_uid NOT IN ($placeholders)
";
$result1 = $dbModel->execReadOnlyQuery($qry1, array_merge(
[$data->kalender_id],
$kollisionsfreie_user,
[$data->kalender_id],
$kollisionsfreie_user
));
if (isError($result1) || !hasData($result1)) return [];
$curUids = array_flip(array_column(getData($result1), 'uid'));
$qry2 = "
SELECT DISTINCT tbl_kalender.kalender_id, tbl_kalender.von, tbl_kalender.bis, tbl_benutzergruppe.uid
FROM lehre.tbl_kalender
JOIN lehre.tbl_kalender_lehreinheit ON tbl_kalender_lehreinheit.kalender_id = tbl_kalender.kalender_id
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
JOIN public.tbl_gruppe
ON tbl_gruppe.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND tbl_gruppe.semester = tbl_lehreinheitgruppe.semester
AND tbl_gruppe.gruppe_kurzbz = tbl_lehreinheitgruppe.gruppe_kurzbz
JOIN public.tbl_benutzergruppe ON tbl_benutzergruppe.gruppe_kurzbz = tbl_gruppe.gruppe_kurzbz
AND tbl_benutzergruppe.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz
WHERE tbl_kalender.von < ?
AND tbl_kalender.bis > ?
AND tbl_kalender.kalender_id != ?
AND tbl_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND tbl_benutzergruppe.uid NOT IN ($placeholders)
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
WHERE vorgaenger.vorgaenger_kalender_id = tbl_kalender.kalender_id
)
UNION ALL
SELECT DISTINCT tbl_kalender.kalender_id, tbl_kalender.von, tbl_kalender.bis, tbl_studentlehrverband.student_uid AS uid
FROM lehre.tbl_kalender
JOIN lehre.tbl_kalender_lehreinheit ON tbl_kalender_lehreinheit.kalender_id = tbl_kalender.kalender_id
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
JOIN public.tbl_studentlehrverband
ON tbl_studentlehrverband.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND tbl_studentlehrverband.semester = tbl_lehreinheitgruppe.semester
AND tbl_studentlehrverband.studiensemester_kurzbz = tbl_lehreinheit.studiensemester_kurzbz
AND (tbl_lehreinheitgruppe.verband = tbl_studentlehrverband.verband OR tbl_lehreinheitgruppe.verband IS NULL OR btrim(tbl_lehreinheitgruppe.verband::text) = '' OR tbl_studentlehrverband.verband IS NULL)
AND (tbl_lehreinheitgruppe.gruppe = tbl_studentlehrverband.gruppe OR tbl_lehreinheitgruppe.gruppe IS NULL OR btrim(tbl_lehreinheitgruppe.gruppe::text) = '' OR tbl_studentlehrverband.gruppe IS NULL)
WHERE tbl_kalender.von < ?
AND tbl_kalender.bis > ?
AND tbl_kalender.kalender_id != ?
AND tbl_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND tbl_studentlehrverband.student_uid NOT IN ($placeholders)
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
WHERE vorgaenger.vorgaenger_kalender_id = tbl_kalender.kalender_id
)
";
$result2 = $dbModel->execReadOnlyQuery($qry2, array_merge(
[$data->bis, $data->von, $data->kalender_id],
$kollisionsfreie_user,
[$data->bis, $data->von, $data->kalender_id],
$kollisionsfreie_user
));
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)) . ')';
}
}
return $conflicts;
}
public function checkAll($kalender_ids)
{
if (empty($kalender_ids)) return [];
if ($this->_ci->variablelib->getVar('kollision_student') !== 'true') return [];
$dbModel = new DB_Model();
$placeholders = implode(',', array_fill(0, count($kalender_ids), '?'));
$sql = "
SELECT DISTINCT current_kalender.kalender_id, current_benutzergruppe.uid
FROM lehre.tbl_kalender current_kalender
JOIN lehre.tbl_kalender_lehreinheit current_kalender_le ON current_kalender_le.kalender_id = current_kalender.kalender_id
JOIN lehre.tbl_lehreinheit current_lehreinheit ON current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe current_lehreinheitgruppe ON current_lehreinheitgruppe.lehreinheit_id = current_lehreinheit.lehreinheit_id
JOIN public.tbl_gruppe current_gruppe
ON current_gruppe.studiengang_kz = current_lehreinheitgruppe.studiengang_kz
AND current_gruppe.semester = current_lehreinheitgruppe.semester
AND current_gruppe.gruppe_kurzbz = current_lehreinheitgruppe.gruppe_kurzbz
JOIN public.tbl_benutzergruppe current_benutzergruppe ON current_benutzergruppe.gruppe_kurzbz = current_gruppe.gruppe_kurzbz
AND current_benutzergruppe.studiensemester_kurzbz = current_lehreinheit.studiensemester_kurzbz
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.kalender_id != current_kalender.kalender_id
AND other_kalender.von < current_kalender.bis
AND other_kalender.bis > current_kalender.von
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
WHERE vorgaenger.vorgaenger_kalender_id = other_kalender.kalender_id
)
JOIN lehre.tbl_kalender_lehreinheit other_kalender_le ON other_kalender_le.kalender_id = other_kalender.kalender_id
JOIN lehre.tbl_lehreinheit other_lehreinheit ON other_lehreinheit.lehreinheit_id = other_kalender_le.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe other_lehreinheitgruppe ON other_lehreinheitgruppe.lehreinheit_id = other_lehreinheit.lehreinheit_id
JOIN public.tbl_gruppe other_gruppe
ON other_gruppe.studiengang_kz = other_lehreinheitgruppe.studiengang_kz
AND other_gruppe.semester = other_lehreinheitgruppe.semester
AND other_gruppe.gruppe_kurzbz = other_lehreinheitgruppe.gruppe_kurzbz
JOIN public.tbl_benutzergruppe other_benutzergruppe
ON other_benutzergruppe.gruppe_kurzbz = other_gruppe.gruppe_kurzbz
AND other_benutzergruppe.uid = current_benutzergruppe.uid
AND other_benutzergruppe.studiensemester_kurzbz = other_lehreinheit.studiensemester_kurzbz
WHERE current_kalender.kalender_id IN ($placeholders)
UNION ALL
SELECT DISTINCT current_kalender.kalender_id, current_studentlehrverband.student_uid AS uid
FROM lehre.tbl_kalender current_kalender
JOIN lehre.tbl_kalender_lehreinheit current_kalender_le ON current_kalender_le.kalender_id = current_kalender.kalender_id
JOIN lehre.tbl_lehreinheit current_lehreinheit ON current_lehreinheit.lehreinheit_id = current_kalender_le.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe current_lehreinheitgruppe ON current_lehreinheitgruppe.lehreinheit_id = current_lehreinheit.lehreinheit_id
JOIN public.tbl_studentlehrverband current_studentlehrverband
ON current_studentlehrverband.studiengang_kz = current_lehreinheitgruppe.studiengang_kz
AND current_studentlehrverband.semester = current_lehreinheitgruppe.semester
AND current_studentlehrverband.studiensemester_kurzbz = current_lehreinheit.studiensemester_kurzbz
AND (current_lehreinheitgruppe.verband = current_studentlehrverband.verband OR current_lehreinheitgruppe.verband IS NULL OR btrim(current_lehreinheitgruppe.verband::text) = '' OR current_studentlehrverband.verband IS NULL)
AND (current_lehreinheitgruppe.gruppe = current_studentlehrverband.gruppe OR current_lehreinheitgruppe.gruppe IS NULL OR btrim(current_lehreinheitgruppe.gruppe::text) = '' OR current_studentlehrverband.gruppe IS NULL)
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.kalender_id != current_kalender.kalender_id
AND other_kalender.von < current_kalender.bis
AND other_kalender.bis > current_kalender.von
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND NOT EXISTS (
SELECT 1 FROM lehre.tbl_kalender vorgaenger
WHERE vorgaenger.vorgaenger_kalender_id = other_kalender.kalender_id
)
JOIN lehre.tbl_kalender_lehreinheit other_kalender_le ON other_kalender_le.kalender_id = other_kalender.kalender_id
JOIN lehre.tbl_lehreinheit other_lehreinheit ON other_lehreinheit.lehreinheit_id = other_kalender_le.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe other_lehreinheitgruppe ON other_lehreinheitgruppe.lehreinheit_id = other_lehreinheit.lehreinheit_id
JOIN public.tbl_studentlehrverband other_slv
ON other_slv.studiengang_kz = other_lehreinheitgruppe.studiengang_kz
AND other_slv.semester = other_lehreinheitgruppe.semester
AND other_slv.studiensemester_kurzbz = other_lehreinheit.studiensemester_kurzbz
AND other_slv.student_uid = current_studentlehrverband.student_uid
AND (other_lehreinheitgruppe.verband = other_slv.verband OR other_lehreinheitgruppe.verband IS NULL OR btrim(other_lehreinheitgruppe.verband::text) = '' OR other_slv.verband IS NULL)
AND (other_lehreinheitgruppe.gruppe = other_slv.gruppe OR other_lehreinheitgruppe.gruppe IS NULL OR btrim(other_lehreinheitgruppe.gruppe::text) = '' OR other_slv.gruppe IS NULL)
WHERE current_kalender.kalender_id IN ($placeholders)
";
$result = $dbModel->execReadOnlyQuery($sql, array_merge($kalender_ids, $kalender_ids));
if (isError($result) || !hasData($result)) return [];
$grouped = [];
foreach (getData($result) as $row)
$grouped[$row->kalender_id][] = true;
return $grouped;
}
}
@@ -1,350 +0,0 @@
<?php
class VerbandCollisionCheck implements ICollisionCheck
{
private $_ci;
public function __construct()
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Kalender_model', 'KalenderModel');
$this->_ci->load->library('VariableLib', array('uid' => getAuthUID()));
$this->_ci->load->library('PhrasesLib', array('ui'));
}
public function getName()
{
return 'verband';
}
public function check($data)
{
if (!isset($data->von, $data->bis, $data->kalender_id)) return [];
if ($this->_ci->variablelib->getVar('ignore_kollision') === 'true') return [];
$kollision_student = $this->_ci->variablelib->getVar('kollision_student') === 'false';
$kollision_reservierung = $this->_ci->variablelib->getVar('ignore_reservierung') === 'false';
if (!$kollision_student && !$kollision_reservierung) return [];
$dbModel = new DB_Model();
$collisions = [];
if ($kollision_student)
{
$union_event = "";
if ($kollision_reservierung)
{
$union_event = "
UNION
SELECT tbl_kalender_event_teilnehmer.studiengang_kz, tbl_kalender_event_teilnehmer.semester, tbl_kalender_event_teilnehmer.verband, tbl_kalender_event_teilnehmer.gruppe, tbl_kalender_event_teilnehmer.gruppe_kurzbz, tbl_kalender_event_teilnehmer.kalender_id
FROM lehre.tbl_kalender_event_teilnehmer
WHERE tbl_kalender_event_teilnehmer.rolle_kurzbz = 'teilnehmer'
";
}
$sql_gruppen = "
SELECT
other_kalender.von,
other_kalender.bis,
COALESCE(
other_lehreinheitguppe.gruppe_kurzbz,
UPPER(stg.typ::text || stg.kurzbz::text) || '-' || other_lehreinheitguppe.semester ||
COALESCE(other_lehreinheitguppe.verband::text, '') ||
COALESCE(other_lehreinheitguppe.gruppe::text, '')
) AS gruppenname
FROM lehre.tbl_kalender current_kalender
JOIN (
SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe,
tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id
FROM lehre.tbl_kalender_lehreinheit
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
". $union_event ."
) current_lehreinheitguppe ON current_lehreinheitguppe.kalender_id = current_kalender.kalender_id
LEFT JOIN public.tbl_gruppe current_gruppe
ON current_gruppe.gruppe_kurzbz = current_lehreinheitguppe.gruppe_kurzbz
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.kalender_id != current_kalender.kalender_id
AND other_kalender.von < ?
AND other_kalender.bis > ?
JOIN (
SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe,
tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id
FROM lehre.tbl_kalender_lehreinheit
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
". $union_event ."
) other_lehreinheitguppe ON other_lehreinheitguppe.kalender_id = other_kalender.kalender_id
LEFT JOIN public.tbl_gruppe other_gruppe
ON other_gruppe.gruppe_kurzbz = other_lehreinheitguppe.gruppe_kurzbz
LEFT JOIN public.tbl_studiengang stg
ON stg.studiengang_kz = other_lehreinheitguppe.studiengang_kz
WHERE current_kalender.kalender_id = ?
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND current_lehreinheitguppe.studiengang_kz = other_lehreinheitguppe.studiengang_kz
AND current_lehreinheitguppe.semester = other_lehreinheitguppe.semester
AND (
(
current_lehreinheitguppe.gruppe_kurzbz IS NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NULL
AND (
current_lehreinheitguppe.verband IS NULL
OR (
current_lehreinheitguppe.verband = other_lehreinheitguppe.verband
AND (current_lehreinheitguppe.gruppe IS NULL OR other_lehreinheitguppe.gruppe IS NULL OR current_lehreinheitguppe.gruppe = other_lehreinheitguppe.gruppe)
)
)
)
OR
(
current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND current_gruppe.direktinskription IS NOT TRUE
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
(
current_lehreinheitguppe.gruppe_kurzbz IS NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NULL
AND current_gruppe.direktinskription IS NOT TRUE
)
)
)
AND other_kalender.kalender_id NOT IN (
SELECT vorgaenger_kalender_id
FROM lehre.tbl_kalender
WHERE vorgaenger_kalender_id IS NOT NULL
)
";
$result = $dbModel->execReadOnlyQuery($sql_gruppen, [
$data->bis,
$data->von,
$data->kalender_id,
]);
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)) . ')';
}
}
if ($kollision_reservierung && !$kollision_student)
{
$sql_reservierung = "
SELECT
other_kalender.von,
other_kalender.bis,
COALESCE(
other_event_teilnehmer.gruppe_kurzbz,
UPPER(stg.typ::text || stg.kurzbz::text) || '-' || other_event_teilnehmer.semester ||
COALESCE(other_event_teilnehmer.verband::text, '') ||
COALESCE(other_event_teilnehmer.gruppe::text, '')
) AS gruppenname
FROM lehre.tbl_kalender_event_teilnehmer current_event_teilnehmer
LEFT JOIN public.tbl_gruppe current_gruppe
ON current_gruppe.gruppe_kurzbz = current_event_teilnehmer.gruppe_kurzbz
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.kalender_id != ?
AND other_kalender.von < ?
AND other_kalender.bis > ?
JOIN lehre.tbl_kalender_event_teilnehmer other_event_teilnehmer
ON other_event_teilnehmer.kalender_id = other_kalender.kalender_id
AND other_event_teilnehmer.rolle_kurzbz = 'teilnehmer'
LEFT JOIN public.tbl_gruppe other_gruppe
ON other_gruppe.gruppe_kurzbz = other_event_teilnehmer.gruppe_kurzbz
LEFT JOIN public.tbl_studiengang stg
ON stg.studiengang_kz = other_event_teilnehmer.studiengang_kz
WHERE current_event_teilnehmer.kalender_id = ?
AND current_event_teilnehmer.rolle_kurzbz = 'teilnehmer'
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND current_event_teilnehmer.studiengang_kz = other_event_teilnehmer.studiengang_kz
AND current_event_teilnehmer.semester = other_event_teilnehmer.semester
AND (
(
current_event_teilnehmer.gruppe_kurzbz IS NULL
AND other_event_teilnehmer.gruppe_kurzbz IS NULL
AND (
current_event_teilnehmer.verband IS NULL
OR (
current_event_teilnehmer.verband = other_event_teilnehmer.verband
AND (current_event_teilnehmer.gruppe IS NULL OR other_event_teilnehmer.gruppe IS NULL OR current_event_teilnehmer.gruppe = other_event_teilnehmer.gruppe)
)
)
)
OR
(
current_event_teilnehmer.gruppe_kurzbz IS NOT NULL
AND other_event_teilnehmer.gruppe_kurzbz IS NOT NULL
AND current_gruppe.direktinskription IS NOT TRUE
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
(
current_event_teilnehmer.gruppe_kurzbz IS NULL
AND other_event_teilnehmer.gruppe_kurzbz IS NOT NULL
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
current_event_teilnehmer.gruppe_kurzbz IS NOT NULL
AND other_event_teilnehmer.gruppe_kurzbz IS NULL
AND current_gruppe.direktinskription IS NOT TRUE
)
)
)
AND other_kalender.kalender_id NOT IN (
SELECT vorgaenger_kalender_id
FROM lehre.tbl_kalender
WHERE vorgaenger_kalender_id IS NOT NULL
)
";
$result = $dbModel->execReadOnlyQuery($sql_reservierung, [
$data->kalender_id,
$data->bis,
$data->von,
$data->kalender_id,
]);
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)) . ')';
}
}
return $collisions;
}
public function checkAll($kalender_ids)
{
if (empty($kalender_ids)) return [];
$dbModel = new DB_Model();
$placeholders = implode(',', array_fill(0, count($kalender_ids), '?'));
$sql = "
SELECT DISTINCT ON (current_kalender.kalender_id) current_kalender.kalender_id
FROM lehre.tbl_kalender current_kalender
JOIN (
SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe,
tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id
FROM lehre.tbl_kalender_lehreinheit
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
UNION
SELECT tbl_kalender_event_teilnehmer.studiengang_kz, tbl_kalender_event_teilnehmer.semester, tbl_kalender_event_teilnehmer.verband, tbl_kalender_event_teilnehmer.gruppe,
tbl_kalender_event_teilnehmer.gruppe_kurzbz, tbl_kalender_event_teilnehmer.kalender_id
FROM lehre.tbl_kalender_event_teilnehmer
) current_lehreinheitguppe ON current_lehreinheitguppe.kalender_id = current_kalender.kalender_id
LEFT JOIN public.tbl_gruppe current_gruppe
ON current_gruppe.gruppe_kurzbz = current_lehreinheitguppe.gruppe_kurzbz
JOIN lehre.tbl_kalender other_kalender
ON other_kalender.kalender_id != current_kalender.kalender_id
AND other_kalender.von < current_kalender.bis
AND other_kalender.bis > current_kalender.von
JOIN (
SELECT tbl_lehreinheitgruppe.studiengang_kz, tbl_lehreinheitgruppe.semester, tbl_lehreinheitgruppe.verband, tbl_lehreinheitgruppe.gruppe,
tbl_lehreinheitgruppe.gruppe_kurzbz, tbl_kalender_lehreinheit.kalender_id
FROM lehre.tbl_kalender_lehreinheit
JOIN lehre.tbl_lehreinheit ON tbl_lehreinheit.lehreinheit_id = tbl_kalender_lehreinheit.lehreinheit_id
JOIN lehre.tbl_lehreinheitgruppe ON tbl_lehreinheitgruppe.lehreinheit_id = tbl_lehreinheit.lehreinheit_id
UNION
SELECT tbl_kalender_event_teilnehmer.studiengang_kz, tbl_kalender_event_teilnehmer.semester, tbl_kalender_event_teilnehmer.verband, tbl_kalender_event_teilnehmer.gruppe,
tbl_kalender_event_teilnehmer.gruppe_kurzbz, tbl_kalender_event_teilnehmer.kalender_id
FROM lehre.tbl_kalender_event_teilnehmer
) other_lehreinheitguppe ON other_lehreinheitguppe.kalender_id = other_kalender.kalender_id
LEFT JOIN public.tbl_gruppe other_gruppe
ON other_gruppe.gruppe_kurzbz = other_lehreinheitguppe.gruppe_kurzbz
WHERE current_kalender.kalender_id IN ({$placeholders})
AND other_kalender.status_kurzbz NOT IN ('archived', 'deleted', 'to_delete')
AND current_lehreinheitguppe.studiengang_kz = other_lehreinheitguppe.studiengang_kz
AND current_lehreinheitguppe.semester = other_lehreinheitguppe.semester
AND (
(
current_lehreinheitguppe.gruppe_kurzbz IS NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NULL
AND (
current_lehreinheitguppe.verband IS NULL
OR (
current_lehreinheitguppe.verband = other_lehreinheitguppe.verband
AND (current_lehreinheitguppe.gruppe IS NULL OR other_lehreinheitguppe.gruppe IS NULL OR current_lehreinheitguppe.gruppe = other_lehreinheitguppe.gruppe)
)
)
)
OR
(
current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND current_gruppe.direktinskription IS NOT TRUE
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
(
current_lehreinheitguppe.gruppe_kurzbz IS NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_gruppe.direktinskription IS NOT TRUE
)
OR
(
current_lehreinheitguppe.gruppe_kurzbz IS NOT NULL
AND other_lehreinheitguppe.gruppe_kurzbz IS NULL
AND current_gruppe.direktinskription IS NOT TRUE
)
)
)
AND other_kalender.kalender_id NOT IN (
SELECT vorgaenger_kalender_id
FROM lehre.tbl_kalender
WHERE vorgaenger_kalender_id IS NOT NULL
)
";
$result = $dbModel->execReadOnlyQuery($sql, $kalender_ids);
if (isError($result) || !hasData($result)) return [];
$grouped = [];
foreach (getData($result) as $row)
$grouped[$row->kalender_id][] = true;
return $grouped;
}
}
@@ -3,6 +3,7 @@ namespace vertragsbestandteil;
use Exception;
use vertragsbestandteil\VertragsbestandteilStunden;
use vertragsbestandteil\VertragsbestandteilLohnguide;
/**
* Description of VertragsbestandteilFactory
@@ -22,6 +23,7 @@ class VertragsbestandteilFactory
const VERTRAGSBESTANDTEIL_URLAUBSANSPRUCH = 'urlaubsanspruch';
const VERTRAGSBESTANDTEIL_ZEITAUFZEICHNUNG = 'zeitaufzeichnung';
const VERTRAGSBESTANDTEIL_LEHRE = 'lehre';
const VERTRAGSBESTANDTEIL_LOHNGUIDE = 'lohnguide';
public static function getVertragsbestandteil($data, $fromdb=false)
{
@@ -69,6 +71,11 @@ class VertragsbestandteilFactory
$vertragsbestandteil = new VertragsbestandteilZeitaufzeichnung();
$vertragsbestandteil->hydrateByStdClass($data, $fromdb);
break;
case self::VERTRAGSBESTANDTEIL_LOHNGUIDE:
$vertragsbestandteil = new VertragsbestandteilLohnguide();
$vertragsbestandteil->hydrateByStdClass($data, $fromdb);
break;
default:
throw new Exception('Unknown vertragsbestandteiltyp_kurzbz '
@@ -127,6 +134,12 @@ class VertragsbestandteilFactory
$vertragsbestandteildbmodel = $CI->VertragsbestandteilZeitaufzeichnung_model;
break;
case self::VERTRAGSBESTANDTEIL_LOHNGUIDE:
$CI->load->model('vertragsbestandteil/VertragsbestandteilLohnguide_model',
'VertragsbestandteilLohnguide_model');
$vertragsbestandteildbmodel = $CI->VertragsbestandteilLohnguide_model;
break;
default:
throw new Exception('Unknown vertragsbestandteil_kurzbz '
. $vertragsbestandteil_kurzbz);
@@ -10,6 +10,7 @@ require_once __DIR__ . '/VertragsbestandteilKuendigungsfrist.php';
require_once __DIR__ . '/VertragsbestandteilUrlaubsanspruch.php';
require_once __DIR__ . '/VertragsbestandteilFreitext.php';
require_once __DIR__ . '/VertragsbestandteilKarenz.php';
require_once __DIR__ . '/VertragsbestandteilLohnguide.php';
require_once __DIR__ . '/VertragsbestandteilFactory.php';
require_once __DIR__ . '/OverlapChecker.php';
@@ -0,0 +1,155 @@
<?php
namespace vertragsbestandteil;
use vertragsbestandteil\Vertragsbestandteil;
use vertragsbestandteil\VertragsbestandteilFactory;
class VertragsbestandteilLohnguide extends Vertragsbestandteil
{
protected $stellenbezeichnung;
protected $vordienstzeit;
protected $fachrichtung_kurzbz;
protected $modellstelle_kurzbz;
protected $kommentar_person;
protected $kommentar_modellstelle;
public function __construct()
{
parent::__construct();
$this->setVertragsbestandteiltyp_kurzbz(
VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_LOHNGUIDE);
}
public function getStellenbezeichnung()
{
return $this->stellenbezeichnung;
}
public function setStellenbezeichnung($stellenbezeichnung): self
{
$this->markDirty('stellenbezeichnung', $this->stellenbezeichnung, $stellenbezeichnung);
$this->stellenbezeichnung = $stellenbezeichnung;
return $this;
}
public function getVordienstzeit()
{
return $this->vordienstzeit;
}
public function setVordienstzeit($vordienstzeit): self
{
$this->markDirty('vordienstzeit', $this->vordienstzeit, $vordienstzeit);
$this->vordienstzeit = $vordienstzeit;
return $this;
}
public function getFachrichtung_kurzbz()
{
return $this->fachrichtung_kurzbz;
}
public function setFachrichtung_kurzbz($fachrichtung_kurzbz): self
{
$this->markDirty('fachrichtung_kurzbz', $this->fachrichtung_kurzbz, $fachrichtung_kurzbz);
$this->fachrichtung_kurzbz = $fachrichtung_kurzbz;
return $this;
}
public function getModellstelle_kurzbz()
{
return $this->modellstelle_kurzbz;
}
public function setModellstelle_kurzbz($modellstelle_kurzbz): self
{
$this->markDirty('modellstelle_kurzbz', $this->modellstelle_kurzbz, $modellstelle_kurzbz);
$this->modellstelle_kurzbz = $modellstelle_kurzbz;
return $this;
}
public function getKommentar_person()
{
return $this->kommentar_person;
}
public function setKommentar_person($kommentar_person): self
{
$this->markDirty('kommentar_person', $this->kommentar_person, $kommentar_person);
$this->kommentar_person = $kommentar_person;
return $this;
}
public function getKommentar_modellstelle()
{
return $this->kommentar_modellstelle;
}
public function setKommentar_modellstelle($kommentar_modellstelle): self
{
$this->markDirty('kommentar_modellstelle', $this->kommentar_modellstelle, $kommentar_modellstelle);
$this->kommentar_modellstelle = $kommentar_modellstelle;
return $this;
}
public function hydrateByStdClass($data, $fromdb=false)
{
parent::hydrateByStdClass($data, $fromdb);
$this->fromdb = $fromdb;
isset($data->fachrichtung_kurzbz) && $this->setFachrichtung_kurzbz($data->fachrichtung_kurzbz);
isset($data->stellenbezeichnung) && $this->setStellenbezeichnung($data->stellenbezeichnung);
isset($data->vordienstzeit) && $this->setVordienstzeit($data->vordienstzeit);
isset($data->modellstelle_kurzbz) && $this->setModellstelle_kurzbz($data->modellstelle_kurzbz);
isset($data->kommentar_person) && $this->setKommentar_person($data->kommentar_person);
isset($data->kommentar_modellstelle) && $this->setKommentar_modellstelle($data->kommentar_modellstelle);
$this->fromdb = false;
}
public function toStdClass(): \stdClass
{
$tmp = array(
'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(),
'stellenbezeichnung' => $this->getStellenbezeichnung(),
'vordienstzeit' => $this->getVordienstzeit(),
'fachrichtung_kurzbz' => $this->getFachrichtung_kurzbz(),
'modellstelle_kurzbz' => $this->getModellstelle_kurzbz(),
'kommentar_person' => $this->getKommentar_person(),
'kommentar_modellstelle' => $this->getKommentar_modellstelle(),
);
$tmp = array_filter($tmp, function($k) {
return in_array($k, $this->modifiedcolumns);
}, ARRAY_FILTER_USE_KEY);
return (object) $tmp;
}
public function __toString()
{
$txt = <<<EOTXT
modellstelle_kurzbz: {$this->getModellstelle_kurzbz()}
EOTXT;
return parent::__toString() . $txt;
}
/* public function validate()
{
if( !(filter_var($this->tage, FILTER_VALIDATE_INT,
array(
'options' => array(
'min_range' => 1,
'max_range' => 50
)
)
)) ) {
$this->validationerrors[] = 'Urlaubsanspruch muss eine Tagesanzahl im Bereich 1 bis 50 sein.';
}
return parent::validate();
} */
}
@@ -402,14 +402,17 @@ class Lehrveranstaltung_model extends DB_Model
SELECT
vorname, nachname, mitarbeiter_uid, lehrfunktion_kurzbz
FROM
lehre.tbl_lehreinheit
lehre.tbl_lehreinheit le
JOIN lehre.tbl_lehreinheitmitarbeiter lema USING (lehreinheit_id)
JOIN public.tbl_benutzer b ON b.uid = lema.mitarbeiter_uid
JOIN public.tbl_person p using (person_id)
WHERE
tbl_lehreinheit.lehrveranstaltung_id= ?
AND tbl_lehreinheit.studiensemester_kurzbz = ?
le.lehrveranstaltung_id= ?
AND le.studiensemester_kurzbz = ?
AND lehrfunktion_kurzbz = 'LV-Leitung'
AND lema.mitarbeiter_uid NOT like '_Dummy%'
AND b.aktiv = TRUE
AND p.aktiv = TRUE
ORDER BY
lema.insertamum DESC
LIMIT 1
@@ -79,10 +79,10 @@ class Paabgabe_model extends DB_Model
JOIN public.tbl_benutzer ON (public.tbl_benutzer.uid = student_uid)
JOIN public.tbl_person USING (person_id)
WHERE (campus.tbl_paabgabe.insertamum >= NOW() - INTERVAL ?
OR campus.tbl_paabgabe.updateamum >= NOW() - INTERVAL ?)
AND campus.tbl_paabgabe.paabgabetyp_kurzbz IN ?";
WHERE (campus.tbl_paabgabe.insertamum::date = CURRENT_DATE - INTERVAL ?
OR campus.tbl_paabgabe.updateamum::date = CURRENT_DATE - INTERVAL ?)
AND campus.tbl_paabgabe.paabgabetyp_kurzbz IN ?";
return $this->execQuery($query, [$interval, $interval, $relevantTypes]);
}
@@ -108,7 +108,7 @@ class Paabgabe_model extends DB_Model
JOIN public.tbl_person ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
WHERE campus.tbl_paabgabe.abgabedatum IS NOT NULL
AND campus.tbl_paabgabe.abgabedatum >= NOW() - INTERVAL ?";
AND campus.tbl_paabgabe.abgabedatum = CURRENT_DATE - INTERVAL ?";
if($relevantTypes !== null) {
$query .= " AND campus.tbl_paabgabe.paabgabetyp_kurzbz IN ?";
@@ -11,26 +11,4 @@ class Gruppe_model extends DB_Model
$this->dbTable = 'public.tbl_gruppe';
$this->pk = 'gruppe_kurzbz';
}
public function search($query_words)
{
$this->addSelect('gruppe_kurzbz,
studiengang_kz,
semester,
bezeichnung,
gid,
\'false\' as lehrverband');
$this->db->where(array('sichtbar' => true, 'aktiv' => true, 'lehre' => true, 'direktinskription' => false, 'semester IS NOT NULL' => null));
$this->db->group_start();
foreach ($query_words as $word)
{
$this->db->group_start();
$this->db->where('gruppe_kurzbz ILIKE', "%" . $word . "%");
$this->db->or_where('bezeichnung ILIKE', "%" . $word . "%");
$this->db->group_end();
}
$this->db->group_end();
return $this->load();
}
}
@@ -41,29 +41,4 @@ class Lehrverband_model extends DB_Model
return $result;
}
public function search($query_words)
{
$this->addSelect('CONCAT(UPPER(CONCAT(typ, kurzbz)), \'\', semester, verband, COALESCE(gruppe,\'\')) as gruppe_kurzbz,
studiengang_kz,
semester,
tbl_lehrverband.bezeichnung,
gid,
\'true\' as lehrverband');
$this->addJoin('public.tbl_studiengang', 'studiengang_kz');
$this->addOrder('verband');
$this->addOrder('gruppe');
$this->db->where(array('tbl_lehrverband.aktiv' => true));
$this->db->group_start();
foreach ($query_words as $word)
{
$this->db->group_start();
$this->db->where('CONCAT(CONCAT(typ, kurzbz), \'\', semester, verband, COALESCE(gruppe,\'\')) ILIKE', "%" . $word . "%");
$this->db->or_where('tbl_lehrverband.bezeichnung ILIKE', "%" . $word . "%");
$this->db->group_end();
}
$this->db->group_end();
return $this->load();
}
}
@@ -594,7 +594,10 @@ class Studiengang_model extends DB_Model
$this->addSelect('p.prestudent_id');
$this->addSelect('pers.vorname');
$this->addSelect('pers.nachname');
$this->addSelect("CONCAT(UPPER(pers.nachname), ' ', pers.vorname, ' (', " . $this->dbTable . ".bezeichnung, ')') AS name");
$this->addSelect("CONCAT(UPPER(pers.nachname), ' ', pers.vorname, ' (', "
. $this->dbTable . ".bezeichnung, ', ', "
. "UPPER(" . $this->dbTable . ".typ), "
. "UPPER(" . $this->dbTable . ".kurzbz),')') AS name");
$this->addJoin('public.tbl_prestudent p', 'studiengang_kz');
$this->addJoin(
@@ -261,6 +261,42 @@ class Benutzerfunktion_model extends DB_Model
}
/**
* Get active Kompetenzfeldleitung bei UID.
*
* @param $uid
* @return array|stdClass|null
*/
public function getKFLByUID($uid)
{
$query = '
SELECT
bf.uid,
bf.oe_kurzbz,
oe.organisationseinheittyp_kurzbz
FROM
public.tbl_benutzerfunktion bf
JOIN public.tbl_organisationseinheit oe USING (oe_kurzbz)
JOIN public.tbl_benutzer b USING (uid)
WHERE
b.uid = ?
AND b.aktiv = TRUE
AND funktion_kurzbz = \'Leitung\'
AND organisationseinheittyp_kurzbz = \'Kompetenzfeld\'
AND (datum_von IS NULL OR datum_von <= now())
AND (datum_bis IS NULL OR datum_bis >= now())
';
$parameters_array = array();
if (is_string($uid))
{
$parameters_array[] = $uid;
}
return $this->execQuery($query, $parameters_array);
}
public function insertBenutzerfunktion($Json)
{
unset($Json['benutzerfunktion_id']);
@@ -1,15 +0,0 @@
<?php
class Kalender_Event_Rolle_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_event_rolle';
$this->pk = array('rolle_kurzbz');
$this->hasSequence = false;
}
}
@@ -1,16 +0,0 @@
<?php
class
Kalender_Event_Teilnehmer_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_event_teilnehmer';
$this->pk = array('kalender_event_teilnehmer_id');
$this->hasSequence = false;
}
}
@@ -1,15 +0,0 @@
<?php
class Kalender_Event_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_event';
$this->pk = array('kalender_id');
$this->hasSequence = false;
}
}
@@ -1,15 +0,0 @@
<?php
class Kalender_Lehreinheit_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_lehreinheit';
$this->pk = array('kalender_id','lehreinheit_id');
$this->hasSequence = false;
}
}
@@ -1,14 +0,0 @@
<?php
class Kalender_Ort_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_ort';
$this->pk = 'kalender_ort_id';
}
}
@@ -1,14 +0,0 @@
<?php
class Kalender_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender';
$this->pk = 'kalender_id';
}
}
@@ -1,14 +0,0 @@
<?php
class Kalenderstatus_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_kalender_status';
$this->pk = 'status_kurzbz';
}
}
+120
View File
@@ -32,4 +32,124 @@ class Ort_model extends DB_Model
}
public function getRoomsWithEmployeesAssigned($ort_kurzbz=null)
{
$ort_kurzbz_clause = is_null($ort_kurzbz)
? ''
: 'and r.ort_kurzbz = ' . $this->escape($ort_kurzbz);
$sql = <<<EOSQL
{$this->roomEmployeesCTEs()}
select
r.rauminfo as room,
mir.ma_count as employee_count,
mir.mas_in_room as employees
from
roominfo r
join
mas_in_room mir on r.ort_kurzbz = mir.ort_kurzbz
where
1=1
{$ort_kurzbz_clause}
order by
mir.ma_count DESC
EOSQL;
return $this->execReadOnlyQuery($sql);
}
public function getEmployeesWithRoomAssigned($mitarbeiter_uid=null)
{
$mtarbeiter_uid_clause = is_null($mitarbeiter_uid)
? ''
: 'and aer.mitarbeiter_uid = ' . $this->escape($mitarbeiter_uid);
$sql = <<<EOSQL
{$this->roomEmployeesCTEs()}
select
m.mainfo as employee,
r.rauminfo as room
from
active_employee_room aer
join
roominfo r on aer.ort_kurzbz = r.ort_kurzbz
join
mainfo m on aer.mitarbeiter_uid = m.mitarbeiter_uid
where
1=1
{$mtarbeiter_uid_clause}
EOSQL;
return $this->execReadOnlyQuery($sql);
}
protected function roomEmployeesCTEs()
{
return <<<EOCTES
with active_employee_room as (
select
tm.mitarbeiter_uid,
tm.ort_kurzbz,
td.vertragsart_kurzbz
from
public.tbl_mitarbeiter tm
join
hr.tbl_dienstverhaeltnis td
on
td.mitarbeiter_uid = tm.mitarbeiter_uid
and NOW() between COALESCE(td.von, '1970-01-01') and coalesce(td.bis, '2170-12-31')
and td.mitarbeiter_uid not like '_Dummy%'
),
roominfo as (
select
o.ort_kurzbz,
json_build_object(
'ort_kurzbz', o.ort_kurzbz,
'bezeichnung', o.bezeichnung,
'planbezeichnung', o.planbezeichnung,
'max_person', o.max_person,
'aktiv', o.aktiv
) as rauminfo
from
public.tbl_ort o
),
mainfo as (
select
tm.mitarbeiter_uid,
tm.ort_kurzbz,
json_build_object(
'mitarbeiter_uid', tm.mitarbeiter_uid,
'vorname', tp.vorname,
'nachname', tp.nachname,
'vertragsart_kurzbz', td.vertragsart_kurzbz
) as mainfo
from
public.tbl_mitarbeiter tm
join
public.tbl_benutzer b on b.uid = tm.mitarbeiter_uid and b.aktiv = true
join
public.tbl_person tp on tp.person_id = b.person_id
join
hr.tbl_dienstverhaeltnis td
on
td.mitarbeiter_uid = tm.mitarbeiter_uid
and NOW() between COALESCE(td.von, '1970-01-01') and coalesce(td.bis, '2170-12-31')
and td.mitarbeiter_uid not like '_Dummy%'
),
mas_in_room as (
select
m.ort_kurzbz,
count(m.mitarbeiter_uid) as ma_count,
json_agg(m.mainfo) as mas_in_room
from
mainfo m
group by
m.ort_kurzbz
order by
ma_count desc
)
EOCTES;
}
}
@@ -1,14 +0,0 @@
<?php
class Reservierung_Kalender_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'sync.tbl_reservierung_kalender';
$this->pk = 'reservierung_kalender_id';
}
}
@@ -1,14 +0,0 @@
<?php
class Stundenplandev_Kalender_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'sync.tbl_stundenplandev_kalender';
$this->pk = 'stundenplandev_kalender_id';
}
}
+6 -4
View File
@@ -242,6 +242,7 @@ class Message_model extends DB_Model
*/
public function getMessagesForTable($person_id, $offset, $limit)
{
$limitoffset = (!is_null($offset) && !is_null($limit)) ? 'limit ? offset ?' : '';
$sql = <<<EOSQL
with filtered_messages as (
select
@@ -310,11 +311,12 @@ class Message_model extends DB_Model
public.tbl_person pr on pr.person_id = fm.recipient_id
order by
m.insertamum DESC
limit ?
offset ?;
{$limitoffset}
EOSQL;
$parametersArray = array($person_id, $person_id, $limit, $offset);
$parametersArray = $limitoffset
? array($person_id, $person_id, $limit, $offset)
: array($person_id, $person_id);
$count = 0;
$data = $this->execQuery($sql, $parametersArray);
@@ -325,7 +327,7 @@ EOSQL;
$data = getData($data);
if($data)
{
$count = ceil($data[0]->total_msgs / $limit);
$count = is_null($limit) ? 1 : ceil($data[0]->total_msgs / $limit);
}
return success(['data' => $data, 'count' => $count]);
@@ -0,0 +1,11 @@
<?php
class VertragsbestandteilLohnguide_model extends DB_Model
{
public function __construct()
{
parent::__construct();
$this->dbTable = 'hr.tbl_vertragsbestandteil_lohnguide';
$this->pk = 'vertragsbestandteil_id';
}
}
@@ -37,7 +37,8 @@ class Vertragsbestandteil_model extends DB_Model
kf.arbeitgeber_frist, kf.arbeitnehmer_frist,
s.wochenstunden, s.teilzeittyp_kurzbz,
u.tage,
z.zeitaufzeichnung, z.azgrelevant, z.homeoffice
z.zeitaufzeichnung, z.azgrelevant, z.homeoffice,
lg.stellenbezeichnung, lg.vordienstzeit, lg.fachrichtung_kurzbz, lg.modellstelle_kurzbz, lg.kommentar_person, lg.kommentar_modellstelle
FROM
hr.tbl_vertragsbestandteil v
LEFT JOIN
@@ -63,6 +64,8 @@ class Vertragsbestandteil_model extends DB_Model
hr.tbl_vertragsbestandteil_urlaubsanspruch u USING(vertragsbestandteil_id)
LEFT JOIN
hr.tbl_vertragsbestandteil_zeitaufzeichnung z USING(vertragsbestandteil_id)
LEFT JOIN
hr.tbl_vertragsbestandteil_lohnguide lg USING(vertragsbestandteil_id)
EOSQL;
return $sql;
}
-50
View File
@@ -1,50 +0,0 @@
<?php
$includesArray = array(
'title' => 'Tempus',
'axios027' => true,
'bootstrap5' => true,
'fontawesome6' => true,
'vue3' => true,
'primevue3' => true,
'tabulator5' => true,
'vuedatepicker11' => true,
'phrases' => array(
'global',
'ui',
'notiz',
),
'customCSSs' => [
'public/css/components/vue-datepicker.css',
'public/css/components/primevue.css',
'public/css/components/calendar.css',
'public/css/Tempus.css',
'public/css/Studentenverwaltung.css',
'public/css/components/function.css'
],
'customJSs' => [
#'vendor/npm-asset/primevue/tree/tree.min.js',
#'vendor/npm-asset/primevue/toast/toast.min.js'
'vendor/moment/luxonjs/luxon.min.js'
],
'customJSModules' => [
'public/js/apps/Tempus.js'
]
);
$this->load->view('templates/FHC-Header', $includesArray);
?>
<div id="main">
<router-view
default-semester="<?= $variables['semester_aktuell']; ?>"
active-addons="<?= defined('ACTIVE_ADDONS') ? ACTIVE_ADDONS : ''; ?>"
tempus-root="<?= site_url('Tempus'); ?>"
cis-root="<?= CIS_ROOT; ?>"
avatar-url="<?= site_url('Cis/Pub/bild/person/' . getAuthPersonId()); ?>"
logout-url="<?= site_url('Cis/Auth/logout'); ?>"
:permissions="<?= htmlspecialchars(json_encode($permissions)); ?>"
:config="<?= htmlspecialchars(json_encode($variables)); ?>"
>
</router-view>
</div>
<?php $this->load->view('templates/FHC-Footer', $includesArray); ?>
+6 -4
View File
@@ -46,12 +46,13 @@ echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<link rel="stylesheet" href="../../../skin/tablesort.css" type="text/css"/>
<link rel="stylesheet" href="../../../skin/style.css.php" type="text/css">
<link rel="stylesheet" type="text/css" href="../../../skin/jquery-ui-1.9.2.custom.min.css">
<script type="text/javascript" src="../../../vendor/jquery/jquery1/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="../../../vendor/christianbach/tablesorter/jquery.tablesorter.min.js"></script>
<script type="text/javascript" src="../../../vendor/components/jqueryui/jquery-ui.min.js"></script>
<script type="text/javascript" src="../../../include/js/jquery.ui.datepicker.translation.js"></script>
<script type="text/javascript" src="../../../vendor/jquery/sizzle/sizzle.js"></script>';
include('../../../include/meta/jquery.php');
include('../../../include/meta/jquery-tablesorter.php');
const MOODLE_ADDON_KURZBZ = 'moodle';
// Load Addons to get Moodle_Path
@@ -71,7 +72,7 @@ echo '
$("#myTable").tablesorter(
{
sortList: [[0,0],[1,0]],
widgets: [\'zebra\']
widgets: [\'zebra\',\'filter\']
});
}
);
@@ -151,8 +152,9 @@ foreach($service->result as $row)
$person = new person();
$person->getPersonFromBenutzer($row->operativ_uid);
$operativ = $person->nachname.' '.$person->vorname;
$oeBez = new organisationseinheit($row->oe_kurzbz);
echo '<tr>';
echo '<td>',$row->oe_kurzbz,'</td>';
echo '<td>',$oeBez->bezeichnung,'</td>';
echo '<td><b>'.$row->bezeichnung.'</b></td>';
echo '<td>',$row->beschreibung,'</td>';
echo '<td><nobr><a href="../profile/index.php?uid='.$row->design_uid.'">',$design,'</a></nobr></td>';
+1 -1
View File
@@ -293,7 +293,7 @@ else if (isset($_SESSION['pruefling_id']))
}
$lastsemester = $row->semester;
echo '<table border="0" cellspacing="0" cellpadding="0" id="Gebiet" style="display: visible; border-collapse: separate; border-spacing: 0 3px;">';
echo '<table border="0" cellspacing="0" cellpadding="0" id="Gebiet" style="display: visible; border-collapse: separate; border-spacing: 0 3px; margin-top: 5px;">';
echo '<tr><td class="HeaderTesttool">'. ($row->semester == '1' ? $p->t('testtool/basisgebiete') : $p->t('testtool/quereinstiegsgebiete')).'</td></tr>';
}
@@ -342,6 +342,8 @@ echo '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>';
<vbox>
<checkbox id="mitarbeiter-entwicklungsteam-detail-checkbox-neu" checked="true" hidden="true" />
<textbox id="mitarbeiter-entwicklungsteam-detail-textbox-studiengang" hidden="true" />
<textbox id="mitarbeiter-entwicklungsteam-detail-entwicklungsteam_id" hidden="true" />
<groupbox id="mitarbeiter-entwicklungsteam-detail-groupbox" flex="1">
<caption label="Details" />
<grid id="mitarbeiter-entwicklungsteam-detail-grid" style="margin:4px;" flex="1">
@@ -1708,6 +1708,7 @@ function MitarbeiterEntwicklungsteamSelect()
document.getElementById('mitarbeiter-entwicklungsteam-detail-textbox-studiengang').value=studiengang_kz;
document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-beginn').value=beginn;
document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-ende').value=ende;
document.getElementById('mitarbeiter-entwicklungsteam-detail-entwicklungsteam_id').value=entwicklungsteam_id;
MitarbeiterEntwicklungsteamDetailDisableFields(false);
}
@@ -1725,6 +1726,7 @@ function MitarbeiterEntwicklungsteamSpeichern()
studiengang_kz_old = document.getElementById('mitarbeiter-entwicklungsteam-detail-textbox-studiengang').value;
beginn = document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-beginn').value;
ende = document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-ende').value;
entwicklungsteam_id = document.getElementById('mitarbeiter-entwicklungsteam-detail-entwicklungsteam_id').value;
if(studiengang_kz=='')
{
+8
View File
@@ -3555,6 +3555,14 @@ function StudentZeugnisDokumentArchivieren()
case 'microcredential_2':
case 'microcredential_3':
case 'microcredential_4':
case 'microdegree_1':
case 'microdegree_2':
case 'microdegree_3':
case 'microdegree_4':
case 'microdegreeabschluss_1':
case 'microdegreeabschluss_2':
case 'microdegreeabschluss_3':
case 'microdegreeabschluss_4':
xml = 'microcredential.xml.php';
break;
+3 -1
View File
@@ -364,9 +364,10 @@ class entwicklungsteam extends basis_db
$bismeldung_jahr = $datetime->format('Y');
//laden des Datensatzes
$qry = "SELECT *
$qry = "SELECT tbl_entwicklungsteam.*, tbl_besqual.*, tbl_studiengang.studiengang_kz, tbl_studiengang.melderelevant
FROM bis.tbl_entwicklungsteam
JOIN bis.tbl_besqual USING(besqualcode)
JOIN public.tbl_studiengang USING(studiengang_kz)
WHERE mitarbeiter_uid=".$this->db_add_param($mitarbeiter_uid)."
AND (beginn is NULL OR beginn <= make_date(". $this->db_add_param($bismeldung_jahr). "::INTEGER, 12, 31))
AND (ende is NULL OR ende >= make_date(". $this->db_add_param($bismeldung_jahr). "::INTEGER, 1, 1))";
@@ -394,6 +395,7 @@ class entwicklungsteam extends basis_db
$obj->insertvon = $row->insertvon;
$obj->ext_id = $row->ext_id;
$obj->besqual = $row->besqualbez;
$obj->melderelevant = $this->db_parse_bool($row->melderelevant);
$this->result[] = $obj;
}
+49 -1
View File
@@ -25,6 +25,7 @@
*/
require_once(dirname(__FILE__).'/basis_db.class.php');
require_once(dirname(__FILE__).'/'.EXT_FKT_PATH.'/generateZahlungsreferenz.inc.php');
require_once(dirname(__FILE__).'/variable.class.php');
class konto extends basis_db
{
@@ -432,6 +433,8 @@ class konto extends basis_db
$qry.=" ORDER BY beschreibung";
$oehBeitrag = $this->_getOEHBeitrag();
if($this->db_query($qry))
{
while($row = $this->db_fetch_object())
@@ -440,7 +443,15 @@ class konto extends basis_db
$typ->buchungstyp_kurzbz = $row->buchungstyp_kurzbz;
$typ->beschreibung = $row->beschreibung;
$typ->standardbetrag = $row->standardbetrag;
if (strtolower($typ->buchungstyp_kurzbz) === 'oeh' && $oehBeitrag)
{
$typ->standardbetrag = $oehBeitrag;
}
else
{
$typ->standardbetrag = $row->standardbetrag;
}
$typ->standardtext = $row->standardtext;
$typ->credit_points = $row->credit_points;
$typ->aktiv = $this->db_parse_bool($row->aktiv);
@@ -990,6 +1001,43 @@ class konto extends basis_db
return false;
}
}
private function _getOEHBeitrag()
{
if(!is_user_logged_in())
{
return false;
}
$variablen_obj = new variable();
$variablen_obj->loadVariables(get_uid());
$qry = "WITH semstart AS (
SELECT start FROM public.tbl_studiensemester
WHERE studiensemester_kurzbz = '". $this->db_escape($variablen_obj->variable->semester_aktuell) . "'
)
SELECT * FROM bis.tbl_oehbeitrag oehb
JOIN public.tbl_studiensemester semvon ON oehb.von_studiensemester_kurzbz = semvon.studiensemester_kurzbz
LEFT JOIN public.tbl_studiensemester sembis ON oehb.bis_studiensemester_kurzbz = sembis.studiensemester_kurzbz
JOIN semstart ON semstart.start::date >= semvon.start::date AND (sembis.studiensemester_kurzbz IS NULL OR semstart.start::date <= sembis.start::date)
ORDER BY semvon.start
LIMIT 1";
if ($this->db_query($qry))
{
if($row = $this->db_fetch_object())
{
$summe = ($row->studierendenbeitrag + $row->versicherung) * -1;
return number_format((float)$summe, 2, '.', '');
}
return false;
}
else
{
$this->errormsg = 'Fehler bei der Abfrage aufgetreten';
return false;
}
}
}
?>
+4 -2
View File
@@ -584,8 +584,9 @@ class lehreinheitmitarbeiter extends basis_db
$qry = '
WITH semester_sws_tbl AS (
SELECT DISTINCT lehreinheit_id, studiensemester_kurzbz, lema.semesterstunden,
stg.studiengang_kz, stg.melde_studiengang_kz, stg.lgartcode
SELECT
DISTINCT lehreinheit_id, studiensemester_kurzbz, lema.semesterstunden,
stg.studiengang_kz, stg.melde_studiengang_kz, stg.lgartcode, stg.melderelevant
FROM lehre.tbl_lehreinheitmitarbeiter lema
JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id)
@@ -598,6 +599,7 @@ class lehreinheitmitarbeiter extends basis_db
AND ss.studiensemester_kurzbz IN ('.$this->implode4SQL($studiensemester_kurzbz_arr).')
-- nur lehre, die bisgemeldet wird
AND lema.bismelden
AND stg.melderelevant
-- keine lehreinheiten ohne semesterstunden
AND lema.semesterstunden != 0
)
-12
View File
@@ -97,15 +97,3 @@
display: none;
}
.weekPageContainer .calendar-event-collisions
{
display: grid;
grid-template-columns: auto 1fr;
background: repeating-linear-gradient(
135deg,
transparent,
transparent 16px,
rgba(0, 0, 0, 0.3) 16px,
rgba(0, 0, 0, 0.3) 32px
);
}
-4
View File
@@ -197,10 +197,6 @@ html.fs_huge {
margin-bottom: -1px;
}
.tiny-90 div.tox.tox-tinymce {
height: 90% !important;
}
/* slim begin */
.stv .form-label {
margin-bottom: .15rem;
-187
View File
@@ -1,187 +0,0 @@
@import './Fhc.css';
@import './components/searchbar/searchbar.css';
@import './components/verticalsplit.css';
@import './components/FilterComponent.css';
@import './components/Tabs.css';
@import './components/Notiz.css';
html {
font-size: .875em;
height: 100%;
}
body {
/*display: flex;*/
height: 100%;
}
.heightfull {
height: 95%;
}
.navbar-dark .navbar-brand:focus {
box-shadow: 0 0 0 .25rem rgba(13,110,253,.25);
z-index: 3;
}
#main {
height: 100%;
}
.tempus {
height: 100%;
}
.searchbar {
margin-right: 0!important;
}
.searchbar > .input-group {
margin-right: 0!important;
}
.searchbar > .input-group > * {
border-radius: 0!important;
}
#sidebarMenu {
width: 0%;
}
.tabulator-row.disabled.tabulator-row-odd .tabulator-cell {
color: var(--gray-400);
}
.tabulator-row.disabled.tabulator-row-even .tabulator-cell {
color: var(--gray-500);
}
/* Dropdown Toolbar Interessent, submenu */
.dropend .dropdown-toggle.d-flex::after {
height: 0;
}
@media (min-width: 768px) {
#sidebarMenu {
visibility: visible!important;
transform: none;
position: inherit;
z-index: 1;
}
}
.toast.toast-success {
color: #0f5132;
background-color: #d1e7dd!important;
border-color: #badbcc!important;
}
.toast.toast-danger {
color: #842029;
background-color: #f8d7da!important;
border-color: #f5c2c7!important;
}
.has-filter .fa-filter {
color: var(--bs-success);
}
#parkingslot {
border: 1px dashed;
min-height: 5vh;
max-height: 15vh;
color: #AAAAAA;
text-align: center;
font-size: large;
margin-top: 1.25rem;
overflow-y: auto;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
}
.course-picker {
border: 1px dashed #AAAAAA;
display: flex;
flex-direction: column;
flex: 1 1 0;
min-height: 0;
}
.course-picker-row {
padding: 0.5rem;
margin-bottom: 0.5rem;
border: 1px solid var(--bs-border-color);
background-color: var(--event-bg);
}
.parkingevent {
border: 1px dashed !important;
border-color: #AAAAAA;
padding: 0.5rem;
margin-bottom: 0.5rem;
margin-left: 0.5rem;
margin-right: 0.5rem;
}
:root{
--fhc-calendar-pane-height: calc(100vh - 120px);
}
.eckerltest {
box-shadow: 3px 3px 3px #ccc;
}
.verband-selection {
border: 1px dashed #AAAAAA;
margin-bottom: 0.5rem;
max-height: 450px;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.lecture-selection {
border: 1px dashed #AAAAAA;
margin-bottom: 0.5rem;
max-height: 20vh;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.room-selection {
border: 1px dashed #AAAAAA;
margin-bottom: 0.5rem;
padding: 0.5rem 0 0.5rem 0.5rem;
}
.btn-link.text-danger {
text-decoration: none;
font-weight: 600;
}
.btn-link.text-danger:hover {
color: #dc3545;
transform: scale(1.1);
}
.bg-lecturer-wish {
opacity: .15;
}
.bg-lecturer-block {
background: rgba(255, 0, 0, 0.15);
}
.wish-w--2 {
background-color: #FF2200;
}
.wish-w--1 {
background-color: #FF9922;
}
.wish-w-1 {
background-color: #CCFFCC;
}
.wish-w-2 {
background-color: #48FA66;
}
-37
View File
@@ -2,10 +2,6 @@
cursor: pointer;
font-size: var(--fhc-calendar-fontsize-event, .875rem);
}
.event--parked {
opacity: 0.45 !important;
}
.fhc-calendar-mode-day .fhc-calendar-base-grid-line,
.fhc-calendar-mode-week .fhc-calendar-base-grid-line {
padding: 0 var(--fhc-calendar-gap-events, var(--fhc-calendar-gap, 1px));
@@ -73,36 +69,3 @@
.fhc-calendar-base .event > *:hover {
filter: brightness(120%);
}
.fhc-resize-bar {
display: flex;
align-items: center;
justify-content: center;
height: 15px;
flex: 0 0 12px;
cursor: ns-resize;
position: relative;
visibility: hidden;
pointer-events: none;
background-color: transparent !important;
border: none !important;
}
.fhc-resize-bar--top {
margin-bottom: -16px;
}
.fhc-resize-bar--bottom {
margin-top: -16px;
}
.fhc-calendar-base-grid-line-event:hover > .fhc-resize-bar {
visibility: visible;
pointer-events: auto;
}
.fhc-calendar-base-grid-line-event.event:hover {
z-index: 50;
}
.fhc-resize-bar {
z-index: 2;
}
+8 -5
View File
@@ -17,13 +17,16 @@
export default {
getMessages(params) {
let url = 'api/frontend/v1/messages/messages/getMessages'
+ '/' + params.id
+ '/' + params.type;
if(params.size && params.page) {
url += '/' + params.size
+ '/' + params.page;
}
return {
method: 'get',
url: 'api/frontend/v1/messages/messages/getMessages/'
+ params.id + '/'
+ params.type + '/'
+ params.size + '/'
+ params.page
url: url
};
},
getVorlagen(){
-8
View File
@@ -9,12 +9,4 @@ export default {
}
};
},
loadTempusRenderers() {
return {
method: 'get',
url: '/api/frontend/v1/RendererLoader/GetTempusRenderers',
params: {
}
};
},
}
+15 -3
View File
@@ -38,6 +38,10 @@ export default {
};
},
insert(params) {
if(params.betrag)
{
params.betrag = params.betrag.replace(',', '.');
}
return {
method: 'post',
url: 'api/frontend/v1/stv/konto/insert',
@@ -52,6 +56,10 @@ export default {
};
},
edit(params) {
if(params.betrag)
{
params.betrag = params.betrag.replace(',', '.');
}
return {
method: 'post',
url: 'api/frontend/v1/stv/konto/update',
@@ -65,10 +73,14 @@ export default {
params: { buchungsnr }
};
},
getBuchungstypen() {
getBuchungstypen(studiensemester_kurzbz) {
let url = 'api/frontend/v1/stv/konto/getBuchungstypen'
if (!!studiensemester_kurzbz)
url = url + '/' + encodeURIComponent(studiensemester_kurzbz);
return {
method: 'get',
url: 'api/frontend/v1/stv/konto/getBuchungstypen'
url: url
};
}
},
};
-38
View File
@@ -1,38 +0,0 @@
/**
* Copyright (C) 2025 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export default {
get() {
return {
method: 'get',
url: 'api/frontend/v1/tempus/config/get'
};
},
getHeader() {
return {
method: 'get',
url: 'api/frontend/v1/tempus/config/getHeader'
};
},
set(params) {
return {
method: 'post',
url: 'api/frontend/v1/tempus/config/set',
params
};
}
};
@@ -1,17 +0,0 @@
export default {
search(query) {
return {
method: 'get',
url: 'api/frontend/v1/tempus/coursepicker/search',
params: { query }
};
},
getByStg(stg, studiensemester_kurzbz) {
return {
method: 'get',
url: 'api/frontend/v1/tempus/coursepicker/getByStg',
params: { stg, studiensemester_kurzbz }
};
},
};
-108
View File
@@ -1,108 +0,0 @@
export default {
getPlan(filter, start_date, end_date)
{
return {
method: 'get',
url: '/api/frontend/v1/tempus/Kalender/getPlan',
params: { ...filter, start_date, end_date }
};
},
getPlanLecturer(start_date, end_date)
{
return {
method: 'get',
url: '/api/frontend/v1/tempus/Kalender/getPlanLecturer',
params: { start_date, end_date }
};
},
getPlanStudent(start_date, end_date)
{
return {
method: 'get',
url: '/api/frontend/v1/tempus/Kalender/getPlanStudent',
params: { start_date, end_date }
};
},
syncToLecturer(kalender_id)
{
return {
method: 'post',
url: '/api/frontend/v1/tempus/Kalender/syncToLecturer',
params: { kalender_id }
};
},
syncToStudent(kalender_id)
{
return {
method: 'post',
url: '/api/frontend/v1/tempus/Kalender/syncToStudent',
params: { kalender_id }
};
},
sync()
{
return {
method: 'post',
url: '/api/frontend/v1/tempus/Kalender/sync',
};
},
getLektorZeitsperren(emp, start_date, end_date) {
return {
method: 'get',
url: '/api/frontend/v1/tempus/Kalender/getZeitsperren',
params: { emp, start_date, end_date }
};
},
getLektorZeitwuensche(emp, start_date, end_date) {
return {
method: 'get',
url: '/api/frontend/v1/tempus/Kalender/getZeitwuensche',
params: { emp, start_date, end_date }
};
},
getStunden() {
return {
method: 'get',
url: '/api/frontend/v1/tempus/Kalender/getStunden',
};
},
updateKalenderEvent(kalender_id, updatedInfos) {
return {
method: 'post',
url: '/api/frontend/v1/tempus/Kalender/updateKalenderEvent',
params: { kalender_id, updatedInfos}
};
},
addKalenderEvent(lehreinheit_id, ort_kurzbz, start_date, end_date) {
return {
method: 'post',
url: '/api/frontend/v1/tempus/Kalender/addKalenderEvent',
params: { lehreinheit_id, ort_kurzbz, start_date, end_date}
};
},
getRaumvorschlag(start_date, end_date, lehreinheit_id) {
return {
method: 'get',
url: '/api/frontend/v1/tempus/Kalender/getRaumvorschlag',
params: { start_date, end_date, lehreinheit_id}
};
},
getHistory(kalender_id) {
return {
method: 'get',
url: '/api/frontend/v1/tempus/Kalender/getHistory',
params: { kalender_id }
};
},
deleteEntry(kalender_id) {
return {
method: 'post',
url: '/api/frontend/v1/tempus/Kalender/deleteEntry',
params: { kalender_id }
};
},
};
@@ -1,59 +0,0 @@
/**
* Copyright (C) 2025 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export default {
getInformation() {
return {
method: 'get',
url: '/api/frontend/v1/tempus/Reservierung/getInformation',
};
},
searchTeilnehmer(query)
{
return {
method: 'get',
url: `/api/frontend/v1/tempus/Reservierung/getLektor?query=${encodeURIComponent(query)}`
};
},
searchGroup(query)
{
return {
method: 'get',
url: `/api/frontend/v1/tempus/Reservierung/searchGroup?query=${encodeURIComponent(query)}`
};
},
getGruppen(query) {
return {
method: 'get',
url: `/api/frontend/v1/tempus/Reservierung/getGruppen?query=${encodeURIComponent(query)}`
};
},
getRollen() {
return {
method: 'get',
url: '/api/frontend/v1/tempus/Reservierung/getRollen',
};
},
addReservierung(titel, beschreibung, ort_kurzbz, start_date, end_date, teilnehmer, specialFinalGroups, specialGroups, groups) {
return {
method: 'post',
url: '/api/frontend/v1/tempus/Reservierung/addReservierung',
params: { titel, beschreibung, ort_kurzbz, start_date, end_date, teilnehmer, specialFinalGroups, specialGroups, groups}
};
},
};
-45
View File
@@ -1,45 +0,0 @@
/**
* Copyright (C) 2024 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import FhcTempus from "../components/Tempus/Tempus.js";
import Phrasen from "../plugins/Phrasen.js";
import {capitalize} from "../helpers/StringHelpers.js";
const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
const router = VueRouter.createRouter({
history: VueRouter.createWebHistory(),
routes: [
{ path: `/${ciPath}/Tempus`, component: FhcTempus },
]
});
const app = Vue.createApp();
app.config.globalProperties.$capitalize = capitalize;
app
.use(router)
.use(primevue.config.default, {
zIndex: {
overlay: 1100
}
})
.use(Phrasen)
.directive('tooltip', primevue.tooltip)
.mount('#main');
+15 -37
View File
@@ -1,31 +1,23 @@
import BaseDraganddrop from './Base/DragAndDrop.js';
import BaseHeader from './Base/Header.js';
import BaseSlider from './Base/Slider.js';
import BsModal from '../Bootstrap/Modal.js';
import CalClick from '../../directives/Calendar/Click.js';
import DragClick from '../../directives/dragClick.js';
import Draggable from '../../directives/draggable.js';
import Drop from '../../directives/drop.js';
export default {
name: "CalendarBase",
components: {
BaseDraganddrop,
BaseHeader,
BaseSlider,
BsModal
},
directives: {
CalClick,
DragClick,
Draggable,
Drop
CalClick
},
provide() {
return {
events: Vue.computed(() => this.convertedEvents),
backgrounds: Vue.computed(() => this.convertedBackgrounds),
dropAllowed: Vue.computed(() => !!this.onDrop),
onDrop: Vue.computed(() => this.onDrop || null),
locale: Vue.computed(() => this.locale),
timezone: Vue.computed(() => this.timezone),
timeGrid: Vue.computed(() => this.timeGrid),
@@ -51,20 +43,8 @@ export default {
return () => true;
}),
resizableEvents: Vue.computed(() => {
if (!this.resizableEvents)
return () => false;
if (Array.isArray(this.resizableEvents))
return event => this.resizableEvents.includes(event.type);
if (this.resizableEvents instanceof Function)
return this.resizableEvents;
return () => true;
}),
hasDragoverFunc: Vue.computed(() => this.onDragover),
mode: Vue.computed(() => this.mode),
onResize: Vue.computed(() => this.onResize || null),
mode: Vue.computed(() => this.mode)
};
},
props: {
@@ -113,17 +93,11 @@ export default {
type: Boolean,
default: undefined
},
btnTableList: {
type: Boolean,
default: undefined
},
timeGrid: Array,
draggableEvents: [Boolean, Array, Function],
dropableEvents: [Boolean, Array, Function],
resizableEvents: [Boolean, Array, Function],
onDragover: Function,
onDrop: Function,
onResize: Function
onDrop: Function
},
emits: [
"click:next",
@@ -214,7 +188,7 @@ export default {
},
watch: {
sDate(n, o) {
if (this.sDate.isValid && (!this.internalDate || !this.sDate.hasSame(this.internalDate, 'day')))
if (this.sDate.isValid && !this.sDate.hasSame(this.internalDate, 'day'))
this.internalDate = this.sDate;
},
sMode() {
@@ -266,7 +240,9 @@ export default {
break;
}
},
onDropItem(evt, start, end) {
this.$emit('drop', evt, start, end);
},
showEventModal(eventObj) {
this.modalEvent = eventObj;
this.$refs.modal.show();
@@ -287,7 +263,11 @@ export default {
},
template: /* html */`
<div class="fhc-calendar-base h-100">
<div class="card h-100"
<base-draganddrop
class="card h-100"
:events="convertedEvents"
:backgrounds="convertedBackgrounds"
@drop="onDropItem"
v-cal-click:container
@cal-click-default.capture="handleClickDefaults"
>
@@ -302,7 +282,6 @@ export default {
:btn-week="!!modes['week'] && (btnWeek || (showBtns && btnWeek !== false))"
:btn-month="!!modes['month'] && (btnMonth || (showBtns && btnMonth !== false))"
:btn-list="!!modes['list'] && (btnList || (showBtns && btnList !== false))"
:btn-table-list="!!modes['tableList'] && (btnTableList || (showBtns && btnTableList !== false))"
:mode-options="modeOptions ? modeOptions[cMode] : undefined"
>
<slot name="actions" />
@@ -314,12 +293,11 @@ export default {
@update:range="$emit('update:range', $event)"
@request-modal-open="showEventModal"
@request-modal-close="hideEventModal"
@drop="$emit('drop', $event)"
v-bind="modeOptions ? modeOptions[cMode] : null || {}"
>
<template v-slot="slot"><slot v-bind="slot" /></template>
</component>
</div>
</base-draganddrop>
<bs-modal ref="modal" dialog-class="modal-lg" body-class="" @hidden-bs-modal="onModalHidden">
<template #title>
<slot v-if="modalEvent" v-bind="{mode: 'eventheader', event: modalEvent.event}" />
@@ -0,0 +1,165 @@
import DragAndDrop from '../../../helpers/DragAndDrop.js';
import CalDnd from '../../../directives/Calendar/DragAndDrop.js';
/**
* TODO(chris): this needs serious rework!
*/
export default {
name: "CalendarDragAndDrop",
directives: {
CalDnd
},
provide() {
return {
events: Vue.computed(() => this.correctedEvents),
backgrounds: Vue.computed(() => this.backgrounds),
dropAllowed: Vue.computed(() => this.dragging && this.dropAllowed)
};
},
inject: {
mode: "mode",
dropableEvents: "dropableEvents"
},
props: {
events: Array,
backgrounds: Array
},
emits: [
"drop"
],
data() {
return {
dragging: false,
allowed: false,
draggedInternalEvent: null,
draggedExternalEvent: null,
targetTimestamp: 0,
targetGridEnds: null,
dropAllowed: false,
shadowPreview: false // TODO(chris): IMPLEMENT! (use background instead of event as preview)
};
},
computed: {
correctedEvents() {
if (this.dragging) {
if (this.draggedInternalEvent) {
const index = this.events.findIndex(e => e.id == this.draggedInternalEvent.id);
if (this.previewEvent && !this.shadowPreview)
return this.events.toSpliced(index, 1, this.previewEvent);
else
return this.events.toSpliced(index, 1);
}
if (this.previewEvent && !this.shadowPreview)
return [...this.events, this.previewEvent];
}
return this.events;
},
correctedBackgrounds() {
if (this.dragging) {
if (this.shadowPreview) {
// TODO(chris): how to get the length
return [...this.backgrounds, {
start: new Date(this.targetTimestamp),
class: 'shadow-preview'
}];
}
}
return this.backgrounds;
},
previewEvent() {
if (!this.dragging || !this.dropAllowed)
return null;
if (!this.targetTimestamp)
return null;
const event = this.draggedInternalEvent || this.draggedExternalEvent;
if (!event)
return null;
// TODO(chris): calculate length correctly from orig
let length = event.end - event.start;
if (this.targetGridEnds)
length = this.targetGridEnds.find(end => end >= this.targetTimestamp + length) - this.targetTimestamp;
return {
orig: event.orig,
start: this.targetTimestamp,
end: this.targetTimestamp + length
};
}
},
methods: {
onDragstart(evt) {
const data = DragAndDrop.convertToTransferData(evt.detail.item.orig);
if (DragAndDrop.isValidDragObject(data)) {
DragAndDrop.setTransferData(evt.detail.originalEvent, data);
this.draggedInternalEvent = evt.detail.item;
}
},
onDragend() {
this.draggedInternalEvent = null;
this.dragging = false;
},
onDragenter(evt) {
this.dragging = true;
if (!this.draggedInternalEvent) {
const event = DragAndDrop.getValidTransferData(evt.detail.originalEvent);
if (event) {
this.draggedExternalEvent = {
id: event.id,
type: event.type,
start: event.isostart
? luxon.DateTime.fromISO(event.isostart).setZone(this.timezone)
: luxon.DateTime.local().setZone(this.timezone),
end: event.isoend
? luxon.DateTime.fromISO(event.isoend).setZone(this.timezone)
: luxon.DateTime.local().setZone(this.timezone),
orig: event
};
} else {
this.draggedExternalEvent = null;
}
this.dropAllowed = this.dropableEvents(event, this.mode);
} else {
this.dropAllowed = this.dropableEvents(this.draggedInternalEvent, this.mode);
}
},
onDragleave() {
this.dragging = false;
},
onDragchange(evt) {
this.targetTimestamp = evt.detail.timestamp;
this.targetGridEnds = evt.detail.ends || null;
},
onDrop(evt) {
if (!this.dragging || !this.dropAllowed)
return;
this.$emit('drop', evt, this.previewEvent.start, this.previewEvent.end);
this.dropAllowed = false;
this.dragging = false;
}
},
template: `
<div
class="fhc-calendar-base-draganddrop"
@calendar-dragstart="onDragstart"
@calendar-dragend="onDragend"
v-cal-dnd:dropcage
@calendar-dragenter="onDragenter"
@calendar-dragleave="onDragleave"
@calendar-dragchange="onDragchange"
@drop="onDrop"
>
<slot />
</div>
`
}
+23 -188
View File
@@ -1,8 +1,7 @@
import GridLine from './Grid/Line.js';
import GridLineEvent from './Grid/Line/Event.js';
import drop from '../../../directives/drop.js';
import { useResizeHandler } from '../../../helpers/Tempus/ResizeHandler.js';
import CalDnd from '../../../directives/Calendar/DragAndDrop.js';
export default {
name: "CalendarGrid",
@@ -11,18 +10,12 @@ export default {
GridLineEvent
},
directives: {
drop
CalDnd
},
inject: {
originalEvents: "events",
originalBackgrounds: "backgrounds",
dropAllowed: "dropAllowed",
onDrop: "onDrop",
onResize: "onResize",
timeGrid: {
from: "timeGrid",
default: () => []
}
dropAllowed: "dropAllowed"
},
provide() {
return {
@@ -64,10 +57,10 @@ export default {
},
data() {
return {
dragging: false,
resizeObserver: null,
mutationObserver: null,
userScroll: true,
isDragging: false
userScroll: true
};
},
computed: {
@@ -259,27 +252,17 @@ export default {
pageLeft += this.getPageLeft(el.offsetParent);
return pageLeft;
},
getTimestampFromMouse(evt, dayTimestamp)
{
getTimestampFromMouse(evt, dayTimestamp) {
let mouse, mouseFrac;
const grabOffsetY = parseFloat(evt.dataTransfer.getData('fhc-grab-offset-y')) || 0;
const grabOffsetX = parseFloat(evt.dataTransfer.getData('fhc-grab-offset-x')) || 0;
if (this.flipAxis)
{
mouse = evt.pageX - this.getPageLeft(this.$refs.body) + this.$refs.scroller.scrollLeft - grabOffsetX;
if (this.flipAxis) {
mouse = evt.pageX - this.getPageLeft(this.$refs.body) + this.$refs.main.scrollLeft;
mouseFrac = mouse / this.$refs.body.offsetWidth;
}
else
{
mouse = evt.pageY - this.getPageTop(this.$refs.body) + this.$refs.scroller.scrollTop - grabOffsetY;
} else {
mouse = evt.pageY - this.getPageTop(this.$refs.body) + this.$refs.main.scrollTop;
mouseFrac = mouse / this.$refs.body.offsetHeight;
}
let rawTimestamp = dayTimestamp + this.start + Math.floor((this.end - this.start) * mouseFrac);
let fiveMinutes = 5 * 60 * 1000;
return Math.round(rawTimestamp / fiveMinutes) * fiveMinutes;
return dayTimestamp + this.start + Math.floor((this.end - this.start) * mouseFrac);
},
/* SCROLLING */
@@ -325,151 +308,7 @@ export default {
} else {
this.$refs.scroller.scrollTo(0, 0);
}
},
calculateNettoDuration(start, end) {
const startDay = start.startOf('day');
const blocks = this.axisPartsWithBreaks.filter(p => p.index !== undefined);
let nettoDuration = luxon.Duration.fromMillis(0);
for (const block of blocks)
{
const blockStart = startDay.plus(block.start);
const blockEnd = startDay.plus(block.end);
const overlapStart = blockStart > start ? blockStart : start;
const overlapEnd = blockEnd < end ? blockEnd : end;
if (overlapStart < overlapEnd) {
nettoDuration = nettoDuration.plus(overlapEnd.diff(overlapStart));
}
}
return nettoDuration;
},
calculateDropEnd(dropStart, durationMs) {
const duration = luxon.Duration.fromMillis(durationMs);
const blocks = this.axisPartsWithBreaks.filter(p => p.index !== undefined);
let accumulated = luxon.Duration.fromMillis(0);
for (const block of blocks)
{
const blockStart = dropStart.startOf('day').plus(block.start);
const blockEnd = dropStart.startOf('day').plus(block.end);
if (blockEnd <= dropStart) continue;
const relevantStart = blockStart > dropStart ? blockStart : dropStart;
const relevantDuration = blockEnd.diff(relevantStart);
accumulated = accumulated.plus(relevantDuration);
if (accumulated >= duration)
{
const overflow = accumulated.minus(duration);
return blockEnd.minus(overflow);
}
}
const lastBlock = blocks[blocks.length - 1];
return dropStart.startOf('day').plus(lastBlock.end);
},
onDropSnap(evt, items, date, part) {
let obj = items;
if (!obj?.orig) return;
const dayStr = evt?.currentTarget?.dataset?.day;
const dropDay = dayStr ? luxon.DateTime.fromISO(dayStr) : date;
const rawTimestamp = this.getTimestampFromMouse(evt, dropDay.toMillis());
const grabTime = luxon.DateTime.fromMillis(rawTimestamp);
const blocks = this.axisPartsWithBreaks.filter(p => p.index !== undefined);
const grabOffset = grabTime.diff(dropDay);
const snappedPart = blocks.find(b => grabOffset >= b.start && grabOffset < b.end) || part;
const dropStart = dropDay.plus(snappedPart.start);
let nettoDuration = this._getNettoDurationForDrop(obj);
let dropEnd = this.calculateDropEnd(dropStart, nettoDuration);
this.onDrop?.({
item: [obj],
start: dropStart.toISO(),
end: dropEnd.toISO()
});
},
_getNettoDurationForDrop(obj) {
if (obj.orig?.isostart && obj.orig?.isoend)
{
const s = luxon.DateTime.fromISO(obj.orig.isostart);
const e = luxon.DateTime.fromISO(obj.orig.isoend);
if (s.isValid && e.isValid)
return this.calculateNettoDuration(s, e);
}
if (obj.stundenblockung)
{
let blocks = this.axisPartsWithBreaks.filter(p => p.index !== undefined);
let firstBlock = blocks[0];
let blockMinutes = luxon.Duration.fromISO(firstBlock.end).minus(luxon.Duration.fromISO(firstBlock.start)).as('minutes');
if (!Number.isFinite(blockMinutes) || blockMinutes <= 0) blockMinutes = 45;
return luxon.Duration.fromObject({ minutes: obj.stundenblockung * blockMinutes });
}
return luxon.Duration.fromObject({ minutes: 45 });
},
onDropFree(evt, items, date)
{
let obj = items;
if (!obj?.orig)
return;
const timestamp = this.getTimestampFromMouse(evt, date);
const dropStart = luxon.DateTime.fromMillis(timestamp);
let nettoDuration = this._getNettoDurationForDrop(obj);
let dropEnd = this.calculateDropEnd(dropStart, nettoDuration);
this.onDrop?.({
item: [obj],
start: dropStart.toISO(),
end: dropEnd.toISO()
});
},
handleResizeStart({ edge, evt, el, event })
{
const gridEl = this.$refs.body;
if (!gridEl)
return;
this.resizeHandler.startResize(edge, evt, {
el,
gridEl,
event,
timeGrid: this.timeGrid,
onEnd: ({ event, newStart, newEnd }) => {
const orig = event?.orig;
if (!orig || !newStart || !newEnd)
return;
this.onResize?.({
item: [{ type: 'kalender', id: orig.kalender_id, orig }],
start: newStart,
end: newEnd
});
}
});
},
},
setup()
{
const resizeHandler = useResizeHandler();
return { resizeHandler };
}
},
beforeUnmount() {
this.disableAutoScroll();
@@ -543,11 +382,11 @@ export default {
ref="body"
class="grid-body"
style="display:grid;grid-template-rows:subgrid;grid-template-columns:subgrid"
@dragenter="isDragging = true"
@dragleave.self="isDragging = false"
@dragend="isDragging = false"
@drop="isDragging = false"
:style="'grid-' + axisCol + ':2/-1;grid-' + axisRow + ':1/-1'"
v-cal-dnd:dropcage
@calendar-dragenter="dragging = true"
@calendar-dragleave="dragging = false"
@dragover="dropAllowed ? $event.preventDefault() : null"
>
<template
v-for="(date, index) in axisMain"
@@ -562,11 +401,9 @@ export default {
>
<slot name="part-body" v-bind="{ index, part }" />
<div
v-if="snapToGrid"
style="position:absolute;inset:0"
:style="{ zIndex: isDragging ? 10 : 1 }"
:data-day="date.toFormat('yyyy-MM-dd')"
v-drop:move.lehreinheit.kalender.reservierung="(evt, item) => onDropSnap(evt, item, date, part)"
v-if="snapToGrid && dragging"
style="position:absolute;inset:0;z-index:1"
v-cal-dnd:dropzone.once="{date: date.plus(part.start || part), ends: ends.slice(ends.findIndex(end => end > date))}"
></div>
</div>
<grid-line
@@ -576,7 +413,6 @@ export default {
:events="eventsNormal[index]"
:backgrounds="backgrounds[index]"
style="position:relative"
@resize-start="handleResizeStart"
:style="'grid-' + axisRow + ':1/-1;grid-' + axisCol + ':' + (1+index)"
>
<template #event="slot">
@@ -584,10 +420,9 @@ export default {
</template>
<template #dropzone>
<div
v-if="!snapToGrid"
style="position:absolute;inset:0"
:style="{ zIndex: isDragging ? 10 : 1 }"
v-drop:move.lehreinheit.kalender.reservierung="(evt, item) => onDropFree(evt, item, date)"
v-if="!snapToGrid && dragging"
style="position:absolute;inset:0;z-index:1"
v-cal-dnd:dropzone="evt => getTimestampFromMouse(evt, date)"
></div>
</template>
</grid-line>
@@ -597,4 +432,4 @@ export default {
</div>
</div>
`
}
}
@@ -74,7 +74,6 @@ export default {
:key="i"
:style="'grid-' + axisRow + ': ' + event.rows.join('/')"
:event="event"
@resize-start="$emit('resize-start', $event)"
>
<template v-slot="slot">
<slot name="event" v-bind="slot" />
@@ -1,35 +1,15 @@
import draggable from '../../../../../directives/draggable.js';
import CalDnd from '../../../../../directives/Calendar/DragAndDrop.js';
import CalClick from '../../../../../directives/Calendar/Click.js';
export default {
name: "GridLineEvent",
directives: {
draggable,
CalDnd,
CalClick
},
emits: [
'resize-start'
],
data() {
return {
contextMenu: {
show: false,
x: 0,
y: 0
}
};
},
inject: {
draggableEvents: "draggableEvents",
resizableEvents: {
from: "resizableEvents",
default: () => () => false
},
mode: "mode",
contextMenuActions: {
from: "contextMenuActions",
default: () => ({})
}
mode: "mode"
},
props: {
event: {
@@ -47,9 +27,6 @@ export default {
draggable() {
return !this.isHeaderOrFooter && this.draggableEvents(this.event.orig, this.mode);
},
resizable() {
return !this.isHeaderOrFooter && this.resizableEvents(this.event.orig, this.mode);
},
classes() {
const classes = [];
if (this.isHeaderOrFooter) {
@@ -60,102 +37,21 @@ export default {
if (this.event.endsHere)
classes.push('event-end');
}
return classes;
},
dragKalenderCollection() {
const orig = this.event.orig;
return {
type: 'kalender',
id: orig?.kalender_id ?? null,
orig,
};
},
activeContextActions() {
if (this.isHeaderOrFooter) return [];
const type = this.event.orig?.type ?? 'lehreinheit';
return this.contextMenuActions[type] ?? this.contextMenuActions['default'] ?? [];
return classes
}
},
methods: {
onResizeStart(edge, evt) {
this.$emit('resize-start', {
edge,
evt,
el: this.$refs.eventEl,
event: this.event
});
},
onRightClick(evt) {
this.contextMenu.show = true;
this.contextMenu.x = evt.clientX;
this.contextMenu.y = evt.clientY;
},
onContextAction(action) {
this.contextMenu.show = false;
action(this.event.orig);
},
closeContextMenu() {
this.contextMenu.show = false;
},
onDragStart(evt) {
const rect = this.$refs.eventEl.getBoundingClientRect();
evt.dataTransfer.setData('fhc-grab-offset-y', evt.clientY - rect.top);
evt.dataTransfer.setData('fhc-grab-offset-x', evt.clientX - rect.left);
},
},
template:`
template: /* html */`
<div
class="fhc-calendar-base-grid-line-event event"
:class="classes"
style="z-index: 2"
style="z-index: 1"
:draggable="draggable"
ref="eventEl"
@dragstart="onDragStart"
v-draggable:move.noimage="draggable ? dragKalenderCollection : {}"
v-cal-dnd:draggable="event"
v-cal-click:event="isHeaderOrFooter ? event : event.orig"
@contextmenu.prevent="onRightClick"
>
<div
v-if="resizable"
class="fhc-resize-bar fhc-resize-bar--top"
@pointerdown.prevent.stop="onResizeStart('start', $event)"
@click.stop
>
<i class="fa-solid fa-grip-lines text-muted"></i>
</div>
<slot :event="isHeaderOrFooter ? event : event.orig">
{{ event.orig }}
</slot>
<div
v-if="resizable"
class="fhc-resize-bar fhc-resize-bar--bottom"
@pointerdown.prevent.stop="onResizeStart('end', $event)"
@click.stop
>
<i class="fa-solid fa-grip-lines text-muted"></i>
</div>
<teleport to="body">
<div
v-if="contextMenu.show"
style="position:fixed; inset:0; z-index:9998"
@click="closeContextMenu"
@contextmenu.prevent="closeContextMenu"
/>
<ul
v-if="contextMenu.show"
class="dropdown-menu show"
:style="{ position: 'fixed', top: contextMenu.y + 'px', left: contextMenu.x + 'px', zIndex: 9999 }"
>
<li v-for="action in activeContextActions" :key="action.label">
<button class="dropdown-item" type="button" @click.stop="onContextAction(action.action)">
<i v-if="action.icon" :class="action.icon + ' me-2'"></i>
{{ action.label }}
</button>
</li>
</ul>
</teleport>
</div>
`
}
}
@@ -1,32 +0,0 @@
import draggable from '../../../../../directives/draggable.js';
export default {
name: 'EventCard',
directives: {
draggable,
},
props: {
event: { type: Object, required: true },
parked: Boolean
},
computed: {
dragKalenderCollection() {
return this.event
},
},
template: `
<div
class="fhc-calendar-base-grid-line-event event"
v-draggable:move.noimage="dragKalenderCollection"
style="border:1px"
>
<div class="title">
{{ event.orig.topic || event.orig.titel || event.orig.lehrfach }}
</div>
<div>
{{ event.orig.datum }} {{ event.orig.beginn }}{{ event.orig.ende }}
<span v-if="event.ort_kurzbz">· {{ event.orig.ort_kurzbz }}</span>
</div>
</div>
`
};
+1 -12
View File
@@ -24,8 +24,7 @@ export default {
btnMonth: Boolean,
btnWeek: Boolean,
btnDay: Boolean,
btnList: Boolean,
btnTableList: Boolean
btnList: Boolean
},
emits: [
"next",
@@ -90,16 +89,6 @@ export default {
>
<i class="fa fa-table-list"></i>
</button>
<button
v-if="btnTableList"
type="button"
class="btn btn-outline-secondary"
:class="{active: mode === 'tableList'}"
@click="clickMode($event, 'tableList')"
>
<i class="fa fa-table-list"></i>
</button>
</div>
</div>
</div>
@@ -39,7 +39,6 @@ export default {
case "list":
return [this.convertedDate.startOf('day').ts, this.convertedDate.startOf('day').plus({ days: this.listLength }).ts - 1];
case "week":
case "tableList":
return [this.convertedDate.startOf('week', { useLocaleWeeks: true }).ts, this.convertedDate.endOf('week', { useLocaleWeeks: true }).ts];
case "day":
return this.convertedDate;
@@ -52,7 +51,6 @@ export default {
case "month":
return this.date.toLocaleString({ month: 'long', year: 'numeric' });
case "week":
case "tableList":
var year = this.date.localWeekYear;
var week = this.date.toFormat('nn');
return this.$p.t('calendar/year_kw', { year, week });
@@ -78,7 +76,6 @@ export default {
break;
case "list":
case "week":
case "tableList":
date = luxon.DateTime.fromJSDate(value[0]).setZone(this.timezone, { keepLocalTime: true }).setLocale(this.locale);
break;
case "day":
@@ -99,7 +96,7 @@ export default {
@update:model-value="update"
:format="() => title"
:month-picker="mode == 'month'"
:week-picker="mode == 'week' || mode == 'tableList'"
:week-picker="mode == 'week'"
:range="mode == 'list' ? { autoRange: listLength - 1 } : false"
:text-input="mode == 'day'"
:week-start="weekStart"
@@ -1,8 +1,7 @@
import LabelDay from '../../Base/Label/Day.js';
import LabelDow from '../../Base/Label/Dow.js';
import draggable from '../../../../directives/draggable.js';
import CalDnd from '../../../../directives/Calendar/DragAndDrop.js';
import CalClick from '../../../../directives/Calendar/Click.js';
// TODO(chris): drag and drop
@@ -14,7 +13,7 @@ export default {
LabelDow
},
directives: {
draggable,
CalDnd,
CalClick
},
inject: {
@@ -87,7 +86,7 @@ export default {
v-else
class="event"
:draggable="draggable(event)"
v-draggable="event.orig"
v-cal-dnd:draggable="event"
v-cal-click:event="event.orig"
>
<slot :event="event.orig" mode="list" />
@@ -36,9 +36,7 @@ export default {
}
}
return events;
}),
draggableEvents: () => false,
resizableEvents: () => false
})
};
},
inject: {
-109
View File
@@ -1,109 +0,0 @@
import BaseSlider from '../Base/Slider.js';
import TableView from './Table/View.js';
export default {
name: "ModeTable",
components: {
BaseSlider,
TableView
},
props: {
currentDate: {
type: luxon.DateTime,
required: true
}
},
emits: [
"update:currentDate",
"update:range",
"click",
"requestModalOpen"
],
data() {
return {
focusDate: this.currentDate,
rangeOffset: 0
};
},
computed: {
range() {
let first = this.focusDate.startOf('week', { useLocaleWeeks: true });
let last = this.focusDate.endOf('week', { useLocaleWeeks: true });
if (this.rangeOffset != 0) {
if (this.rangeOffset < 0) {
first = first.plus({ weeks: this.rangeOffset });
} else {
last = last.plus({ weeks: this.rangeOffset });
}
}
return luxon.Interval.fromDateTimes(first, last);
}
},
watch: {
currentDate() {
if (this.currentDate.locale != this.focusDate.locale) {
this.focusDate = this.currentDate;
this.$emit('update:range', this.range);
} else {
this.rangeOffset = this.currentDate.startOf('week', { useLocaleWeeks: true }).diff(this.focusDate.startOf('week', { useLocaleWeeks: true }), 'weeks').weeks;
if (this.rangeOffset) {
this.$emit('update:range', this.range);
this.$refs.slider.slidePages(this.rangeOffset).then(this.updatePage);
}
}
}
},
methods: {
prevPage() {
this.rangeOffset = this.$refs.slider.target - 1;
this.$emit('update:range', this.range);
this.$refs.slider.prevPage().then(this.updatePage);
},
nextPage() {
this.rangeOffset = this.$refs.slider.target + 1;
this.$emit('update:range', this.range);
this.$refs.slider.nextPage().then(this.updatePage);
},
updatePage(weeks) {
const newFocusDate = this.focusDate.plus({ weeks });
this.focusDate = newFocusDate;
this.rangeOffset = 0;
this.$emit('update:currentDate', this.focusDate);
this.$emit('update:range', this.range);
},
viewAttrs(weeks) {
const day = this.focusDate.plus({ weeks });
return { ...this.$attrs, day };
},
handleClickDefaults(evt) {
switch (evt.detail.source) {
case 'day':
// default: Set current-date
this.$emit('update:currentDate', evt.detail.value);
break;
case 'event':
// default: Request Modal
this.$emit('requestModalOpen', { event: evt.detail.value });
break;
}
}
},
mounted() {
this.$emit('update:range', this.range);
},
template: `
<div
class="fhc-calendar-mode-week flex-grow-1 position-relative"
@cal-click-default.capture="handleClickDefaults"
>
<base-slider ref="slider" v-slot="slot">
<table-view ref="view" v-bind="viewAttrs(slot.offset)">
<template v-slot="slot"><slot v-bind="slot" mode="week" /></template>
</table-view>
</base-slider>
</div>
`
}
@@ -1,147 +0,0 @@
import {CoreFilterCmpt} from "../../../../components/filter/Filter.js";
import BsModal from '../../../Bootstrap/Modal.js';
import FormInput from "../../../Form/Input.js";
import ApiDetails from "../../../../api/lehrveranstaltung/details.js";
export default {
name: "TableView",
inject: {
events: "events",
timezone: "timezone"
},
components: {
CoreFilterCmpt,
BsModal,
FormInput
},
props: {
day: {
type: luxon.DateTime,
required: true
}
},
data()
{
return {
raumtyp_array: []
}
},
computed: {
start() {
return this.day.startOf('week', { useLocaleWeeks: true });
},
preparedEvents() {
const end = this.start.plus({ days: 7 });
return this.events
.filter(e => e.start < end && e.end > this.start)
.sort((a, b) => a.start.ts - b.start.ts)
.map(event => ({
...event.orig,
row_index: event.id,
}));
},
tabulatorOptions() {
return {
index: "row_index",
layout: 'fitDataStretch',
placeholder: "Keine Daten verfügbar",
persistenceID: "2026_03_09_table_view_v1",
data: this.preparedEvents,
columns: [
{
formatter: 'rowSelection',
titleFormatter: 'rowSelection',
titleFormatterParams: {
rowRange: "active"
},
headerSort: false,
width: 40
},
{title: 'Datum', field: 'datum', headerFilter: "input", formatter: (cell) => {
let val = cell.getValue();
if (!val)
return '&nbsp;';
return luxon.DateTime.fromISO(val).toFormat('dd.MM.yyyy')
}
},
{title: 'Von', field: 'beginn', headerFilter: "input"},
{title: 'Bis', field: 'ende', headerFilter: "input"},
{title: 'Lehrfach', field: 'lehrfach', headerFilter: "input"},
{title: 'Bezeichnung', field: 'lehrfach_bez', headerFilter: "input"},
{title: 'Lehrform', field: 'lehrform', headerFilter: "input"},
{title: 'Raum', field: 'ort_kurzbz', headerFilter: "input"},
{
title: 'Lektor',
field: 'lektor',
headerFilter: "input",
mutator: (value) => {
if (!value)
return '';
return value.map(l => l.kurzbz).join(', ') ?? ''
}
},
{title: 'OE', field: 'organisationseinheit', headerFilter: "input"},
{title: 'Status', field: 'status_kurzbz', headerFilter: "input"},
]
}
}
},
methods:
{
openModal() {
this.$refs.raumModal.show();
}
},
watch: {
preparedEvents(newData) {
this.$refs.tableViewTable?.tabulator?.setData(newData);
}
},
mounted() {
this.$api.call(ApiDetails.getRaumtyp())
.then(result => {
this.raumtyp_array = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
},
template: /* html */`
<div class="fhc-calendar-mode-table-view h-100 overflow-auto">
<core-filter-cmpt
ref="tableViewTable"
:tabulator-options="tabulatorOptions"
:table-only="true"
:side-menu="false"
:download="true"
>
<template #actions>
<button class="btn btn-outline-secondary btn-sm">Verschieben</button>
<button @click="openModal" class="btn btn-outline-secondary btn-sm">Raum wechsel</button>
</template>
</core-filter-cmpt>
<bs-modal ref="raumModal" class="bootstrap-prompt" dialogClass="modal-lg">
<template #title>Raum verschiebung</template>
<form-input
:label="$p.t('lehre', 'raumtyp')"
type="select"
container-class="col-3"
name="raumtyp"
>
<option
v-for="raumtyp in raumtyp_array"
:value="raumtyp.raumtyp_kurzbz"
:key="raumtyp.raumtyp_kurzbz"
>
{{ raumtyp.raumtyp_kurzbz }} {{ raumtyp.beschreibung }}
</option>
</form-input>
<template #footer>
<button type="button" class="btn btn-primary">{{ $p.t('ui', 'speichern') }}</button>
</template>
</bs-modal>
</div>
`
}
-257
View File
@@ -1,257 +0,0 @@
import FhcCalendar from "./Base.js";
import { useEventLoader } from '../../composables/EventLoader.js';
import ModeWeek from './Mode/Week.js';
import ModeMonth from './Mode/Month.js';
import ModeTable from './Mode/Table.js';
import ApiKalender from '../../api/factory/tempus/kalender.js';
import draggable from '../../directives/draggable.js';
export default {
name: "CalendarTempus",
components: {
FhcCalendar
},
inject: {
renderers: {from: 'renderers'},
appConfig: {
from: 'appConfig',
default: {
visible_status: 'all'
}
}
},
directives: {
draggable,
},
props: {
timezone: {
type: String,
required: true
},
date: {
type: [Date, String, Number, luxon.DateTime],
default: luxon.DateTime.local()
},
mode: {
type: String,
default: 'Week'
},
getPromiseFunc: {
type: Function,
required: true
},
parkedEvents: {
type: Object,
default: () => new Set()
},
visibleLecturers: {
type: Array,
default: null
},
extraBackgrounds: {
type: Array,
default: () => []
},
visibleStatus: {
type: Array,
default: () => ['all']
},
},
emits: [
"update:date",
"update:mode",
"update:range",
"drop",
"resize"
],
data() {
return {
modes: {
week: Vue.markRaw(ModeWeek),
month: Vue.markRaw(ModeMonth),
tableList: Vue.markRaw(ModeTable),
},
modeOptions: {
day: {
emptyMessage: Vue.computed(() => this.$p.t('lehre/noLvFound')),
emptyMessageDetails: Vue.computed(() => this.$p.t('lehre/noLvFound'))
},
week: {
collapseEmptyDays: false
}
},
currentMode: this.mode,
teachingunits: null,
showRaster: true,
};
},
computed: {
backgrounds() {
let now = luxon.DateTime.now().setZone(this.timezone);
let past = [];
if (this.mode == 'Month')
{
past = [{
class: 'background-past',
end: now.startOf('day')
}];
}
else
{
past = [{
class: 'background-past',
end: now,
label: now.startOf('minute').toISOTime({ suppressSeconds: true, includeOffset: false })
}];
}
return [
...past,
...(this.extraBackgrounds || [])
];
},
visibleEvents()
{
let list = this.events;
if (Array.isArray(this.visibleLecturers))
{
const visibleLectures = new Set(this.visibleLecturers);
list = list.filter(event => {
if (!event.lektor?.length)
return true;
return event.lektor.some(lektor => visibleLectures.has(lektor.mitarbeiter_uid));
});
}
if (!this.visibleStatus.length || this.visibleStatus.includes('all'))
return list;
return list.filter(event => this.visibleStatus.includes(event.status_kurzbz));
},
},
methods: {
eventStyle(event) {
if (!event.farbe)
return undefined;
return '--event-bg:#' + event.farbe;
},
updateRange(rangeInterval) {
this.rangeInterval = rangeInterval;
this.$emit('update:range', rangeInterval);
},
ondrop(payload){
this.$emit('drop', payload);
},
onresize(payload){
this.$emit('resize', payload);
},
resetEventLoader() {
this.reset();
},
},
setup(props, context) {
const rangeInterval = Vue.ref(null);
const { events, lv, reset } = useEventLoader(rangeInterval, props.getPromiseFunc);
Vue.watch(lv, newValue => {
context.emit('update:lv', newValue);
});
return {
rangeInterval,
events,
lv,
reset
};
},
created() {
this.$api
.call(ApiKalender.getStunden())
.then(res => {
return this.teachingunits = res.data.map(el => ({
id: el.stunde,
start: el.beginn,
end: el.ende
}));
});
},
template: /* html */`
<fhc-calendar
ref="calendar"
class="fhc-calendar-lvplan"
:date="date"
:modes="modes"
:mode-options="modeOptions"
:mode="mode"
:timezone="timezone"
:locale="$p.user_locale.value"
:events="visibleEvents || []"
:backgrounds="backgrounds"
:time-grid="showRaster ? teachingunits : null"
show-btns
:draggable-events="true"
:resizable-events="true"
:on-drop="currentMode === 'week' ? ondrop : null"
:on-resize="onresize"
@update:date="(newDate, newMode) => $emit('update:date', newDate, newMode)"
@update:mode="(newMode, newDate) => { currentMode = newMode; $emit('update:mode', newMode, newDate) }"
@update:range="updateRange"
>
<template v-slot="{ event, mode }">
<div
:class="['event-type-' + event.type + ' ' + mode + 'PageContainer', { 'event--parked': parkedEvents.has(String(event.kalender_id)) }]"
:type="mode == 'day' ? 'button' : undefined"
:style="eventStyle(event)"
>
<component
v-if="mode == 'event'"
:is="renderers[event.type]?.modalContent"
:event="event"
></component>
<component
v-else-if="mode == 'eventheader'"
:is="renderers[event.type]?.modalTitle"
:event="event"
></component>
<component
v-else
:is="renderers[event.type]?.calendarEvent"
:event="event"
></component>
</div>
</template>
<template #actions>
<div class="d-flex align-items-center gap-2">
<div
class="d-flex align-items-center gap-2"
style="cursor:pointer"
@click="showRaster = !showRaster"
>
<i :class="showRaster ? 'fa-solid fa-toggle-on text-primary' : 'fa-solid fa-toggle-off text-muted'"></i>
<span class="form-check-label">Stundenraster</span>
</div>
<div
class="d-flex align-items-center gap-2 "
v-draggable:move.noimage="{ type: 'reservierung', id: null, orig: {} }"
>
<i
class="fa-solid fa-calendar-plus text-primary"
style="cursor:pointer"
@click.stop="$emit('open-reservierung')"
></i>
<span>Reservierung</span>
</div>
</div>
</template>
</fhc-calendar>`
}
@@ -31,7 +31,7 @@ export default {
this.event.lektor.slice(0, 3).map(lektor => lektor.kurzbz).join("\n")
+ "\n" + this.$p.t('lehre/weitereLektoren', [this.event.lektor.length - 3])
].join(": "));
} else {
} else {;
tooltipArray.push([
this.$p.t('lehre/lektor'),
this.event.lektor.map(lektor => lektor.kurzbz).join("\n")
@@ -63,7 +63,7 @@ export default {
const vm = this;
tinymce.init({
target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component
//height: 800,
min_height: 300,
//plugins: ['lists'],
toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify | link',
plugins: 'link',
@@ -133,6 +133,7 @@ export default {
return this.$api
.call(ApiMessages.getDataVorlage(vorlage_kurzbz))
.then(response => {
this.editor.setContent(response.data.text);
this.formData.body = response.data.text;
this.formData.subject = response.data.subject;
}).catch(this.$fhcAlert.handleSystemError);
@@ -203,24 +204,6 @@ export default {
},
},
watch: {
'formData.body': {
handler(newVal) {
const tinymcsVal = this.editor.getContent();
if (newVal && tinymcsVal != newVal) {
//Inhalt des Editors aktualisieren
this.editor.setContent(newVal);
}
}
},
'formData.vorlage_kurzbz': {
handler(newVal){
if (newVal && newVal != null) {
this.formData.subject = newVal;
return this.getDataVorlage(newVal);
}
}
},
messageId: {
immediate: true,
handler: async function (newMessageId) {
@@ -231,6 +214,7 @@ export default {
this.replyData = result.data;
if (this.replyData.length > 0) {
this.editor.setContent(this.replyData[0].replyBody);
this.formData.subject = this.replyData[0].replySubject;
this.formData.body = this.replyData[0].replyBody;
this.formData.relationmessage_id = newMessageId;
@@ -290,19 +274,6 @@ export default {
})
.catch(this.$fhcAlert.handleSystemError);
//case of reply
if(this.messageId) {
this.$api
.call(ApiMessages.getReplyData(this.messageId))
.then(result => {
this.replyData = result.data;
this.formData.subject = this.replyData[0].replySubject;
this.formData.body = this.replyData[0].replyBody;
this.formData.relationmessage_id = this.messageId;
})
.catch(this.$fhcAlert.handleSystemError);
}
},
async mounted() {
this.initTinyMCE();
@@ -342,7 +313,7 @@ export default {
<div class="row">
<div class="col-sm-8">
<form-form class="row g-3 mt-2 h-100" ref="formMessage">
<form-form class="row g-3 mt-2 align-content-start" ref="formMessage">
<div class="row mb-3">
@@ -367,7 +338,7 @@ export default {
</div>
<!--Tiny MCE-->
<div class="row mb-3 h-100 tiny-90">
<div class="row mb-3 tiny-90">
<form-input
ref="editor"
:label="$p.t('global','nachricht') + ' *'"
@@ -62,9 +62,18 @@ export default {
const vm = this;
tinymce.init({
target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component
//height: 800,
min_height: 300,
//plugins: ['lists'],
toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify',
toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify | link',
plugins: 'link',
link_context_toolbar: true,
automatic_uploads: true,
default_link_target: "_blank",
link_title: true,
target_list: [
{ title: 'New tab', value: '_blank' },
{ title: 'Same tab', value: '_self' }
],
style_formats: [
{title: 'Blocks', block: 'div'},
{title: 'Paragraph', block: 'p'},
@@ -98,7 +107,8 @@ export default {
return this.$api
.call(ApiMessages.sendMessage(this.typeId, data))
.then(response => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent'));
if(this.openMode == "inSamePage")
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent'));
this.hideTemplate();
this.resetForm();
this.messageSent = true;
@@ -114,19 +124,17 @@ export default {
return this.$api
.call(ApiMessages.getDataVorlage(vorlage_kurzbz))
.then(response => {
this.editor.setContent(response.data.text);
this.formData.body = response.data.text;
this.formData.subject = response.data.subject;
}).catch(this.$fhcAlert.handleSystemError);
},
getPreviewText(){
console.log("subj" + this.formData.subject);
const data = new FormData();
data.append('data', JSON.stringify(this.formData.body));
data.append('ids', JSON.stringify(this.id));
console.log("subj" + this.formData.subject);
return this.$api
.call(ApiMessages.getPreviewText(
this.typeId, data))
@@ -195,6 +203,7 @@ export default {
.call(ApiMessages.getReplyData(messageId))
.then(result => {
this.replyData = result.data;
this.editor.setContent(this.replyData[0].replyBody);
this.formData.subject = this.replyData[0].replySubject;
this.formData.body = this.replyData[0].replyBody;
this.formData.relationmessage_id = messageId;
@@ -202,27 +211,6 @@ export default {
.catch(this.$fhcAlert.handleSystemError);
}
},
watch: {
'formData.body': {
handler(newVal) {
const tinymcsVal = this.editor.getContent();
if (newVal && tinymcsVal != newVal) {
//Inhalt des Editors aktualisieren
this.editor.setContent(newVal);
}
}
},
'formData.vorlage_kurzbz': {
handler(newVal){
if (newVal && newVal != null) {
this.formData.subject = newVal;
return this.getDataVorlage(newVal);
}
}
},
},
created(){
const missingparamsmsgs = [];
if(!this.typeId)
@@ -291,17 +279,8 @@ export default {
.catch(this.$fhcAlert.handleSystemError);
//case of reply
if(this.messageId != null) {
if(this.messageId) {
this.loadReplyData(this.messageId);
/* this.$api
.call(ApiMessages.getReplyData(this.messageId))
.then(result => {
this.replyData = result.data;
this.formData.subject = this.replyData[0].replySubject;
this.formData.body = this.replyData[0].replyBody;
this.formData.relationmessage_id = this.messageId;
})
.catch(this.$fhcAlert.handleSystemError);*/
}
},
@@ -499,10 +478,10 @@ export default {
<div class="row">
<div class="col-6" style="border-right: 1px">
You can safely close this window.
You can safely close this window/tab.
</div>
<div class="col-6">
Sie können dieses Fenster schließen.
Fenster/Reiter kann geschlossen werden!
</div>
</div>
</div>
@@ -30,6 +30,7 @@ export default {
personId: null,
layoutColumnsOnNewData: false,
height: '400',
arePhrasesLoaded: false
}
},
methods: {
@@ -65,7 +66,14 @@ export default {
buildTreemap(messages) {
if (!messages || !messages.data || messages.data.length === 0)
{
return {data: [], last_page: 0};
if(this.tabulatorOptions.pagination)
{
return {data: [], last_page: 0};
}
else
{
return [];
}
}
const last_page = messages.meta.count;
@@ -106,7 +114,15 @@ export default {
// to avoid endless loop
if (iteration > messages.length) break;
}
return {data: messageNested, last_page: last_page};
if(this.tabulatorOptions.pagination)
{
return {data: messageNested, last_page: last_page};
}
else
{
return messageNested;
}
},
loadAjaxCall(url, config, params){
return this.$api.call(
@@ -180,7 +196,7 @@ export default {
],
formatter: (cell, formatterParams) => {
const key = formatterParams[cell.getValue()];
return this.$p.t('messages', key);
return this.$p?.t?.('messages', key) || key;
},
},
{
@@ -252,7 +268,7 @@ export default {
frozen: true
}
],
pagination: true,
pagination: false,
paginationMode: "remote",
paginationSize: 15,
paginationInitialPage: 1,
@@ -290,8 +306,6 @@ export default {
{
event: 'tableBuilt',
handler: async() => {
await this.$p.loadCategory(['global', 'person', 'stv', 'messages', 'ui', 'notiz']);
const setHeader = (field, text) => {
const col = this.$refs.table.tabulator.getColumn(field);
if (!col) return;
@@ -342,6 +356,12 @@ export default {
});*/
},
created(){
this.$p
.loadCategory(['global', 'person', 'stv', 'messages', 'ui', 'notiz'])
.then(() => {
this.arePhrasesLoaded = true;
});
if(this.typeId != 'person_id' && Array.isArray(this.id) && this.id.length === 1) {
const params = {
id: this.id,
@@ -366,6 +386,7 @@ export default {
<!--table-->
<div class="col-sm-6 pt-1">
<core-filter-cmpt
v-if="arePhrasesLoaded"
ref="table"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
@@ -398,6 +419,7 @@ export default {
<div class="col-sm-12 pt-6">
<core-filter-cmpt
ref="table"
v-if="arePhrasesLoaded"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
table-only
+8 -6
View File
@@ -82,14 +82,16 @@ export default {
this.$refs.modalMsg.show();
}
else if (this.openMode == "inSamePage"){
console.log("in same Page");
this.isVisibleDiv = true;
if(messageId)
this.$refs.templateNewDivMessage.loadReplyData(messageId);
else
this.$refs.templateNewDivMessage.resetForm();
this.$refs.templateNewDivMessage.showTemplate();
this.$nextTick(() => {
if(messageId)
this.$refs.templateNewDivMessage.loadReplyData(messageId);
else
this.$refs.templateNewDivMessage.resetForm();
this.$refs.templateNewDivMessage.showTemplate();
});
}
else
console.log("no valid openMode");
@@ -84,6 +84,14 @@ export default {
'microcredential_2',
'microcredential_3',
'microcredential_4',
'microdegree_1',
'microdegree_2',
'microdegree_3',
'microdegree_4',
'microdegreeabschluss_1',
'microdegreeabschluss_2',
'microdegreeabschluss_3',
'microdegreeabschluss_4',
]
},
documentDropdownObject: {}
@@ -83,6 +83,8 @@ export default {
});
},
open() {
this.getBuchungstypen(this.currentSemester);
this.data = {
buchungstyp_kurzbz: '',
betrag: '-0.00',
@@ -105,7 +107,7 @@ export default {
const text = typ.standardtext || '';
const creditpoints = typ.credit_points || '';
if (!this.data.betrag || this.data.betrag == '-0.00')
if (!this.data.betrag || this.data.betrag == '-0.00' || this.data.betrag !== amount)
this.data.betrag = amount;
if (!this.data.buchungstext)
@@ -113,7 +115,18 @@ export default {
if (this.config.showCreditpoints && (this.data.credit_points == '0.00' || this.data.credit_points === null))
this.data.credit_points = creditpoints;
}
},
getBuchungstypen(studiensemester_kurzbz)
{
this.$api
.call(ApiKonto.getBuchungstypen(studiensemester_kurzbz))
.then(result => {
this.lists.buchungstypen = result.data;
if (this.data.buchungstyp_kurzbz)
this.checkDefaultBetrag(this.data.buchungstyp_kurzbz);
})
.catch(this.$fhcAlert.handleSystemError);
},
},
template: `
<core-form ref="form" class="stv-details-konto-edit" @submit.prevent="save">
@@ -166,6 +179,7 @@ export default {
<form-input
type="select"
v-model="data.studiensemester_kurzbz"
@change="getBuchungstypen(data.studiensemester_kurzbz)"
name="studiensemester_kurzbz"
:label="$p.t('lehre/studiensemester')"
>
@@ -131,7 +131,7 @@ export default {
},
onSelectTreeNode(node) {
if (node.data.link)
this.$emit('selectVerband', {link: node.data.link, studiengang_kz: node.data.stg_kz, semester: node.data.semester, orgform_kurzbz: node.data.orgform_kurzbz, name: node.data.name});
this.$emit('selectVerband', {link: node.data.link, studiengang_kz: node.data.stg_kz, semester: node.data.semester, orgform_kurzbz: node.data.orgform_kurzbz});
},
mapNodesToNoSemReloadNodes(result, node) {
if (node.data.no_sem_reload)
-177
View File
@@ -1,177 +0,0 @@
import FormInput from '../Form/Input.js';
import draggable from "../../directives/draggable.js";
import ApiCoursePicker from '../../api/factory/tempus/coursepicker.js';
export default {
components: {
FormInput
},
directives: {
draggable
},
props: {
stg: {
type: [String, Number],
default: null,
},
studiensemester: {
type: String,
default: null
},
},
emits: ['select-lecturer', 'select-kw'],
data() {
return {
searchparam: '',
allCourses: [],
}
},
computed: {
courses() {
const query = (this.searchparam ?? '').trim().toLowerCase();
if (!query)
return this.allCourses;
return this.allCourses.filter(course =>
course.showname.toLowerCase().includes(query) ||
course.lektoren?.some(l =>
l.name.toLowerCase().includes(query) ||
l.kurzbz.toLowerCase().includes(query)
)
);
}
},
watch: {
stg(val) {
this.searchparam = '';
this.loadCoursesByStg(val);
},
studiensemester() {
if (this.stg)
this.loadCoursesByStg(this.stg);
},
},
methods: {
async loadCoursesByStg(stg) {
if (!stg) {
this.allCourses = [];
return;
}
this.$api.call(ApiCoursePicker.getByStg(this.stg, this.studiensemester))
.then(result => {
this.allCourses = result.data.map(e => ({
lehreinheit_id: e.lehreinheit_id,
lektoren: e.lektoren,
raumtyp: e.raumtyp,
raumtypalternativ: e.raumtypalternativ,
semesterstunden: e.planstunden,
stundenblockung: e.stundenblockung,
wochenrythmus: e.wochenrythmus,
offenestunden: e.offenestunden,
start_kw: e.start_kw,
anmerkung: e.anmerkung,
lehrfach: e.lehrfach,
lehrform: e.lehrform,
lehrfach_bez: e.lehrfach_bez,
lehrfach_farbe: e.lehrfach_farbe,
lehrverband: e.lehrverband,
showname: `${e.lehrfach} ${e.lehrform}`,
orig: {
type: 'lehreinheit',
lehreinheit_id: e.lehreinheit_id[0],
blockung: e.stundenblockung,
entry: e,
}
}));
})
.catch(this.$fhcAlert.handleSystemError);
},
dragLehreinheitCollection(course) {
const orig = course.orig;
return {
type: 'lehreinheit',
id: orig.lehreinheit_id,
orig: orig,
stundenblockung: course.stundenblockung,
};
},
courseStyle(course) {
if (!course.lehrfach_farbe)
return {};
return '--event-bg:#' + course.lehrfach_farbe;
},
selectLecturer(lektor) {
this.$emit('select-lecturer', lektor);
}
},
template: `
<div class="course-picker d-flex flex-column h-100">
<div class="p-2">
<form-input
:label="$p.t('ui', 'suche')"
type="text"
v-model="searchparam"
/>
</div>
<div v-if="!stg" class="d-flex flex-column align-items-center justify-content-center text-center text-muted py-5 px-3 h-100">
<span class="small fw-semibold mb-1">Keine Lehreinheiten</span>
<span class="small">Wähle einen Studiengang, um Lehreinheiten anzuzeigen.</span>
</div>
<div v-else class="overflow-auto px-2 pb-2 flex-grow-1">
<div
v-for="course in courses"
:key="course.lehreinheit_id"
:style="courseStyle(course)"
class="course-picker-row"
v-draggable:move.noimage="dragLehreinheitCollection(course)"
tabindex="0"
>
<div class="d-flex gap-1">
<span class="fw-semibold small w-50" v-tooltip="course.lehrfach_bez">{{ course.lehrfach }} {{ course.lehrform }}</span>
<span class="fw-semibold small w-50" v-tooltip="course.raumtypalternativ">{{ course.raumtyp }}</span>
</div>
<div class="d-flex gap-1 text-muted">
<div class="w-50 d-flex flex-column" v-tooltip="course.anmerkung">
<span
v-for="verband in course.lehrverband"
:key="verband">
{{ verband }}
</span>
</div>
<span
style="cursor:pointer"
class="text-decoration-underline w-50"
@click.stop="$emit('select-kw', course.start_kw)">KW: {{ course.start_kw }}
</span>
</div>
<div class="d-flex gap-1 text-muted">
<div class="w-50 d-flex flex-column"
v-tooltip="course.lektoren.length > 3 ? course.lektoren.map(l => l.kurzbz).join(', ') : null">
<span
v-for="lektor in course.lektoren.slice(0, 3)"
:key="lektor.uid"
style="cursor:pointer"
class="text-decoration-underline"
@click.stop="selectLecturer(lektor)">
{{ lektor.kurzbz }}
</span>
<span v-if="course.lektoren.length > 3" class="text-muted fst-italic">
+{{ course.lektoren.length - 3 }} weitere...
</span>
</div>
<span class="w-50 align-self-start">WR: {{ course.wochenrythmus }} Bl: {{ course.stundenblockung }}</span>
</div>
<div class="d-flex gap-1 text-muted">
<span class="w-50">Offen: {{ course.offenestunden }}</span>
<span class="w-50">{{ course.semesterstunden }}</span>
</div>
</div>
</div>
</div>
`
}
@@ -1,44 +0,0 @@
import FormInput from '../Form/Input.js';
export default {
name: "LectureSelection",
props: {
lecturers: {
type: Array,
required: true
}
},
emits: ['remove'],
template: `
<div class="lecture-selection">
<div v-for="l in lecturers" :key="l.uid">
<div class="fw-semibold px-2 pt-2 d-flex align-items-center justify-content-between">
{{ l.label }}
<button
type="button"
class="btn btn-sm btn-link text-danger p-0"
@click="$emit('remove', l.uid)"
title="Lektor entfernen"
>
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<div class="overflow-auto flex-grow-1 px-2 pb-2">
<div class="d-flex align-items-center gap-2" @click="l.showEvents = !l.showEvents" style="cursor:pointer">
<i :class="l.showEvents ? 'fa-solid fa-toggle-on text-primary' : 'fa-solid fa-toggle-off text-muted'"></i>
<span class="form-check-label">Plan</span>
</div>
<div class="d-flex align-items-center gap-2" @click="l.overlays.blocks = !l.overlays.blocks" style="cursor:pointer">
<i :class="l.overlays.blocks ? 'fa-solid fa-toggle-on text-primary' : 'fa-solid fa-toggle-off text-muted'"></i>
<span class="form-check-label">Zeitsperren</span>
</div>
<div class="d-flex align-items-center gap-2" @click="l.overlays.wishes = !l.overlays.wishes" style="cursor:pointer">
<i :class="l.overlays.wishes ? 'fa-solid fa-toggle-on text-primary' : 'fa-solid fa-toggle-off text-muted'"></i>
<span class="form-check-label">Zeitwünsche</span>
</div>
</div>
</div>
</div>
`
}
@@ -1,78 +0,0 @@
import EventCard from '../Calendar/Base/Grid/Line/EventCard.js';
import drop from '../../directives/drop.js';
export default {
name: "ParkingSlot",
components: {
EventCard
},
directives: {
drop
},
emits: ['update:parkedKeys'],
data() {
return {
parked: [],
parkedKeys: new Set()
};
},
methods: {
park(evt, items) {
const list = Array.isArray(items) ? items : [items];
const stored = JSON.parse(localStorage.getItem('tempus_parking') || '[]');
list.forEach(item => {
const key = `${item.id}`;
if (this.parkedKeys.has(key))
return;
this.parkedKeys.add(key);
stored.push({
type: item.type,
id: item.id,
orig: item.orig
});
this.parked.push(item);
});
localStorage.setItem('tempus_parking', JSON.stringify(stored));
this.$emit('update:parkedKeys', this.parkedKeys);
},
unpark(event) {
const key = `${event.id}`;
this.parkedKeys.delete(key);
this.parked = this.parked.filter(parkedEvent => parkedEvent.id !== event.id);
const stored = JSON.parse(localStorage.getItem('tempus_parking') || '[]').filter(parkedEvent => parkedEvent.id !== event.id);
localStorage.setItem('tempus_parking', JSON.stringify(stored));
this.$emit('update:parkedKeys', this.parkedKeys);
},
isParked(id) {
return this.parkedKeys.has(`${id}`);
}
},
mounted() {
const stored = JSON.parse(localStorage.getItem('tempus_parking') || '[]');
this.parked = stored;
this.parkedKeys = new Set(stored.map(store => `${store.id}`));
this.$emit('update:parkedKeys', this.parkedKeys);
},
template: `
<div class="overflow-auto" tabindex="-1">
<div
id="parkingslot"
class="parkingslot"
v-drop:move.kalender-collection="(evt, item) => park(evt, item)"
>
<i v-if="!parked.length" class="fa-solid fa-square-parking"></i>
<event-card
class="parkingevent"
v-for="parkedEvent in parked"
:key="parkedEvent.id"
:event="parkedEvent"
parked
/>
</div>
</div>
`
}
@@ -1,94 +0,0 @@
export default {
props:{
event: {
type: Object,
required: true
}
},
computed:{
classes() {
const classes = ['cis-renderer-lehreinheit-calendar-event', 'calendar-event-default', 'h-100', 'w-100', 'p-1'];
if (this.event.collisions) {
classes.push('calendar-event-collisions');
}
return classes;
},
tooltipString() {
const tooltipArray = [];
tooltipArray.push([
this.$p.t('global/uhrzeit'),
[this.start, this.end].join(' - ')
].join(": "));
tooltipArray.push([
this.$p.t('profilUpdate/topic'),
this.event.topic
].join(": "));
tooltipArray.push([
this.$p.t('person/ort'),
this.event.ort_kurzbz
].join(": "));
if (Array.isArray(this.event.lektor) && this.event.lektor.length > 0) {
if (this.event.lektor.length > 3) {
tooltipArray.push([
this.$p.t('lehre/lektor'),
this.event.lektor.slice(0, 3).map(lektor => lektor.kurzbz).join("\n")
+ "\n" + this.$p.t('lehre/weitereLektoren', [this.event.lektor.length - 3])
].join(": "));
} else {
tooltipArray.push([
this.$p.t('lehre/lektor'),
this.event.lektor.map(lektor => lektor.kurzbz).join("\n")
].join(": "));
}
}
return tooltipArray.join("\n");
},
start() {
return luxon.Duration
.fromISOTime(this.event.beginn)
.toISOTime({ suppressSeconds: true });
},
end() {
return luxon.Duration
.fromISOTime(this.event.ende)
.toISOTime({ suppressSeconds: true });
}
},
template: /*html*/`
<div
:class="classes"
@wheel.stop
>
<div
v-if="!event.allDayEvent && event?.beginn && event?.ende"
class="event-time d-none d-xl-grid h-100"
>
<span>{{ start }}</span>
<span>{{ end }}</span>
</div>
<div class="event-text" v-tooltip="tooltipString">
<span class="event-topic">{{ event.topic }}</span>
<span class="event-place">{{ event.ort_kurzbz }}</span>
<span
v-for="(lektor,index) in event.lektor.slice(0, 3)"
class="event-lectors"
>
{{ lektor.kurzbz }}
</span>
<span
v-if="event.lektor.length > 3"
class="event-lectors-plus"
>
... +{{ event.lektor.length - 3 }}
</span>
</div>
</div>
`,
}
@@ -1,148 +0,0 @@
import { numberPadding, formatDate } from "../../../../helpers/DateHelpers.js"
import LvMenu from "../../../../components/Cis/Mylv/LvMenu.js";
import ApiLvPlan from '../../../../api/factory/lvPlan.js';
import ApiAddons from '../../../../api/factory/addons.js';
export default {
components:{
LvMenu,
},
props:{
event: {
type: Object,
required: true,
}
},
data() {
return {
lvMenu: []
};
},
computed: {
lektorenLinks: function () {
if (!this.event || !Array.isArray(this.event.lektor) || !this.event.lektor.length) return "a";
let lektorenLinks = {};
this.event.lektor.forEach((lektor) => {
lektorenLinks[lektor.kurzbz] = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/Cis/Profil/View/${lektor.mitarbeiter_uid}`;
})
return lektorenLinks;
},
getOrtContentLink: function () {
if (!this.event || !this.event.ort_content_id) return "a";
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/CisVue/Cms/content/${this.event.ort_content_id}`
},
start_time: function () {
if (!this.event.beginn)
return 'N/A';
if (!(this.event.beginn instanceof Date)) {
return this.event.beginn;
}
return numberPadding(this.event.beginn.getHours()) + ":" + numberPadding(this.event.beginn.getMinutes());
},
end_time: function () {
if (!this.event.ende)
return 'N/A';
if (!(this.event.ende instanceof Date)) {
return this.event.ende;
}
return numberPadding(this.event.ende.getHours()) + ":" + numberPadding(this.event.ende.getMinutes());
}
},
methods: {
mehtodNumberPadding: function (number) {
return numberPadding(number);
},
methodFormatDate: function (d) {
return formatDate(d);
},
},
created() {
if (this.event.type == 'lehreinheit') {
this.$api
.call(ApiLvPlan.getLehreinheitStudiensemester(Array.isArray(this.event.lehreinheit_id) ? this.event.lehreinheit_id[0] : this.event.lehreinheit_id))
.then(res => res.data)
.then(studiensemester_kurzbz => this.$api.call(
ApiAddons.getLvMenu(
this.event.lehrveranstaltung_id,
studiensemester_kurzbz
)
))
.then(res => {
this.lvMenu = res.data;
});
}
},
template: `
<div>
<h5>
{{$p.t('lvinfo','lehrveranstaltungsinformationen')}}
</h5>
<table class="table table-hover mb-4">
<tbody>
<tr>
<th>{{
$p.t('global','datum')?
$p.t('global','datum')+':'
:''
}}</th>
<td>{{methodFormatDate(event.datum)}}</td>
</tr>
<tr>
<th>{{
$p.t('ui','zeitraum')?
$p.t('ui','zeitraum')+':'
:''
}}</th>
<td>{{start_time + ' - ' + end_time}}</td>
</tr>
<tr>
<th>{{
$p.t('global','raum')?
$p.t('global','raum')+':'
:''
}}</th>
<td>
<a v-if="event.ort_content_id" :aria-label="$p.t('global','raum')" :title="$p.t('global','raum')" :href="getOrtContentLink"><i class="fa fa-arrow-up-right-from-square me-1" aria-hidden="true" style="color:#00649C"></i></a>
{{event.ort_kurzbz}}
</td>
</tr>
<tr>
<th>{{
$p.t('lehre','lehrveranstaltung')?
$p.t('lehre','lehrveranstaltung')+':'
:''
}}</th>
<td>{{'('+event.lehrform+') ' + event.lehrfach_bez}}</td>
</tr>
<tr>
<th>{{
$p.t('lehre','lektor')?
$p.t('lehre','lektor')+':'
:''
}}</th>
<td>
<div id="lektorenContainer">
<div v-for="lektor in event.lektor" class="d-block">
<a v-if="lektorenLinks[lektor.kurzbz]" :aria-label="$p.t('lehre','lektor')" :title="$p.t('lehre','lektor')" :href="lektorenLinks[lektor.kurzbz]"><i class="fa fa-arrow-up-right-from-square me-1" style="color:#00649C" aria-hidden="true"></i></a>
{{lektor.kurzbz}}
</div>
</div>
</td>
</tr>
<tr>
<th>{{
$p.t('lehre','organisationseinheit')?
$p.t('lehre','organisationseinheit')+':'
:''
}}</th>
<td>{{event.organisationseinheit}}</td>
</tr>
</tbody>
</table>
<lv-menu :containerStyles="['p-0']" :rowStyles="['m-0']" v-if="lvMenu.length" :menu="lvMenu" />
</div>`,
}
@@ -1,12 +0,0 @@
export default {
props:{
event: {
type: Object,
required: true,
}
},
template:`
<div v-if="event.titel">{{ event.titel + ' - ' + event.lehrfach_bez + ' [' + event.ort_kurzbz+']'}}</div>
<div v-else>{{ event.lehrfach_bez + ' [' + event.ort_kurzbz+']'}}</div>
`
}
@@ -1,93 +0,0 @@
export default {
props: {
event: {
type: Object,
required: true
}
},
computed: {
classes() {
const classes = ['cis-renderer-reservierungen-calendar-event', 'calendar-event-default', 'h-100', 'w-100', 'p-1'];
if (this.event.collisions) {
classes.push('calendar-event-collisions');
}
return classes;
},
tooltipString() {
const tooltipArray = [];
tooltipArray.push([
this.$p.t('global/uhrzeit'),
[this.start, this.end].join(' - ')
].join(": "));
tooltipArray.push([
this.$p.t('profilUpdate/topic'),
this.event.topic
].join(": "));
tooltipArray.push([
this.$p.t('person/ort'),
this.event.ort_kurzbz
].join(": "));
if (Array.isArray(this.event.lektor) && this.event.lektor.length > 0) {
if (this.event.lektor.length > 3) {
tooltipArray.push([
this.$p.t('lehre/lektor'),
this.event.lektor.slice(0, 3).map(lektor => lektor.kurzbz).join("\n")
+ "\n" + this.$p.t('lehre/weitereLektoren', [this.event.lektor.length - 3])
].join(": "));
} else {
tooltipArray.push([
this.$p.t('lehre/lektor'),
this.event.lektor.map(lektor => lektor.kurzbz).join("\n")
].join(": "));
}
}
return tooltipArray.join("\n");
},
start() {
return luxon.Duration
.fromISOTime(this.event.beginn)
.toISOTime({ suppressSeconds: true });
},
end() {
return luxon.Duration
.fromISOTime(this.event.ende)
.toISOTime({ suppressSeconds: true });
}
},
template: /* html */`
<div
:class="classes"
>
<div
v-if="!event.allDayEvent && event?.beginn && event?.ende"
class="event-time d-grid h-100"
>
<span>{{ start }}</span>
<span>{{ end }}</span>
</div>
<div class="event-text" v-tooltip="tooltipString">
<span class="event-topic">{{ event.topic }}</span>
<span
v-for="lektor in event.lektor.slice(0, 3)"
class="event-lectors"
>
{{ lektor.kurzbz }}
</span>
<span
v-if="event.lektor.length > 3"
class="event-lectors-plus"
>
... +{{ event.lektor.length - 3 }}
</span>
<span class="event-place">{{ event.ort_kurzbz }}</span>
</div>
</div>
`,
}
@@ -1,133 +0,0 @@
import { numberPadding, formatDate } from "../../../../helpers/DateHelpers.js"
import LvMenu from "../../../Cis/Mylv/LvMenu.js";
export default {
props:{
event: {
type: Object,
required: true,
},
lvMenu:{
type: Object,
required: false,
default: null,
},
},
components:{
LvMenu,
},
computed: {
lektorenLinks: function () {
if (!this.event || !Array.isArray(this.event.lektor) || !this.event.lektor.length) return "a";
let lektorenLinks = {};
this.event.lektor.forEach((lektor) => {
lektorenLinks[lektor.kurzbz] = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/Cis/Profil/View/${lektor.mitarbeiter_uid}`;
})
return lektorenLinks;
},
getOrtContentLink: function () {
if (!this.event || !this.event.ort_content_id) return "a";
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + `/CisVue/Cms/content/${this.event.ort_content_id}`
},
start_time: function () {
if (!this.event.beginn)
return 'N/A';
if (!(this.event.beginn instanceof Date)) {
return this.event.beginn;
}
return numberPadding(this.event.beginn.getHours()) + ":" + numberPadding(this.event.beginn.getMinutes());
},
end_time: function () {
if (!this.event.ende)
return 'N/A';
if (!(this.event.ende instanceof Date)) {
return this.event.ende;
}
return numberPadding(this.event.ende.getHours()) + ":" + numberPadding(this.event.ende.getMinutes());
}
},
methods: {
mehtodNumberPadding: function (number) {
return numberPadding(number);
},
methodFormatDate: function (d) {
return formatDate(d);
},
},
template: `
<div>
<h6>
{{ event.beschreibung }}
</h6>
<h5>
{{$p.t('ui','reservierungsinformationen')}}
</h5>
<table class="table table-hover mb-4">
<tbody>
<tr>
<th>{{
$p.t('global','datum')?
$p.t('global','datum')+':'
:''
}}</th>
<td>{{methodFormatDate(event.datum)}}</td>
</tr>
<tr>
<th>{{
$p.t('ui','zeitraum')?
$p.t('ui','zeitraum')+':'
:''
}}</th>
<td>{{start_time + ' - ' + end_time}}</td>
</tr>
<tr>
<th>{{
$p.t('global','raum')?
$p.t('global','raum')+':'
:''
}}</th>
<td>
<a v-if="event.ort_content_id" :aria-label="$p.t('global','raum')" :title="$p.t('global','raum')" :href="getOrtContentLink"><i class="fa fa-arrow-up-right-from-square me-1" style="color:#00649C" aria-hidden="true"></i></a>
{{event.ort_kurzbz}}
</td>
</tr>
<tr>
<th>{{
$p.t('ui','organisierende')?
$p.t('ui','organisierende')+':'
:''
}}</th>
<td>
<div v-for="lektor in event.lektor" class="d-block">
<a v-if="lektorenLinks[lektor.kurzbz]" :aria-label="$p.t('lehre','lektor')" :tooltip="$p.t('lehre','lektor')" :href="lektorenLinks[lektor.kurzbz]"><i class="fa fa-arrow-up-right-from-square me-1" aria-hidden="true" style="color:#00649C"></i></a>
{{lektor.kurzbz}}
</div>
</td>
</tr>
<tr>
<th>{{
$p.t('ui','teilnehmende')?
$p.t('ui','teilnehmende')+':'
:''
}}</th>
<td>
<div v-for="teilnehmer in event.teilnehmer_person" class="d-block">
{{teilnehmer.kurzbz}}
</div>
<div v-for="gruppe in event.teilnehmer_gruppe" class="d-block">
{{gruppe.gruppe_kurzbz}}
</div>
</td>
</tr>
</tbody>
</table>
</div>`,
}
@@ -1,11 +0,0 @@
export default {
props:{
event: {
type: Object,
required: true,
}
},
template:`
<div >{{ event.titel }}</div>
`
}
-302
View File
@@ -1,302 +0,0 @@
import BsModal from '../Bootstrap/Modal.js';
import FormInput from '../Form/Input.js';
import ApiReservierung from '../../api/factory/tempus/reservierung.js';
export default {
name: 'ReservierungModal',
components: {
BsModal,
FormInput
},
props: {
ortKurzbz: {
type: String,
default: null
}
},
emits: ['saved'],
data() {
return {
titel: '',
beschreibung: '',
start: null,
end: null,
ort_kurzbz: null,
raeume_array: [],
studiensemester_array: [],
teilnehmer: [],
specialFinalGroups: [],
rollen_array: [],
studiengaenge: [],
show_all_fields: false,
filteredUsers: [],
filteredGroups: [],
abortController: null
};
},
created()
{
this.$api.call(ApiReservierung.getInformation())
.then(result => result.data)
.then(result => {
if (result.berechtigt)
{
this.studiengaenge = result.studiengaenge
}
this.show_all_fields = result.berechtigt;
this.raeume_array = result.raeume;
this.rollen_array = result.rollen;
this.studiensemester_array = result.studiensemester;
})
.catch(this.$fhcAlert.handleSystemError);
},
methods: {
async searchGroup(event)
{
const query = event.query.trim();
if (query.length < 2)
return [];
if (this.abortController)
this.abortController.abort();
this.abortController = new AbortController();
this.$api.call(ApiReservierung.searchGroup(query), { signal: this.abortController.signal })
.then(result => {
this.filteredGroups =result.data.map(gruppe => ({
label: gruppe.bezeichnung
? `${gruppe.gruppe_kurzbz.trim()} (${gruppe.bezeichnung})`
: gruppe.gruppe_kurzbz.trim(),
gid: gruppe.gid,
gruppe_kurzbz: gruppe.gruppe_kurzbz.trim(),
lehrverband: gruppe.lehrverband,
}));
})
.catch(this.$fhcAlert.handleSystemError);
},
searchUser(event)
{
const query = event.query.trim();
if (!query || query.length < 2)
{
this.filteredUsers = [];
return;
}
if (this.abortController)
this.abortController.abort();
this.abortController = new AbortController();
this.$api.call(ApiReservierung.searchTeilnehmer(query), { signal: this.abortController.signal })
.then(result => {
this.filteredUsers = result.data.map(u => ({
label: `${u.nachname} ${u.vorname} (${u.uid})`,
uid: u.uid
}));
})
.catch(this.$fhcAlert.handleSystemError);
},
selectUser(event, index)
{
this.teilnehmer[index].uid = event.value.uid;
this.teilnehmer[index].label = event.value.label;
},
selectFinalGroup(event, index)
{
this.specialFinalGroups[index].gid = event.value.gid;
this.specialFinalGroups[index].gruppe_kurzbz = event.value.gruppe_kurzbz;
this.specialFinalGroups[index].lehrverband = event.value.lehrverband;
},
show(start, end)
{
this.titel = '';
this.beschreibung = '';
this.start = start;
this.end = end;
this.ort_kurzbz = this.ortKurzbz ?? null;
this.teilnehmer = [{ uid: null, rolle: null }];
this.specialFinalGroups = [{ gid: null, studiensemester_kurzbz: null, lehrverband: null, gruppe_kurzbz: null, rolle: null }];
this.$refs.modal.show();
},
hide()
{
this.$refs.modal.hide();
},
save()
{
this.$api.call(
ApiReservierung.addReservierung(
this.titel,
this.beschreibung,
this.ort_kurzbz,
luxon.DateTime.fromFormat(this.start, 'yyyy-MM-dd HH:mm').toISO(),
luxon.DateTime.fromFormat(this.end, 'yyyy-MM-dd HH:mm').toISO(),
this.teilnehmer.filter(t => t.uid && t.rolle).map(nehmer => ({ uid: nehmer.uid, rolle: nehmer.rolle })),
this.specialFinalGroups.filter(group => group.gid && group.rolle && group.studiensemester_kurzbz).map(group => ({ gid: group.gid, lehrverband: group.lehrverband, gruppe_kurzbz: group.gruppe_kurzbz, rolle: group.rolle, studiensemester_kurzbz: group.studiensemester_kurzbz })),
)
).then(() => {
this.$refs.modal.hide();
this.$emit('saved');
});
},
},
// language=HTML
template: `
<bs-modal ref="modal" class="bootstrap-prompt" dialogClass="modal-xl">
<template #title>Neue Reservierung</template>
<template #default>
<div class="row g-3">
<form-input
label="Titel"
type="text"
container-class="col-12"
name="titel"
v-model="titel"
></form-input>
<form-input
label="Beschreibung"
type="textarea"
container-class="col-12"
name="beschreibung"
v-model="beschreibung"
></form-input>
<div class="col-6">
<form-input
type="datepicker"
v-model="start"
name="star_date"
format="dd.MM.yyyy HH:mm"
auto-apply
:enable-time-picker="true"
preview-format="dd.MM.yyyy HH:mm"
model-type="yyyy-MM-dd HH:mm"
:label="$p.t('ui', 'von')"
/>
</div>
<div class="col-6">
<form-input
type="datepicker"
v-model="end"
name="end_time"
format="dd.MM.yyyy HH:mm"
auto-apply
:enable-time-picker="true"
preview-format="dd.MM.yyyy HH:mm"
model-type="yyyy-MM-dd HH:mm"
:label="$p.t('global', 'bis')"
/>
</div>
<div class="col-6">
<form-input
:label="$p.t('global', 'raum')"
type="select"
container-class="col-6"
v-model="ort_kurzbz"
name="ort_kurzbz"
>
<option
v-for="raum in raeume_array"
:value="raum.ort_kurzbz"
:key="raum.ort_kurzbz"
>
{{ raum.ort_kurzbz }} {{ raum.bezeichnung }}
</option>
</form-input>
</div>
<div class="col-12" v-if="show_all_fields">
<div v-for="(nehmer, i) in teilnehmer" :key="i" class="d-flex gap-2 mb-2 align-items-end">
<form-input
type="autocomplete"
:label="$p.t('ui', 'teilnehmende')"
:suggestions="filteredUsers"
v-model="nehmer.label"
field="label"
container-class="flex-grow-1"
:name="'user_' + i"
@complete="searchUser($event, i)"
@item-select="selectUser($event, i)"
></form-input>
<form-input
type="select"
:label="$p.t('lehre', 'status_rolle')"
v-model="nehmer.rolle"
:name="'rolle_' + i"
>
<option v-for="rolle in rollen_array" :value="rolle.rolle_kurzbz" :key="rolle.rolle_kurzbz">
{{ rolle.bezeichnung }}
</option>
</form-input>
<button type="button" class="btn btn-outline-danger" @click="teilnehmer.splice(i, 1)">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<button type="button" class="btn btn-outline-secondary btn-sm" @click="teilnehmer.push({ uid: null, label: '', rolle: null })">
<i class="fa-solid fa-plus me-1"></i>{{$capitalize( $p.t('global', 'hinzufuegen') )}}
</button>
</div>
<div class="col-12" v-if="show_all_fields">
<div v-for="(group, i) in specialFinalGroups" :key="i" class="d-flex gap-3 mb-3 align-items-end">
<form-input
type="autocomplete"
:label="$p.t('lehre', 'gruppe')"
:suggestions="filteredGroups"
v-model="group.label"
field="label"
container-class="flex-grow-1"
:name="'group_' + i"
@complete="searchGroup($event, i)"
@item-select="selectFinalGroup($event, i)"
></form-input>
<form-input
type="select"
:label="$p.t('lehre', 'studiensemester')"
v-model="group.studiensemester_kurzbz"
:name="'studiensemester_' + i"
>
<option v-for="studiensemester in studiensemester_array" :value="studiensemester.studiensemester_kurzbz" :key="studiensemester.studiensemester_kurzbz">
{{ studiensemester.studiensemester_kurzbz }}
</option>
</form-input>
<form-input
type="select"
:label="$p.t('lehre', 'status_rolle')"
v-model="group.rolle"
:name="'rolle_' + i"
>
<option v-for="rolle in rollen_array" :value="rolle.rolle_kurzbz" :key="rolle.rolle_kurzbz">
{{ rolle.bezeichnung }}
</option>
</form-input>
<button type="button" class="btn btn-outline-danger" @click="specialFinalGroups.splice(i, 1)">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
<button type="button" class="btn btn-outline-secondary btn-sm" @click="specialFinalGroups.push({ gruppe_kurzbz: null, studiensemester_kurzbz: null, label: '', rolle: null })">
<i class="fa-solid fa-plus me-1"></i>{{$p.t('lehre', 'gruppe')}} {{$p.t('global', 'hinzufuegen')}}
</button>
</div>
</div>
</template>
<template #footer>
<button type="button" class="btn btn-primary" @click="save">Speichern</button>
</template>
</bs-modal>`
}

Some files were not shown because too many files have changed in this diff Show More