Compare commits

...

24 Commits

Author SHA1 Message Date
ma0048 e9312dfbb3 lvverwaltung new release 2026-07-15 11:35:37 +02:00
ma0048 b21900d006 Merge remote-tracking branch 'origin/feature-70656/lvverwaltung_gruppen_im_baum_und_drag_and_drop' into feature-77372/lv_verwaltung_release_fine_tuning 2026-07-15 11:27:48 +02:00
ma0048 012571d070 Merge remote-tracking branch 'origin/feature-69453/lv_verwaltung_karteireiter_noten' into feature-77372/lv_verwaltung_release_fine_tuning
# Conflicts:
#	public/js/components/Stv/Studentenverwaltung/Details/Noten/Teacher.js
#	public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js
2026-07-15 09:43:53 +02:00
ma0048 a2d10ae09d Merge remote-tracking branch 'origin/feature-69454/lvverwaltung_karteireiter_lv_termine' into feature-77372/lv_verwaltung_release_fine_tuning
# Conflicts:
#	application/controllers/api/frontend/v1/LvPlan.php
#	public/js/components/Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js
2026-07-15 09:32:03 +02:00
ma0048 96bf45ceb0 Merge remote-tracking branch 'origin/feature-75410/lvverwaltung_finetuning' into feature-77372/lv_verwaltung_release_fine_tuning
# Conflicts:
#	system/phrasesupdate.php
2026-07-15 09:26:55 +02:00
ma0048 c233902fe2 Merge remote-tracking branch 'origin/feature-70746/lvverwaltung_lektorentausch' into feature-77372/lv_verwaltung_release_fine_tuning
# Conflicts:
#	application/libraries/LektorLib.php
2026-07-15 09:20:57 +02:00
ma0048 fd8de88abb Merge remote-tracking branch 'origin/bug-69283/scroll_verhalten_lv_verwaltung_anders_als_in_studierendenverwaltung' into feature-77372/lv_verwaltung_release_fine_tuning 2026-07-15 09:17:51 +02:00
ma0048 0ec2c8c543 Merge remote-tracking branch 'origin/bug-69492/bug_lvverwaltung_doppelte_eintraege' into feature-77372/lv_verwaltung_release_fine_tuning 2026-07-15 09:17:29 +02:00
ma0048 29738b6690 Merge remote-tracking branch 'origin/feature-69353/lv_verwaltung_stundensatz_auf_leer_setzen_geht_nicht' into feature-77372/lv_verwaltung_release_fine_tuning 2026-07-15 09:17:19 +02:00
ma0048 b57836c2af fixed bug 2026-04-28 14:17:23 +02:00
ma0048 e80ee03365 fixed bug 2026-04-28 14:13:22 +02:00
ma0048 7f91e20d03 lvverwaltung: vilesci lehrveranstaltung verwaltung verlinkt 2026-03-04 15:15:12 +01:00
ma0048 233a6e8b89 lvverwaltung:
- event hinzugefuegt damit tabs erweitert werden können
- berichte hinzugefuegt
2026-02-25 15:25:36 +01:00
ma0048 bb23679683 auskommentierten code entfernt 2026-02-12 10:45:32 +01:00
ma0048 e26387a75a lektoren tausch auch bei verplanten lektoren hinzugefuegt 2026-01-19 15:08:59 +01:00
ma0048 ab63bf9d74 gruppen in baum anzeigen und drag and drop von gruppen 2026-01-12 09:27:27 +01:00
ma0048 60f128b314 tabs gleichgezogen 2025-12-09 13:00:40 +01:00
ma0048 cc0a89c924 lvverwaltung noten hinzugefuegt
noten highlight wenn keine note im zeugnis eingetragen ist
2025-12-04 14:18:13 +01:00
ma0048 8f974e8902 sql angepasst 2025-12-03 08:37:38 +01:00
ma0048 a91fe05395 funktionen umbenannt 2025-12-02 13:23:09 +01:00
ma0048 d9cdeb9773 scroll verhalten angepasst 2025-12-02 08:42:04 +01:00
ma0048 0de033e428 termine tab hinzugefuegt 2025-12-01 10:55:04 +01:00
ma0048 1ab9635039 disitnct lv id 2025-11-26 13:56:37 +01:00
ma0048 e7fdbe13d0 nullable felder speichern 2025-11-20 15:32:27 +01:00
48 changed files with 1897 additions and 439 deletions
@@ -49,6 +49,8 @@ class LvPlan extends FHCAPI_Controller
'getLehrverband' => self::PERM_LOGGED,
'permissionOtherLvPlan' => self::PERM_LOGGED,
'compactibleEventTypes' => self::PERM_LOGGED,
'getLeEvents' => self::PERM_LOGGED,
'getLvEvents' => self::PERM_LOGGED,
]);
$this->load->library('LogLib');
@@ -60,7 +62,13 @@ class LvPlan extends FHCAPI_Controller
'dbExecuteUser' => 'RESTful API'
));
$this->load->library('form_validation');
$this->load->library('form_validation');
$this->load->library('PhrasesLib');
$this->loadPhrases(
array(
'ui'
)
);
}
//------------------------------------------------------------------------------------------------------------------
@@ -196,6 +204,38 @@ class LvPlan extends FHCAPI_Controller
));
}
public function getLeEvents($le_id = null, $start_date = null, $end_date = null, $stundenplan = 'stundenplandev')
{
if (is_null($le_id) || is_null($start_date) || is_null($end_date))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
if ($stundenplan !== 'stundenplandev' && $stundenplan !== 'stundenplan')
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$this->load->library('StundenplanLib');
$result = $this->stundenplanlib->getEventsByLE($le_id, $start_date, $end_date, $stundenplan);
$lvplanEvents = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($lvplanEvents);
}
public function getLvEvents($lv_id = null, $start_date = null, $end_date = null, $stundenplan = 'stundenplandev')
{
if (is_null($lv_id) || is_null($start_date) || is_null($end_date))
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
if ($stundenplan !== 'stundenplandev' && $stundenplan !== 'stundenplan')
$this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$this->load->library('StundenplanLib');
$result = $this->stundenplanlib->getEventsByLV($lv_id, $start_date, $end_date, $stundenplan);
$this->terminateWithSuccess(hasData($result) ? getData($result) : []);
}
//TODO: delete this function if we don't use the old calendar export endpoints anymore
public function studiensemesterDateInterval($date)
{
@@ -0,0 +1,86 @@
<?php
if (!defined('BASEPATH'))
exit('No direct script access allowed');
class Config extends FHCAPI_Controller
{
private $_ci;
private $_uid;
public function __construct()
{
parent::__construct([
'get' => ['admin:r', 'assistenz:r'],
'set' => ['admin:r', 'assistenz:r'],
]);
$this->_ci = &get_instance();
$this->_setAuthUID();
$this->loadPhrases([
'lehre'
]);
$this->_ci->load->library('VariableLib', ['uid' => $this->_uid]);
$this->_ci->load->library('PermissionLib');
}
public function get()
{
if (!($this->permissionlib->isBerechtigt('basis/tempus')) && !($this->permissionlib->isBerechtigt('lv-plan')))
$this->terminateWithSuccess([]);
$ignore_kollision = $this->_ci->variablelib->getVar('ignore_kollision');
$ignore_zeitsperre = $this->_ci->variablelib->getVar('ignore_zeitsperre');
$ignore_reservierung = $this->_ci->variablelib->getVar('ignore_reservierung');
$config['ignore_kollision'] = [
"type" => "checkbox",
"label" => 'ignore_kollision',
"value" => $ignore_kollision,
];
$config['ignore_zeitsperre'] = [
"type" => "checkbox",
"label" => 'ignore_zeitsperre',
"value" => $ignore_zeitsperre,
];
$config['ignore_reservierung'] = [
"type" => "checkbox",
"label" => 'ignore_reservierung',
"value" => $ignore_reservierung,
];
$this->terminateWithSuccess($config);
}
public function set()
{
if (!($this->permissionlib->isBerechtigt('basis/tempus')) && !($this->permissionlib->isBerechtigt('lv-plan')))
$this->terminateWithSuccess([]);
$this->load->model('system/Variable_model', 'VariableModel');
foreach (['ignore_kollision','ignore_zeitsperre','ignore_reservierung'] as $variable)
{
if ($this->_ci->input->post($variable) !== null)
{
$this->VariableModel->update(array('uid' => $this->_uid, 'name' => $variable), array('wert' => $this->input->post($variable)));
}
}
$this->terminateWithSuccess();
}
private function _setAuthUID()
{
$this->_uid = getAuthUID();
if (!$this->_uid)
show_error('User authentification failed');
}
}
@@ -15,6 +15,7 @@ class Gruppe extends FHCAPI_Controller
'getBenutzerSearch' => ['admin:r', 'assistenz:r'],
'getAllSearch' => ['admin:r', 'assistenz:r'],
'getByLehreinheit' => ['admin:r', 'assistenz:r'],
'getGruppe' => ['admin:r', 'assistenz:r'],
]);
$this->_ci = &get_instance();
@@ -67,7 +68,7 @@ class Gruppe extends FHCAPI_Controller
$this->checkPermission($lehreinheit_id);
$result = $this->_ci->LehreinheitgruppeModel->addGroup($lehreinheit_id, $gid, !($lehrverband === 'false'));
$result = $this->_ci->LehreinheitgruppeModel->addGroup($lehreinheit_id, $gid, $lehrverband === true || $lehrverband === 'true');
if (isError($result))
$this->terminateWithError(getError($result));
@@ -75,6 +76,71 @@ class Gruppe extends FHCAPI_Controller
$this->terminateWithSuccess($result);
}
public function getGruppe()
{
$lehrverband = $this->input->post('lehrverband');
$gruppen_result = array();
if ($lehrverband === false)
{
$gruppen_result = $this->_ci->GruppeModel->loadWhere(array(
'studiengang_kz' => $this->input->post('stg_kz'),
'gruppe_kurzbz' => $this->input->post('gruppe_kurzbz'),
'aktiv' => true
));
}
else if ($lehrverband === true)
{
if (!isEmptyString($this->input->post('verband')))
{
$this->LehrverbandModel->db->where('verband', $this->input->post('verband'));
}
else
{
$this->LehrverbandModel->db->group_start();
$this->LehrverbandModel->db->where("trim(verband) = ''");
$this->LehrverbandModel->db->or_where("verband IS NULL");
$this->LehrverbandModel->db->group_end();
}
if (!isEmptyString($this->input->post('gruppe')))
{
$this->LehrverbandModel->db->where('gruppe', $this->input->post('gruppe'));
}
else
{
$this->LehrverbandModel->db->group_start();
$this->LehrverbandModel->db->where("trim(gruppe) = ''");
$this->LehrverbandModel->db->or_where("gruppe IS NULL");
$this->LehrverbandModel->db->group_end();
}
if (!isEmptyString((string)$this->input->post('semester')))
{
$this->LehrverbandModel->db->where('semester', $this->input->post('semester'));
}
else
{
$this->LehrverbandModel->db->group_start();
$this->LehrverbandModel->db->where("semester = ''");
$this->LehrverbandModel->db->or_where("semester IS NULL");
$this->LehrverbandModel->db->group_end();
}
$gruppen_result = $this->LehrverbandModel->loadWhere(array('studiengang_kz' => $this->input->post('stg_kz'), 'aktiv' => true));
}
if (!hasData($gruppen_result))
return $this->terminateWithError('No group found');
$gruppen_array = getData($gruppen_result)[0];
$this->terminateWithSuccess($gruppen_array->gid);
}
public function getByLehreinheit($lehreinheit_id = null)
{
if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id))
@@ -134,9 +134,14 @@ class Lektor extends FHCAPI_Controller
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
if (isset($formData['semesterstunden']) && (!is_numeric($formData['semesterstunden']) || $formData['semesterstunden'] === ''))
$nullable_fields = array('semesterstunden', 'stundensatz', 'planstunden');
foreach ($nullable_fields as $nullable_field)
{
$formData['semesterstunden'] = null;
if (isset($formData[$nullable_field]) && (!is_numeric($formData[$nullable_field]) || $formData[$nullable_field] === ''))
{
$formData[$nullable_field] = null;
}
}
$lehreinheit_permission = $this->checkPermission($lehreinheit_id, array('admin', 'assistenz', 'lv-plan'));
@@ -144,6 +149,9 @@ class Lektor extends FHCAPI_Controller
if (!$lehreinheit_permission)
$this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess'));
if (!is_null($this->getLektorVertrag($lehreinheit_id, $mitarbeiter_uid)) && (array_key_exists('mitarbeiter_uid', $formData) && $mitarbeiter_uid !== $formData['mitarbeiter_uid']))
$this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess'));
$result = $this->_ci->lektorlib->updateLektorFromLehreinheit($lehreinheit_id, $mitarbeiter_uid, $formData);
if (isError($result)) $this->terminateWithError(getError($result));
@@ -154,7 +162,7 @@ class Lektor extends FHCAPI_Controller
{
$value = str_replace(',', '.', $value);
if (!is_numeric($value))
if (!is_numeric($value) && $value !== "")
{
$this->form_validation->set_message('_check_decimal', 'Das Feld {field} muss eine Zahl sein.');
return false;
@@ -0,0 +1,84 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
class Noten extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'getCertificate' => 'student/noten:r',
'getTeacherProposal' => 'student/noten:r',
]);
// Load Libraries
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
// Load Phrases
$this->loadPhrases([
'stv',
'person',
'lehre'
]);
}
public function getCertificate($lv_id, $studiensemester_kurzbz = null)
{
if (is_null($lv_id) || !ctype_digit((string)$lv_id))
$this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$this->load->model('education/lehrveranstaltung_model', 'LehrveranstaltungModel');
$this->load->model('education/Zeugnisnote_model', 'ZeugnisnoteModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$result = $this->LehrveranstaltungModel->loadWhere([
'lehrveranstaltung_id' => $lv_id
]);
$lehrveranstaltung = $this->getDataOrTerminateWithError($result);
if (!$lehrveranstaltung)
$this->terminateWithSuccess([]);
if ($studiensemester_kurzbz !== null && !$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
{
$this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester'));
}
$result = $this->ZeugnisnoteModel->getZeugnisnoten(null, $studiensemester_kurzbz, $lehrveranstaltung[0]->lehrveranstaltung_id);
$grades = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($grades);
}
public function getTeacherProposal($lv_id, $studiensemester_kurzbz = null)
{
if (is_null($lv_id) || !ctype_digit((string)$lv_id))
$this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL);
$this->load->model('education/lehrveranstaltung_model', 'LehrveranstaltungModel');
$this->load->model('education/Lvgesamtnote_model', 'LvgesamtnoteModel');
$this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel');
$result = $this->LehrveranstaltungModel->loadWhere([
'lehrveranstaltung_id' => $lv_id
]);
$lehrveranstaltung = $this->getDataOrTerminateWithError($result);
if (!$lehrveranstaltung)
$this->terminateWithSuccess([]);
if ($studiensemester_kurzbz !== null && !$this->StudiensemesterModel->isValidStudiensemester($studiensemester_kurzbz))
{
$this->terminateWithError($studiensemester_kurzbz . ' - ' . $this->p->t('lehre', 'error_noStudiensemester'));
}
$result = $this->LvgesamtnoteModel->getLvGesamtNoten($lv_id, null, $studiensemester_kurzbz);
$grades = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($grades);
}
}
@@ -19,6 +19,8 @@
if (!defined('BASEPATH'))
exit('No direct script access allowed');
use CI3_Events as Events;
class Setup extends FHCAPI_Controller
{
private $_ci;
@@ -27,7 +29,8 @@ class Setup extends FHCAPI_Controller
public function __construct()
{
parent::__construct([
'getTabs' => ['admin:r', 'assistenz:r'],
'getLETabs' => ['admin:r', 'assistenz:r'],
'getLVTabs' => ['admin:r', 'assistenz:r'],
'getStudiensemester' => ['admin:r', 'assistenz:r'],
'getSprache' => ['admin:r', 'assistenz:r'],
'getRaumtyp' => ['admin:r', 'assistenz:r'],
@@ -41,9 +44,10 @@ class Setup extends FHCAPI_Controller
$this->_ci->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel');
$this->_ci->load->library('VariableLib', ['uid' => $this->_uid]);
$this->_ci->load->helper('hlp_document');
}
public function getTabs()
public function getLETabs()
{
$tabs['details'] = array (
'title' => 'Details',
@@ -60,11 +64,43 @@ class Setup extends FHCAPI_Controller
'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Lektor.js'),
'config' => []
);
$tabs['termine'] = array (
'title' => 'Termine',
'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Termine.js'),
'config' => []
);
$tabs['notiz'] = array (
'title' => 'Notizen',
'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Notiz.js'),
'config' => []
);
Events::trigger('lvv_conf_tabs', function & () use (&$tabs) {
return $tabs;
});
$this->terminateWithSuccess($tabs);
}
public function getLVTabs()
{
$tabs['termine'] = array (
'title' => 'Termine',
'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/LVTermine.js'),
'config' => []
);
$tabs['noten'] = array (
'title' => 'Noten',
'component' => absoluteJsImportUrl('public/js/components/LVVerwaltung/Tabs/Noten.js'),
'config' => [
'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE,
'edit' => 'both', // Possible values: both|header|inline
'delete' => 'inline', // Possible values: both|header|inline
'documents' => 'inline', // Possible values: both|header|inline
'documentslist' => gradesDocumentsList(),
'semesterSelect' => false
]
);
$this->terminateWithSuccess($tabs);
}
@@ -25,7 +25,25 @@ class StgTree extends FHCAPI_Controller
return $this->_outputAuthError([$method => ['admin:r', 'assistenz:r']]);
}
return $this->getStudiengang($method);
$count = count($params);
if (!$count)
return $this->getStudiengang($method);
if ($count == 1) {
if (is_numeric($params[0]))
return $this->getSemester($method, $params[0]);
else
return $this->getStudiengang($method, $params[0]);
}
if ($count == 2) {
if (is_numeric($params[0]))
return $this->getVerband($method, $params[0], $params[1]);
else
return $this->getSemester($method, $params[1], $params[0]);
}
show_404();
}
@@ -64,16 +82,27 @@ class StgTree extends FHCAPI_Controller
$this->terminateWithSuccess($list);
}
protected function getStudiengang($studiengang_kz)
protected function getStudiengang($studiengang_kz, $org_form = null)
{
$link = $studiengang_kz . '/';
if ($org_form !== null)
$link .= $org_form . '/';
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addDistinct();
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", semester) AS link", false);
$this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester ORDER BY verband, gruppe LIMIT 1)) AS name", false);
$this->StudiengangModel->addSelect("TRUE AS leaf", false);
$this->StudiengangModel->addSelect("CONCAT(
UPPER(CONCAT(typ, kurzbz)),
'-',
semester,
(
SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END
FROM public.tbl_lehrverband
WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester
ORDER BY verband, gruppe LIMIT 1
)
) AS name", false);
$this->StudiengangModel->addSelect('semester');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
@@ -111,6 +140,115 @@ class StgTree extends FHCAPI_Controller
$list = array_merge($list, $result);
}
}
$this->terminateWithSuccess($list);
}
protected function getSemester($studiengang_kz, $semester, $org_form = null)
{
$link = $studiengang_kz . '/';
if ($org_form !== null)
$link .= $org_form . '/';
$link .= $semester . '/';
$this->load->model('organisation/Gruppe_model', 'GruppeModel');
$this->GruppeModel->addDistinct();
$this->GruppeModel->addSelect("CONCAT(" . $this->GruppeModel->escape($link . 'grp/') . ", gruppe_kurzbz) AS link", false);
$this->GruppeModel->addSelect("CONCAT(gruppe_kurzbz, ' (', bezeichnung, ')') AS name", false);
$this->GruppeModel->addSelect("TRUE AS leaf", false);
$this->GruppeModel->addSelect('sort');
$this->GruppeModel->addSelect('gruppe_kurzbz');
$this->GruppeModel->addSelect($this->GruppeModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->GruppeModel->addOrder('sort');
$this->GruppeModel->addOrder('gruppe_kurzbz');
$where = [
'studiengang_kz' => $studiengang_kz,
'semester' => $semester,
'lehre' => true,
'sichtbar' => true,
'aktiv' => true,
'direktinskription' => false
];
if ($org_form !== null)
$where['orgform_kurzbz'] = $org_form;
$result = $this->GruppeModel->loadWhere($where);
$list = $this->getDataOrTerminateWithError($result);
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", verband) AS link", false);
$this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, verband, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester AND verband=v.verband ORDER BY gruppe LIMIT 1)) AS name", false);
$this->StudiengangModel->addSelect("CASE WHEN MAX(gruppe)='' OR MAX(gruppe)=' ' THEN TRUE ELSE FALSE END AS leaf");
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($semester) . ' AS semester');
$this->StudiengangModel->addSelect('verband');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->StudiengangModel->addOrder('verband');
$this->StudiengangModel->addGroupBy('link, name, verband');
$where = [
'v.studiengang_kz' => $studiengang_kz,
'v.semester' => $semester,
'v.verband !=' => '',
'v.aktiv' => true
];
if ($org_form !== null && $semester) // NOTE(chris): on semester 0 show all?
$where['v.orgform_kurzbz'] = $org_form;
$result = $this->StudiengangModel->loadWhere($where);
$result = $this->getDataOrTerminateWithError($result);
$list = array_merge($list, $result);
$this->terminateWithSuccess($list);
}
protected function getVerband($studiengang_kz, $semester, $verband, $org_form = null)
{
$link = $studiengang_kz . '/';
if ($org_form !== null)
$link .= $org_form . '/';
$link .= $semester . '/'. $verband . '/';
$this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz');
$this->StudiengangModel->addDistinct();
$this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", gruppe) AS link", false);
$this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, verband, gruppe, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester AND verband=v.verband AND gruppe=v.gruppe ORDER BY gruppe LIMIT 1)) AS name", false);
$this->StudiengangModel->addSelect("TRUE AS leaf", false);
$this->StudiengangModel->addSelect('v.semester');
$this->StudiengangModel->addSelect('v.verband');
$this->StudiengangModel->addSelect('gruppe');
$this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false);
$this->StudiengangModel->addOrder('gruppe');
$where = [
'v.studiengang_kz' => $studiengang_kz,
'v.semester' => $semester,
'v.verband' => $verband,
'v.gruppe !=' => '',
'v.aktiv' => true
];
if ($org_form !== null && $semester)
$where['v.orgform_kurzbz'] = $org_form;
$result = $this->StudiengangModel->loadWhere($where);
$list = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($list);
}
@@ -301,6 +301,7 @@ class Config extends FHCAPI_Controller
public function student()
{
$this->load->helper('hlp_document');
$result = [];
$config = $this->config->item('tabs');
@@ -376,9 +377,9 @@ class Config extends FHCAPI_Controller
'config' => [
'usePoints' => defined('CIS_GESAMTNOTE_PUNKTE') && CIS_GESAMTNOTE_PUNKTE,
'edit' => 'both', // Possible values: both|header|inline
'delete' => 'both', // Possible values: both|header|inline
'documents' => 'both', // Possible values: both|header|inline
'documentslist' => $this->gradesDocumentsList()
'delete' => 'inline', // Possible values: both|header|inline
'documents' => 'inline', // Possible values: both|header|inline
'documentslist' => gradesDocumentsList()
]
];
@@ -622,188 +623,6 @@ class Config extends FHCAPI_Controller
] + $this->kontoColumns();
}
/**
* Helper function to generate the default documentslist config for the
* grades tab.
*
* The resulting array consists of elements which are associative arrays
* that can have the following entries:
* title (required) on the first level this can be HTML code.
* permissioncheck (optional) an URL to an FHCAPI endpoint which returns
* true or false.
* link (optional) an URL that will be called if "action" and
* "children" are not defined.
* action (optional) an associative array that describes an
* POST action that will be called if "children" is
* not defined.
* It can have the following entries:
* - url (required) an URL to an FHCAPI endpoint.
* - post (optional) an associative array with the POST data to
* be sent.
* - response (optional) a string that will be displayed on success.
* children (optional) an array of child elements
*
* All strings that start with { and end with } in the URLs and the
* actions post parameter will be replaced with the corresponding
* attribute of the current dataset (e.G: {uid} will be replaced with the
* uid of the current dataset)
*
* @return array
*/
protected function gradesDocumentsList()
{
$permissioncheck = site_url("api/frontend/v1/documents/permissionAlternativeFormat/{studiengang_kz}");
$title_ger = $this->p->t("global", "deutsch");
$title_eng = $this->p->t("global", "englisch");
$title_ff = $this->p->t("stv", "document_certificate");
$title_lv = $this->p->t("stv", "document_coursecertificate");
$link_ff = "documents/export/" .
"zertifikat.rdf.php/" .
"Zertifikat" .
"?stg_kz={studiengang_kz_lv}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$link_lv_ger = "documents/export/" .
"lehrveranstaltungszeugnis.rdf.php/" .
"LVZeugnis" .
"?stg_kz={studiengang_kz}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$link_lv_eng = "documents/export/" .
"lehrveranstaltungszeugnis.rdf.php/" .
"LVZeugnisEng" .
"?stg_kz={studiengang_kz}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$archive_url = "api/frontend/v1/documents/archiveSigned";
$archive_response = $this->p->t("stv", "document_signed_and_archived");
$archive_post_ff = [
"xml" => "zertifikat.rdf.php",
"xsl" => "Zertifikat",
"stg_kz" => "{studiengang_kz_lv}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$archive_post_lv_ger = [
"xml" => "lehrveranstaltungszeugnis.rdf.php",
"xsl" => "LVZeugnis",
"stg_kz" => "{studiengang_kz}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$archive_post_lv_eng = [
"xml" => "lehrveranstaltungszeugnis.rdf.php",
"xsl" => "LVZeugnisEng",
"stg_kz" => "{studiengang_kz}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$list = [
[
'title' => '<i class="fa fa-download" title="' . $this->p->t("stv", "document_download") . '"></i>',
'children' => [
[
'title' => $title_ff,
'link' => site_url($link_ff)
],
[
'title' => $title_lv,
'children' => [
[
'title' => $title_ger,
'link' => site_url($link_lv_ger),
'children' => [
[
'title' => 'PDF',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger)
],
[
'title' => 'DOC',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger . "&output=doc")
],
[
'title' => 'ODT',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger . "&output=odt")
]
]
],
[
'title' => $title_eng,
'link' => site_url($link_lv_eng),
'children' => [
[
'title' => 'PDF',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng)
],
[
'title' => 'DOC',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng . "&output=doc")
],
[
'title' => 'ODT',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng . "&output=odt")
]
]
]
]
]
]
],
[
'title' => '<i class="fas fa-archive" title="' . $this->p->t("stv", "document_archive") . '"></i>',
'children' => [
[
'title' => $title_ff,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_ff,
'response' => $archive_response
]
],
[
'title' => $title_lv,
'children' => [
[
'title' => $title_ger,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_lv_ger,
'response' => $archive_response
]
],
[
'title' => $title_eng,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_lv_eng,
'response' => $archive_response
]
]
]
]
]
]
];
return $list;
}
/**
* Sort tab list
*
@@ -34,7 +34,7 @@ class LvTermine extends FHCAPI_Controller
//TODO Build own lib or combine with Controller Stundenplan.php
//here use of logic of Stundenplan.php, extended with parameters uid, grouping, and used dbTable
public function getStundenplan($uid, $start_date = null, $end_date = null, $groupConsecutiveHours = false, $dbStundenplanTable = "stundenplan")
public function getStundenplan($uid, $start_date = null, $end_date = null, $dbStundenplanTable = "stundenplan", $groupConsecutiveHours = false)
{
$student_uid = $uid;
$semester_range = $this->studienSemesterErmitteln($start_date, $end_date);
@@ -80,13 +80,6 @@ class LvTermine extends FHCAPI_Controller
$stundenplan_data = $this->getDataOrTerminateWithError($stundenplan_data) ?? [];
$this->terminateWithSuccess($stundenplan_data);
$this->expand_object_information($stundenplan_data);
$this->returnObj['$stundenplan_query'] = $stundenplan_query;
$this->returnObj['$student_lehrverband'] = $student_lehrverband;
$this->returnObj['$benutzer_gruppen'] = $benutzer_gruppen;
$this->terminateWithSuccess($stundenplan_data);
}
public function getStudiensemester()
+188
View File
@@ -0,0 +1,188 @@
<?php
if (!defined('BASEPATH')) exit('No direct script access allowed');
/**
* Helper function to generate the default documentslist config for the
* grades tab.
*
* The resulting array consists of elements which are associative arrays
* that can have the following entries:
* title (required) on the first level this can be HTML code.
* permissioncheck (optional) an URL to an FHCAPI endpoint which returns
* true or false.
* link (optional) an URL that will be called if "action" and
* "children" are not defined.
* action (optional) an associative array that describes an
* POST action that will be called if "children" is
* not defined.
* It can have the following entries:
* - url (required) an URL to an FHCAPI endpoint.
* - post (optional) an associative array with the POST data to
* be sent.
* - response (optional) a string that will be displayed on success.
* children (optional) an array of child elements
*
* All strings that start with { and end with } in the URLs and the
* actions post parameter will be replaced with the corresponding
* attribute of the current dataset (e.G: {uid} will be replaced with the
* uid of the current dataset)
*
* @return array
*/
function gradesDocumentsList()
{
$ci =& get_instance();
$ci->load->library('PhrasesLib', array('stv'), 'p');
$permissioncheck = site_url("api/frontend/v1/documents/permissionAlternativeFormat/{studiengang_kz}");
$title_ger = $ci->p->t("global", "deutsch");
$title_eng = $ci->p->t("global", "englisch");
$title_ff = $ci->p->t("stv", "document_certificate");
$title_lv = $ci->p->t("stv", "document_coursecertificate");
$link_ff = "documents/export/" .
"zertifikat.rdf.php/" .
"Zertifikat" .
"?stg_kz={studiengang_kz_lv}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$link_lv_ger = "documents/export/" .
"lehrveranstaltungszeugnis.rdf.php/" .
"LVZeugnis" .
"?stg_kz={studiengang_kz}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$link_lv_eng = "documents/export/" .
"lehrveranstaltungszeugnis.rdf.php/" .
"LVZeugnisEng" .
"?stg_kz={studiengang_kz}" .
"&uid={uid}" .
"&ss={studiensemester_kurzbz}" .
"&lvid={lehrveranstaltung_id}";
$archive_url = "api/frontend/v1/documents/archiveSigned";
$archive_response = $ci->p->t("stv", "document_signed_and_archived");
$archive_post_ff = [
"xml" => "zertifikat.rdf.php",
"xsl" => "Zertifikat",
"stg_kz" => "{studiengang_kz_lv}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$archive_post_lv_ger = [
"xml" => "lehrveranstaltungszeugnis.rdf.php",
"xsl" => "LVZeugnis",
"stg_kz" => "{studiengang_kz}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$archive_post_lv_eng = [
"xml" => "lehrveranstaltungszeugnis.rdf.php",
"xsl" => "LVZeugnisEng",
"stg_kz" => "{studiengang_kz}",
"uid" => "{uid}",
"ss" => "{studiensemester_kurzbz}",
"lvid" => "{lehrveranstaltung_id}"
];
$list = [
[
'title' => '<i class="fa fa-download" title="' . $ci->p->t("stv", "document_download") . '"></i>',
'children' => [
[
'title' => $title_ff,
'link' => site_url($link_ff)
],
[
'title' => $title_lv,
'children' => [
[
'title' => $title_ger,
'link' => site_url($link_lv_ger),
'children' => [
[
'title' => 'PDF',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger)
],
[
'title' => 'DOC',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger . "&output=doc")
],
[
'title' => 'ODT',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_ger . "&output=odt")
]
]
],
[
'title' => $title_eng,
'link' => site_url($link_lv_eng),
'children' => [
[
'title' => 'PDF',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng)
],
[
'title' => 'DOC',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng . "&output=doc")
],
[
'title' => 'ODT',
'permissioncheck' => $permissioncheck,
'link' => site_url($link_lv_eng . "&output=odt")
]
]
]
]
]
]
],
[
'title' => '<i class="fas fa-archive" title="' . $ci->p->t("stv", "document_archive") . '"></i>',
'children' => [
[
'title' => $title_ff,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_ff,
'response' => $archive_response
]
],
[
'title' => $title_lv,
'children' => [
[
'title' => $title_ger,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_lv_ger,
'response' => $archive_response
]
],
[
'title' => $title_eng,
'action' => [
'url' => site_url($archive_url),
'post' => $archive_post_lv_eng,
'response' => $archive_response
]
]
]
]
]
]
];
return $list;
}
+178 -79
View File
@@ -17,7 +17,12 @@ class LektorLib
$this->_ci->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
$this->_ci->load->model('ressource/mitarbeiter_model', 'MitarbeiterModel');
$this->_ci->load->model('person/Benutzer_model', 'BenutzerModel');
$this->_ci->load->model('ressource/Zeitsperre_model', 'ZeitsperreModel');
$this->_ci->load->model('ressource/Reservierung_model', 'ReservierungModel');
$this->_ci->load->model('ressource/stundenplandev_model', 'StundenplandevModel');
$this->_ci->load->library('PhrasesLib', array('lehre'));
$this->_ci->load->library('VariableLib', ['uid' => getAuthUID()]);
}
public function addLektorToLehreinheit($lehreinheit_id, $mitarbeiter_uid)
@@ -78,10 +83,13 @@ class LektorLib
public function updateLektorFromLehreinheit($lehreinheit_id, $mitarbeiter_uid, $new_data)
{
$old_uid = $mitarbeiter_uid;
$new_uid = isset($new_data['mitarbeiter_uid']) ? $new_data['mitarbeiter_uid'] : $mitarbeiter_uid;
$this->_ci->LehreinheitmitarbeiterModel->addSelect('lehre.tbl_lehreinheitmitarbeiter.*, lehre.tbl_lehreinheit.studiensemester_kurzbz, tbl_lehrveranstaltung.studiengang_kz');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id');
$lehreinheit_result = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid));
$lehreinheit_result = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $old_uid));
if (isError($lehreinheit_result)) return $lehreinheit_result;
@@ -89,27 +97,47 @@ class LektorLib
$lehreinheit = getData($lehreinheit_result)[0];
$semesterstunden_alt = $lehreinheit->semesterstunden;
$semesterstunden_neu = isset($new_data['semesterstunden']) ? $new_data['semesterstunden'] : $semesterstunden_alt;
$bismelden_neu = isset($new_data['bismelden']) ? $new_data['bismelden'] : $lehreinheit->bismelden;
$neue_stunden_eingerechnet = (bool)$bismelden_neu;
$alte_stunden_eingerechnet = (bool)$lehreinheit->bismelden;
$stundenplan_update = false;
//TODO kollision check, wird vorerst nicht implementiert -> nur über das FAS möglich
if (isset($new_data['mitarbeiter_uid']) && $new_data['mitarbeiter_uid'] !== $mitarbeiter_uid)
if ($old_uid !== $new_uid)
{
$this->_ci->load->model('ressource/stundenplandev_model', 'StundenplandevModel');
$this->_ci->StundenplandevModel->addGroupBy('stundenplandev_id');
$this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid');
$this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid');
$verplant = $this->_ci->StundenplandevModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid));
if (hasData($verplant))
return error($this->_ci->phraseslib->t("lehre", "lektorbereitsverplant"));
$lehreinheit_data = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('mitarbeiter_uid' => $new_data['mitarbeiter_uid'], 'lehreinheit_id' => $lehreinheit_id));
$lehreinheit_data = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('mitarbeiter_uid' => $new_uid, 'lehreinheit_id' => $lehreinheit_id));
if (hasData($lehreinheit_data))
return error($this->_ci->phraseslib->t("lehre", "bereitzugeteilt"));
$this->_ci->StundenplandevModel->addGroupBy('stundenplandev_id');
$this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid');
$verplant = $this->_ci->StundenplandevModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $old_uid));
if (hasData($verplant))
{
$kollision = $this->hasKollision(getData($verplant), $new_uid);
$ignore_kollision = $this->_ci->variablelib->getVar('ignore_kollision');
if ($kollision === false || $ignore_kollision == 'true')
{
$stundenplan_update = true;
}
else if (is_array($kollision))
{
return error( "Änderung fehlgeschlagen! Die Änderung des Lektors führt zu ".count($kollision)." Kollision(en) im LV-Plan. Deaktivieren Sie die Kollisionspruefung oder wenden Sie sich an die LV-Planung!\n zB. $kollision[0]");
}
else
{
return error($kollision);
}
}
}
$warning = '';
if (isset($new_data['semesterstunden']))
if (($semesterstunden_neu !== '' && $semesterstunden_alt !== '') && (($semesterstunden_neu > $semesterstunden_alt) || $neue_stunden_eingerechnet))
{
$studiengang_result = $this->_ci->StudiengangModel->loadWhere(array('studiengang_kz' => $lehreinheit->studiengang_kz));
if (isError($studiengang_result)) return $studiengang_result;
@@ -120,7 +148,7 @@ class LektorLib
if (isError($studiensemester_result)) return $studiensemester_result;
$studiensemester = getData($studiensemester_result)[0];
$echter_dv_result = $this->_ci->DienstverhaeltnisModel->existsDienstverhaeltnis($mitarbeiter_uid, $studiensemester->start, $studiensemester->ende, 'echterdv');
$echter_dv_result = $this->_ci->DienstverhaeltnisModel->existsDienstverhaeltnis($new_uid, $studiensemester->start, $studiensemester->ende, 'echterdv');
$echter_dv = false;
@@ -129,83 +157,81 @@ class LektorLib
$echter_dv = true;
}
$neue_stunden_eingerechnet = isset($new_data['bismelden']) ? $new_data['bismelden'] : $lehreinheit->bismelden;
$alte_stunden_eingerechnet = $lehreinheit->bismelden;
$stundengrenze_result = $this->_ci->OrganisationseinheitModel->getStundengrenze($studiengang->oe_kurzbz, $echter_dv);
if (isError($stundengrenze_result)) return $stundengrenze_result;
if (($new_data['semesterstunden'] > $lehreinheit->semesterstunden) || $neue_stunden_eingerechnet)
$stundengrenze = getData($stundengrenze_result)[0];
$oe_result = $this->_ci->OrganisationseinheitModel->getChilds($stundengrenze->oe_kurzbz);
$oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array();
$semesterstunden_alt_sql = is_null($semesterstunden_alt) ? 0 : $semesterstunden_alt;
$semesterstunden_neu_sql = is_null($semesterstunden_neu) ? 0 : $semesterstunden_neu;
if ($alte_stunden_eingerechnet && $neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($semesterstunden_alt_sql) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($semesterstunden_neu_sql)}) as summe");
else if ($alte_stunden_eingerechnet && !$neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($semesterstunden_alt_sql)) as summe");
else if (!$alte_stunden_eingerechnet && $neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) + ({$this->_ci->LehreinheitmitarbeiterModel->db->escape($semesterstunden_neu_sql)})) as summe");
else if (!$alte_stunden_eingerechnet && !$neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden)) as summe");
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('public.tbl_studiengang', 'studiengang_kz');
$this->_ci->LehreinheitmitarbeiterModel->db->where('mitarbeiter_uid', $new_uid);
$this->_ci->LehreinheitmitarbeiterModel->db->where('studiensemester_kurzbz', $lehreinheit->studiensemester_kurzbz);
$this->_ci->LehreinheitmitarbeiterModel->db->where('bismelden', true);
$this->_ci->LehreinheitmitarbeiterModel->db->where('lower(mitarbeiter_uid) NOT LIKE', '_dummy%');
if (count($oe_array) > 0)
{
$stundengrenze_result = $this->_ci->OrganisationseinheitModel->getStundengrenze($studiengang->oe_kurzbz, $echter_dv);
if (isError($stundengrenze_result)) return $stundengrenze_result;
$stundengrenze = getData($stundengrenze_result)[0];
$oe_result = $this->_ci->OrganisationseinheitModel->getChilds($stundengrenze->oe_kurzbz);
$oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array('');
if ($alte_stunden_eingerechnet && $neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($lehreinheit->semesterstunden) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])}) as summe");
else if ($alte_stunden_eingerechnet && !$neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($lehreinheit->semesterstunden)) as summe");
else if (!$alte_stunden_eingerechnet && $neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) + ({$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])})) as summe");
else if (!$alte_stunden_eingerechnet && !$neue_stunden_eingerechnet)
$this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden)) as summe");
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id');
$this->_ci->LehreinheitmitarbeiterModel->addJoin('public.tbl_studiengang', 'studiengang_kz');
$this->_ci->LehreinheitmitarbeiterModel->db->where('mitarbeiter_uid', (isset($new_data['mitarbeiter_uid']) ? $new_data['mitarbeiter_uid'] : $mitarbeiter_uid));
$this->_ci->LehreinheitmitarbeiterModel->db->where('studiensemester_kurzbz', $lehreinheit->studiensemester_kurzbz);
$this->_ci->LehreinheitmitarbeiterModel->db->where('bismelden', true);
$this->_ci->LehreinheitmitarbeiterModel->db->where('lower(mitarbeiter_uid) NOT LIKE', '_dummy%');
$this->_ci->LehreinheitmitarbeiterModel->db->where_in('tbl_studiengang.oe_kurzbz', $oe_array);
}
if(defined('FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE')
&& is_array(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE)
&& count(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) > 0)
{
$this->_ci->LehreinheitmitarbeiterModel->db->where_not_in('tbl_studiengang.oe_kurzbz', FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE);
}
if(defined('FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE')
&& is_array(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE)
&& count(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) > 0)
$summe_result = $this->_ci->LehreinheitmitarbeiterModel->load();
if (isError($summe_result)) return $summe_result;
if (!hasData($summe_result)) return error('Fehler beim Ermitteln der Gesamtstunden');
$summe = getData($summe_result)[0]->summe;
if ($summe > $stundengrenze->stunden)
{
if (!$echter_dv && (!$this->_ci->permissionlib->isBerechtigt('admin')))
{
$this->_ci->LehreinheitmitarbeiterModel->db->where_not_in('tbl_studiengang.oe_kurzbz', FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE);
if (!$this->LehrauftragAufFirma($new_uid))
return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden NICHT gespeichert!\n\n");
}
else
{
$warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden gespeichert!\n\n";
}
$summe_result = $this->_ci->LehreinheitmitarbeiterModel->load();
$stunden_limit_result = $this->getStundenInstitut($new_uid, $lehreinheit->studiensemester_kurzbz, $oe_array);
if (isError($summe_result)) return $summe_result;
if (!hasData($summe_result)) return error('Fehler beim Ermitteln der Gesamtstunden');
$summe = getData($summe_result)[0]->summe;
if ($summe > $stundengrenze->stunden)
if (hasData($stunden_limit_result))
{
if (!$echter_dv && (!$this->_ci->permissionlib->isBerechtigt('admin')))
$stunden_limit_array = getData($stunden_limit_result);
foreach ($stunden_limit_array as $stunden_limit)
{
if (!$this->LehrauftragAufFirma(isset($formData['mitarbeiter_uid']) ? $formData['mitarbeiter_uid'] : $mitarbeiter_uid))
return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden NICHT gespeichert!\n\n");
}
else
{
$warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden gespeichert!\n\n";
}
$stunden_limit_result = $this->getStundenInstitut($mitarbeiter_uid, $lehreinheit->studiensemester_kurzbz, $oe_array);
if (hasData($stunden_limit_result))
{
$stunden_limit_array = getData($stunden_limit_result);
foreach ($stunden_limit_array as $stunden_limit)
{
$warning .= $stunden_limit->summe . ' Stunden ' . $stunden_limit->bezeichnung . "\n";
}
$warning .= $stunden_limit->summe . ' Stunden ' . $stunden_limit->bezeichnung . "\n";
}
}
}
}
$benutzer_result = $this->_ci->BenutzerModel->load(array(isset($formData['mitarbeiter_uid']) ? $formData['mitarbeiter_uid'] : $mitarbeiter_uid));
$benutzer_result = $this->_ci->BenutzerModel->load(array($new_uid));
if (isError($benutzer_result)) return $benutzer_result;
@@ -227,12 +253,23 @@ class LektorLib
'bismelden'
);
$nullable_fields = array('stundensatz', 'semesterstunden', 'planstunden');
$updateData = array();
foreach ($updatableFields as $field)
{
$value = isset($new_data[$field]) ? $new_data[$field] : null;
if (!array_key_exists($field, $new_data))
{
continue;
}
if ($value !== null)
$value = $new_data[$field];
if (in_array($field, $nullable_fields))
{
$updateData[$field] = $value;
}
elseif ($value !== null)
{
$updateData[$field] = $value;
}
@@ -240,10 +277,24 @@ class LektorLib
$updateData['updatevon'] = getAuthUID();
$updateData['updateamum'] = date('Y-m-d H:i:s');
$result = $this->_ci->LehreinheitmitarbeiterModel->update(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid), $updateData);
$result = $this->_ci->LehreinheitmitarbeiterModel->update(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $old_uid), $updateData);
if (isError($result)) return $result;
if ($stundenplan_update)
{
$update_result = $this->_ci->StundenplandevModel->update([
'lehreinheit_id' => $lehreinheit_id,
'mitarbeiter_uid' => $old_uid,
], [
'mitarbeiter_uid' => $new_uid,
'updateamum' => date('Y-m-d H:i:s'),
'updatevon' => getAuthUID()
]);
if (isError($update_result)) return $update_result;
}
if ($warning !== '') return success(['warning' => $warning]);
return success('Erfolgreich geupdated');
@@ -347,4 +398,52 @@ class LektorLib
$this->_ci->LehreinheitmitarbeiterModel->addGroupBy('tbl_studiengang.bezeichnung');
return $this->_ci->LehreinheitmitarbeiterModel->load();
}
private function hasKollision($stunden, $mitarbeiter)
{
$kollision = array();
$ignore_zeitsperre = $this->_ci->variablelib->getVar('ignore_zeitsperre');
$ignore_reservierung = $this->_ci->variablelib->getVar('ignore_reservierung');
foreach ($stunden as $stunde)
{
$stundenplan_result = $this->_ci->StundenplandevModel->lektorHasStundenplandevEintrag($mitarbeiter, $stunde->datum, $stunde->stunde);
if (isError($stundenplan_result))
return $stundenplan_result;
if (hasData($stundenplan_result))
{
$stundenplan_result = getData($stundenplan_result)[0];
$kollision[] = "Kollision stundenplandev: $stundenplan_result->stundenplandev_id|$stundenplan_result->lektor|$stundenplan_result->ort_kurzbz|$stundenplan_result->stg_kurzbz-$stundenplan_result->semester$stundenplan_result->verband$stundenplan_result->gruppe$stundenplan_result->gruppe_kurzbz - $stundenplan_result->datum/$stundenplan_result->stunde";
}
else
{
if ($ignore_zeitsperre == 'false' && (!defined('KOLLISIONSFREIE_USER') || !in_array($mitarbeiter, unserialize(KOLLISIONSFREIE_USER))))
{
$zeitsperre_result = $this->_ci->ZeitsperreModel->checkIfZeitsperreExists($mitarbeiter, $stunde->datum, $stunde->stunde);
if (hasData($zeitsperre_result))
{
$zeitsperre_result = getData($zeitsperre_result)[0];
$kollision[] = "Kollision (Zeitsperre): $zeitsperre_result->zeitsperre_id|$zeitsperre_result->mitarbeiter_uid|$zeitsperre_result->zeitsperretyp_kurzbz - $zeitsperre_result->vondatum/$zeitsperre_result->vonstunde|$zeitsperre_result->bisdatum/$zeitsperre_result->bisstunde";
}
}
if ($ignore_reservierung == 'false' && (!defined('KOLLISIONSFREIE_USER') || !in_array($mitarbeiter, unserialize(KOLLISIONSFREIE_USER))))
{
$reservierung_result = $this->_ci->ReservierungModel->lektorHasReservierung($mitarbeiter, $stunde->datum, $stunde->stunde);
if (hasData($reservierung_result))
{
$reservierung_result = getData($reservierung_result)[0];
$kollision[] = "Kollision (Reservierung): $reservierung_result->reservierung_id|$reservierung_result->uid|$reservierung_result->ort_kurzbz|$reservierung_result->stg_kurzbz-$reservierung_result->semester$reservierung_result->verband$reservierung_result->gruppe$reservierung_result->gruppe_kurzbz - $reservierung_result->datum/$reservierung_result->stunde";
}
}
}
}
return isEmptyArray($kollision) ? false : $kollision;
}
}
+15
View File
@@ -184,6 +184,21 @@ class StundenplanLib
return success($stundenplan_data);
}
public function getEventsByLE($lehreinheit_id, $start, $end, $stundenplan)
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Stundenplan_model', 'StundenplanModel');
return $this->_ci->StundenplanModel->getStundenplanLE($lehreinheit_id, $start, $end, $stundenplan);
}
public function getEventsByLV($lehrveranstaltung_id, $start, $end, $stundenplan)
{
$this->_ci =& get_instance();
$this->_ci->load->model('ressource/Stundenplan_model', 'StundenplanModel');
return $this->_ci->StundenplanModel->getStundenplanLV($lehrveranstaltung_id, $start, $end, $stundenplan);
}
/**
* Get stundenplan for a room
*
@@ -341,7 +341,7 @@ class Lehreinheitgruppe_model extends DB_Model
$this->db->where('lehreinheit_id', $lehreinheit_id);
$this->db->where('studiengang_kz', $gruppen_array->studiengang_kz);
if (!isEmptyString($gruppen_array->semester))
if (!isEmptyString((string)$gruppen_array->semester))
{
$this->db->where('semester', $gruppen_array->semester);
}
@@ -444,30 +444,37 @@ class Lehreinheitgruppe_model extends DB_Model
)
ELSE tbl_gruppe.beschreibung
END AS beschreibung");
$this->addSelect("CASE
WHEN tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL THEN
(
SELECT EXISTS (
SELECT 1
FROM lehre.tbl_stundenplandev
WHERE lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id
AND studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND semester = tbl_lehreinheitgruppe.semester
AND TRIM(COALESCE(verband, '')) = TRIM(tbl_lehreinheitgruppe.verband)
AND TRIM(COALESCE(gruppe, '')) = TRIM(tbl_lehreinheitgruppe.gruppe)
AND (gruppe_kurzbz IS NULL OR gruppe_kurzbz = '')
)
)
ELSE
$this->addSelect("
CASE
WHEN trim(COALESCE(tbl_lehreinheitgruppe.gruppe_kurzbz, '')) = '' THEN
(
SELECT EXISTS (
SELECT 1
FROM lehre.tbl_stundenplandev
WHERE lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id
AND gruppe_kurzbz = tbl_lehreinheitgruppe.gruppe_kurzbz
FROM lehre.tbl_stundenplandev sp
WHERE sp.lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id
AND sp.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND sp.semester = tbl_lehreinheitgruppe.semester
AND trim(COALESCE(sp.verband, '')) = trim(COALESCE(tbl_lehreinheitgruppe.verband, ''))
AND trim(COALESCE(sp.gruppe, '')) = trim(COALESCE(tbl_lehreinheitgruppe.gruppe, ''))
AND trim(COALESCE(sp.gruppe_kurzbz, '')) = ''
)
)
END AS verplant");
ELSE
(
SELECT EXISTS (
SELECT 1
FROM lehre.tbl_stundenplandev sp
WHERE sp.lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id
AND sp.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz
AND sp.semester = tbl_lehreinheitgruppe.semester
AND trim(COALESCE(sp.verband, '')) = trim(COALESCE(tbl_lehreinheitgruppe.verband, ''))
AND trim(COALESCE(sp.gruppe, '')) = trim(COALESCE(tbl_lehreinheitgruppe.gruppe, ''))
AND trim(COALESCE(sp.gruppe_kurzbz, '')) = trim(COALESCE(tbl_lehreinheitgruppe.gruppe_kurzbz, ''))
)
)
END AS verplant
");
$this->addJoin('tbl_studiengang', 'studiengang_kz', 'LEFT');
$this->addJoin('public.tbl_gruppe', 'gruppe_kurzbz', 'LEFT');
@@ -1245,7 +1245,7 @@ class Lehrveranstaltung_model extends DB_Model
{
return "
SELECT
lehrveranstaltung_id, tbl_lehrveranstaltung.kurzbz as lv_kurzbz, tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, bezeichnung_english as lv_bezeichnung_english, studiengang_kz,
distinct on (lehrveranstaltung_id) lehrveranstaltung_id, tbl_lehrveranstaltung.kurzbz as lv_kurzbz, tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, bezeichnung_english as lv_bezeichnung_english, studiengang_kz,
tbl_studienplan_lehrveranstaltung.semester, tbl_lehrveranstaltung.sprache,
ects as lv_ects, semesterstunden, anmerkung, lehre, lehreverzeichnis as lv_lehreverzeichnis, tbl_lehrveranstaltung.aktiv,
planfaktor as lv_planfaktor, planlektoren as lv_planlektoren, planpersonalkosten as lv_planpersonalkosten,
@@ -29,10 +29,14 @@ class Lvgesamtnote_model extends DB_Model
$this->addSelect("lv.bezeichnung AS lehrveranstaltung_bezeichnung");
$this->addSelect("lv.studiengang_kz");
$this->addSelect("UPPER(stg.typ || stg.kurzbz) AS studiengang");
$this->addSelect("person.vorname");
$this->addSelect("person.nachname");
$this->addJoin("lehre.tbl_note n", "note");
$this->addJoin("lehre.tbl_lehrveranstaltung lv", "lehrveranstaltung_id");
$this->addJoin("public.tbl_studiengang stg", "studiengang_kz");
$this->addJoin("public.tbl_benutzer benutzer", "uid = student_uid", "LEFT");
$this->addJoin("public.tbl_person person", "person_id", "LEFT");
$this->db->where($this->dbTable . ".freigabedatum <", "NOW()", false);
@@ -148,7 +148,7 @@ class Zeugnisnote_model extends DB_Model
*
* @return object
*/
public function getZeugnisnoten($student_uid, $studiensemester_kurzbz)
public function getZeugnisnoten($student_uid, $studiensemester_kurzbz, $lehrveranstaltung_id = null)
{
$params = array();
$where='';
@@ -163,6 +163,11 @@ class Zeugnisnote_model extends DB_Model
$where.=" AND vw_student_lehrveranstaltung.studiensemester_kurzbz= ?";
$params[] = $studiensemester_kurzbz;
}
if($lehrveranstaltung_id != null)
{
$where .= " AND vw_student_lehrveranstaltung.lehrveranstaltung_id = ?";
$params[] = $lehrveranstaltung_id;
}
$where2='';
@@ -176,6 +181,11 @@ class Zeugnisnote_model extends DB_Model
$where2 .= " AND studiensemester_kurzbz= ?";
$params[] = $studiensemester_kurzbz;
}
if($lehrveranstaltung_id != null)
{
$where2 .=" AND lehrveranstaltung_id = ?";
$params[] = $lehrveranstaltung_id;
}
$qry = "SELECT
a.*,
@@ -188,7 +198,10 @@ class Zeugnisnote_model extends DB_Model
lv.semester AS semester_lv,
lv.ects AS ects_lv,
lv.zeugnis,
lv.bezeichnung_english AS lehrveranstaltung_bezeichnung_english
lv.bezeichnung_english AS lehrveranstaltung_bezeichnung_english,
s.verband,
person.vorname,
person.nachname
FROM (
SELECT vw_student_lehrveranstaltung.lehrveranstaltung_id, uid,
vw_student_lehrveranstaltung.studiensemester_kurzbz, note, punkte, uebernahmedatum, benotungsdatum,
@@ -231,6 +244,8 @@ class Zeugnisnote_model extends DB_Model
ORDER BY sort
) a
LEFT JOIN public.tbl_student s ON (a.uid = s.student_uid)
LEFT JOIN public.tbl_benutzer benutzer ON benutzer.uid = s.student_uid
LEFT JOIN public.tbl_person person ON benutzer.person_id = person.person_id
LEFT JOIN public.tbl_studiengang stg1 ON (s.studiengang_kz = stg1.studiengang_kz)
LEFT JOIN lehre.tbl_lehrveranstaltung lv USING (lehrveranstaltung_id)
LEFT JOIN public.tbl_studiengang stg2 ON (lv.studiengang_kz = stg2.studiengang_kz)";
@@ -135,4 +135,15 @@ class Reservierung_model extends DB_Model
return $this->execQuery($query, [$uid, $uid]);
}
public function lektorHasReservierung($uid, $datum, $stunde)
{
$qry = "SELECT reservierung_id, uid, stg_kurzbz, ort_kurzbz, semester, verband, gruppe, gruppe_kurzbz, datum, stunde
FROM lehre.vw_reservierung
WHERE uid = ?
AND datum = ?
AND stunde = ?";
return $this->execReadOnlyQuery($qry, [$uid, $datum, $stunde]);
}
}
@@ -333,6 +333,68 @@ class Stundenplan_model extends DB_Model
", [$start_date, $end_date, $lv_id]);
}
public function getStundenplanLE($lehreinheit, $start_date, $end_date, $stundenplan)
{
$qry = "
WITH lehreinheiten AS (
SELECT lehreinheit_id FROM lehre.tbl_lehreinheit WHERE lehreinheit_id = ?
), " . $this->getStundenplanCTE($stundenplan) . "
SELECT *
FROM stundenplanentries
";
return $this->execReadOnlyQuery($qry, array($lehreinheit, $start_date, $end_date));
}
public function getStundenplanLV($lehrveranstaltung_id, $start_date, $end_date, $stundenplan)
{
$qry = "
WITH lehreinheiten AS (
SELECT lehreinheit_id
FROM lehre.tbl_lehreinheit
JOIN tbl_studiensemester USING(studiensemester_kurzbz)
WHERE lehrveranstaltung_id = ?
AND tbl_studiensemester.start >= ? AND tbl_studiensemester.ende <= ?
), " . $this->getStundenplanCTE($stundenplan) . "
SELECT *
FROM stundenplanentries
";
return $this->execReadOnlyQuery($qry, array($lehrveranstaltung_id, $start_date, $end_date, $start_date, $end_date));
}
private function getStundenplanCTE($stundenplan)
{
return "entries AS (
SELECT
datum, min(stunde) as stunde_beginn, max(stunde) as stunde_ende,
array_agg(DISTINCT(
CASE WHEN gruppe_kurzbz is not null THEN gruppe_kurzbz
ELSE (UPPER(stg_typ || stg_kurzbz) || COALESCE(semester,'0') || COALESCE(verband,'') || COALESCE(gruppe,''))
END)) as gruppen_kuerzel,
array_agg(DISTINCT CONCAT(vorname || ' ' || nachname)) as lektorname,
array_agg(DISTINCT stundenplan.ort_kurzbz) as ort_kurzbz,
array_agg(DISTINCT titel) as titel,
lehrfach_bez, stundenplan.lehreinheit_id, lehrveranstaltung_id
FROM lehre.vw_$stundenplan as stundenplan
JOIN public.tbl_mitarbeiter ON stundenplan.uid = tbl_mitarbeiter.mitarbeiter_uid
JOIN tbl_benutzer ON tbl_mitarbeiter.mitarbeiter_uid = tbl_benutzer.uid
JOIN tbl_person USING(person_id)
JOIN lehreinheiten ON stundenplan.lehreinheit_id = lehreinheiten.lehreinheit_id
WHERE datum >= ? AND datum <= ?
GROUP BY datum, unr, stundenplan.lehreinheit_id, lehrveranstaltung_id, lehrfach_bez, lehrfach_bez
ORDER BY datum, min(stunde), unr, lehreinheit_id
),
stundenplanentries AS (
SELECT
entries.*,
stundeb.beginn AS beginn,
stundee.ende AS ende
FROM entries
JOIN lehre.tbl_stunde stundeb ON stundeb.stunde = entries.stunde_beginn
JOIN lehre.tbl_stunde stundee ON stundee.stunde = entries.stunde_ende
)";
}
/**
* queries Stundenplan and filters by assigned ma_kurzbz, very similar to get by LVA
*
@@ -241,4 +241,15 @@ class Stundenplandev_model extends DB_Model
return $this->delete(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid));
}
public function lektorHasStundenplandevEintrag($uid, $datum, $stunde)
{
$qry = "SELECT stundenplandev_id, lektor, stg_kurzbz, ort_kurzbz, semester, verband, gruppe, gruppe_kurzbz, datum, stunde
FROM lehre.vw_stundenplandev
WHERE uid = ?
AND datum = ?
AND stunde = ?";
return $this->execReadOnlyQuery($qry, [$uid, $datum, $stunde]);
}
}
@@ -61,4 +61,40 @@ class Zeitsperre_model extends DB_Model
return $this->execQuery($qry);
}
public function checkIfZeitsperreExists($uid, $datum, $stunde)
{
$this->db->select("*");
$this->db->where('mitarbeiter_uid', $uid);
$this->db->where('zeitsperretyp_kurzbz !=', 'ZVerfueg');
$this->db->group_start();
$this->db->where('vondatum <', $datum);
$this->db->or_group_start();
$this->db->where('vondatum', $datum);
$this->db->group_start();
$this->db->where('vonstunde <=', $stunde);
$this->db->or_where('vonstunde IS NULL', null, false);
$this->db->group_end();
$this->db->group_end();
$this->db->group_end();
$this->db->group_start();
$this->db->where('bisdatum >', $datum);
$this->db->or_group_start();
$this->db->where('bisdatum', $datum);
$this->db->group_start();
$this->db->where('bisstunde >=', $stunde);
$this->db->or_where('bisstunde IS NULL', null, false);
$this->db->group_end();
$this->db->group_end();
$this->db->group_end();
return $this->load();
}
}
+2
View File
@@ -31,6 +31,8 @@
lv-root="<?= site_url('LVVerwaltung'); ?>"
:permissions="<?= htmlspecialchars(json_encode($permissions));?>"
:config="<?= htmlspecialchars(json_encode($configs)); ?>"
avatar-url="<?= site_url('Cis/Pub/bild/person/' . getAuthPersonId()); ?>"
logout-url="<?= site_url('Cis/Auth/logout'); ?>"
>
</router-view>
@@ -41,6 +41,12 @@ else
$user = get_uid();
loadVariables($user);
if (isset($_GET['studiensemester_kurzbz']))
{
if (check_stsem($_GET['studiensemester_kurzbz']))
$semester_aktuell = $_GET['studiensemester_kurzbz'];
}
//Studiengang laden
$studiengang = new studiengang($studiengang_kz);
+6
View File
@@ -50,6 +50,12 @@ else
$user = get_uid();
loadVariables($user);
if (isset($_GET['studiensemester_kurzbz']))
{
if (check_stsem($_GET['studiensemester_kurzbz']))
$semester_aktuell = $_GET['studiensemester_kurzbz'];
}
$rechte = new benutzerberechtigung();
$rechte->getBerechtigungen($user);
+6
View File
@@ -38,3 +38,9 @@ textarea[name="anmerkung"] {
{
border-color: black;
}
.node-verband {
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
}
+10 -6
View File
@@ -16,16 +16,20 @@
*/
export default {
getCourselist(params) {
getCourselist(student_uid, start_date, end_date, stundenplan) {
return {
method: 'get',
url: 'api/frontend/v1/stv/LvTermine/getStundenplan/' + params.student_uid + '/'
+ params.start_date + '/'
+ params.end_date + '/'
+ params.group_consecutiveHours + '/'
+ params.dbStundenplanTable
url: 'api/frontend/v1/stv/LvTermine/getStundenplan/' + encodeURIComponent(student_uid) + '/'
+ encodeURIComponent(start_date) + '/'
+ encodeURIComponent(end_date) + '/'
+ encodeURIComponent(stundenplan) + '/'
+ encodeURIComponent(true)
};
},
exportCalendar(student_uid, stundenplan)
{
return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'content/statistik/termine.xls.php?student_uid=' + encodeURIComponent(student_uid) + '&db_stpl_table='+encodeURIComponent(stundenplan);
},
getStudiensemester(){
return {
method: 'get',
+15
View File
@@ -0,0 +1,15 @@
export default {
get() {
return {
method: 'get',
url: '/api/frontend/v1/lv/config/get'
};
},
set(params) {
return {
method: 'post',
url: 'api/frontend/v1/lv/config/set',
params
};
}
};
@@ -18,6 +18,14 @@ export default {
params: newData
};
},
getGruppe(gruppe)
{
return {
method: 'post',
url: '/api/frontend/v1/lv/gruppe/getGruppe/',
params: gruppe
};
},
getByLehreinheit(lehreinheit_id)
{
return {
@@ -0,0 +1,19 @@
export default {
getCourselist(le_id, start_date, end_date, stundenplan)
{
return {
method: 'get',
url: '/api/frontend/v1/lvPlan/getLeEvents/' + encodeURIComponent(le_id) + "/" + encodeURIComponent(start_date) + "/" + encodeURIComponent(end_date) + "/" + encodeURIComponent(stundenplan),
};
},
exportCalendar(le_id, stundenplan)
{
return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'content/statistik/termine.xls.php?lehreinheit_id=' + encodeURIComponent(le_id) + '&db_stpl_table='+encodeURIComponent(stundenplan);
},
getStudiensemester(){
return {
method: 'get',
url: '/api/frontend/v1/lv/setup/getStudiensemester/'
};
},
};
@@ -0,0 +1,19 @@
export default {
getCourselist(lv_id, start_date, end_date, stundenplan)
{
return {
method: 'get',
url: '/api/frontend/v1/lvPlan/getLvEvents/' + encodeURIComponent(lv_id) + "/" + encodeURIComponent(start_date) + "/" + encodeURIComponent(end_date) + "/" + encodeURIComponent(stundenplan),
};
},
exportCalendar(lv_id, stundenplan)
{
return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'content/statistik/termine.xls.php?lehrveranstaltung_id=' + encodeURIComponent(lv_id) + '&db_stpl_table='+encodeURIComponent(stundenplan);
},
getStudiensemester(){
return {
method: 'get',
url: '/api/frontend/v1/lv/setup/getStudiensemester/'
};
},
};
+25
View File
@@ -0,0 +1,25 @@
import Grades from '../factory/stv/grades.js';
export default {
...Grades,
getCertificate(lv_id, studiensemester_kurzbz) {
let url = 'api/frontend/v1/lv/noten/getCertificate/' + encodeURIComponent(lv_id);
if (!!studiensemester_kurzbz) {
url = url + '/' + encodeURIComponent(studiensemester_kurzbz);
}
return {
method: 'get',
url: url
};
},
getTeacherProposal(lv_id, studiensemester_kurzbz) {
let url = 'api/frontend/v1/lv/noten/getTeacherProposal/' + encodeURIComponent(lv_id);
if (!!studiensemester_kurzbz) {
url = url + '/' + encodeURIComponent(studiensemester_kurzbz);
}
return {
method: 'get',
url: url
};
},
};
+9 -2
View File
@@ -1,9 +1,16 @@
export default {
getTabs()
getLETabs()
{
return {
method: 'get',
url: '/api/frontend/v1/lv/setup/getTabs/'
url: '/api/frontend/v1/lv/setup/getLETabs/'
};
},
getLVTabs()
{
return {
method: 'get',
url: '/api/frontend/v1/lv/setup/getLVTabs/'
};
},
}
@@ -2,6 +2,7 @@ import {CoreFilterCmpt} from "../../filter/Filter.js";
import FormForm from '../../Form/Form.js';
import FormInput from '../../Form/Input.js';
import ApiGruppe from "../../../api/lehrveranstaltung/gruppe.js";
import drop from '../../../directives/drop.js';
export default{
name: "LVGruppen",
components: {
@@ -9,6 +10,9 @@ export default{
FormForm,
FormInput
},
directives: {
drop
},
props: {
lehreinheit_id: Number
},
@@ -187,28 +191,48 @@ export default{
this.reload();
})
},
onDropVerband(node, gruppe) {
this.$api.call(ApiGruppe.getGruppe(gruppe))
.then(result => result.data)
.then(result => {
let newData = {
'gid': result,
'lehreinheit_id': this.lehreinheit_id,
'lehrverband': gruppe.lehrverband,
}
this.$api.call(ApiGruppe.add(newData))
.then(result => {
this.reload()
})
});
},
},
template: `
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
table-only
:side-menu="false"
:reload=true
>
<template #search> <!--TODO (david) Slot prüfen -->
<form-input
type="autocomplete"
:suggestions="filteredGroups"
:placeholder="$p.t('lehre', 'addGroup')"
v-model="selectedGroup"
field="label"
@item-select="addGroup"
@complete="searchGroup"
></form-input>
</template>
</core-filter-cmpt>
<div v-drop:link-strict.verband="(evt, gruppe) => onDropVerband(node, gruppe)">
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
table-only
:side-menu="false"
:reload=true
>
<template #search> <!--TODO (david) Slot prüfen -->
<form-input
type="autocomplete"
:suggestions="filteredGroups"
:placeholder="$p.t('lehre', 'addGroup')"
v-model="selectedGroup"
field="label"
@item-select="addGroup"
@complete="searchGroup"
></form-input>
</template>
</core-filter-cmpt>
</div>
`
};
@@ -8,9 +8,10 @@ import LvTabs from "./Setup/Tabs.js";
import ApiDetails from "../../api/lehrveranstaltung/details.js";
import ApiLektor from "../../api/lehrveranstaltung/lektor.js";
import ApiGruppe from "../../api/lehrveranstaltung/gruppe.js";
import ApiStudiengangTree from "../../api/lehrveranstaltung/studiengangtree.js";
import ApiSearchbar from "../../api/factory/searchbar.js";
import AppConfig from "../AppConfig.js";
import ApiLvConfig from "../../api/lehrveranstaltung/config.js";
export default {
@@ -23,6 +24,7 @@ export default {
StvStudiensemester,
LvTable,
LvTabs,
AppConfig
},
props: {
defaultSemester: String,
@@ -32,7 +34,9 @@ export default {
stg: { type: String, required: false },
semester: { type: [Number, String], required: false, default: null },
studiensemester_kurzbz: { type: String, required: false, default: null },
emp: { type: String, required: false, default: null }
emp: { type: String, required: false, default: null },
avatarUrl: String,
logoutUrl: String,
},
provide() {
@@ -44,7 +48,6 @@ export default {
lehreinheitAnmerkungDefault: (this.config.lehreinheitAnmerkungDefault || '').replace(/\\n/g, '\n'),
lehreinheitRaumtypDefault: this.config.lehreinheitRaumtypDefault,
lehreinheitRaumtypAlternativeDefault: this.config.lehreinheitRaumtypAlternativeDefault,
permissionLehrveranstaltung: this.permissions['lehre/lehrveranstaltung'],
permissionGruppenEntfernen: this.permissions['lv-plan/gruppenentfernen'],
permissionLektorEntfernen: this.permissions['lv-plan/lektorentfernen'],
@@ -72,6 +75,8 @@ export default {
},
data() {
return {
appconfig:{},
configEndpoints: ApiLvConfig,
selected: [],
studiengang: "",
filter: {},
@@ -205,6 +210,21 @@ export default {
this.$router.push({ name: routeName, params: newParams });
this.selected = [];
},
isDisabled(item)
{
if (!item?.requires?.length)
return false;
const values = {
stg: this.stg,
emp: this.emp,
studiensemester: this.selectedStudiensemester,
semester: this.semester
};
return item.requires.some(req => !values[req]);
}
},
created() {
this.$p.loadCategory(['lehre', 'person', 'global'])
@@ -239,6 +259,74 @@ export default {
})
.catch(this.$fhcAlert.handleSystemError);
},
computed:
{
appMenuExtraItems()
{
let extraItems = [];
const studiengang_kz = this.stg || '';
const studiensemester = this.selectedStudiensemester;
const semester = this.semester || '';
const uid = this.emp || '';
extraItems.push(
{
description: 'lehre/berichte',
requires: ['stg'],
children: [
{
link: FHC_JS_DATA_STORAGE_OBJECT.app_root
+ 'content/statistik/lvplanung.xls.php'
+ '?studiengang_kz=' + studiengang_kz
+ '&studiensemester_kurzbz=' + studiensemester
+ '&semester=' + semester,
description: 'lehre/lvplanung',
requires: ['stg']
},
{
link: FHC_JS_DATA_STORAGE_OBJECT.app_root
+ 'content/statistik/lehrauftragsliste_gst.xls.php'
+ '?studiengang_kz=' + studiengang_kz
+ '&studiensemester_kurzbz=' + studiensemester
+ '&semester=' + semester,
description: 'lehre/lehrauftragsliste',
requires: ['stg']
},
{
link: FHC_JS_DATA_STORAGE_OBJECT.app_root
+ 'content/pdfExport.php?xml=lehrauftrag.xml.php'
+ '&xsl=Lehrauftrag'
+ '&stg_kz=' + studiengang_kz
+ '&ss=' + studiensemester,
description: 'lehre/lehrauftraege',
requires: ['stg']
},
{
link: FHC_JS_DATA_STORAGE_OBJECT.app_root
+ 'content/pdfExport.php?xml=lehrauftrag.xml.php'
+ '&xsl=Lehrauftrag'
+ '&stg_kz=' + studiengang_kz
+ '&ss=' + studiensemester
+ '&uid=' + uid,
description: 'lehre/lehrauftragslisteemp',
requires: ['emp']
}
]
},
{
link: FHC_JS_DATA_STORAGE_OBJECT.app_root
+ 'vilesci/lehre/lehrveranstaltung.php'
+ '?stg_kz=' + studiengang_kz,
description: 'lehre/extrakvverwaltung',
requires: ['stg']
}
);
return extraItems;
}
},
template: /* html */`
<div class="stv">
@@ -269,6 +357,51 @@ export default {
<span class="fa-solid fa-table-list"></span>
</button>
<core-searchbar :searchoptions="searchbaroptions" :searchfunction=searchfunction class="searchbar w-100"></core-searchbar>
<div id="nav-user" class="dropdown">
<button
id="nav-user-btn"
class="btn btn-link rounded-0 py-0"
type="button"
data-bs-toggle="dropdown"
data-bs-target="#nav-user-menu"
aria-expanded="false"
aria-controls="nav-user-menu"
>
<img
:src="avatarUrl"
:alt="$p.t('profilUpdate/profilBild')"
class="bg-light avatar rounded-circle border border-light"
/>
</button>
<ul
ref="navUserDropdown"
class="dropdown-menu dropdown-menu-dark dropdown-menu-end rounded-0 text-center m-0"
aria-labelledby="nav-user-btn"
>
<li>
<button
type="button"
class="dropdown-item"
data-bs-toggle="modal"
data-bs-target="#configModal"
>
{{ $p.t('ui/settings') }}
</button>
</li>
<li><hr class="dropdown-divider m-0"/></li>
<li>
<nav-language
item-class="dropdown-item border-left-dark"
/>
</li>
<li><hr class="dropdown-divider m-0"/></li>
<li>
<a class="dropdown-item" :href="logoutUrl">
{{ $p.t('ui/logout') }}
</a>
</li>
</ul>
</div>
</header>
<div class="container-fluid overflow-hidden">
<div class="row h-100">
@@ -278,14 +411,47 @@ export default {
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" :aria-label="$p.t('ui/schliessen')"></button>
</div>
<div class="offcanvas-body">
<app-menu app-identifier="lvv" />
<app-menu app-identifier="lvv">
<template v-for="(item, key) in appMenuExtraItems" :key="key">
<li v-if="item.children" class="dropend">
<a
class="dropdown-toggle"
href="#"
role="button"
data-bs-toggle="dropdown"
aria-expanded="false"
data-bs-popper-config='{"strategy":"fixed"}'
>
{{ $p.t(item.description) }}
</a>
<ul class="dropdown-menu p-0">
<li
v-for="(child, childKey) in item.children"
:key="childKey"
>
<a class="dropdown-item" :href="child.link" target="_blank" :class="{ disabled: isDisabled(child) }">
{{ $p.t(child.description) }}
</a>
</li>
</ul>
</li>
<li v-else>
<a
:href="item.link"
target="_blank"
:class="{ disabled: isDisabled(item) }">
{{ $p.t(item.description) }}
</a>
</li>
</template>
</app-menu>
</div>
</aside>
<nav id="sidebarMenu" class="bg-light offcanvas offcanvas-start col-md p-md-0 h-100">
<div class="offcanvas-header justify-content-end px-1 d-md-none">
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" :aria-label="$p.t('ui/schliessen')"></button>
</div>
<stv-verband :preselectedKey="selectedStudiengang" :endpoint="endpoint" @select-verband="onSelectVerband" class="col" style="height:0%"></stv-verband>
<stv-verband :preselectedKey="selectedStudiengang" :dragEnabled=true :endpoint="endpoint" @select-verband="onSelectVerband" class="col" style="height:0%"></stv-verband>
<stv-studiensemester v-model:studiensemester-kurzbz="selectedStudiensemester" @update:studiensemester-kurzbz="studiensemesterChanged"></stv-studiensemester>
</nav>
@@ -327,5 +493,6 @@ export default {
</main>
</div>
</div>
<app-config ref="config" v-model="appconfig" :endpoints="configEndpoints"></app-config>
</div>`
};
@@ -140,7 +140,7 @@ export default{
{
this.$emit('changedLektor', this.changed.mitarbeiter_uid);
}
if (this.changed.semesterstunden || this.changed.stundensatz)
else if (this.changed.semesterstunden || this.changed.stundensatz)
{
this.$emit('changedCosts');
}
@@ -183,9 +183,6 @@ export default{
},
},
created() {
this.getLektorData()
},
template: `
<core-form ref="form" @submit.prevent="updateDaten">
<div class="position-sticky top-0 z-1">
@@ -54,6 +54,7 @@ export default {
if (this.$refs.table && this.$refs.table.tabulator)
{
this.expanded = [];
this.currentTreeLevel = 0;
this.reload();
}
},
@@ -140,7 +141,8 @@ export default {
headerFilterFunc: extendedHeaderFilter,
},
layout: 'fitDataStretch',
persistenceID: 'lehrveranstaltungen_2025_07_31_v1',
height: '100%',
persistenceID: 'lehrveranstaltungen_2026_07_15_v1',
selectableRowsRangeMode: 'click',
selectableRows: true,
rowContextMenu: (component, e) => {
@@ -304,14 +306,13 @@ export default {
if (data[0]?.lehreinheit_id !== undefined && this.selectedColumnValues.length === 1)
{
this.$emit('update:selected', [data[0]]);
this.lv_info = false
}
else if (data[0]?.lehrveranstaltung_id)
{
this.$emit('update:selected', {});
this.getLVInfos(data[0]);
}
this.$emit('update:selected', data);
},
getLVInfos(data)
{
@@ -518,47 +519,50 @@ export default {
},
},
template: `
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
table-only
:side-menu="false"
:reload=true
new-btn-label="LV-Teil hinzufügen"
new-btn-show
:new-btn-disabled="!lv_info"
@click:new="showLehreinheitModal">
<template #actions>
<button @click="expandTree" class="btn btn-outline-secondary" type="button" :title="$p.t('lehre', 'aufklappen')"><i class="fa-solid fa-maximize"></i></button>
<button @click="resetTree" class="btn btn-outline-secondary" type="button" :title="$p.t('lehre', 'zuklappen')"><i id="togglegroup" class="fa-solid fa-minimize"></i></button>
<core-tag ref="tagComponent"
:endpoint="tagEndpoint"
:values="selectedColumnValues"
@added="addedTag"
@deleted="deletedTag"
@updated="updatedTag"
zuordnung_typ="lehreinheit_id"
></core-tag>
</template>
<template #search>
<slot name="filterzuruecksetzen"></slot>
</template>
</core-filter-cmpt>
<bs-modal ref="lehreinheitModal" dialogClass="modal-xxl">
<template #title>
<p class="fw-bold mt-3">{{$p.t('lehre', 'newlehreinheit')}}</p>
</template>
<template v-if="lv_info">
<details-form :data="lv_info"/>
</template>
<template #footer>
<button type="button" class="btn btn-primary" @click="addNewLehreinheit">{{$p.t('ui', 'speichern')}}</button>
</template>
</bs-modal>
<div class="lv-list h-100 pt-3">
<div class="tabulator-container d-flex flex-column h-100">
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
table-only
:side-menu="false"
:reload=true
new-btn-label="LV-Teil hinzufügen"
new-btn-show
:new-btn-disabled="!lv_info"
@click:new="showLehreinheitModal">
<template #actions>
<button @click="expandTree" class="btn btn-outline-secondary" type="button" :title="$p.t('lehre', 'aufklappen')"><i class="fa-solid fa-maximize"></i></button>
<button @click="resetTree" class="btn btn-outline-secondary" type="button" :title="$p.t('lehre', 'zuklappen')"><i id="togglegroup" class="fa-solid fa-minimize"></i></button>
<core-tag ref="tagComponent"
:endpoint="tagEndpoint"
:values="selectedColumnValues"
@added="addedTag"
@deleted="deletedTag"
@updated="updatedTag"
zuordnung_typ="lehreinheit_id"
></core-tag>
</template>
<template #search>
<slot name="filterzuruecksetzen"></slot>
</template>
</core-filter-cmpt>
</div>
<bs-modal ref="lehreinheitModal" dialogClass="modal-xxl">
<template #title>
<p class="fw-bold mt-3">{{$p.t('lehre', 'newlehreinheit')}}</p>
</template>
<template v-if="lv_info">
<details-form :data="lv_info"/>
</template>
<template #footer>
<button type="button" class="btn btn-primary" @click="addNewLehreinheit">{{$p.t('ui', 'speichern')}}</button>
</template>
</bs-modal>
</div>
`
};
@@ -8,6 +8,7 @@ export default {
},
data() {
return {
configLETabs: {},
configLVTabs: {},
};
},
@@ -19,7 +20,7 @@ export default {
if (!this.lv || !this.lv.length)
return {};
return this.configLVTabs;
return this.configLETabs;
}
},
methods: {
@@ -31,26 +32,42 @@ export default {
}
},
created() {
this.$api.call(Setup.getTabs())
this.$api.call(Setup.getLETabs())
.then(result => {
this.configLETabs = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
this.$api.call(Setup.getLVTabs())
.then(result => {
this.configLVTabs = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
},
template: `
<div class="stv-details h-100 pb-3 d-flex flex-column">
<div v-if="!lv?.length" class="justify-content-center d-flex h-100 align-items-center">
Bitte eine Lehreinheit auswählen!
</div>
<div v-else-if="configLVTabs" class="d-flex flex-column h-100 pb-3">
<div v-else-if="configLETabs && configLVTabs" class="d-flex flex-column h-100 pb-3">
<fhc-tabs
v-if="lv.length === 1"
v-if="lv.length === 1 && lv[0]?.lehreinheit_id"
ref="tabs"
:useprimevue="true"
:modelValue="lv[0]"
:config="configLETabs"
:default="$route.params.tab"
style="flex: 1 1 0%; height: 0%"
@changed="reload"
/>
<fhc-tabs
v-else-if="lv.length === 1"
ref="tabs"
:useprimevue="true"
:modelValue="lv[0]"
:config="configLVTabs"
:default="$route.params.tab"
style="flex: 1 1 0%; height: 0%"
@changed="reload"
/>
</div>
@@ -0,0 +1,21 @@
import TableLvList from "../../Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js";
import ApiLVTermine from "../../../api/lehrveranstaltung/lvtermine.js";
export default {
name: "LVTabTermine",
components: {
TableLvList
},
props: {
modelValue: Object,
},
data() {
return {
endpoint: ApiLVTermine
};
},
template: `
<div class="lv-details-course-list h-100 d-flex flex-column">
<table-lv-list ref="tbl_course_list" :id="modelValue.lehrveranstaltung_id" :endpoint="endpoint"></table-lv-list>
</div>`
};
@@ -0,0 +1,116 @@
import NotenZeugnis from "../../Stv/Studentenverwaltung/Details/Noten/Zeugnis.js";
import NotenTeacher from "../../Stv/Studentenverwaltung/Details/Noten/Teacher.js";
import NotenRepeater from "../../Stv/Studentenverwaltung/Details/Noten/Repeater.js";
import ApiLVNoten from "../../../api/lehrveranstaltung/noten.js";
import { highlightGesamtnote } from "../../../helpers/DocumentHelper.js";
const LOCAL_STORAGE_ID = 'lv_details_noten_2025_12_02_stdsem_all';
export default {
name: "LVTabNoten",
components: {
NotenZeugnis,
NotenTeacher,
NotenRepeater
},
provide() {
return {
config: this.config
}
},
props: {
modelValue: Object,
config: Object
},
data() {
return {
stdsem: '',
endpoint: ApiLVNoten,
tabulatorOptions: {
visibleColumns: {
vorname: true,
nachname: true,
lehrveranstaltung_bezeichnung: false
},
headerFilter: {
vorname: true,
nachname: true,
lehrveranstaltung_bezeichnung: false
},
persistenceZeugnisID: 'lv-details-noten-zeugnis-2025120401',
persistenceTeacherID: 'lv-details-noten-teacher-2025120401',
},
zeugnisLoaded: false,
teacherLoaded: false,
};
},
methods: {
reload() {
this.zeugnisLoaded = false;
this.teacherLoaded = false;
this.$refs.zeugnis.$refs.table.reloadTable();
this.$refs.teacher.$refs.table.reloadTable();
},
saveStdsem(event) {
window.localStorage.setItem(LOCAL_STORAGE_ID, event.target.value);
},
onZeugnisLoaded() {
this.zeugnisLoaded = true;
this.checkHighlight();
},
onTeacherLoaded() {
this.teacherLoaded = true;
this.checkHighlight();
},
checkHighlight()
{
if (!this.zeugnisLoaded || !this.teacherLoaded)
return;
if (!this.$refs.zeugnis || !this.$refs.teacher)
return;
let zeugnisTable = this.$refs.zeugnis.$refs.table.tabulator;
let teacherTable = this.$refs.teacher.$refs.table.tabulator;
if (!zeugnisTable || !teacherTable)
return;
highlightGesamtnote(zeugnisTable, teacherTable);
}
},
created() {
const savedPath = window.localStorage.getItem(LOCAL_STORAGE_ID);
this.stdsem = savedPath || '';
},
template: `
<div class="stv-details-noten d-flex flex-column overflow-hidden">
<div class="mb-3">
<select class="form-select" v-model="stdsem" @input="saveStdsem" v-if="config?.semesterSelect ?? true">
<option value="">{{ $p.t('ui/current_semester') }}</option>
<option value="true">{{ $p.t('ui/all_semester') }}</option>
</select>
</div>
<div class="row">
<div class="col-8">
<noten-zeugnis
ref="zeugnis"
:id="modelValue.lehrveranstaltung_id"
:all-semester="!!stdsem"
:endpoint="endpoint"
:optionalTabulatorOptions="tabulatorOptions"
@loaded="onZeugnisLoaded"/>
</div>
<div class="col-4">
<noten-teacher
ref="teacher"
:id="modelValue.lehrveranstaltung_id"
:all-semester="!!stdsem"
:endpoint="endpoint"
@copied="reload"
:optionalTabulatorOptions="tabulatorOptions"
@loaded="onTeacherLoaded"/>
</div>
</div>
</div>`
};
@@ -0,0 +1,21 @@
import TableLvList from "../../Stv/Studentenverwaltung/Details/Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js";
import ApiLETermine from "../../../api/lehrveranstaltung/letermine.js";
export default {
name: "LETabTermine",
components: {
TableLvList
},
props: {
modelValue: Object,
},
data() {
return {
endpoint: ApiLETermine
};
},
template: `
<div class="le-details-course-list h-100 d-flex flex-column">
<table-lv-list ref="tbl_course_list" :id="modelValue.lehreinheit_id" :endpoint="endpoint"></table-lv-list>
</div>`
};
@@ -1,4 +1,5 @@
import TableLvList from "./Lehrveranstaltungstermine/ListLehrveranstaltungstermine.js";
import ApiStvCoursedates from "../../../../api/factory/stv/coursedates.js";
export default {
name: "TabCourseList",
@@ -8,11 +9,13 @@ export default {
props: {
modelValue: Object,
},
data(){
return {}
data() {
return {
endpoint: ApiStvCoursedates
};
},
template: `
<div class="stv-details-course-list h-100 d-flex flex-column">
<table-lv-list ref="tbl_course_list" :student="modelValue"></table-lv-list>
<table-lv-list ref="tbl_course_list" :id="modelValue.uid" :endpoint="endpoint"></table-lv-list>
</div>`
};
@@ -2,8 +2,6 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js";
import FormInput from "../../../../Form/Input.js";
import FormForm from '../../../../Form/Form.js';
import ApiStvCoursedates from "../../../../../api/factory/stv/coursedates.js";
export default {
name: "TblCourseList",
components: {
@@ -17,7 +15,14 @@ export default {
},
},
props: {
student: Object
id: {
type: [Number, String],
required: true
},
endpoint: {
type: Object,
required: true
},
},
data(){
return {
@@ -48,14 +53,7 @@ export default {
initTabulatorOptions(){
this.tabulatorOptions = {
ajaxURL: 'dummy',
ajaxRequestFunc: () => this.$api.call(
ApiStvCoursedates.getCourselist({
student_uid: this.student.uid,
start_date: this.dataSem.start,
end_date: this.dataSem.ende,
group_consecutiveHours: true,
dbStundenplanTable: this.dbStundenplanTable})
),
ajaxRequestFunc: () => this.$api.call(this.endpoint.getCourselist(this.id, this.dataSem.start, this.dataSem.ende, this.dbStundenplanTable)),
ajaxResponse: (url, params, response) => {
return response.data;
},
@@ -131,7 +129,7 @@ export default {
this.dataSem = this.listStudiensemester.find(item => item.studiensemester_kurzbz === studiensemester_kurzbz);
},
exportToExcel(){
window.open(this.downloadLink, '_blank');
window.open(this.endpoint.exportCalendar(this.id, this.dbStundenplanTable), '_blank');
},
reload() {
this.$refs.table.reloadTable();
@@ -145,10 +143,13 @@ export default {
currentSemester(newVal, oldVal) {
this.getDatesOfSemester(newVal);
},
id() {
this.reload();
}
},
created(){
this.$api
.call(ApiStvCoursedates.getStudiensemester())
.call(this.endpoint.getStudiensemester())
.then(result => {
this.listStudiensemester = result.data;
this.getDatesOfSemester(this.currentSemester);
@@ -2,6 +2,9 @@ import NotenZeugnis from './Noten/Zeugnis.js';
import NotenTeacher from './Noten/Teacher.js';
import NotenRepeater from './Noten/Repeater.js';
import ApiStvGrades from '../../../../api/factory/stv/grades.js';
import { highlightGesamtnote } from "../../../../helpers/DocumentHelper.js";
const LOCAL_STORAGE_ID = 'stv_details_noten_2024-11-25_stdsem_all';
export default {
@@ -22,7 +25,10 @@ export default {
},
data() {
return {
stdsem: ''
stdsem: '',
endpoint: ApiStvGrades,
zeugnisLoaded: false,
teacherLoaded: false,
};
},
methods: {
@@ -33,6 +39,30 @@ export default {
},
saveStdsem(event) {
window.localStorage.setItem(LOCAL_STORAGE_ID, event.target.value);
},
onZeugnisLoaded() {
this.zeugnisLoaded = true;
this.checkHighlight();
},
onTeacherLoaded() {
this.teacherLoaded = true;
this.checkHighlight();
},
checkHighlight()
{
if (!this.zeugnisLoaded || !this.teacherLoaded)
return;
if (!this.$refs.zeugnis || !this.$refs.teacher)
return;
let zeugnisTable = this.$refs.zeugnis.$refs.table.tabulator;
let teacherTable = this.$refs.teacher.$refs.table.tabulator;
if (!zeugnisTable || !teacherTable)
return;
highlightGesamtnote(zeugnisTable, teacherTable);
}
},
created() {
@@ -49,10 +79,10 @@ export default {
</div>
<div class="row">
<div class="col-8">
<noten-zeugnis ref="zeugnis" :student="modelValue" :all-semester="!!stdsem"></noten-zeugnis>
<noten-zeugnis ref="zeugnis" :id="modelValue.prestudent_id" :all-semester="!!stdsem" :endpoint="endpoint" @loaded="onZeugnisLoaded"></noten-zeugnis>
</div>
<div class="col-4">
<noten-teacher ref="teacher" :student="modelValue" :all-semester="!!stdsem" @copied="reload"></noten-teacher>
<noten-teacher ref="teacher" :id="modelValue.prestudent_id" :endpoint="endpoint" :all-semester="!!stdsem" @copied="reload" @loaded="onTeacherLoaded"></noten-teacher>
<noten-repeater class="mt-4" ref="repeater" :student="modelValue" :all-semester="!!stdsem" @copied="reload"></noten-repeater>
</div>
</div>
@@ -1,13 +1,12 @@
import {CoreFilterCmpt} from "../../../../filter/Filter.js";
import ApiStvGrades from '../../../../../api/factory/stv/grades.js';
export default {
components: {
CoreFilterCmpt
},
emits: [
"copied"
"copied",
"loaded"
],
inject: {
currentSemester: {
@@ -16,20 +15,33 @@ export default {
}
},
props: {
student: Object,
allSemester: Boolean
endpoint: {
type: Object,
required: true
},
id: {
type: [Number, String],
required: true
},
allSemester: Boolean,
optionalTabulatorOptions: Object,
},
data() {
return {
tabulatorEvents: []
tabulatorEvents: [
{
event: "dataProcessed",
handler: () => this.$emit("loaded"),
},
]
};
},
computed: {
tabulatorOptions() {
return {
ajaxURL: 'dummy',
ajaxRequestFunc: () => this.$api.call(ApiStvGrades.getTeacherProposal(
this.student.prestudent_id,
ajaxRequestFunc: () => this.$api.call(this.endpoint.getTeacherProposal(
this.id,
(!this.allSemester ? this.currentSemester : null)
)),
ajaxResponse: (url, params, response) => {
@@ -77,16 +89,19 @@ export default {
{ field: 'lehrveranstaltung_id', title: this.$p.t('lehre/lehrveranstaltung_id'), visible: false },
{ field: 'punkte', title: this.$p.t('stv/grades_points'), visible: false }
],
columnDefaults: {
headerFilter: this.optionalTabulatorOptions?.headerFilter ?? false,
},
layout: 'fitDataStretch',
height: '100%',
selectableRows: true,
selectableRowsRangeMode: 'click',
persistenceID: 'stv-details-noten-teacher-20260217'
persistenceID: this.optionalTabulatorOptions?.persistenceTeacherID ?? 'stv-details-noten-teacher-2025120401',
};
}
},
watch: {
student(n) {
id() {
this.$refs.table.reloadTable();
},
allSemester(n) {
@@ -97,7 +112,7 @@ export default {
copyGrades(selected) {
const promises = selected.map(
grade => this.$api
.call(ApiStvGrades.copyTeacherProposalToCertificate(grade), {
.call(this.endpoint.copyTeacherProposalToCertificate(grade), {
errorHeader: grade.lehrveranstaltung_bezeichnung
})
.then(() => {
@@ -2,8 +2,6 @@ import {CoreFilterCmpt} from "../../../../filter/Filter.js";
import ZeugnisActions from './Zeugnis/Actions.js';
import ZeugnisDocuments from './Zeugnis/Documents.js';
import ApiStvGrades from '../../../../../api/factory/stv/grades.js';
export default {
name: 'Zeugnis',
components: {
@@ -11,6 +9,7 @@ export default {
ZeugnisActions,
ZeugnisDocuments
},
emits: ['loaded'],
inject: {
config: {
from: 'config',
@@ -22,7 +21,15 @@ export default {
}
},
props: {
student: Object,
endpoint: {
type: Object,
required: true
},
id: {
type: [Number, String],
required: true
},
optionalTabulatorOptions: Object,
allSemester: Boolean
},
data() {
@@ -35,6 +42,10 @@ export default {
return item;
})
},
{
event: "dataProcessed",
handler: () => this.$emit("loaded")
},
{
event: "rowSelected",
handler: row => row.getElement().style.zIndex = 12
@@ -53,7 +64,7 @@ export default {
computed: {
tabulatorOptions() {
const listPromise = this.$api
.call(ApiStvGrades.list())
.call(this.endpoint.list())
.then(res => res.data.map(({bezeichnung: label, note: value}) => ({label, value})));
let gradeField = {
@@ -86,7 +97,7 @@ export default {
note_bezeichnung
}))
// send to backend
.then(data => this.$api.call(ApiStvGrades.updateCertificate(data)))
.then(data => this.$api.call(this.endpoint.updateCertificate(data)))
// get bezeichnung again
.then(() => listPromise)
.then(list => list.find(el => el.value == note))
@@ -109,7 +120,7 @@ export default {
if (filterTerm) {
return this.$api
.call(
ApiStvGrades.getGradeFromPoints(
this.endpoint.getGradeFromPoints(
filterTerm,
cell.getData().lehrveranstaltung_id,
this.currentSemester
@@ -142,6 +153,8 @@ export default {
.then(() => node.innerText = this.$p.t('ui/loading'))
.catch(this.$fhcAlert.handleSystemError);
gradeField.editorParams.placeholderLoading = node;
gradeField.visible = this.optionalTabulatorOptions?.visibleColumns?.note ?? true
gradeField.headerFiler = this.optionalTabulatorOptions?.headerFilter?.note || this.optionalTabulatorOptions?.note || false
}
const columns = [
@@ -238,8 +251,8 @@ export default {
return {
ajaxURL: 'dummy',
ajaxRequestFunc: () => this.$api.call(ApiStvGrades.getCertificate(
this.student.prestudent_id,
ajaxRequestFunc: () => this.$api.call(this.endpoint.getCertificate(
this.id,
(!this.allSemester ? this.currentSemester : null)
)),
ajaxResponse: (url, params, response) => {
@@ -248,9 +261,10 @@ export default {
columns,
height: '100%',
layout: 'fitDataStretchFrozen',
selectableRows: 1,
selectable: true,
selectableRowsRangeMode: 'click',
persistenceID: 'stv-details-noten-zeugnis-20260217',
selectableRows: true,
persistenceID: this.optionalTabulatorOptions?.persistenceZeugnisID ?? 'stv-details-noten-zeugnis-20260217',
persistence:{
columns: ["width", "visible", "frozen"]
}
@@ -258,7 +272,8 @@ export default {
}
},
watch: {
student(n) {
id()
{
this.$refs.table.reloadTable();
},
allSemester(n) {
@@ -269,7 +284,7 @@ export default {
setGrade(data) {
this.$api
.call(
ApiStvGrades.updateCertificate(data),
this.endpoint.updateCertificate(data),
{ errorHeader: data.lehrveranstaltung_bezeichnung }
)
.then(this.$refs.table.reloadTable)
@@ -282,7 +297,7 @@ export default {
.confirmDelete()
.then(result => result ? data : Promise.reject({handled:true}))
.then(data => this.$api.call(
ApiStvGrades.deleteCertificate(data),
this.endpoint.deleteCertificate(data),
{ errorHeader: data.lehrveranstaltung_bezeichnung }
))
.then(this.$refs.table.reloadTable)
@@ -291,7 +306,7 @@ export default {
}
},
created() {
this.$p.loadCategory(['global', 'stv', 'lehre'])
this.$p.loadCategory(['global', 'stv', 'lehre', 'person'])
.then(() => {
if (this.$refs.table.tableBuilt)
this.$refs.table.tabulator.columnManager.setColumns(this.tabulatorOptions.columns);
@@ -1,5 +1,6 @@
import drop from '../../../directives/drop.js';
import dragClick from '../../../directives/dragClick.js';
import draggable from '../../../directives/draggable.js';
import ApiStvGroups from '../../../api/factory/stv/group.js';
import ApiStvDetails from '../../../api/factory/stv/details.js';
@@ -11,7 +12,8 @@ export default {
},
directives: {
drop,
dragClick
dragClick,
draggable
},
inject: {
$reloadList: {
@@ -40,6 +42,10 @@ export default {
preselectedKey: {
type: String,
default: null
},
dragEnabled: {
type: Boolean,
default: false
}
},
data() {
@@ -79,6 +85,22 @@ export default {
}
},
methods: {
dragVerband(node) {
const gruppe = node?.data || {};
const id = gruppe.gruppe_kurzbz ?? gruppe.link ?? node?.key ?? null;
return [{
type: 'verband',
id: id,
gruppe_kurzbz: gruppe.gruppe_kurzbz ?? null,
semester: gruppe.semester ?? null,
verband: gruppe.verband ?? null,
gruppe: gruppe.gruppe ?? null,
lehrverband: gruppe.gruppe_kurzbz == null,
stg_kz: gruppe.stg_kz ?? null,
}];
},
findNodeByKey(key, arr) {
if (!arr)
arr = this.nodes;
@@ -359,7 +381,9 @@ export default {
:data-tree-item-key="node.key"
:title="node.data.studiengang_kz"
v-drag-click="() => toggleTreeNode(node)"
class="node-verband"
v-drop:link-strict.student-collection="(evt, students) => dropStudents(node, students)"
v-draggable:link-strict="dragEnabled && dragVerband(node)"
>
{{ node.data.name }}
</span>
+44
View File
@@ -0,0 +1,44 @@
export function highlightGesamtnote(zeugnisTable, teacherTable)
{
let zeugnisData = zeugnisTable.getData();
let studentsWithNote = new Set();
zeugnisData.forEach(row => {
let student = row.uid;
let lv = row.lehrveranstaltung_id;
let note = row.note;
if (!student || !lv)
return;
if (note == null || note === "")
return;
let key = `${student}_${lv}`;
studentsWithNote.add(key);
});
teacherTable.deselectRow();
teacherTable.getRows().forEach(row => {
let data = row.getData();
let student = data.student_uid;
let lv = data.lehrveranstaltung_id;
let note = data.note;
if (!student || !lv)
return;
if (note == null || note === "")
return;
let key = `${student}_${lv}`;
if (!studentsWithNote.has(key))
{
row.select();
}
});
}
+4
View File
@@ -30,6 +30,10 @@ const TYPE_DEFINITION = {
prestudent: {
id: "prestudent_id",
dragIcon: "fa-solid fa-user-graduate text-muted"
},
verband: {
id: "gruppe_id",
dragIcon: "fa-solid fa-user-group text-muted"
}
// TODO: IMPLEMENT OTHER TYPES
};
+120
View File
@@ -50791,6 +50791,126 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'berichte',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Berichte',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Reports',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'lvplanung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'LV-Planung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Course Planning',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'lehrauftragsliste',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lehrauftragsliste',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Teaching Assignments',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'lehrauftraege',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lehraufträge',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Lectureships',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'lehrauftragslisteemp',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lehrauftrag Lehrende',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Teaching Assignment Lecturers',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'lehre',
'phrase' => 'extrakvverwaltung',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Lehrveranstaltung Verwaltung',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Course Management',
'description' => '',
'insertvon' => 'system'
)
)
),
// feature-55614 end
array(
'app' => 'softwarebereitstellung',