Merge branch 'master' into feature-71405/Ferienzeiten

This commit is contained in:
Alexei Karpenko
2026-05-05 15:24:43 +02:00
97 changed files with 10001 additions and 1535 deletions
+8 -1
View File
@@ -208,7 +208,14 @@ $config['navigation_header'] = array(
'expand' => true, 'expand' => true,
'sort' => 30, 'sort' => 30,
'requiredPermissions' => 'lehre/anrechnungszeitfenster:rw' 'requiredPermissions' => 'lehre/anrechnungszeitfenster:rw'
) ),
'dashboardadmin' => array(
'link' => site_url('dashboard/Admin'),
'description' => 'Dashboard Admin',
'expand' => true,
'sort' => 40,
'requiredPermissions' => 'dashboard/admin:r'
)
) )
) )
) )
@@ -512,9 +512,10 @@ class Abgabe extends FHCAPI_Controller
}; };
$projektarbeiten_ids = array_map($mapFunc, $projektarbeiten->retval); $projektarbeiten_ids = array_map($mapFunc, $projektarbeiten->retval);
$ret = $this->ProjektarbeitModel->getProjektarbeitenAbgabetermine($projektarbeiten_ids); if(count($projektarbeiten_ids) > 0) {
$projektabgaben = $this->getDataOrTerminateWithError($ret, 'general'); $ret = $this->ProjektarbeitModel->getProjektarbeitenAbgabetermine($projektarbeiten_ids);
$projektabgaben = $this->getDataOrTerminateWithError($ret, 'general');
}
forEach($projektarbeiten->retval as $pa) { forEach($projektarbeiten->retval as $pa) {
@@ -846,9 +847,10 @@ class Abgabe extends FHCAPI_Controller
private function getProjektbetreuerEmailByProjektarbeitID($projektarbeit_id) { private function getProjektbetreuerEmailByProjektarbeitID($projektarbeit_id) {
$this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel'); $this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel');
$result = $this->ProjektarbeitModel->getProjektbetreuerEmail($projektarbeit_id); $result = $this->ProjektarbeitModel->getProjektbetreuerEmail($projektarbeit_id);
$email = $this->getDataOrTerminateWithError($result, 'general'); if(count($result->retval) > 0) {
$email = getData($result);
return $email[0]->uid ? $email[0]->uid.'@'.DOMAIN : $email[0]->private_email; return $email[0]->uid ? $email[0]->uid.'@'.DOMAIN : $email[0]->private_email;
} else return '';
} }
@@ -208,7 +208,6 @@ class Documents extends FHCAPI_Controller
$this->load->model('system/Vorlage_model', 'VorlageModel'); $this->load->model('system/Vorlage_model', 'VorlageModel');
$result = $this->VorlageModel->load($xsl); $result = $this->VorlageModel->load($xsl);
$this->addMeta("ress", $result);
$vorlage = current($this->getDataOrTerminateWithError($result)); $vorlage = current($this->getDataOrTerminateWithError($result));
if (!$vorlage) if (!$vorlage)
show_404(); show_404();
@@ -221,7 +220,7 @@ class Documents extends FHCAPI_Controller
'gedruckt' => true, 'gedruckt' => true,
'insertamum' => date('c'), 'insertamum' => date('c'),
'insertvon' => getAuthUID(), 'insertvon' => getAuthUID(),
'uid' => $this->input->post_get('uid') ?: '', 'uid' => $this->input->post_get('uid') ?: null,
'archiv' => true, 'archiv' => true,
'signiert' => !!$sign_user, 'signiert' => !!$sign_user,
'stud_selfservice' => $vorlage->stud_selfservice 'stud_selfservice' => $vorlage->stud_selfservice
@@ -251,6 +250,9 @@ class Documents extends FHCAPI_Controller
'studiensemester_kurzbz' => $ss, 'studiensemester_kurzbz' => $ss,
'student_uid' => $akteData['uid'] 'student_uid' => $akteData['uid']
]); ]);
if (!hasData($result)) $this->terminateWithError($this->p->t("stv", "error_noLehrverbandAssigned"));
$res = current($this->getDataOrTerminateWithError($result)); $res = current($this->getDataOrTerminateWithError($result));
$studiengang_kz = $res->studiengang_kz; $studiengang_kz = $res->studiengang_kz;
@@ -332,6 +334,7 @@ class Documents extends FHCAPI_Controller
if ($prestudent_id) { if ($prestudent_id) {
$this->load->model('crm/prestudent_model', 'PrestudentModel'); $this->load->model('crm/prestudent_model', 'PrestudentModel');
$this->PrestudentModel->addJoin('public.tbl_studiengang', 'studiengang_kz', 'LEFT'); $this->PrestudentModel->addJoin('public.tbl_studiengang', 'studiengang_kz', 'LEFT');
$this->PrestudentModel->addSelect('tbl_prestudent.*, UPPER(typ || kurzbz) AS kuerzel');
$result = $this->PrestudentModel->load($prestudent_id); $result = $this->PrestudentModel->load($prestudent_id);
$prestudent = current($this->getDataOrTerminateWithError($result)); $prestudent = current($this->getDataOrTerminateWithError($result));
@@ -0,0 +1,121 @@
<?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 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');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about addresses
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Board extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'list' => 'dashboard/admin:r',
'create' => 'dashboard/admin:rw',
'update' => 'dashboard/admin:rw',
'delete' => 'dashboard/admin:rw'
]);
// Models
$this->load->model('dashboard/Dashboard_model', 'DashboardModel');
}
public function list()
{
$result = $this->DashboardModel->load();
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($result);
}
public function create()
{
$dashboard_kurzbz = $this->input->post('dashboard_kurzbz');
$result = $this->DashboardModel->insert([
'dashboard_kurzbz' => $dashboard_kurzbz
]);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function update()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard_id', 'Dashboard ID', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$dashboard_id = $this->input->post('dashboard_id');
$dashboard_kurzbz = $this->input->post('dashboard_kurzbz');
$beschreibung = $this->input->post('beschreibung');
$result = $this->DashboardModel->update([
'dashboard_id' => $dashboard_id
], [
'dashboard_kurzbz' => $dashboard_kurzbz,
'beschreibung' => $beschreibung
]);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($result);
}
public function delete()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard_id', 'Dashboard ID', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$dashboard_id = $this->input->post('dashboard_id');
//delete all presets
$this->load->model('dashboard/Dashboard_Preset_model', 'DashboardPresetModel');
$result = $this->DashboardPresetModel->delete([
'dashboard_id' => $dashboard_id
]);
$this->getDataOrTerminateWithError($result);
//delete all widgets
$this->load->model('dashboard/Dashboard_Widget_model', 'DashboardWidgetModel');
$result = $this->DashboardWidgetModel->delete([
'dashboard_id' => $dashboard_id
]);
$this->getDataOrTerminateWithError($result);
$result = $this->DashboardModel->delete($dashboard_id);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($result);
}
}
@@ -0,0 +1,200 @@
<?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 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');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about addresses
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Preset extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'list' => 'dashboard/admin:r',
'getBatch' => 'dashboard/admin:r',
'addWidget' => 'dashboard/admin:rw',
'removeWidget' => 'dashboard/admin:rw'
]);
// Load language phrases
$this->loadPhrases([
'ui'
]);
// Libraries
$this->load->library('dashboard/DashboardLib');
// Models
$this->load->model('ressource/Funktion_model', 'FunktionModel');
}
public function list($dashboard_kurzbz)
{
$sql = "
WITH
dashboard_presets AS (
SELECT
*
FROM
dashboard.tbl_dashboard_preset dp
JOIN
dashboard.tbl_dashboard d ON d.dashboard_id = dp.dashboard_id
WHERE
d.dashboard_kurzbz = {$this->db->escape($dashboard_kurzbz)}
),
general AS (
SELECT
'general' AS funktion_kurzbz,
'Allgemein' AS beschreibung
)
(
SELECT
f.funktion_kurzbz,
f.beschreibung,
COUNT(p.preset_id) AS has_preset
FROM
general f
LEFT JOIN
dashboard_presets p ON p.funktion_kurzbz IS NULL
GROUP BY
f.funktion_kurzbz, f.beschreibung
)
UNION ALL
(
SELECT
f.funktion_kurzbz,
f.beschreibung,
COUNT(p.preset_id) AS has_preset
FROM
public.tbl_funktion f
LEFT JOIN
dashboard_presets p ON p.funktion_kurzbz = f.funktion_kurzbz
GROUP BY
f.funktion_kurzbz, f.beschreibung
ORDER BY
f.beschreibung ASC
)
";
$result = $this->FunktionModel->execReadOnlyQuery($sql);
$funktionen = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($funktionen);
}
public function getBatch()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('db', 'Dashboard', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$db = $this->input->post('db');
$funktionen = $this->input->post('funktionen') ?: [];
$result = [];
foreach ($funktionen as $funktion) {
$conf = $this->dashboardlib->getPreset($db, $funktion);
if ($conf) {
$preset = json_decode($conf->preset, true);
if (!isset($preset[$funktion]) || !isset($preset[$funktion]['widgets']))
$result[$funktion] = [];
else
$result[$funktion] = $preset[$funktion]['widgets'];
} else {
$result[$funktion] = [];
}
}
return $this->terminateWithSuccess($result);
}
public function addWidget()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard', 'Dashboard', 'required');
$this->form_validation->set_rules('funktion_kurzbz', 'Funktion', 'required');
$this->form_validation->set_rules('widget[widget]', 'Widget', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$dashboard_kurzbz = $this->input->post('dashboard');
$funktion_kurzbz = $this->input->post('funktion_kurzbz');
$widget = $this->input->post('widget');
if (!isset($widget['widgetid']))
$widget['widgetid'] = $this->dashboardlib->generateWidgetId($dashboard_kurzbz);
$preset = $this->dashboardlib->getPresetOrCreateEmptyPreset($dashboard_kurzbz, $funktion_kurzbz);
$preset_decoded = json_decode($preset->preset, true);
$this->dashboardlib->addWidgetsToWidgets($preset_decoded, $dashboard_kurzbz, $funktion_kurzbz, [$widget]);
$preset->preset = json_encode($preset_decoded);
$result = $this->dashboardlib->insertOrUpdatePreset($preset);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($widget['widgetid']);
}
public function removeWidget()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('db', 'Dashboard', 'required');
$this->form_validation->set_rules('funktion_kurzbz', 'Funktion', 'required');
$this->form_validation->set_rules('widgetid', 'Widget', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$dashboard_kurzbz = $this->input->post('db');
$funktion_kurzbz = $this->input->post('funktion_kurzbz');
$widgetid = $this->input->post('widgetid');
$preset = $this->dashboardlib->getPreset($dashboard_kurzbz, $funktion_kurzbz);
if (!$preset)
show_404();
$preset_decoded = json_decode($preset->preset, true);
if (!$this->dashboardlib->removeWidgetFromWidgets($preset_decoded, $funktion_kurzbz, $widgetid))
show_404();
$preset->preset = json_encode($preset_decoded);
$result = $this->dashboardlib->insertOrUpdatePreset($preset);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess(array('msg' => $this->p->t('dashboard', 'success_savePreset')));
}
}
@@ -0,0 +1,159 @@
<?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 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');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about the users dashboard
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class User extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'get' => 'dashboard/benutzer:r',
'addWidget' => 'dashboard/benutzer:rw',
'removeWidget' => 'dashboard/benutzer:rw'
]);
// Libraries
$this->load->library('dashboard/DashboardLib');
// Models
$this->load->model('ressource/Funktion_model', 'FunktionModel');
}
public function get($dashboard_kurzbz)
{
$dashboard = $this->dashboardlib->getDashboardByKurzbz($dashboard_kurzbz);
if (!$dashboard)
show_404();
$uid = $this->authlib->getAuthObj()->username;
/*$mergedconfig = $this->dashboardlib->getMergedConfig($dashboard->dashboard_id, $uid);
$this->terminateWithSuccess([
'general' => call_user_func_array(
'array_merge_recursive',
$mergedconfig
)
]);*/
$defaultconfig = $this->dashboardlib->getDefaultConfig($dashboard->dashboard_id);
$userconfig = $this->dashboardlib->getUserConfig($dashboard->dashboard_id, $uid);
$defaultconfig_squashed = $defaultconfig ? call_user_func_array('array_replace_recursive', $defaultconfig) : [];
$userconfig_squashed = $userconfig ? call_user_func_array('array_replace_recursive', $userconfig) : [];
$mergedconfig = array_replace_recursive($defaultconfig_squashed, $userconfig_squashed);
$this->terminateWithSuccess([
DashboardLib::SECTION_IF_FUNKTION_KURZBZ_IS_NULL => $mergedconfig
]);
}
public function addWidget()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard', 'Dashboard', 'required');
$this->form_validation->set_rules('widget[widget]', 'Widget', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$widget = $this->input->post('widget');
$dashboard_kurzbz = $this->input->post('dashboard');
$uid = $this->authlib->getAuthObj()->username;
if (!isset($widget['widgetid']))
$widget['widgetid'] = $this->dashboardlib->generateWidgetId($dashboard_kurzbz);
$override = $this->dashboardlib->getOverrideOrCreateEmptyOverride($dashboard_kurzbz, $uid);
$override_decoded = json_decode($override->override, true);
if (!isset($override_decoded['general']) || !is_array($override_decoded['general']))
$override_decoded['general'] = [];
if (!isset($override_decoded['general']['widgets']))
$override_decoded['general']['widgets'] = [];
$override_decoded['general']['widgets'][$widget['widgetid']] = $widget;
// NOTE(chris): remove doubles in other funktionen
foreach ($override_decoded as $funktion => $array) {
if ($funktion == 'general')
continue;
if (isset($array['widgets']) && isset($array['widgets'][$widget['widgetid']]))
unset($override_decoded[$funktion]['widgets'][$widget['widgetid']]);
}
$override->override = json_encode($override_decoded);
$result = $this->dashboardlib->insertOrUpdateOverride($override);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($widget['widgetid']);
}
public function removeWidget()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard', 'Dashboard', 'required');
$this->form_validation->set_rules('widget', 'Widget', 'required');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$widget_id = $this->input->post('widget');
$dashboard_kurzbz = $this->input->post('dashboard');
$uid = $this->authlib->getAuthObj()->username;
$override = $this->dashboardlib->getOverride($dashboard_kurzbz, $uid);
if (!$override)
show_404();
$override_decoded = json_decode($override->override, true);
foreach (array_keys($override_decoded) as $k) {
if (!isset($override_decoded[$k]["widgets"])) {
unset($override_decoded[$k]);
continue;
}
if (isset($override_decoded[$k]["widgets"][$widget_id])) {
unset($override_decoded[$k]["widgets"][$widget_id]);
}
if (!$override_decoded[$k]["widgets"]) {
unset($override_decoded[$k]);
}
}
$override->override = json_encode($override_decoded);
$result = $this->dashboardlib->insertOrUpdateOverride($override);
$this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess();
}
}
@@ -0,0 +1,137 @@
<?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 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');
/**
* This controller operates between (interface) the JS (GUI) and the back-end
* Provides data to the ajax get calls about the users dashboard
* This controller works with JSON calls on the HTTP GET or POST and the output is always JSON
*/
class Widget extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'get' => ['dashboard/benutzer:r', 'dashboard/admin:r'],
'list' => 'dashboard/admin:r',
'listAllowed' => ['dashboard/benutzer:rw', 'dashboard/admin:r'],
'setAllowed' => 'dashboard/admin:rw'
]);
// Libraries
$this->load->library('dashboard/DashboardLib');
// Models
$this->load->model('dashboard/Widget_model', 'WidgetModel');
}
public function get($id)
{
$result = $this->WidgetModel->load($id);
$widget = $this->getDataOrTerminateWithError($result);
if (!$widget)
return $this->terminateWithSuccess([
"widget_id" => 0,
"widget_kurzbz" => "notfound",
"arguments" => [
"className" => 'alert-danger',
"title" => 'Widget Not Found',
"msg" => 'The widget with the id ' . $id . ' could not be found'
],
"setup" => [
"name" => 'Widget Not Found',
"file" => absoluteJsImportUrl('public/js/components/DashboardWidget/Default.js'),
"width" => 1,
"height" => 1
]
]);
$widget = current($widget);
$widget->arguments = json_decode($widget->arguments);
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
$this->terminateWithSuccess($widget);
}
public function list($dashboard)
{
$result = $this->WidgetModel->getWithAllowedForDashboard($dashboard);
$widgets = $this->getDataOrTerminateWithError($result);
$widgets = array_map(function ($widget) {
$widget->arguments = json_decode($widget->arguments);
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
return $widget;
}, $widgets);
$this->terminateWithSuccess($widgets);
}
public function listAllowed($dashboard)
{
$result = $this->WidgetModel->getForDashboard($dashboard);
$widgets = $this->getDataOrTerminateWithError($result);
$widgets = array_map(function ($widget) {
$widget->arguments = json_decode($widget->arguments);
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
return $widget;
}, $widgets);
$this->terminateWithSuccess($widgets);
}
public function setAllowed()
{
$this->load->library('form_validation');
$this->form_validation->set_rules('dashboard_id', 'Dashboard', 'required');
$this->form_validation->set_rules('widget_id', 'Widget', 'required');
$this->form_validation->set_rules('allowed', 'Allowed', 'is_bool');
if (!$this->form_validation->run())
$this->terminateWithValidationErrors($this->form_validation->error_array());
$data = [
'dashboard_id' => $this->input->post('dashboard_id'),
'widget_id' => $this->input->post('widget_id')
];
$this->load->model('dashboard/Dashboard_Widget_model', 'DashboardWidgetModel');
if ($this->input->post('allowed'))
$result = $this->DashboardWidgetModel->insert($data);
else
$result = $this->DashboardWidgetModel->delete($data);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
}
@@ -42,14 +42,22 @@ class Messages extends FHCAPI_Controller
]); ]);
} }
public function getMessages($id, $type_id, $size, $page) public function getMessages($id, $type_id, $size=null, $page=null)
{ {
if($type_id != 'person_id'){ if($type_id != 'person_id'){
$id = $this->_getPersonId($id, $type_id); $id = $this->_getPersonId($id, $type_id);
} }
$offset = $size * ($page - 1); if(!(is_null($size) && is_null($page)))
$limit = $size; {
$offset = $size * ($page - 1);
$limit = $size;
}
else
{
$offset = null;
$limit = null;
}
$result = $this->MessageModel->getMessagesForTable($id, $offset, $limit); $result = $this->MessageModel->getMessagesForTable($id, $offset, $limit);
@@ -24,6 +24,7 @@ class NotizPerson extends Notiz_Controller
//Load Models //Load Models
$this->load->model('person/Benutzer_model', 'BenutzerModel'); $this->load->model('person/Benutzer_model', 'BenutzerModel');
$this->load->model('crm/Student_model', 'StudentModel'); $this->load->model('crm/Student_model', 'StudentModel');
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
//Permission checks for allowed Oes //Permission checks for allowed Oes
if ($this->router->method == 'addNewNotiz') if ($this->router->method == 'addNewNotiz')
@@ -38,7 +39,7 @@ class NotizPerson extends Notiz_Controller
{ {
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Person ID']), self::ERROR_TYPE_GENERAL); return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Person ID']), self::ERROR_TYPE_GENERAL);
} }
$this->_checkIfBerechtigungForOneUidExists($person_id, $allowedStgs); $this->_checkIfBerechtigungForOnePrestudentExists($person_id, $allowedStgs);
} }
if ( $this->router->method == 'updateNotiz') if ( $this->router->method == 'updateNotiz')
@@ -59,7 +60,7 @@ class NotizPerson extends Notiz_Controller
$person_id = current($data)->person_id; $person_id = current($data)->person_id;
$allowedStgs = $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []; $allowedStgs = $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: [];
$this->_checkIfBerechtigungForOneUidExists($person_id, $allowedStgs); $this->_checkIfBerechtigungForOnePrestudentExists($person_id, $allowedStgs);
} }
if ($this->router->method == 'deleteNotiz' ) if ($this->router->method == 'deleteNotiz' )
@@ -78,7 +79,7 @@ class NotizPerson extends Notiz_Controller
} }
$allowedStgs = $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []; $allowedStgs = $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: [];
$this->_checkIfBerechtigungForOneUidExists($person_id, $allowedStgs); $this->_checkIfBerechtigungForOnePrestudentExists($person_id, $allowedStgs);
} }
} }
@@ -99,44 +100,20 @@ class NotizPerson extends Notiz_Controller
} }
//stv: if person has permission of one studiengang of person -> permission to add/update/delete Note //stv: if person has permission of one studiengang of person -> permission to add/update/delete Note
private function _checkIfBerechtigungForOneUidExists($person_id, $allowedStgs) private function _checkIfBerechtigungForOnePrestudentExists($person_id, $allowedStgs)
{ {
//get all studentUids of person_id $result = $this->PrestudentModel->loadWhere(['person_id' => $person_id]);
$result = $this->BenutzerModel->loadWhere(['person_id' => $person_id]);
$data = $this->getDataOrTerminateWithError($result); $data = $this->getDataOrTerminateWithError($result);
$checkarray = []; $checkarray = [];
foreach ($data as $item) foreach ($data as $item)
{ {
//check if isStudent if(in_array($item->studiengang_kz, $allowedStgs))
$result = $this->StudentModel->isStudent($item->uid);
$isStudent = $this->getDataOrTerminateWithError($result);
if($isStudent)
{ {
$checkarray[] = $this->_checkAllowedStgsFromUid($item->uid, $allowedStgs); return true;
} }
} }
if (!in_array(1, $checkarray))
return $this->terminateWithError($this->p->t('ui', 'error_keineBerechtigungStg'), self::ERROR_TYPE_GENERAL);
}
private function _checkAllowedStgsFromUid($student_uid, $allowedStgs) $this->terminateWithError($this->p->t('ui', 'error_keineBerechtigungStg'), self::ERROR_TYPE_GENERAL);
{
$this->load->model('crm/Student_model', 'StudentModel');
$result = $this->StudentModel->loadWhere(['student_uid' => $student_uid]);
$data = $this->getDataOrTerminateWithError($result);
$studiengang_kz = current($data)->studiengang_kz;
if (!in_array($studiengang_kz, $allowedStgs))
{
return 0;
}
else
{
return 1;
}
} }
} }
@@ -48,7 +48,8 @@ class Konto extends FHCAPI_Controller
// Load language phrases // Load language phrases
$this->loadPhrases([ $this->loadPhrases([
'konto' 'konto',
'lehre'
]); ]);
} }
@@ -112,7 +113,7 @@ class Konto extends FHCAPI_Controller
* *
* @return void * @return void
*/ */
public function getBuchungstypen() public function getBuchungstypen($studiensemester_kurzbz = null)
{ {
$this->load->model('crm/Buchungstyp_model', 'BuchungstypModel'); $this->load->model('crm/Buchungstyp_model', 'BuchungstypModel');
@@ -122,6 +123,7 @@ class Konto extends FHCAPI_Controller
$data = $this->getDataOrTerminateWithError($result); $data = $this->getDataOrTerminateWithError($result);
$this->_getOEHBeitrag($data, $studiensemester_kurzbz);
$this->terminateWithSuccess($data); $this->terminateWithSuccess($data);
} }
@@ -494,4 +496,43 @@ class Konto extends FHCAPI_Controller
$this->terminateWithSuccess(); $this->terminateWithSuccess();
} }
private function _getOEHBeitrag(&$data, $studiensemester_kurzbz = null)
{
if (is_null($studiensemester_kurzbz))
{
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
$studiensemester_akt = $this->variablelib->getVar('semester_aktuell');
}
else
{
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
if ($this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
$studiensemester_akt = $studiensemester_kurzbz;
else
$this->terminateWithError($this->p->t('lehre', 'error_noStudiensemester'));
}
$this->load->model('codex/Oehbeitrag_model', 'OehbeitragModel');
$oehBeitrag = $this->OehbeitragModel->getByStudiensemester($studiensemester_akt);
$oehStandardbetrag = null;
if (hasData($oehBeitrag))
{
$oeh = getData($oehBeitrag)[0];
$summe = ($oeh->studierendenbeitrag + $oeh->versicherung) * -1;
$oehStandardbetrag = number_format((float)$summe, 2, '.', '');
}
if ($oehStandardbetrag !== null)
{
$data = array_map(function ($buchungstyp) use ($oehStandardbetrag) {
if (isset($buchungstyp->buchungstyp_kurzbz) && (strtolower($buchungstyp->buchungstyp_kurzbz) === 'oeh'))
{
$buchungstyp->standardbetrag = $oehStandardbetrag;
}
return $buchungstyp;
}, $data);
}
}
} }
@@ -851,40 +851,44 @@ class Students extends FHCAPI_Controller
$stdsemEsc = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL'; $stdsemEsc = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL';
$this->load->config('stv'); $this->load->config('stv');
$tags = $this->config->item('stv_prestudent_tags');
$whereTags = ''; if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
if (is_array($tags) && !isEmptyArray($tags)) { {
$tags = array_keys($tags); $tags = $this->config->item('stv_prestudent_tags');
foreach ($tags as $key => $tag) { $whereTags = '';
$tags[$key] = $this->db->escape($tag); if (is_array($tags) && !isEmptyArray($tags)) {
$tags = array_keys($tags);
foreach ($tags as $key => $tag) {
$tags[$key] = $this->db->escape($tag);
}
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")";
} }
$whereTags = " AND nt.typ_kurzbz IN (" . implode(",", $tags) . ")"; $subQueryTag = "
(
SELECT
tag.prestudent_id,
COALESCE(json_agg(tag ORDER BY tag.done), '[]'::json) AS tags
FROM (
SELECT DISTINCT ON (n.notiz_id)
n.notiz_id AS id,
nt.typ_kurzbz,
array_to_json(nt.bezeichnung_mehrsprachig)->>0 AS beschreibung,
n.text AS notiz,
nt.style,
n.erledigt AS done,
nz.prestudent_id
FROM public.tbl_notizzuordnung AS nz
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz "
. $whereTags .
"
) AS tag
GROUP BY tag.prestudent_id
) AS tag_data_agg
";
} }
$subQueryTag = "
(
SELECT
tag.prestudent_id,
COALESCE(json_agg(tag ORDER BY tag.done), '[]'::json) AS tags
FROM (
SELECT DISTINCT ON (n.notiz_id)
n.notiz_id AS id,
nt.typ_kurzbz,
array_to_json(nt.bezeichnung_mehrsprachig)->>0 AS beschreibung,
n.text AS notiz,
nt.style,
n.erledigt AS done,
nz.prestudent_id
FROM public.tbl_notizzuordnung AS nz
JOIN public.tbl_notiz AS n ON nz.notiz_id = n.notiz_id
JOIN public.tbl_notiz_typ AS nt ON n.typ = nt.typ_kurzbz "
. $whereTags .
"
) AS tag
GROUP BY tag.prestudent_id
) AS tag_data_agg
";
$this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT'); $this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT');
$this->PrestudentModel->addJoin('public.tbl_person p', 'person_id'); $this->PrestudentModel->addJoin('public.tbl_person p', 'person_id');
@@ -907,11 +911,17 @@ class Students extends FHCAPI_Controller
AND ps.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ') AND ps.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')
AND ps.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')', 'LEFT'); AND ps.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')', 'LEFT');
$this->PrestudentModel->addJoin($subQueryTag, 'tag_data_agg.prestudent_id = tbl_prestudent.prestudent_id', 'LEFT'); if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
{
$this->PrestudentModel->addJoin($subQueryTag, 'tag_data_agg.prestudent_id = tbl_prestudent.prestudent_id', 'LEFT');
}
$this->PrestudentModel->addSelect("b.uid"); $this->PrestudentModel->addSelect("b.uid");
$this->PrestudentModel->addSelect('tag_data_agg.tags'); if(defined('STV_TAGS_ENABLED') && STV_TAGS_ENABLED)
{
$this->PrestudentModel->addSelect('tag_data_agg.tags');
}
$this->PrestudentModel->addSelect('titelpre'); $this->PrestudentModel->addSelect('titelpre');
$this->PrestudentModel->addSelect('nachname'); $this->PrestudentModel->addSelect('nachname');
$this->PrestudentModel->addSelect('vorname'); $this->PrestudentModel->addSelect('vorname');
@@ -0,0 +1,52 @@
<?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 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');
/**
*/
class Admin extends Auth_Controller
{
/**
* Constructor
*/
public function __construct()
{
// Set required permissions
parent::__construct(
array(
'index' => 'dashboard/admin:rw',
'preview' => 'dashboard/admin:r',
)
);
}
// -----------------------------------------------------------------------------------------------------------------
// Public methods
public function index()
{
$this->load->view('dashboard/admin.php', []);
}
public function preview($dashboard_kurzbz = 'CIS')
{
$this->load->view('dashboard/preview.php', [
'dashboard_kurzbz' => $dashboard_kurzbz
]);
}
}
-76
View File
@@ -1,76 +0,0 @@
<?php
defined('BASEPATH') || exit('No direct script access allowed');
class Api extends Auth_Controller
{
public function __construct()
{
parent::__construct(
array(
'index' => 'dashboard/admin:rw',
'getNews' => 'dashboard/benutzer:r',
'getAmpeln' => 'dashboard/benutzer:r',
)
);
$this->load->library('AuthLib', null, 'AuthLib');
$this->_setAuthUID();
}
public function index()
{
echo 'Dashboard API Controller';
}
/**
* Get News.
*/
public function getNews()
{
$limit = $this->input->get('limit');
$this->load->model('content/News_model', 'NewsModel');
$result = $this->NewsModel->getAll($limit);
if (hasData($result))
{
$this->outputJson(getData($result), REST_Controller::HTTP_OK);
}
else
{
$this->terminateWithJsonError('fehler entdeckt');
}
}
/**
* Get Ampeln.
*/
public function getAmpeln()
{
$this->load->model('content/Ampel_model', 'AmpelModel');
$result = $this->AmpelModel->getByUser($this->_uid);
if (hasData($result))
{
$this->outputJson(getData($result), REST_Controller::HTTP_OK);
}
else
{
$this->terminateWithJsonError('fehler entdeckt');
}
}
/**
* Retrieve the UID of the logged user and checks if it is valid
*/
private function _setAuthUID()
{
$this->_uid = getAuthUID();
if (!$this->_uid) show_error('User authentification failed');
}
}
@@ -1,216 +0,0 @@
<?php
defined('BASEPATH') || exit('No direct script access allowed');
/**
* Description of Config
*
* @author bambi
*/
class Config extends Auth_Controller
{
public function __construct()
{
parent::__construct(
array(
'index' => 'dashboard/benutzer:r',
'dummy' => 'dashboard/benutzer:r',
'genWidgetId' => 'dashboard/benutzer:rw',
'addWidgetsToPreset' => 'dashboard/admin:rw',
'removeWidgetFromPreset' => 'dashboard/admin:rw',
'addWidgetsToUserOverride' => 'dashboard/benutzer:rw',
'removeWidgetFromUserOverride' => 'dashboard/benutzer:rw',
'funktionen' => 'dashboard/admin:r',
'preset' => 'dashboard/admin:r',
'presetBatch' => 'dashboard/admin:r'
)
);
$this->load->library('dashboard/DashboardLib', null, 'DashboardLib');
$this->load->library('AuthLib', null, 'AuthLib');
$this->load->model('ressource/Funktion_model', 'FunktionModel');
}
public function index()
{
$dashboard_kurzbz = $this->input->get('db');
$uid = $this->AuthLib->getAuthObj()->username;
$dashboard = $this->DashboardLib->getDashboardByKurzbz($dashboard_kurzbz);
if(!$dashboard) {
http_response_code(404);
$this->terminateWithJsonError(array(
'error' => 'Dashboard ' . $dashboard_kurzbz . ' not found.'
));
}
$mergedconfig = $this->DashboardLib->getMergedConfig($dashboard->dashboard_id, $uid);
$this->outputJsonSuccess($mergedconfig);
}
public function genWidgetId()
{
$dashboard_kurzbz = $this->input->get('db');
$widgetid = $this->DashboardLib->generateWidgetId($dashboard_kurzbz);
$this->outputJsonSuccess(array(
'widgetid' => $widgetid
));
}
public function addWidgetsToPreset()
{
$input = json_decode($this->input->raw_input_stream);
$dashboard_kurzbz = $input->db;
$funktion_kurzbz = $input->funktion_kurzbz;
$preset = $this->DashboardLib->getPresetOrCreateEmptyPreset($dashboard_kurzbz, $funktion_kurzbz);
$preset_decoded = json_decode($preset->preset, true);
$this->DashboardLib->addWidgetsToWidgets($preset_decoded, $dashboard_kurzbz, $funktion_kurzbz, $input->widgets);
$preset->preset = json_encode($preset_decoded);
$result = $this->DashboardLib->insertOrUpdatePreset($preset);
if (isError($result)) {
http_response_code(500);
$this->terminateWithJsonError('preset could not be saved');
}
$this->outputJsonSuccess(array('msg' => 'preset successfully stored.', 'data' => $preset_decoded));
}
public function removeWidgetFromPreset()
{
$input = json_decode($this->input->raw_input_stream);
$dashboard_kurzbz = $input->db;
$funktion_kurzbz = $input->funktion_kurzbz;
$widgetid = $input->widgetid;
$preset = $this->DashboardLib->getPreset($dashboard_kurzbz, $funktion_kurzbz);
if ($preset === null) {
http_response_code(404);
$this->terminateWithJsonError('preset for dashboard ' . $dashboard_kurzbz . ' and funktion ' . $funktion_kurzbz . ' not found.');
}
$preset_decoded = json_decode($preset->preset, true);
if (!$this->DashboardLib->removeWidgetFromWidgets($preset_decoded, $funktion_kurzbz, $widgetid))
{
http_response_code(404);
$this->terminateWithJsonError('widgetid ' . $widgetid . ' not found');
}
$preset->preset = json_encode($preset_decoded);
$result = $this->DashboardLib->insertOrUpdatePreset($preset);
if (isError($result))
{
http_response_code(500);
$this->terminateWithJsonError('failed to remove widget');
}
$this->outputJsonSuccess(array('msg' => 'preset successfully updated.'));
}
public function addWidgetsToUserOverride()
{
$input = json_decode($this->input->raw_input_stream);
$dashboard_kurzbz = $input->db;
$funktion_kurzbz = $input->funktion_kurzbz;
$uid = $this->AuthLib->getAuthObj()->username;
$override = $this->DashboardLib->getOverrideOrCreateEmptyOverride($dashboard_kurzbz, $uid);
$override_decoded = json_decode($override->override, true);
$this->DashboardLib->addWidgetsToWidgets($override_decoded, $dashboard_kurzbz, $funktion_kurzbz, $input->widgets);
$override->override = json_encode($override_decoded);
$result = $this->DashboardLib->insertOrUpdateOverride($override);
if (isError($result)) {
http_response_code(500);
$this->terminateWithJsonError('override could not be saved');
}
$this->outputJsonSuccess(array('msg' => 'override successfully stored.', 'data' => $override_decoded));
}
public function removeWidgetFromUserOverride()
{
$input = json_decode($this->input->raw_input_stream);
$dashboard_kurzbz = $input->db;
$funktion_kurzbz = $input->funktion_kurzbz;
$uid = $this->AuthLib->getAuthObj()->username;
$widgetid = $input->widgetid;
$override = $this->DashboardLib->getOverride($dashboard_kurzbz, $uid);
if (empty($override)) {
http_response_code(404);
$this->terminateWithJsonError('userconfig for dashboard ' . $dashboard_kurzbz . ' not found.');
}
$override_decoded = json_decode($override->override, true);
if (!$this->DashboardLib->removeWidgetFromWidgets($override_decoded, $funktion_kurzbz, $widgetid))
{
http_response_code(404);
$this->terminateWithJsonError('widgetid ' . $widgetid . ' not found');
}
$override->override = json_encode($override_decoded);
$result = $this->DashboardLib->insertOrUpdateOverride($override, $uid);
if (isError($result))
{
http_response_code(500);
$this->terminateWithJsonError('failed to remove widget');
}
$this->outputJsonSuccess(array('msg' => 'override successfully updated.'));
}
public function funktionen()
{
$funktionen = $this->FunktionModel->load();
if (isError($funktionen)) {
http_response_code(404);
$this->terminateWithJsonError([
'error' => getError($funktionen)
]);
}
return $this->outputJsonSuccess(getData($funktionen) ?: []);
}
public function preset()
{
$db = $this->input->get('db');
$funktion = $this->input->get('funktion');
$conf = $this->DashboardLib->getPreset($db, $funktion);
if (!$conf)
return $this->outputJsonSuccess(['widgets' => [$funktion => []]]);
return $this->outputJsonSuccess(json_decode($conf->preset, true));
}
public function presetBatch()
{
$db = $this->input->get('db');
$funktionen = $this->input->get('funktionen');
$result = [];
foreach ($funktionen as $funktion) {
$conf = $this->DashboardLib->getPreset($db, $funktion);
if ($conf)
{
$preset = json_decode($conf->preset, true);
if (!isset($preset[$funktion]) || !isset($preset[$funktion]['widgets']))
$result[$funktion] = [];
else
$result[$funktion] = $preset[$funktion]['widgets'];
}
else
$result[$funktion] = [];
}
return $this->outputJsonSuccess($result);
}
}
@@ -1,86 +0,0 @@
<?php
defined('BASEPATH') || exit('No direct script access allowed');
/**
* Description of Widget
*
* @author chris
*/
class Dashboard extends Auth_Controller
{
public function __construct()
{
parent::__construct(
array(
'index' => 'dashboard/admin:r',
'create' => 'dashboard/admin:rw',
'update' => 'dashboard/admin:rw',
'delete' => 'dashboard/admin:rw'
)
);
$this->load->library('dashboard/DashboardLib', null, 'DashboardLib');
$this->load->model('dashboard/Dashboard_model', 'DashboardModel');
}
public function index()
{
$result = $this->DashboardModel->load();
if (isError($result)) {
http_response_code(404);
$this->terminateWithJsonError([
'error' => getError($result)
]);
}
return $this->outputJsonSuccess(getData($result) ?: []);
}
public function create()
{
$input = $this->getPostJSON();
$result = $this->DashboardModel->insert($input);
if (isError($result)) {
http_response_code(404);
$this->terminateWithJsonError([
'error' => getError($result)
]);
}
return $this->outputJsonSuccess(getData($result) ?: []);
}
public function update()
{
$input = $this->getPostJSON();
$result = $this->DashboardModel->update($input->dashboard_id, $input);
if (isError($result)) {
http_response_code(404);
$this->terminateWithJsonError([
'error' => getError($result)
]);
}
return $this->outputJsonSuccess(getData($result) ?: []);
}
public function delete()
{
$input = $this->getPostJSON();
$result = $this->DashboardModel->delete($input->dashboard_id);
if (isError($result)) {
http_response_code(404);
$this->terminateWithJsonError([
'error' => getError($result)
]);
}
return $this->outputJsonSuccess(getData($result) ?: []);
}
}
@@ -1,58 +0,0 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
/**
*/
class DashboardDemo extends Auth_Controller
{
private $_uid; // uid of the logged user
/**
* Constructor
*/
public function __construct()
{
// Set required permissions
parent::__construct(
array(
'index' => 'dashboard/benutzer:r',
'admin' => 'dashboard/admin:rw'
)
);
$this->load->library('AuthLib');
$this->load->library('WidgetLib');
$this->_setAuthUID(); // sets property uid
$this->setControllerId(); // sets the controller id
}
// -----------------------------------------------------------------------------------------------------------------
// Public methods
public function index()
{
$this->load->view('dashboard/dashboard_demo.php', []);
}
// -----------------------------------------------------------------------------------------------------------------
// Public methods
public function admin()
{
$this->load->view('dashboard/dashboard_demo_admin.php', []);
}
// -----------------------------------------------------------------------------------------------------------------
// Private methods
/**
* Retrieve the UID of the logged user and checks if it is valid
*/
private function _setAuthUID()
{
$this->_uid = getAuthUID();
if (!$this->_uid) show_error('User authentification failed');
}
}
@@ -1,134 +0,0 @@
<?php
defined('BASEPATH') || exit('No direct script access allowed');
/**
* Description of Widget
*
* @author chris
*/
class Widget extends Auth_Controller
{
public function __construct()
{
parent::__construct(
array(
'index' => ['dashboard/benutzer:r', 'dashboard/admin:r'],
'getAll' => 'dashboard/admin:r',
'getWidgetsForDashboard' => ['dashboard/benutzer:rw', 'dashboard/admin:r'],
'setAllowed' => 'dashboard/admin:rw'
)
);
$this->load->library('dashboard/DashboardLib', null, 'DashboardLib');
$this->load->model('dashboard/Widget_model', 'WidgetModel');
$this->load->model('dashboard/Dashboard_Widget_model', 'DashboardWidgetModel');
}
public function index()
{
$widget_id = $this->input->get('id');
$widget = $this->WidgetModel->load($widget_id);
if (isError($widget) || !getData($widget))
return $this->outputJsonSuccess([
"widget_id" => 0,
"widget_kurzbz" => "notfound",
"arguments" => [
"className" => 'alert-danger',
"title" => 'Widget Not Found',
"msg" => 'The widget with the id ' . $widget_id . ' could not be found'
],
"setup" => [
"name" => 'Widget Not Found',
"file" => absoluteJsImportUrl('public/js/components/DashboardWidget/Default.js'),
"width" => 1,
"height" => 1
]
]);
$widget = current(getData($widget));
$widget->arguments = json_decode($widget->arguments);
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
return $this->outputJsonSuccess($widget);
}
public function getAll()
{
$dashboard_id = $this->input->get('dashboard_id');
$result = $this->WidgetModel->getWithAllowedForDashboard($dashboard_id);
if (isError($result))
return $this->outputJsonError(getError($result));
$tmpwidgets = getData($result) ?: [];
$widgets = array_map(function($widget) {
$widget->arguments = json_decode($widget->arguments);
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
return $widget;
}, $tmpwidgets);
$this->outputJsonSuccess($widgets);
}
public function getWidgetsForDashboard()
{
$db = $this->input->get('db');
$result = $this->WidgetModel->getForDashboard($db);
if (isError($result)) {
http_response_code(404);
$this->terminateWithJsonError([
'error' => getError($result)
]);
}
$tmpwidgets = getData($result) ?: [];
$widgets = array_map(function($widget) {
$widget->arguments = json_decode($widget->arguments);
$tmpsetup = json_decode($widget->setup);
$tmpsetup->file = absoluteJsImportUrl($tmpsetup->file);
$widget->setup = $tmpsetup;
return $widget;
}, $tmpwidgets);
$this->outputJsonSuccess($widgets);
}
public function setAllowed()
{
$input = $this->getPostJSON();
$dashboard_id = $input->dashboard_id;
$widget_id = $input->widget_id;
$action = $input->action;
if ($action == 'add') {
$result = $this->DashboardWidgetModel->insert([
'dashboard_id' => $dashboard_id,
'widget_id' => $widget_id
]);
} elseif ($action == 'delete') {
$result = $this->DashboardWidgetModel->delete([
'dashboard_id' => $dashboard_id,
'widget_id' => $widget_id
]);
} else {
http_response_code(404); // TODO(chris): 400?
$this->terminateWithJsonError([
'error' => 'action value invalid'
]);
}
if (isError($result)) {
http_response_code(404);
$this->terminateWithJsonError([
'error' => getError($result)
]);
}
return $this->outputJsonSuccess(getData($result));
}
}
@@ -495,6 +495,10 @@ class AbgabetoolJob extends JOB_Controller
// get all new or changed termine in interval // get all new or changed termine in interval
$result = $this->_ci->PaabgabeModel->findAbgabenNewOrUpdatedSince($interval, $relevantTypes); $result = $this->_ci->PaabgabeModel->findAbgabenNewOrUpdatedSince($interval, $relevantTypes);
$retval = getData($result); $retval = getData($result);
if(!$retval) {
$this->_ci->logInfo("Keine Emails an Betreuer über neue oder veränderte Termine versandt");
return;
}
// group changed/new abgaben for projektarbeiten // group changed/new abgaben for projektarbeiten
$projektarbeiten = []; $projektarbeiten = [];
@@ -557,6 +561,8 @@ class AbgabetoolJob extends JOB_Controller
$anredeFillString = $data->anrede == "Herr" ? "r" : ""; $anredeFillString = $data->anrede == "Herr" ? "r" : "";
$fullFormattedNameString = $data->first; $fullFormattedNameString = $data->first;
$relevantCounter = 0; // workaround to check if a betreuer needs to have any notification about relevant
// abgaben at all to avoid sending empty emails since we filter on certain conditions
forEach($tupelArr as $tupel) { forEach($tupelArr as $tupel) {
$projektarbeit_id = $tupel[0]; $projektarbeit_id = $tupel[0];
$betreuerRow = $tupel[1]; $betreuerRow = $tupel[1];
@@ -575,6 +581,8 @@ class AbgabetoolJob extends JOB_Controller
continue; continue;
} }
$relevantCounter++;
// format the Student Name // format the Student Name
$s = $relevantAbgaben[0]; $s = $relevantAbgaben[0];
$nameParts = []; $nameParts = [];
@@ -633,6 +641,11 @@ class AbgabetoolJob extends JOB_Controller
// done with building the change list, now send it // done with building the change list, now send it
$betreuerRow = $tupelArr[0][1]; $betreuerRow = $tupelArr[0][1];
if($relevantCounter == 0) {
$this->_ci->logInfo('No Relevant Abgaben to notify Betreuer PersonID: "'.$betreuerRow->person_id.'".');
continue;
}
$path = $this->_ci->config->item('URL_MITARBEITER'); $path = $this->_ci->config->item('URL_MITARBEITER');
$url = CIS_ROOT.$path; $url = CIS_ROOT.$path;
+1
View File
@@ -417,6 +417,7 @@ abstract class Notiz_Controller extends FHCAPI_Controller
$notiz_id = $this->input->post('notiz_id'); $notiz_id = $this->input->post('notiz_id');
$this->NotizModel->addSelect('campus.tbl_dms_version.*'); $this->NotizModel->addSelect('campus.tbl_dms_version.*');
$this->NotizModel->addSelect($this->NotizModel->escape(base_url('content/notizdokdownload.php?id=')) . ' || public.tbl_notiz_dokument.dms_id AS preview');
$this->NotizModel->addJoin('public.tbl_notiz_dokument', 'ON (public.tbl_notiz_dokument.notiz_id = public.tbl_notiz.notiz_id)'); $this->NotizModel->addJoin('public.tbl_notiz_dokument', 'ON (public.tbl_notiz_dokument.notiz_id = public.tbl_notiz.notiz_id)');
$this->NotizModel->addJoin('campus.tbl_dms_version', 'ON (public.tbl_notiz_dokument.dms_id = campus.tbl_dms_version.dms_id)'); $this->NotizModel->addJoin('campus.tbl_dms_version', 'ON (public.tbl_notiz_dokument.dms_id = campus.tbl_dms_version.dms_id)');
+1 -1
View File
@@ -128,7 +128,7 @@ class AntragLib
return $this->_ci->StudierendenantragstatusModel->resumeAntraegeForAbmeldungStgl($antrag_id); return $this->_ci->StudierendenantragstatusModel->resumeAntraegeForAbmeldungStgl($antrag_id);
} }
// NOTE(chris): get last status that is not pause // NOTE(chris): get last status that is not pause
$this->_ci->StudierendenantragstatusModel->addOrder('insertamum'); $this->_ci->StudierendenantragstatusModel->addOrder('insertamum', 'DESC');
$this->_ci->StudierendenantragstatusModel->addLimit(1); $this->_ci->StudierendenantragstatusModel->addLimit(1);
$result = $this->_ci->StudierendenantragstatusModel->loadWhere([ $result = $this->_ci->StudierendenantragstatusModel->loadWhere([
'studierendenantrag_id' => $antrag_id, 'studierendenantrag_id' => $antrag_id,
+16 -1
View File
@@ -50,6 +50,7 @@ class PermissionLib
const LOGINAS_PERSONIDS_BLACKLIST = 'permission_loginas_personids_blacklist'; const LOGINAS_PERSONIDS_BLACKLIST = 'permission_loginas_personids_blacklist';
private $_ci; // CI instance private $_ci; // CI instance
private $access_rights; // current users access rights
private static $bb; // benutzerberechtigung private static $bb; // benutzerberechtigung
/** /**
@@ -61,6 +62,8 @@ class PermissionLib
// Loads CI instance // Loads CI instance
$this->_ci =& get_instance(); $this->_ci =& get_instance();
$this->access_rights = null;
$this->_ci->config->load('permission'); // Loads permission configuration $this->_ci->config->load('permission'); // Loads permission configuration
// If it's NOT called from command line // If it's NOT called from command line
@@ -69,8 +72,10 @@ class PermissionLib
// API Caller rights initialization // API Caller rights initialization
$authObj = $this->_ci->authlib->getAuthObj(); $authObj = $this->_ci->authlib->getAuthObj();
self::$bb = new benutzerberechtigung(); self::$bb = new benutzerberechtigung();
if ($authObj) if ($authObj) {
self::$bb->getBerechtigungen($authObj->{AuthLib::AO_USERNAME}); self::$bb->getBerechtigungen($authObj->{AuthLib::AO_USERNAME});
$this->access_rights = self::$bb->berechtigungen;
}
} }
} }
@@ -340,6 +345,16 @@ class PermissionLib
} }
} }
/**
* Returns the access rights for the current user
*
* @return array|null
*/
public function getAccessRights()
{
return $this->access_rights;
}
//------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------
// Private methods // Private methods
@@ -49,7 +49,7 @@ class DashboardLib
public function getMergedConfig($dashboard_id, $uid) public function getMergedConfig($dashboard_id, $uid)
{ {
$defaultconfig = $this->getDefaultConfig($dashboard_id, $uid); $defaultconfig = $this->getDefaultConfig($dashboard_id);
$userconfig = $this->getUserConfig($dashboard_id, $uid); $userconfig = $this->getUserConfig($dashboard_id, $uid);
$mergedconfig = array_replace_recursive($defaultconfig, $userconfig); $mergedconfig = array_replace_recursive($defaultconfig, $userconfig);
@@ -57,14 +57,31 @@ class DashboardLib
return $mergedconfig; return $mergedconfig;
} }
public function getDefaultConfig($dashboard_id, $uid) public function getDefaultConfig($dashboard_id)
{ {
$res_presets = $this->_ci->DashboardPresetModel->getPresets($dashboard_id, $uid); $funktion_kurzbzs = [];
$rights = $this->_ci->permissionlib->getAccessRights();
if ($rights)
$funktion_kurzbzs = array_unique(array_map(function ($right) {
return $right->funktion_kurzbz;
}, $rights));
$this->_ci->DashboardPresetModel->db
->group_start()
->where_in('funktion_kurzbz', $funktion_kurzbzs)
->or_where('funktion_kurzbz IS NULL')
->group_end();
$this->_ci->DashboardPresetModel->addOrder('funktion_kurzbz', 'DESC');
$result = $this->_ci->DashboardPresetModel->loadWhere([
'dashboard_id' => $dashboard_id
]);
$defaultconfig = array(); $defaultconfig = array();
if (hasData($res_presets)) if (hasData($result))
{ {
$presets = getData($res_presets); $presets = getData($result);
foreach ($presets as $presetobj) foreach ($presets as $presetobj)
{ {
$preset = json_decode($presetobj->preset, true); $preset = json_decode($presetobj->preset, true);
@@ -137,8 +154,10 @@ class DashboardLib
$dashboard = $this->getDashboardByKurzbz($dashboard_kurzbz); $dashboard = $this->getDashboardByKurzbz($dashboard_kurzbz);
$funktion_kurzbz = ($section === self::SECTION_IF_FUNKTION_KURZBZ_IS_NULL) ? null : $section; $funktion_kurzbz = ($section === self::SECTION_IF_FUNKTION_KURZBZ_IS_NULL) ? null : $section;
$result = $this->_ci->DashboardPresetModel $result = $this->_ci->DashboardPresetModel->loadWhere([
->getPresetByDashboardAndFunktion($dashboard->dashboard_id, $funktion_kurzbz); 'dashboard_id' => $dashboard->dashboard_id,
'funktion_kurzbz' => $funktion_kurzbz
]);
if (hasData($result)) if (hasData($result))
{ {
@@ -195,11 +214,11 @@ class DashboardLib
{ {
foreach ($addwigets as $widget) foreach ($addwigets as $widget)
{ {
if(!isset($widget->widgetid)) if(!isset($widget['widgetid']))
{ {
$widget->widgetid = $this->generateWidgetId($dashboard_kurzbz); $widget['widgetid'] = $this->generateWidgetId($dashboard_kurzbz);
} }
$this->addWidgetToWidgets($widgets, $section, $widget, $widget->widgetid); $this->addWidgetToWidgets($widgets, $section, $widget, $widget['widgetid']);
} }
} }
@@ -3,6 +3,7 @@ namespace vertragsbestandteil;
use Exception; use Exception;
use vertragsbestandteil\VertragsbestandteilStunden; use vertragsbestandteil\VertragsbestandteilStunden;
use vertragsbestandteil\VertragsbestandteilLohnguide;
/** /**
* Description of VertragsbestandteilFactory * Description of VertragsbestandteilFactory
@@ -22,6 +23,7 @@ class VertragsbestandteilFactory
const VERTRAGSBESTANDTEIL_URLAUBSANSPRUCH = 'urlaubsanspruch'; const VERTRAGSBESTANDTEIL_URLAUBSANSPRUCH = 'urlaubsanspruch';
const VERTRAGSBESTANDTEIL_ZEITAUFZEICHNUNG = 'zeitaufzeichnung'; const VERTRAGSBESTANDTEIL_ZEITAUFZEICHNUNG = 'zeitaufzeichnung';
const VERTRAGSBESTANDTEIL_LEHRE = 'lehre'; const VERTRAGSBESTANDTEIL_LEHRE = 'lehre';
const VERTRAGSBESTANDTEIL_LOHNGUIDE = 'lohnguide';
public static function getVertragsbestandteil($data, $fromdb=false) public static function getVertragsbestandteil($data, $fromdb=false)
{ {
@@ -70,6 +72,11 @@ class VertragsbestandteilFactory
$vertragsbestandteil->hydrateByStdClass($data, $fromdb); $vertragsbestandteil->hydrateByStdClass($data, $fromdb);
break; break;
case self::VERTRAGSBESTANDTEIL_LOHNGUIDE:
$vertragsbestandteil = new VertragsbestandteilLohnguide();
$vertragsbestandteil->hydrateByStdClass($data, $fromdb);
break;
default: default:
throw new Exception('Unknown vertragsbestandteiltyp_kurzbz ' throw new Exception('Unknown vertragsbestandteiltyp_kurzbz '
. $vertragsbestandteiltyp_kurzbz); . $vertragsbestandteiltyp_kurzbz);
@@ -127,6 +134,12 @@ class VertragsbestandteilFactory
$vertragsbestandteildbmodel = $CI->VertragsbestandteilZeitaufzeichnung_model; $vertragsbestandteildbmodel = $CI->VertragsbestandteilZeitaufzeichnung_model;
break; break;
case self::VERTRAGSBESTANDTEIL_LOHNGUIDE:
$CI->load->model('vertragsbestandteil/VertragsbestandteilLohnguide_model',
'VertragsbestandteilLohnguide_model');
$vertragsbestandteildbmodel = $CI->VertragsbestandteilLohnguide_model;
break;
default: default:
throw new Exception('Unknown vertragsbestandteil_kurzbz ' throw new Exception('Unknown vertragsbestandteil_kurzbz '
. $vertragsbestandteil_kurzbz); . $vertragsbestandteil_kurzbz);
@@ -10,6 +10,7 @@ require_once __DIR__ . '/VertragsbestandteilKuendigungsfrist.php';
require_once __DIR__ . '/VertragsbestandteilUrlaubsanspruch.php'; require_once __DIR__ . '/VertragsbestandteilUrlaubsanspruch.php';
require_once __DIR__ . '/VertragsbestandteilFreitext.php'; require_once __DIR__ . '/VertragsbestandteilFreitext.php';
require_once __DIR__ . '/VertragsbestandteilKarenz.php'; require_once __DIR__ . '/VertragsbestandteilKarenz.php';
require_once __DIR__ . '/VertragsbestandteilLohnguide.php';
require_once __DIR__ . '/VertragsbestandteilFactory.php'; require_once __DIR__ . '/VertragsbestandteilFactory.php';
require_once __DIR__ . '/OverlapChecker.php'; require_once __DIR__ . '/OverlapChecker.php';
@@ -0,0 +1,155 @@
<?php
namespace vertragsbestandteil;
use vertragsbestandteil\Vertragsbestandteil;
use vertragsbestandteil\VertragsbestandteilFactory;
class VertragsbestandteilLohnguide extends Vertragsbestandteil
{
protected $stellenbezeichnung;
protected $vordienstzeit;
protected $fachrichtung_kurzbz;
protected $modellstelle_kurzbz;
protected $kommentar_person;
protected $kommentar_modellstelle;
public function __construct()
{
parent::__construct();
$this->setVertragsbestandteiltyp_kurzbz(
VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_LOHNGUIDE);
}
public function getStellenbezeichnung()
{
return $this->stellenbezeichnung;
}
public function setStellenbezeichnung($stellenbezeichnung): self
{
$this->markDirty('stellenbezeichnung', $this->stellenbezeichnung, $stellenbezeichnung);
$this->stellenbezeichnung = $stellenbezeichnung;
return $this;
}
public function getVordienstzeit()
{
return $this->vordienstzeit;
}
public function setVordienstzeit($vordienstzeit): self
{
$this->markDirty('vordienstzeit', $this->vordienstzeit, $vordienstzeit);
$this->vordienstzeit = $vordienstzeit;
return $this;
}
public function getFachrichtung_kurzbz()
{
return $this->fachrichtung_kurzbz;
}
public function setFachrichtung_kurzbz($fachrichtung_kurzbz): self
{
$this->markDirty('fachrichtung_kurzbz', $this->fachrichtung_kurzbz, $fachrichtung_kurzbz);
$this->fachrichtung_kurzbz = $fachrichtung_kurzbz;
return $this;
}
public function getModellstelle_kurzbz()
{
return $this->modellstelle_kurzbz;
}
public function setModellstelle_kurzbz($modellstelle_kurzbz): self
{
$this->markDirty('modellstelle_kurzbz', $this->modellstelle_kurzbz, $modellstelle_kurzbz);
$this->modellstelle_kurzbz = $modellstelle_kurzbz;
return $this;
}
public function getKommentar_person()
{
return $this->kommentar_person;
}
public function setKommentar_person($kommentar_person): self
{
$this->markDirty('kommentar_person', $this->kommentar_person, $kommentar_person);
$this->kommentar_person = $kommentar_person;
return $this;
}
public function getKommentar_modellstelle()
{
return $this->kommentar_modellstelle;
}
public function setKommentar_modellstelle($kommentar_modellstelle): self
{
$this->markDirty('kommentar_modellstelle', $this->kommentar_modellstelle, $kommentar_modellstelle);
$this->kommentar_modellstelle = $kommentar_modellstelle;
return $this;
}
public function hydrateByStdClass($data, $fromdb=false)
{
parent::hydrateByStdClass($data, $fromdb);
$this->fromdb = $fromdb;
isset($data->fachrichtung_kurzbz) && $this->setFachrichtung_kurzbz($data->fachrichtung_kurzbz);
isset($data->stellenbezeichnung) && $this->setStellenbezeichnung($data->stellenbezeichnung);
isset($data->vordienstzeit) && $this->setVordienstzeit($data->vordienstzeit);
isset($data->modellstelle_kurzbz) && $this->setModellstelle_kurzbz($data->modellstelle_kurzbz);
isset($data->kommentar_person) && $this->setKommentar_person($data->kommentar_person);
isset($data->kommentar_modellstelle) && $this->setKommentar_modellstelle($data->kommentar_modellstelle);
$this->fromdb = false;
}
public function toStdClass(): \stdClass
{
$tmp = array(
'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(),
'stellenbezeichnung' => $this->getStellenbezeichnung(),
'vordienstzeit' => $this->getVordienstzeit(),
'fachrichtung_kurzbz' => $this->getFachrichtung_kurzbz(),
'modellstelle_kurzbz' => $this->getModellstelle_kurzbz(),
'kommentar_person' => $this->getKommentar_person(),
'kommentar_modellstelle' => $this->getKommentar_modellstelle(),
);
$tmp = array_filter($tmp, function($k) {
return in_array($k, $this->modifiedcolumns);
}, ARRAY_FILTER_USE_KEY);
return (object) $tmp;
}
public function __toString()
{
$txt = <<<EOTXT
modellstelle_kurzbz: {$this->getModellstelle_kurzbz()}
EOTXT;
return parent::__toString() . $txt;
}
/* public function validate()
{
if( !(filter_var($this->tage, FILTER_VALIDATE_INT,
array(
'options' => array(
'min_range' => 1,
'max_range' => 50
)
)
)) ) {
$this->validationerrors[] = 'Urlaubsanspruch muss eine Tagesanzahl im Bereich 1 bis 50 sein.';
}
return parent::validate();
} */
}
@@ -11,57 +11,4 @@ class Dashboard_Preset_model extends DB_Model
$this->dbTable = 'dashboard.tbl_dashboard_preset'; $this->dbTable = 'dashboard.tbl_dashboard_preset';
$this->pk = 'preset_id'; $this->pk = 'preset_id';
} }
/**
* Get Presets of given uid.
* @param integer dashboard_id
* @param string $uid
* @return array
*/
public function getPresets($dashboard_id, $uid)
{
// TODO: get Funktionen for uid and load all preset for all funktionen for uid
//return $this->loadWhere(array('dashboard_id' => $dashboard_id, 'funktion_kurzbz'=> null));
$sql = <<<EOSQL
SELECT
*
FROM
dashboard.tbl_dashboard_preset
WHERE
dashboard_id = ?
AND (
funktion_kurzbz IN (
SELECT
DISTINCT funktion_kurzbz
FROM
public.tbl_benutzerfunktion
WHERE
uid = ?
AND
NOW()::date
BETWEEN
COALESCE(datum_von, '1970-01-01')
AND
COALESCE(datum_bis, '2170-12-31')
)
OR
funktion_kurzbz IS NULL
)
ORDER BY
funktion_kurzbz DESC
EOSQL;
return $this->execQuery($sql, array($dashboard_id, $uid));
}
/**
* Get Preset by Dashboard and Funktion
* @param integer dashboard_id
* @param string funktion_kurzbz
* @return array
*/
public function getPresetByDashboardAndFunktion($dashboard_id, $funktion_kurzbz)
{
return $this->loadWhere(array('dashboard_id' => $dashboard_id, 'funktion_kurzbz' => $funktion_kurzbz));
}
} }
@@ -402,14 +402,17 @@ class Lehrveranstaltung_model extends DB_Model
SELECT SELECT
vorname, nachname, mitarbeiter_uid, lehrfunktion_kurzbz vorname, nachname, mitarbeiter_uid, lehrfunktion_kurzbz
FROM FROM
lehre.tbl_lehreinheit lehre.tbl_lehreinheit le
JOIN lehre.tbl_lehreinheitmitarbeiter lema USING (lehreinheit_id) JOIN lehre.tbl_lehreinheitmitarbeiter lema USING (lehreinheit_id)
JOIN public.tbl_benutzer b ON b.uid = lema.mitarbeiter_uid JOIN public.tbl_benutzer b ON b.uid = lema.mitarbeiter_uid
JOIN public.tbl_person p using (person_id) JOIN public.tbl_person p using (person_id)
WHERE WHERE
tbl_lehreinheit.lehrveranstaltung_id= ? le.lehrveranstaltung_id= ?
AND tbl_lehreinheit.studiensemester_kurzbz = ? AND le.studiensemester_kurzbz = ?
AND lehrfunktion_kurzbz = 'LV-Leitung' AND lehrfunktion_kurzbz = 'LV-Leitung'
AND lema.mitarbeiter_uid NOT like '_Dummy%'
AND b.aktiv = TRUE
AND p.aktiv = TRUE
ORDER BY ORDER BY
lema.insertamum DESC lema.insertamum DESC
LIMIT 1 LIMIT 1
@@ -79,9 +79,9 @@ class Paabgabe_model extends DB_Model
JOIN public.tbl_benutzer ON (public.tbl_benutzer.uid = student_uid) JOIN public.tbl_benutzer ON (public.tbl_benutzer.uid = student_uid)
JOIN public.tbl_person USING (person_id) JOIN public.tbl_person USING (person_id)
WHERE (campus.tbl_paabgabe.insertamum >= NOW() - INTERVAL ? WHERE (campus.tbl_paabgabe.insertamum::date = CURRENT_DATE - INTERVAL ?
OR campus.tbl_paabgabe.updateamum >= NOW() - INTERVAL ?) OR campus.tbl_paabgabe.updateamum::date = CURRENT_DATE - INTERVAL ?)
AND campus.tbl_paabgabe.paabgabetyp_kurzbz IN ?"; AND campus.tbl_paabgabe.paabgabetyp_kurzbz IN ?";
return $this->execQuery($query, [$interval, $interval, $relevantTypes]); return $this->execQuery($query, [$interval, $interval, $relevantTypes]);
} }
@@ -108,7 +108,7 @@ class Paabgabe_model extends DB_Model
JOIN public.tbl_person ON (public.tbl_benutzer.person_id = public.tbl_person.person_id) JOIN public.tbl_person ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
WHERE campus.tbl_paabgabe.abgabedatum IS NOT NULL WHERE campus.tbl_paabgabe.abgabedatum IS NOT NULL
AND campus.tbl_paabgabe.abgabedatum >= NOW() - INTERVAL ?"; AND campus.tbl_paabgabe.abgabedatum = CURRENT_DATE - INTERVAL ?";
if($relevantTypes !== null) { if($relevantTypes !== null) {
$query .= " AND campus.tbl_paabgabe.paabgabetyp_kurzbz IN ?"; $query .= " AND campus.tbl_paabgabe.paabgabetyp_kurzbz IN ?";
@@ -594,7 +594,10 @@ class Studiengang_model extends DB_Model
$this->addSelect('p.prestudent_id'); $this->addSelect('p.prestudent_id');
$this->addSelect('pers.vorname'); $this->addSelect('pers.vorname');
$this->addSelect('pers.nachname'); $this->addSelect('pers.nachname');
$this->addSelect("CONCAT(UPPER(pers.nachname), ' ', pers.vorname, ' (', " . $this->dbTable . ".bezeichnung, ')') AS name"); $this->addSelect("CONCAT(UPPER(pers.nachname), ' ', pers.vorname, ' (', "
. $this->dbTable . ".bezeichnung, ', ', "
. "UPPER(" . $this->dbTable . ".typ), "
. "UPPER(" . $this->dbTable . ".kurzbz),')') AS name");
$this->addJoin('public.tbl_prestudent p', 'studiengang_kz'); $this->addJoin('public.tbl_prestudent p', 'studiengang_kz');
$this->addJoin( $this->addJoin(
@@ -261,6 +261,42 @@ class Benutzerfunktion_model extends DB_Model
} }
/**
* Get active Kompetenzfeldleitung bei UID.
*
* @param $uid
* @return array|stdClass|null
*/
public function getKFLByUID($uid)
{
$query = '
SELECT
bf.uid,
bf.oe_kurzbz,
oe.organisationseinheittyp_kurzbz
FROM
public.tbl_benutzerfunktion bf
JOIN public.tbl_organisationseinheit oe USING (oe_kurzbz)
JOIN public.tbl_benutzer b USING (uid)
WHERE
b.uid = ?
AND b.aktiv = TRUE
AND funktion_kurzbz = \'Leitung\'
AND organisationseinheittyp_kurzbz = \'Kompetenzfeld\'
AND (datum_von IS NULL OR datum_von <= now())
AND (datum_bis IS NULL OR datum_bis >= now())
';
$parameters_array = array();
if (is_string($uid))
{
$parameters_array[] = $uid;
}
return $this->execQuery($query, $parameters_array);
}
public function insertBenutzerfunktion($Json) public function insertBenutzerfunktion($Json)
{ {
unset($Json['benutzerfunktion_id']); unset($Json['benutzerfunktion_id']);
+6 -4
View File
@@ -242,6 +242,7 @@ class Message_model extends DB_Model
*/ */
public function getMessagesForTable($person_id, $offset, $limit) public function getMessagesForTable($person_id, $offset, $limit)
{ {
$limitoffset = (!is_null($offset) && !is_null($limit)) ? 'limit ? offset ?' : '';
$sql = <<<EOSQL $sql = <<<EOSQL
with filtered_messages as ( with filtered_messages as (
select select
@@ -310,11 +311,12 @@ class Message_model extends DB_Model
public.tbl_person pr on pr.person_id = fm.recipient_id public.tbl_person pr on pr.person_id = fm.recipient_id
order by order by
m.insertamum DESC m.insertamum DESC
limit ? {$limitoffset}
offset ?;
EOSQL; EOSQL;
$parametersArray = array($person_id, $person_id, $limit, $offset); $parametersArray = $limitoffset
? array($person_id, $person_id, $limit, $offset)
: array($person_id, $person_id);
$count = 0; $count = 0;
$data = $this->execQuery($sql, $parametersArray); $data = $this->execQuery($sql, $parametersArray);
@@ -325,7 +327,7 @@ EOSQL;
$data = getData($data); $data = getData($data);
if($data) if($data)
{ {
$count = ceil($data[0]->total_msgs / $limit); $count = is_null($limit) ? 1 : ceil($data[0]->total_msgs / $limit);
} }
return success(['data' => $data, 'count' => $count]); return success(['data' => $data, 'count' => $count]);
@@ -0,0 +1,11 @@
<?php
class VertragsbestandteilLohnguide_model extends DB_Model
{
public function __construct()
{
parent::__construct();
$this->dbTable = 'hr.tbl_vertragsbestandteil_lohnguide';
$this->pk = 'vertragsbestandteil_id';
}
}
@@ -37,7 +37,8 @@ class Vertragsbestandteil_model extends DB_Model
kf.arbeitgeber_frist, kf.arbeitnehmer_frist, kf.arbeitgeber_frist, kf.arbeitnehmer_frist,
s.wochenstunden, s.teilzeittyp_kurzbz, s.wochenstunden, s.teilzeittyp_kurzbz,
u.tage, u.tage,
z.zeitaufzeichnung, z.azgrelevant, z.homeoffice z.zeitaufzeichnung, z.azgrelevant, z.homeoffice,
lg.stellenbezeichnung, lg.vordienstzeit, lg.fachrichtung_kurzbz, lg.modellstelle_kurzbz, lg.kommentar_person, lg.kommentar_modellstelle
FROM FROM
hr.tbl_vertragsbestandteil v hr.tbl_vertragsbestandteil v
LEFT JOIN LEFT JOIN
@@ -63,6 +64,8 @@ class Vertragsbestandteil_model extends DB_Model
hr.tbl_vertragsbestandteil_urlaubsanspruch u USING(vertragsbestandteil_id) hr.tbl_vertragsbestandteil_urlaubsanspruch u USING(vertragsbestandteil_id)
LEFT JOIN LEFT JOIN
hr.tbl_vertragsbestandteil_zeitaufzeichnung z USING(vertragsbestandteil_id) hr.tbl_vertragsbestandteil_zeitaufzeichnung z USING(vertragsbestandteil_id)
LEFT JOIN
hr.tbl_vertragsbestandteil_lohnguide lg USING(vertragsbestandteil_id)
EOSQL; EOSQL;
return $sql; return $sql;
} }
@@ -8,9 +8,15 @@ $this->load->view(
'axios027' => true, 'axios027' => true,
'restclient' => true, 'restclient' => true,
'vue3' => true, 'vue3' => true,
'customJSModules' => ['public/js/apps/Dashboard.js'], 'primevue3' => true,
'vuedatepicker11' => true,
'customJSs' => [
'vendor/moment/luxonjs/luxon.min.js'
],
'customJSModules' => ['public/js/apps/Dashboard/Admin.js'],
'customCSSs' => [ 'customCSSs' => [
'public/css/components/dashboard.css' 'public/css/components/dashboard.css',
'public/css/components/primevue.css',
], ],
'navigationcomponent' => true 'navigationcomponent' => true
) )
@@ -25,7 +31,7 @@ $this->load->view(
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Dashboard</h1> <h1 class="h2">Dashboard</h1>
</div> </div>
<core-dashboard dashboard="CIS" apiurl="<?= site_url('dashboard'); ?>"></core-dashboard> <dashboard-admin></dashboard-admin>
</div> </div>
</div> </div>
@@ -8,7 +8,12 @@ $this->load->view(
'axios027' => true, 'axios027' => true,
'restclient' => true, 'restclient' => true,
'vue3' => true, 'vue3' => true,
'customJSModules' => ['public/js/apps/DashboardAdmin.js'], 'vuedatepicker11' => true,
'primevue3' => true,
'customJSs' => [
'vendor/moment/luxonjs/luxon.min.js'
],
'customJSModules' => ['public/js/apps/Dashboard/Preview.js'],
'customCSSs' => [ 'customCSSs' => [
'public/css/components/dashboard.css' 'public/css/components/dashboard.css'
], ],
@@ -23,9 +28,9 @@ $this->load->view(
<div id="content"> <div id="content">
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom"> <div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
<h1 class="h2">Dashboard</h1> <h1 class="h2">Dashboard <?= $dashboard_kurzbz ?></h1>
</div> </div>
<dashboard-admin dashboard="CIS" apiurl="<?= site_url('dashboard'); ?>"></dashboard-admin> <core-dashboard dashboard="<?= $dashboard_kurzbz ?>"></core-dashboard>
</div> </div>
</div> </div>
+6 -4
View File
@@ -46,12 +46,13 @@ echo '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<link rel="stylesheet" href="../../../skin/tablesort.css" type="text/css"/> <link rel="stylesheet" href="../../../skin/tablesort.css" type="text/css"/>
<link rel="stylesheet" href="../../../skin/style.css.php" type="text/css"> <link rel="stylesheet" href="../../../skin/style.css.php" type="text/css">
<link rel="stylesheet" type="text/css" href="../../../skin/jquery-ui-1.9.2.custom.min.css"> <link rel="stylesheet" type="text/css" href="../../../skin/jquery-ui-1.9.2.custom.min.css">
<script type="text/javascript" src="../../../vendor/jquery/jquery1/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="../../../vendor/christianbach/tablesorter/jquery.tablesorter.min.js"></script>
<script type="text/javascript" src="../../../vendor/components/jqueryui/jquery-ui.min.js"></script> <script type="text/javascript" src="../../../vendor/components/jqueryui/jquery-ui.min.js"></script>
<script type="text/javascript" src="../../../include/js/jquery.ui.datepicker.translation.js"></script> <script type="text/javascript" src="../../../include/js/jquery.ui.datepicker.translation.js"></script>
<script type="text/javascript" src="../../../vendor/jquery/sizzle/sizzle.js"></script>'; <script type="text/javascript" src="../../../vendor/jquery/sizzle/sizzle.js"></script>';
include('../../../include/meta/jquery.php');
include('../../../include/meta/jquery-tablesorter.php');
const MOODLE_ADDON_KURZBZ = 'moodle'; const MOODLE_ADDON_KURZBZ = 'moodle';
// Load Addons to get Moodle_Path // Load Addons to get Moodle_Path
@@ -71,7 +72,7 @@ echo '
$("#myTable").tablesorter( $("#myTable").tablesorter(
{ {
sortList: [[0,0],[1,0]], sortList: [[0,0],[1,0]],
widgets: [\'zebra\'] widgets: [\'zebra\',\'filter\']
}); });
} }
); );
@@ -151,8 +152,9 @@ foreach($service->result as $row)
$person = new person(); $person = new person();
$person->getPersonFromBenutzer($row->operativ_uid); $person->getPersonFromBenutzer($row->operativ_uid);
$operativ = $person->nachname.' '.$person->vorname; $operativ = $person->nachname.' '.$person->vorname;
$oeBez = new organisationseinheit($row->oe_kurzbz);
echo '<tr>'; echo '<tr>';
echo '<td>',$row->oe_kurzbz,'</td>'; echo '<td>',$oeBez->bezeichnung,'</td>';
echo '<td><b>'.$row->bezeichnung.'</b></td>'; echo '<td><b>'.$row->bezeichnung.'</b></td>';
echo '<td>',$row->beschreibung,'</td>'; echo '<td>',$row->beschreibung,'</td>';
echo '<td><nobr><a href="../profile/index.php?uid='.$row->design_uid.'">',$design,'</a></nobr></td>'; echo '<td><nobr><a href="../profile/index.php?uid='.$row->design_uid.'">',$design,'</a></nobr></td>';
+1 -1
View File
@@ -293,7 +293,7 @@ else if (isset($_SESSION['pruefling_id']))
} }
$lastsemester = $row->semester; $lastsemester = $row->semester;
echo '<table border="0" cellspacing="0" cellpadding="0" id="Gebiet" style="display: visible; border-collapse: separate; border-spacing: 0 3px;">'; echo '<table border="0" cellspacing="0" cellpadding="0" id="Gebiet" style="display: visible; border-collapse: separate; border-spacing: 0 3px; margin-top: 5px;">';
echo '<tr><td class="HeaderTesttool">'. ($row->semester == '1' ? $p->t('testtool/basisgebiete') : $p->t('testtool/quereinstiegsgebiete')).'</td></tr>'; echo '<tr><td class="HeaderTesttool">'. ($row->semester == '1' ? $p->t('testtool/basisgebiete') : $p->t('testtool/quereinstiegsgebiete')).'</td></tr>';
} }
@@ -342,6 +342,8 @@ echo '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>';
<vbox> <vbox>
<checkbox id="mitarbeiter-entwicklungsteam-detail-checkbox-neu" checked="true" hidden="true" /> <checkbox id="mitarbeiter-entwicklungsteam-detail-checkbox-neu" checked="true" hidden="true" />
<textbox id="mitarbeiter-entwicklungsteam-detail-textbox-studiengang" hidden="true" /> <textbox id="mitarbeiter-entwicklungsteam-detail-textbox-studiengang" hidden="true" />
<textbox id="mitarbeiter-entwicklungsteam-detail-entwicklungsteam_id" hidden="true" />
<groupbox id="mitarbeiter-entwicklungsteam-detail-groupbox" flex="1"> <groupbox id="mitarbeiter-entwicklungsteam-detail-groupbox" flex="1">
<caption label="Details" /> <caption label="Details" />
<grid id="mitarbeiter-entwicklungsteam-detail-grid" style="margin:4px;" flex="1"> <grid id="mitarbeiter-entwicklungsteam-detail-grid" style="margin:4px;" flex="1">
@@ -1708,6 +1708,7 @@ function MitarbeiterEntwicklungsteamSelect()
document.getElementById('mitarbeiter-entwicklungsteam-detail-textbox-studiengang').value=studiengang_kz; document.getElementById('mitarbeiter-entwicklungsteam-detail-textbox-studiengang').value=studiengang_kz;
document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-beginn').value=beginn; document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-beginn').value=beginn;
document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-ende').value=ende; document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-ende').value=ende;
document.getElementById('mitarbeiter-entwicklungsteam-detail-entwicklungsteam_id').value=entwicklungsteam_id;
MitarbeiterEntwicklungsteamDetailDisableFields(false); MitarbeiterEntwicklungsteamDetailDisableFields(false);
} }
@@ -1725,6 +1726,7 @@ function MitarbeiterEntwicklungsteamSpeichern()
studiengang_kz_old = document.getElementById('mitarbeiter-entwicklungsteam-detail-textbox-studiengang').value; studiengang_kz_old = document.getElementById('mitarbeiter-entwicklungsteam-detail-textbox-studiengang').value;
beginn = document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-beginn').value; beginn = document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-beginn').value;
ende = document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-ende').value; ende = document.getElementById('mitarbeiter-entwicklungsteam-detail-datum-ende').value;
entwicklungsteam_id = document.getElementById('mitarbeiter-entwicklungsteam-detail-entwicklungsteam_id').value;
if(studiengang_kz=='') if(studiengang_kz=='')
{ {
@@ -798,6 +798,14 @@ echo '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>';
class="sortDirectionIndicator" class="sortDirectionIndicator"
sort="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#updatevon" /> sort="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#updatevon" />
<splitter class="tree-splitter"/> <splitter class="tree-splitter"/>
<treecol id="student-prestudent-tree-rolle-fgm" label="FGM" flex="1" hidden="true" persist="hidden, width, ordinal"
class="sortDirectionIndicator"
sort="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#fgm" />
<splitter class="tree-splitter"/>
<treecol id="student-prestudent-tree-rolle-faktiv" label="F-Aktiv" flex="1" hidden="true" persist="hidden, width, ordinal"
class="sortDirectionIndicator"
sort="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#faktiv" />
<splitter class="tree-splitter"/>
</treecols> </treecols>
<template> <template>
@@ -823,6 +831,8 @@ echo '<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>';
<treecell properties="Aktiv_rdf:http://www.technikum-wien.at/prestudentrolle/rdf#aktiv rdf:http://www.technikum-wien.at/prestudentrolle/rdf#stichtagsaktiv" label="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#insertvon"/> <treecell properties="Aktiv_rdf:http://www.technikum-wien.at/prestudentrolle/rdf#aktiv rdf:http://www.technikum-wien.at/prestudentrolle/rdf#stichtagsaktiv" label="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#insertvon"/>
<treecell properties="Aktiv_rdf:http://www.technikum-wien.at/prestudentrolle/rdf#aktiv rdf:http://www.technikum-wien.at/prestudentrolle/rdf#stichtagsaktiv" label="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#updateamum"/> <treecell properties="Aktiv_rdf:http://www.technikum-wien.at/prestudentrolle/rdf#aktiv rdf:http://www.technikum-wien.at/prestudentrolle/rdf#stichtagsaktiv" label="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#updateamum"/>
<treecell properties="Aktiv_rdf:http://www.technikum-wien.at/prestudentrolle/rdf#aktiv rdf:http://www.technikum-wien.at/prestudentrolle/rdf#stichtagsaktiv" label="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#updatevon"/> <treecell properties="Aktiv_rdf:http://www.technikum-wien.at/prestudentrolle/rdf#aktiv rdf:http://www.technikum-wien.at/prestudentrolle/rdf#stichtagsaktiv" label="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#updatevon"/>
<treecell properties="Aktiv_rdf:http://www.technikum-wien.at/prestudentrolle/rdf#aktiv rdf:http://www.technikum-wien.at/prestudentrolle/rdf#stichtagsaktiv" label="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#fgm"/>
<treecell properties="Aktiv_rdf:http://www.technikum-wien.at/prestudentrolle/rdf#aktiv rdf:http://www.technikum-wien.at/prestudentrolle/rdf#stichtagsaktiv" label="rdf:http://www.technikum-wien.at/prestudentrolle/rdf#faktiv"/>
</treerow> </treerow>
</treeitem> </treeitem>
</treechildren> </treechildren>
+10
View File
@@ -3550,9 +3550,19 @@ function StudentZeugnisDokumentArchivieren()
case 'microcredentialzertifikat_1': case 'microcredentialzertifikat_1':
case 'microcredentialzertifikat_2': case 'microcredentialzertifikat_2':
case 'microcredentialzertifikat_3': case 'microcredentialzertifikat_3':
case 'microcredentialzertifikat_4':
case 'microcredential_1': case 'microcredential_1':
case 'microcredential_2': case 'microcredential_2':
case 'microcredential_3': case 'microcredential_3':
case 'microcredential_4':
case 'microdegree_1':
case 'microdegree_2':
case 'microdegree_3':
case 'microdegree_4':
case 'microdegreeabschluss_1':
case 'microdegreeabschluss_2':
case 'microdegreeabschluss_3':
case 'microdegreeabschluss_4':
xml = 'microcredential.xml.php'; xml = 'microcredential.xml.php';
break; break;
+3 -1
View File
@@ -364,9 +364,10 @@ class entwicklungsteam extends basis_db
$bismeldung_jahr = $datetime->format('Y'); $bismeldung_jahr = $datetime->format('Y');
//laden des Datensatzes //laden des Datensatzes
$qry = "SELECT * $qry = "SELECT tbl_entwicklungsteam.*, tbl_besqual.*, tbl_studiengang.studiengang_kz, tbl_studiengang.melderelevant
FROM bis.tbl_entwicklungsteam FROM bis.tbl_entwicklungsteam
JOIN bis.tbl_besqual USING(besqualcode) JOIN bis.tbl_besqual USING(besqualcode)
JOIN public.tbl_studiengang USING(studiengang_kz)
WHERE mitarbeiter_uid=".$this->db_add_param($mitarbeiter_uid)." WHERE mitarbeiter_uid=".$this->db_add_param($mitarbeiter_uid)."
AND (beginn is NULL OR beginn <= make_date(". $this->db_add_param($bismeldung_jahr). "::INTEGER, 12, 31)) AND (beginn is NULL OR beginn <= make_date(". $this->db_add_param($bismeldung_jahr). "::INTEGER, 12, 31))
AND (ende is NULL OR ende >= make_date(". $this->db_add_param($bismeldung_jahr). "::INTEGER, 1, 1))"; AND (ende is NULL OR ende >= make_date(". $this->db_add_param($bismeldung_jahr). "::INTEGER, 1, 1))";
@@ -394,6 +395,7 @@ class entwicklungsteam extends basis_db
$obj->insertvon = $row->insertvon; $obj->insertvon = $row->insertvon;
$obj->ext_id = $row->ext_id; $obj->ext_id = $row->ext_id;
$obj->besqual = $row->besqualbez; $obj->besqual = $row->besqualbez;
$obj->melderelevant = $this->db_parse_bool($row->melderelevant);
$this->result[] = $obj; $this->result[] = $obj;
} }
+49 -1
View File
@@ -25,6 +25,7 @@
*/ */
require_once(dirname(__FILE__).'/basis_db.class.php'); require_once(dirname(__FILE__).'/basis_db.class.php');
require_once(dirname(__FILE__).'/'.EXT_FKT_PATH.'/generateZahlungsreferenz.inc.php'); require_once(dirname(__FILE__).'/'.EXT_FKT_PATH.'/generateZahlungsreferenz.inc.php');
require_once(dirname(__FILE__).'/variable.class.php');
class konto extends basis_db class konto extends basis_db
{ {
@@ -432,6 +433,8 @@ class konto extends basis_db
$qry.=" ORDER BY beschreibung"; $qry.=" ORDER BY beschreibung";
$oehBeitrag = $this->_getOEHBeitrag();
if($this->db_query($qry)) if($this->db_query($qry))
{ {
while($row = $this->db_fetch_object()) while($row = $this->db_fetch_object())
@@ -440,7 +443,15 @@ class konto extends basis_db
$typ->buchungstyp_kurzbz = $row->buchungstyp_kurzbz; $typ->buchungstyp_kurzbz = $row->buchungstyp_kurzbz;
$typ->beschreibung = $row->beschreibung; $typ->beschreibung = $row->beschreibung;
$typ->standardbetrag = $row->standardbetrag; if (strtolower($typ->buchungstyp_kurzbz) === 'oeh' && $oehBeitrag)
{
$typ->standardbetrag = $oehBeitrag;
}
else
{
$typ->standardbetrag = $row->standardbetrag;
}
$typ->standardtext = $row->standardtext; $typ->standardtext = $row->standardtext;
$typ->credit_points = $row->credit_points; $typ->credit_points = $row->credit_points;
$typ->aktiv = $this->db_parse_bool($row->aktiv); $typ->aktiv = $this->db_parse_bool($row->aktiv);
@@ -990,6 +1001,43 @@ class konto extends basis_db
return false; return false;
} }
} }
private function _getOEHBeitrag()
{
if(!is_user_logged_in())
{
return false;
}
$variablen_obj = new variable();
$variablen_obj->loadVariables(get_uid());
$qry = "WITH semstart AS (
SELECT start FROM public.tbl_studiensemester
WHERE studiensemester_kurzbz = '". $this->db_escape($variablen_obj->variable->semester_aktuell) . "'
)
SELECT * FROM bis.tbl_oehbeitrag oehb
JOIN public.tbl_studiensemester semvon ON oehb.von_studiensemester_kurzbz = semvon.studiensemester_kurzbz
LEFT JOIN public.tbl_studiensemester sembis ON oehb.bis_studiensemester_kurzbz = sembis.studiensemester_kurzbz
JOIN semstart ON semstart.start::date >= semvon.start::date AND (sembis.studiensemester_kurzbz IS NULL OR semstart.start::date <= sembis.start::date)
ORDER BY semvon.start
LIMIT 1";
if ($this->db_query($qry))
{
if($row = $this->db_fetch_object())
{
$summe = ($row->studierendenbeitrag + $row->versicherung) * -1;
return number_format((float)$summe, 2, '.', '');
}
return false;
}
else
{
$this->errormsg = 'Fehler bei der Abfrage aufgetreten';
return false;
}
}
} }
?> ?>
+164 -7
View File
@@ -552,9 +552,41 @@ class lehreinheitmitarbeiter extends basis_db
$beginn = new DateTime($beginn); $beginn = new DateTime($beginn);
$ende = new DateTime($ende); $ende = new DateTime($ende);
// get relevant Studiensemester
$studiensemester_kurzbz_arr = [];
$qry = '
SELECT
studiensemester_kurzbz
FROM
public.tbl_studiensemester
WHERE
start BETWEEN
'. $this->db_add_param($beginn->format('Y-m-d')). ' AND
'. $this->db_add_param($ende->format('Y-m-d'));
if ($this->db_query($qry))
{
while($row = $this->db_fetch_object())
{
$studiensemester_kurzbz_arr[] = $row->studiensemester_kurzbz;
}
}
else
{
$this->errormsg = 'Fehler bei der Datenbankabfrage';
return false;
}
$lehrgaengeDistr = $this->_getLehrgaengeForDistribution($studiensemester_kurzbz_arr);
if (!is_array($studiensemester_kurzbz_arr) || empty($studiensemester_kurzbz_arr)) return true;
$qry = ' $qry = '
WITH semester_sws_tbl AS ( WITH semester_sws_tbl AS (
SELECT DISTINCT lehreinheit_id, studiensemester_kurzbz, lema.semesterstunden, stg.studiengang_kz SELECT
DISTINCT lehreinheit_id, studiensemester_kurzbz, lema.semesterstunden,
stg.studiengang_kz, stg.melde_studiengang_kz, stg.lgartcode, stg.melderelevant
FROM lehre.tbl_lehreinheitmitarbeiter lema FROM lehre.tbl_lehreinheitmitarbeiter lema
JOIN lehre.tbl_lehreinheit USING (lehreinheit_id) JOIN lehre.tbl_lehreinheit USING (lehreinheit_id)
JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id) JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id)
@@ -564,38 +596,104 @@ class lehreinheitmitarbeiter extends basis_db
JOIN public.tbl_studiengang stg ON stg.studiengang_kz = sto.studiengang_kz JOIN public.tbl_studiengang stg ON stg.studiengang_kz = sto.studiengang_kz
JOIN public.tbl_studiensemester ss USING (studiensemester_kurzbz) JOIN public.tbl_studiensemester ss USING (studiensemester_kurzbz)
WHERE mitarbeiter_uid = '. $this->db_add_param($uid). ' WHERE mitarbeiter_uid = '. $this->db_add_param($uid). '
AND ( AND ss.studiensemester_kurzbz IN ('.$this->implode4SQL($studiensemester_kurzbz_arr).')
ss.start BETWEEN
'. $this->db_add_param($beginn->format('Y-m-d')). ' AND
'. $this->db_add_param($ende->format('Y-m-d')). ')
-- nur lehre, die bisgemeldet wird -- nur lehre, die bisgemeldet wird
AND lema.bismelden AND lema.bismelden
AND stg.melderelevant
-- keine lehreinheiten ohne semesterstunden -- keine lehreinheiten ohne semesterstunden
AND lema.semesterstunden != 0 AND lema.semesterstunden != 0
) )
SELECT SELECT
studiengang_kz, studiengang_kz,
studiensemester_kurzbz, studiensemester_kurzbz,
melde_studiengang_kz,
lgartcode,
sum(semesterstunden) AS summe, sum(semesterstunden) AS summe,
round(sum(semesterstunden) / 15, 2) AS sws round(sum(semesterstunden) / 15, 2) AS sws
FROM FROM
semester_sws_tbl semester_sws_tbl
GROUP BY GROUP BY
studiengang_kz, studiengang_kz,
studiensemester_kurzbz studiensemester_kurzbz,
melde_studiengang_kz,
lgartcode
ORDER BY ORDER BY
studiengang_kz; studiengang_kz;
'; ';
if ($this->db_query($qry)) if ($this->db_query($qry))
{ {
$additionalLehrgaenge = [];
while($row = $this->db_fetch_object()) while($row = $this->db_fetch_object())
{ {
$obj = new StdClass(); $obj = new StdClass();
$obj->studiengang_kz = $row->studiengang_kz; $obj->studiengang_kz = $row->studiengang_kz;
$obj->studiensemester_kurzbz = $row->studiensemester_kurzbz; $obj->studiensemester_kurzbz = $row->studiensemester_kurzbz;
$obj->melde_studiengang_kz = $row->melde_studiengang_kz;
$obj->lgartcode = $row->lgartcode;
$obj->sws = $row->sws; $obj->sws = $row->sws;
if (isset($lehrgaengeDistr[$uid][$row->studiensemester_kurzbz]))
{
$lehrgaenge = $lehrgaengeDistr[$uid][$row->studiensemester_kurzbz];
foreach ($lehrgaenge as $lehreinheit_id => $lehrgangKzArr)
{
// wenn lehrgang gefunden, zusammenhängende Lehrgaenge holen und sws aufteilen
if (array_key_exists($row->studiengang_kz, $lehrgangKzArr))
{
foreach ($lehrgangKzArr as $studiengang_kz => $lehrgang)
{
// check: nur eine Studiengangsverknüpfung pro Mitarbeiter, Semester, und Referenzstudiengang
if (
$studiengang_kz == $row->studiengang_kz
|| isset(
$additionalLehrgaenge[$uid][$row->studiensemester_kurzbz][$row->studiengang_kz][$studiengang_kz]
)
) continue;
// Lehrgang erstellen
$lg = new StdClass();
$lg->mitarbeiter_uid = $uid;
$lg->melde_studiengang_kz = $lehrgang->melde_studiengang_kz;
$lg->lgartcode = $lehrgang->lgartcode;
$lg->studiengang_kz = $lehrgang->studiengang_kz;
$lg->studiensemester_kurzbz = $lehrgang->studiensemester_kurzbz;
$lg->summe = $row->summe;
$lg->sws = $row->sws;
// Lehrgang, der mit Ursprungsstudiengang aufgrund lehreinheit "verknüpft" ist, hinzufügen
$additionalLehrgaenge[$uid][$row->studiensemester_kurzbz][$row->studiengang_kz][$studiengang_kz] = $lg;
}
}
}
// ignorieren, wenn für den Studiengang keine verknüpften Lehrgaenge hat
if (isset($additionalLehrgaenge[$uid][$row->studiensemester_kurzbz][$row->studiengang_kz]))
{
$addLehrgaenge = $additionalLehrgaenge[$uid][$row->studiensemester_kurzbz][$row->studiengang_kz];
// sws Durchschnitt über alle verknuepften Lehrgaenge berechnet
$summeSws = $row->summe/(count($addLehrgaenge) + 1);
$sws = $row->sws/(count($addLehrgaenge) + 1);
// neue sws zuweisen
$obj->summe = $summeSws;
$obj->sws = $sws;
foreach ($addLehrgaenge as $conn_ws_studiengang_kz => $lehrgang)
{
// sws fuer jeden verknuepften Lehrgang zuweisen
$lehrgang->summe = $summeSws;
$lehrgang->sws = $sws;
// neue lehrgang sws hinzufuegen
$this->result [] = $lehrgang;
}
}
}
$this->result []= $obj; $this->result []= $obj;
} }
return true; return true;
@@ -655,4 +753,63 @@ class lehreinheitmitarbeiter extends basis_db
return false; return false;
} }
/**
* Get "connected" Lehrgaenge for equal sws distribution.
* @param $studiensemester_kurzbz_arr all semester for which Lehrgaenge should be retrieved
* @return object success or error
*/
private function _getLehrgaengeForDistribution($studiensemester_kurzbz_arr)
{
if (!is_array($studiensemester_kurzbz_arr) || empty($studiensemester_kurzbz_arr)) return [];
$qry = "
WITH gruppen AS (
SELECT
mitarbeiter_uid, lehreinheit_id, lehrveranstaltung_id, studiensemester_kurzbz, sem.start, sem.ende,
lehreinheitgruppe_id, studiengang_kz, melde_studiengang_kz, lgartcode
FROM
lehre.tbl_lehreinheitmitarbeiter lema
JOIN lehre.tbl_lehreinheit le USING (lehreinheit_id)
JOIN lehre.tbl_lehreinheitgruppe legr USING (lehreinheit_id)
JOIN public.tbl_studiengang stg USING (studiengang_kz)
JOIN public.tbl_studiensemester sem USING (studiensemester_kurzbz)
WHERE
bismelden
AND stg.melderelevant
AND stg.typ = 'l'
AND le.studiensemester_kurzbz IN (".$this->implode4SQL($studiensemester_kurzbz_arr).")
)
SELECT
DISTINCT mitarbeiter_uid, studiensemester_kurzbz, lehreinheit_id, studiengang_kz, melde_studiengang_kz, lgartcode
FROM
gruppen gr
GROUP BY
mitarbeiter_uid, studiensemester_kurzbz, lehreinheit_id, studiengang_kz, melde_studiengang_kz, lgartcode
ORDER BY
mitarbeiter_uid, studiensemester_kurzbz, lehreinheit_id, studiengang_kz, melde_studiengang_kz, lgartcode";
$lehrgaengeDistributions = [];
if($this->db_query($qry))
{
while($row = $this->db_fetch_object())
{
// group by properties
$lehrgaengeDistributions
[$row->mitarbeiter_uid]
[$row->studiensemester_kurzbz]
[$row->lehreinheit_id]
[$row->studiengang_kz]
= $row;
}
}
else
{
$this->errormsg = 'Fehler bei der Datenbankabfrage';
return false;
}
return $lehrgaengeDistributions;
}
} }
+2
View File
@@ -270,6 +270,8 @@ class LehreListHelper
} else if ($row->bisio_id != '' && $row->status != 'Incoming' && ($row->von > $stsemdatumvon || $row->von == '')) { } else if ($row->bisio_id != '' && $row->status != 'Incoming' && ($row->von > $stsemdatumvon || $row->von == '')) {
// if bis datum is not yet known but von is available already // if bis datum is not yet known but von is available already
$zusatz .= '(o)(ab '.$datum->formatDatum($row->von, 'd.m.Y').')'; $zusatz .= '(o)(ab '.$datum->formatDatum($row->von, 'd.m.Y').')';
} else if ($row->bisio_id != '' && $row->status != 'Incoming' && ($row->von <= $stsemdatumvon || $row->von == '') && ($row->bis == '' || $row->bis > date('Y-m-d'))){
$zusatz .= '(o)(ab '.$datum->formatDatum($row->von, 'd.m.Y').')';
} }
+2
View File
@@ -705,6 +705,8 @@ class prestudent extends person
$rolle->studienplan_bezeichnung = $row->studienplan_bezeichnung; $rolle->studienplan_bezeichnung = $row->studienplan_bezeichnung;
$rolle->bestaetigtam = $row->bestaetigtam; $rolle->bestaetigtam = $row->bestaetigtam;
$rolle->bestaetigtvon = $row->bestaetigtvon; $rolle->bestaetigtvon = $row->bestaetigtvon;
$rolle->fgm = $row->fgm;
$rolle->faktiv = $this->db_parse_bool($row->faktiv);
$rolle->anmerkung_status = $row->anmerkung; $rolle->anmerkung_status = $row->anmerkung;
$rolle->bewerbung_abgeschicktamum = $row->bewerbung_abgeschicktamum; $rolle->bewerbung_abgeschicktamum = $row->bewerbung_abgeschicktamum;
$rolle->rt_stufe = $row->rt_stufe; $rolle->rt_stufe = $row->rt_stufe;
-4
View File
@@ -197,10 +197,6 @@ html.fs_huge {
margin-bottom: -1px; margin-bottom: -1px;
} }
.tiny-90 div.tox.tox-tinymce {
height: 90% !important;
}
/* slim begin */ /* slim begin */
.stv .form-label { .stv .form-label {
margin-bottom: .15rem; margin-bottom: .15rem;
+3
View File
@@ -193,3 +193,6 @@
word-break: break-word; word-break: break-word;
} }
.news-list-item p {
word-break: break-word;
}
+46
View File
@@ -0,0 +1,46 @@
/**
* 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 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 {
list() {
return {
method: 'get',
url: 'api/frontend/v1/dashboard/board/list'
};
},
add(params) {
return {
method: 'post',
url: 'api/frontend/v1/dashboard/board/create',
params
};
},
update(params) {
return {
method: 'post',
url: 'api/frontend/v1/dashboard/board/update',
params
};
},
delete(dashboard_id) {
return {
method: 'post',
url: 'api/frontend/v1/dashboard/board/delete',
params: { dashboard_id }
};
}
}
+47
View File
@@ -0,0 +1,47 @@
/**
* 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 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 {
list(dashboard_kurzbz) {
return {
method: 'get',
url: 'api/frontend/v1/dashboard/preset/list/'
+ encodeURIComponent(dashboard_kurzbz)
};
},
getBatch(params) {
return {
method: 'post',
url: 'api/frontend/v1/dashboard/preset/getBatch',
params
};
},
addWidget(params) {
return {
method: 'post',
url: 'api/frontend/v1/dashboard/preset/addWidget',
params
};
},
removeWidget(params) {
return {
method: 'post',
url: 'api/frontend/v1/dashboard/preset/removeWidget',
params
};
}
};
+45
View File
@@ -0,0 +1,45 @@
/**
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export default {
get(dashboard) {
return {
method: 'get',
url: '/api/frontend/v1/dashboard/user/get/' + dashboard
};
},
addWidget(dashboard, widget) {
return {
method: 'post',
url: '/api/frontend/v1/dashboard/user/addWidget',
params: {
dashboard,
widget
}
};
},
removeWidget(dashboard, widget) {
return {
method: 'post',
url: '/api/frontend/v1/dashboard/user/removeWidget',
params: {
dashboard,
widget
}
};
}
};
+46
View File
@@ -0,0 +1,46 @@
/**
* 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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export default {
get(widget) {
return {
method: 'get',
url: '/api/frontend/v1/dashboard/widget/get/' + widget
};
},
list(dashboard) {
return {
method: 'get',
url: '/api/frontend/v1/dashboard/widget/list/' + dashboard
};
},
listAllowed(dashboard) {
return {
method: 'get',
url: '/api/frontend/v1/dashboard/widget/listAllowed/' + dashboard
};
},
setAllowed(dashboard_id, widget_id, allowed) {
return {
method: 'post',
url: '/api/frontend/v1/dashboard/widget/setAllowed',
params: {
dashboard_id, widget_id, allowed
}
};
}
};
+8 -5
View File
@@ -17,13 +17,16 @@
export default { export default {
getMessages(params) { getMessages(params) {
let url = 'api/frontend/v1/messages/messages/getMessages'
+ '/' + params.id
+ '/' + params.type;
if(params.size && params.page) {
url += '/' + params.size
+ '/' + params.page;
}
return { return {
method: 'get', method: 'get',
url: 'api/frontend/v1/messages/messages/getMessages/' url: url
+ params.id + '/'
+ params.type + '/'
+ params.size + '/'
+ params.page
}; };
}, },
getVorlagen(){ getVorlagen(){
+15 -3
View File
@@ -38,6 +38,10 @@ export default {
}; };
}, },
insert(params) { insert(params) {
if(params.betrag)
{
params.betrag = params.betrag.replace(',', '.');
}
return { return {
method: 'post', method: 'post',
url: 'api/frontend/v1/stv/konto/insert', url: 'api/frontend/v1/stv/konto/insert',
@@ -52,6 +56,10 @@ export default {
}; };
}, },
edit(params) { edit(params) {
if(params.betrag)
{
params.betrag = params.betrag.replace(',', '.');
}
return { return {
method: 'post', method: 'post',
url: 'api/frontend/v1/stv/konto/update', url: 'api/frontend/v1/stv/konto/update',
@@ -65,10 +73,14 @@ export default {
params: { buchungsnr } params: { buchungsnr }
}; };
}, },
getBuchungstypen() { getBuchungstypen(studiensemester_kurzbz) {
let url = 'api/frontend/v1/stv/konto/getBuchungstypen'
if (!!studiensemester_kurzbz)
url = url + '/' + encodeURIComponent(studiensemester_kurzbz);
return { return {
method: 'get', method: 'get',
url: 'api/frontend/v1/stv/konto/getBuchungstypen' url: url
}; };
} },
}; };
+60 -9
View File
@@ -1,16 +1,67 @@
import {CoreNavigationCmpt} from '../../components/navigation/Navigation.js'; import { CoreNavigationCmpt } from '../../components/navigation/Navigation.js';
import DashboardAdmin from '../../components/Dashboard/Admin.js'; import DashboardAdmin from '../../components/Dashboard/Admin.js';
import PluginsPhrasen from '../../plugins/Phrasen.js'; import PluginsPhrasen from '../../plugins/Phrasen.js';
import ApiRenderers from '../../api/factory/renderers.js';
const app = Vue.createApp({ const app = Vue.createApp({
name: 'AdminApp', name: 'DashboardAdminApp',
data: () => ({ data: () => ({
appSideMenuEntries: {} appSideMenuEntries: {},
}), renderers: null
components: { }),
CoreNavigationCmpt, components: {
DashboardAdmin CoreNavigationCmpt,
} DashboardAdmin
},
provide() {
return {
// TODO(chris): move those two into the components that need it
renderers: Vue.computed(() => this.renderers),
timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone
};
},
created() {
this.$api
.call(ApiRenderers.loadRenderers())
.then(res => {
for (let rendertype of Object.keys(res.data)) {
let modalTitle = null;
let modalContent = null;
let calendarEvent = null;
if (res.data[rendertype].modalTitle)
modalTitle = Vue.markRaw(Vue.defineAsyncComponent(() => import(res.data[rendertype].modalTitle)));
if (res.data[rendertype].modalContent)
modalContent = Vue.markRaw(Vue.defineAsyncComponent(() => import(res.data[rendertype].modalContent)));
if (res.data[rendertype].calendarEvent)
calendarEvent = Vue.markRaw(Vue.defineAsyncComponent(() => import(res.data[rendertype].calendarEvent)));
if (res.data[rendertype].calendarEventStyles) {
var head = document.head;
if (!head.querySelector(`link[href="${res.data[rendertype].calendarEventStyles}"]`)) {
var link = document.createElement("link");
link.type = "text/css";
link.rel = "stylesheet";
link.href = res.data[rendertype].calendarEventStyles;
head.appendChild(link);
}
}
if (this.renderers === null) {
this.renderers = {};
}
if (!this.renderers[rendertype]) {
this.renderers[rendertype] = {}
}
this.renderers[rendertype].modalTitle = modalTitle;
this.renderers[rendertype].modalContent = modalContent;
this.renderers[rendertype].calendarEvent = calendarEvent;
}
})
.catch(this.$fhcAlert.handleSystemErrors);
}
}); });
app.use(PluginsPhrasen); app.use(PluginsPhrasen);
app.directive('tooltip', primevue.tooltip);
app.mount('#main'); app.mount('#main');
+17
View File
@@ -0,0 +1,17 @@
import {CoreNavigationCmpt} from '../../components/navigation/Navigation.js';
import CoreDashboard from '../../components/Dashboard/Dashboard.js';
import PluginsPhrasen from '../../plugins/Phrasen.js';
const app = Vue.createApp({
name: 'DashboardPreviewApp',
data: () => ({
appSideMenuEntries: {}
}),
components: {
CoreNavigationCmpt,
CoreDashboard
}
});
app.use(PluginsPhrasen);
app.directive('tooltip', primevue.tooltip);
app.mount('#main');
+1 -1
View File
@@ -17,7 +17,7 @@ export default {
</template> </template>
<template v-slot:footer> <template v-slot:footer>
<button type="button" class="btn btn-primary" @click="result=true;this.hide()">OK</button> <button type="button" class="btn btn-primary" @click="result=true;this.hide()">OK</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{{this.$p.t('ui', 'cancel')}}</button>
</template> </template>
</bs-modal>` </bs-modal>`
} }
@@ -180,7 +180,7 @@ export const AbgabetoolAssistenz = {
// frozen: true, // frozen: true,
// width: 40 // width: 40
// }, // },
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4details'))), field: 'details', headerFilter: false, headerSort: false, formatter: this.formAction, tooltip:false, minWidth: 150, cssClass: 'sticky-col'}, {title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4details'))), field: 'details', headerFilter: false, headerSort: false, formatter: this.formAction, tooltip:false, minWidth: 100, cssClass: 'sticky-col'},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4personenkennzeichen'))), headerFilter: true, field: 'pkz', formatter: this.pkzTextFormatter, widthGrow: 1, tooltip: false}, {title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4personenkennzeichen'))), headerFilter: true, field: 'pkz', formatter: this.pkzTextFormatter, widthGrow: 1, tooltip: false},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4vorname'))), field: 'student_vorname', headerFilter: true, formatter: this.centeredTextFormatter,widthGrow: 1}, {title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4vorname'))), field: 'student_vorname', headerFilter: true, formatter: this.centeredTextFormatter,widthGrow: 1},
{title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4nachname'))), field: 'student_nachname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1}, {title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4nachname'))), field: 'student_nachname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1},
@@ -226,7 +226,7 @@ export const AbgabetoolAssistenz = {
field: 'qgate2Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220, tooltip: false}, field: 'qgate2Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220, tooltip: false},
], ],
persistence: false, persistence: false,
persistenceID: "abgabetool_2026_02_26" persistenceID: "abgabetool_2026_03_16"
}, },
abgabeTableEventHandlers: [ abgabeTableEventHandlers: [
{ {
@@ -645,7 +645,7 @@ export const AbgabetoolAssistenz = {
actionButtons.className = "d-flex gap-3"; // you can keep Bootstrap gap if loaded actionButtons.className = "d-flex gap-3"; // you can keep Bootstrap gap if loaded
actionButtons.style.display = "flex"; actionButtons.style.display = "flex";
actionButtons.style.alignItems = "stretch"; // buttons stretch to full height actionButtons.style.alignItems = "stretch"; // buttons stretch to full height
actionButtons.style.justifyContent = "center"; actionButtons.style.justifyContent = "start";
actionButtons.style.height = "100%"; // full grid cell height actionButtons.style.height = "100%"; // full grid cell height
const val = cell.getValue(); const val = cell.getValue();
@@ -675,8 +675,20 @@ export const AbgabetoolAssistenz = {
createButton('fa fa-timeline', 'abgabetool/c4termineTimeLine', () => this.openTimeline(val)) createButton('fa fa-timeline', 'abgabetool/c4termineTimeLine', () => this.openTimeline(val))
); );
if(val.latestTerminWithUpload) {
actionButtons.append(
createButton('fa fa-download', 'abgabetool/c4downloadLatestAbgabe', () => this.downloadAbgabe(val.latestTerminWithUpload.paabgabe_id, val.student_uid, val.projektarbeit_id))
)
}
return actionButtons; return actionButtons;
}, },
downloadAbgabe(paabgabe_id, student_uid, projektarbeit_id) {
const url = `/api/frontend/v1/Abgabe/getStudentProjektarbeitAbgabeFile?paabgabe_id=${paabgabe_id}&student_uid=${student_uid}&projektarbeit_id=${projektarbeit_id}`;
window.open(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + url)
// this.$api.call(ApiAbgabe.getStudentProjektarbeitAbgabeFile(termin.paabgabe_id, this.projektarbeit.student_uid))
},
undoSelection(cell) { undoSelection(cell) {
// checks if cells row is selected and unselects -> imitates columns which dont trigger row selection // checks if cells row is selected and unselects -> imitates columns which dont trigger row selection
@@ -781,12 +793,15 @@ export const AbgabetoolAssistenz = {
projekt.note_bez = opt.bezeichnung projekt.note_bez = opt.bezeichnung
} }
const latestTerminWithUpload = this.findLatestTerminWithUpload(projekt)
return { return {
...projekt, ...projekt,
abgabetermine: projekt.abgabetermine, abgabetermine: projekt.abgabetermine,
details: { details: {
student_uid: projekt.student_uid, student_uid: projekt.student_uid,
projektarbeit_id: projekt.projektarbeit_id, projektarbeit_id: projekt.projektarbeit_id,
latestTerminWithUpload: latestTerminWithUpload ?? null
}, },
pkz: this.buildPKZ(projekt), pkz: this.buildPKZ(projekt),
beurteilung: projekt.beurteilungLink ?? null, beurteilung: projekt.beurteilungLink ?? null,
@@ -800,6 +815,15 @@ export const AbgabetoolAssistenz = {
} }
}) })
}, },
findLatestTerminWithUpload(projekt) {
const withAbgabedatumSorted = projekt?.abgabetermine?.filter(t => t.abgabedatum != null)?.sort((a,b) => a < b)
if(withAbgabedatumSorted.length) {
return withAbgabedatumSorted[0]
}
return null
},
createInfoString(data) { createInfoString(data) {
let str = ''; let str = '';
@@ -1413,9 +1437,12 @@ export const AbgabetoolAssistenz = {
<div id="abgabetable" style="max-height:40vw;"> <div id="abgabetable" style="max-height:40vw;">
<div class="row"> <div class="row">
<div class="col-auto"> <div class="col-auto me-auto">
<h2 tabindex="1">{{$p.t('abgabetool/abgabetoolTitle')}}</h2> <h2 tabindex="1">{{$p.t('abgabetool/abgabetoolTitle')}}</h2>
</div> </div>
<div class="col-auto">
<label class="col-form-label">{{$capitalize($p.t('lehre/studiengang'))}}:</label>
</div>
<div class="col-3"> <div class="col-3">
<Dropdown <Dropdown
:placeholder="$capitalize($p.t('lehre/studiengang'))" :placeholder="$capitalize($p.t('lehre/studiengang'))"
@@ -1430,6 +1457,9 @@ export const AbgabetoolAssistenz = {
</template> </template>
</Dropdown> </Dropdown>
</div> </div>
<div class="col-auto">
<label class="col-form-label">{{$capitalize($p.t('lehre/note'))}}:</label>
</div>
<div class="col-3"> <div class="col-3">
<Dropdown <Dropdown
:placeholder="$p.t('lehre/note')" :placeholder="$p.t('lehre/note')"
@@ -667,7 +667,9 @@ export const AbgabetoolMitarbeiter = {
setDetailComponent(details){ setDetailComponent(details){
this.loading=true this.loading=true
const pa = this.projektarbeiten?.retval?.find(projekarbeit => projekarbeit.projektarbeit_id == details.projektarbeit_id) const projektarbeiten = this.projektarbeiten?.retval ?? this.projektarbeiten
const pa = projektarbeiten.find(projekarbeit => projekarbeit.projektarbeit_id == details.projektarbeit_id)
let paIsBenotet = false let paIsBenotet = false
if(pa.note !== undefined && pa.note !== null) { if(pa.note !== undefined && pa.note !== null) {
+66 -34
View File
@@ -3,15 +3,20 @@ import DashboardAdminEdit from "./Admin/Edit.js";
import DashboardAdminWidgets from "./Admin/Widgets.js"; import DashboardAdminWidgets from "./Admin/Widgets.js";
import DashboardAdminPresets from "./Admin/Presets.js"; import DashboardAdminPresets from "./Admin/Presets.js";
import ApiDashboardBoard from "../../api/factory/dashboard/board.js";
import ApiDashboardWidget from "../../api/factory/dashboard/widget.js";
export default { export default {
name: 'DashboardAdmin',
components: { components: {
DashboardAdminEdit, DashboardAdminEdit,
DashboardAdminWidgets, DashboardAdminWidgets,
DashboardAdminPresets DashboardAdminPresets,
}, },
provide() { provide() {
return { return {
adminMode: true adminMode: true,
widgetsSetup: Vue.computed(() => this.dashboards[this.current] ? this.dashboards[this.current].widgetSetup : null)
}; };
}, },
data() { data() {
@@ -22,9 +27,6 @@ export default {
}; };
}, },
computed: { computed: {
apiurl() {
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/dashboard';
},
dashboard() { dashboard() {
return this.dashboards.find(el => el.dashboard_id == this.current); return this.dashboards.find(el => el.dashboard_id == this.current);
} }
@@ -35,33 +37,50 @@ export default {
BsPrompt.popup('New Dashboard name').then( BsPrompt.popup('New Dashboard name').then(
name => { name => {
_name = name; _name = name;
return axios.post(this.apiurl + '/Dashboard/create', { const params = {
dashboard_kurzbz: name dashboard_kurzbz: name
}) };
} return this.$api
).then(res => { .call(ApiDashboardBoard.add(params))
let newDashboard = { .then(response =>{
dashboard_id: res.data.retval, this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
dashboard_kurzbz: _name,
beschreibung: '' let newDashboard = {
}; dashboard_id: response.data,
this.dashboards.push(newDashboard); dashboard_kurzbz: _name,
this.current = newDashboard.dashboard_id; beschreibung: ''
}).catch(err => err !== undefined ? console.error('ERROR:', err) : 0); };
this.dashboards.push(newDashboard);
this.current = newDashboard.dashboard_id;
})
.catch(this.$fhcAlert.handleSystemError);
});
}, },
dashboardUpdate(dashboard) { dashboardUpdate(dashboard) {
// TODO(chris): Loading or message return this.$api
axios.post(this.apiurl + '/Dashboard/update', dashboard).then(() => { .call(ApiDashboardBoard.update(dashboard))
let old = this.dashboards.find(el => el.dashboard_id == dashboard.dashboard_id); .then(response =>{
old.dashboard_kurzbz = dashboard.dashboard_kurzbz;
old.beschreibung = dashboard.beschreibung; this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
}).catch(err => console.error('ERROR:', err));
let old = this.dashboards.find(el => el.dashboard_id == dashboard.dashboard_id);
old.dashboard_kurzbz = dashboard.dashboard_kurzbz;
old.beschreibung = dashboard.beschreibung;
})
.catch(this.$fhcAlert.handleSystemError);
}, },
dashboardDelete(dashboard_id) { dashboardDelete(dashboard_id) {
axios.post(this.apiurl + '/Dashboard/delete', {dashboard_id}).then(() => { return this.$api
this.current = -1; .call(ApiDashboardBoard.delete(dashboard_id))
this.dashboards = this.dashboards.filter(el => el.dashboard_id != dashboard_id); .then(response => {
}).catch(err => console.error('ERROR:', err)); this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'));
})
.catch(this.$fhcAlert.handleSystemError)
.finally(() => {
this.current = -1;
this.dashboards = this.dashboards.filter(el => el.dashboard_id != dashboard_id);
});
}, },
assignWidgets(widgets) { assignWidgets(widgets) {
this.widgets = widgets; this.widgets = widgets;
@@ -72,22 +91,35 @@ export default {
} }
}, },
created() { created() {
axios.get(this.apiurl + '/Dashboard').then(res => { this.$api
this.dashboards = res.data.retval; .call(ApiDashboardBoard.list())
}).catch(err => console.error('ERROR:', err)); .then(result => {
this.dashboards = result.data.retval;
for (const dashboard of this.dashboards) {
this.$api
.call(ApiDashboardWidget.list(dashboard.dashboard_id))
.then(res => {
dashboard.widgetSetup = res.data;
})
.catch(this.$fhcAlert.handleSystemError);
}
})
.catch(this.$fhcAlert.handleSystemError);
}, },
template: `<div class="dashboard-admin"> template: `<div class="dashboard-admin">
<div class="input-group"> <div class="input-group">
<label for="dashbaord-select" class="input-group-text">Dashboard:</label> <label for="dashboard-select" class="input-group-text">Dashboard:</label>
<select id="dashbaord-select" class="form-select" v-model="current"> <select id="dashboard-select" class="form-select" v-model="current">
<option v-for="dashboard in dashboards" :key="dashboard.dashboard_id" :value="dashboard.dashboard_id">{{dashboard.dashboard_kurzbz}}</option> <option v-for="dashboard in dashboards" :key="dashboard.dashboard_id" :value="dashboard.dashboard_id">{{dashboard.dashboard_kurzbz}}</option>
</select> </select>
<button class="btn btn-outline-secondary" type="button" @click="dashboardAdd"><i class="fa-solid fa-plus"></i></button> <button class="btn btn-outline-secondary" type="button" @click="dashboardAdd"><i class="fa-solid fa-plus"></i></button>
</div> </div>
<div v-if="dashboard"> <div v-if="dashboard">
<ul class="nav nav-tabs mt-3" role="tablist"> <ul class="nav nav-tabs mt-3" role="tablist">
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link" id="edit-tab" data-bs-toggle="tab" data-bs-target="#edit" type="button" role="tab" aria-controls="edit" aria-selected="false">Edit</button> <button class="nav-link" id="edit-tab" data-bs-toggle="tab" data-bs-target="#edit" type="button" role="tab" aria-controls="edit" aria-selected="false">{{this.$p.t('ui', 'bearbeiten')}}</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<button class="nav-link active" id="widgets-tab" data-bs-toggle="tab" data-bs-target="#widgets" type="button" role="tab" aria-controls="widgets" aria-selected="true">Widgets</button> <button class="nav-link active" id="widgets-tab" data-bs-toggle="tab" data-bs-target="#widgets" type="button" role="tab" aria-controls="widgets" aria-selected="true">Widgets</button>
@@ -101,7 +133,7 @@ export default {
<dashboard-admin-edit v-bind="dashboard" :key="dashboard.dashboard_id" @change="dashboardUpdate($event)" @delete="dashboardDelete($event)"></dashboard-admin-edit> <dashboard-admin-edit v-bind="dashboard" :key="dashboard.dashboard_id" @change="dashboardUpdate($event)" @delete="dashboardDelete($event)"></dashboard-admin-edit>
</div> </div>
<div class="tab-pane fade show active" id="widgets" role="tabpanel" aria-labelledby="widgets-tab"> <div class="tab-pane fade show active" id="widgets" role="tabpanel" aria-labelledby="widgets-tab">
<dashboard-admin-widgets :key="dashboard.dashboard_id" :dashboard_id="dashboard.dashboard_id" :widgets="widgets" @change="test" @assign-widgets="assignWidgets"></dashboard-admin-widgets> <dashboard-admin-widgets :key="dashboard.dashboard_id" :dashboard_id="dashboard.dashboard_id" :widgets="widgets" @assign-widgets="assignWidgets"></dashboard-admin-widgets>
</div> </div>
<div class="tab-pane fade" id="presets" role="tabpanel" aria-labelledby="presets-tab"> <div class="tab-pane fade" id="presets" role="tabpanel" aria-labelledby="presets-tab">
<dashboard-admin-presets :dashboard="dashboard.dashboard_kurzbz" :widgets="widgets"></dashboard-admin-presets> <dashboard-admin-presets :dashboard="dashboard.dashboard_kurzbz" :widgets="widgets"></dashboard-admin-presets>
+4 -3
View File
@@ -18,7 +18,8 @@ export default {
}, },
methods: { methods: {
sendDelete() { sendDelete() {
BsConfirm.popup('Sure?').then(() => this.$emit('delete', this.dashboard_id)).catch(); BsConfirm.popup(this.$p.t('ui', 'confirm_delete') + " " + this.$p.t('ui', 'deleteInfo'))
.then(() => this.$emit('delete', this.dashboard_id)).catch();
} }
}, },
template: `<div class="dashboard-admin-edit px-3"> template: `<div class="dashboard-admin-edit px-3">
@@ -31,8 +32,8 @@ export default {
<textarea id="dashboard-admin-edit-beschreibung" class="form-control" v-model="desc"></textarea> <textarea id="dashboard-admin-edit-beschreibung" class="form-control" v-model="desc"></textarea>
</div> </div>
<div> <div>
<button class="btn btn-danger" @click="sendDelete">Delete</button> <button class="btn btn-danger" @click="sendDelete">{{this.$p.t('ui', 'loeschen')}}</button>
<button class="btn btn-primary" @click="$emit('change', {dashboard_id,dashboard_kurzbz:kurzbz,beschreibung:desc})">Update</button> <button class="btn btn-primary" @click="$emit('change', {dashboard_id,dashboard_kurzbz:kurzbz,beschreibung:desc})">{{this.$p.t('ui', 'btnAktualisieren')}}</button>
</div> </div>
</div>` </div>`
} }
+110 -88
View File
@@ -1,6 +1,7 @@
import DashboardSection from "../Section.js"; import DashboardSection from "../Section.js";
import DashboardWidgetPicker from "../Widget/Picker.js"; import DashboardWidgetPicker from "../Widget/Picker.js";
import ObjectUtils from "../../../helpers/ObjectUtils.js"; import ObjectUtils from "../../../helpers/ObjectUtils.js";
import ApiDashboardPreset from "../../../api/factory/dashboard/preset.js";
export default { export default {
components: { components: {
@@ -17,9 +18,6 @@ export default {
tmpLoading: '' tmpLoading: ''
}), }),
computed: { computed: {
apiurl() {
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/dashboard';
},
pickerWidgets() { pickerWidgets() {
return this.widgets.filter(widget => widget.allowed); return this.widgets.filter(widget => widget.allowed);
} }
@@ -28,6 +26,7 @@ export default {
widgetAdd(section_name, widget) { widgetAdd(section_name, widget) {
this.$refs.widgetpicker.getWidget().then(widget_id => { this.$refs.widgetpicker.getWidget().then(widget_id => {
widget.widget = widget_id; widget.widget = widget_id;
widget.id = 'loading_' + String((new Date()).valueOf());
delete widget.custom; delete widget.custom;
widget.preset = 1; widget.preset = 1;
let loading = {...widget}; let loading = {...widget};
@@ -37,129 +36,152 @@ export default {
section.widgets.push(loading); section.widgets.push(loading);
}); });
axios.post(this.apiurl + '/Config/addWidgetsToPreset', { const params = {
db: this.dashboard, dashboard: this.dashboard,
funktion_kurzbz: section_name, funktion_kurzbz: section_name,
widgets: [widget] widget
}).then(result => { };
let newId = Object.keys(result.data.retval.data[section_name].widgets).pop();
widget.id = newId; return this.$api
widget.custom = 1; .call(ApiDashboardPreset.addWidget(params))
this.sections.forEach(section => { .then(result => {
if (section.name == section_name) { let newId = result.data;
section.widgets.splice(section.widgets.indexOf(loading),1); widget.id = newId;
section.widgets.push(widget); widget.custom = 1;
} this.sections.forEach(section => {
}); if (section.name == section_name) {
}).catch(error => { section.widgets.splice(section.widgets.indexOf(loading),1);
console.error('ERROR: ', error); section.widgets.push(widget);
alert('ERROR: ' + error.response.data.retval); }
}); });
}).catch(() => {}); this.funktionen.forEach(funktion => {
if(funktion.funktion_kurzbz === section_name && funktion.has_preset < 1) {
funktion.has_preset = 1;
}
});
})
.catch(this.$fhcAlert.handleSystemError);
})
.catch(() => {});
}, },
widgetUpdate(section_name, payload) { widgetUpdate(section_name, payload) {
payload = payload[section_name]; payload = payload[section_name];
for (var k in payload) { for (var k in payload) {
for (var i in this.sections) { const section = this.sections.find(section => section.name == section_name);
if (this.sections[i].name == section_name) { for (var wid in section.widgets) {
for (var wid in this.sections[i].widgets) { if (section.widgets[wid].id == k) {
if (this.sections[i].widgets[wid].id == k) { payload[k] = ObjectUtils.mergeDeep(section.widgets[wid], payload[k]);
payload[k] = ObjectUtils.mergeDeep(this.sections[i].widgets[wid], payload[k]); // NOTE(chris): remove internal props
// NOTE(chris): remove internal props for (var prop of ['_x', '_y', '_w', '_h', 'index', 'id'])
for (var prop in {_x:1,_y:1,_w:1,_h:1,index:1,id:1}) if (payload[k][prop])
if (payload[k][prop]) delete payload[k][prop];
delete payload[k][prop];
break;
}
}
break; break;
} }
} }
payload[k].widgetid = k; payload[k].widgetid = k;
delete payload[k].custom; delete payload[k].custom;
} }
axios.post(this.apiurl + '/Config/addWidgetsToPreset', { this.$api
db: this.dashboard, .call(Object.entries(payload).map(([key, widget]) => [
funktion_kurzbz: section_name, key,
widgets: payload ApiDashboardPreset.addWidget({
}).then(() => { dashboard: this.dashboard,
this.sections.forEach(section => { funktion_kurzbz: section_name,
if (section.name == section_name) { widget
section.widgets.forEach((widget, i) => { })
if (payload[widget.id]) { ]))
payload[widget.id].id = widget.id; .then(result => {
payload[widget.id].index = widget.index; this.sections.forEach(section => {
section.widgets[i] = payload[widget.id]; if (section.name == section_name) {
section.widgets[i].custom = 1; section.widgets.forEach((widget, i) => {
} if (payload[widget.id]) {
}); payload[widget.id].id = widget.id;
} payload[widget.id].index = widget.index;
}); section.widgets[i] = payload[widget.id];
}).catch(error => { section.widgets[i].custom = 1;
// TODO(chris): revert placement on failure }
console.error('ERROR: ', error); });
alert('ERROR: ' + error.response.data.retval); }
}); });
})
.catch(this.$fhcAlert.handleSystemError);
}, },
widgetRemove(section_name, id) { widgetRemove(section_name, id) {
axios.post(this.apiurl + '/Config/removeWidgetFromPreset', { const params = {
db: this.dashboard, db: this.dashboard,
funktion_kurzbz: section_name, funktion_kurzbz: section_name,
widgetid: id widgetid: id
}).then(() => { };
this.sections.forEach(section => { return this.$api
if (section.name == section_name) .call(ApiDashboardPreset.removeWidget(params))
section.widgets = section.widgets.filter(widget => widget.id != id); .then(result => {
}); this.sections.forEach(section => {
}).catch(error => { if (section.name == section_name)
console.error('ERROR: ', error); section.widgets = section.widgets.filter(widget => widget.id != id);
alert('ERROR: ' + error.response.data.retval); });
}); })
.catch(this.$fhcAlert.handleSystemError);
}, },
loadSections(evt) { loadSections(evt) {
let funktionen = Array.from(evt.target.querySelectorAll("option:checked"),e=>e.value); let funktionen = Array.from(evt.target.querySelectorAll("option:checked"),e=>e.value);
this.sections = []; this.sections = [];
this.tmpLoading = funktionen.join('###'); this.tmpLoading = funktionen.join('###');
axios.get(this.apiurl + '/Config/presetBatch', {params: {
const params = {
db: this.dashboard, db: this.dashboard,
funktionen funktionen
}}).then(res => { };
if (this.tmpLoading !== funktionen.join('###'))
return; // NOTE(chris): prevent race condition return this.$api
for (var section in res.data.retval) { .call(ApiDashboardPreset.getBatch(params))
let widgets = []; .then(result => {
for (var wid in res.data.retval[section]) { if (this.tmpLoading !== funktionen.join('###'))
res.data.retval[section][wid].id = wid; return; // NOTE(chris): prevent race condition
res.data.retval[section][wid].custom = 1; for (var section in result.data) {
widgets.push(res.data.retval[section][wid]); let widgets = [];
for (var wid in result.data[section]) {
result.data[section][wid].id = wid;
result.data[section][wid].custom = 1;
widgets.push(result.data[section][wid]);
}
this.sections.push({
name: section,
widgets
});
} }
this.sections.push({ })
name: section, .catch(this.$fhcAlert.handleSystemError);
widgets
}); },
} loadFunktionen() {
}).catch(err => console.error('ERROR:', err)); this.$api
.call(ApiDashboardPreset.list(this.dashboard))
.then(result => {
this.funktionen = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
} }
}, },
created() { created() {
axios.get(this.apiurl + '/Config/funktionen').then(res => { this.loadFunktionen();
this.funktionen = {general: 'GENERAL'};
res.data.retval.forEach(funktion => {
this.funktionen[funktion.funktion_kurzbz] = funktion.beschreibung;
});
}).catch(err => console.error('ERROR:', err));
}, },
watch: { watch: {
dashboard() { dashboard() {
// TODO(chris): this should be done without a watcher // TODO(chris): this should be done without a watcher
this.loadSections({target:this.$refs.funktionenList}); this.loadSections({target:this.$refs.funktionenList});
this.loadFunktionen();
} }
}, },
template: `<div class="dashboard-admin-presets"> template: `<div class="dashboard-admin-presets">
<div class="row"> <div class="row">
<div class="col-3"> <div class="col-3">
<select ref="funktionenList" style="height:30em" class="form-control" multiple @input="loadSections"> <select ref="funktionenList" style="height:30em" class="form-control" multiple @input="loadSections">
<option v-for="name,id in funktionen" :key="id" :value="id">{{ name }}</option> <option
v-for="funktion in funktionen"
:key="funktion.funktion_kurzbz"
:value="funktion.funktion_kurzbz"
:class="(funktion.has_preset > 0) ? 'fw-bold' : ''"
>{{ funktion.beschreibung }}</option>
</select> </select>
</div> </div>
<div class="col-9"> <div class="col-9">
+13 -20
View File
@@ -1,3 +1,5 @@
import ApiDashboardWidget from "../../../api/factory/dashboard/widget.js";
export default { export default {
emits: [ emits: [
"change", "change",
@@ -7,34 +9,25 @@ export default {
dashboard_id: Number, dashboard_id: Number,
widgets: Array widgets: Array
}, },
computed: {
apiurl() {
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/dashboard';
}
},
methods: { methods: {
sendChange(widget_id) { sendChange(widget_id) {
let allow = !this.widgets.find(el => el.widget_id == widget_id).allowed; let allow = !this.widgets.find(el => el.widget_id == widget_id).allowed;
axios.post(this.apiurl + '/Widget/setAllowed', {
dashboard_id: this.dashboard_id, this.$api
widget_id, .call(ApiDashboardWidget.setAllowed(this.dashboard_id, widget_id, allow))
action: allow ? 'add' : 'delete' .catch(this.$fhcAlert.handleSystemError);
}).catch(err => console.error('ERROR: ' + err));
} }
}, },
created() { created() {
axios.get(this.apiurl + '/Widget/getAll', { this.$api
params:{ .call(ApiDashboardWidget.list(this.dashboard_id))
dashboard_id: this.dashboard_id .then(result => {
} this.$emit('assignWidgets', result.data.map(el => ({
}).then(
result => {
this.$emit('assignWidgets', result.data.retval.map(el => ({
...el, ...el,
...{setup:JSON.parse(el.setup),arguments:JSON.parse(el.arguments),allowed:!!el.allowed} allowed: !!el.allowed
}))); })));
} })
).catch(err => console.error('ERROR:', err)); .catch(this.$fhcAlert.handleSystemError);
}, },
template: ` template: `
<div class="dashboard-admin-widgets"> <div class="dashboard-admin-widgets">
+104 -137
View File
@@ -2,7 +2,8 @@ import DashboardSection from "./Section.js";
import DashboardWidgetPicker from "./Widget/Picker.js"; import DashboardWidgetPicker from "./Widget/Picker.js";
import ObjectUtils from "../../helpers/ObjectUtils.js"; import ObjectUtils from "../../helpers/ObjectUtils.js";
import ApiDashboard from '../../api/factory/cis/dashboard.js'; import ApiDashboardWidget from '../../api/factory/dashboard/widget.js';
import ApiDashboardUser from '../../api/factory/dashboard/user.js';
export default { export default {
name: 'Dashboard', name: 'Dashboard',
@@ -20,181 +21,147 @@ export default {
type: Object, type: Object,
required: true, required: true,
validator(value) { validator(value) {
return value && value.name && value.uid && value.timezone return value && value.name && value.timezone
} }
} }
}, },
data() { data() {
return { return {
sections: [], widgets: [],
widgets: null, originalWidgets: {},
editMode: false, widgetsSetup: null,
viewDataInternal: this.viewData editMode: false
} }
}, },
provide() { provide() {
return { return {
editMode: Vue.computed(()=>this.editMode), editMode: Vue.computed(()=>this.editMode),
widgetsSetup: Vue.computed(() => this.widgets), widgetsSetup: Vue.computed(() => this.widgetsSetup),
timezone: Vue.computed(() => this.viewData.timezone) timezone: Vue.computed(() => this.viewData.timezone)
} }
}, },
computed: {
apiurl() {
return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/dashboard';
}
},
methods: { methods: {
widgetAdd(section_name, widget) { widgetAdd(section_name, widget) {
if (this.widgets === null) { // TODO(chris): remove section_name? (change order of params => get rid of it)
axios.get(this.apiurl + '/Widget/getWidgetsForDashboard', {params:{ this.$refs.widgetpicker
db: this.dashboard .getWidget()
}}).then(res => { .then(widget_id => {
res.data.retval.forEach(widget => { widget.widget = widget_id;
widget.arguments = JSON.parse(widget.arguments); widget.id = 'loading_' + String((new Date()).valueOf());
widget.setup = JSON.parse(widget.setup); let loading = { ...widget };
}); loading.loading = true;
this.widgets = res.data.retval; this.widgets.push(loading);
}).catch(err => console.error('ERROR:', err));
}
this.$refs.widgetpicker.getWidget().then(widget_id => {
widget.widget = widget_id;
widget.id = 'loading_' + String((new Date()).valueOf());
let loading = {...widget};
loading.loading = true;
this.sections.forEach(section => {
if (section.name == section_name)
section.widgets.push(loading);
});
axios.post(this.apiurl + '/Config/addWidgetsToUserOverride', { this.$api
db: this.dashboard, .call(ApiDashboardUser.addWidget(this.dashboard, widget))
funktion_kurzbz: section_name, .then(result => {
widgets: [widget] widget.id = result.data;
}).then(result => { this.widgets.splice(this.widgets.indexOf(loading), 1);
let newId = Object.keys(result.data.retval.data[section_name].widgets).pop(); this.widgets.push(widget);
widget.id = newId; this.originalWidgets[widget.id] = structuredClone(ObjectUtils.deepToRaw(widget));
this.sections.forEach(section => { })
if (section.name == section_name) { .catch(this.$fhcAlert.handleSystemError);
section.widgets.splice(section.widgets.indexOf(loading),1); })
section.widgets.push(widget); .catch(() => {});
}
});
}).catch(error => {
console.error('ERROR: ', error);
alert('ERROR: ' + error.response.data.retval);
});
}).catch(() => {});
}, },
widgetUpdate(section_name, payload) { widgetUpdate(section_name, payload) {
payload = payload[section_name]; payload = payload[section_name];
for (var k in payload) { for (var k in payload) {
for (var i in this.sections) { for (var wid in this.widgets) {
if (this.sections[i].name == section_name) { if (this.widgets[wid].id == k) {
for (var wid in this.sections[i].widgets) { payload[k] = ObjectUtils.mergeDeep(this.widgets[wid], payload[k]);
if (this.sections[i].widgets[wid].id == k) { // NOTE(chris): remove internal props
payload[k] = ObjectUtils.mergeDeep(this.sections[i].widgets[wid], payload[k]); for (var prop of ['_x','_y','_w','_h','index','id','preset'])
// NOTE(chris): remove internal props if (payload[k][prop])
for (var prop in {_x:1,_y:1,_w:1,_h:1,index:1,id:1,preset:1}) delete payload[k][prop];
if (payload[k][prop])
delete payload[k][prop];
break;
}
}
break; break;
} }
} }
payload[k].widgetid = k; payload[k].widgetid = k;
} }
axios.post(this.apiurl + '/Config/addWidgetsToUserOverride', { this.$api
db: this.dashboard, .call(Object.entries(payload).map(([key, widget]) => [
funktion_kurzbz: section_name, key,
widgets: payload ApiDashboardUser.addWidget(this.dashboard, widget)
}).then(() => { ]))
this.sections.forEach(section => { .then(result => {
if (section.name == section_name) { const failed = result
section.widgets.forEach((widget, i) => { .filter(o => o.status == 'rejected')
if (payload[widget.id]) { .map(o => o.reason.config.errorHeader);
payload[widget.id].id = widget.id;
payload[widget.id].index = widget.index; this.widgets.forEach((widget, i) => {
section.widgets[i] = payload[widget.id]; if (failed.includes(widget.id)) {
this.widgets[i] = structuredClone(ObjectUtils.deepToRaw(this.originalWidgets[widget.id]));
/** NOTE(chris): if you wanna hide or unhide a
* preset and it fails: switch around the hidden
* value to revert it properly (checkboxes can't
* really handle it otherwise)
*/
if (payload[widget.id].hidden !== undefined) {
this.widgets[i].hidden = payload[widget.id].hidden;
this.$nextTick(() => {
this.widgets[i] = structuredClone(ObjectUtils.deepToRaw(this.originalWidgets[widget.id]));
});
} }
}); } else if (payload[widget.id]) {
} payload[widget.id].id = widget.id;
}); payload[widget.id].index = widget.index;
}).catch(error => { this.widgets[i] = payload[widget.id];
// TODO(chris): revert placement on failure this.originalWidgets[widget.id] = structuredClone(ObjectUtils.deepToRaw(this.widgets[i]));
console.error('ERROR: ', error); }
alert('ERROR: ' + error.response.data.retval); });
}); })
.catch(this.$fhcAlert.handleSystemError);
}, },
widgetRemove(section_name, id) { widgetRemove(section_name, id) {
axios.post(this.apiurl + '/Config/removeWidgetFromUserOverride', { this.$api
db: this.dashboard, .call(ApiDashboardUser.removeWidget(this.dashboard, id))
funktion_kurzbz: section_name, .then(() => {
widgetid: id this.widgets = this.widgets.filter(widget => widget.id != id);
}).then(() => { })
this.sections.forEach(section => { .catch(this.$fhcAlert.handleSystemError);
if (section.name == section_name)
section.widgets = section.widgets.filter(widget => widget.id != id);
});
}).catch(error => {
console.error('ERROR: ', error);
alert('ERROR: ' + error.response.data.retval);
});
} }
}, },
created() { created() {
this.$p.loadCategory('dashboard'); this.$p.loadCategory('dashboard');
axios.get(this.apiurl + '/Widget/getWidgetsForDashboard', {
params: {
db: this.dashboard
}
}).then(res => {
this.widgets = res.data.retval;
}).catch(err => console.error('ERROR:', err));
axios.get(this.apiurl + '/Config', {params:{ this.$api
db: this.dashboard .call(ApiDashboardWidget.listAllowed(this.dashboard))
}}).then(res => { .then(res => {
for (var name in res.data.retval) { this.widgetsSetup = res.data;
let widgets = []; })
let remove = []; .catch(this.$fhcAlert.handleSystemError);
for (var wid in res.data.retval[name].widgets) {
res.data.retval[name].widgets[wid].id = wid; this.$api
if (res.data.retval[name].widgets[wid].custom || res.data.retval[name].widgets[wid].preset) .call(ApiDashboardUser.get(this.dashboard))
widgets.push(res.data.retval[name].widgets[wid]); .then(res => {
else const widgets = [];
const remove = [];
for (var wid in res.data.general.widgets) {
let widget = res.data.general.widgets[wid];
widget.id = wid;
if (widget.custom || widget.preset) {
widgets.push(widget);
this.originalWidgets[wid] = structuredClone(widget);
} else {
remove.push(wid); remove.push(wid);
}
} }
this.sections.push({
name: name, remove.forEach(wid => this.widgetRemove('general', wid));
widgets: widgets
}); this.widgets = widgets;
remove.forEach(wid => this.widgetRemove(name, wid)); })
} .catch(this.$fhcAlert.handleSystemError);
this.sections = this.sections.sort((section1, section2) => {
if(section1.name == 'custom')
return 1;
if (section2.name == 'custom')
return -1;
return section2.widgets.length - section1.widgets.length;
});
}).catch(err => console.error('ERROR:', err));
},
async beforeMount() {
if (!this.viewData.name || !this.viewData.uid) {
const res = await this.$api.call(ApiDashboard.getViewData());
this.viewDataInternal = res.data
}
}, },
template: ` template: `
<div class="core-dashboard"> <div class="core-dashboard">
<h3 v-show="viewDataInternal?.name"> <h3>
{{ $p.t('global/personalGreeting', [ viewDataInternal?.name ]) }} {{ $p.t('global/personalGreeting', [ viewData?.name ]) }}
<button style="margin-left: 8px;" class="btn" @click="editMode = !editMode" aria-label="edit dashboard" v-tooltip="{showDelay:1000,value:'edit dashboard'}"><i class="fa-solid fa-gear" aria-hidden="true"></i></button> <button style="margin-left: 8px;" class="btn" @click="editMode = !editMode" aria-label="edit dashboard" v-tooltip="{showDelay:1000,value:'edit dashboard'}"><i class="fa-solid fa-gear" aria-hidden="true"></i></button>
</h3> </h3>
<dashboard-section v-for="(section, index) in sections" :key="section.name" :seperator="index" :name="section.name" :widgets="section.widgets" @widgetAdd="widgetAdd" @widgetUpdate="widgetUpdate" @widgetRemove="widgetRemove"></dashboard-section> <dashboard-section :seperator="0" name="general" :widgets="widgets" @widgetAdd="widgetAdd" @widgetUpdate="widgetUpdate" @widgetRemove="widgetRemove"></dashboard-section>
<dashboard-widget-picker ref="widgetpicker" :widgets="widgets"></dashboard-widget-picker> <dashboard-widget-picker ref="widgetpicker" :widgets="widgetsSetup"></dashboard-widget-picker>
</div>` </div>`
} }
+17 -3
View File
@@ -1,5 +1,5 @@
import BsModal from "../Bootstrap/Modal.js"; import BsModal from "../Bootstrap/Modal.js";
import CachedWidgetLoader from "../../composables/Dashboard/CachedWidgetLoader.js"; import { useCachedWidgetLoader } from "../../composables/Dashboard/CachedWidgetLoader.js";
import HeightTransition from "../Tranistion/HeightTransition.js"; import HeightTransition from "../Tranistion/HeightTransition.js";
export default { export default {
@@ -70,6 +70,14 @@ export default {
ready() { ready() {
return this.component && this.arguments !== null; return this.component && this.arguments !== null;
}, },
visible: {
get() {
return !this.hidden;
},
set(value) {
this.$emit('remove', this.hidden);
}
}
}, },
methods: { methods: {
unpin(){ unpin(){
@@ -142,8 +150,14 @@ export default {
this.isLoading = false; this.isLoading = false;
}, },
}, },
setup() {
const { actions } = useCachedWidgetLoader();
return {
loadWidget: actions.load
};
},
async created() { async created() {
this.widget = await CachedWidgetLoader.loadWidget(this.id); this.widget = await this.loadWidget(this.id);
let component = (await import(this.widget.setup.file)).default; let component = (await import(this.widget.setup.file)).default;
this.$options.components["widget" + this.widget.widget_id] = component; this.$options.components["widget" + this.widget.widget_id] = component;
this.component = "widget" + this.widget.widget_id; this.component = "widget" + this.widget.widget_id;
@@ -185,7 +199,7 @@ export default {
</a> </a>
<Transition> <Transition>
<div v-if="!custom && editMode" class="col-auto px-1 form-switch"> <div v-if="!custom && editMode" class="col-auto px-1 form-switch">
<input class="form-check-input ms-0" type="checkbox" role="switch" aria-label="toggle widget" id="flexSwitchCheckChecked" :checked="!hidden" @input="$emit('remove', hidden)"> <input class="form-check-input ms-0" type="checkbox" role="switch" aria-label="toggle widget" id="flexSwitchCheckChecked" v-model="visible" :value="true">
</div> </div>
</Transition> </Transition>
</div> </div>
+14 -7
View File
@@ -1,7 +1,7 @@
import BsConfirm from "../Bootstrap/Confirm.js"; import BsConfirm from "../Bootstrap/Confirm.js";
import DropGrid from '../Drop/Grid.js' import DropGrid from '../Drop/Grid.js'
import DashboardItem from "./Item.js"; import DashboardItem from "./Item.js";
import CachedWidgetLoader from "../../composables/Dashboard/CachedWidgetLoader.js"; import { useCachedWidgetLoader } from "../../composables/Dashboard/CachedWidgetLoader.js";
import WidgetIcon from "./Widget/WidgetIcon.js" import WidgetIcon from "./Widget/WidgetIcon.js"
export default { export default {
@@ -125,23 +125,23 @@ export default {
}, },
checkResizeLimit(item, w, h) { checkResizeLimit(item, w, h) {
// NOTE(chris): widgets needs to be loaded for this to work // NOTE(chris): widgets needs to be loaded for this to work
let widget = CachedWidgetLoader.getWidget(item.widget); let widget = this.widgetState[item.widget];
if (widget) { if (widget) {
let minmaxW = widget.setup.width; let minmaxW = { ...widget.setup.width };
if (minmaxW.max) if (minmaxW.max)
minmaxW.min = minmaxW.min || 1; minmaxW.min = minmaxW.min || 1;
else else
minmaxW = {min:minmaxW,max:minmaxW}; minmaxW = { min: minmaxW, max: minmaxW };
if (w < minmaxW.min) if (w < minmaxW.min)
w = minmaxW.min; w = minmaxW.min;
if (w > minmaxW.max) if (w > minmaxW.max)
w = minmaxW.max; w = minmaxW.max;
let minmaxH = widget.setup.height; let minmaxH = { ...widget.setup.height };
if (minmaxH.max) if (minmaxH.max)
minmaxH.min = minmaxH.min || 1; minmaxH.min = minmaxH.min || 1;
else else
minmaxH = {min:minmaxH,max:minmaxH}; minmaxH = { min: minmaxH, max: minmaxH };
if (h < minmaxH.min) if (h < minmaxH.min)
h = minmaxH.min; h = minmaxH.min;
if (h > minmaxH.max) if (h > minmaxH.max)
@@ -151,7 +151,7 @@ export default {
}, },
removeWidget(item, revert) { removeWidget(item, revert) {
if (item.custom) { if (item.custom) {
BsConfirm.popup('Are you sure you want to delete this widget?').then(() => this.$emit('widgetRemove', this.name, item.id)); BsConfirm.popup(this.$p.t('dashboard', 'alert_deleteWidget')).then(() => this.$emit('widgetRemove', this.name, item.id));
} else { } else {
let update = {}; let update = {};
update[item.id] = { hidden: !revert }; update[item.id] = { hidden: !revert };
@@ -199,6 +199,13 @@ export default {
this.$emit('widgetUpdate', this.name, payload); this.$emit('widgetUpdate', this.name, payload);
} }
}, },
setup() {
const { state: widgetState } = useCachedWidgetLoader();
return {
widgetState
};
},
mounted() { mounted() {
let self = this; let self = this;
let cont = self.$refs.container; let cont = self.$refs.container;
+4 -3
View File
@@ -170,6 +170,7 @@ export default {
return this.$attrs.modelValue; return this.$attrs.modelValue;
}, },
set(v) { set(v) {
this.clearValidationForThisName()
if (!this.$attrs.hasOwnProperty('modelValue')) if (!this.$attrs.hasOwnProperty('modelValue'))
this.modelValueDummy = v; this.modelValueDummy = v;
this.$emit('update:modelValue', v); this.$emit('update:modelValue', v);
@@ -242,9 +243,9 @@ export default {
template: ` template: `
<component :is="!hasContainer ? 'FhcFragment' : 'div'" class="position-relative" :class="autoContainerClass"> <component :is="!hasContainer ? 'FhcFragment' : 'div'" class="position-relative" :class="autoContainerClass">
<label v-if="label && lcType != 'radio' && lcType != 'checkbox'" :class="!noAutoClass && 'form-label'" :for="idCmp">{{label}}</label> <label v-if="label && lcType != 'radio' && lcType != 'checkbox'" :class="!noAutoClass && 'form-label'" :for="idCmp">{{label}}</label>
<input v-if="tag == 'input'" :type="lcType" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidationForThisName(); $emit('input', $event)"> <input v-if="tag == 'input'" :type="lcType" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="$emit('input', $event)">
<textarea v-else-if="tag == 'textarea'" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidationForThisName(); $emit('input', $event)"></textarea> <textarea v-else-if="tag == 'textarea'" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="$emit('input', $event)"></textarea>
<select v-else-if="tag == 'select'" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="clearValidationForThisName(); $emit('input', $event)"> <select v-else-if="tag == 'select'" ref="input" v-model="modelValueCmp" v-bind="$attrs" :id="idCmp" :name="name" :class="validationClass" :modelValue="undefined" @input="$emit('input', $event)">
<slot></slot> <slot></slot>
</select> </select>
<component <component
@@ -63,7 +63,7 @@ export default {
const vm = this; const vm = this;
tinymce.init({ tinymce.init({
target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component
//height: 800, min_height: 300,
//plugins: ['lists'], //plugins: ['lists'],
toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify | link', toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify | link',
plugins: 'link', plugins: 'link',
@@ -133,6 +133,7 @@ export default {
return this.$api return this.$api
.call(ApiMessages.getDataVorlage(vorlage_kurzbz)) .call(ApiMessages.getDataVorlage(vorlage_kurzbz))
.then(response => { .then(response => {
this.editor.setContent(response.data.text);
this.formData.body = response.data.text; this.formData.body = response.data.text;
this.formData.subject = response.data.subject; this.formData.subject = response.data.subject;
}).catch(this.$fhcAlert.handleSystemError); }).catch(this.$fhcAlert.handleSystemError);
@@ -203,24 +204,6 @@ export default {
}, },
}, },
watch: { watch: {
'formData.body': {
handler(newVal) {
const tinymcsVal = this.editor.getContent();
if (newVal && tinymcsVal != newVal) {
//Inhalt des Editors aktualisieren
this.editor.setContent(newVal);
}
}
},
'formData.vorlage_kurzbz': {
handler(newVal){
if (newVal && newVal != null) {
this.formData.subject = newVal;
return this.getDataVorlage(newVal);
}
}
},
messageId: { messageId: {
immediate: true, immediate: true,
handler: async function (newMessageId) { handler: async function (newMessageId) {
@@ -231,6 +214,7 @@ export default {
this.replyData = result.data; this.replyData = result.data;
if (this.replyData.length > 0) { if (this.replyData.length > 0) {
this.editor.setContent(this.replyData[0].replyBody);
this.formData.subject = this.replyData[0].replySubject; this.formData.subject = this.replyData[0].replySubject;
this.formData.body = this.replyData[0].replyBody; this.formData.body = this.replyData[0].replyBody;
this.formData.relationmessage_id = newMessageId; this.formData.relationmessage_id = newMessageId;
@@ -290,19 +274,6 @@ export default {
}) })
.catch(this.$fhcAlert.handleSystemError); .catch(this.$fhcAlert.handleSystemError);
//case of reply
if(this.messageId) {
this.$api
.call(ApiMessages.getReplyData(this.messageId))
.then(result => {
this.replyData = result.data;
this.formData.subject = this.replyData[0].replySubject;
this.formData.body = this.replyData[0].replyBody;
this.formData.relationmessage_id = this.messageId;
})
.catch(this.$fhcAlert.handleSystemError);
}
}, },
async mounted() { async mounted() {
this.initTinyMCE(); this.initTinyMCE();
@@ -342,7 +313,7 @@ export default {
<div class="row"> <div class="row">
<div class="col-sm-8"> <div class="col-sm-8">
<form-form class="row g-3 mt-2 h-100" ref="formMessage"> <form-form class="row g-3 mt-2 align-content-start" ref="formMessage">
<div class="row mb-3"> <div class="row mb-3">
@@ -367,7 +338,7 @@ export default {
</div> </div>
<!--Tiny MCE--> <!--Tiny MCE-->
<div class="row mb-3 h-100 tiny-90"> <div class="row mb-3 tiny-90">
<form-input <form-input
ref="editor" ref="editor"
:label="$p.t('global','nachricht') + ' *'" :label="$p.t('global','nachricht') + ' *'"
@@ -62,9 +62,18 @@ export default {
const vm = this; const vm = this;
tinymce.init({ tinymce.init({
target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component target: this.$refs.editor.$refs.input, //Important: not selector: to enable multiple import of component
//height: 800, min_height: 300,
//plugins: ['lists'], //plugins: ['lists'],
toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify', toolbar: 'styleselect | bold italic underline | alignleft aligncenter alignright alignjustify | link',
plugins: 'link',
link_context_toolbar: true,
automatic_uploads: true,
default_link_target: "_blank",
link_title: true,
target_list: [
{ title: 'New tab', value: '_blank' },
{ title: 'Same tab', value: '_self' }
],
style_formats: [ style_formats: [
{title: 'Blocks', block: 'div'}, {title: 'Blocks', block: 'div'},
{title: 'Paragraph', block: 'p'}, {title: 'Paragraph', block: 'p'},
@@ -98,7 +107,8 @@ export default {
return this.$api return this.$api
.call(ApiMessages.sendMessage(this.typeId, data)) .call(ApiMessages.sendMessage(this.typeId, data))
.then(response => { .then(response => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent')); if(this.openMode == "inSamePage")
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSent'));
this.hideTemplate(); this.hideTemplate();
this.resetForm(); this.resetForm();
this.messageSent = true; this.messageSent = true;
@@ -114,19 +124,17 @@ export default {
return this.$api return this.$api
.call(ApiMessages.getDataVorlage(vorlage_kurzbz)) .call(ApiMessages.getDataVorlage(vorlage_kurzbz))
.then(response => { .then(response => {
this.editor.setContent(response.data.text);
this.formData.body = response.data.text; this.formData.body = response.data.text;
this.formData.subject = response.data.subject; this.formData.subject = response.data.subject;
}).catch(this.$fhcAlert.handleSystemError); }).catch(this.$fhcAlert.handleSystemError);
}, },
getPreviewText(){ getPreviewText(){
console.log("subj" + this.formData.subject);
const data = new FormData(); const data = new FormData();
data.append('data', JSON.stringify(this.formData.body)); data.append('data', JSON.stringify(this.formData.body));
data.append('ids', JSON.stringify(this.id)); data.append('ids', JSON.stringify(this.id));
console.log("subj" + this.formData.subject);
return this.$api return this.$api
.call(ApiMessages.getPreviewText( .call(ApiMessages.getPreviewText(
this.typeId, data)) this.typeId, data))
@@ -195,6 +203,7 @@ export default {
.call(ApiMessages.getReplyData(messageId)) .call(ApiMessages.getReplyData(messageId))
.then(result => { .then(result => {
this.replyData = result.data; this.replyData = result.data;
this.editor.setContent(this.replyData[0].replyBody);
this.formData.subject = this.replyData[0].replySubject; this.formData.subject = this.replyData[0].replySubject;
this.formData.body = this.replyData[0].replyBody; this.formData.body = this.replyData[0].replyBody;
this.formData.relationmessage_id = messageId; this.formData.relationmessage_id = messageId;
@@ -202,27 +211,6 @@ export default {
.catch(this.$fhcAlert.handleSystemError); .catch(this.$fhcAlert.handleSystemError);
} }
}, },
watch: {
'formData.body': {
handler(newVal) {
const tinymcsVal = this.editor.getContent();
if (newVal && tinymcsVal != newVal) {
//Inhalt des Editors aktualisieren
this.editor.setContent(newVal);
}
}
},
'formData.vorlage_kurzbz': {
handler(newVal){
if (newVal && newVal != null) {
this.formData.subject = newVal;
return this.getDataVorlage(newVal);
}
}
},
},
created(){ created(){
const missingparamsmsgs = []; const missingparamsmsgs = [];
if(!this.typeId) if(!this.typeId)
@@ -291,17 +279,8 @@ export default {
.catch(this.$fhcAlert.handleSystemError); .catch(this.$fhcAlert.handleSystemError);
//case of reply //case of reply
if(this.messageId != null) { if(this.messageId) {
this.loadReplyData(this.messageId); this.loadReplyData(this.messageId);
/* this.$api
.call(ApiMessages.getReplyData(this.messageId))
.then(result => {
this.replyData = result.data;
this.formData.subject = this.replyData[0].replySubject;
this.formData.body = this.replyData[0].replyBody;
this.formData.relationmessage_id = this.messageId;
})
.catch(this.$fhcAlert.handleSystemError);*/
} }
}, },
@@ -499,10 +478,10 @@ export default {
<div class="row"> <div class="row">
<div class="col-6" style="border-right: 1px"> <div class="col-6" style="border-right: 1px">
You can safely close this window. You can safely close this window/tab.
</div> </div>
<div class="col-6"> <div class="col-6">
Sie können dieses Fenster schließen. Fenster/Reiter kann geschlossen werden!
</div> </div>
</div> </div>
</div> </div>
@@ -30,6 +30,7 @@ export default {
personId: null, personId: null,
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: '400', height: '400',
arePhrasesLoaded: false
} }
}, },
methods: { methods: {
@@ -65,7 +66,14 @@ export default {
buildTreemap(messages) { buildTreemap(messages) {
if (!messages || !messages.data || messages.data.length === 0) if (!messages || !messages.data || messages.data.length === 0)
{ {
return {data: [], last_page: 0}; if(this.tabulatorOptions.pagination)
{
return {data: [], last_page: 0};
}
else
{
return [];
}
} }
const last_page = messages.meta.count; const last_page = messages.meta.count;
@@ -106,7 +114,15 @@ export default {
// to avoid endless loop // to avoid endless loop
if (iteration > messages.length) break; if (iteration > messages.length) break;
} }
return {data: messageNested, last_page: last_page};
if(this.tabulatorOptions.pagination)
{
return {data: messageNested, last_page: last_page};
}
else
{
return messageNested;
}
}, },
loadAjaxCall(url, config, params){ loadAjaxCall(url, config, params){
return this.$api.call( return this.$api.call(
@@ -180,7 +196,7 @@ export default {
], ],
formatter: (cell, formatterParams) => { formatter: (cell, formatterParams) => {
const key = formatterParams[cell.getValue()]; const key = formatterParams[cell.getValue()];
return this.$p.t('messages', key); return this.$p?.t?.('messages', key) || key;
}, },
}, },
{ {
@@ -252,7 +268,7 @@ export default {
frozen: true frozen: true
} }
], ],
pagination: true, pagination: false,
paginationMode: "remote", paginationMode: "remote",
paginationSize: 15, paginationSize: 15,
paginationInitialPage: 1, paginationInitialPage: 1,
@@ -290,8 +306,6 @@ export default {
{ {
event: 'tableBuilt', event: 'tableBuilt',
handler: async() => { handler: async() => {
await this.$p.loadCategory(['global', 'person', 'stv', 'messages', 'ui', 'notiz']);
const setHeader = (field, text) => { const setHeader = (field, text) => {
const col = this.$refs.table.tabulator.getColumn(field); const col = this.$refs.table.tabulator.getColumn(field);
if (!col) return; if (!col) return;
@@ -342,6 +356,12 @@ export default {
});*/ });*/
}, },
created(){ created(){
this.$p
.loadCategory(['global', 'person', 'stv', 'messages', 'ui', 'notiz'])
.then(() => {
this.arePhrasesLoaded = true;
});
if(this.typeId != 'person_id' && Array.isArray(this.id) && this.id.length === 1) { if(this.typeId != 'person_id' && Array.isArray(this.id) && this.id.length === 1) {
const params = { const params = {
id: this.id, id: this.id,
@@ -366,6 +386,7 @@ export default {
<!--table--> <!--table-->
<div class="col-sm-6 pt-1"> <div class="col-sm-6 pt-1">
<core-filter-cmpt <core-filter-cmpt
v-if="arePhrasesLoaded"
ref="table" ref="table"
:tabulator-options="tabulatorOptions" :tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents" :tabulator-events="tabulatorEvents"
@@ -398,6 +419,7 @@ export default {
<div class="col-sm-12 pt-6"> <div class="col-sm-12 pt-6">
<core-filter-cmpt <core-filter-cmpt
ref="table" ref="table"
v-if="arePhrasesLoaded"
:tabulator-options="tabulatorOptions" :tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents" :tabulator-events="tabulatorEvents"
table-only table-only
+8 -6
View File
@@ -82,14 +82,16 @@ export default {
this.$refs.modalMsg.show(); this.$refs.modalMsg.show();
} }
else if (this.openMode == "inSamePage"){ else if (this.openMode == "inSamePage"){
console.log("in same Page");
this.isVisibleDiv = true; this.isVisibleDiv = true;
if(messageId)
this.$refs.templateNewDivMessage.loadReplyData(messageId);
else
this.$refs.templateNewDivMessage.resetForm();
this.$refs.templateNewDivMessage.showTemplate(); this.$nextTick(() => {
if(messageId)
this.$refs.templateNewDivMessage.loadReplyData(messageId);
else
this.$refs.templateNewDivMessage.resetForm();
this.$refs.templateNewDivMessage.showTemplate();
});
} }
else else
console.log("no valid openMode"); console.log("no valid openMode");
@@ -74,6 +74,24 @@ export default {
], ],
'abschlussdokument_lehrgaenge.xml.php': [ 'abschlussdokument_lehrgaenge.xml.php': [
'AbschlussdokumentLehrgaenge' 'AbschlussdokumentLehrgaenge'
],
'microcredential.xml.php' : [
'microcredentialzertifikat_1',
'microcredentialzertifikat_2',
'microcredentialzertifikat_3',
'microcredentialzertifikat_4',
'microcredential_1',
'microcredential_2',
'microcredential_3',
'microcredential_4',
'microdegree_1',
'microdegree_2',
'microdegree_3',
'microdegree_4',
'microdegreeabschluss_1',
'microdegreeabschluss_2',
'microdegreeabschluss_3',
'microdegreeabschluss_4',
] ]
}, },
documentDropdownObject: {} documentDropdownObject: {}
@@ -83,6 +83,8 @@ export default {
}); });
}, },
open() { open() {
this.getBuchungstypen(this.currentSemester);
this.data = { this.data = {
buchungstyp_kurzbz: '', buchungstyp_kurzbz: '',
betrag: '-0.00', betrag: '-0.00',
@@ -105,7 +107,7 @@ export default {
const text = typ.standardtext || ''; const text = typ.standardtext || '';
const creditpoints = typ.credit_points || ''; const creditpoints = typ.credit_points || '';
if (!this.data.betrag || this.data.betrag == '-0.00') if (!this.data.betrag || this.data.betrag == '-0.00' || this.data.betrag !== amount)
this.data.betrag = amount; this.data.betrag = amount;
if (!this.data.buchungstext) if (!this.data.buchungstext)
@@ -113,7 +115,18 @@ export default {
if (this.config.showCreditpoints && (this.data.credit_points == '0.00' || this.data.credit_points === null)) if (this.config.showCreditpoints && (this.data.credit_points == '0.00' || this.data.credit_points === null))
this.data.credit_points = creditpoints; this.data.credit_points = creditpoints;
} },
getBuchungstypen(studiensemester_kurzbz)
{
this.$api
.call(ApiKonto.getBuchungstypen(studiensemester_kurzbz))
.then(result => {
this.lists.buchungstypen = result.data;
if (this.data.buchungstyp_kurzbz)
this.checkDefaultBetrag(this.data.buchungstyp_kurzbz);
})
.catch(this.$fhcAlert.handleSystemError);
},
}, },
template: ` template: `
<core-form ref="form" class="stv-details-konto-edit" @submit.prevent="save"> <core-form ref="form" class="stv-details-konto-edit" @submit.prevent="save">
@@ -166,6 +179,7 @@ export default {
<form-input <form-input
type="select" type="select"
v-model="data.studiensemester_kurzbz" v-model="data.studiensemester_kurzbz"
@change="getBuchungstypen(data.studiensemester_kurzbz)"
name="studiensemester_kurzbz" name="studiensemester_kurzbz"
:label="$p.t('lehre/studiensemester')" :label="$p.t('lehre/studiensemester')"
> >
@@ -14,6 +14,9 @@ export default {
inject: { inject: {
defaultSemester: { defaultSemester: {
from: 'defaultSemester' from: 'defaultSemester'
},
currentSemester: {
from: 'currentSemester'
} }
}, },
computed: { computed: {
@@ -95,8 +98,9 @@ export default {
this.formData.themenbereich = null; this.formData.themenbereich = null;
this.formData.projekttyp_kurzbz = null; this.formData.projekttyp_kurzbz = null;
this.formData.firma = null; this.formData.firma = null;
this.formData.lehrveranstaltung_id = null; // dont reset these form fields for UX reasons
this.formData.lehreinheit_id = null; // this.formData.lehrveranstaltung_id = null;
// this.formData.lehreinheit_id = null;
this.formData.beginn = null; this.formData.beginn = null;
this.formData.ende = null; this.formData.ende = null;
this.formData.freigegeben = true; this.formData.freigegeben = true;
@@ -109,7 +113,7 @@ export default {
getFormData(newProjektarbeit, studiensemester_kurzbz, additional_lehrveranstaltung_id) { getFormData(newProjektarbeit, studiensemester_kurzbz, additional_lehrveranstaltung_id) {
this.additional_lehrveranstaltung_id = additional_lehrveranstaltung_id; this.additional_lehrveranstaltung_id = additional_lehrveranstaltung_id;
this.studiensemester = studiensemester_kurzbz || this.defaultSemester; this.studiensemester = studiensemester_kurzbz || this.currentSemester;
this.newProjektarbeit = newProjektarbeit; this.newProjektarbeit = newProjektarbeit;
this.$api this.$api
@@ -121,7 +121,6 @@ export default {
height: 'auto', height: 'auto',
minHeight: '100', minHeight: '100',
selectableRows: true, selectableRows: true,
selectableRows: 1,
index: 'betreuer_id', index: 'betreuer_id',
persistence:{ persistence:{
columns: true, //persist column layout columns: true, //persist column layout
+13 -13
View File
@@ -41,8 +41,8 @@ export default {
), ),
ajaxResponse: (url, params, response) => response.data, ajaxResponse: (url, params, response) => response.data,
columns: [ columns: [
{title: "Typ", field: "type"}, {title: "Typ", field: "type", headerFilter: "list", headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"}},
{title: "Betrag", field: "betrag", {title: "Betrag", field: "betrag", headerFilter: true,
formatter: function(cell) { formatter: function(cell) {
let value = cell.getValue(); let value = cell.getValue();
if (value == null) { if (value == null) {
@@ -51,14 +51,14 @@ export default {
return parseFloat(value).toFixed(2); return parseFloat(value).toFixed(2);
} }
}, },
{title: "Bezeichnung", field: "bezeichnung"}, {title: "Bezeichnung", field: "bezeichnung", headerFilter: true},
{title: "Studiensemester", field: "studiensemester_kurzbz"}, {title: "Studiensemester", field: "studiensemester_kurzbz", headerFilter: "list", headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"}},
{title: "Pruefung_id", field: "pruefung_id", visible: false}, {title: "Pruefung_id", field: "pruefung_id", visible: false, headerFilter: true},
{title: "mitarbeiter_uid", field: "mitarbeiter_uid", visible: false}, {title: "mitarbeiter_uid", field: "mitarbeiter_uid", visible: false, headerFilter: true},
{title: "projektarbeit_id", field: "projektarbeit_id", visible: false}, {title: "projektarbeit_id", field: "projektarbeit_id", visible: false, headerFilter: true},
{title: "lehreinheit_id", field: "lehreinheit_id", visible: true}, {title: "lehreinheit_id", field: "lehreinheit_id", visible: true, headerFilter: true},
{title: "betreuerart_kurzbz", field: "betreuerart_kurzbz", visible: false}, {title: "betreuerart_kurzbz", field: "betreuerart_kurzbz", visible: false, headerFilter: true},
{title: "vertrag_id", field: "vertrag_id", visible: false}, //just for testing {title: "vertrag_id", field: "vertrag_id", visible: false, headerFilter: true}, //just for testing
{ {
title: 'Aktionen', field: 'actions', title: 'Aktionen', field: 'actions',
minWidth: 50, minWidth: 50,
@@ -110,10 +110,10 @@ export default {
], ],
layout: 'fitColumns', layout: 'fitColumns',
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: '200', height: '250',
selectableRowsRangeMode: 'click', selectableRowsRangeMode: 'click',
selectableRows: true, selectableRows: true,
persistenceID: 'core-contracts-details-2026021701' persistenceID: 'core-contracts-details-2026050501'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -137,7 +137,7 @@ export default {
setHeader('type', this.$p.t('global', 'typ')); setHeader('type', this.$p.t('global', 'typ'));
setHeader('bezeichnung', this.$p.t('ui', 'bezeichnung')); setHeader('bezeichnung', this.$p.t('ui', 'bezeichnung'));
setHeader('lehreinheit_id', this.$p.t('ui', 'lehreinheit_id')); setHeader('lehreinheit_id', this.$p.t('lehre', 'lehreinheit_id'));
setHeader('betrag', this.$p.t('ui', 'betrag')); setHeader('betrag', this.$p.t('ui', 'betrag'));
setHeader('studiensemester_kurzbz', this.$p.t('lehre', 'studiensemester')); setHeader('studiensemester_kurzbz', this.$p.t('lehre', 'studiensemester'));
setHeader('mitarbeiter_uid', this.$p.t('ui', 'mitarbeiter_uid')); setHeader('mitarbeiter_uid', this.$p.t('ui', 'mitarbeiter_uid'));
+11 -8
View File
@@ -47,12 +47,13 @@ export default {
this.endpoint.getStatiOfContract(this.person_id, this.vertrag_id) this.endpoint.getStatiOfContract(this.person_id, this.vertrag_id)
), ),
ajaxResponse: (url, params, response) => response.data, ajaxResponse: (url, params, response) => response.data,
persistenceID: 'core-contracts-status-2026021701', persistenceID: 'core-contracts-status-2026050501',
columns: [ columns: [
{title: "Status", field: "bezeichnung"}, {title: "Status", field: "bezeichnung", headerFilter: "list", headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"}},
{ {
title: "Datum", title: "Datum",
field: "datum", field: "datum",
headerFilter: true,
formatter: function (cell) { formatter: function (cell) {
const dateStr = cell.getValue(); const dateStr = cell.getValue();
const date = new Date(dateStr); // Convert to Date object const date = new Date(dateStr); // Convert to Date object
@@ -66,14 +67,15 @@ export default {
}); });
} }
}, },
{title: "vertrag_id", field: "vertrag_id", visible: false}, {title: "vertrag_id", field: "vertrag_id", visible: false, headerFilter: true},
{title: "Vertragsstatus", field: "vertragsstatus_kurzbz", visible: false}, {title: "Vertragsstatus", field: "vertragsstatus_kurzbz", visible: false, headerFilter: true},
{title: "User", field: "mitarbeiter_uid", visible: false}, {title: "User", field: "mitarbeiter_uid", visible: false, headerFilter: true},
{title: "insertvon", field: "insertvon", visible: false}, {title: "insertvon", field: "insertvon", visible: false, headerFilter: true},
{ {
title: "insertamum", title: "insertamum",
field: "insertamum", field: "insertamum",
visible: false, visible: false,
headerFilter: true,
formatter: function (cell) { formatter: function (cell) {
const dateStr = cell.getValue(); const dateStr = cell.getValue();
const date = new Date(dateStr); const date = new Date(dateStr);
@@ -87,11 +89,12 @@ export default {
}); });
} }
}, },
{title: "updatevon", field: "updatevon", visible: false}, {title: "updatevon", field: "updatevon", visible: false, headerFilter: true},
{ {
title: "updateamum", title: "updateamum",
field: "updateamum", field: "updateamum",
visible: false, visible: false,
headerFilter: true,
formatter: function (cell) { formatter: function (cell) {
const dateStr = cell.getValue(); const dateStr = cell.getValue();
const date = new Date(dateStr); const date = new Date(dateStr);
@@ -148,7 +151,7 @@ export default {
], ],
layout: 'fitColumns', layout: 'fitColumns',
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: '200', height: '250',
selectableRowsRangeMode: 'click', selectableRowsRangeMode: 'click',
selectableRows: true, selectableRows: true,
}, },
@@ -30,10 +30,11 @@ export default {
), ),
ajaxResponse: (url, params, response) => response.data, ajaxResponse: (url, params, response) => response.data,
columns: [ columns: [
{title: "Typ", field: "type", width: 100}, {title: "Typ", field: "type", width: 100, headerFilter: "list", headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"}},
{ {
title: "Betrag", title: "Betrag",
field: "betrag1", field: "betrag1",
headerFilter: true,
formatter: function(cell) { formatter: function(cell) {
let value = cell.getValue(); let value = cell.getValue();
if (value == null) { if (value == null) {
@@ -41,28 +42,29 @@ export default {
} }
return parseFloat(value).toFixed(2); return parseFloat(value).toFixed(2);
}}, }},
{title: "Bezeichnung", field: "bezeichnung", width: 150}, {title: "Bezeichnung", field: "bezeichnung", width: 150, headerFilter: true},
{title: "Studiensemester", field: "studiensemester_kurzbz", width: 160}, {title: "Studiensemester", field: "studiensemester_kurzbz", width: 160, headerFilter: "list", headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"}},
{title: "mitarbeiter_uid", field: "mitarbeiter_uid", visible: false}, {title: "mitarbeiter_uid", field: "mitarbeiter_uid", visible: false, headerFilter: true},
{title: "projektarbeit_id", field: "projektarbeit_id", visible: false}, {title: "projektarbeit_id", field: "projektarbeit_id", visible: false, headerFilter: true},
{title: "lehreinheit_id", field: "lehreinheit_id", visible: true}, {title: "lehreinheit_id", field: "lehreinheit_id", visible: true, headerFilter: true},
{title: "betreuerart_kurzbz", field: "betreuerart_kurzbz", visible: false}, {title: "betreuerart_kurzbz", field: "betreuerart_kurzbz", visible: false, headerFilter: true},
{title: "Vertragsstunden", field: "vertragsstunden", visible: false}, {title: "Vertragsstunden", field: "vertragsstunden", visible: false, headerFilter: true},
{title: "vertrag_id", field: "vertrag_id", visible: false}, //just for testing {title: "vertrag_id", field: "vertrag_id", visible: false, headerFilter: true}, //just for testing
{ {
title: "VertragsstundenStudiensemester", title: "VertragsstundenStudiensemester",
field: "vertragsstunden_studiensemester_kurzbz", field: "vertragsstunden_studiensemester_kurzbz",
visible: false visible: false,
headerFilter: true
}, },
], ],
layout: 'fitColumns', layout: 'fitColumns',
layoutColumnsOnNewData: false, layoutColumnsOnNewData: false,
height: 150, height: 250,
selectableRowsRangeMode: 'click', selectableRowsRangeMode: 'click',
selectableRows: true, selectableRows: true,
selectableRowsRollingSelection: false, //only allow multiselect with STRG selectableRowsRollingSelection: false, //only allow multiselect with STRG
index: "lehreinheit_id", index: "lehreinheit_id",
persistenceID: 'core-contracts-unassigned-2026021701' persistenceID: 'core-contracts-unassigned-2026050501'
}, },
tabulatorEvents: [ tabulatorEvents: [
{ {
@@ -100,7 +102,7 @@ export default {
setHeader('type', this.$p.t('global', 'typ')); setHeader('type', this.$p.t('global', 'typ'));
setHeader('bezeichnung', this.$p.t('ui', 'bezeichnung')); setHeader('bezeichnung', this.$p.t('ui', 'bezeichnung'));
setHeader('lehreinheit_id', this.$p.t('ui', 'lehreinheit_id')); setHeader('lehreinheit_id', this.$p.t('lehre', 'lehreinheit_id'));
setHeader('betrag1', this.$p.t('ui', 'betrag')); setHeader('betrag1', this.$p.t('ui', 'betrag'));
setHeader('studiensemester_kurzbz', this.$p.t('lehre', 'studiensemester')); setHeader('studiensemester_kurzbz', this.$p.t('lehre', 'studiensemester'));
setHeader('mitarbeiter_uid', this.$p.t('ui', 'mitarbeiter_uid')); setHeader('mitarbeiter_uid', this.$p.t('ui', 'mitarbeiter_uid'));
+26 -137
View File
@@ -20,9 +20,6 @@ export default {
ContractStati ContractStati
}, },
inject: { inject: {
/* cisRoot: {
from: 'cisRoot'
},*/
hasSchreibrechte: { hasSchreibrechte: {
from: 'hasSchreibrechte', from: 'hasSchreibrechte',
default: false default: false
@@ -54,9 +51,9 @@ export default {
), ),
ajaxResponse: (url, params, response) => response.data, ajaxResponse: (url, params, response) => response.data,
columns: [ columns: [
{title: "Bezeichnung", field: "bezeichnung", width: 300}, {title: "Bezeichnung", field: "bezeichnung", width: 300, headerFilter: true},
{ {
title: "Betrag", field: "betrag", width: 100, title: "Betrag", field: "betrag", width: 100, headerFilter: true,
formatter: function (cell) { formatter: function (cell) {
let value = cell.getValue(); let value = cell.getValue();
@@ -66,12 +63,13 @@ export default {
return parseFloat(value).toFixed(2); return parseFloat(value).toFixed(2);
} }
}, },
{title: "Vertragstyp", field: "vertragstyp_bezeichnung", width: 125}, {title: "Vertragstyp", field: "vertragstyp_bezeichnung", width: 125, headerFilter: "list", headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"}},
{title: "Status", field: "status", width: 100}, {title: "Status", field: "status", width: 100, headerFilter: "list", headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"}},
{ {
title: "Vertragsdatum", title: "Vertragsdatum",
field: "vertragsdatum", field: "vertragsdatum",
width: 128, width: 128,
headerFilter: true,
formatter: function (cell) { formatter: function (cell) {
const dateStr = cell.getValue(); const dateStr = cell.getValue();
const date = new Date(dateStr); const date = new Date(dateStr);
@@ -82,11 +80,11 @@ export default {
}); });
} }
}, },
{title: "VertragId", field: "vertrag_id", visible: false}, {title: "VertragId", field: "vertrag_id", visible: false, headerFilter: true},
{title: "Vertragsstunden", field: "vertragsstunden", visible: false}, {title: "Vertragsstunden", field: "vertragsstunden", visible: false, headerFilter: true},
{title: "VertragsstundenStudiensemester", field: "vertragsstunden_studiensemester_kurzbz", visible: false}, {title: "VertragsstundenStudiensemester", field: "vertragsstunden_studiensemester_kurzbz", visible: false, headerFilter: true},
{title: "Anmerkung", field: "anmerkung", visible: false}, {title: "Anmerkung", field: "anmerkung", visible: false, headerFilter: true},
{title: "isAbgerechnet", field: "isabgerechnet", visible: false}, {title: "isAbgerechnet", field: "isabgerechnet", visible: false, headerFilter: true},
{ {
title: 'Aktionen', field: 'actions', title: 'Aktionen', field: 'actions',
minWidth: 150, minWidth: 150,
@@ -140,11 +138,13 @@ export default {
columns: true, columns: true,
filter: false //to avoids js errors filter: false //to avoids js errors
}, },
persistenceID: 'core-contracts-2026021701', persistenceID: 'core-contracts-2026050501',
}; };
return options; return options;
}, },
tabulatorEvents() { tabulatorEvents() {
const vm = this;
const events = [ const events = [
{ {
event: 'tableBuilt', event: 'tableBuilt',
@@ -177,28 +177,11 @@ export default {
setHeader('actions', this.$p.t('global', 'aktionen')); setHeader('actions', this.$p.t('global', 'aktionen'));
} }
}, },
/* {
//is just enabled for ADDON Injection KU: MultiprintHonorarvertrag
//(maybe enable also for ADDON FH Burgenland: MultiAccept later)
event: 'rowClick',
handler: (e, row) => {
if (this.dataPrintHonorar != null && this.dataPrintHonorar.multiselect != null) {
const selectedContract = row.getData().vertrag_id;
const status = row.getData().status;
const bezeichnung = row.getData().bezeichnung;
this.toggleRowClick(selectedContract, status, bezeichnung);
}
}
},*/
{ {
event: 'rowClick', event: 'rowClick',
handler: (e, row) => { handler: function (e, row) {
if (!this.dataPrintHonorar?.multiselect) return;
const { vertrag_id, status, bezeichnung, vertragstyp_bezeichnung } = row.getData(); const { vertrag_id, status, bezeichnung, vertragstyp_bezeichnung } = row.getData();
vm.toggleRowClick(e, vertrag_id, status, bezeichnung, vertragstyp_bezeichnung);
this.toggleRowClick(e, vertrag_id, status, bezeichnung, vertragstyp_bezeichnung);
} }
}, },
{ {
@@ -242,8 +225,6 @@ export default {
person_id() { person_id() {
this.$refs.table.reloadTable(); this.$refs.table.reloadTable();
this.arraySelectedContracts = []; this.arraySelectedContracts = [];
/* if(this.dataPrintHonorar?.multiselect)
this.dataPrintHonorar.multiselect = [];*/
}, },
}, },
methods: { methods: {
@@ -270,7 +251,6 @@ export default {
) )
.then(result => { .then(result => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'));
//window.scrollTo(0, 0);
this.reload(); this.reload();
this.contractSelected.vertrag_id = null; this.contractSelected.vertrag_id = null;
}) })
@@ -518,19 +498,9 @@ export default {
'content/pdfExport.php?xml=' + this.dataPrintHonorar.xml + '&xsl=' + this.dataPrintHonorar.xsl + '&mitarbeiter_uid=' + this.mitarbeiter_uid + vertragString + '&output=pdf&uid=' + this.mitarbeiter_uid; 'content/pdfExport.php?xml=' + this.dataPrintHonorar.xml + '&xsl=' + this.dataPrintHonorar.xsl + '&mitarbeiter_uid=' + this.mitarbeiter_uid + vertragString + '&output=pdf&uid=' + this.mitarbeiter_uid;
window.open(linkToPdf, '_blank'); window.open(linkToPdf, '_blank');
}, },
/* toggleRowClick(contractId, status, bezeichnung) {
const index = this.arraySelectedContracts.findIndex(
([id]) => id === contractId
);
if (index !== -1) {
this.arraySelectedContracts.splice(index, 1);
} else {
this.arraySelectedContracts.push([contractId, status, bezeichnung]);
}
},*/
toggleRowClick(event, vertrag_id, status, bezeichnung, vertragstyp_bezeichnung) { toggleRowClick(event, vertrag_id, status, bezeichnung, vertragstyp_bezeichnung) {
if (!this.dataPrintHonorar?.multiselect) return;
const isMulti = this.dataPrintHonorar?.multiselect === true;
const isCtrl = event.ctrlKey || event.metaKey; const isCtrl = event.ctrlKey || event.metaKey;
const entry = { const entry = {
@@ -540,28 +510,29 @@ export default {
vertragstyp_bezeichnung vertragstyp_bezeichnung
}; };
// Single click // allow MultiSelect just in case event multiActionPrintHonorarvertrag
if (!isCtrl) { const allowMultiClick = isMulti && isCtrl;
if (!allowMultiClick) {
this.arraySelectedContracts = [entry]; this.arraySelectedContracts = [entry];
//just mark last selected row as selected
this.$refs.table.tabulator.deselectRow();
this.$refs.table.tabulator.selectRow(vertrag_id);
return; return;
} }
// CTRL / CMD → toggle
const index = this.arraySelectedContracts.findIndex( const index = this.arraySelectedContracts.findIndex(
e => e.vertrag_id === vertrag_id e => e.vertrag_id === vertrag_id
); );
if (index === -1) { if (index === -1) {
this.arraySelectedContracts.push(entry); this.arraySelectedContracts.push(entry);
//this.arraySelectedContracts.push([entry.vertrag_id, entry.status, entry.bezeichnung, entry.vertragstyp_bezeichnung]);
} else { } else {
this.arraySelectedContracts.splice(index, 1); this.arraySelectedContracts.splice(index, 1);
} }
},
/* clearSelection(){ }
this.arraySelectedContracts = [];
this.$refs.table.tabulator.deselectRow();
}*/
}, },
created() { created() {
Promise.all([ Promise.all([
@@ -587,88 +558,6 @@ export default {
}); });
this.getFormattedDate(); this.getFormattedDate();
}, },
/*
TODO(Manu) delete after check
<div class="row mb-3">
<form-input
type="DatePicker"
:label="$p.t('vertrag/datum_vertrag')"
name="vertragsdatum"
v-model="formData.vertragsdatum"
auto-apply
:enable-time-picker="false"
format="dd.MM.yyyy"
preview-format="dd.MM.yyyy"
:teleport="true"
>
</form-input>
</div>
<div class="row mb-3">
<form-input
type="text"
:label="$p.t('ui/bezeichnung')"
name="bezeichnung"
v-model="formData.bezeichnung"
>
</form-input>
</div>
<div class="row mb-3">
<form-input
type="select"
:label="$p.t('global/typ')"
v-model="formData.vertragstyp_kurzbz"
name="vertragstyp_kurzbz"
>
<option :value="null">-- {{$p.t('fehlermonitoring', 'keineAuswahl')}} --</option>
<option
v-for="entry in listContractTypes"
:key="entry.vertragstyp_kurzbz"
:value="entry.vertragstyp_kurzbz"
>
{{entry.bezeichnung}}
</option>
</form-input>
</div>
<div class="row mb-3">
<form-input
:label="$p.t('ui/betrag')"
name="betrag"
v-model="formData.betrag"
>
</form-input>
</div>
<div class="row mb-3" v-if="!statusNew">
<form-input
type="text"
:label="$p.t('ui/stunden') + ' (' + $p.t('vertrag/vertrag_urfassung')+ ')'"
name="vertragsstunden"
v-model="formData.vertragsstunden"
disabled
>
</form-input>
</div>
<div class="row mb-3" v-if="!statusNew">
<form-input
type="text"
:label="$p.t('lehre/studiensemester') + ' (' + $p.t('vertrag/vertrag_urfassung')+ ')'"
name="vertragsstunden_studiensemester_kurzbz"
v-model="formData.vertragsstunden_studiensemester_kurzbz"
disabled
>
</form-input>
</div>
<div class="row mb-3">
<form-input
type="textarea"
:label="$p.t('global/anmerkung')"
name="anmerkung"
v-model="formData.anmerkung"
>
</form-input>
</div>
*/
template: ` template: `
<div class="core-contracts h-100 d-flex flex-column"> <div class="core-contracts h-100 d-flex flex-column">
@@ -71,7 +71,6 @@ export default {
:mitarbeiter_uid="this.mitarbeiter_uid" :mitarbeiter_uid="this.mitarbeiter_uid"
typeHeader="mitarbeiter" typeHeader="mitarbeiter"
:domain="config.domain" :domain="config.domain"
fotoEditable
@redirectToLeitung="handleSelection" @redirectToLeitung="handleSelection"
> >
<template #uid>{{tile_MaUid}}</template> <template #uid>{{tile_MaUid}}</template>
+2 -2
View File
@@ -280,7 +280,7 @@ export const CoreFilterCmpt = {
}); });
} }
if (tabulatorOptions.selectable || (tabulatorOptions.columns && tabulatorOptions.columns.filter(el => el.formatter == 'rowSelection').length)) if (tabulatorOptions.selectable || tabulatorOptions.selectableRows || (tabulatorOptions.columns && tabulatorOptions.columns.filter(el => el.formatter == 'rowSelection').length))
this.tabulatorHasSelector = true; this.tabulatorHasSelector = true;
if (this.idField) { if (this.idField) {
@@ -358,7 +358,7 @@ export const CoreFilterCmpt = {
} }
}, },
_updateTabulator() { _updateTabulator() {
this.tabulatorHasSelector = this.tabulatorOptions.selectable || this.filteredColumns.filter(el => el.formatter == 'rowSelection').length; this.tabulatorHasSelector = this.tabulatorOptions.selectable || this.tabulatorOptions.selectableRows || this.filteredColumns.filter(el => el.formatter == 'rowSelection').length;
this.tabulator.setColumns(this.filteredColumns); this.tabulator.setColumns(this.filteredColumns);
this.tabulator.setData(this.filteredData); this.tabulator.setData(this.filteredData);
this._setHeaderFilter() this._setHeaderFilter()
@@ -1,29 +1,36 @@
let __widgets = {}; import ApiWidget from "../../api/factory/dashboard/widget.js";
let __widgetsStarted = {};
let __path = FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/dashboard/Widget';
export default { const promises = Vue.ref([]);
getWidget(id) { const stateRef = Vue.ref([]);
return __widgets[id]; const state = Vue.readonly(stateRef);
},
loadWidget(id) {
if (__widgets[id])
return Promise.resolve(__widgets[id]);
if (__widgetsStarted[id])
return __widgetsStarted[id];
if (!__path)
return Promise.reject('Widget could not be loaded because there is no path yet!');
__widgetsStarted[id] = new Promise((resolve, reject) => { export function useCachedWidgetLoader() {
axios.get(__path, {params:{id}}).then(res => { const $api = Vue.inject('$api');
__widgets[id] = res.data.retval; const $fhcAlert = Vue.inject('$fhcAlert');
__widgetsStarted[id] = undefined;
resolve(__widgets[id]); function load(id) {
}).catch(error => reject(error.response.data.retval.error)); if (state.value[id])
}); return Promise.resolve(state.value[id]);
return __widgetsStarted[id];
}, if (!promises.value[id])
setPath(path) { promises.value[id] = new Promise((resolve, reject) => {
__path = path; $api
.call(ApiWidget.get(id))
.then(res => {
stateRef.value[id] = res.data;
promises.value[id] = undefined;
resolve(state.value[id]);
})
.catch($fhcAlert.handleSystemError);
});
return promises.value[id];
} }
return {
state,
actions: {
load
}
};
} }
+68 -27
View File
@@ -1,31 +1,72 @@
export default { /**
/** * Performs a deep merge of objects and returns new object. Does not modify
* Performs a deep merge of objects and returns new object. Does not modify * objects (immutable) and merges arrays via concatenation.
* objects (immutable) and merges arrays via concatenation. *
* * @param {...object} objects - Objects to merge
* @param {...object} objects - Objects to merge * @returns {object} New object with merged key/values
* @returns {object} New object with merged key/values */
*/ function mergeDeep(...objects) {
mergeDeep(...objects) { const isObject = obj => obj && typeof obj === 'object';
const isObject = obj => obj && typeof obj === 'object';
return objects.reduce((prev, obj) => { return objects.reduce((prev, obj) => {
Object.keys(obj).forEach(key => { Object.keys(obj).forEach(key => {
const pVal = prev[key]; const pVal = prev[key];
const oVal = obj[key]; const oVal = obj[key];
if (Array.isArray(pVal) && Array.isArray(oVal)) { if (Array.isArray(pVal) && Array.isArray(oVal)) {
prev[key] = pVal.concat(...oVal); prev[key] = pVal.concat(...oVal);
} }
else if (isObject(pVal) && isObject(oVal)) { else if (isObject(pVal) && isObject(oVal)) {
prev[key] = this.mergeDeep(pVal, oVal); prev[key] = this.mergeDeep(pVal, oVal);
} }
else { else {
prev[key] = oVal; prev[key] = oVal;
} }
}); });
return prev; return prev;
}, {}); }, {});
} }
/**
* Extends VUEs toRaw() function to nested Proxies
* @see https://www.reddit.com/r/javascript/comments/10gzynk/deep_cloning_objects_in_javascript_the_modern_way/
*
* @param object sourceObj - Object to transform
* @returns object
*/
function deepToRaw(sourceObj) {
const objectIterator = input => {
if (Array.isArray(input))
return input.map(objectIterator);
if (Vue.isRef(input) || Vue.isReactive(input) || Vue.isProxy(input))
return objectIterator(Vue.toRaw(input));
if (input && typeof input === 'object') {
/** use custom handling of 'Date' objects to avoid data loss if treating it like any other object.
* reminder:
* typeof (new Date()) ==> 'object'
* Object.keys(new Date()) ==> []
*/
if (input instanceof Date)
return input;
return Object.keys(input).reduce((acc, key) => {
acc[key] = objectIterator(input[key]);
return acc;
}, {});
}
return input;
};
return objectIterator(sourceObj);
}
export {
mergeDeep,
deepToRaw
}
export default {
mergeDeep,
deepToRaw
} }
+8 -8
View File
@@ -430,16 +430,16 @@ export default {
fhcApiAxios.interceptors.response.use( fhcApiAxios.interceptors.response.use(
response => { response => {
if (response.config?.errorHandling == 'off' const errorConfig = get_error_handler(response.config);
|| response.config?.errorHandling === false
|| response.config?.errorHandling == 'fail') if (!errorConfig.success)
return clean_return_value(response); return clean_return_value(response);
// NOTE(chris): loop through errors const errors = popHandleableErrors(errorConfig, response.data.errors);
if (response.data.errors)
response.data.errors = response.data.errors.filter( for (var type in errors) {
err => (response.config[err.type + 'ErrorHandler'] || app.config.globalProperties.$api._defaultErrorHandlers[err.type])(err, response.config) errorConfig.handler[type](errors[type]);
); }
return clean_return_value(response); return clean_return_value(response);
}, },
+2
View File
@@ -143,6 +143,8 @@ foreach($ps->result as $row)
<ROLLE:updatevon><![CDATA['.$row->updatevon.']]></ROLLE:updatevon> <ROLLE:updatevon><![CDATA['.$row->updatevon.']]></ROLLE:updatevon>
<ROLLE:stichtagsaktiv><![CDATA['.$stichtagsaktiv.']]></ROLLE:stichtagsaktiv> <ROLLE:stichtagsaktiv><![CDATA['.$stichtagsaktiv.']]></ROLLE:stichtagsaktiv>
<ROLLE:aktiv><![CDATA['.$aktiv.']]></ROLLE:aktiv> <ROLLE:aktiv><![CDATA['.$aktiv.']]></ROLLE:aktiv>
<ROLLE:fgm><![CDATA['.$row->fgm.']]></ROLLE:fgm>
<ROLLE:faktiv><![CDATA['.($row->faktiv?'Ja':'Nein').']]></ROLLE:faktiv>
</RDF:Description> </RDF:Description>
</RDF:li> </RDF:li>
'; ';
+3 -3
View File
@@ -450,18 +450,18 @@ td.MarkLine
td.HeaderTesttool /*fuer die Button-Optik beim Testtool*/ td.HeaderTesttool /*fuer die Button-Optik beim Testtool*/
{ {
color: #FFFFFF; color: #FFFFFF;
background-color: #00639C; background-color: #71787D;
white-space:nowrap; white-space:nowrap;
line-height: 25px; line-height: 25px;
box-shadow: inset 0 0 2px #FFFFFF; box-shadow: inset 0 0 2px #FFFFFF;
padding: 10px; padding: 0 10px;
width: 170px; width: 170px;
} }
td.HeaderTesttoolSTG /*fuer die Button-Optik der Quereinstiegs-Studiengänge beim Testtool*/ td.HeaderTesttoolSTG /*fuer die Button-Optik der Quereinstiegs-Studiengänge beim Testtool*/
{ {
color: white; color: white;
border: 2px solid #73a9d6; border: 2px solid #73a9d6;
padding: 10px; padding: 0 10px;
max-width: 100px; max-width: 100px;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
+5998 -107
View File
File diff suppressed because it is too large Load Diff
+7
View File
@@ -92,6 +92,8 @@ require_once('dbupdate_3.4/68744_StV_settings.php');
require_once('dbupdate_3.4/62889_reihungstest_ueberwachung_mit_constructor.php'); require_once('dbupdate_3.4/62889_reihungstest_ueberwachung_mit_constructor.php');
require_once('dbupdate_3.4/71399_dashboard_update_widget_paths.php'); require_once('dbupdate_3.4/71399_dashboard_update_widget_paths.php');
require_once('dbupdate_3.4/71645_studvw_messagetab_ladezeit.php'); require_once('dbupdate_3.4/71645_studvw_messagetab_ladezeit.php');
require_once('dbupdate_3.4/71566_studienordnungsdokument_neuer_organisationseinheitstyp_programm.php');
require_once('dbupdate_3.4/70376_lohnguide.php');
require_once('dbupdate_3.4/71405_ferienzeiten.php'); require_once('dbupdate_3.4/71405_ferienzeiten.php');
// *** Pruefung und hinzufuegen der neuen Attribute und Tabellen // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen
@@ -240,6 +242,11 @@ $tabellen=array(
"hr.tbl_valorisierung_instanz" => array("updateamum", "oe_kurzbz", "valorisierungsdatum", "valorisierung_kurzbz", "beschreibung", "ausgewaehlt", "updatevon", "valorisierung_instanz_id"), "hr.tbl_valorisierung_instanz" => array("updateamum", "oe_kurzbz", "valorisierungsdatum", "valorisierung_kurzbz", "beschreibung", "ausgewaehlt", "updatevon", "valorisierung_instanz_id"),
"hr.tbl_valorisierung_instanz_methode" => array("valorisierung_instanz_id", "valorisierung_methode_kurzbz", "beschreibung", "valorisierung_methode_parameter"), "hr.tbl_valorisierung_instanz_methode" => array("valorisierung_instanz_id", "valorisierung_methode_kurzbz", "beschreibung", "valorisierung_methode_parameter"),
"hr.tbl_valorisierung_methode" => array("beschreibung", "valorisierung_methode_kurzbz"), "hr.tbl_valorisierung_methode" => array("beschreibung", "valorisierung_methode_kurzbz"),
"hr.tbl_lohnguide_jobfamilie" => array("jobfamilie_kurzbz", "bezeichnung", "aktiv", "sort", "insertvon", "insertamum", "updatevon", "updateamum"),
"hr.tbl_lohnguide_modellfunktion" => array("modellfunktion_kurzbz", "bezeichnung", "jobfamilie_kurzbz", "aktiv", "sort", "insertvon", "insertamum", "updatevon", "updateamum"),
"hr.tbl_lohnguide_modellstelle" => array("modellstelle_kurzbz", "bezeichnung", "grade", "modellfunktion_kurzbz", "aktiv", "sort", "insertvon", "insertamum", "updatevon", "updateamum"),
"hr.tbl_lohnguide_fachrichtung" => array("fachrichtung_kurzbz", "bezeichnung", "aktiv", "insertvon", "insertamum", "updatevon", "updateamum"),
"hr.tbl_vertragsbestandteil_lohnguide" => array("vertragsbestandteil_id", "stellenbezeichnung", "vordienstzeit", "fachrichtung_kurzbz", "modellstelle_kurzbz", "kommentar_person", "kommentar_modellstelle"),
"lehre.tbl_abschlussbeurteilung" => array("abschlussbeurteilung_kurzbz","bezeichnung","bezeichnung_english","sort"), "lehre.tbl_abschlussbeurteilung" => array("abschlussbeurteilung_kurzbz","bezeichnung","bezeichnung_english","sort"),
"lehre.tbl_abschlusspruefung" => array("abschlusspruefung_id","student_uid","vorsitz","pruefer1","pruefer2","pruefer3","abschlussbeurteilung_kurzbz","akadgrad_id","pruefungstyp_kurzbz","datum","uhrzeit","sponsion","anmerkung","updateamum","updatevon","insertamum","insertvon","ext_id","note","protokoll","endezeit","pruefungsantritt_kurzbz","freigabedatum"), "lehre.tbl_abschlusspruefung" => array("abschlusspruefung_id","student_uid","vorsitz","pruefer1","pruefer2","pruefer3","abschlussbeurteilung_kurzbz","akadgrad_id","pruefungstyp_kurzbz","datum","uhrzeit","sponsion","anmerkung","updateamum","updatevon","insertamum","insertvon","ext_id","note","protokoll","endezeit","pruefungsantritt_kurzbz","freigabedatum"),
"lehre.tbl_abschlusspruefung_antritt" => array("pruefungsantritt_kurzbz","bezeichnung","bezeichnung_english","sort"), "lehre.tbl_abschlusspruefung_antritt" => array("pruefungsantritt_kurzbz","bezeichnung","bezeichnung_english","sort"),
@@ -1,6 +1,19 @@
<?php <?php
if (! defined('DB_NAME')) exit('No direct script access allowed'); if (! defined('DB_NAME')) exit('No direct script access allowed');
if ($result = @$db->db_query("SELECT 1 FROM system.tbl_app WHERE app='lvevaluierung' LIMIT 1"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "INSERT INTO system.tbl_app (app) VALUES ('lvevaluierung');";
if(!$db->db_query($qry))
echo '<strong>system.tbl_app: '.$db->db_last_error().'</strong><br>';
else
echo ' system.tbl_app: lvevaluierung hinzugefügt<br>';
}
}
//Add column evaluierung to lehre.tbl_lehrveranstaltung //Add column evaluierung to lehre.tbl_lehrveranstaltung
if(!@$db->db_query("SELECT evaluierung FROM lehre.tbl_lehrveranstaltung LIMIT 1")) if(!@$db->db_query("SELECT evaluierung FROM lehre.tbl_lehrveranstaltung LIMIT 1"))
{ {
+357
View File
@@ -0,0 +1,357 @@
<?php
if (! defined('DB_NAME')) exit('No direct script access allowed');
if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table_name='tbl_lohnguide_jobfamilie' AND table_schema='hr'"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "
CREATE TABLE IF NOT EXISTS hr.tbl_lohnguide_jobfamilie (
jobfamilie_kurzbz character varying(32) NOT NULL,
bezeichnung varchar(64) NOT NULL,
aktiv boolean DEFAULT FALSE,
sort smallint,
insertvon character varying(32) NOT NULL,
insertamum timestamp without time zone DEFAULT now() NOT NULL,
updatevon character varying(32),
updateamum timestamp without time zone,
CONSTRAINT tbl_lohnguide_jobfamilie_pkey PRIMARY KEY (jobfamilie_kurzbz)
);
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE hr.tbl_lohnguide_jobfamilie TO vilesci;
INSERT INTO hr.tbl_lohnguide_jobfamilie(jobfamilie_kurzbz, bezeichnung,aktiv, sort, insertvon, insertamum) VALUES
('FÜHRUNG','Führung',true,1,'system',NOW()),
('AKADEMIA','Akademia',true,2,'system',NOW()),
('VERWALTUNG','Verwaltung',true,3,'system',NOW()),
('TECHNIK','Technik',true,4,'system',NOW()),
('IT_SOFTWARE','IT & Software',true,5,'system',NOW()),
('TECHN_DIENSTE','Technische Dienste',true,6,'system',NOW())
ON CONFLICT (jobfamilie_kurzbz) DO NOTHING;
";
if (! $db->db_query($qry))
echo '<strong>Lohnguide Jobfamilie: ' . $db->db_last_error() . '</strong><br>';
else
echo 'hr.tbl_lohnguide_jobfamilie wurde neu erstellt<br>';
}
}
if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table_name='tbl_lohnguide_modellfunktion' AND table_schema='hr'"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "
CREATE TABLE IF NOT EXISTS hr.tbl_lohnguide_modellfunktion (
modellfunktion_kurzbz character varying(32) NOT NULL,
bezeichnung varchar(64) NOT NULL,
jobfamilie_kurzbz character varying(32) NOT NULL,
aktiv boolean DEFAULT FALSE,
sort smallint,
insertvon character varying(32) NOT NULL,
insertamum timestamp without time zone DEFAULT now() NOT NULL,
updatevon character varying(32),
updateamum timestamp without time zone,
CONSTRAINT tbl_lohnguide_modellfunktion_pkey PRIMARY KEY (modellfunktion_kurzbz),
CONSTRAINT tbl_lohnguide_modellfunktion_jobfamilie_fk FOREIGN KEY (jobfamilie_kurzbz) REFERENCES hr.tbl_lohnguide_jobfamilie (jobfamilie_kurzbz) MATCH FULL ON DELETE RESTRICT ON UPDATE CASCADE
);
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE hr.tbl_lohnguide_modellfunktion TO vilesci;
INSERT INTO hr.tbl_lohnguide_modellfunktion(modellfunktion_kurzbz, bezeichnung, jobfamilie_kurzbz, aktiv, sort, insertvon, insertamum) VALUES
('ABTEILUNGSLEITUNG','Abteilungsleitung','FÜHRUNG',true,1,'system',NOW()),
('GF','Geschäftsführung','FÜHRUNG',true,2,'system',NOW()),
('KOMPETENZFELDLEITER','Kompetenzfeldleiter*in','FÜHRUNG',true,3,'system',NOW()),
('DEPARTMENTSLEITER','Departmentsleiter*in','FÜHRUNG',true,4,'system',NOW()),
('FAKULTÄTSLEITER','Fakultätsleiter*in','FÜHRUNG',true,5,'system',NOW()),
/* Akademia */
('STUDENTISCHE_MA','Studentische MA','AKADEMIA',true,6,'system',NOW()),
('JUNIOR_LEC_RES','Junior Lecturer/Researcher','AKADEMIA',true,7,'system',NOW()),
('LEC_RES','Lecturer/Researcher','AKADEMIA',true,8,'system',NOW()),
('SEN_LEC_RES','Senior Lecturer/Researcher','AKADEMIA',true,9,'system',NOW()),
('STUDIENGANGSLEITUNG','Studiengangsleitung','AKADEMIA',true,10,'system',NOW()),
/* Verwaltung */
('FK_VERWALTUNG','Fachkraft Verwaltung','VERWALTUNG',true,11,'system',NOW()),
('SFK_VERWALTUNG','Spezial-Fachkraft Verwaltung','VERWALTUNG',true,12,'system',NOW()),
('SP_VERWALTUNG','Spezialist:in Verwaltung','VERWALTUNG',true,13,'system',NOW()),
('EXP_VERWALTUNG','Expert:in Verwaltung','VERWALTUNG',true,14,'system',NOW()),
/* Technik */
('FK_TECHNIK','Fachkraft Technik','TECHNIK',true,15,'system',NOW()),
/* IT & Software */
('FK_IT','Fachkraft IT & Software','IT_SOFTWARE',true,16,'system',NOW()),
('SFK_IT','Spezial-Fachkraft IT & Software','IT_SOFTWARE',true,17,'system',NOW()),
('SP_IT','Spezialist:in IT & Software','IT_SOFTWARE',true,18,'system',NOW()),
('EXP_IT','Expert:in IT & Software','IT_SOFTWARE',true,19,'system',NOW()),
/* Technische Dienste */
('HK_TECHN_DIENSTE','Hilfskraft Technische Dienste','TECHN_DIENSTE',true,20,'system',NOW()),
('FK_TECHN_DIENSTE','Fachkraft Technische Dienste','TECHN_DIENSTE',true,21,'system',NOW()),
('SFK_TECHN_DIENSTE','Spezial-Fachkraft Technische Dienste','TECHN_DIENSTE',true,22,'system',NOW())
ON CONFLICT (modellfunktion_kurzbz) DO NOTHING;
";
if (! $db->db_query($qry))
echo '<strong>Lohnguide Modellfunktion: ' . $db->db_last_error() . '</strong><br>';
else
echo 'hr.tbl_lohnguide_modellfunktion wurde neu erstellt<br>';
}
}
if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table_name='tbl_lohnguide_modellstelle' AND table_schema='hr'"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "
CREATE TABLE IF NOT EXISTS hr.tbl_lohnguide_modellstelle (
modellstelle_kurzbz character varying(32) NOT NULL,
bezeichnung varchar(128) NOT NULL,
code character varying(32) NOT NULL,
grade int NOT NULL,
modellfunktion_kurzbz character varying(32) NOT NULL,
aktiv boolean DEFAULT FALSE,
sort smallint,
insertvon character varying(32) NOT NULL,
insertamum timestamp without time zone DEFAULT now() NOT NULL,
updatevon character varying(32),
updateamum timestamp without time zone,
CONSTRAINT tbl_lohnguide_modellstelle_pkey PRIMARY KEY (modellstelle_kurzbz),
CONSTRAINT tbl_lohnguide_modellstelle_modellfunktion_fk FOREIGN KEY (modellfunktion_kurzbz) REFERENCES hr.tbl_lohnguide_modellfunktion (modellfunktion_kurzbz) MATCH FULL ON DELETE RESTRICT ON UPDATE CASCADE
);
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE hr.tbl_lohnguide_modellstelle TO vilesci;
-- FÜHRUNG
INSERT INTO hr.tbl_lohnguide_modellstelle(modellstelle_kurzbz,bezeichnung, code, grade, modellfunktion_kurzbz, aktiv, sort, insertvon, insertamum) VALUES
('ABTL_1_4', 'Abteilungsleitung 1/4', '111', 16, 'ABTEILUNGSLEITUNG', true, 1, 'system', NOW()),
('ABTL_2A_4', 'Abteilungsleitung 2a/4', '112a', 17, 'ABTEILUNGSLEITUNG', true, 2, 'system', NOW()),
('ABTL_2B_4', 'Abteilungsleitung 2b/4', '112b', 17, 'ABTEILUNGSLEITUNG', true, 3, 'system', NOW()),
('ABTL_3A_4', 'Abteilungsleitung 3a/4', '113a', 18, 'ABTEILUNGSLEITUNG', true, 4, 'system', NOW()),
('ABTL_3B_4', 'Abteilungsleitung 3b/4', '113b', 18, 'ABTEILUNGSLEITUNG', true, 5, 'system', NOW()),
('ABTL_4_4', 'Abteilungsleitung 4/4', '114', 19, 'ABTEILUNGSLEITUNG', true, 6, 'system', NOW()),
('GF_1_2', 'Geschäftsführung 1/2', '121', 22, 'GF', true, 7, 'system', NOW()),
('GF_2_2', 'Geschäftsführung 2/2', '122', 23, 'GF', true, 8, 'system', NOW()),
('KOMFL_1_1', 'Kompetenzfeldleiter*in 1/1', '131', 15, 'KOMPETENZFELDLEITER', true, 9, 'system', NOW()),
('DEPL_1_1', 'Departmentleiter*in 1/1', '141', 18, 'DEPARTMENTSLEITER', true, 10, 'system', NOW()),
('FAKL_1_1', 'Fakultätsleiter*in 1/1', '151', 20, 'FAKULTÄTSLEITER', true, 11, 'system', NOW())
ON CONFLICT (modellstelle_kurzbz) DO NOTHING;
-- AKADEMIA
INSERT INTO hr.tbl_lohnguide_modellstelle(modellstelle_kurzbz, bezeichnung, code, grade, modellfunktion_kurzbz, aktiv, sort, insertvon, insertamum) VALUES
('STUDENTISCHE_MA_1_1', 'Studentische MA 1/1', '211', 5, 'STUDENTISCHE_MA', true, 12, 'system', NOW()),
('JUNIOR_LEC_RES_1_2', 'Junior Lecturer/Researcher 1/2', '221', 8, 'JUNIOR_LEC_RES', true, 13, 'system', NOW()),
('JUNIOR_LEC_RES_2_2', 'Junior Lecturer/Researcher 2/2', '222', 9, 'JUNIOR_LEC_RES', true, 14, 'system', NOW()),
('LEC_RES_1_2', 'Lecturer/Researcher 1/2', '231', 11, 'LEC_RES', true, 15, 'system', NOW()),
('LEC_RES_2_2', 'Lecturer/Researcher 2/2', '232', 12, 'LEC_RES', true, 16, 'system', NOW()),
('SEN_LEC_RES_1_2', 'Senior Lecturer/Researcher 1/2', '241', 13, 'SEN_LEC_RES', true, 17, 'system', NOW()),
('SEN_LEC_RES_2_2', 'Senior Lecturer/Researcher 2/2', '242', 14, 'SEN_LEC_RES', true, 18, 'system', NOW()),
('STGL_1_2', 'Studiengangsleitung 1/2', '251', 15, 'STUDIENGANGSLEITUNG', true, 19, 'system', NOW()),
('STGL_2_2', 'Studiengangsleitung 2/2', '252', 16, 'STUDIENGANGSLEITUNG', true, 20, 'system', NOW())
ON CONFLICT (modellstelle_kurzbz) DO NOTHING;
-- VERWALTUNG
INSERT INTO hr.tbl_lohnguide_modellstelle(modellstelle_kurzbz, bezeichnung, code, grade, modellfunktion_kurzbz, aktiv, sort, insertvon, insertamum) VALUES
('FK_VERWALTUNG_1_3', 'Fachkraft Verwaltung 1/3', '311', 4, 'FK_VERWALTUNG', true, 21, 'system', NOW()),
('FK_VERWALTUNG_2A_3', 'Fachkraft Verwaltung 2a/3', '312a', 5, 'FK_VERWALTUNG', true, 22, 'system', NOW()),
('FK_VERWALTUNG_2B_3', 'Fachkraft Verwaltung 2b/3', '312b', 5, 'FK_VERWALTUNG', true, 23, 'system', NOW()),
('FK_VERWALTUNG_3_3', 'Fachkraft Verwaltung 3/3', '313', 6, 'FK_VERWALTUNG', true, 24, 'system', NOW()),
('SFK_VERWALTUNG_1_4', 'Spezial-Fachkraft Verwaltung 1/4', '321', 7, 'SFK_VERWALTUNG', true, 25, 'system', NOW()),
('SFK_VERWALTUNG_2A_4', 'Spezial-Fachkraft Verwaltung 2a/4', '322a', 8, 'SFK_VERWALTUNG', true, 26, 'system', NOW()),
('SFK_VERWALTUNG_2B_4', 'Spezial-Fachkraft Verwaltung 2b/4', '322b', 8, 'SFK_VERWALTUNG', true, 27, 'system', NOW()),
('SFK_VERWALTUNG_3A_4', 'Spezial-Fachkraft Verwaltung 3a/4', '323a', 9, 'SFK_VERWALTUNG', true, 28, 'system', NOW()),
('SFK_VERWALTUNG_3B_4', 'Spezial-Fachkraft Verwaltung 3b/4', '323b', 9, 'SFK_VERWALTUNG', true, 29, 'system', NOW()),
('SFK_VERWALTUNG_4_4', 'Spezial-Fachkraft Verwaltung 4/4', '324', 10, 'SFK_VERWALTUNG', true, 30, 'system', NOW()),
('SP_VERWATLTUNG_1_4', 'Spezialist:in Verwaltung 1/4', '331', 11, 'SP_VERWALTUNG', true, 31, 'system', NOW()),
('SP_VERWATLTUNG_2A_4', 'Spezialist:in Verwaltung 2a/4', '332a', 12, 'SP_VERWALTUNG', true, 32, 'system', NOW()),
('SP_VERWATLTUNG_2B_4', 'Spezialist:in Verwaltung 2b/4', '332b', 12, 'SP_VERWALTUNG', true, 33, 'system', NOW()),
('SP_VERWATLTUNG_3A_4', 'Spezialist:in Verwaltung 3a/4', '333a', 13, 'SP_VERWALTUNG', true, 34, 'system', NOW()),
('SP_VERWATLTUNG_3B_4', 'Spezialist:in Verwaltung 3b/4', '333b', 13, 'SP_VERWALTUNG', true, 35, 'system', NOW()),
('SP_VERWATLTUNG_4_4', 'Spezialist:in Verwaltung 4/4', '334', 14, 'SP_VERWALTUNG', true, 36, 'system', NOW()),
('EXP_VERWALTUNG_1_1', 'Expert:in Verwaltung 1/1', '341', 15, 'EXP_VERWALTUNG', true, 37, 'system', NOW())
ON CONFLICT (modellstelle_kurzbz) DO NOTHING;
-- TECHNIK
INSERT INTO hr.tbl_lohnguide_modellstelle(modellstelle_kurzbz, bezeichnung, code, grade, modellfunktion_kurzbz, aktiv, sort, insertvon, insertamum) VALUES
('FK_TECHNIK_1_3', 'Fachkraft Technik 1/3', '311', 4, 'FK_TECHNIK', true, 38, 'system', NOW()),
('FK_TECHNIK_2a_3', 'Fachkraft Technik 2a/3', '312a', 5, 'FK_TECHNIK', true, 39, 'system', NOW()),
('FK_TECHNIK_2b_3','Fachkraft Technik 2b/3', '312b', 5, 'FK_TECHNIK', true, 40, 'system', NOW()),
('FK_TECHNIK_3_3', 'Fachkraft Technik 3/3', '313', 6, 'FK_TECHNIK', true, 41, 'system', NOW())
ON CONFLICT (modellstelle_kurzbz) DO NOTHING;
-- IT & Software
INSERT INTO hr.tbl_lohnguide_modellstelle(modellstelle_kurzbz, bezeichnung, code, grade, modellfunktion_kurzbz, aktiv, sort, insertvon, insertamum) VALUES
('FK_IT_1_2', 'Fachkraft IT & Software 1/2', '411', 5, 'FK_IT', true, 42, 'system', NOW()),
('FK_IT_2_2', 'Fachkraft IT & Software 2/2', '412', 6, 'FK_IT', true, 43, 'system', NOW()),
('SFK_IT_1_4', 'Spezial-Fachkraft IT & Software 1/4', '421', 7, 'SFK_IT', true, 44, 'system', NOW()),
('SFK_IT_2_4', 'Spezial-Fachkraft IT & Software 2/4', '422', 8, 'SFK_IT', true, 45, 'system', NOW()),
('SFK_IT_3_4', 'Spezial-Fachkraft IT & Software 3/4', '423', 9, 'SFK_IT', true, 46, 'system', NOW()),
('SFK_IT_4_4', 'Spezial-Fachkraft IT & Software 4/4', '424', 10, 'SFK_IT', true, 47, 'system', NOW()),
('SP_IT_1_4', 'Spezialist:in IT & Software 1/4', '431', 11, 'SP_IT', true, 48, 'system', NOW()),
('SP_IT_2A_4', 'Spezialist:in IT & Software 2a/4', '432a', 12, 'SP_IT', true, 49, 'system', NOW()),
('SP_IT_2B_4', 'Spezialist:in IT & Software 2b/4', '432b', 12, 'SP_IT', true, 50, 'system', NOW()),
('SP_IT_3A_4', 'Spezialist:in IT & Software 3a/4', '433a', 13, 'SP_IT', true, 51, 'system', NOW()),
('SP_IT_3B_4', 'Spezialist:in IT & Software 3b/4', '433b', 13, 'SP_IT', true, 52, 'system', NOW()),
('SP_IT_4_4', 'Spezialist:in IT & Software 4/4', '434', 14, 'SP_IT', true, 53, 'system', NOW()),
('EXP_IT_1_1', 'Expert:in IT & Software 1/1', '441', 15, 'EXP_IT', true, 54, 'system', NOW())
ON CONFLICT (modellstelle_kurzbz) DO NOTHING;
-- TECHNISCHE DIENSTE
INSERT INTO hr.tbl_lohnguide_modellstelle(modellstelle_kurzbz, bezeichnung, code, grade, modellfunktion_kurzbz, aktiv, sort, insertvon, insertamum) VALUES
('HK_TECHN_DIENSTE_1_4', 'Hilfskraft Technische Dienste 1/4', '511', 1, 'HK_TECHN_DIENSTE', true, 55, 'system', NOW()),
('HK_TECHN_DIENSTE_2_4', 'Hilfskraft Technische Dienste 2/4', '512', 2, 'HK_TECHN_DIENSTE', true, 56, 'system', NOW()),
('HK_TECHN_DIENSTE_3_4', 'Hilfskraft Technische Dienste 3/4', '513', 3, 'HK_TECHN_DIENSTE', true, 57, 'system', NOW()),
('HK_TECHN_DIENSTE_4_4', 'Hilfskraft Technische Dienste 4/4', '514', 4, 'HK_TECHN_DIENSTE', true, 58, 'system', NOW()),
('FK_TECHN_DIENSTE_1_2', 'Fachkraft Technische Dienste 1/2', '521', 5, 'FK_TECHN_DIENSTE', true, 59, 'system', NOW()),
('FK_TECHN_DIENSTE_2_2', 'Fachkraft Technische Dienste 2/2', '522', 6, 'FK_TECHN_DIENSTE', true, 60, 'system', NOW()),
('SFK_TECHN_DIENSTE_1_4', 'Spezial-Fachkraft Technische Dienste 1/4', '531', 7, 'SFK_TECHN_DIENSTE', true, 61, 'system', NOW()),
('SFK_TECHN_DIENSTE_2_4', 'Spezial-Fachkraft Technische Dienste 2/4', '532', 8, 'SFK_TECHN_DIENSTE', true, 62, 'system', NOW()),
('SFK_TECHN_DIENSTE_3_4', 'Spezial-Fachkraft Technische Dienste 3/4', '533', 9, 'SFK_TECHN_DIENSTE', true, 63, 'system', NOW()),
('SFK_TECHN_DIENSTE_4_4', 'Spezial-Fachkraft Technische Dienste 4/4', '534', 10, 'SFK_TECHN_DIENSTE', true, 64, 'system', NOW())
ON CONFLICT (modellstelle_kurzbz) DO NOTHING;
";
if (! $db->db_query($qry))
echo '<strong>Lohnguide Modellstelle: ' . $db->db_last_error() . '</strong><br>';
else
echo 'hr.tbl_lohnguide_modellstelle wurde neu erstellt<br>';
}
}
if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table_name='tbl_lohnguide_fachrichtung' AND table_schema='hr'"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "
CREATE TABLE IF NOT EXISTS hr.tbl_lohnguide_fachrichtung (
fachrichtung_kurzbz character varying(32) NOT NULL,
bezeichnung varchar(32) NOT NULL,
aktiv boolean DEFAULT FALSE,
insertvon character varying(32) NOT NULL,
insertamum timestamp without time zone DEFAULT now() NOT NULL,
updatevon character varying(32),
updateamum timestamp without time zone,
CONSTRAINT tbl_lohnguide_fachrichtung_pkey PRIMARY KEY (fachrichtung_kurzbz)
);
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE hr.tbl_lohnguide_fachrichtung TO vilesci;
INSERT INTO hr.tbl_lohnguide_fachrichtung(fachrichtung_kurzbz,bezeichnung,aktiv,insertvon,insertamum) VALUES
('FA00','Keine Berücksichtigung',true,'system',NOW())
ON CONFLICT (fachrichtung_kurzbz) DO NOTHING;
";
if (! $db->db_query($qry))
echo '<strong>Lohnguide Fachrichtung: ' . $db->db_last_error() . '</strong><br>';
else
echo 'hr.tbl_lohnguide_fachrichtung wurde neu erstellt<br>';
}
}
if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table_name='tbl_vertragsbestandteil_lohnguide' AND table_schema='hr'"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "
CREATE TABLE IF NOT EXISTS hr.tbl_vertragsbestandteil_lohnguide (
vertragsbestandteil_id integer NOT NULL,
vordienstzeit int,
stellenbezeichnung varchar(255),
fachrichtung_kurzbz character varying(32) NOT NULL,
modellstelle_kurzbz character varying(32) NOT NULL,
kommentar_person varchar(255),
kommentar_modellstelle varchar(255),
CONSTRAINT tbl_vertragsbestandteil_lohnguide_pk PRIMARY KEY (vertragsbestandteil_id),
CONSTRAINT tbl_vertragsbestandteil_fk FOREIGN KEY (vertragsbestandteil_id) REFERENCES hr.tbl_vertragsbestandteil (vertragsbestandteil_id) MATCH FULL ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT tbl_vertragsbestandteil_lohnguide_fachrichtung_fk FOREIGN KEY (fachrichtung_kurzbz) REFERENCES hr.tbl_lohnguide_fachrichtung (fachrichtung_kurzbz) MATCH FULL ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT tbl_vertragsbestandteil_modellstelle_fachrichtung_fk FOREIGN KEY (modellstelle_kurzbz) REFERENCES hr.tbl_lohnguide_modellstelle (modellstelle_kurzbz) MATCH FULL ON DELETE RESTRICT ON UPDATE CASCADE
);
COMMENT ON TABLE hr.tbl_vertragsbestandteil_lohnguide IS E'Zuordnung für EU-Entgelttransparenzrichtlinie';
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE hr.tbl_vertragsbestandteil_lohnguide TO vilesci;
";
if (! $db->db_query($qry))
echo '<strong>Vertragsbestandteil Lohnguide: ' . $db->db_last_error() . '</strong><br>';
else
echo 'hr.tbl_vertragsbestandteil_lohnguide wurde neu erstellt<br>';
}
}
if($result = $db->db_query("SELECT 1 FROM hr.tbl_vertragsbestandteiltyp WHERE vertragsbestandteiltyp_kurzbz = 'lohnguide'"))
{
if($db->db_num_rows($result) === 0)
{
$qry = "insert into hr.tbl_vertragsbestandteiltyp (vertragsbestandteiltyp_kurzbz,bezeichnung,ueberlappend) values('lohnguide','Lohnguide',false)";
if(!$db->db_query($qry))
echo '<strong>Public Tabelle person: '.$db->db_last_error().'</strong><br>';
else
echo "<br>Vertragsbestandteiltyp 'lohnguide' hinzugefuegt";
}
}
if ($result = $db->db_query("SELECT * FROM information_schema.columns WHERE column_name='vordienstzeit' AND table_name='tbl_vertragsbestandteil_lohnguide' AND table_schema='hr'"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "
ALTER TABLE
hr.tbl_vertragsbestandteil_lohnguide
ADD COLUMN
vordienstzeit int;
";
if (! $db->db_query($qry))
echo '<strong>Lohnguide: ' . $db->db_last_error() . '</strong><br>';
else
echo 'Spalte vordienstzeit wurde in hr.tbl_vertragsbestandteil_lohnguide neu erstellt<br>';
}
}
if ($result = $db->db_query("SELECT * FROM hr.tbl_gehaltstyp WHERE gehaltstyp_kurzbz='ueberstundenpauschale'"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "
INSERT INTO hr.tbl_gehaltstyp
(gehaltstyp_kurzbz, bezeichnung, valorisierung, sort, aktiv, lvexport)
VALUES
('ueberstundenpauschale','Überstundenpauschale', true, 8, true, true);
";
if (! $db->db_query($qry))
echo '<strong>Gehaltstyp: ' . $db->db_last_error() . '</strong><br>';
else
echo 'Gehaltstyp "Überstundenpauschale" erstellt.<br />';
}
}
if ($result = $db->db_query("SELECT * FROM hr.tbl_gehaltstyp WHERE gehaltstyp_kurzbz='sachbezug_pkw'"))
{
if ($db->db_num_rows($result) == 0)
{
$qry = "
INSERT INTO hr.tbl_gehaltstyp
(gehaltstyp_kurzbz, bezeichnung, valorisierung, sort, aktiv, lvexport)
VALUES
('sachbezug_pkw','Sachbezug PKW', true, 9, true, true);
";
if (! $db->db_query($qry))
echo '<strong>Gehaltstyp: ' . $db->db_last_error() . '</strong><br>';
else
echo 'Gehaltstyp "Sachbezug PKW" erstellt.<br />';
}
}
@@ -0,0 +1,15 @@
<?php
// neuen Organisationseinheittyp (Programm) als Zeile hinzufügen
if($result = @$db->db_query("SELECT 1 FROM public.tbl_organisationseinheittyp WHERE organisationseinheittyp_kurzbz= 'Programm';"))
{
if($db->db_num_rows($result) == 0)
{
$qry = "INSERT INTO public.tbl_organisationseinheittyp(organisationseinheittyp_kurzbz, beschreibung, bezeichnung) VALUES ('Programm', 'Programm', 'Programm');";
if(!$db->db_query($qry))
echo '<strong>public.tbl_organisationseinheittyp: '.$db->db_last_error().'</strong><br>';
else
echo '<br>public.tbl_organisationseinheittyp: Zeile Programm hinzugefuegt!<br>';
}
}
+1231 -2
View File
File diff suppressed because it is too large Load Diff
+23 -13
View File
@@ -742,7 +742,7 @@ function _getFunktionscontainer_Funktionscode123456($bisfunktion_arr)
$has_oe_lehrgang = !($studiengang->studiengang_kz > 0 && $studiengang->studiengang_kz < 10000); $has_oe_lehrgang = !($studiengang->studiengang_kz > 0 && $studiengang->studiengang_kz < 10000);
// STG, die nicht BIS-bemeldet werden, ueberspringen // STG, die nicht BIS-bemeldet werden, ueberspringen
if (in_array($studiengang->studiengang_kz, BIS_EXCLUDE_STG)) if (in_array($studiengang->studiengang_kz, BIS_EXCLUDE_STG) || !$studiengang->melderelevant)
{ {
continue; continue;
} }
@@ -825,6 +825,7 @@ function _addFunktionscontainer_Funktionscode7($uid, $funktion_arr, $stichtag)
$entwicklungsteam_arr = array_filter($entwicklungsteam_arr, function ($obj) { $entwicklungsteam_arr = array_filter($entwicklungsteam_arr, function ($obj) {
return return
!in_array($obj->studiengang_kz, BIS_EXCLUDE_STG) && !in_array($obj->studiengang_kz, BIS_EXCLUDE_STG) &&
$obj->melderelevant &&
$obj->studiengang_kz > 0 && $obj->studiengang_kz > 0 &&
$obj->studiengang_kz < 10000; $obj->studiengang_kz < 10000;
}); });
@@ -875,7 +876,6 @@ function _getLehrecontainer($sws_proStg_arr)
$sws_proStg_arr = array_filter($sws_proStg_arr, function ($obj) { $sws_proStg_arr = array_filter($sws_proStg_arr, function ($obj) {
return return
!in_array($obj->studiengang_kz, BIS_EXCLUDE_STG) && !in_array($obj->studiengang_kz, BIS_EXCLUDE_STG) &&
$obj->studiengang_kz > 0 &&
$obj->studiengang_kz < 10000; $obj->studiengang_kz < 10000;
}); });
} }
@@ -886,13 +886,17 @@ function _getLehrecontainer($sws_proStg_arr)
{ {
$is_sommersemester = substr($sws_proStg->studiensemester_kurzbz, 0, 2) == 'SS'; $is_sommersemester = substr($sws_proStg->studiensemester_kurzbz, 0, 2) == 'SS';
$is_wintersemester = substr($sws_proStg->studiensemester_kurzbz, 0, 2) == 'WS'; $is_wintersemester = substr($sws_proStg->studiensemester_kurzbz, 0, 2) == 'WS';
$is_lehrgang = isset($sws_proStg->lgartcode);
$kennzeichen_name = $is_lehrgang ? 'LehrgangNr' : 'StgKz';
// Lehreobjekt generieren // Lehreobjekt generieren
if (empty($lehre_arr) || !lehre_stg_exists($sws_proStg->studiengang_kz, $lehre_arr)) if (empty($lehre_arr) || !lehre_stg_exists($sws_proStg->melde_studiengang_kz, $lehre_arr))
{ {
$lehre_obj = new StdClass(); $lehre_obj = new StdClass();
$lehre_obj->StgKz = setLeadingZero(intval($sws_proStg->studiengang_kz), 4); $lehre_obj->{$kennzeichen_name} = $sws_proStg->melde_studiengang_kz;
//~ $lehre_obj->StgKz = setLeadingZero(intval($sws_proStg->studiengang_kz), 4);
$lehre_obj->SommersemesterSWS = $is_sommersemester ? $sws_proStg->sws : 0.00; $lehre_obj->SommersemesterSWS = $is_sommersemester ? $sws_proStg->sws : 0.00;
$lehre_obj->WintersemesterSWS = $is_wintersemester ? $sws_proStg->sws : 0.00; $lehre_obj->WintersemesterSWS = $is_wintersemester ? $sws_proStg->sws : 0.00;
@@ -901,8 +905,8 @@ function _getLehrecontainer($sws_proStg_arr)
} }
else // Lehrecontainer mit STG schon vorhanden else // Lehrecontainer mit STG schon vorhanden
{ {
$lehre_obj_arr = array_filter($lehre_arr, function (&$obj) use ($sws_proStg) { $lehre_obj_arr = array_filter($lehre_arr, function (&$obj) use ($sws_proStg, $kennzeichen_name) {
return $obj->StgKz == $sws_proStg->studiengang_kz; return isset($obj->{$kennzeichen_name}) && $obj->{$kennzeichen_name} == $sws_proStg->melde_studiengang_kz;
}); });
// SWS ergaenzen // SWS ergaenzen
@@ -1020,9 +1024,14 @@ function _generateXML($person_arr)
foreach ($person->lehre_arr as $lehre) foreach ($person->lehre_arr as $lehre)
{ {
$xml .= '<Lehre>'; $xml .= '<Lehre>';
$xml .= '<StgKz><![CDATA['. $lehre->StgKz. ']]></StgKz>';
$xml .= '<SommersemesterSWS><![CDATA['. $lehre->SommersemesterSWS. ']]></SommersemesterSWS>'; if (isset($lehre->LehrgangNr))
$xml .= '<WintersemesterSWS><![CDATA['. $lehre->WintersemesterSWS. ']]></WintersemesterSWS>'; $xml .= '<LehrgangNr><![CDATA['. $lehre->LehrgangNr. ']]></LehrgangNr>';
else
$xml .= '<StgKz><![CDATA['. $lehre->StgKz. ']]></StgKz>';
$xml .= '<SommersemesterSWS><![CDATA['. number_format($lehre->SommersemesterSWS, 2, '.', ''). ']]></SommersemesterSWS>';
$xml .= '<WintersemesterSWS><![CDATA['. number_format($lehre->WintersemesterSWS, 2, '.', ''). ']]></WintersemesterSWS>';
$xml .= '</Lehre>'; $xml .= '</Lehre>';
} }
@@ -1211,7 +1220,7 @@ function _outputHTML($person_arr)
{ {
echo ' echo '
<tr> <tr>
<td>'. $lehre->StgKz. '</td> <td>'. (isset($lehre->LehrgangNr) ? $lehre->LehrgangNr : $lehre->StgKz). '</td>
<td>'. $lehre->SommersemesterSWS. '</td> <td>'. $lehre->SommersemesterSWS. '</td>
<td>'. $lehre->WintersemesterSWS. '</td> <td>'. $lehre->WintersemesterSWS. '</td>
</tr>'; </tr>';
@@ -1351,15 +1360,16 @@ function verwendung_exists($bisverwendung, $verwendung_arr)
/** /**
* Prueft ob ein Studiengang bereits im Lehre Container vorhanden ist * Prueft ob ein Studiengang bereits im Lehre Container vorhanden ist
* @param $studiengang_kz Studiengangskennzahl * @param $melde_studiengang_kz Studiengangskennzahl
* @param $lehre_arr Array mit Lehre Objekten * @param $lehre_arr Array mit Lehre Objekten
* @return true wenn der Studiengang bereits existiert * @return true wenn der Studiengang bereits existiert
*/ */
function lehre_stg_exists($studiengang_kz, $lehre_arr) function lehre_stg_exists($melde_studiengang_kz, $lehre_arr)
{ {
foreach($lehre_arr as $row) foreach($lehre_arr as $row)
{ {
if($row->StgKz == $studiengang_kz) $kennzeichenName = isset($row->LehrgangNr) ? 'LehrgangNr' : 'StgKz';
if(isset($row->{$kennzeichenName}) && $row->{$kennzeichenName} == $melde_studiengang_kz)
return true; return true;
} }
return false; return false;
+12 -3
View File
@@ -227,7 +227,8 @@ if (isset($_GET['sendform']))
<table class="tablesorter" id="t1"> <table class="tablesorter" id="t1">
<thead> <thead>
<tr> <tr>
<th><span class="tooltip"><img src="../../skin/images/information.png" height="20px" name="infoicon"/> <th><button type="button" class="resetsaved" title="Reset Filter">Reset Filter</button>
<span class="tooltip"><img src="../../skin/images/information.png" height="20px" name="infoicon"/>
'.$tooltiptext.' '.$tooltiptext.'
</span> </span>
</th> </th>
@@ -364,9 +365,10 @@ if (isset($_GET['sendform']))
$("#t1").tablesorter( $("#t1").tablesorter(
{ {
sortList: [[3,0]], sortList: [[3,0]],
widgets: ["zebra", "filter", "stickyHeaders"], widgets: ["saveSort", "zebra", "filter", "stickyHeaders"],
headers: { 0: { filter: false, sorter: false }}, headers: { 0: { filter: false, sorter: false }},
widgetOptions : { filter_functions : { widgetOptions : { filter_saveFilters : true,
filter_functions : {
// Add select menu to this column // Add select menu to this column
8 : { 8 : {
"True" : function(e, n, f, i, $r, c, data) { return /t/.test(e); }, "True" : function(e, n, f, i, $r, c, data) { return /t/.test(e); },
@@ -382,6 +384,13 @@ if (isset($_GET['sendform']))
} }
}} }}
}); });
$('.resetsaved').click(function()
{
$("#t1").trigger("filterReset");
location.reload(forceGet);
return false;
});
}); });
function changeboolean(ort_kurzbz, name) function changeboolean(ort_kurzbz, name)
@@ -588,7 +588,9 @@ if(isset($_POST['testergebnisanzeigen']) && isset($_POST['prestudent_id']))
{ {
if(is_numeric($_POST['prestudent_id']) && $_POST['prestudent_id']!='') if(is_numeric($_POST['prestudent_id']) && $_POST['prestudent_id']!='')
{ {
$qry="SELECT nachname,vorname,person_id,prestudent_id,tbl_pruefling.pruefling_id,tbl_pruefling_frage.begintime,bezeichnung,kurzbz,tbl_frage.nummer,level, tbl_vorschlag.nummer as antwortnummer, tbl_vorschlag.punkte $qry="SELECT nachname,vorname,person_id,prestudent_id,tbl_pruefling.pruefling_id,
tbl_pruefling_frage.begintime,bezeichnung,kurzbz,tbl_frage.nummer,level,
tbl_vorschlag.nummer as antwortnummer, tbl_vorschlag.punkte, tbl_frage.frage_id
FROM testtool.tbl_antwort FROM testtool.tbl_antwort
JOIN testtool.tbl_vorschlag USING(vorschlag_id) JOIN testtool.tbl_vorschlag USING(vorschlag_id)
JOIN testtool.tbl_frage USING (frage_id) JOIN testtool.tbl_frage USING (frage_id)
@@ -615,6 +617,7 @@ if(isset($_POST['testergebnisanzeigen']) && isset($_POST['prestudent_id']))
<th>Level</th> <th>Level</th>
<th>Antwort #</th> <th>Antwort #</th>
<th>Punkte</th> <th>Punkte</th>
<th>FrageID</th>
</tr> </tr>
</thead> </thead>
<tbody>'; <tbody>';
@@ -632,6 +635,7 @@ if(isset($_POST['testergebnisanzeigen']) && isset($_POST['prestudent_id']))
echo "<td>$row->level</td>"; echo "<td>$row->level</td>";
echo "<td>$row->antwortnummer</td>"; echo "<td>$row->antwortnummer</td>";
echo "<td>$row->punkte</td>"; echo "<td>$row->punkte</td>";
echo "<td>$row->frage_id</td>";
echo '</tr>'; echo '</tr>';
} }
echo '</tbody></table>'; echo '</tbody></table>';
+29 -2
View File
@@ -837,6 +837,25 @@ if(isset($_GET['excel']))
<script src="../../vendor/fgelinas/timepicker/jquery.ui.timepicker.js" type="text/javascript" ></script> <script src="../../vendor/fgelinas/timepicker/jquery.ui.timepicker.js" type="text/javascript" ></script>
<script type="text/javascript"> <script type="text/javascript">
$.tablesorter.addParser({
id: "customDate",
is: function(s) {
//return false;
//use the above line if you don\'t want table sorter to auto detected this parser
// match dd.mm.yyyy e.g. 01.01.2001 as regex
//return /\d{1,4}-\d{1,2}-\d{1,2} \d{1,2}:\d{1,2} .*/.test(s);
return /\d{1,2}.\d{1,2}.\d{1,4}.*/.test(s);
},
// replace regex-wildcards and return new date
format: function(s) {
s = s.replace(/\-/g," ");
s = s.replace(/:/g," ");
s = s.replace(/\./g," ");
s = s.split(" ");
return $.tablesorter.formatFloat(new Date(s[2], s[1]-1, s[0]).getTime());
},
type: "numeric"
});
$(document).ready(function() $(document).ready(function()
{ {
// Check, ob Räume zugeteilt sind oder max_teilnehmer gesetzt ist, wenn "öffentlich" gesetzt wird // Check, ob Räume zugeteilt sind oder max_teilnehmer gesetzt ist, wenn "öffentlich" gesetzt wird
@@ -1007,7 +1026,7 @@ if(isset($_GET['excel']))
{ {
widgets: ["zebra", "filter", "stickyHeaders"], widgets: ["zebra", "filter", "stickyHeaders"],
sortList: [[2,0],[3,0]], sortList: [[2,0],[3,0]],
headers: {0: { sorter: false}}, headers: {0: { sorter: false},10: { sorter: "customDate"},11: { sorter: "customDate"}},
widgetOptions: {filter_cssFilter: [ widgetOptions: {filter_cssFilter: [
"filter_clm_null", "filter_clm_null",
"filter_clm_prestudent_id", "filter_clm_prestudent_id",
@@ -1020,6 +1039,7 @@ if(isset($_GET['excel']))
"filter_clm_studienplan", "filter_clm_studienplan",
"filter_clm_einstiegssemester", "filter_clm_einstiegssemester",
"filter_clm_geburtsdatum", "filter_clm_geburtsdatum",
"filter_clm_anmeldedatum",
"filter_clm_email", "filter_clm_email",
"filter_clm_absolviert"]} "filter_clm_absolviert"]}
}); });
@@ -1072,6 +1092,7 @@ if(isset($_GET['excel']))
'clm_studienplan', 'clm_studienplan',
'clm_einstiegssemester', 'clm_einstiegssemester',
'clm_geburtsdatum', 'clm_geburtsdatum',
"filter_clm_anmeldedatum",
'clm_email', 'clm_email',
'clm_absolviert']; 'clm_absolviert'];
for (var i in arr) for (var i in arr)
@@ -2697,7 +2718,8 @@ if($reihungstest_id!='')
WHERE prestudent_id = tbl_prestudent.prestudent_id WHERE prestudent_id = tbl_prestudent.prestudent_id
AND status_kurzbz = 'Interessent' AND status_kurzbz = 'Interessent'
) LIMIT 1 ) LIMIT 1
) AS orgform_kurzbz ) AS orgform_kurzbz,
tbl_rt_person.anmeldedatum
FROM PUBLIC.tbl_rt_person FROM PUBLIC.tbl_rt_person
JOIN PUBLIC.tbl_person USING (person_id) JOIN PUBLIC.tbl_person USING (person_id)
JOIN PUBLIC.tbl_reihungstest rt ON (rt_id = rt.reihungstest_id) JOIN PUBLIC.tbl_reihungstest rt ON (rt_id = rt.reihungstest_id)
@@ -2786,6 +2808,7 @@ if($reihungstest_id!='')
echo '<div id="clm_studienplan" class="active" onclick="hideColumn(\'clm_studienplan\')">Studienplan</div>'; echo '<div id="clm_studienplan" class="active" onclick="hideColumn(\'clm_studienplan\')">Studienplan</div>';
echo '<div id="clm_einstiegssemester" class="active" onclick="hideColumn(\'clm_einstiegssemester\')">Einstiegssemester</div>'; echo '<div id="clm_einstiegssemester" class="active" onclick="hideColumn(\'clm_einstiegssemester\')">Einstiegssemester</div>';
echo '<div id="clm_geburtsdatum" class="active" onclick="hideColumn(\'clm_geburtsdatum\')">Geburtsdatum</div>'; echo '<div id="clm_geburtsdatum" class="active" onclick="hideColumn(\'clm_geburtsdatum\')">Geburtsdatum</div>';
echo '<div id="clm_anmeldedatum" class="active" onclick="hideColumn(\'clm_anmeldedatum\')">Geburtsdatum</div>';
echo '<div id="clm_email" class="active" onclick="hideColumn(\'clm_email\')">EMail</div>'; echo '<div id="clm_email" class="active" onclick="hideColumn(\'clm_email\')">EMail</div>';
echo '<div id="clm_absolviert" class="active" onclick="hideColumn(\'clm_absolviert\')">Absolvierte Tests <span class="wait"></span></div>'; echo '<div id="clm_absolviert" class="active" onclick="hideColumn(\'clm_absolviert\')">Absolvierte Tests <span class="wait"></span></div>';
//echo '<div id="clm_ergebnis" class="active" onclick="hideColumn(\'clm_ergebnis\')">Ergebnis <span class="wait"></span></div>'; //echo '<div id="clm_ergebnis" class="active" onclick="hideColumn(\'clm_ergebnis\')">Ergebnis <span class="wait"></span></div>';
@@ -2827,6 +2850,7 @@ if($reihungstest_id!='')
<th style="display: table-cell" class="clm_studienplan">Studienplan</th> <th style="display: table-cell" class="clm_studienplan">Studienplan</th>
<th style="display: table-cell" class="clm_einstiegssemester">Einstiegssemester</th> <th style="display: table-cell" class="clm_einstiegssemester">Einstiegssemester</th>
<th style="display: table-cell" class="clm_geburtsdatum">Geburtsdatum</th> <th style="display: table-cell" class="clm_geburtsdatum">Geburtsdatum</th>
<th style="display: table-cell" class="clm_anmeldedatum">Anmeldedatum</th>
<th style="display: table-cell" class="clm_email">EMail</th> <th style="display: table-cell" class="clm_email">EMail</th>
<th style="display: table-cell" class="clm_absolviert">bereits absolvierte Verfahren</th> <th style="display: table-cell" class="clm_absolviert">bereits absolvierte Verfahren</th>
<!--<th style="display: table-cell" class="clm_ergebnis">Ergebnis</th> <!--<th style="display: table-cell" class="clm_ergebnis">Ergebnis</th>
@@ -2946,6 +2970,7 @@ if($reihungstest_id!='')
<td style="display: table-cell" class="clm_studienplan">'.$db->convert_html_chars($studienplan_bezeichnung).' ('.$row->studienplan_id.')</td> <td style="display: table-cell" class="clm_studienplan">'.$db->convert_html_chars($studienplan_bezeichnung).' ('.$row->studienplan_id.')</td>
<td style="display: table-cell" class="clm_einstiegssemester">'.$db->convert_html_chars($row->ausbildungssemester).'</td> <td style="display: table-cell" class="clm_einstiegssemester">'.$db->convert_html_chars($row->ausbildungssemester).'</td>
<td style="display: table-cell" class="clm_geburtsdatum">'.$db->convert_html_chars($row->gebdatum!=''?$datum_obj->convertISODate($row->gebdatum):' ').'</td> <td style="display: table-cell" class="clm_geburtsdatum">'.$db->convert_html_chars($row->gebdatum!=''?$datum_obj->convertISODate($row->gebdatum):' ').'</td>
<td style="display: table-cell" class="clm_anmeldedatum">'.$db->convert_html_chars($row->anmeldedatum!=''?$datum_obj->convertISODate($row->anmeldedatum):' ').'</td>
<td style="display: table-cell; text-align: center" class="clm_email"><a href="mailto:'.$db->convert_html_chars($row->email).'"><img src="../../skin/images/button_mail.gif" name="mail"></a></td> <td style="display: table-cell; text-align: center" class="clm_email"><a href="mailto:'.$db->convert_html_chars($row->email).'"><img src="../../skin/images/button_mail.gif" name="mail"></a></td>
<td style="display: table-cell;" class="clm_absolviert">'.$rt_in_anderen_stg.'</td> <td style="display: table-cell;" class="clm_absolviert">'.$rt_in_anderen_stg.'</td>
</tr>'; </tr>';
@@ -3009,6 +3034,7 @@ if($reihungstest_id!='')
<th style="display: table-cell" class="clm_studienplan">Studienplan</th> <th style="display: table-cell" class="clm_studienplan">Studienplan</th>
<th style="display: table-cell" class="clm_einstiegssemester">Einstiegssemester</th> <th style="display: table-cell" class="clm_einstiegssemester">Einstiegssemester</th>
<th style="display: table-cell" class="clm_geburtsdatum">Geburtsdatum</th> <th style="display: table-cell" class="clm_geburtsdatum">Geburtsdatum</th>
<th style="display: table-cell" class="clm_anmeldedatum">Anmeldedatum</th>
<th style="display: table-cell" class="clm_email">EMail</th> <th style="display: table-cell" class="clm_email">EMail</th>
<th style="display: table-cell" class="clm_absolviert">bereits absolvierte Verfahren</th> <th style="display: table-cell" class="clm_absolviert">bereits absolvierte Verfahren</th>
<!--<th style="display: table-cell" class="clm_ergebnis">Ergebnis</th> <!--<th style="display: table-cell" class="clm_ergebnis">Ergebnis</th>
@@ -3128,6 +3154,7 @@ if($reihungstest_id!='')
<td style="display: table-cell" class="clm_studienplan">'.$db->convert_html_chars($studienplan_bezeichnung).' ('.$row->studienplan_id.')</td> <td style="display: table-cell" class="clm_studienplan">'.$db->convert_html_chars($studienplan_bezeichnung).' ('.$row->studienplan_id.')</td>
<td style="display: table-cell" class="clm_einstiegssemester">'.$db->convert_html_chars($row->ausbildungssemester).'</td> <td style="display: table-cell" class="clm_einstiegssemester">'.$db->convert_html_chars($row->ausbildungssemester).'</td>
<td style="display: table-cell" class="clm_geburtsdatum">'.$db->convert_html_chars($row->gebdatum!=''?$datum_obj->convertISODate($row->gebdatum):' ').'</td> <td style="display: table-cell" class="clm_geburtsdatum">'.$db->convert_html_chars($row->gebdatum!=''?$datum_obj->convertISODate($row->gebdatum):' ').'</td>
<td style="display: table-cell" class="clm_anmeldedatum">'.$db->convert_html_chars($row->anmeldedatum!=''?$datum_obj->convertISODate($row->anmeldedatum):' ').'</td>
<td style="display: table-cell; text-align: center" class="clm_email"><a href="mailto:'.$db->convert_html_chars($row->email).'"><img src="../../skin/images/button_mail.gif" name="mail"></a></td> <td style="display: table-cell; text-align: center" class="clm_email"><a href="mailto:'.$db->convert_html_chars($row->email).'"><img src="../../skin/images/button_mail.gif" name="mail"></a></td>
<td style="display: table-cell;" class="clm_absolviert">'.$rt_in_anderen_stg.'</td>'; <td style="display: table-cell;" class="clm_absolviert">'.$rt_in_anderen_stg.'</td>';
/*echo '<td style="display: table-cell; align: right" class="clm_ergebnis">'.($rtergebnis==0?'-':number_format($rtergebnis,2,'.','')).' %</td> /*echo '<td style="display: table-cell; align: right" class="clm_ergebnis">'.($rtergebnis==0?'-':number_format($rtergebnis,2,'.','')).' %</td>