Compare commits

..
Author SHA1 Message Date
Alexei Karpenko 89ea378cbb Ferien import config: added comment 2026-10-01 12:05:14 +02:00
Alexei Karpenko 2d353799d8 Ferien import: added comments 2026-09-30 12:37:40 +02:00
Alexei Karpenko e327270ea2 Ferienverwaltung import: added phrases 2026-09-30 12:31:43 +02:00
Alexei Karpenko e9049e1660 Merge branch 'master' into feature-71405/Ferienzeiten 2026-09-30 12:10:23 +02:00
Alexei Karpenko 85bdd3a686 Ferien: added import from government csv 2026-09-28 18:40:07 +02:00
Alexei Karpenko 1c6912776b Ferienverwaltung: changed comment 2026-09-16 17:03:02 +02:00
Alexei Karpenko bfdec12c0e Ferienverwaltung: CI code: made completely independent from studiengang, legacy code: made backwards compatible by including oe_kurzbz where applicable 2026-05-25 13:52:05 +02:00
Alexei Karpenko 179386bea9 Ferien: added to vilesci menu, made oe_kurzbz optional, added default ferientypen, made studiengang_kz column deprecated 2026-05-05 18:14:27 +02:00
Alexei Karpenko 8ae3afa98a Merge branch 'master' into feature-71405/Ferienzeiten 2026-05-05 15:24:43 +02:00
Alexei Karpenko 4a4731e619 Ferien: adapted StudienplanLib to new table structure with oe_kurzbz 2026-03-16 11:14:29 +01:00
Alexei Karpenko 0e4c7dcd14 Ferien: prefilled oe_kurzbz column, stundenplan: adapted to get ferien by oe_kurzbz of studiengang 2026-03-13 16:36:58 +01:00
Alexei Karpenko a68b730ce0 Ferien: bugfix permission check (is_valid_date), added phrases 2026-03-11 17:09:30 +01:00
Alexei Karpenko cdcc734401 Merge branch 'master' into feature-71405/Ferienzeiten 2026-03-11 15:01:42 +01:00
Alexei Karpenko f9b9fc1124 Ferien: added permission checks for oes 2026-03-10 17:24:28 +01:00
Alexei Karpenko 976ef1f975 Ferienverwaltung: added new fields Organisationseinheit, Studienplan, added new table and field ferientyp, filtering by date instead of Studiengang 2026-03-03 23:07:22 +01:00
Alexei Karpenko f42ef3d5b6 Ferienzeiten list: added possibility to update entries 2026-02-25 14:35:13 +01:00
Alexei Karpenko c47a1cb627 Ferienverwaltung: created page with VUE Js, displaying Ferien and adding, deleting 2026-02-23 18:40:37 +01:00
Alexei Karpenko a57df7862c Ferienverwaltung: added new sequential primary key ferien_id, added primary constraint 2026-02-19 17:08:43 +01:00
63 changed files with 2086 additions and 1188 deletions
+6
View File
@@ -0,0 +1,6 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
// Link for download of Ferien days (should be csv)
$config['ferien_import_link'] = 'https://www.wien.gv.at/gogv/l9ogdfeiertagskalender';
+9
View File
@@ -119,6 +119,15 @@ $config['navigation_header'] = array(
'requiredPermissions' => array(
'lehre/zgvpruefung:r'
)
),
'ferien' => array(
'link' => site_url('lehre/Ferienverwaltung'),
'description' => 'Ferienverwaltung',
'expand' => true,
'sort' => 55,
'requiredPermissions' => array(
'basis/ferien:r'
)
)
)
),
+2 -8
View File
@@ -129,19 +129,13 @@ $route['api/frontend/v1/treemenudata/stv/.*'] = 'api/frontend/v1/stv/students/in
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/semester/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/semester/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/orgform/(:any)/semester/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStgOrgform/$1/$2/$3/$4';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/orgform/(:any)/semester/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByStgOrgform/$1/$2/$3/$4';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/orgform/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStgOrgform/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/orgform/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByStgOrgform/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/orgform/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/stg/(:any)/orgform/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByStg/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByEmp/$1/$2';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)/stg/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByEmp/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/emp/(:any)/stg/(:any)/.*'] = 'api/frontend/v1/Lehrveranstaltung/getByEmp/$1/$2/$3';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/le/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByLe/$1/$2';
$route['api/frontend/v1/treemenudata/lvverwaltung/stdsem/(:any)/lv/(:any)'] = 'api/frontend/v1/Lehrveranstaltung/getByLv/$1/$2';
// load routes from extensions, also look for environment-specific configs
$subdirs = ['application/config/extensions', 'application/config/' . ENVIRONMENT . '/extensions'];
+2 -3
View File
@@ -26,8 +26,7 @@ $config['root'] = [
'verband' => [
'group'
]
]
],
'orgform'
]
];
$config['root']['stg']['orgform'] = $config['root']['stg'];
@@ -1916,7 +1916,7 @@ class Abgabe extends FHCAPI_Controller
if (!$mailres)
{
$this->terminateWithError($this->p->t('abgabetool', 'c4fehlerMailZweitBegutachterv2'), 'general');
$this->terminateWithError($this->p->t('abgabetool', 'c4fehlerMailBegutachterv2'), 'general');
}
}
@@ -28,10 +28,7 @@ class Lehrveranstaltung extends FHCAPI_Controller
{
parent::__construct([
'getByEmp' => ['admin:r', 'assistenz:r'],
'getByLe' => ['admin:r', 'assistenz:r'],
'getByLv' => ['admin:r', 'assistenz:r'],
'getByStg' => ['admin:r', 'assistenz:r'],
'getByStgOrgform' => ['admin:r', 'assistenz:r'],
'loadByLV' => ['admin:r', 'assistenz:r'],
]);
@@ -80,117 +77,41 @@ class Lehrveranstaltung extends FHCAPI_Controller
$this->terminateWithSuccess($tree);
}
public function getByLe($studiensemester_kurzbz = null, $lehreinheit_id = null)
{
if (is_null($lehreinheit_id))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$lehreinheiten = $this->_ci->LehreinheitModel->getByLeStudiensemester($lehreinheit_id, $studiensemester_kurzbz);
$lehreinheiten_data = $this->getDataOrTerminateWithError($lehreinheiten);
$this->terminateWithSuccess($lehreinheiten_data);
}
public function getByLv($studiensemester_kurzbz = null, $lehrveranstaltung_id = null)
{
if (is_null($lehrveranstaltung_id))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$tree = [];
$this->_ci->LehrveranstaltungModel->addSelect('studiengang_kz');
$lv = $this->_ci->LehrveranstaltungModel->load($lehrveranstaltung_id);
$lv = $this->getDataOrTerminateWithError($lv);
if (empty($lv))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$lehrveranstaltungen_data = array();
foreach ($this->_loadLvRows(current($lv)->studiengang_kz, $studiensemester_kurzbz) as $row)
{
if ((string)$row->lehrveranstaltung_id === (string)$lehrveranstaltung_id)
{
$lehrveranstaltungen_data[] = $row;
break;
}
}
if (empty($lehrveranstaltungen_data))
{
$this->_ci->LehrveranstaltungModel->addSelect('
tbl_lehrveranstaltung.*,
tbl_lehrveranstaltung.kurzbz as lv_kurzbz,
lehrveranstaltung_id,
lehrtyp_kurzbz,
studiengang_kz as lv_studiengang_kz,
UPPER(CONCAT(tbl_studiengang.typ, tbl_studiengang.kurzbz)) as studiengang,
semester as semester,
tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung,
ects as lv_ects,
lehreverzeichnis as lv_lehreverzeichnis,
planfaktor as lv_planfaktor,
planlektoren as lv_planlektoren,
planpersonalkosten as lv_planpersonalkosten,
plankostenprolektor as lv_plankostenprolektor,
tbl_lehrveranstaltung.orgform_kurzbz as orgform_kurzbz,
tbl_lehrveranstaltung.sprache as sprache,
lehrform_kurzbz as lv_lehrform_kurzbz,
tbl_lehrveranstaltung.bezeichnung_english as lv_bezeichnung_english,
semesterstunden as lv_semesterstunden,
');
$this->_ci->LehrveranstaltungModel->addJoin('public.tbl_studiengang', 'studiengang_kz');
$lehrveranstaltungen = $this->_ci->LehrveranstaltungModel->load($lehrveranstaltung_id);
$lehrveranstaltungen_data = $this->getDataOrTerminateWithError($lehrveranstaltungen);
}
foreach ($lehrveranstaltungen_data as $lehrveranstaltung)
{
$lehreinheiten = $this->_ci->LehreinheitModel->getByLvidStudiensemester($lehrveranstaltung->lehrveranstaltung_id, $studiensemester_kurzbz);
$lehreinheiten_data = $this->getDataOrTerminateWithError($lehreinheiten);
if (!isset($lehrveranstaltung->_children))
{
$lehrveranstaltung->_children = $lehreinheiten_data;
}
$tree[] = $lehrveranstaltung;
}
$counter = 0;
$this->assignUniqueIndex($tree, $counter);
$this->terminateWithSuccess($tree);
}
public function getByStg($studiensemester_kurzbz = null, $stg_kz = null, $semester = null)
{
$this->_getLvTree($studiensemester_kurzbz, $stg_kz, $semester, null);
}
public function getByStgOrgform($studiensemester_kurzbz = null, $stg_kz = null, $orgform = null, $semester = null)
{
$orgform_kurzbz = $this->getOrgformKurzbz($orgform);
$this->_getLvTree($studiensemester_kurzbz, $stg_kz, $semester, $orgform_kurzbz);
}
private function _getLvTree($studiensemester_kurzbz, $stg_kz, $semester, $orgform_kurzbz)
{
$studiengang_kz = $this->getStudiengangKz($stg_kz);
if (is_null($studiengang_kz) || !preg_match("/^(-?[1-9][0-9]*|0)$/", (string)$studiengang_kz))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
if (!is_null($semester) && !ctype_digit((string)$semester))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$verband = null;
if (!is_null($semester) && !is_numeric($semester))
{
$verband = $this->getOrgformKurzbz($semester);
$semester = null;
}
$this->_ci->load->model('organisation/Studienplan_model', 'StudienplanModel');
$studiensemester_kurzbz = $this->getStudiensemesterKurzbz($studiensemester_kurzbz);
$studienplan_data = $this->_ci->StudienplanModel->getStudienplaeneBySemester($studiengang_kz, $studiensemester_kurzbz, $semester, $verband);
$lehrveranstaltungen_data = $this->_loadLvRows($studiengang_kz, $studiensemester_kurzbz, $semester, $orgform_kurzbz);
$studienplan_ids = array();
$only_ids = array();
$placeholders = array();
if (hasData($studienplan_data))
{
foreach (getData($studienplan_data) as $studienplan) {
$placeholders[] = "(?, ?)";
$studienplan_ids[] = $studienplan->studienplan_id;
$studienplan_ids[] = $studienplan->semester;
$only_ids[] = $studienplan->studienplan_id;
}
}
$lehrveranstaltungen_data = $this->_ci->LehrveranstaltungModel->getLvsByStudiengang($studienplan_ids, $placeholders, $only_ids, $studiengang_kz, $studiensemester_kurzbz, $semester, $verband);
$lehrveranstaltungen_data = hasData($lehrveranstaltungen_data) ? getData($lehrveranstaltungen_data) : array();
$tree = [];
foreach ($lehrveranstaltungen_data as $row)
@@ -323,31 +244,6 @@ class Lehrveranstaltung extends FHCAPI_Controller
$this->LehreinheitModel->getLvsByFachbereich($fachbereich, $studiensemester_kurzbz, $mitarbeiter_uid);
}*/
private function _loadLvRows($studiengang_kz, $studiensemester_kurzbz, $semester = null, $orgform_kurzbz = null)
{
$this->_ci->load->model('organisation/Studienplan_model', 'StudienplanModel');
$studienplan_data = $this->_ci->StudienplanModel->getStudienplaeneBySemester($studiengang_kz, $studiensemester_kurzbz, $semester, $orgform_kurzbz);
$studienplan_ids = array();
$only_ids = array();
$placeholders = array();
if (hasData($studienplan_data))
{
foreach (getData($studienplan_data) as $studienplan) {
$placeholders[] = "(?, ?)";
$studienplan_ids[] = $studienplan->studienplan_id;
$studienplan_ids[] = $studienplan->semester;
$only_ids[] = $studienplan->studienplan_id;
}
}
$lehrveranstaltungen_data = $this->_ci->LehrveranstaltungModel->getLvsByStudiengang($studienplan_ids, $placeholders, $only_ids, $studiengang_kz, $studiensemester_kurzbz, $semester, $orgform_kurzbz);
return hasData($lehrveranstaltungen_data) ? getData($lehrveranstaltungen_data) : array();
}
private function _setAuthUID()
{
$this->_uid = getAuthUID();
@@ -413,8 +309,8 @@ class Lehrveranstaltung extends FHCAPI_Controller
$data = $this->getDataOrTerminateWithError($result);
if (!$data)
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
return $orgform_kurzbz;
return current($data)->orgform_kurzbz;
}
}
}
@@ -101,9 +101,6 @@ class Widget extends FHCAPI_Controller
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
$widget->permitted = empty($widget->berechtigung_kurzbz)
|| $this->permissionlib->isBerechtigt($widget->berechtigung_kurzbz);
return $widget;
}, $widgets);
@@ -0,0 +1,482 @@
<?php
/**
* 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/>.
*/
if (!defined('BASEPATH')) exit('No direct script access allowed');
//use CI3_Events as Events;
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Ferien extends FHCAPI_Controller
{
const DEFAULT_BERECHTIGUNG = 'basis/ferien';
const FERIENTYP_KURZBZ = 'Feiertag';
/**
* Calls the parent's constructor and prepares libraries and phrases
*/
public function __construct()
{
parent::__construct([
'getFerien' => self::DEFAULT_BERECHTIGUNG.':r',
'getDefaultVonBis' => self::DEFAULT_BERECHTIGUNG.':r',
'getOe' => self::DEFAULT_BERECHTIGUNG.':r',
'getStudienplaene' => self::DEFAULT_BERECHTIGUNG.':r',
'getFerientypen' => self::DEFAULT_BERECHTIGUNG.':r',
'insert' => self::DEFAULT_BERECHTIGUNG.':w',
'update' => self::DEFAULT_BERECHTIGUNG.':w',
'delete' => self::DEFAULT_BERECHTIGUNG.':w',
'importFerien' => self::DEFAULT_BERECHTIGUNG.':w'
]);
// Load models
$this->load->model('organisation/Ferien_model', 'FerienModel');
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->load->library('PermissionLib');
$this->load->config('ferienimport');
// Load language phrases
$this->loadPhrases([
'ui'
]);
}
//------------------------------------------------------------------------------------------------------------------
// Public methods
/**
* Get Ferien
*/
public function getFerien()
{
$filterVonDatum = $this->input->get('filterVonDatum');
$filterBisDatum = $this->input->get('filterBisDatum');
if (isset($filterVonDatum) && !is_valid_date($filterVonDatum))
return $this->terminateWithError($this->p->t('ui', 'error_invalid_date'), self::ERROR_TYPE_GENERAL);
if (isset($filterBisDatum) && !is_valid_date($filterBisDatum))
return $this->terminateWithError($this->p->t('ui', 'error_invalid_date'), self::ERROR_TYPE_GENERAL);
$this->FerienModel->addSelect(
'tbl_ferien.ferien_id, tbl_ferien.bezeichnung, tbl_ferien.vondatum, tbl_ferien.bisdatum,
plan.studienplan_id, oe.oe_kurzbz, fetyp.ferientyp_kurzbz, oe.bezeichnung AS oe_bezeichnung,
plan.studienplan_id, plan.bezeichnung AS studienplan_bezeichnung, fetyp.mitarbeiter AS mitarbeiterrelevant,
fetyp.studierende AS studierendenrelevant, fetyp.lehre'
);
$this->FerienModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT');
$this->FerienModel->addJoin('lehre.tbl_studienplan plan', 'studienplan_id', 'LEFT');
$this->FerienModel->addJoin('public.tbl_organisationseinheit oe', 'tbl_ferien.oe_kurzbz = oe.oe_kurzbz', 'LEFT');
$this->FerienModel->addJoin('lehre.tbl_ferientyp fetyp', 'ferientyp_kurzbz', 'LEFT');
if (isset($filterVonDatum))
$this->FerienModel->db->where('tbl_ferien.bisdatum >=', $filterVonDatum);
if (isset($filterBisDatum))
$this->FerienModel->db->where('tbl_ferien.vondatum <=', $filterBisDatum);
$this->FerienModel->addOrder('vondatum', 'DESC');
$result = $this->FerienModel->load();
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
/**
* Gets default dates (from - to) for filtering Ferien.
*/
public function getDefaultVonBis()
{
$defaultVonBis = ['defaultVon' => null, 'defaultBis' => null];
// get current Studienjahr
$this->load->model('organisation/Studienjahr_model', 'StudienjahrModel');
$result = $this->StudienjahrModel->getAktOrNextStudienjahr(62);
if (isError($result)) return $this->terminateWithError(getError($result));
if (hasData($result))
{
$studienjahr = getData($result)[0];
$defaultVonBis['defaultVon'] = $studienjahr->beginn;
$defaultVonBis['defaultBis'] = $studienjahr->ende;
}
$this->terminateWithSuccess($defaultVonBis);
}
/**
* Get list of Organisationseinheiten
*/
public function getOe()
{
$this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
//$this->StudiengangModel->addSelect(' tbl_studiengang.*, UPPER(typ::varchar(1) || kurzbz) AS kuerzel');
$this->OrganisationseinheitModel->addOrder('organisationseinheittyp_kurzbz, oe_kurzbz');
$result = $this->OrganisationseinheitModel->loadWhere(['aktiv' => true]);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
/**
* Get list of Studienplaene.
* Studienplaene are returned by Organisationseinheit, von and bis datum.
*/
public function getStudienplaene()
{
// check input
$oe_kurzbz = $this->input->get('oe_kurzbz');
$vondatum = $this->input->get('vondatum');
$bisdatum = $this->input->get('bisdatum');
if (!isset($oe_kurzbz) || isEmptyString($oe_kurzbz))
return $this->terminateWithError($this->p->t('ferien', 'error_missingId', ['id' => 'Organisationseinheit']));
if (isset($vondatum) && !is_valid_date($vondatum))
return $this->terminateWithError($this->p->t('ui', 'error_invalid_date'), self::ERROR_TYPE_GENERAL);
if (isset($bisdatum) && !is_valid_date($bisdatum))
return $this->terminateWithError($this->p->t('ui', 'error_invalid_date'), self::ERROR_TYPE_GENERAL);
// get Studiengang from Oe
$result = $this->StudiengangModel->loadWhere(['oe_kurzbz' => $oe_kurzbz]);
if (isError($result)) return $this->terminateWithError(getError($result));
if (!hasData($result)) return $this->terminateWithSuccess([]);
$studiengangKzArr = array_column(getData($result), 'studiengang_kz');
// load models
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$this->load->model('organisation/Studienplan_model', 'StudienplanModel');
// get all Studiensemester in requested date range
$result = $this->StudiensemesterModel->getByDateRange($vondatum, $bisdatum);
if (isError($result)) return $this->terminateWithError(getError($result));
if (!hasData($result)) return $this->terminateWithSuccess([]);
$studiensemesterArr = array_column(getData($result), 'studiensemester_kurzbz');
$studienplaene = [];
foreach ($studiengangKzArr as $studiengang_kz)
{
foreach ($studiensemesterArr as $studiensemester_kurzbz)
{
// get studienplaene for each Studiengang and Studiensemester
$this->StudienplanModel->addDistinct("studienplan_id");
$this->StudienplanModel->addSelect("lehre.tbl_studienplan.*");
$this->StudienplanModel->addJoin("lehre.tbl_studienordnung", "studienordnung_id");
$this->StudienplanModel->addJoin("lehre.tbl_studienplan_semester", "studienplan_id");
$whereArray = array(
"tbl_studienplan.aktiv" => "TRUE",
"tbl_studienordnung.studiengang_kz" => $studiengang_kz,
"tbl_studienplan_semester.studiensemester_kurzbz" => $studiensemester_kurzbz
);
$result = $this->StudienplanModel->loadWhere($whereArray);
if (isError($result)) return $this->terminateWithError(getError($result));
if (!hasData($result)) continue;
foreach (getData($result) as $studienplan)
{
$studienplaene[$studienplan->studienplan_id] = $studienplan;
}
}
}
$this->terminateWithSuccess($studienplaene);
}
/**
* Get list of Ferientypen
*/
public function getFerientypen()
{
$this->load->model('organisation/Ferientyp_model', 'FerientypModel');
$this->FerientypModel->addOrder('ferientyp_kurzbz');
$result = $this->FerientypModel->load();
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
/**
* Add Ferien
*/
public function insert()
{
$this->_validate();
$data = $this->_getData();
// check permissions for new Ferien
if (!$this->permissionlib->isBerechtigt(self::DEFAULT_BERECHTIGUNG, 'suid', $data['oe_kurzbz']))
return $this->terminateWithError($this->p->t('ui', 'keineBerechtigung'));
$data = array_merge($data, ['insertamum' => date('c'), 'insertvon' => getAuthUID()]);
$id = $this->getDataOrTerminateWithError($this->FerienModel->insert($data));
$this->terminateWithSuccess(hasData($id) ? getData($id) : null);
}
/**
* Update Ferien
*/
public function update()
{
$id = $this->input->post('ferien_id');
if (!is_numeric($id))
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Ferien Id']), self::ERROR_TYPE_GENERAL);
$this->_validate();
$data = $this->_getData();
// check permissions for existing Ferien
$this->_validateBerechtigung('suid', $id);
// check permissions for new Ferien
if (!$this->permissionlib->isBerechtigt(self::DEFAULT_BERECHTIGUNG, 'suid', $data['oe_kurzbz']))
return $this->terminateWithError($this->p->t('ui', 'keineBerechtigung'));
if (isEmptyArray($data)) return $this->terminateWithSuccess(null);
$data = array_merge($data, ['ferien_id' => $id, 'updateamum' => date('c'), 'updatevon' => getAuthUID()]);
$result = $this->FerienModel->update($id, $data);
if (isError($result)) return $this->terminateWithError(getError($result));
$this->terminateWithSuccess($id);
}
/**
* Delete Ferien
*/
public function delete()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('ferien_id', 'Ferien Id', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$ferien_id = $this->input->post('ferien_id');
$this->_validateBerechtigung('suid', $ferien_id);
$this->FerienModel->addSelect('ferien_id');
$result = $this->FerienModel->load($ferien_id);
if (!hasData($result)) return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['ferien_id' => $ferien_id]));
$result = $this->getDataOrTerminateWithError($this->FerienModel->delete($ferien_id));
$this->terminateWithSuccess();
}
/**
* Import Ferien from external source
*/
public function importFerien()
{
$filterVonDatum = $this->input->get('filterVonDatum');
$filterBisDatum = $this->input->get('filterBisDatum');
if (isset($filterVonDatum) && !is_valid_date($filterVonDatum))
return $this->terminateWithError($this->p->t('ui', 'error_invalid_date'), self::ERROR_TYPE_GENERAL);
if (isset($filterBisDatum) && !is_valid_date($filterBisDatum))
return $this->terminateWithError($this->p->t('ui', 'error_invalid_date'), self::ERROR_TYPE_GENERAL);
$noImported = 0;
$data = file_get_contents($this->config->item('ferien_import_link'));
if (!$data) return $this->terminateWithError($this->p->t('ferien', 'csvNichtGelesen'), self::ERROR_TYPE_GENERAL);
$rows = explode("\n", $data);
$headers = [];
$ferien = [];
$headerRow = true;
foreach($rows as $row)
{
/*
* Wenn escape auf etwas anderes als eine leere Zeichenkette ("") gesetzt wird, kann dies zu einer CSV-Datei führen,
* die nicht mit » RFC 4180 konform ist oder die den Umlauf durch die PHP-CSV-Funktionen nicht übersteht.
* Der Standardwert für escape ist "\\", weshalb empfohlen wird, diesen Parameter explizit auf eine leere Zeichenkette zu setzen.
*/
$fe = str_getcsv($row, ",", "\"", '');
if ($headerRow)
{
$headers = $fe;
}
else
{
$importedFerien = [];
foreach ($fe as $idx => $value)
{
if (!isset($headers[$idx])) continue;
$importedFerien[$headers[$idx]] = $value;
}
// map Ferien so they can be imported
$ferien = $this->_mapImportFerien($importedFerien);
// do not import Ferien if no successfull import or not in date range
if (
!$ferien
|| ($filterVonDatum != null && new DateTime($filterVonDatum) > new DateTime($ferien['bisdatum']))
|| ($filterBisDatum != null && new DateTime($filterBisDatum) < new DateTime($ferien['vondatum']))
) continue;
$result = $this->FerienModel->loadWhere([
'vondatum' => $ferien['vondatum'],
'bisdatum' => $ferien['bisdatum'],
'bezeichnung' => $ferien['bezeichnung'],
'oe_kurzbz' => null
]);
if (isError($result)) return $this->terminateWithError($this->p->t('ferien', 'fehlerBeimLaden'), self::ERROR_TYPE_GENERAL);
// add Ferien if there have been
if (!hasData($result))
{
$result = $this->FerienModel->insert($ferien);
if (isError($result)) return $this->terminateWithError($this->p->t('ferien', 'fehlerBeimHinzufuegen'), self::ERROR_TYPE_GENERAL);
$noImported++;
}
}
$headerRow = false;
}
$this->terminateWithSuccess($noImported);
}
/**
* Validate ferien post input.
*/
private function _validate()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('vondatum', 'Von Datum', 'required|is_valid_date');
$this->form_validation->set_rules('bisdatum', 'Bis Datum', 'required|is_valid_date');
$this->form_validation->set_rules('bezeichnung', 'Bezeichnung', 'required|max_length[128]');
$this->form_validation->set_rules('oe_kurzbz', 'Organisationseinheit', 'max_length[32]');
$this->form_validation->set_rules('studienplan_id', 'Studienplan', 'numeric');
$this->form_validation->set_rules('ferientyp_kurzbz', 'Ferientyp', 'max_length[64]');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
/**
* Checks permission for oe of Ferien. Terminates if unauthorized.
* @param typ permission type suid
* @param ferien_id
* @return void
*/
private function _validateBerechtigung($typ, $ferien_id)
{
if (isset($ferien_id))
{
$this->FerienModel->addSelect('oe_kurzbz');
$result = $this->FerienModel->load($ferien_id);
if (isError($result)) return $this->terminateWithError(getError($result));
if (hasData($result))
{
$ferien = getData($result)[0];
if ($this->permissionlib->isBerechtigt(self::DEFAULT_BERECHTIGUNG, $typ, $ferien->oe_kurzbz)) return;
}
}
return $this->terminateWithError($this->p->t('ui', 'keineBerechtigung'));
}
/**
* Gets Ferien data from post input.
*/
private function _getData()
{
$data = [];
$allowed = [
'vondatum',
'bisdatum',
'bezeichnung',
'oe_kurzbz',
'studienplan_id',
'ferientyp_kurzbz'
];
foreach ($allowed as $field)
{
$data[$field] = $this->input->post($field);
}
return $data;
}
/**
* Map ferien from external source to internal format
* @param $importedFerien from external source
* @return array imported Ferien, in fhcomplete format
*/
private function _mapImportFerien($importedFerien)
{
$mappings = [
'vondatum' => 'DATUM',
'bisdatum' => 'DATUM',
'bezeichnung' => 'TEXT'
];
$ferien = [
'ferientyp_kurzbz' => self::FERIENTYP_KURZBZ,
'insertamum' => date('c'),
'insertvon' => getAuthUID()
];
foreach ($mappings as $key => $name)
{
if (!isset($importedFerien[$name])) return null;
$ferien[$key] = $importedFerien[$name];
}
return $ferien;
}
}
@@ -28,8 +28,7 @@ class Studiensemester extends FHCAPI_Controller
'getStudienjahrByStudiensemester' => self::PERM_LOGGED,
'getAllStudiensemesterAndAktOrNext' => self::PERM_LOGGED,
'current' => self::PERM_LOGGED,
'set' => self::PERM_LOGGED,
'getContainingOrNearestByDateRange' => self::PERM_LOGGED,
'set' => self::PERM_LOGGED
)
);
// Load model StudiensemesterModel
@@ -204,15 +203,4 @@ class Studiensemester extends FHCAPI_Controller
$this->terminateWithSuccess(true);
}
public function getContainingOrNearestByDateRange()
{
$from = $this->input->get("from");
$to = $this->input->get("to");
$result = $this->StudiensemesterModel->getContainingOrNearestByDateRange($from, $to);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
}
@@ -574,19 +574,6 @@ class Kontakt extends FHCAPI_Controller
$person_id = $this->input->post('person_id');
$standort_id = $this->input->post('standort_id');
//check person_id: allow editing only of persons who are no mitarbeiter
if($person_id)
{
$this->load->model('person/Benutzer_model', 'BenutzerModel');
$this->BenutzerModel->addJoin('public.tbl_mitarbeiter ma', 'ON (ma.mitarbeiter_uid = public.tbl_benutzer.uid)');
$result = $this->BenutzerModel->loadWhere([
'person_id' => $person_id
]);
if(hasData($result))
return $this->terminateWithError($this->p->t('ui', 'editingMitarbeiterPVonly'), self::ERROR_TYPE_GENERAL);
}
$result = $this->KontaktModel->update(
[
'kontakt_id' => $kontakt_id
@@ -0,0 +1,44 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
* Ferien management
*/
class Ferienverwaltung extends Auth_Controller
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct(
array(
'index' => ['basis/ferien:r']
)
);
// Loads WidgetLib
//$this->load->library('WidgetLib');
// Loads phrases system
$this->loadPhrases(
array(
'global',
'ui'
//'ferien'
)
);
}
// -----------------------------------------------------------------------------------------------------------------
// Public methods
/**
* Everything has a beginning
*/
public function index()
{
$this->load->view('lehre/ferienverwaltung.php');
}
}
+4 -101
View File
@@ -33,7 +33,7 @@ class SearchBarLib
const ERROR_NOT_AUTH = 'ERR005';
// List of allowed types of search
const ALLOWED_TYPES = ['mitarbeiter', 'mitarbeiter_ohne_zuordnung', 'organisationunit', 'raum', 'person', 'student','studentStv', 'prestudent', 'document', 'cms', 'lehreinheit', 'lehrveranstaltung'];
const ALLOWED_TYPES = ['mitarbeiter', 'mitarbeiter_ohne_zuordnung', 'organisationunit', 'raum', 'person', 'student','studentStv', 'prestudent', 'document', 'cms'];
const PHOTO_IMG_URL = '/cis/public/bild.php?src=person&person_id=';
@@ -180,14 +180,10 @@ class SearchBarLib
protected function buildSearchClause(DB_Model $dbModel, array $columns, $searchstr)
{
$searchstr = preg_replace('/[[:punct:]]/', ' ', $searchstr);
$words = preg_split('/\s+/', trim($searchstr), -1, PREG_SPLIT_NO_EMPTY);
if (empty($words)) return array();
$document = implode(' || \' \' || ', $columns);
$query = '\'' . implode(':* & ', $words) . ':*\'';
$reversequery = '\'*:' . implode(' & *:', $words) . '\'';
$nospacequery = '\'' . implode('', $words) . ':*\'';
$query = '\'' . implode(':* & ', explode(' ', trim($searchstr))) . ':*\'';
$reversequery = '\'*:' . implode(' & *:', explode(' ', trim($searchstr))) . '\'';
$nospacequery = '\'' . implode('', explode(' ', trim($searchstr))) . ':*\'';
$searchclause = <<<EOSC
to_tsvector(lower(regexp_replace({$document}, '[[:punct:]]', ' ', 'g'))) @@ to_tsquery(lower({$query}))
@@ -600,98 +596,5 @@ EOSC;
// Otherwise return an empty array
return array();
}
private function _lehreinheit($searchstr, $type)
{
$dbModel = new DB_Model();
$idwhere = '';
if (ctype_digit(trim($searchstr)))
{
$id = (int)trim($searchstr);
$idwhere = ' OR le.lehreinheit_id = ' . $id;
}
$lehreinheit = $dbModel->execReadOnlyQuery('
SELECT
\'teachingunit\' AS renderer,
\''.$type.'\' AS type,
le.lehreinheit_id AS id,
le.studiensemester_kurzbz,
lv.bezeichnung,
\'lv_table_icon icon-\' AS foto,
UPPER(stg.typ || stg.kurzbz) AS studiengang,
le.lehrform_kurzbz,
lv.semester
FROM lehre.tbl_lehreinheit le
JOIN lehre.tbl_lehrveranstaltung lv ON (lv.lehrveranstaltung_id = le.lehrveranstaltung_id)
JOIN public.tbl_studiengang stg ON (stg.studiengang_kz = lv.studiengang_kz)
JOIN public.tbl_studiensemester sem ON (sem.studiensemester_kurzbz = le.studiensemester_kurzbz)
WHERE (' .
$this->buildSearchClause(
$dbModel,
array(
'(stg.typ || stg.kurzbz)',
'lv.semester',
'lv.bezeichnung'
),
$searchstr
) . ')' . $idwhere . '
');
// If something has been found then return it
if (hasData($lehreinheit)) return getData($lehreinheit);
// Otherwise return an empty array
return array();
}
private function _lehrveranstaltung($searchstr, $type)
{
$dbModel = new DB_Model();
$idwhere = '';
if (ctype_digit(trim($searchstr)))
{
$id = (int)trim($searchstr);
$idwhere = ' OR tbl_lehrveranstaltung.lehrveranstaltung_id = ' . $id;
}
$lehreinheit = $dbModel->execReadOnlyQuery('
SELECT
\'teachingunit\' AS renderer,
\''.$type.'\' AS type,
lehrveranstaltung_id as id,
tbl_lehrveranstaltung.bezeichnung,
\'lv_table_icon icon-lv\' as foto,
UPPER(tbl_studiengang.typ::varchar(1) || tbl_studiengang.kurzbz) as studiengang,
semester,
lehrform_kurzbz,
tbl_organisationseinheit.bezeichnung as oe_bezeichnung
FROM lehre.tbl_lehrveranstaltung
JOIN public.tbl_studiengang USING(studiengang_kz)
JOIN public.tbl_organisationseinheit ON tbl_lehrveranstaltung.oe_kurzbz = tbl_organisationseinheit.oe_kurzbz
WHERE (' .
$this->buildSearchClause(
$dbModel,
array(
'(tbl_studiengang.typ || tbl_studiengang.kurzbz)',
'semester',
'tbl_lehrveranstaltung.bezeichnung'
),
$searchstr
) . ')' . $idwhere . '
');
// If something has been found then return it
if (hasData($lehreinheit)) return getData($lehreinheit);
// Otherwise return an empty array
return array();
}
}
+1 -5
View File
@@ -405,11 +405,7 @@ class StundenplanLib
$tz = new DateTimeZone($this->_ci->config->item('timezone'));
$ferienEvents = $this->_ci->FerienModel->execReadOnlyQuery("
SELECT *
FROM lehre.tbl_ferien
WHERE (bisdatum >= ? AND vondatum < ?) AND (studiengang_kz = 0 OR studiengang_kz = ?)
", [$start_date, $end_date, $studiengang_kz]);
$ferienEvents = $this->_ci->FerienModel->getByDateRange($start_date, $end_date, $studiengang_kz);
if (isError($ferienEvents))
return $ferienEvents;
@@ -159,6 +159,8 @@ class LvVwLib
if (!$stg->mischform)
return [];
$this->_ci->StudiengangModel->db->select('TRUE AS leaf', false);
return $this->_ci->stglib->orgform($path_template, $stg->studiengang_kz);
}
@@ -340,20 +340,6 @@ EOSQL;
}
public function getByLeStudiensemester($lehreinheit_id, $studiensemester_kurzbz)
{
$qry = "WITH lehreinheiten AS (
SELECT *
FROM lehre.tbl_lehreinheit
WHERE lehreinheit_id = ?
AND studiensemester_kurzbz = ?
)," . $this->_getLeCTE();
$params = array($lehreinheit_id, $studiensemester_kurzbz);
return $this->execReadOnlyQuery($qry, $params);
}
public function getByLvidStudiensemester($lv_id, $studiensemester_kurzbz, $mitarbeiter_uid = null, $fachbereich_kurzbz = null)
{
$qry = "WITH lehreinheiten AS (
@@ -361,7 +347,35 @@ EOSQL;
FROM lehre.tbl_lehreinheit
WHERE lehrveranstaltung_id = ?
AND studiensemester_kurzbz = ?
)," . $this->_getLeCTE();
),
". $this->_getGruppenCTE() . ",
". $this->_getLektorenCTE() . ",
". $this->_getFachbereichCTE() . ",
". $this->_getTagsCTE() . "
SELECT lehreinheiten.*,
lehreinheiten.lehrform_kurzbz as lv_lehrform_kurzbz,
tbl_lehrveranstaltung.kurzbz as lv_kurzbz,
tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung,
COALESCE(tag_data_agg.tags, '[]'::json) AS tags,
gruppen.gruppen,
mitarbeiter.lektoren,
mitarbeiter.le_planstunden,
mitarbeiter.vorname,
mitarbeiter.nachname,
mitarbeiter.semesterstunden,
fachbereich.bezeichnung as fachbereich,
UPPER(CONCAT(tbl_studiengang.typ,tbl_studiengang.kurzbz)) as studiengang,
semester
FROM lehreinheiten
LEFT JOIN lehre.tbl_lehrveranstaltung ON tbl_lehrveranstaltung.lehrveranstaltung_id = lehreinheiten.lehrfach_id
LEFT JOIN public.tbl_studiengang USING(studiengang_kz)
LEFT JOIN tag_data_agg ON tag_data_agg.lehreinheit_id = lehreinheiten.lehreinheit_id
LEFT JOIN mitarbeiter ON lehreinheiten.lehreinheit_id = mitarbeiter.lehreinheit_id
LEFT JOIN fachbereich ON lehreinheiten.lehreinheit_id = fachbereich.lehreinheit_id
LEFT JOIN gruppen ON lehreinheiten.lehreinheit_id = gruppen.lehreinheit_id
WHERE true
";
$params = array($lv_id, $studiensemester_kurzbz);
@@ -381,83 +395,9 @@ EOSQL;
return $this->execReadOnlyQuery($qry, $params);
}
public function getOffeneStunden($lehreinheit_ids)
private function getLVTmp($stg_kz = null)
{
if (!is_array($lehreinheit_ids))
$lehreinheit_ids = [$lehreinheit_ids];
if (empty($lehreinheit_ids))
return success([]);
$db = new DB_Model();
$placeholders = implode(',', array_fill(0, count($lehreinheit_ids), '?'));
$qry = "WITH eventdauer AS (
SELECT
tbl_kalender_lehreinheit.lehreinheit_id,
tbl_kalender.von,
tbl_kalender.bis,
tbl_kalender.kalender_id
FROM lehre.tbl_lehreinheit
JOIN lehre.tbl_kalender_lehreinheit USING(lehreinheit_id)
JOIN lehre.tbl_kalender USING(kalender_id)
WHERE tbl_lehreinheit.lehreinheit_id IN ($placeholders)
AND NOT EXISTS (SELECT 1 FROM lehre.tbl_kalender nachfolger
WHERE nachfolger.vorgaenger_kalender_id = tbl_kalender.kalender_id)
AND tbl_kalender.status_kurzbz NOT IN ('deleted', 'todelete', 'archived')
GROUP BY tbl_kalender_lehreinheit.lehreinheit_id, tbl_kalender.von, tbl_kalender.bis, tbl_kalender.kalender_id
),
raster AS (
SELECT
eventdauer.lehreinheit_id,
eventdauer.kalender_id,
eventdauer.von,
eventdauer.bis,
vonstunde.stunde AS vonstunde_nr,
bisstunde.stunde AS bisstunde_nr
FROM eventdauer
LEFT JOIN lehre.tbl_stunde vonstunde ON eventdauer.von::time = vonstunde.beginn
LEFT JOIN lehre.tbl_stunde bisstunde ON eventdauer.bis::time = bisstunde.ende
),
unterrichtsdauer AS (
SELECT
raster.lehreinheit_id,
raster.kalender_id,
sum(EXTRACT(EPOCH FROM (LEAST(stunde.ende, raster.bis::time) - GREATEST(stunde.beginn, raster.von::time))) / 60) AS minuten
FROM raster JOIN lehre.tbl_stunde stunde ON stunde.beginn < raster.bis::time AND stunde.ende > raster.von::time
WHERE raster.vonstunde_nr IS NULL OR raster.bisstunde_nr IS NULL
GROUP BY raster.lehreinheit_id, raster.kalender_id
),
verplantestunden AS (
SELECT raster.lehreinheit_id, raster.kalender_id,
CASE
WHEN raster.vonstunde_nr IS NOT NULL AND raster.bisstunde_nr IS NOT NULL
THEN (raster.bisstunde_nr - raster.vonstunde_nr + 1)
ELSE coalesce(unterrichtsdauer.minuten, 0) / 45
END AS verplantestunde
FROM raster LEFT JOIN unterrichtsdauer ON unterrichtsdauer.lehreinheit_id = raster.lehreinheit_id AND unterrichtsdauer.kalender_id = raster.kalender_id
),
verplant_gesamt AS (
SELECT lehreinheit_id, SUM(verplantestunde) AS verplant
FROM verplantestunden
GROUP BY lehreinheit_id
)
SELECT
lema.lehreinheit_id,
lema.mitarbeiter_uid,
lema.planstunden,
ROUND(coalesce(verplant_gesamt.verplant, 0), 2) AS verplant,
ROUND((lema.planstunden - coalesce(verplant_gesamt.verplant, 0)), 2) AS offenestunden
FROM lehre.tbl_lehreinheitmitarbeiter lema
LEFT JOIN verplant_gesamt ON verplant_gesamt.lehreinheit_id = lema.lehreinheit_id
WHERE lema.lehreinheit_id IN ($placeholders)";
return $db->execReadOnlyQuery($qry, array_merge($lehreinheit_ids, $lehreinheit_ids));
}
private function getLVTmp()
{
return "SELECT DISTINCT ON(lehrveranstaltung_id) *,
$qry = "SELECT DISTINCT ON(lehrveranstaltung_id) *,
'' as stundenblockung,
'' as lehreinheit_id,
'' as wochenrythmus,
@@ -468,33 +408,24 @@ EOSQL;
'' as studienplan_beeichnung,
UPPER(CONCAT(vw_lehreinheit.stg_typ, vw_lehreinheit.stg_kurzbz)) as studiengang
FROM campus.vw_lehreinheit
WHERE studiensemester_kurzbz = ? ";
WHERE mitarbeiter_uid = ?
AND studiensemester_kurzbz = ?";
if (!is_null($stg_kz)) {
$qry .= " AND lv_studiengang_kz = ?";
}
return $qry;
}
public function getLvsById($lehrveranstaltung_id, $studiensemester_kurzbz)
{
$where = ' AND lehrveranstaltung_id = ?';
$qry = "WITH lvs AS (" . $this->getLVTmp() . $where .")
SELECT lvs.*
FROM lvs
";
$params = array($studiensemester_kurzbz, $lehrveranstaltung_id);
return $this->execReadOnlyQuery($qry, $params);
}
public function getLvsByEmployee($mitarbeiter_uid, $studiensemester_kurzbz, $stg_kz = null)
{
$where = ' AND mitarbeiter_uid = ?';
if ($stg_kz != null)
$where .= " AND lv_studiengang_kz = ?";
$qry = "WITH lvs AS (" . $this->getLVTmp() . $where .")
$qry = "WITH lvs AS (" . $this->getLVTmp($stg_kz) . ")
SELECT lvs.*
FROM lvs";
$params = array($studiensemester_kurzbz, $mitarbeiter_uid);
FROM lvs
";
$params = array($mitarbeiter_uid, $studiensemester_kurzbz);
if (!is_null($stg_kz))
{
$params[] = $stg_kz;
@@ -701,36 +632,6 @@ EOSQL;
return success('Contract successfully updated.');
}
private function _getLeCTE()
{
return $this->_getGruppenCTE() . ",
". $this->_getLektorenCTE() . ",
". $this->_getFachbereichCTE() . ",
". $this->_getTagsCTE() . "
SELECT lehreinheiten.*,
lehreinheiten.lehrform_kurzbz as lv_lehrform_kurzbz,
tbl_lehrveranstaltung.kurzbz as lv_kurzbz,
tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung,
COALESCE(tag_data_agg.tags, '[]'::json) AS tags,
gruppen.gruppen,
mitarbeiter.lektoren,
mitarbeiter.le_planstunden,
mitarbeiter.vorname,
mitarbeiter.nachname,
mitarbeiter.semesterstunden,
fachbereich.bezeichnung as fachbereich,
UPPER(CONCAT(tbl_studiengang.typ,tbl_studiengang.kurzbz)) as studiengang,
semester
FROM lehreinheiten
LEFT JOIN lehre.tbl_lehrveranstaltung ON tbl_lehrveranstaltung.lehrveranstaltung_id = lehreinheiten.lehrfach_id
LEFT JOIN public.tbl_studiengang USING(studiengang_kz)
LEFT JOIN tag_data_agg ON tag_data_agg.lehreinheit_id = lehreinheiten.lehreinheit_id
LEFT JOIN mitarbeiter ON lehreinheiten.lehreinheit_id = mitarbeiter.lehreinheit_id
LEFT JOIN fachbereich ON lehreinheiten.lehreinheit_id = fachbereich.lehreinheit_id
LEFT JOIN gruppen ON lehreinheiten.lehreinheit_id = gruppen.lehreinheit_id
WHERE true";
}
private function _getGruppenCTE()
{
return "gruppen AS (
@@ -9,6 +9,52 @@ class Ferien_model extends DB_Model
{
parent::__construct();
$this->dbTable = 'lehre.tbl_ferien';
$this->pk = array('studiengang_kz', 'bezeichnung');
$this->pk = 'ferien_id';
}
/**
* Loads all Ferien between two dates.
* @param $vondatum
* @param $bisdatum
* @param $studiengang_kz by default, loads only Ferien from oe of 0 Studiengang (and parents)
* @return object success or error
*/
public function getByDateRange($vondatum, $bisdatum, $studiengang_kz = 0)
{
if (!is_numeric($studiengang_kz)) return error("Invalid Studiengang Kz");
if (!is_valid_date($vondatum)) return error("Invalid von date");
if (!is_valid_date($bisdatum)) return error("Invalid bis date");
// get oe from studiengang
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
$result = $this->StudiengangModel->loadWhere(['studiengang_kz' => $studiengang_kz]);
if (isError($result)) return $result;
if (!hasData($result)) return success([]);
$oe_kurzbz = getData($result)[0]->oe_kurzbz;
// get all parents oes
$this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
$result = $this->OrganisationseinheitModel->getParents($oe_kurzbz);
if (isError($result)) return $result;
if (!hasData($result)) return success([]);
$parents = array_column(getData($result), 'oe_kurzbz');
// get ferien - use oe_kurzbz
$qry = "
SELECT
*
FROM
lehre.tbl_ferien
WHERE
bisdatum >= ? AND vondatum < ?
AND (oe_kurzbz IS NULL OR oe_kurzbz IN ?)
ORDER BY
vondatum";
return $this->execReadOnlyQuery($qry, [$vondatum, $bisdatum, $parents]);
}
}
@@ -0,0 +1,15 @@
<?php
class Ferientyp_model extends DB_Model
{
/**
* Constructor
*/
public function __construct()
{
parent::__construct();
$this->dbTable = 'lehre.tbl_ferientyp';
$this->pk = 'ferientyp_kurzbz';
$this->hasSequence = false;
}
}
@@ -53,11 +53,9 @@ class Studienjahr_model extends DB_Model
* @param int $days
* @return array|stdClass|null
*/
public function getLastOrAktStudienjahr($days = 60)
public function getLastOrAktStudienjahr($days = 0)
{
if (!is_numeric($days)) {
$days = 60;
}
$days = is_numeric($days) ? $this->escape($days) : 0;
$query = '
SELECT *
@@ -77,19 +75,25 @@ class Studienjahr_model extends DB_Model
* @param int $days
* @return array|stdClass|null
*/
public function getAktOrNextStudienjahr($days = 62)
public function getAktOrNextStudienjahr($days = 0)
{
if (!is_numeric($days)) {
$days = 62;
}
$days = is_numeric($days) ? $this->escape($days) : 0;
$query = '
SELECT *
FROM public.tbl_studienjahr
JOIN public.tbl_studiensemester using(studienjahr_kurzbz)
WHERE start < NOW() + \'' . $days . ' DAYS\'::INTERVAL
ORDER by start DESC
LIMIT 1
SELECT * FROM (
SELECT
jahr.*, MIN(sem.start) AS beginn, MAX(sem.ende) AS ende
FROM
public.tbl_studienjahr jahr
JOIN public.tbl_studiensemester sem using(studienjahr_kurzbz)
GROUP BY
studienjahr_kurzbz
) jahre
WHERE
ende >= NOW() + \'' . $days . ' DAYS\'::INTERVAL
ORDER BY
ende
LIMIT 1
';
return $this->execQuery($query);
@@ -292,29 +292,13 @@ class Studiensemester_model extends DB_Model
COALESCE(
(SELECT studiensemester_kurzbz FROM semester_interval_startdate),
(SELECT studiensemester_kurzbz FROM nearest_semester_interval_startdate)
) AS studiensemester_kurzbz,
COALESCE(
(SELECT start FROM semester_interval_startdate),
(SELECT start FROM nearest_semester_interval_startdate)
) as start,
COALESCE(
(SELECT ende FROM semester_interval_startdate),
(SELECT ende FROM nearest_semester_interval_startdate)
) as ende
) AS studiensemester_kurzbz
UNION
SELECT
COALESCE(
(SELECT studiensemester_kurzbz FROM semester_interval_enddate),
(SELECT studiensemester_kurzbz FROM nearest_semester_interval_enddate)
) AS studiensemester_kurzbz,
COALESCE(
(SELECT start FROM semester_interval_enddate),
(SELECT start FROM nearest_semester_interval_enddate)
) as start,
COALESCE(
(SELECT ende FROM semester_interval_enddate),
(SELECT ende FROM nearest_semester_interval_enddate)
) as ende
) AS studiensemester_kurzbz
EOSQL;
@@ -0,0 +1,27 @@
<?php
$includesArray = array(
'title' => 'Ferienverwaltung',
'axios027' => true,
'bootstrap5' => true,
'fontawesome6' => true,
'vue3' => true,
'filtercomponent' => true,
'navigationcomponent' => true,
'tabulator6' => true,
'primevue3' => true,
//'vuedatepicker11' => true,
'customJSModules' => array('public/js/apps/lehre/Ferienverwaltung/Ferienverwaltung.js'),
'customCSSs' => array('vendor/vuejs/vuedatepicker_css/main.css')
);
$this->load->view('templates/FHC-Header', $includesArray);
?>
<div id="main">
<div>
<ferienverwaltung></ferienverwaltung>
</div>
</div>
<?php $this->load->view('templates/FHC-Footer', $includesArray); ?>
@@ -21,7 +21,6 @@ $this->load->view('templates/FHC-Header', $includesArray);
?>
<script type="text/javascript">
document.body.classList.add("cis4");
if (window.self !== window.top)
document.body.classList.add("in-frame");
</script>
+25 -63
View File
@@ -21,7 +21,6 @@
* Manuela Thamer <[email protected]>
*/
require_once(dirname(__FILE__).'/basis_db.class.php');
require_once(dirname(__FILE__).'/mitarbeiter.class.php');
class entwicklungsteam extends basis_db
{
@@ -44,6 +43,7 @@ class entwicklungsteam extends basis_db
public $ext_id;
public $besqual;
public $studiengang_kz_old;
/**
* Konstruktor
@@ -74,7 +74,7 @@ class entwicklungsteam extends basis_db
$qry = "SELECT * FROM bis.tbl_entwicklungsteam JOIN bis.tbl_besqual USING(besqualcode)
WHERE entwicklungsteam_id=".$this->db_add_param($entwicklungsteam_id);
$qry.=";";
$qry.=";";
if($this->db_query($qry))
{
@@ -147,11 +147,6 @@ class entwicklungsteam extends basis_db
$this->errormsg = 'Es muss ein Mitarbeiter angegeben werden';
return false;
}
if(!$this->checkIfExistingUid($this->mitarbeiter_uid))
{
$this->errormsg = 'Bitte einen Eintrag aus dem Dropdown Personensuche auswählen!';
return false;
}
if($this->studiengang_kz=='')
{
$this->errormsg = 'Es muss ein Studiengang angegeben werden';
@@ -167,26 +162,6 @@ class entwicklungsteam extends basis_db
$this->errormsg = 'Endedatum darf nicht vor Anfangsdatum liegen';
return false;
}
if($this->beginn != '')
{
$beginnParts = explode('-', $this->beginn);
if (!checkdate((int)$beginnParts[1], (int)$beginnParts[2], (int)$beginnParts[0])) {
$this->errormsg = 'Anfangsdatum ist ungültig';
return false;
}
}
if($this->ende != '')
{
$endeParts = explode('-', $this->ende);
if (!checkdate((int)$endeParts[1], (int)$endeParts[2], (int)$endeParts[0]))
{
$this->errormsg = 'Endedatum ist ungültig';
return false;
}
}
return true;
}
@@ -208,28 +183,30 @@ class entwicklungsteam extends basis_db
//Neuen Datensatz anlegen
$qry = "INSERT INTO bis.tbl_entwicklungsteam (mitarbeiter_uid, studiengang_kz, besqualcode, beginn, ende,
updateamum, updatevon, insertamum, insertvon) VALUES (".
$this->db_add_param($this->mitarbeiter_uid).', '.
$this->db_add_param($this->studiengang_kz, FHC_INTEGER).', '.
$this->db_add_param($this->besqualcode, FHC_INTEGER).', '.
$this->db_add_param($this->beginn).', '.
$this->db_add_param($this->ende).', '.
$this->db_add_param($this->updateamum).', '.
$this->db_add_param($this->updatevon).', '.
$this->db_add_param($this->insertamum).', '.
$this->db_add_param($this->insertvon).');';
$this->db_add_param($this->mitarbeiter_uid).', '.
$this->db_add_param($this->studiengang_kz, FHC_INTEGER).', '.
$this->db_add_param($this->besqualcode, FHC_INTEGER).', '.
$this->db_add_param($this->beginn).', '.
$this->db_add_param($this->ende).', '.
$this->db_add_param($this->updateamum).', '.
$this->db_add_param($this->updatevon).', '.
$this->db_add_param($this->insertamum).', '.
$this->db_add_param($this->insertvon).');';
}
else
{
if($this->studiengang_kz_old=='')
$this->studiengang_kz_old = $this->studiengang_kz;
//Bestehenden Datensatz aktualisieren
$qry= "UPDATE bis.tbl_entwicklungsteam SET".
" besqualcode=".$this->db_add_param($this->besqualcode, FHC_INTEGER).",".
" beginn=".$this->db_add_param($this->beginn).",".
" studiengang_kz=".$this->db_add_param($this->studiengang_kz, FHC_INTEGER).",".
" ende=".$this->db_add_param($this->ende).",".
" mitarbeiter_uid=".$this->db_add_param($this->mitarbeiter_uid).",".
" updateamum=".$this->db_add_param($this->updateamum).",".
" updatevon=".$this->db_add_param($this->updatevon).
" WHERE entwicklungsteam_id=".$this->db_add_param($this->entwicklungsteam_id).";";
" besqualcode=".$this->db_add_param($this->besqualcode, FHC_INTEGER).",".
" beginn=".$this->db_add_param($this->beginn).",".
" studiengang_kz=".$this->db_add_param($this->studiengang_kz, FHC_INTEGER).",".
" ende=".$this->db_add_param($this->ende).",".
" updateamum=".$this->db_add_param($this->updateamum).",".
" updatevon=".$this->db_add_param($this->updatevon).
" WHERE entwicklungsteam_id=".$this->db_add_param($this->entwicklungsteam_id).";";
}
if($this->db_query($qry))
@@ -257,7 +234,7 @@ class entwicklungsteam extends basis_db
if($studiengang_kz!=null)
$qry.=" AND studiengang_kz=".$this->db_add_param($studiengang_kz);
$qry.=";";
$qry.=";";
if($this->db_query($qry))
{
@@ -339,7 +316,7 @@ class entwicklungsteam extends basis_db
if ($sort != null)
{
$qry .= " ORDER BY ".$sort;
$qry .= " ORDER BY ".$sort;
}
$qry .= ";";
@@ -387,7 +364,7 @@ class entwicklungsteam extends basis_db
$bismeldung_jahr = $datetime->format('Y');
//laden des Datensatzes
$qry = "SELECT tbl_entwicklungsteam.*, tbl_besqual.*, tbl_studiengang.studiengang_kz, tbl_studiengang.melderelevant
$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)
@@ -398,7 +375,7 @@ class entwicklungsteam extends basis_db
if($studiengang_kz!=null)
$qry.=" AND studiengang_kz=".$this->db_add_param($studiengang_kz);
$qry.=";";
$qry.=";";
if($this->db_query($qry))
{
@@ -430,20 +407,5 @@ class entwicklungsteam extends basis_db
return false;
}
}
/*
* Überprüft, ob die übergebene Uid in der Tabelle tbl_mitarbeiter vorhanden ist
* @param String $uid UID des Mitarbeiters
* @return true wenn vorhanden, false wenn nicht
*/
private function checkIfExistingUid($uid)
{
$mitarbeiter = new mitarbeiter();
if(!$mitarbeiter->checkIfExistingUid($uid))
return false;
return true;
}
}
?>
+44 -1
View File
@@ -24,6 +24,7 @@
* @create 07-12-2006
*/
require_once(dirname(__FILE__).'/basis_db.class.php');
require_once(dirname(__FILE__).'/organisationseinheit.class.php');
class ferien extends basis_db
{
@@ -62,8 +63,50 @@ class ferien extends basis_db
$this->errormsg = 'Studiengang_kz ist ungültig';
return false;
}
// get oe from studiengang
$sql_query="
SELECT
oe_kurzbz
FROM
public.tbl_studiengang
WHERE
studiengang_kz=".$this->db_add_param($stg_kz, FHC_INTEGER)."
ORDER BY
studiengang_kz";
$sql_query="SELECT * FROM lehre.tbl_ferien WHERE studiengang_kz=0 OR studiengang_kz=".$this->db_add_param($stg_kz, FHC_INTEGER)." ORDER BY vondatum;";
if (!$this->db_query($sql_query))
{
$this->errormsg = $this->db_last_error();
return false;
}
$oe_kurzbz = '';
while ($row = $this->db_fetch_object())
{
$oe_kurzbz = $row->oe_kurzbz;
}
// get all parents oes
$organisationseinheit = new organisationseinheit();
$parents = $organisationseinheit->getParents($oe_kurzbz);
if (!$parents)
{
$this->errormsg = $parents->errormsg;
return false;
}
$sql_query="
SELECT
*
FROM
lehre.tbl_ferien
WHERE
oe_kurzbz IS NULL
OR oe_kurzbz IN (".$this->implode4SQL($parents).")
ORDER BY
vondatum";
if (!$this->db_query($sql_query))
{
-18
View File
@@ -1995,23 +1995,5 @@ class mitarbeiter extends benutzer
return true;
}
}
/**
* Prueft ob eine existierende ma_uid übergeben wurde
* @param String $mitarbeiter_uid mitarbeiter_uid
* @return bool True wenn mitarbeiter_uid vorhanden sonst false.
*/
public function checkIfExistingUid($mitarbeiter_uid)
{
$qry = "Select 1 from public.tbl_mitarbeiter where mitarbeiter_uid =".$this->db_add_param($mitarbeiter_uid);
if ($result = $this->db_query($qry))
{
if ($this->db_num_rows($result) > 0)
return true;
else
return false;
}
}
}
?>
+4 -25
View File
@@ -7,11 +7,6 @@ html {
font-size: 0.875em;
}
body.compat,
body.compat main#cis-main {
background-color: #fff;
}
.fhc-dark-bg{
background-color: var(--fhc-dark);
color:var(--fhc-light) !important;
@@ -459,8 +454,8 @@ body.compat main#cis-main {
/* desktop */
@media (min-width: 992px) {
body.cis4 {
display: flex;
body {
display: flex;
padding-top: var(--fhc-cis-header-height);
width: calc(100svw - var(--scrollbar-width, 0px));
/* overflow: visible !important; */
@@ -765,7 +760,7 @@ body.compat main#cis-main {
}
.dashboard-item {
overscroll-behavior: auto;
overscroll-behavior: none;
}
.abgabe-zieldatum-border-red,
@@ -858,20 +853,4 @@ body.compat main#cis-main {
border: 1px solid rgba(0, 0, 0, 0.15);
border-radius: 0.5rem;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);
}
.cis-main-menu {
max-width: 100vw;
}
.cis-main-menu ul {
list-style: none;
margin: 0;
padding: 0;
}
.cis-main-menu ul li {
margin: 0;
padding: 0;
width: 100%;
}
}
@@ -0,0 +1,89 @@
/**
* 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 {
getFerien(filterVonDatum, filterBisDatum) {
return {
method: 'get',
url: 'api/frontend/v1/education/ferien/getFerien',
params: {
filterVonDatum,
filterBisDatum
}
};
},
getOe() {
return {
method: 'get',
url: 'api/frontend/v1/education/ferien/getOe'
};
},
getStudienplaene(oe_kurzbz, vondatum, bisdatum) {
return {
method: 'get',
url: 'api/frontend/v1/education/ferien/getStudienplaene',
params: {
oe_kurzbz,
vondatum,
bisdatum
}
};
},
getFerientypen() {
return {
method: 'get',
url: 'api/frontend/v1/education/ferien/getFerientypen'
};
},
getDefaultVonBis() {
return {
method: 'get',
url: 'api/frontend/v1/education/ferien/getDefaultVonBis'
};
},
insert(params) {
return {
method: 'post',
url: 'api/frontend/v1/education/ferien/insert',
params
};
},
update(params) {
return {
method: 'post',
url: 'api/frontend/v1/education/ferien/update',
params
};
},
delete(ferien_id) {
return {
method: 'post',
url: 'api/frontend/v1/education/ferien/delete',
params: { ferien_id }
};
},
importFerien(filterVonDatum, filterBisDatum) {
return {
method: 'get',
url: 'api/frontend/v1/education/ferien/importFerien',
params: {
filterVonDatum,
filterBisDatum
}
};
},
};
+1 -11
View File
@@ -44,15 +44,5 @@ export default {
studiensemester_kurzbz
}
};
},
getContainingOrNearestByDateRange(from, to) {
return {
method: 'get',
url: 'api/frontend/v1/organisation/studiensemester/getContainingOrNearestByDateRange',
params: {
from,
to,
}
};
},
}
};
-2
View File
@@ -17,8 +17,6 @@ const router = VueRouter.createRouter({
component: LVVerwaltung,
children: [
{ name: 'emp', path: 'emp/:emp/:treemenu(.*)*', component: LVVerwaltung },
{ name: 'le', path: 'le/:le', component: LVVerwaltung },
{ name: 'lv', path: 'lv/:lv', component: LVVerwaltung },
{ name: 'treemenu', path: ':treemenu(.*)*', component: LVVerwaltung }
]
},
@@ -0,0 +1,12 @@
import Ferienverwaltung from '../../../components/Ferienverwaltung/Ferienverwaltung.js';
import PluginsPhrasen from '../../../plugins/Phrasen.js';
const app = Vue.createApp({
name: 'FerienverwaltungApp',
components: {
Ferienverwaltung
}
});
app
.use(PluginsPhrasen)
.mount('#main');
-7
View File
@@ -103,13 +103,6 @@ export default {
keyboard: this.keyboard
});
},
//to avoid pagelocks if more than one instance
beforeUnmount() {
if (this.modal) {
this.modal.dispose();
this.modal = null;
}
},
popup(body, options, title, footer) {
const BsModal = this,
slots = {};
-6
View File
@@ -16,15 +16,9 @@ export default {
return this.mode + '#' + this.path + '#' + this.query_string;
}
},
beforeMount: function() {
document.body.classList.add('compat');
},
mounted: function() {
this.srcUrl = this.buildSrcUrl();
},
beforeUnmount: function() {
document.body.classList.remove('compat');
},
watch: {
propsWatchHelper: function() {
if(this.lastLoadediFrameURL === '') {
+19 -30
View File
@@ -1,7 +1,6 @@
import FhcCalendar from "../../Calendar/LvPlan.js";
import ApiLvPlan from '../../../api/factory/lvPlan.js';
import ApiStudienSemester from '../../../api/factory/studiensemester.js';
import ApiAuthinfo from '../../../api/factory/authinfo.js';
export const DEFAULT_MODE_LVPLAN_DESKTOP = "Week";
@@ -17,12 +16,13 @@ export default {
},
data() {
return {
studiensemester_kurzbz: null,
studiensemester_start: null,
studiensemester_ende: null,
uid: null,
isMitarbeiter: false,
isStudent: false,
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
startSemester: null,
endSemester: null,
};
},
inject: ["isMobile"],
@@ -48,12 +48,9 @@ export default {
return this.propsViewData?.mode;
},
downloadLinks() {
const startDate = this.startSemester?.start;
const endDate = this.endSemester ? this.endSemester.ende : this.startSemester?.ende;
if (!startDate || !endDate || !this.uid)
if (!this.studiensemester_start || !this.studiensemester_ende || !this.uid)
return false;
let type = false;
type = this.isStudent ? 'student' : type;
type = this.isMitarbeiter ? 'lektor' : type;
@@ -64,10 +61,10 @@ export default {
const opts = { zone: this.timezone };
const start = luxon.DateTime
.fromISO(startDate, opts)
.fromISO(this.studiensemester_start, opts)
.toUnixInteger();
const ende = luxon.DateTime
.fromISO(endDate, opts)
.fromISO(this.studiensemester_ende, opts)
.toUnixInteger();
const download_link = FHC_JS_DATA_STORAGE_OBJECT.app_root
@@ -112,21 +109,16 @@ export default {
}
});
},
async updateRange(rangeInterval) {
const semesterResponse = await this.$api.call(
ApiStudienSemester.getContainingOrNearestByDateRange(
rangeInterval.s.toISO().slice(0, 10),
rangeInterval.e.toISO().slice(0, 10),
),
);
this.startSemester =
semesterResponse.data.length
? semesterResponse.data[0]
: null;
this.endSemester =
semesterResponse.data.length > 1
? semesterResponse.data[1]
: null;
updateRange(rangeInterval) {
this.$api
.call(ApiLvPlan.studiensemesterDateInterval(
rangeInterval.end.startOf('week').toISODate()
))
.then(res => {
this.studiensemester_kurzbz = res.data.studiensemester_kurzbz;
this.studiensemester_start = res.data.start;
this.studiensemester_ende = res.data.ende;
});
},
getPromiseFunc(start, end) {
return [
@@ -150,11 +142,8 @@ export default {
<div class="cis-lvplan-personal d-flex flex-column h-100">
<h2>
{{ $p.t('lehre/stundenplan') }}
<span v-if="startSemester?.studiensemester_kurzbz">
{{ startSemester.studiensemester_kurzbz }}
<span v-if="endSemester?.studiensemester_kurzbz">
{{ "- " + endSemester.studiensemester_kurzbz }}
</span>
<span v-if="studiensemester_kurzbz" class="ps-3">
{{ studiensemester_kurzbz }}
</span>
</h2>
<hr>
+25 -32
View File
@@ -5,7 +5,6 @@ import FhcCalendar from "../../Calendar/LvPlan.js";
import ApiLvPlan from "../.././../api/factory/lvPlan.js";
import ApiOtherLvPlan from "../.././../api/factory/otherLvPlan.js";
import ApiAuthinfo from "../../../api/factory/authinfo.js";
import ApiStudienSemester from '../../../api/factory/studiensemester.js';
export const DEFAULT_MODE_LVPLAN_DESKTOP = "Week";
export const DEFAULT_MODE_LVPLAN_MOBILE = "List";
@@ -23,6 +22,9 @@ export default {
data() {
return {
localProps: {},
studiensemester_kurzbz: null,
studiensemester_start: null,
studiensemester_ende: null,
isOtherPersonMitarbeiter: false,
isOtherPersonStudent: false,
currentStgBezeichnung: null,
@@ -34,8 +36,6 @@ export default {
photo: "",
},
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone,
startSemester: null,
endSemester: null,
};
},
inject: ["isMobile"],
@@ -67,10 +67,11 @@ export default {
// do not show download links in otherLvPlan Mode
return false;
const startDate = this.startSemester?.start;
const endDate = this.endSemester ? this.endSemester.ende : this.startSemester?.ende;
if (!startDate || !endDate || !this.uid)
if (
!this.studiensemester_start ||
!this.studiensemester_ende ||
!this.propsViewData.otherUid
)
return false;
const type = this.isOtherPersonStudent
@@ -83,11 +84,11 @@ export default {
const opts = { zone: this.timezone };
const start = luxon.DateTime.fromISO(
startDate,
this.studiensemester_start,
opts,
).toUnixInteger();
const ende = luxon.DateTime.fromISO(
endDate,
this.studiensemester_ende,
opts,
).toUnixInteger();
@@ -165,21 +166,19 @@ export default {
},
});
},
async updateRange(rangeInterval) {
const semesterResponse = await this.$api.call(
ApiStudienSemester.getContainingOrNearestByDateRange(
rangeInterval.s.toISO().slice(0, 10),
rangeInterval.e.toISO().slice(0, 10),
),
);
this.startSemester =
semesterResponse.data.length
? semesterResponse.data[0]
: null;
this.endSemester =
semesterResponse.data.length > 1
? semesterResponse.data[1]
: null;
updateRange(rangeInterval) {
this.$api
.call(
ApiLvPlan.studiensemesterDateInterval(
rangeInterval.end.startOf("week").toISODate(),
),
)
.then((res) => {
this.studiensemester_kurzbz =
res.data.studiensemester_kurzbz;
this.studiensemester_start = res.data.start;
this.studiensemester_ende = res.data.ende;
});
},
getPromiseFunc(start, end) {
return [
@@ -251,14 +250,8 @@ export default {
<div class="d-flex flex-column h-100">
<h2>
<div class="d-flex flex-row justify-content-between align-items-center">
<span>
{{ $p.t('lehre/stundenplan') }}
<span v-if="startSemester?.studiensemester_kurzbz">
{{ startSemester.studiensemester_kurzbz }}
<span v-if="endSemester?.studiensemester_kurzbz">
{{ "- " + endSemester.studiensemester_kurzbz }}
</span>
</span>
<span>
{{ $p.t('lehre/stundenplan') + (studiensemester_kurzbz ? " " + studiensemester_kurzbz : "") }}
</span>
<div @click="this.$router.push({name: 'ProfilView', params: {uid: propsViewData.otherUid}})" type="button" class="d-flex flex-row align-items-center gap-3">
<span v-if="otherPersonData.fullNameWithTitle?.length">
+1 -1
View File
@@ -186,7 +186,7 @@ export default {
</div>
</div>
<nav id="nav-main" class="cis-main-menu offcanvas offcanvas-start" tabindex="-1" aria-labelledby="nav-main-btn" data-bs-backdrop="false">
<nav id="nav-main" class="offcanvas offcanvas-start" tabindex="-1" aria-labelledby="nav-main-btn" data-bs-backdrop="false">
<div id="nav-main-sticky">
<div class="d-flex flex-row h-100">
<div class="offcanvas-body p-0">
+1 -5
View File
@@ -162,7 +162,6 @@ export default {
<div class="btn-group w-100">
<a :target="target"
:href="(entry.menu_open && hasFullLink) ? entry.url : null"
draggable="false"
@click="toggleCollapse"
:class="{
'btn btn-default rounded-0 text-start': true,
@@ -181,15 +180,12 @@ export default {
</div>
<ul ref="children"
class="nav w-100 collapse">
<li>
<cis-menu-entry :highestMatchingUrlCount="highestMatchingUrlCount" :activeContent="activeContent" v-for="child in entry.childs" :key="child" :entry="child" :level="level + 1"/>
</li>
<cis-menu-entry :highestMatchingUrlCount="highestMatchingUrlCount" :activeContent="activeContent" v-for="child in entry.childs" :key="child" :entry="child" :level="level + 1"/>
</ul>
</template>
<a v-else
:href="entry.url"
:target="target"
draggable="false"
:class="{
'btn btn-default rounded-0 w-100 text-start': true,
['btn-level-' + level]: true,
@@ -73,7 +73,7 @@ export default {
// check if the lv has lvplan entries for this studiensemester
if (this.studiensemester && this.event) {
return this.$fhcApi.factory.studium.getLvPlanForStudiensemester(this.studiensemester, this.event.lehreinheit_id ?? this.event.lehrveranstaltung_id)
.then(data => data.data?.retval)
.then(data => data.data)
.then(res => {
if (Array.isArray(res) && res.length > 0) {
this.hasLvPlanEintraege = true;
@@ -114,4 +114,4 @@ export default {
`,
};
};
@@ -2,16 +2,15 @@ export default {
props: {
data: {
type: String,
},
}
},
data() {
return {};
return {}
},
template: /*html*/ `
template: /*html*/`
<div class="card">
<div class="card-body">
<span v-if="data">{{$p.t('profil','fhAusweisStatus',[data])}}</span>
<span v-else>{{$p.t('profil','fhAusweisStatusNichtAusgegeben')}}</span>
<span >{{$p.t('profil','fhAusweisStatus',[data])}}</span>
</div>
</div>`,
};
}
@@ -1,6 +1,5 @@
export default {
name: 'Cis-Renderer-Feiertag-CalendarEvent',
props: {
event: {
type: Object,
@@ -1,7 +1,6 @@
import { formatDate } from "../../../../helpers/DateHelpers.js"
export default {
name: 'Cis-Renderer-Feiertag-ModalContent',
props:{
event: {
type: Object,
@@ -1,5 +1,4 @@
export default {
name: 'Cis-Renderer-Feiertag-ModalTitle',
props:{
event: {
type: Object,
@@ -1,5 +1,4 @@
export default {
name: 'Cis-Renderer-Lehreinheit-CalendarEvent',
props:{
event: {
type: Object,
@@ -5,7 +5,6 @@ import ApiLvPlan from '../../../../api/factory/lvPlan.js';
import ApiAddons from '../../../../api/factory/addons.js';
export default {
name: 'Cis-Renderer-Lehreinheit-ModalContent',
components:{
LvMenu,
},
@@ -50,16 +49,6 @@ export default {
return this.event.ende;
}
return numberPadding(this.event.ende.getHours()) + ":" + numberPadding(this.event.ende.getMinutes());
},
showLvMenu: function() {
const hideOnRoutes = [
'OtherLvPlan',
'StgOrgLvPlan'
];
if(hideOnRoutes.includes(this.$route.name)) {
return false;
}
return true;
}
},
watch: {
@@ -173,6 +162,6 @@ export default {
</tr>
</tbody>
</table>
<lv-menu v-if="lvMenu.length && showLvMenu" :containerStyles="['p-0']" :rowStyles="['m-0']" :menu="lvMenu" />
<lv-menu v-if="lvMenu.length && $route.name === 'MyLvPlan'" :containerStyles="['p-0']" :rowStyles="['m-0']" :menu="lvMenu" />
</div>`,
}
@@ -1,5 +1,4 @@
export default {
name: 'Cis-Renderer-Lehreinheit-ModalTitle',
props:{
event: {
type: Object,
@@ -1,5 +1,4 @@
export default {
name: 'Cis-Renderer-Reservierung-CalendarEvent',
props: {
event: {
type: Object,
@@ -2,7 +2,6 @@ import { numberPadding, formatDate } from "../../../../helpers/DateHelpers.js"
import LvMenu from "../../Mylv/LvMenu.js";
export default {
name: 'Cis-Renderer-Reservierung-ModalContent',
props:{
event: {
type: Object,
@@ -1,5 +1,4 @@
export default {
name: 'Cis-Renderer-Reservierung-ModalTitle',
props:{
event: {
type: Object,
+2 -13
View File
@@ -1,6 +1,5 @@
import BsModal from "../Bootstrap/Modal.js";
import HeightTransition from "../Tranistion/HeightTransition.js";
import MissingPermissionWidget from "../DashboardWidget/MissingPermission.js";
import { enableDragDropTouch } from "../../../../vendor/drag-drop-touch-js/dragdroptouch/dist/drag-drop-touch.esm.min.js";
@@ -113,12 +112,6 @@ export default {
isPinned() {
return this.place?.pinned ? true : false;
},
permitted() {
// widgets without a linked permission (or before the template loaded)
// are considered permitted; the backend sets permitted === false only
// when the user is missing the widget's required permission
return this.widgetTemplate?.permitted !== false;
},
ready() {
return this.component && this.arguments !== null;
}
@@ -176,11 +169,7 @@ export default {
&& this.widgetTemplate.widget_id
&& this.widgetTemplate.arguments
) {
// render the "missing permission" screen instead of the actual
// widget when the user does not hold the widget's linked permission
let component = this.permitted
? (await import(this.widgetTemplate.setup.file)).default
: MissingPermissionWidget;
let component = (await import(this.widgetTemplate.setup.file)).default;
this.$options.components["widget" + this.widgetTemplate.widget_id] = component;
this.component = "widget" + this.widgetTemplate.widget_id;
this.arguments = { ...this.widgetTemplate.arguments, ...this.config };
@@ -280,7 +269,7 @@ export default {
</template>
<!-- widget link -->
<a
v-if="widgetTemplate.setup.cis4link && permitted"
v-if="widgetTemplate.setup.cis4link"
:href="getWidgetC4Link(widgetTemplate)"
class="col-auto ms-auto"
:aria-label="$p.t('dashboard/widget_link')"
@@ -14,14 +14,10 @@ export default {
callbacks: {}
}),
computed: {
// filter widgets away the user has no permissions for
availableWidgets() {
return (this.widgets || []).filter(widget => widget.permitted !== false);
},
hasAnyWidgets() {
if (!this.widgets)
return false;
if (!this.availableWidgets.length && !this.hiddenWidgets?.length)
if (!this.widgets.length && !this.hiddenWidgets?.length)
return false;
return true;
}
@@ -58,7 +54,7 @@ export default {
<template v-slot:default>
<template v-if="widgets && hiddenWidgets">
<div
v-if="!availableWidgets.length && !hiddenWidgets.length"
v-if="!widgets.length && !hiddenWidgets.length"
class="row g-2"
>
<div>{{ $p.t('dashboard/noWidgetsAvailable') }}</div>
@@ -78,17 +74,16 @@ export default {
</div>
</div>
<div
v-if="availableWidgets.length"
v-if="widgets.length"
class="row g-2"
>
<template
v-for="widget in availableWidgets"
<div
v-for="widget in widgets"
:key="widget.widget_id"
class="widget-icon-container col-sm-6 col-md-4 col-lg-3 col-xl-2"
>
<div v-if="widget.permitted" class="widget-icon-container col-sm-6 col-md-4 col-lg-3 col-xl-2">
<widget-icon @select="pick" :widget="widget"></widget-icon>
</div>
</template>
<widget-icon @select="pick" :widget="widget"></widget-icon>
</div>
</div>
</template>
</template>
@@ -1,21 +0,0 @@
import AbstractWidget from './Abstract.js';
/**
* Fallback screen rendered in place of a widget when the current user is missing
* the permission (berechtigung_kurzbz) linked to that widget. Used for widgets
* that are already on a user's dashboard but whose required permission the user
* no longer holds.
*/
export default {
mixins: [
AbstractWidget
],
created() {
this.$emit('setConfig', false);
},
template: /*html*/`
<div class="dashboard-widget-missing-permission d-flex flex-column justify-content-center align-items-center text-center h-100 p-3 text-body-secondary">
<i class="fa-solid fa-lock fa-2x mb-2" aria-hidden="true"></i>
<p class="mb-0">{{ $p.t('dashboard/widget_missing_permission') }}</p>
</div>`
}
@@ -0,0 +1,304 @@
import {CoreFilterCmpt} from "../filter/Filter.js";
import {CoreNavigationCmpt} from "../navigation/Navigation.js";
import FormInput from "../Form/Input.js";
import FerienModal from "./Modal.js";
import ApiFerienverwaltung from '../../api/factory/ferienverwaltung/ferienverwaltung.js';
export default {
name: "Ferienverwaltung",
components: {
CoreFilterCmpt,
CoreNavigationCmpt,
FormInput,
FerienModal
},
data() {
return {
filterVonDatum: null,
filterBisDatum: null,
loading: false,
sideMenuEntries: {},
headerMenuEntries: {},
tabulatorOptions: {
ajaxURL: 'dummy',
ajaxRequestFunc: () => this.$api.call(
ApiFerienverwaltung.getFerien(this.filterVonDatum, this.filterBisDatum)
),
ajaxResponse: (url, params, response) => response.data,
columns: [
{title:"Ferien Id", field:"ferien_id", visible: false, headerFilter: true},
{
title:"Datum von",
field:"vondatum",
headerFilter: true,
formatter: function (cell) {
const dateStr = cell.getValue();
if (!dateStr) return "";
const date = new Date(dateStr);
return date.toLocaleString("de-DE", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour12: false
});
}
},
{
title:"Datum bis",
field:"bisdatum",
headerFilter: true,
formatter: function (cell) {
const dateStr = cell.getValue();
if (!dateStr) return "";
const date = new Date(dateStr);
return date.toLocaleString("de-DE", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour12: false
});
}
},
{title:"Bezeichnung", field:"bezeichnung", headerFilter: true},
{title:"Organisationseinheit Kurzbezeichnung", field:"oe_kurzbz", visible: false, headerFilter: true},
{title:"Organisationseinheit", field:"oe_bezeichnung", headerFilter: true},
{title:"Studienplan", field:"studienplan_bezeichnung", visible: false, headerFilter: true},
{title:"Ferientyp Kurzbezeichnung", field:"ferientyp_kurzbz", visible: false, headerFilter: true},
{
title:"Mitarbeiterrelevant",
field:"mitarbeiterrelevant",
visible: false,
headerFilter: true,
hozAlign: "center",
formatter:'tickCross', formatterParams: {
tickElement: '<i class="fas fa-check text-success"></i>',
crossElement: '<i class="fas fa-times text-danger"></i>'
},
headerFilter:"tickCross", headerFilterParams: {
"tristate":true, elementAttributes:{"value":"true"}
},
headerFilterEmptyCheck:function(value){return value === null}
},
{
title:"Studierendenrelevant",
field:"studierendenrelevant",
visible: false,
headerFilter: true,
hozAlign: "center",
formatter:'tickCross', formatterParams: {
tickElement: '<i class="fas fa-check text-success"></i>',
crossElement: '<i class="fas fa-times text-danger"></i>'
},
headerFilter:"tickCross", headerFilterParams: {
"tristate":true, elementAttributes:{"value":"true"}
},
headerFilterEmptyCheck:function(value){return value === null}
},
{
title:"Lehre planbar",
field:"lehre",
visible: false,
headerFilter: true,
hozAlign: "center",
formatter:'tickCross', formatterParams: {
tickElement: '<i class="fas fa-check text-success"></i>',
crossElement: '<i class="fas fa-times text-danger"></i>'
},
headerFilter:"tickCross", headerFilterParams: {
"tristate":true, elementAttributes:{"value":"true"}
},
headerFilterEmptyCheck:function(value){return value === null}
},
{title:"Aktionen", field: "actions",
minWidth: 150, // Ensures Action-buttons will be always fully displayed
formatter: (cell, formatterParams, onRendered) => {
let container = document.createElement('div');
container.className = "d-flex gap-2";
let button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-edit"></i>';
button.title = this.$p.t('person', 'ferien_edit');
button.addEventListener('click', (event) =>
this.$refs.modal.open(JSON.parse(JSON.stringify(cell.getData()))) // deep copy
);
container.append(button);
button = document.createElement('button');
button.className = 'btn btn-outline-secondary';
button.innerHTML = '<i class="fa fa-trash"></i>';
button.addEventListener('click', evt => {
evt.stopPropagation();
this.$fhcAlert
.confirmDelete()
.then(result => result ? cell.getData().ferien_id : Promise.reject({handled:true}))
.then(ferien_id => this.$api.call(ApiFerienverwaltung.delete(ferien_id)))
.then(() => {
//cell.getRow().delete();
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'));
this.reload();
})
.catch(this.$fhcAlert.handleSystemError);
});
container.append(button);
return container;
},
frozen: true
}
]
},
tabulatorEvents: [
{
event: 'tableBuilt',
handler: async () => {
await this.$p.loadCategory(['global', 'ferien']);
const setHeader = (field, text) => {
const col = this.$refs.table.tabulator.getColumn(field);
if (!col) return;
const el = col.getElement();
if (!el || !el.querySelector) return;
const titleEl = el.querySelector('.tabulator-col-title');
if (titleEl) {
titleEl.textContent = text;
}
};
setHeader('ferien_id', this.$p.t('ferien', 'ferienId'));
setHeader('vondatum', this.$p.t('ferien', 'vondatum'));
setHeader('bisdatum', this.$p.t('ferien', 'bisdatum'));
setHeader('bezeichnung', this.$p.t('global', 'bezeichnung'));
setHeader('oe_kurzbz', this.$p.t('ferien', 'oeKurzbezeichnung'));
setHeader('oe_bezeichnung', this.$p.t('ferien', 'oeBezeichnung'));
setHeader('studienplan_bezeichnung', this.$p.t('global', 'studienplanBezeichnung'));
setHeader('ferientyp_kurzbz', this.$p.t('ferien', 'ferientypKurzbz'));
setHeader('mitarbeiterrelevant', this.$p.t('ferien', 'mitarbeiterrelevant'));
setHeader('studierendenrelevant', this.$p.t('ferien', 'studierendenrelevant'));
setHeader('lehre', this.$p.t('ferien', 'lehrePlanbar'));
setHeader('actions', this.$p.t('global', 'aktionen'));
}
}
]
}
},
computed: {
},
methods: {
reload() {
this.$refs.table.reloadTable();
},
actionNew() {
this.$refs.modal.open();
},
importFerien() {
this.$api
.call(ApiFerienverwaltung.importFerien(this.filterVonDatum, this.filterBisDatum))
.then(result => {
this.$fhcAlert.alertSuccess(this.$p.t('ferien', 'importiert') + ": " + result.data);
this.reload();
}
)
.catch(error => {
if (error)
this.$fhcAlert.handleSystemError(error);
});
}
},
created() {
this.$api
.call(ApiFerienverwaltung.getDefaultVonBis())
.then(result => {
this.filterVonDatum = result.data.defaultVon;
this.filterBisDatum = result.data.defaultBis;
}
)
.catch(error => {
if (error)
this.$fhcAlert.handleSystemError(error);
});
},
template: `
<core-navigation-cmpt
v-bind:add-side-menu-entries="sideMenuEntries"
v-bind:add-header-menu-entries="headerMenuEntries"
>
</core-navigation-cmpt>
<div class="h-100 d-flex flex-column">
<div class="row">
<div class="col-4">
<form-input
type="DatePicker"
v-model="filterVonDatum"
name="filtervondatum"
:label="$p.t('ferien/vondatum')"
:enable-time-picker="false"
text-input
format="dd.MM.yyyy"
auto-apply
>
</form-input>
</div>
<div class="col-4">
<form-input
type="DatePicker"
v-model="filterBisDatum"
name="filterbisdatum"
:label="$p.t('ferien/bisdatum')"
:enable-time-picker="false"
text-input
format="dd.MM.yyyy"
auto-apply
>
</form-input>
</div>
<div class="col-2 align-self-end">
<button
class="btn btn-primary"
@click="reload()"
:disabled="loading"
>
<i v-if="loading" class="fa fa-spinner fa-spin"></i>
{{ $p.t('ui/anzeigen') }}
</button>
</div>
<div class="col-2 align-self-end justify-content-end">
<button
class="btn btn-secondary"
@click="importFerien()"
:disabled="loading"
>
<i v-if="loading" class="fa fa-spinner fa-spin"></i>
{{ $p.t('ferien/ferienImportieren') }}
</button>
</div>
</div>
<div class="row mt-3">
<div class="col">
<core-filter-cmpt
ref="table"
table-only
:side-menu="false"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
reload
:reload-btn-infotext="this.$p.t('table', 'reload')"
new-btn-show
:new-btn-label="$p.t('ui/neu')"
@click:new="actionNew"
>
</core-filter-cmpt>
<ferien-modal ref="modal" @saved="reload"></ferien-modal>
</div>
</div>
</div>`
};
@@ -0,0 +1,190 @@
import BsModal from "../Bootstrap/Modal.js";
import BsConfirm from "../Bootstrap/Confirm.js";
import CoreForm from "../Form/Form.js";
import FormValidation from "../Form/Validation.js";
import FormInput from "../Form/Input.js";
import ApiFerien from '../../api/factory/ferienverwaltung/ferienverwaltung.js';
export default {
components: {
BsModal,
CoreForm,
FormValidation,
FormInput
},
data() {
return {
oeList: [],
studienplaeneList: [],
ferientypList: [],
loading: false,
data: {},
};
},
computed: {
},
methods: {
save() {
this.$refs.form.clearValidation();
this.loading = true;
let saveFunc = this.data.ferien_id ? ApiFerien.update : ApiFerien.insert;
this.$refs.form
.call(saveFunc(this.data))
.then(result => {
this.$emit('saved', result.data);
this.loading = false;
this.$refs.modal.hide();
this.$fhcAlert.alertSuccess(this.$p.t('ui/gespeichert'));
})
.catch(error => {
if (error)
this.$fhcAlert.handleSystemError(error);
this.loading = false;
});
},
open(data) {
this.$refs.form.clearValidation();
this.data = data ?? {
oe_kurzbz: null,
bezeichnung: '',
vondatum: null,
bisdatum: null,
studienplan_id: null
};
this.$api
.call(ApiFerien.getOe())
.then(result => {
this.oeList = result.data;
//this.loading = false;
}
)
.catch(error => {
if (error)
this.$fhcAlert.handleSystemError(error);
//this.loading = false;
});
this.getStudienplaene();
this.$api
.call(ApiFerien.getFerientypen())
.then(result => {
this.ferientypList = result.data;
}
)
.catch(error => {
if (error)
this.$fhcAlert.handleSystemError(error);
});
this.$refs.modal.show();
},
getStudienplaene() {
if (!this.data.oe_kurzbz) return;
this.$api
.call(ApiFerien.getStudienplaene(this.data.oe_kurzbz, this.data.vondatum, this.data.bisdatum))
.then(result => {
this.studienplaeneList = result.data;
}
)
.catch(error => {
if (error)
this.$fhcAlert.handleSystemError(error);
});
},
preventCloseOnLoading(ev) {
if (this.loading)
ev.returnValue = false;
}
},
template: `
<core-form ref="form" class="stv-details-ferien-edit" @submit.prevent="save">
<bs-modal ref="modal" @hide-bs-modal="preventCloseOnLoading">
<form-validation></form-validation>
<fieldset :disabled="loading">
<form-input
type="DatePicker"
v-model="data.vondatum"
name="vondatum"
:label="$p.t('ferien/vondatum')"
:enable-time-picker="false"
text-input
format="dd.MM.yyyy"
auto-apply
>
</form-input>
<form-input
type="DatePicker"
v-model="data.bisdatum"
name="bisdatum"
:label="$p.t('ferien/bisdatum')"
:enable-time-picker="false"
text-input
format="dd.MM.yyyy"
auto-apply
>
</form-input>
<form-input
v-model="data.bezeichnung"
name="bezeichnung"
:label="$p.t('global/bezeichnung')"
>
</form-input>
<form-input
type="select"
v-model="data.oe_kurzbz"
name="oe_kurzbz"
:label="$p.t('ferien/organisationseinheit')"
@change="getStudienplaene"
>
<option :value="null">-- {{ $p.t('ui/alle') }} --</option>
<option v-for="oe in oeList" :key="oe.oe_kurzbz" :value="oe.oe_kurzbz">
{{ oe.organisationseinheittyp_kurzbz + ' ' + oe.bezeichnung }}
</option>
</form-input>
<form-input
type="select"
v-model="data.studienplan_id"
name="studienplan_id"
:label="$p.t('ferien/studienplan')"
>
<option :value="null">-- {{ $p.t('ui/keineAuswahl') }} --</option>
<option v-for="studienplan in studienplaeneList" :key="studienplan.studienplan_id" :value="studienplan.studienplan_id">
{{ studienplan.bezeichnung }}
</option>
</form-input>
<form-input
type="select"
v-model="data.ferientyp_kurzbz"
name="ferientyp_kurzbz"
:label="$p.t('ferien/ferientypKurzbz')"
>
<option :value="null">-- {{ $p.t('ui/keineAuswahl') }} --</option>
<option v-for="ferientyp in ferientypList" :key="ferientyp.ferientyp_kurzbz" :value="ferientyp.ferientyp_kurzbz">
{{ ferientyp.ferientyp_kurzbz }}
</option>
</form-input>
</fieldset>
<template #footer>
<button type="submit" class="btn btn-primary" :disabled="loading">
<i v-if="loading" class="fa fa-spinner fa-spin"></i>
{{ $p.t('ui/speichern') }}
</button>
</template>
</bs-modal>
</core-form>`
};
@@ -61,7 +61,6 @@ export default {
selected: [],
studiengang_kz: null,
selectedStudiensemester: this.defaultSemester,
preselected: null,
dropdowns: {
studiensemester_array: [],
sprachen_array: [],
@@ -74,11 +73,7 @@ export default {
calcheightonly: true,
types: [
"mitarbeiter",
"mitarbeiter_ohne_zuordnung",
/*
"lehreinheit",
"lehrveranstaltung",
*/
"mitarbeiter_ohne_zuordnung"
],
actions: {
employee: {
@@ -91,26 +86,6 @@ export default {
childactions: [
]
},
lehreinheit: {
defaultaction: {
type: "function",
action: (data) => {
this.onSelectLehreinheit(data);
}
},
childactions: [
]
},
lehrveranstaltung: {
defaultaction: {
type: "function",
action: (data) => {
this.onSelectLehrveranstaltung(data);
}
},
childactions: [
]
}
}
},
}
@@ -119,8 +94,6 @@ export default {
filter() {
let filter = {
emp: this.$route.params.emp,
le: this.$route.params.le,
lv: this.$route.params.lv,
studiensemester_kurzbz: this.selectedStudiensemester
};
let index;
@@ -132,7 +105,7 @@ export default {
if (index > -1)
filter.semester = this.$route.params.treemenu[index+1];
}
filter.activeFilter = filter.emp ? 'employee' : filter.stg ? 'verband' : filter.le ? 'lehreinheit' : filter.lv ? 'lehrveranstaltung' : null;
filter.activeFilter = filter.emp ? 'employee' : filter.stg ? 'verband' : null;
return filter;
},
emp() {
@@ -230,50 +203,20 @@ export default {
},
onSelectEmployee(emp)
{
let params = { ...this.$route.params }
delete params.le;
delete params.lv;
this.$router.push({
name: 'emp',
params: {
...params,
...this.$route.params,
emp
}
});
},
onSelectLehreinheit(lehreinheit)
{
this.$router.push({
name: 'le',
params: {
le: lehreinheit.id,
stdsem: lehreinheit.studiensemester_kurzbz.toLowerCase()
}
});
},
onSelectLehrveranstaltung(lehrveranstaltung)
{
this.$router.push({
name: 'lv',
params: {
lv: lehrveranstaltung.id,
stdsem: lehrveranstaltung?.studiensemester_kurzbz?.toLowerCase() ?? this.selectedStudiensemester.toLowerCase()
}
});
},
onSelectVerband({ path: link, stg_kz })
{
let params = { ...this.$route.params }
delete params.le;
delete params.lv;
this.$router.push({
name: this.$route.name == 'emp' ? 'emp' : 'treemenu',
params: {
...params,
...this.$route.params,
treemenu: link.split('/')
}
});
@@ -352,7 +295,7 @@ export default {
}
},
created() {
if (this.$route.name !== 'le' && this.$route.name !== 'lv' && !this.$route.params.stdsem) {
if (!this.$route.params.stdsem) {
this.$router.replace({
name: 'stdsem',
params: {
@@ -534,8 +477,7 @@ export default {
<template #top>
<lv-table ref="lvTable"
v-model:selected="selected"
@row-clicked="handleRowClicked"
@select-LV="onSelectLehrveranstaltung"
@row-clicked="handleRowClicked"
:filter="filter"
>
<template #filterzuruecksetzen v-if="filter.activeFilter === 'employee'">
@@ -57,8 +57,7 @@ export default {
},
emits: [
'update:selected',
'row-clicked',
'selectLV',
'row-clicked'
],
watch: {
filter: {
@@ -107,24 +106,8 @@ export default {
{
event: 'dataProcessed',
handler: (data) => {
if (this.$route.params.le)
{
this.$refs.table.tabulator.selectRow(this.$refs.table.tabulator.getRows());
}
else if (this.$route.params.lv)
{
this.$refs.table.tabulator.selectRow(this.$refs.table.tabulator.getRows());
this.allRows = this.getAllRows(this.$refs.table.tabulator.getRows());
this.allRows.forEach(row => {
row.treeExpand()
});
}
else
{
this.reexpandRows()
this.$emit('update:selected', {})
}
this.reexpandRows()
this.$emit('update:selected', {})
}
},
{
@@ -238,35 +221,35 @@ export default {
selectableRows: true,
rowContextMenu: (component, e) => {
if (e.getData()?.lehreinheit_id === undefined || !e.getData()?.lehreinheit_id)
return [];
if (e.getData()?.lehreinheit_id === undefined)
return;
return [
{
label: this.$p.t('lehre', 'lvteilkopieren'),
label: "LV-Teil kopieren",
menu: [
{
label: this.$p.t('lehre', 'alles'),
label: "Alles",
action: (e, row) =>
{
this.copyLehreinheit(row, "alle");
},
},
{
label: this.$p.t('lehre', 'nurlvteil'),
label: "Nur LV-Teil",
action: (e, row) =>
{
this.copyLehreinheit(row, "lvteil");
},
},
{
label: this.$p.t('lehre', 'nurmitgruppen'),
label: "Nur mit Gruppen",
action: (e, row) =>
{
this.copyLehreinheit(row, "gruppen");
},
},
{
label: this.$p.t('lehre', 'nurmitlehrende'),
label: "Nur mit Lehrenden",
action: (e, row) =>
{
this.copyLehreinheit(row, "lektoren");
@@ -275,21 +258,7 @@ export default {
],
},
{
label: this.$p.t('lehre', 'zurlvspringen'),
action: (e, row) => {
this.openLV(row)
},
},
{
label: this.$p.t('lehre', 'lvteillinkkopieren'),
action: (e, row) => {
let rowData = row.getData();
let link = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/LVVerwaltung/stdsem/' + rowData.studiensemester_kurzbz.toLowerCase() + '/le/' + rowData.lehreinheit_id;
navigator.clipboard.writeText(link);
},
},
{
label: this.$p.t('ui', 'entfernen'),
label: "Entfernen",
action: (e, row) => {
this.deleteLehreinheit(row)
},
@@ -386,7 +355,7 @@ export default {
},
buildApiUrl()
{
if (!['emp', 'treemenu', 'le', 'lv'].includes(this.$route.name))
if (!['emp', 'treemenu'].includes(this.$route.name))
return null;
let url = 'stdsem/' + this.$route.params.stdsem;
@@ -395,14 +364,6 @@ export default {
url += '/emp/' + this.$route.params.emp;
}
if (this.$route.params.le) {
url += '/le/' + this.$route.params.le;
}
if (this.$route.params.lv) {
url += '/lv/' + this.$route.params.lv;
}
if (this.$route.params.treemenu) {
url += '/' + this.$route.params.treemenu.join('/');
}
@@ -541,17 +502,6 @@ export default {
})
.catch(this.$fhcAlert.handleSystemError);
},
openLV(row)
{
let rowData = row.getData();
let data = {
id: rowData.lehrveranstaltung_id,
studiensemester_kurzbz: rowData.studiensemester_kurzbz
}
this.$emit('selectLV', data);
},
getAllRows(rows)
{
let result = [];
@@ -263,7 +263,7 @@ export default {
this.$refs[modalRef].hide();
},
reload() {
this.$refs.table?.reloadTable();
this.$refs.table.reloadTable();
},
searchFirma(event) {
if (this.abortController.firmen) {
@@ -30,9 +30,6 @@ export default {
computed: {
betreuerFormOpened() {
return this.newMode || this.editMode;
},
isMitarbeiter(){
return this.autocompleteSelectedBetreuer?.name?.includes('Mitarbeiter') ?? false;
}
},
props: {
@@ -433,11 +430,6 @@ export default {
},
actionKontaktdatenBearbeiten() {
if (!this.autocompleteSelectedBetreuer) return;
if (this.isMitarbeiter)
{
this.$fhcAlert.alertError(this.$p.t('ui', 'editingMitarbeiterPVonly'));
return;
}
this.$refs.kontaktdatenModal.show();
},
// stuff to do after new person has been saved
@@ -502,12 +494,7 @@ export default {
<button class="btn btn-outline-secondary" @click="actionNewPerson">{{ $p.t('projektarbeit', 'neuePersonAnlegen') }}</button>
</div>
<div class="col-6">
<button
class="btn btn-outline-secondary float-end"
@click="actionKontaktdatenBearbeiten"
>
{{ $p.t('projektarbeit', 'kontaktdatenBearbeiten') }}
</button>
<button class="btn btn-outline-secondary float-end" @click="actionKontaktdatenBearbeiten">{{ $p.t('projektarbeit', 'kontaktdatenBearbeiten') }}</button>
</div>
</div>
@@ -618,7 +605,7 @@ export default {
</contact>
</div>
</div>
</bs-modal>
</bs-modal>
`
}
@@ -1,62 +0,0 @@
import TemplateFrame from "./template/frame.js";
export default {
name: 'SearchbarResultTeachingUnit',
components: {
TemplateFrame
},
emits: [ 'actionexecuted' ],
props: {
res: Object,
actions: Object
},
template: `
<template-frame
class="searchbar-result-teachingunit"
:res="res"
:actions="actions"
:title="res.bezeichnung"
:image-fallback="res.foto"
@actionexecuted="$emit('actionexecuted')"
>
<div class="searchbar_table">
<div class="searchbar_tablerow">
<div class="searchbar_tablecell searchbar_label"> {{ res.type === 'lehreinheit' ? $p.t('lehre/lehreinheit') : $p.t('lehre/lehrveranstaltung') }}</div>
<div class="searchbar_tablecell searchbar_value">
{{ res.id }}
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell searchbar_label">{{ $p.t('lehre/studiengang') }}</div>
<div class="searchbar_tablecell searchbar_value">
{{ res.studiengang }}
</div>
</div>
<div class="searchbar_tablerow" v-if="res.oe_bezeichnung">
<div class="searchbar_tablecell searchbar_label">{{ $p.t('lehre/organisationseinheit') }}</div>
<div class="searchbar_tablecell searchbar_value">
{{ res.oe_bezeichnung }}
</div>
</div>
<div class="searchbar_tablerow" v-if="res.studiensemester_kurzbz">
<div class="searchbar_tablecell searchbar_label">{{ $p.t('lehre/studiensemester') }}</div>
<div class="searchbar_tablecell searchbar_value">
{{ res.studiensemester_kurzbz }}
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell searchbar_label">{{ $p.t('lehre/ausbildungssemester') }}</div>
<div class="searchbar_tablecell searchbar_value">
{{ res.semester }}
</div>
</div>
<div class="searchbar_tablerow">
<div class="searchbar_tablecell searchbar_label">{{ $p.t('lehre/lehrform') }}</div>
<div class="searchbar_tablecell searchbar_value">
{{ res.lehrform_kurzbz }}
</div>
</div>
</div>
</template-frame>`
};
@@ -8,7 +8,6 @@ import dms from "./result/dms.js";
import cms from "./result/cms.js";
import mergedStudent from "./result/mergedstudent.js";
import mergedPerson from "./result/mergedperson.js";
import teachingunit from "./result/teachingunit.js";
import { debounce } from "../../helpers/DebounceHelper.js";
export default {
@@ -24,7 +23,6 @@ export default {
cms,
mergedStudent,
mergedPerson,
teachingunit,
},
props: {
searchoptions: {
+2 -2
View File
@@ -103,7 +103,7 @@ require_once('dbupdate_3.4/76160_lvv_favorites.php');
require_once('dbupdate_3.4/77080_tabulator_presets_table.php');
require_once('dbupdate_3.4/78292_gehaltsanpassungtyp.php');
require_once('dbupdate_3.4/54225_reihungstest_ablauf_fuer_quereinsteiger.php');
require_once('dbupdate_3.4/77757_widgets_berechtigungen.php');
require_once('dbupdate_3.4/71405_ferienzeiten.php');
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
echo '<H2>Pruefe Tabellen und Attribute!</H2>';
@@ -266,7 +266,7 @@ $tabellen=array(
"lehre.tbl_anrechnung_begruendung" => array("begruendung_id","bezeichnung"),
"lehre.tbl_anrechnungszeitraum" => array("anrechnungszeitraum_id","studiensemester_kurzbz","anrechnungstart","anrechnungende", "insertamum", "insertvon"),
"lehre.tbl_betreuerart" => array("betreuerart_kurzbz","beschreibung","aktiv"),
"lehre.tbl_ferien" => array("bezeichnung","studiengang_kz","vondatum","bisdatum"),
"lehre.tbl_ferien" => array("ferien_id","bezeichnung","studiengang_kz","vondatum","bisdatum","oe_kurzbz","studienplan_id","ferientyp_kurzbz","insertamum","insertvon","updateamum","updatevon"),
"lehre.tbl_lehreinheit" => array("lehreinheit_id","lehrveranstaltung_id","studiensemester_kurzbz","lehrfach_id","lehrform_kurzbz","stundenblockung","wochenrythmus","start_kw","raumtyp","raumtypalternativ","sprache","lehre","anmerkung","unr","lvnr","updateamum","updatevon","insertamum","insertvon","ext_id","lehrfach_id_old","gewicht"),
"lehre.tbl_lehreinheitgruppe" => array("lehreinheitgruppe_id","lehreinheit_id","studiengang_kz","semester","verband","gruppe","gruppe_kurzbz","updateamum","updatevon","insertamum","insertvon","ext_id"),
"lehre.tbl_lehreinheitmitarbeiter" => array("lehreinheit_id","mitarbeiter_uid","lehrfunktion_kurzbz","semesterstunden","planstunden","stundensatz","faktor","anmerkung","bismelden","updateamum","updatevon","insertamum","insertvon","ext_id","standort_id","vertrag_id"),
+220
View File
@@ -0,0 +1,220 @@
<?php
if (! defined('DB_NAME')) exit('No direct script access allowed');
//Add column ferien_id to lehre.tbl_ferien
if(!@$db->db_query("SELECT ferien_id FROM lehre.tbl_ferien LIMIT 1"))
{
$qry = 'ALTER TABLE lehre.tbl_ferien ADD COLUMN ferien_id integer;';
if(!$db->db_query($qry))
echo '<strong> lehre.tbl_ferien '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_ferien: Neue Spalte ferien_id hinzugefügt';
}
//Column ferien_id mit Werten befüllen
if($result = @$db->db_query("SELECT ferien_id FROM lehre.tbl_ferien where ferien_id is not null LIMIT 1"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = 'UPDATE lehre.tbl_ferien et SET ferien_id =
(SELECT rownumber FROM (SELECT ROW_NUMBER() OVER (ORDER BY bezeichnung, studiengang_kz)
AS rownumber, t.* FROM lehre.tbl_ferien t ORDER BY bezeichnung, studiengang_kz) rn
WHERE rn.bezeichnung = et.bezeichnung
AND rn.studiengang_kz = et.studiengang_kz);
';
if(!$db->db_query($qry))
echo '<strong> lehre.tbl_ferien '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_ferien: Spalte bis.tbl_ferien_id mit Werten aufgefüllt';
}
}
//Create Sequence lehre.tbl_ferien and grant Rights
if ($result = @$db->db_query("SELECT * FROM pg_class WHERE relname = 'tbl_ferien_ferien_id_seq'"))
{
if ($db->db_num_rows($result) == 0)
{
if ($count = @$db->db_query("SELECT * FROM lehre.tbl_ferien"))
{
$count = $db->db_num_rows($count) + 1;
$qry = 'CREATE SEQUENCE lehre.tbl_ferien_ferien_id_seq START ';
$qry .= $count;
if(!$db->db_query($qry))
{
echo '<strong> lehre.tbl_ferien '.$db->db_last_error().'</strong><br>';
}
else
{
echo '<br>lehre.tbl_ferien: Sequence lehre.tbl_ferien_ferien_id_seq mit Startwert ' . $count . ' erstellt';
$qry2 = "GRANT SELECT, UPDATE ON lehre.tbl_ferien_ferien_id_seq TO vilesci;
GRANT SELECT, UPDATE ON lehre.tbl_ferien_ferien_id_seq TO web;";
if(!$db->db_query($qry2))
{
echo '<strong>lehre.tbl_ferien_ferien_id_seq Berechtigungen: '.$db->db_last_error().'</strong><br>';
}
else
{
echo '<br>lehre.tbl_ferien: Rechte auf lehre.tbl_ferien_ferien_id_seq fuer web user und vilesci gesetzt ';
}
}
}
}
}
//lehre.tbl_ferien auf NOT NULL setzen
if ($result = @$db->db_query("SELECT is_nullable FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'tbl_ferien' AND column_name = 'ferien_id' and is_nullable = 'NO'"))
{
if($db->db_num_rows($result)==0)
{
$qry = 'ALTER TABLE lehre.tbl_ferien ALTER COLUMN ferien_id SET NOT NULL';
if(!$db->db_query($qry))
echo '<strong> lehre.tbl_ferien '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_ferien: Spalte bis.tbl_ferien_id auf NOT NULL gesetzt';
}
}
//lehre.tbl_ferien DEFAULT einstellen
if ($result = @$db->db_query("SELECT column_default FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'tbl_ferien' AND column_name = 'ferien_id' and column_default is null"))
{
if($db->db_num_rows($result)==1)
{
$qry = "ALTER TABLE lehre.tbl_ferien ALTER COLUMN ferien_id SET DEFAULT nextval('lehre.tbl_ferien_ferien_id_seq'::regclass);";
if(!$db->db_query($qry))
echo '<strong> lehre.tbl_ferien '.$db->db_last_error().'</strong><br>';
else
echo '<br> lehre.tbl_ferien: Defaultwert bei Spalte bis.tbl_ferien_id gesetzt';
}
}
//DELETE Constraint PRIMARY KEY pk_tbl_ferien (bezeichnung, studiengang_kz) entfernen
if ($result = @$db->db_query("SELECT conname FROM pg_constraint WHERE conname = 'pk_tbl_ferien'"))
{
if($db->db_num_rows($result)==1)
{
$qry = "ALTER TABLE lehre.tbl_ferien DROP CONSTRAINT pk_tbl_ferien;";
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_ferien: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_ferien: Primary Key pk_tbl_ferien (bezeichnung, studiengang_kz) entfernt ';
}
}
// ADD PRIMARY KEY tbl_ferien_pk to lehre.tbl_ferien
if ($result = @$db->db_query("SELECT conname FROM pg_constraint WHERE conname = 'tbl_ferien_pk'"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "ALTER TABLE lehre.tbl_ferien ADD CONSTRAINT tbl_ferien_pk PRIMARY KEY(ferien_id);";
if (!$db->db_query($qry))
echo '<strong>slehre.tbl_ferien: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_ferien: Primary Key tbl_ferien_pk (ferien_id) hinzugefügt';
}
}
// add new fields to tbl_ferien, migrate data (add oe_kurzbz data), mark studiengang_kz as deprecated
if(!$result = @$db->db_query("SELECT oe_kurzbz FROM lehre.tbl_ferien LIMIT 1"))
{
$qry = "ALTER TABLE lehre.tbl_ferien
ADD COLUMN IF NOT EXISTS oe_kurzbz VARCHAR(32),
ADD COLUMN IF NOT EXISTS studienplan_id SMALLINT DEFAULT NULL,
ADD CONSTRAINT tbl_ferien_studienplan_fk
FOREIGN KEY (studienplan_id)
REFERENCES lehre.tbl_studienplan(studienplan_id)
ON UPDATE CASCADE ON DELETE RESTRICT,
ADD CONSTRAINT tbl_ferien_oe_kurzbz_fk
FOREIGN KEY (oe_kurzbz)
REFERENCES public.tbl_organisationseinheit(oe_kurzbz)
ON UPDATE CASCADE ON DELETE RESTRICT,
ADD COLUMN IF NOT EXISTS insertamum timestamp DEFAULT NOW(),
ADD COLUMN IF NOT EXISTS insertvon VARCHAR(32),
ADD COLUMN IF NOT EXISTS updateamum timestamp,
ADD COLUMN IF NOT EXISTS updatevon VARCHAR(32);
UPDATE lehre.tbl_ferien
SET oe_kurzbz = (
SELECT
CASE
WHEN studiengang_kz = 0
THEN NULL
ELSE oe_kurzbz
END
FROM
public.tbl_studiengang
WHERE
studiengang_kz = tbl_ferien.studiengang_kz
)
WHERE oe_kurzbz IS NULL AND studiengang_kz IS NOT NULL;
ALTER TABLE lehre.tbl_ferien ALTER COLUMN studiengang_kz DROP NOT NULL;
COMMENT ON COLUMN lehre.tbl_ferien.studiengang_kz IS 'DEPRECATED';";
if(!$db->db_query($qry))
echo '<strong>lehre.tbl_ferien: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_ferien columns oe_kurzbz, studienplan_id, insertamum, insertvon, updateamum, updatevon hinzugefuegt';
}
// Creates table lehre.tbl_ferientyp if it doesn't exist and grants privileges
if (!$result = @$db->db_query('SELECT 0 FROM lehre.tbl_ferientyp WHERE 0 = 1'))
{
$qry = 'CREATE TABLE lehre.tbl_ferientyp (
ferientyp_kurzbz VARCHAR(64),
beschreibung VARCHAR(256) NOT NULL,
mitarbeiter boolean NOT NULL,
studierende boolean NOT NULL,
lehre boolean NOT NULL
);
COMMENT ON TABLE lehre.tbl_ferientyp IS \'Typ-Tabelle zum Speichern von Informationen zu Ferien.\';
COMMENT ON COLUMN lehre.tbl_ferientyp.ferientyp_kurzbz IS \'Typ der Ferien.\';
COMMENT ON COLUMN lehre.tbl_ferientyp.mitarbeiter IS \'Ob die Ferien für MitarbeiterInnen relevant sind.\';
COMMENT ON COLUMN lehre.tbl_ferientyp.studierende IS \'Ob die Ferien für Studierende relevant sind.\';
COMMENT ON COLUMN lehre.tbl_ferientyp.lehre IS \'Ob Lehre in den Ferien verplant werden kann.\';
ALTER TABLE lehre.tbl_ferientyp ADD CONSTRAINT pk_tbl_ferientyp PRIMARY KEY (ferientyp_kurzbz);
ALTER TABLE lehre.tbl_ferien ADD COLUMN IF NOT EXISTS ferientyp_kurzbz VARCHAR(64) DEFAULT NULL;
ALTER TABLE lehre.tbl_ferien ADD CONSTRAINT tbl_lehre_ferien_ferientyp_kurzbz_fk FOREIGN KEY (ferientyp_kurzbz)
REFERENCES lehre.tbl_ferientyp (ferientyp_kurzbz) MATCH FULL
ON DELETE SET NULL ON UPDATE CASCADE;
INSERT INTO lehre.tbl_ferientyp (ferientyp_kurzbz, beschreibung, mitarbeiter, studierende, lehre)
VALUES(\'Feiertag\', \'Gesetzliche und andere Feiertage\', true, true, false);
INSERT INTO lehre.tbl_ferientyp (ferientyp_kurzbz, beschreibung, mitarbeiter, studierende, lehre)
VALUES(\'Ferien\', \'Ferientage\', true, true, false);
INSERT INTO lehre.tbl_ferientyp (ferientyp_kurzbz, beschreibung, mitarbeiter, studierende, lehre)
VALUES(\'Info\', \'Weitere Zeiten für Ereignisse, z.B. Sportwoche, Ausgleichswoche... \', true, true, false);
';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_ferientyp: '.$db->db_last_error().'</strong><br>';
else
echo '<br>lehre.tbl_ferientyp table created';
$qry = 'GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE lehre.tbl_ferientyp TO vilesci;';
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_ferientyp: '.$db->db_last_error().'</strong><br>';
else
echo '<br>Granted privileges to <strong>vilesci</strong> on lehre.tbl_ferientyp';
}
// Add UNIQUE constraint on fehlercode and fehler_kurzbz on system.tbl_fehler
if ($result = @$db->db_query("SELECT conname FROM pg_constraint WHERE conname = 'uk_tbl_ferien_vondatum_bisdatum_oe_bezeichnung'"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "ALTER TABLE lehre.tbl_ferien ADD CONSTRAINT uk_tbl_ferien_vondatum_bisdatum_oe_bezeichnung UNIQUE (vondatum, bisdatum, oe_kurzbz, bezeichnung);";
if (!$db->db_query($qry))
echo '<strong>lehre.tbl_ferien '.$db->db_last_error().'</strong><br>';
else
echo '<br>added UNIQUE constraint on "vondatum", "bisdatum" and "bezeichnung" for lehre.tbl_ferien<br>';
}
}
@@ -1,57 +0,0 @@
<?php
/* Copyright (C) 2026 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Beschreibung:
* Dashboard Widgets: Verknüpfung einer (einzelnen) Berechtigung pro Widget.
* Neue Spalte dashboard.tbl_widget.berechtigung_kurzbz mit FK auf
* system.tbl_berechtigung. Ist die Spalte NULL, erfordert das Widget keine
* gesonderte Berechtigung. Benutzer denen die verknüpfte Berechtigung fehlt,
* bekommen das Widget nicht mehr zur Auswahl angezeigt bzw. sehen (falls bereits
* am Dashboard) einen "Fehlende Berechtigung"-Screen.
*/
if (! defined('DB_NAME')) exit('No direct script access allowed');
// Add column dashboard.tbl_widget.berechtigung_kurzbz (FK => system.tbl_berechtigung)
if ($result = @$db->db_query("
SELECT 1
FROM information_schema.columns
WHERE table_schema = 'dashboard'
AND table_name = 'tbl_widget'
AND column_name = 'berechtigung_kurzbz';"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "
ALTER TABLE dashboard.tbl_widget
ADD COLUMN berechtigung_kurzbz VARCHAR(32) NULL;
ALTER TABLE dashboard.tbl_widget
ADD CONSTRAINT tbl_widget_berechtigung_fk
FOREIGN KEY (berechtigung_kurzbz)
REFERENCES system.tbl_berechtigung (berechtigung_kurzbz)
ON UPDATE CASCADE ON DELETE SET NULL;";
if (!$db->db_query($qry))
{
echo '<strong>dashboard.tbl_widget: '.$db->db_last_error().'</strong><br>';
}
else
{
echo 'dashboard.tbl_widget: Spalte berechtigung_kurzbz (FK system.tbl_berechtigung) hinzugefuegt<br>';
}
}
}
+367 -185
View File
@@ -29443,26 +29443,6 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'profil',
'phrase' => 'fhAusweisStatusNichtAusgegeben',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Der FH Ausweis wurde noch nicht ausgegeben.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'The FH ID card has not been issued yet.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'profil',
@@ -49620,26 +49600,6 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'dashboard',
'phrase' => 'widget_missing_permission',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Ihnen fehlt die erforderliche Berechtigung, um dieses Widget anzuzeigen.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'You do not have the permission required to display this widget.',
'description' => '',
'insertvon' => 'system'
)
)
),
// CIS4 phrases from legacy code end
// FHC4 Phrases Abschlusspruefung
array(
@@ -53372,146 +53332,6 @@ and represent the current state of research on the topic. The prescribed citatio
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'lvteilkopieren',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'LV-Teil kopieren',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Copy teaching unit',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'nurlvteil',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nur LV-Teil',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Teaching unit only',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'nurmitgruppen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nur mit Gruppen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'With groups only',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'nurmitlehrende',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nur mit Lehrenden',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'With lecturers only',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'zurlvspringen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Zur LV Springen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Go to teaching unit',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'lvteillinkkopieren',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Link zu diesem LV-Teil kopieren',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Copy link to this teaching unit',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'alles',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Alles',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Everything',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
@@ -61477,7 +61297,7 @@ I have been informed that I am under no obligation to consent to the transmissio
'insertvon' => 'system'
)
)
),
),
array(
'app' => 'core',
'category' => 'tabulator',
@@ -62753,26 +62573,388 @@ I have been informed that I am under no obligation to consent to the transmissio
)
),
// ### Infocenter Onboarding END
// ### Ferien START
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'editingMitarbeiterPVonly',
'category' => 'ferien',
'phrase' => 'ferienId',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Kontaktdaten von Mitarbeiter*innen dürfen nur in der Personalverwaltung editiert werden.',
'text' => 'Ferien Id',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Employee contact details may only be edited in the personnel administration system.',
'text' => 'Holiday Id',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'vondatum',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Datum von',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'From date',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'bisdatum',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Datum bis',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'To date',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'organisationseinheit',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Organisationseinheit",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "Organisational unit",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'oeKurzbezeichnung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => "Organisationseinheit Kurzbezeichung",
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => "Organisational unit short name",
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'oeBezeichnung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Organisationseinheit Bezeichnung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Organizational unit name',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'studienplan',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Studienplan',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Study plan',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'studienplanBezeichnung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Studienplan Bezeichnung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Study plan name',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'ferientypKurzbz',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Ferientyp Bezeichnung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Holiday type name',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'mitarbeiterrelevant',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Mitarbeiterrelevant',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Employee relevant',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'studierendenrelevant',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Studierendenrelevant',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Student relevant',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'lehrePlanbar',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lehre planbar',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Classes assignable',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'ferien_edit',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'edit holidays',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Ferien bearbeiten',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'keineAuswahl',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'keine Auswahl',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'no selection',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'csvNichtGelesen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'CSV nicht gelesen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'CSV could not be read',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'fehlerBeimLaden',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Fehler beim Laden',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Error when loading',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'fehlerBeimHinzufuegen',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Fehler beim Hinzufügen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Error when adding',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'ferienImportieren',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Ferientage importieren',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Import holidays',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ferien',
'phrase' => 'importiert',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Importiert',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Imported',
'description' => '',
'insertvon' => 'system'
)
)
)
// ### Ferien END
);
@@ -1,9 +1,9 @@
INSERT INTO lehre.tbl_projektarbeit
(projektarbeit_id, projekttyp_kurzbz, titel, lehreinheit_id, student_uid, firma_id, note, punkte, beginn, ende, faktor, freigegeben, gesperrtbis, stundensatz, themenbereich, anmerkung, updateamum, updatevon, insertamum, insertvon, ext_id, gesamtstunden, titel_english, sprache, seitenanzahl, abgabedatum, kontrollschlagwoerter, schlagwoerter, schlagwoerter_en, abstract, abstract_en, "final", lehrveranstaltung_id, studiensemester_kurzbz) VALUES
(1, 'Bachelor', 'Auswirkung der Sonneneinstrahlung auf die Gesundheit', 46111, 's46b413', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, 4611, NearestWintersemester(1)),
(2, 'Bachelor', 'Neue Unterrichtsmethoden mit KI', 46111, 's46b414', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, 4611, NearestWintersemester(1)),
(3, 'Bachelor', 'Betrugsbekämpfung bei Anwesenheitskontrolle', 46111, 's46b415', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, 4611, NearestWintersemester(1)),
(4, 'Bachelor', 'Neuronale Netze', 46111, 's46b416', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true, 4611, NearestWintersemester(1))
(projektarbeit_id, projekttyp_kurzbz, titel, lehreinheit_id, student_uid, firma_id, note, punkte, beginn, ende, faktor, freigegeben, gesperrtbis, stundensatz, themenbereich, anmerkung, updateamum, updatevon, insertamum, insertvon, ext_id, gesamtstunden, titel_english, sprache, seitenanzahl, abgabedatum, kontrollschlagwoerter, schlagwoerter, schlagwoerter_en, abstract, abstract_en, "final") VALUES
(1, 'Bachelor', 'Auswirkung der Sonneneinstrahlung auf die Gesundheit', 46111, 's46b413', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true),
(2, 'Bachelor', 'Neue Unterrichtsmethoden mit KI', 46111, 's46b414', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true),
(3, 'Bachelor', 'Betrugsbekämpfung bei Anwesenheitskontrolle', 46111, 's46b415', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true),
(4, 'Bachelor', 'Neuronale Netze', 46111, 's46b416', NULL, NULL, NULL, NULL, NULL, NULL, true, NULL, NULL, NULL, NULL, NULL, NULL, '2025-12-12 14:06:10.000', 'anondata', NULL, 3.0000, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, true)
;
INSERT INTO lehre.tbl_projektbetreuer
+5 -3
View File
@@ -125,11 +125,13 @@
}
else
{
$sql_query="INSERT INTO lehre.tbl_ferien (studiengang_kz, bezeichnung, vondatum, bisdatum) VALUES(
$sql_query="INSERT INTO lehre.tbl_ferien (studiengang_kz, bezeichnung, vondatum, bisdatum, oe_kurzbz) VALUES(
".$db->db_add_param($_POST['studiengang_kz'], FHC_INTEGER).",
".$db->db_add_param($_POST['bezeichnung']).",
".$db->db_add_param($datum_obj->formatDatum($_POST['vondatum'],'Y-m-d')).",
".$db->db_add_param($datum_obj->formatDatum($_POST['bisdatum'],'Y-m-d')).");";
".$db->db_add_param($datum_obj->formatDatum($_POST['bisdatum'],'Y-m-d')).",
CASE WHEN ".$db->db_add_param($_POST['studiengang_kz'], FHC_INTEGER)." = 0 THEN NULL
ELSE (SELECT oe_kurzbz FROM public.tbl_studiengang WHERE studiengang_kz = ".$db->db_add_param($_POST['studiengang_kz'], FHC_INTEGER).") END);";
//echo $sql_query;
$db->db_query($sql_query);
$stg_kz = $_POST['studiengang_kz'];
@@ -251,7 +253,7 @@
{
echo '
<tr>
<td>'.$db->convert_html_chars($stg_arr[$row->studiengang_kz]).'</td>
<td>'.$db->convert_html_chars($stg_arr[$row->studiengang_kz] ?? '').'</td>
<td>'.$db->convert_html_chars($row->vondatum).'</td>
<td>'.$db->convert_html_chars($row->bisdatum).'</td>
<td>'.$db->convert_html_chars($row->bezeichnung).'</td>';