diff --git a/application/controllers/api/frontend/v1/funktionen/Funktionen.php b/application/controllers/api/frontend/v1/funktionen/Funktionen.php new file mode 100644 index 000000000..b2787072b --- /dev/null +++ b/application/controllers/api/frontend/v1/funktionen/Funktionen.php @@ -0,0 +1,328 @@ + ['admin:r', 'assistenz:r'], + 'getAllUserFunctions' => ['admin:r', 'assistenz:r'], + 'getOrgHeads' => ['admin:r', 'assistenz:r'], + 'getOrgetsForCompany' => ['admin:r', 'assistenz:r'], + 'getAllOrgUnits' => ['admin:r', 'assistenz:r'], + 'loadFunction' => ['admin:r', 'assistenz:r'], + 'insertFunction' => ['admin:rw', 'assistenz:rw'], + 'updateFunction' => ['admin:rw', 'assistenz:rw'], + 'deleteFunction' => ['admin:rw', 'assistenz:rw'], + ) + ); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + ]); + + // Load models + $this->load->model('extensions/FHC-Core-Personalverwaltung/Api_model', 'ApiModel'); + $this->load->model('ressource/Funktion_model', 'FunktionModel'); + $this->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel'); + + $this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel'); + } + + public function getAllFunctions() + { + $this->FunktionModel->addSelect("funktion_kurzbz"); + $this->FunktionModel->addSelect("beschreibung"); + $this->FunktionModel->addSelect("aktiv"); + $this->FunktionModel->addSelect("beschreibung AS label"); + $this->FunktionModel->addOrder("beschreibung"); + $result = $this->FunktionModel->load(); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getOrgHeads() + { + $result = $this->OrganisationseinheitModel->getHeads(); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getAllUserFunctions($uid) + { + if(!$uid) + { + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'UID']), self::ERROR_TYPE_GENERAL); + } + + $sql = " + SELECT + dv.dienstverhaeltnis_id, + un.bezeichnung || ' (' || TO_CHAR(dv.von, 'DD.MM.YYYY') || CASE WHEN dv.bis IS NOT NULL THEN ' - ' + || TO_CHAR(dv.bis, 'DD.MM.YYYY') ELSE '' END || ')' AS dienstverhaeltnis_unternehmen , + '[' || oet.bezeichnung || '] ' || oe.bezeichnung AS funktion_oebezeichnung, + f.beschreibung AS funktion_beschreibung, + bf.*, + fb.bezeichnung AS fachbereich_bezeichnung, + CASE + WHEN + bf.datum_bis IS NOT NULL AND bf.datum_bis::date < now()::date + THEN + false + ELSE + true + END aktiv + FROM + public.tbl_benutzerfunktion bf + JOIN + public.tbl_organisationseinheit oe ON oe.oe_kurzbz = bf.oe_kurzbz + JOIN + public.tbl_organisationseinheittyp oet ON oe.organisationseinheittyp_kurzbz = oet.organisationseinheittyp_kurzbz + JOIN + public.tbl_funktion f ON f.funktion_kurzbz = bf.funktion_kurzbz + LEFT JOIN + hr.tbl_vertragsbestandteil_funktion vf ON vf.benutzerfunktion_id = bf.benutzerfunktion_id + LEFT JOIN + hr.tbl_vertragsbestandteil v ON vf.vertragsbestandteil_id = v.vertragsbestandteil_id + LEFT JOIN + hr.tbl_dienstverhaeltnis dv ON v.dienstverhaeltnis_id = dv.dienstverhaeltnis_id + LEFT JOIN + public.tbl_organisationseinheit un ON dv.oe_kurzbz = un.oe_kurzbz + LEFT JOIN + public.tbl_fachbereich fb ON fb.fachbereich_kurzbz = bf.fachbereich_kurzbz + WHERE + bf.uid = ? + ORDER BY + bf.datum_von, bf.datum_von ASC"; + + $benutzerfunktionen = $this->BenutzerfunktionModel->execReadOnlyQuery($sql, array($uid)); + $data = $this->getDataOrTerminateWithError($benutzerfunktionen); + + $this->terminateWithSuccess($data); + } + + /* + * returns list of all organisation units + * as key value list to be used in select or autocomplete + */ + public function getAllOrgUnits() + { + $sql = " + SELECT + oe.oe_kurzbz, oe.aktiv, + '[' || COALESCE(oet.bezeichnung, oet.organisationseinheittyp_kurzbz) || + '] ' || COALESCE(oe.bezeichnung, oe.oe_kurzbz) AS label + FROM public.tbl_organisationseinheit oe + JOIN public.tbl_organisationseinheittyp oet ON oe.organisationseinheittyp_kurzbz = oet.organisationseinheittyp_kurzbz + ORDER BY oet.bezeichnung ASC, oe.bezeichnung ASC"; + + $result = $this->OrganisationseinheitModel->execReadOnlyQuery($sql); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + /* + * return list of child orgets for a given company orget_kurzbz + * as key value list to be used in select or autocomplete + */ + public function getOrgetsForCompany($companyOrgetkurzbz = null) + { + $sql = " + SELECT + oe.oe_kurzbz, oe.aktiv, + '[' || COALESCE(oet.bezeichnung, oet.organisationseinheittyp_kurzbz) || + '] ' || COALESCE(oe.bezeichnung, oe.oe_kurzbz) AS label + FROM ( + WITH RECURSIVE oes(oe_kurzbz, oe_parent_kurzbz) as + ( + SELECT oe_kurzbz, oe_parent_kurzbz FROM public.tbl_organisationseinheit + WHERE oe_kurzbz=? + UNION ALL + SELECT o.oe_kurzbz, o.oe_parent_kurzbz FROM public.tbl_organisationseinheit o, oes + WHERE o.oe_parent_kurzbz=oes.oe_kurzbz + ) + SELECT oe_kurzbz + FROM oes + GROUP BY oe_kurzbz + ) c + JOIN public.tbl_organisationseinheit oe ON oe.oe_kurzbz = c.oe_kurzbz + JOIN public.tbl_organisationseinheittyp oet ON oe.organisationseinheittyp_kurzbz = oet.organisationseinheittyp_kurzbz + ORDER BY oet.bezeichnung ASC, oe.bezeichnung ASC"; + + $childorgets = $this->OrganisationseinheitModel->execReadOnlyQuery($sql, array($companyOrgetkurzbz)); + $data = $this->getDataOrTerminateWithError($childorgets); + + $this->terminateWithSuccess($data); + } + + public function loadFunction($benutzerfunktion_id) + { + $this->BenutzerfunktionModel->addSelect("*"); + $result = $this->BenutzerfunktionModel->loadWhere( + array('benutzerfunktion_id' => $benutzerfunktion_id) + ); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(current($data)); + } + + public function insertFunction() + { + $this->load->library('form_validation'); + $authUID = getAuthUID(); + + $uid = $this->input->post('uid'); + + if(!$uid) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'UID']), self::ERROR_TYPE_GENERAL); + } + + $formData = $this->input->post('formData'); + + $datum_von = $formData['datum_von'] ?? null; + $datum_bis = $formData['datum_bis'] ?? null; + $formData['oe_kurzbz'] = is_array($formData['oe_kurzbz']) ? $formData['oe_kurzbz']['oe_kurzbz'] : $formData['oe_kurzbz']; + $formData['funktion_kurzbz'] = is_array($formData['funktion_kurzbz']) + ? $formData['funktion_kurzbz']['funktion_kurzbz'] + : $formData['funktion_kurzbz']; + $bezeichnung = $formData['bezeichnung'] ?? null; + $wochenstunden = $formData['wochenstunden'] ?? null; + + $this->form_validation->set_data($formData); + $this->form_validation->set_rules('datum_von', 'VonDatum', 'required|is_valid_date', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'VonDatum']), + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VonDatum']) + ]); + $this->form_validation->set_rules('datum_bis', 'BisDatum', 'is_valid_date', [ + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'BisDatum']) + ]); + $this->form_validation->set_rules('oe_kurzbz', 'Organisationseinheit', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Organisationseinheit']) + ]); + $this->form_validation->set_rules('funktion_kurzbz', 'Funktion', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Funktion']) + ]); + $this->form_validation->set_rules('wochenstunden', 'Wochenstunden', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Wochenstunden']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $result = $this->BenutzerfunktionModel->insert([ + 'uid' => $uid, + 'datum_von' => $datum_von, + 'datum_bis' => $datum_bis , + 'oe_kurzbz' => $formData['oe_kurzbz'], + 'funktion_kurzbz' => $formData['funktion_kurzbz'], + 'bezeichnung' => $bezeichnung, + 'wochenstunden' => $wochenstunden, + 'insertamum' => date('c'), + 'insertvon' => $authUID, + ]); + + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function updateFunction() + { + $this->load->library('form_validation'); + $authUID = getAuthUID(); + + $uid = $this->input->post('uid'); + + if(!$uid) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'UID']), self::ERROR_TYPE_GENERAL); + } + $benutzerfunktion_id = $this->input->post('benutzerfunktion_id'); + + if(!$benutzerfunktion_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Benutzerfunktion ID']), self::ERROR_TYPE_GENERAL); + } + + $formData = $this->input->post('formData'); + + $datum_von = $formData['datum_von'] ?? null; + $datum_bis = $formData['datum_bis'] ?? null; + $formData['oe_kurzbz'] = is_array($formData['oe_kurzbz']) ? $formData['oe_kurzbz']['oe_kurzbz'] : $formData['oe_kurzbz']; + $formData['funktion_kurzbz'] = is_array($formData['funktion_kurzbz']) + ? $formData['funktion_kurzbz']['funktion_kurzbz'] + : $formData['funktion_kurzbz']; + $bezeichnung = $formData['bezeichnung'] ?? null; + $wochenstunden = $formData['wochenstunden'] ?? null; + + $this->form_validation->set_data($formData); + $this->form_validation->set_rules('datum_von', 'VonDatum', 'required|is_valid_date', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'VonDatum']), + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'VonDatum']) + ]); + $this->form_validation->set_rules('datum_bis', 'BisDatum', 'is_valid_date', [ + 'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'BisDatum']) + ]); + $this->form_validation->set_rules('oe_kurzbz', 'Organisationseinheit', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Organisationseinheit']) + ]); + $this->form_validation->set_rules('funktion_kurzbz', 'Funktion', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Funktion']) + ]); + $this->form_validation->set_rules('wochenstunden', 'Wochenstunden', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Wochenstunden']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $result = $this->BenutzerfunktionModel->update( + [ + 'benutzerfunktion_id' => $benutzerfunktion_id, + ], + [ + 'uid' => $uid, + 'datum_von' => $datum_von, + 'datum_bis' => $datum_bis , + 'oe_kurzbz' => $formData['oe_kurzbz'], + 'funktion_kurzbz' => $formData['funktion_kurzbz'], + 'bezeichnung' => $bezeichnung, + 'wochenstunden' => $wochenstunden, + 'updateamum' => date('c'), + 'updatevon' => $authUID, + ] + ); + + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } + + public function deleteFunction($benutzerfunktion_id) + { + $result = $this->BenutzerfunktionModel->delete( + array('benutzerfunktion_id' => $benutzerfunktion_id) + ); + + $data = $this->getDataOrTerminateWithError($result); + $this->terminateWithSuccess($data); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Config.php b/application/controllers/api/frontend/v1/stv/Config.php index 813edad10..a9c49fa3f 100644 --- a/application/controllers/api/frontend/v1/stv/Config.php +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -170,6 +170,11 @@ class Config extends FHCAPI_Controller 'component' => './Stv/Studentenverwaltung/Details/Aufnahmetermine.js' ]; + $result['functions'] = [ + 'title' => $this->p->t('stv', 'tab_functions'), + 'component' => './Stv/Studentenverwaltung/Details/Funktionen.js' + ]; + Events::trigger('stv_conf_student', function & () use (&$result) { return $result; }); diff --git a/application/models/organisation/Organisationseinheit_model.php b/application/models/organisation/Organisationseinheit_model.php index 1b1a826aa..ba91964f6 100644 --- a/application/models/organisation/Organisationseinheit_model.php +++ b/application/models/organisation/Organisationseinheit_model.php @@ -191,7 +191,7 @@ class Organisationseinheit_model extends DB_Model /** * @param string $oe_kurzbz - * + * * @return stdClass */ public function getWithType($oe_kurzbz) @@ -203,18 +203,14 @@ class Organisationseinheit_model extends DB_Model } /** - * Get OEs by eventQuery string. Use with autocomplete event queries. - * @param $eventQuery String - * @return array + * get highest organisation units */ - public function getAutocompleteSuggestions($eventQuery) + public function getHeads() { - $this->addSelect('oe_kurzbz'); - $this->addSelect('organisationseinheittyp_kurzbz, oe_kurzbz, bezeichnung, aktiv, lehre'); - $this->addOrder('organisationseinheittyp_kurzbz, bezeichnung'); + $this->addSelect('*'); + $this->addSelect('oe_kurzbz as head'); + $result = $this->loadWhere(array('oe_parent_kurzbz' => null, 'aktiv' => true)); - return $this->loadWhere(" - oe_kurzbz ILIKE '%". $this->escapeLike($eventQuery). "%' - "); + return $result; } } diff --git a/application/views/Studentenverwaltung.php b/application/views/Studentenverwaltung.php index 8e4c523d6..01e611657 100644 --- a/application/views/Studentenverwaltung.php +++ b/application/views/Studentenverwaltung.php @@ -15,11 +15,14 @@ 'notiz', ), 'customCSSs' => [ + #datepicker fuer component functions 'public/css/components/vue-datepicker.css', 'public/css/components/primevue.css', - 'public/css/Studentenverwaltung.css' + 'public/css/Studentenverwaltung.css', + 'public/css/components/function.css' ], 'customJSs' => [ + 'vendor/vuejs/vuedatepicker_js/vue-datepicker.iife.js' #'vendor/npm-asset/primevue/tree/tree.min.js', #'vendor/npm-asset/primevue/toast/toast.min.js' ], diff --git a/public/css/components/function.css b/public/css/components/function.css new file mode 100644 index 000000000..3e5e4a632 --- /dev/null +++ b/public/css/components/function.css @@ -0,0 +1,3 @@ +.item-inactive { + text-decoration: line-through; +} \ No newline at end of file diff --git a/public/js/api/factory/functions.js b/public/js/api/factory/functions.js new file mode 100644 index 000000000..ef0be43cb --- /dev/null +++ b/public/js/api/factory/functions.js @@ -0,0 +1,89 @@ +/** + * Copyright (C) 2025 fhcomplete.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +export default { + getOrgHeads() { + var url = 'api/frontend/v1/funktionen/Funktionen/getOrgHeads'; + return { + method: 'get', + url, + }; + }, + getOrgetsForCompany(unternehmen) { + var url = 'api/frontend/v1/funktionen/Funktionen/getOrgetsForCompany' + + '/' + unternehmen; + return { + method: 'get', + url, + }; + }, + getAllOrgUnits(filterStudent) { + var url = 'api/frontend/v1/funktionen/Funktionen/getAllOrgUnits'; + return { + method: 'get', + url, + }; + }, + getAllUserFunctions(mitarbeiter_uid) { + var url = 'api/frontend/v1/funktionen/Funktionen/getAllUserFunctions' + + '/' + mitarbeiter_uid; + return { + method: 'get', + url, + }; + }, + getAllFunctions() { + var url = 'api/frontend/v1/funktionen/Funktionen/getAllFunctions'; + return { + method: 'get', + url, + }; + }, + addFunction(params) { + return { + method: 'post', + url: 'api/frontend/v1/funktionen/Funktionen/insertFunction/', + params + }; + }, + loadFunction(benutzerfunktion_id) { + var url = 'api/frontend/v1/funktionen/Funktionen/loadFunction' + + '/' + benutzerfunktion_id; + return { + method: 'get', + url, + }; + }, + updateFunction(params) { + return { + method: 'post', + url: 'api/frontend/v1/funktionen/Funktionen/updateFunction/', + params + }; + }, + deleteFunction(benutzerfunktion_id) { + return { + method: 'post', + url: 'api/frontend/v1/funktionen/Funktionen/deleteFunction/' + benutzerfunktion_id + }; + }, + getOes(head, searchString) { + return { + method: 'get', + url: 'api/frontend/v1/funktionen/Funktionen/searchOes/' + head + '/' + searchString + }; + }, +}; \ No newline at end of file diff --git a/public/js/components/Funktionen/Funktionen.js b/public/js/components/Funktionen/Funktionen.js new file mode 100644 index 000000000..4fdf5b6e4 --- /dev/null +++ b/public/js/components/Funktionen/Funktionen.js @@ -0,0 +1,588 @@ +import {CoreFilterCmpt} from "../filter/Filter.js"; +import FormInput from "../Form/Input.js"; +import FormForm from "../Form/Form.js"; +import BsModal from "../Bootstrap/Modal.js"; +import PvAutoComplete from "../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; + +import ApiCoreFunktion from '../../api/factory/functions.js'; + +export default { + name: 'FunctionComponent', + components: { + CoreFilterCmpt, + FormInput, + FormForm, + BsModal, + PvAutoComplete + }, + props: { + modelValue: { + type: Object, + default: () => ({}), + required: false + }, + config: {type: Object, default: () => ({}), required: false}, + readonlyMode: {type: Boolean, required: false, default: false}, + personID: {type: Number, required: true}, + personUID: {type: String, required: true}, + writePermission: {type: Boolean, required: false}, + showDvCompany: {type: Boolean, required: false, default: true}, + saveFunctionAsCopy: {type: Boolean, required: false, default: false}, + stylePv21: {type: Boolean, required: false, default: false}, + companyLinkFormatter: {type: Function || null, default: null} + }, + data(){ + return { + tabulatorOptions: { + ajaxURL: 'dummy', + ajaxRequestFunc: () => this.$api.call( + ApiCoreFunktion.getAllUserFunctions(this.personUID) + ), + ajaxResponse: (url, params, response) => response.data, + columns: [ + { + title: "dienstverhaeltnis_unternehmen", + field: "dienstverhaeltnis_unternehmen", + headerFilter: "list", + headerFilterParams: {valuesLookup: true, autocomplete: true, sort: "asc"}, + }, + { + title: "funktion_beschreibung", field: "funktion_beschreibung", headerFilter: "list", + headerFilterParams: {valuesLookup: true, autocomplete: true, sort: "asc"}, + }, + { + title: "funktion_oebezeichnung", field: "funktion_oebezeichnung", headerFilter: "list", + headerFilterParams: {valuesLookup: true, autocomplete: true, sort: "asc"} + }, + {title: "wochenstunden", field: "wochenstunden", headerFilter: true}, + { + title: "Von", + field: "datum_von", + headerFilter: true, + formatter: function (cell) { + const dateStr = cell.getValue(); + if (!dateStr) return ""; + + const date = new Date(dateStr); + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + }); + }, + }, + { + title: "Bis", + field: "datum_bis", + headerFilter: true, + formatter: function (cell) { + const dateStr = cell.getValue(); + if (!dateStr) return ""; + + const date = new Date(dateStr); + return date.toLocaleString("de-DE", { + day: "2-digit", + month: "2-digit", + year: "numeric", + }); + }, + }, + {title: "bezeichnung", field: "bezeichnung", headerFilter: true}, + {title: "aktiv", field: "aktiv", visible: false}, + {title: "benutzerfunktion_id", field: "benutzerfunktion_id", visible: false}, + {title: "uid", field: "uid", visible: false}, + { + //title: 'Aktionen', field: 'actions', + minWidth: 150, // Ensures Action-buttons will be always fully displayed + formatter: (cell, formatterParams, onRendered) => { + let container = document.createElement('div'); + container.className = "d-flex gap-2"; + + if( cell.getRow().getData().dienstverhaeltnis_unternehmen === null ) { + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + if(this.stylePv21) + button.innerHTML = ''; + else + button.innerHTML = ''; + button.title = this.$p.t('ui', 'bearbeiten'); + button.addEventListener('click', (event) => + this.actionEditFunction(cell.getData().benutzerfunktion_id) + ); + if(this.readonlyMode === true) button.disabled = true; + container.append(button); + } + if( cell.getRow().getData().dienstverhaeltnis_unternehmen === null ) { + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'loeschen'); + button.addEventListener('click', () => + this.actionDeleteFunction(cell.getData().benutzerfunktion_id) + ); + if(this.readonlyMode === true) button.disabled = true; + container.append(button); + } + + if (cell.getRow().getData().dienstverhaeltnis_unternehmen === null && this.saveFunctionAsCopy) { + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'saveAsCopy'); + button.addEventListener('click', () => + this.actionCopyFunction(cell.getData().benutzerfunktion_id) + ); + if(this.readonlyMode === true) button.disabled = true; + container.append(button); + } + + return container; + }, + frozen: true + } + ], + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + height: '300', + persistenceID: 'core-functions', + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async () => { + await this.$p.loadCategory(['global', 'lehre', 'person', 'ui']); + let cm = this.$refs.table.tabulator.columnManager; + + //Field Company: if visible show link to dv + const column = cm.getColumnByField('dienstverhaeltnis_unternehmen'); + const companyDv = { + title: this.$p.t('person', 'dv_unternehmen'), + width: 140, + visible: this.showDvCompany, + formatter: this.companyLinkFormatter + }; + column.component.updateDefinition(companyDv); + + cm.getColumnByField('funktion_beschreibung').component.updateDefinition({ + title: this.$p.t('person', 'zuordnung_taetigkeit'), + width: 140 + }); + cm.getColumnByField('funktion_oebezeichnung').component.updateDefinition({ + title: this.$p.t('lehre', 'organisationseinheit'), + width: 140 + }); + cm.getColumnByField('wochenstunden').component.updateDefinition({ + title: this.$p.t('person', 'wochenstunden') + }); + + const columnDatumVon = cm.getColumnByField('datum_von'); + const fieldVonDatum = { + title: this.$p.t('ui', 'from') + }; + + columnDatumVon.component.updateDefinition(fieldVonDatum); + + const columnDatumBis = cm.getColumnByField('datum_bis'); + const fieldBisDatum = { + title: this.$p.t('global', 'bis'), + }; + columnDatumBis.component.updateDefinition(fieldBisDatum); + + cm.getColumnByField('bezeichnung').component.updateDefinition({ + title: this.$p.t('ui', 'bezeichnung'), + width: 140 + }); + + } + } + ], + isFilterSet: true, + listOrgHeads: [], + listOrgUnits: [], //Old + listAllOrgUnits: [], + listOrgUnits_GST: [], + listOrgUnits_GMBH: [], + formData: { + head: 'gst', + oe_kurzbz: '', + funktion_kurzbz: null, + label:'', + //funktion_label: '', + funktion: null, + }, + statusNew: true, + listAllFunctions: [], + abortController: { + oes: null, + functions: null + }, + filteredOes: [], + filteredFunctions: [], + newBtnStyle: '', + selectedFunction: null, + selectedOe: null + } + }, + watch: { + selectedFunction(newVal) { + this.formData.funktion_kurzbz = newVal?.funktion_kurzbz || ''; + }, + selectedOe(newVal) { + this.formData.oe_kurzbz = newVal?.oe_kurzbz || ''; + } + }, + methods: { + onSwitchChange() { + if (this.isFilterSet) { + this.$refs.table.tabulator.setFilter("aktiv", "=", true); + } + else { + this.$refs.table.tabulator.clearFilter(); + this.isFilterSet = false; + } + }, + actionNewFunction(){ + this.resetModal(); + this.statusNew = true; + this.formData.datum_von = new Date(); + this.$refs.functionModal.show(); + }, + actionCopyFunction(benutzerfunktion_id) { + this.statusNew = true; + this.loadFunction(benutzerfunktion_id).then(() => { + this.$refs.functionModal.show(); + }); + }, + actionDeleteFunction(benutzerfunktion_id) { + this.$fhcAlert + .confirmDelete() + .then(result => result + ? benutzerfunktion_id + : Promise.reject({handled: true})) + .then(this.deleteFunction) + .catch(this.$fhcAlert.handleSystemError); + }, + actionEditFunction(benutzerfunktion_id) { + this.resetModal(); + this.statusNew = false; + this.loadFunction(benutzerfunktion_id).then(() => { + //set selectedFunction and selectedOd to enable viewing label in primevue autocomplete fields + this.selectedFunction = this.listAllFunctions.find( + item => item.funktion_kurzbz === this.formData.funktion_kurzbz + ); + this.selectedOe = this.listAllOrgUnits.find( + item => item.oe_kurzbz === this.formData.oe_kurzbz + ); + }); + this.$refs.functionModal.show(); + }, + addFunction() { + const dataToSend = { + uid: this.personUID, + formData: this.formData + }; + return this.$refs.functionData + .call(ApiCoreFunktion.addFunction(dataToSend)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal('functionModal'); + this.resetModal(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + loadFunction(benutzerfunktion_id) { + return this.$api + .call(ApiCoreFunktion.loadFunction(benutzerfunktion_id)) + .then(result => { + this.formData = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + updateFunction(benutzerfunktion_id){ + const dataToSend = { + uid: this.personUID, + formData: this.formData, + benutzerfunktion_id: benutzerfunktion_id + }; + return this.$refs.functionData + .call(ApiCoreFunktion.updateFunction(dataToSend)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal('functionModal'); + this.resetModal(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + deleteFunction(benutzerfunktion_id) { + return this.$api + .call(ApiCoreFunktion.deleteFunction(benutzerfunktion_id)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + this.reload(); + }); + }, + hideModal(modalRef) { + this.$refs[modalRef].hide(); + }, + reload() { + this.$refs.table.reloadTable(); + }, + resetModal(){ + this.formData = {}; + this.formData.head = 'gst'; + this.formData.oe_kurzbz = ''; + this.formData.funktion_kurzbz = ''; + }, + filterFunctions(event) { + const query = event.query.toLowerCase(); + this.filteredFunctions = this.listAllFunctions.filter(item => + item.label.toLowerCase().includes(query) + ) + }, + filterOes(event) { + const query = event.query.toLowerCase(); + + if(!this.formData.head) + this.$fhcAlert.alertError(this.$p.t('ui', 'bitteUnternehmenWaehlen')); + + if(this.formData.head == 'gst') { + this.filteredOes = this.listOrgUnits_GST.filter(item => + item.label.toLowerCase().includes(query) + ); + } + if(this.formData.head == 'gmbh') { + this.filteredOes = this.listOrgUnits_GMBH.filter(item => + item.label.toLowerCase().includes(query) + ); + } + }, + + styleNewButton(){ + if(this.stylePv21) { + this.newBtnStyle = "btn-sm"; + } + }, + //helper function: workaround to trigger validation if input is not a number + normalizeStunden() { + if (this.formData.wochenstunden === null || this.formData.wochenstunden === '') { + this.formData.wochenstunden = 'xxx' + } + } + }, + created() { + this.$api + .call(ApiCoreFunktion.getOrgHeads()) + .then(result => { + this.listOrgHeads = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api + .call(ApiCoreFunktion.getAllFunctions()) + .then(result => { + this.listAllFunctions = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$api + .call(ApiCoreFunktion.getAllOrgUnits()) + .then(result => { + this.listAllOrgUnits = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$api + .call(ApiCoreFunktion.getOrgetsForCompany('gst')) + .then(result => { + this.listOrgUnits_GST = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$api + .call(ApiCoreFunktion.getOrgetsForCompany('gmbh')) + .then(result => { + this.listOrgUnits_GMBH = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.styleNewButton(); + + }, + template: ` +
+ +
+ + +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + +
+ + +
+ +
+ ` +} diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Funktionen.js b/public/js/components/Stv/Studentenverwaltung/Details/Funktionen.js new file mode 100644 index 000000000..f968ebecc --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Funktionen.js @@ -0,0 +1,24 @@ +import PersonFunctions from "../../../Funktionen/Funktionen.js"; + +export default { + components: { + PersonFunctions, + }, + props: { + modelValue: Object, + }, + template: ` +
+ + + + +
`, +}; diff --git a/public/js/components/Stv/Studentenverwaltung/Details/FunktionenOld.js b/public/js/components/Stv/Studentenverwaltung/Details/FunktionenOld.js new file mode 100644 index 000000000..5188c8d1b --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/FunktionenOld.js @@ -0,0 +1,28 @@ +import PersonFunctions from "../../../Funktionen/Funktionen_composition_api"; + +//import PersonFunctions from "../../../Funktionen/Funktionen.js"; + +export default { + components: { + PersonFunctions, + }, + props: { + modelValue: Object, + }, + template: ` +
+ + + + + + +
`, +}; diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 1251efff5..4901047b9 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -44252,6 +44252,148 @@ and represent the current state of research on the topic. The prescribed citatio ) ), // FHC4 STUDIERENDENVERWALTUNG ANZAHL ENDE --------------------------------------------------------------- + // FHC-4 Studierendenverwaltung FUNCTIONS START + array( + 'app' => 'core', + 'category' => 'stv', + 'phrase' => 'tab_functions', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Funktionen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Functions', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'funktion', + 'phrase' => 'filter_active', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nur aktive anzeigen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Display only active', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'funktion', + 'phrase' => 'addFunktion', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Funktion hinzufügen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Add function', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'funktion', + 'phrase' => 'editFunktion', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Funktion bearbeiten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Edit function', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'saveAsCopy', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Als Kopie speichern', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Save as copy', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'error_fieldMustBePositiveInteger', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Das Eingabefeld {field} darf nur positive Ganzzahlen enthalten.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'The input field {field} may only contain positive integers', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'ui', + 'phrase' => 'bitteUnternehmenWaehlen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Vor Änderung der Organisationseinheit bitte Unternehmen wählen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Before changing the organizational unit, please select company', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + // FHC-4 Studierendenverwaltung FUNCTIONS END );