diff --git a/application/config/anrechnung.php b/application/config/anrechnung.php index 768ec3197..2466d2bb1 100755 --- a/application/config/anrechnung.php +++ b/application/config/anrechnung.php @@ -21,3 +21,6 @@ $config['grades_blocking_application'] = array( $config['fbl'] = FALSE; //Enables Info Mails $config['send_mail'] = TRUE; + +// Display fields to explain equivalence of ECTS and LV-Inhalte +$config['explain_equivalence'] = TRUE; diff --git a/application/config/migratecontract.php b/application/config/migratecontract.php new file mode 100644 index 000000000..75ba2f505 --- /dev/null +++ b/application/config/migratecontract.php @@ -0,0 +1,36 @@ +. + */ + +if (!defined('BASEPATH')) exit('No direct script access allowed'); + +$config['migratecontract_oe_default'] = 'TODO_OE_DEFAULT'; + +$config['migratecontract_matching_ba1_vertragsart'] = array( + '101'=>'dvbund', + '102'=>'dvanderengk', + '103'=>'echterdv', + '104'=>'studentischehilfskr', + '105'=>'externerlehrender', + '106'=>'dvanderenbet', + '107'=>'werkvertrag', + '108'=>'studentischehilfskr', + '109'=>'ueberlassungsvertrag', + '110'=>'echterfreier', + '111'=>'echterdv' //All-In +); \ No newline at end of file diff --git a/application/controllers/Studentenverwaltung.php b/application/controllers/Studentenverwaltung.php new file mode 100644 index 000000000..e09d04c6a --- /dev/null +++ b/application/controllers/Studentenverwaltung.php @@ -0,0 +1,40 @@ +method] = ['admin:r', 'assistenz:r']; + parent::__construct($permissions); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + } + + /** + * @return void + */ + public function _remap() + { + $this->load->view('Studentenverwaltung', [ + 'permissions' => [ + 'student/bpk' => $this->permissionlib->isBerechtigt('student/bpk'), + 'student/alias' => $this->permissionlib->isBerechtigt('student/alias'), + 'basis/prestudent' => $this->permissionlib->isBerechtigt('basis/prestudent'), + 'basis/prestudentstatus' => $this->permissionlib->isBerechtigt('basis/prestudentstatus'), + 'assistenz_stgs' => $this->permissionlib->getSTG_isEntitledFor('assistenz'), + 'admin' => $this->permissionlib->isBerechtigt('admin'), + 'assistenz_schreibrechte' => $this->permissionlib->isBerechtigt('assistenz','suid'), + 'student/keine_studstatuspruefung' => $this->permissionlib->isBerechtigt('student/keine_studstatuspruefung'), + 'lehre/reihungstestAufsicht' => $this->permissionlib->isBerechtigt('lehre/reihungstestAufsicht') + ], + 'variables' => [ + 'semester_aktuell' => $this->variablelib->getVar('semester_aktuell') + ] + ]); + } +} diff --git a/application/controllers/api/frontend/fas/studstatus/Wiederholung.php b/application/controllers/api/frontend/fas/studstatus/Wiederholung.php index c6e5a4fa9..19ace3d0d 100644 --- a/application/controllers/api/frontend/fas/studstatus/Wiederholung.php +++ b/application/controllers/api/frontend/fas/studstatus/Wiederholung.php @@ -63,7 +63,9 @@ class Wiederholung extends Auth_Controller $result = $this->antraglib->getLvsForPrestudent($prestudent_id, $sem_akt); - $lvs = $this->getDataOrTerminateWithError($result) ?: []; + if (isError($result)) + return $result; + $lvs = $result->retval; $rdf_url = 'http://www.technikum-wien.at/antragnote'; diff --git a/application/controllers/api/frontend/v1/Udf.php b/application/controllers/api/frontend/v1/Udf.php new file mode 100644 index 000000000..4bdc613e0 --- /dev/null +++ b/application/controllers/api/frontend/v1/Udf.php @@ -0,0 +1,133 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller operates between (interface) the JS (GUI) and the UDFLib (back-end) + * Provides data to the ajax get calls about the Udf component + * Listens to ajax post calls to change the Udf data + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Udf extends FHCAPI_Controller +{ + /** + * Calls the parent's constructor and prepares the UDFLib + */ + public function __construct() + { + // NOTE: UdfLib has its own permissions checks + parent::__construct([ + 'load' => self::PERM_LOGGED, + 'save' => self::PERM_LOGGED + ]); + + // Libraries + $this->load->library('form_validation'); + $this->load->library('UDFLib'); + + // Models + $this->load->model($this->getTargetModelPath(), 'TargetModel'); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Load all UDFs for a dataset + * + * @return void + */ + public function load() + { + $pks = $this->TargetModel->getPks(); + foreach ($pks as $id) + $this->form_validation->set_rules($id, $id, 'required'); + + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + $id = []; + foreach ($pks as $pk) + $id[$pk] = $this->input->post($pk); + if (!is_array($this->TargetModel->getPk())) + $id = current($id); + + $result = $this->udflib->getFieldArray($this->TargetModel, $id); + + $fields = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($fields); + } + + /** + * Saves UDFs to a dataset + * + * @return void + */ + public function save() + { + $pks = $this->TargetModel->getPks(); + foreach ($pks as $id) + $this->form_validation->set_rules($id, $id, 'required'); + + $result = $this->udflib->getCiValidations($this->TargetModel, $this->input->post()); + + $fieldValidations = $this->getDataOrTerminateWithError($result); + + $this->form_validation->set_rules($fieldvalidations); + + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + $id = []; + $fields = $this->input->post(); + foreach ($pks as $pk) { + $id[$pk] = $fields[$pk]; + unset($fields[$pk]); + } + if (!is_array($this->TargetModel->getPk())) + $id = current($id); + + $result = $this->TargetModel->update($id, $fields); + + $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(array_fill_keys(array_keys($fields), '')); + } + + //------------------------------------------------------------------------------------------------------------------ + // Private methods + + /** + * Get the path to the target model from the url + * + * @return string + */ + private function getTargetModelPath() + { + $ci_model_path = array_slice($this->uri->rsegments, 2); + if ($ci_model_path) + $ci_model_path[] = ucfirst(array_pop($ci_model_path)) . '_model'; + return implode(DIRECTORY_SEPARATOR, $ci_model_path); + } +} \ No newline at end of file diff --git a/application/controllers/api/frontend/v1/betriebsmittel/BetriebsmittelP.php b/application/controllers/api/frontend/v1/betriebsmittel/BetriebsmittelP.php new file mode 100644 index 000000000..8e44b2326 --- /dev/null +++ b/application/controllers/api/frontend/v1/betriebsmittel/BetriebsmittelP.php @@ -0,0 +1,387 @@ + ['admin:r', 'assistenz:r'], + 'addNewBetriebsmittel' => self::PERM_LOGGED, + 'updateBetriebsmittel' => self::PERM_LOGGED, + 'loadBetriebsmittel' => ['admin:r', 'assistenz:r'], + 'deleteBetriebsmittel' => self::PERM_LOGGED, + 'getTypenBetriebsmittel' => ['admin:r', 'assistenz:r'], + 'loadInventarliste' => ['admin:r', 'assistenz:r'] + ]); + + //Load Models + $this->load->model('ressource/Betriebsmittel_model', 'BetriebsmittelModel'); + $this->load->model('ressource/Betriebsmittelperson_model', 'BetriebsmittelpersonModel'); + + // Additional Permission Checks + if ($this->router->method == 'addNewBetriebsmittel') { + $this->person_id = current(array_slice($this->uri->rsegments, 2)); + + $this->checkPermissionsForPerson( + $this->person_id, + ['admin:rw', 'mitarbeiter:rw', 'basis/betriebsmittel:rw'], + ['admin:rw', 'assistenz:rw', 'basis/betriebsmittel:rw'] + ); + } elseif ($this->router->method == 'updateBetriebsmittel' || $this->router->method == 'deleteBetriebsmittel') { + $betriebsmittelperson_id = current(array_slice($this->uri->rsegments, 2)); + $result = $this->BetriebsmittelpersonModel->load($betriebsmittelperson_id); + if (!hasData($result)) + show_404(); + $this->person_id = current(getData($result))->person_id; + + $this->checkPermissionsForPerson( + $this->person_id, + ['admin:rw', 'mitarbeiter:rw', 'basis/betriebsmittel:rw'], + ['admin:rw', 'assistenz:rw', 'basis/betriebsmittel:rw'] + ); + } + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + 'wawi' + ]); + } + + public function getAllBetriebsmittel($type_id, $id) + { + $result = $this->BetriebsmittelpersonModel->getBetriebsmittelData($id, $type_id); + + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + $this->terminateWithSuccess((getData($result) ?: [])); + } + + protected function validateNewOrUpdate() + { + $this->form_validation->set_rules('betriebsmitteltyp', 'Typ', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired') + ]); + + $this->form_validation->set_rules('kaution', 'Kaution', 'numeric|less_than_equal_to[9999.99]', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric') + ]); + + $this->form_validation->set_rules('ausgegebenam', 'Ausgegeben am', 'required|is_valid_date', [ + 'required' => $this->p->t('ui', 'error_fieldRequired') + ]); + + if ($this->input->post('ausgegebenam') && $this->input->post('retouram')) { + $this->form_validation->set_rules('retouram', 'Retour am', [ + 'is_valid_date', + ['is_not_before_ausgegebenam', function ($value) { + return (new DateTime($value) >= new DateTime($this->input->post('ausgegebenam'))); + }] + ], [ + 'is_not_before_ausgegebenam' => $this->p->t('wawi', 'error_retourdatumVorAusgabe') + ]); + } else { + $this->form_validation->set_rules('retouram', 'Retour am', 'is_valid_date'); + } + + $this->form_validation->set_rules('anmerkung', 'Anmerkung', 'max_length[256]'); + + if ($this->input->post('betriebsmitteltyp') == 'Inventar') { + // Inventar + $this->form_validation->set_rules('betriebsmittel_id', 'Inventarnummer', 'required'); + } elseif ($this->input->post('betriebsmitteltyp') == 'Zutrittskarte') { + // Zutrittskarte + if ($this->input->post('nummer') === null && $this->input->post('nummer') === null) { + $this->form_validation->set_rules('nummer', 'Nummer', 'required', [ + 'required' => $this->p->t('wawi', 'error_zutrittskarteOhneNummer') + ]); + $this->form_validation->set_rules('nummer2', 'Nummer2', 'required', [ + 'required' => $this->p->t('wawi', 'error_zutrittskarteOhneNummer') + ]); + } else { + if ($this->input->post('nummer') === null) { + $result = $this->BetriebsmittelpersonModel->loadViewWhere([ + 'betriebsmitteltyp' => $this->input->post('betriebsmitteltyp'), + 'nummer2' => $this->input->post('nummer2'), + 'person_id !=' => $this->person_id, + 'retouram IS NULL' => null + ]); + if (hasData($result)) + $this->form_validation->set_rules('nummer2', 'Nummer2', 'is_array', [ + 'is_array' => $this->p->t('wawi', 'error_bmZutrittskarteOccupied', (array)current(getData($result))) + ]); + } else { + $result = $this->BetriebsmittelpersonModel->loadViewWhere([ + 'betriebsmitteltyp' => $this->input->post('betriebsmitteltyp'), + 'nummer' => $this->input->post('nummer'), + 'person_id !=' => $this->person_id, + 'retouram IS NULL' => null + ]); + if (hasData($result)) + $this->form_validation->set_rules('nummer', 'Nummer', 'is_array', [ + 'is_array' => $this->p->t('wawi', 'error_bmZutrittskarteOccupied', (array)current(getData($result))) + ]); + } + } + } + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + public function addNewBetriebsmittel($person_id) + { + $this->form_validation->set_rules('uid', 'UID', [ + ['uid_in_person', function ($value) use ($person_id) { + if ($value === null) + return true; + $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $result = $this->BenutzerModel->loadWhere([ + 'uid' => $value, + 'person_id' => $person_id + ]); + + return hasData($result); + }] + ], [ + 'uid_in_person' => $this->p->t('person', 'error_uidNotInPerson') + ]); + $this->validateNewOrUpdate(); + + $betriebsmitteltyp = $this->input->post('betriebsmitteltyp'); + $nummer = $this->input->post('nummer'); + $nummer2 = $this->input->post('nummer2'); + $beschreibung = $this->input->post('beschreibung'); + $betriebsmittel_id = $this->input->post('betriebsmittel_id'); + $anmerkung = $this->input->post('anmerkung'); + $kaution = $this->input->post('kaution'); + $ausgegebenam = $this->input->post('ausgegebenam'); + $retouram = $this->input->post('retouram'); + $uid = $this->input->post('uid'); + + // NOTE(chris): transform_kartennummer + if ($betriebsmitteltyp == 'Zutrittskarte' && $nummer) + $nummer = is_numeric($nummer) ? ltrim($nummer, "0") : hexdec(implode("", array_reverse(str_split(trim($nummer))))); + + $this->db->trans_start(); + + if ($betriebsmitteltyp != 'Inventar') { + $this->BetriebsmittelModel->addOrder('updateamum', 'DESC'); + if ($betriebsmitteltyp == 'Zutrittskarte' && $nummer === null) { + $result = $this->BetriebsmittelModel->loadWhere([ + 'betriebsmitteltyp' => $betriebsmitteltyp, + 'nummer2' => $nummer2 + ]); + } else { + $result = $this->BetriebsmittelModel->loadWhere([ + 'betriebsmitteltyp' => $betriebsmitteltyp, + 'nummer' => $nummer + ]); + } + $data = $this->getDataOrTerminateWithError($result); + + if ($data) { + $data = current($data); + if ($data->nummer !== $nummer || $data->nummer2 !== $nummer2 || $data->beschreibung !== $beschreibung) { + $result = $this->BetriebsmittelModel->update($data->betriebsmittel_id, [ + 'nummer' => $nummer, + 'nummer2' => $nummer2, + 'beschreibung' => $beschreibung, + 'updateamum' => date('c'), + 'updatevon' => getAuthUID() + ]); + $this->getDataOrTerminateWithError($result); + } + $betriebsmittel_id = $data->betriebsmittel_id; + } else { + $result = $this->BetriebsmittelModel->insert([ + 'betriebsmitteltyp' => $betriebsmitteltyp, + 'nummer' => $nummer, + 'nummer2' => $nummer2, + 'beschreibung' => $beschreibung, + 'reservieren' => false, + 'ort_kurzbz' => null, + 'insertamum' => date('c'), + 'insertvon' => getAuthUID(), + ]); + $betriebsmittel_id = $this->getDataOrTerminateWithError($result); + } + } + + $result = $this->BetriebsmittelpersonModel->insert([ + 'person_id' => $person_id, + 'betriebsmittel_id' => $betriebsmittel_id, + 'anmerkung' => $anmerkung, + 'kaution' => $kaution, + 'ausgegebenam' => $ausgegebenam, + 'retouram' => $retouram, + 'uid' => $uid, + 'insertamum' => date('c'), + 'insertvon' => getAuthUID() + ]); + + $data = $this->getDataOrTerminateWithError($result); + + $this->db->trans_complete(); + + $this->terminateWithSuccess(true); + } + + public function updateBetriebsmittel($betriebsmittelperson_id) + { + $this->validateNewOrUpdate(); + + $betriebsmitteltyp = $this->input->post('betriebsmitteltyp'); + $nummer = $this->input->post('nummer'); + $nummer2 = $this->input->post('nummer2'); + $beschreibung = $this->input->post('beschreibung'); + $betriebsmittel_id = $this->input->post('betriebsmittel_id'); + $anmerkung = $this->input->post('anmerkung'); + $kaution = $this->input->post('kaution'); + $ausgegebenam = $this->input->post('ausgegebenam'); + $retouram = $this->input->post('retouram'); + + // NOTE(chris): transform_kartennummer + if ($betriebsmitteltyp == 'Zutrittskarte' && $nummer) + $nummer = is_numeric($nummer) ? ltrim($nummer, "0") : hexdec(implode("", array_reverse(str_split(trim($nummer))))); + + $this->db->trans_start(); + + if ($betriebsmitteltyp != 'Inventar') { + $found = false; + if ($nummer !== null && $betriebsmittel_id !== null) { + $result = $this->BetriebsmittelModel->load($betriebsmittel_id); + $data = $this->getDataOrTerminateWithError($result); + if ($data && current($data)->nummer == $nummer) { + $found = true; + } + } + + if (!$found) { + $this->BetriebsmittelModel->addOrder('updateamum', 'DESC'); + if ($betriebsmitteltyp == 'Zutrittskarte' && $nummer === null) { + $result = $this->BetriebsmittelModel->loadWhere([ + 'betriebsmitteltyp' => $betriebsmitteltyp, + 'nummer2' => $nummer2 + ]); + } else { + $result = $this->BetriebsmittelModel->loadWhere([ + 'betriebsmitteltyp' => $betriebsmitteltyp, + 'nummer' => $nummer + ]); + } + $data = $this->getDataOrTerminateWithError($result); + } + + if ($data) { + $data = current($data); + if ($data->nummer !== $nummer || $data->nummer2 !== $nummer2 || $data->beschreibung !== $beschreibung) { + $result = $this->BetriebsmittelModel->update($data->betriebsmittel_id, [ + 'nummer' => $nummer, + 'nummer2' => $nummer2, + 'beschreibung' => $beschreibung, + 'updateamum' => date('c'), + 'updatevon' => getAuthUID() + ]); + $this->getDataOrTerminateWithError($result); + } + $betriebsmittel_id = $data->betriebsmittel_id; + } else { + $result = $this->BetriebsmittelModel->insert([ + 'betriebsmitteltyp' => $betriebsmitteltyp, + 'nummer' => $nummer, + 'nummer2' => $nummer2, + 'beschreibung' => $beschreibung, + 'reservieren' => false, + 'ort_kurzbz' => null, + 'insertamum' => date('c'), + 'insertvon' => getAuthUID(), + ]); + $betriebsmittel_id = $this->getDataOrTerminateWithError($result); + } + } + + $result = $this->BetriebsmittelpersonModel->update($betriebsmittelperson_id, [ + 'betriebsmittel_id' => $betriebsmittel_id, + 'anmerkung' => $anmerkung, + 'kaution' => $kaution, + 'ausgegebenam' => $ausgegebenam, + 'retouram' => $retouram, + 'updateamum' => date('c'), + 'updatevon' => getAuthUID() + ]); + + $data = $this->getDataOrTerminateWithError($result); + + $this->db->trans_complete(); + + $this->terminateWithSuccess(true); + } + + public function loadBetriebsmittel($betriebsmittelperson_id) + { + $result = $this->BetriebsmittelpersonModel->getBetriebsmittelData($betriebsmittelperson_id, 'betriebsmittelperson_id'); + + if (isError($result)) { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + if (!hasData($result)) { + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Betriebsmittelperson_id']), self::ERROR_TYPE_GENERAL); + } + + $this->terminateWithSuccess(current(getData($result))); + } + + public function deleteBetriebsmittel($betriebsmittelperson_id) + { + $result = $this->BetriebsmittelpersonModel->delete( + array('betriebsmittelperson_id' => $betriebsmittelperson_id, + ) + ); + + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + if (!hasData($result)) { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Betriebsmittelperson_id']), self::ERROR_TYPE_GENERAL); + } + return $this->outputJsonSuccess(current(getData($result))); + } + + public function getTypenBetriebsmittel() + { + $this->load->model('ressource/Betriebsmitteltyp_model', 'BetriebsmitteltypModel'); + + $this->BetriebsmitteltypModel->addOrder('beschreibung', 'ASC'); + $result = $this->BetriebsmitteltypModel->load(); // load All + + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result) ?: []); + } + + public function loadInventarliste($searchString) + { + $result = $this->BetriebsmittelModel->loadInventarliste($searchString); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } +} + + diff --git a/application/controllers/api/frontend/v1/notiz/NotizPerson.php b/application/controllers/api/frontend/v1/notiz/NotizPerson.php new file mode 100644 index 000000000..cb9d31024 --- /dev/null +++ b/application/controllers/api/frontend/v1/notiz/NotizPerson.php @@ -0,0 +1,51 @@ + ['admin:r', 'assistenz:r'], + 'getNotizen' => ['admin:r', 'assistenz:r'], + 'loadNotiz' => ['admin:r', 'assistenz:r'], + 'addNewNotiz' => ['admin:rw', 'assistenz:rw'], + 'updateNotiz' => ['admin:rw', 'assistenz:rw'], + 'deleteNotiz' => ['admin:rw', 'assistenz:rw'], + 'loadDokumente' => ['admin:r', 'assistenz:r'], + 'getMitarbeiter' => ['admin:r', 'assistenz:r'], + 'isBerechtigt' => ['admin:r', 'assistenz:r'], + ]); + } + + public function isBerechtigt($id, $typeId) + { + if($typeId != "person_id") + { + return $this->terminateWithError($this->p->t('ui', 'error_typeNotizIdIncorrect'), self::ERROR_TYPE_GENERAL); + } + + //TODO define permission + if (!$this->permissionlib->isBerechtigt('admin', 'suid') && !$this->permissionlib->isBerechtigt('assistenz', 'suid')) + { + $result = $this->p->t('lehre', 'error_keineSchreibrechte'); + + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + return $this->outputJsonSuccess(true); + } + + public function loadDokumente() + { + $notiz_id = $this->input->post('notiz_id'); + + // TODO(chris): make CI variant of endpoint + $this->NotizModel->addSelect($this->NotizModel->escape(base_url('content/notizdokdownload.php?id=')) . ' || campus.tbl_dms_version.dms_id AS preview'); + + return parent::loadDokumente(); + } +} \ No newline at end of file diff --git a/application/controllers/api/frontend/v1/studstatus/Leitung.php b/application/controllers/api/frontend/v1/studstatus/Leitung.php index 2699a3dbb..87099ad74 100644 --- a/application/controllers/api/frontend/v1/studstatus/Leitung.php +++ b/application/controllers/api/frontend/v1/studstatus/Leitung.php @@ -53,7 +53,8 @@ class Leitung extends FHCAPI_Controller // Load language phrases $this->loadPhrases([ - 'studierendenantrag' + 'studierendenantrag', + 'lehre' ]); } diff --git a/application/controllers/api/frontend/v1/stv/Address.php b/application/controllers/api/frontend/v1/stv/Address.php new file mode 100644 index 000000000..7685fcd04 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Address.php @@ -0,0 +1,66 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * Provides data to the ajax get calls about addresses + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Address extends FHCAPI_Controller +{ + public function __construct() + { + parent::__construct([ + 'getNations' => self::PERM_LOGGED, + 'getPlaces' => self::PERM_LOGGED + ]); + } + + public function getNations() + { + $this->load->model('codex/Nation_model', 'NationModel'); + + $this->NationModel->addOrder('kurztext'); + + $result = $this->NationModel->load(); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getPlaces($plz) + { + $this->load->model('codex/Gemeinde_model', 'GemeindeModel'); + + $this->load->library('form_validation'); + + $this->form_validation->set_data(['address.plz' => $plz]); + + $this->form_validation->set_rules('address.plz', 'PLZ', 'numeric|less_than[10000]'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $result = $this->GemeindeModel->getGemeindeByPlz($plz); + $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 new file mode 100644 index 000000000..c28c49485 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Config.php @@ -0,0 +1,233 @@ +. + */ + +if (!defined('BASEPATH')) exit('No direct script access allowed'); + +use CI3_Events as Events; + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * Provides data to the ajax get calls about the StV Config + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Config extends FHCAPI_Controller +{ + + + public function __construct() + { + // TODO(chris): permissions + parent::__construct([ + 'student' => ['admin:r', 'assistenz:r'], + 'students' => ['admin:r', 'assistenz:r'] + ]); + + + // Load Phrases + $this->loadPhrases([ + 'global', + 'person', + 'lehre', + 'stv', + 'konto' + ]); + } + + public function student() + { + $result = []; + $result['details'] = [ + 'title' => $this->p->t('stv', 'tab_details'), + 'component' => './Stv/Studentenverwaltung/Details/Details.js' + ]; + $result['notes'] = [ + 'title' => $this->p->t('stv', 'tab_notes'), + 'component' => './Stv/Studentenverwaltung/Details/Notizen.js' + ]; + $result['contact'] = [ + 'title' => $this->p->t('stv', 'tab_contact'), + 'component' => './Stv/Studentenverwaltung/Details/Kontakt.js', + 'config' => [ + 'showBankaccount' => $this->permissionlib->isBerechtigt('mitarbeiter/bankdaten') + || $this->permissionlib->isBerechtigt('student/bankdaten') + ] + ]; + $result['prestudent'] = [ + 'title' => $this->p->t('stv', 'tab_prestudent'), + 'component' => './Stv/Studentenverwaltung/Details/Prestudent.js' + ]; + $result['status'] = [ + 'title' => 'Status', + 'component' => './Stv/Studentenverwaltung/Details/MultiStatus.js' + ]; + $result['banking'] = [ + 'title' => $this->p->t('stv', 'tab_banking'), + 'component' => './Stv/Studentenverwaltung/Details/Konto.js', + 'config' => [ + 'showZahlungsbestaetigung' => (defined('ZAHLUNGSBESTAETIGUNG_ANZEIGEN') && ZAHLUNGSBESTAETIGUNG_ANZEIGEN), + 'showBuchungsnr' => $this->permissionlib->isBerechtigt('admin'), + 'showMahnspanne' => (!defined('FAS_KONTO_SHOW_MAHNSPANNE') || FAS_KONTO_SHOW_MAHNSPANNE===true), + 'showCreditpoints' => (defined('FAS_KONTO_SHOW_CREDIT_POINTS') && FAS_KONTO_SHOW_CREDIT_POINTS == 'true'), + 'columns' => $this->kontoColumns(), + 'additionalCols' => [] + ] + ]; + $result['resources'] = [ + 'title' => $this->p->t('stv', 'tab_resources'), + 'component' => './Stv/Studentenverwaltung/Details/Betriebsmittel.js' + ]; + /* TODO(chris): Ausgeblendet für Testing + $result['grades'] = [ + 'title' => $this->p->t('stv', 'tab_grades'), + 'component' => './Stv/Studentenverwaltung/Details/Noten.js' + ]; + */ + + Events::trigger('stv_conf_student', function & () use (&$result) { + return $result; + }); + + $this->terminateWithSuccess($result); + } + + public function students() + { + $result = []; + $result['banking'] = [ + 'title' => $this->p->t('stv', 'tab_banking'), + 'component' => './Stv/Studentenverwaltung/Details/Konto.js', + 'config' => [ + 'showZahlungsbestaetigung' => (defined('ZAHLUNGSBESTAETIGUNG_ANZEIGEN') && ZAHLUNGSBESTAETIGUNG_ANZEIGEN), + 'showBuchungsnr' => $this->permissionlib->isBerechtigt('admin'), + 'showMahnspanne' => (!defined('FAS_KONTO_SHOW_MAHNSPANNE') || FAS_KONTO_SHOW_MAHNSPANNE===true), + 'showCreditpoints' => (defined('FAS_KONTO_SHOW_CREDIT_POINTS') && FAS_KONTO_SHOW_CREDIT_POINTS == 'true'), + 'columns' => $this->kontoColumnsMultiPerson(), + 'additionalCols' => [] + ] + ]; + $result['status'] = [ + 'title' => 'Status', + 'component' => './Stv/Studentenverwaltung/Details/MultiStatus.js', + 'config' => [ + 'changeStatusToAbbrecherStgl' => $this->permissionlib->isBerechtigt('admin'), + 'changeStatusToAbbrecherStud' => $this->permissionlib->isBerechtigt('admin'), + 'changeStatusToUnterbrecher' => $this->permissionlib->isBerechtigt('admin'), + 'changeStatusToDiplomand' => $this->permissionlib->isBerechtigt('admin'), + 'changeStatusToAbsolvent' => $this->permissionlib->isBerechtigt('admin') + ] + ]; + + Events::trigger('stv_conf_students', function & () use (&$result) { + return $result; + }); + + $this->terminateWithSuccess($result); + } + + protected function kontoColumns() + { + return [ + 'buchungsdatum' => [ + 'field' => "buchungsdatum", + 'title' => $this->p->t('konto', 'buchungsdatum') + ], + 'buchungstext' => [ + 'field' => "buchungstext", + 'title' => $this->p->t('konto', 'buchungstext') + ], + 'betrag' => [ + 'field' => "betrag", + 'title' => $this->p->t('konto', 'betrag') + ], + 'studiensemester_kurzbz' => [ + 'field' => "studiensemester_kurzbz", + 'title' => $this->p->t('lehre', 'studiensemester') + ], + 'buchungstyp_kurzbz' => [ + 'field' => "buchungstyp_kurzbz", + 'title' => $this->p->t('konto', 'buchungstyp'), + 'visible' => false + ], + 'buchungsnr' => [ + 'field' => "buchungsnr", + 'title' => $this->p->t('konto', 'buchungsnr'), + 'visible' => false + ], + 'insertvon' => [ + 'field' => "insertvon", + 'title' => $this->p->t('global', 'insertvon'), + 'visible' => false + ], + 'insertamum' => [ + 'field' => "insertamum", + 'title' => $this->p->t('global', 'insertamum'), + 'visible' => false + ], + 'kuerzel' => [ + 'field' => "kuerzel", + 'title' => $this->p->t('lehre', 'studiengang'), + 'visible' => false + ], + 'anmerkung' => [ + 'field' => "anmerkung", + 'title' => $this->p->t('global', 'anmerkung') + ], + 'actions' => [ + 'title' => $this->p->t('global', 'actions'), + 'frozen' => true + ] + ]; + } + protected function kontoColumnsMultiPerson() + { + return [ + 'person_id' => [ + 'field' => "person_id", + 'title' => $this->p->t('person', 'person_id') + ], + 'anrede' => [ + 'field' => "anrede", + 'title' => $this->p->t('person', 'anrede'), + 'visible' => false + ], + 'titelpost' => [ + 'field' => "titelpost", + 'title' => $this->p->t('person', 'titelpost'), + 'visible' => false + ], + 'titelpre' => [ + 'field' => "titelpre", + 'title' => $this->p->t('person', 'titelpre'), + 'visible' => false + ], + 'vorname' => [ + 'field' => "vorname", + 'title' => $this->p->t('person', 'vorname') + ], + 'vornamen' => [ + 'field' => "vornamen", + 'title' => $this->p->t('person', 'vornamen'), + 'visible' => false + ], + 'nachname' => [ + 'field' => "nachname", + 'title' => $this->p->t('person', 'nachname') + ] + ] + $this->kontoColumns(); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Favorites.php b/application/controllers/api/frontend/v1/stv/Favorites.php new file mode 100644 index 000000000..8d7a6cd14 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Favorites.php @@ -0,0 +1,71 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * Provides data to the ajax get calls about favorite verbände + * Listens to ajax post calls to change the favorite verbände data + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Favorites extends FHCAPI_Controller +{ + public function __construct() + { + parent::__construct([ + 'index' => self::PERM_LOGGED, + 'set' => self::PERM_LOGGED + ]); + + // Load models + $this->load->model('system/Variable_model', 'VariableModel'); + + // TODO(chris): variable table might be to small to store favorites! + } + + public function index() + { + $result = $this->VariableModel->getVariables(getAuthUID(), ['stv_favorites']); + + $data = $this->getDataOrTerminateWithError($result); + + if (!$data) + $this->terminateWithSuccess(null); + else + $this->terminateWithSuccess($data['stv_favorites']); + } + + public function set() + { + $this->load->library('form_validation'); + + $this->form_validation->set_rules('favorites', 'Favorites', 'required'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $favorites = $this->input->post('favorites'); + + $result = $this->VariableModel->setVariable(getAuthUID(), 'stv_favorites', $favorites); + + $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(true); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Filter.php b/application/controllers/api/frontend/v1/stv/Filter.php new file mode 100644 index 000000000..dbf70e4fb --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Filter.php @@ -0,0 +1,84 @@ +. + */ + +if (!defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * Provides data to the ajax get calls about the Studiengang filter + * Listens to ajax post calls to change the Studiengang filter data + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Filter extends FHCAPI_Controller +{ + /** + * Calls the parent's constructor and prepares libraries and phrases + */ + public function __construct() + { + parent::__construct([ + 'getStg' => self::PERM_LOGGED, + 'setStg' => self::PERM_LOGGED + ]); + + // Load models + $this->load->model('system/Variable_model', 'VariableModel'); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Get current setting + * + * @return void + */ + public function getStg() + { + $result = $this->VariableModel->getVariables(getAuthUID(), ['kontofilterstg']); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data['kontofilterstg'] == 'true'); + } + + /** + * Set current setting + * + * @return void + */ + public function setStg() + { + $this->load->library('form_validation'); + + $studiengang_kz = $this->input->post('studiengang_kz'); + + if ($studiengang_kz === null) { + $this->form_validation->set_rules('studiengang_kz', 'Studiengang', 'required'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $result = $this->VariableModel->setVariable(getAuthUID(), 'kontofilterstg', $studiengang_kz ? 'true' : 'false'); + + $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(true); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Kontakt.php b/application/controllers/api/frontend/v1/stv/Kontakt.php new file mode 100644 index 000000000..379184ee0 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Kontakt.php @@ -0,0 +1,754 @@ + ['admin:r', 'assistenz:r'], + 'addNewAddress' => ['admin:rw', 'assistenz:rw'], + 'addNewContact' => ['admin:rw', 'assistenz:rw'], + 'addNewBankverbindung' => ['mitarbeiter/bankdaten:rw', 'student/bankdaten:rw'], + 'updateAddress' => ['admin:rw', 'assistenz:rw'], + 'updateContact' => ['admin:rw', 'assistenz:rw'], + 'updateBankverbindung' => ['mitarbeiter/bankdaten:rw', 'student/bankdaten:rw'], + 'loadAddress' => ['admin:r', 'assistenz:r'], + 'loadContact' => ['admin:r', 'assistenz:r'], + 'loadBankverbindung' => ['mitarbeiter/bankdaten:r', 'student/bankdaten:r'], + 'deleteAddress' => ['admin:rw', 'assistenz:rw'], + 'deleteContact' => ['admin:rw','assistenz:rw'], + 'deleteBankverbindung' => ['mitarbeiter/bankdaten:rw','astudent/bankdaten:rw'], + 'getAdressentypen' => ['admin:r', 'assistenz:r'], + 'getKontakttypen' => ['admin:r', 'assistenz:r'], + 'getFirmen' => ['admin:r', 'assistenz:r'], + 'getStandorte' => ['admin:r', 'assistenz:r'], + 'getStandorteByFirma' => ['admin:r', 'assistenz:r'], + 'getKontakte' => ['admin:r', 'assistenz:r'], + 'getBankverbindung' => ['mitarbeiter/bankdaten:r', 'student/bankdaten:r'] + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('form_validation'); + + // Load language phrases + $this->loadPhrases([ + 'ui', + 'person' + ]); + + // Load models + $this->load->model('person/Adresse_model', 'AdresseModel'); + $this->load->model('organisation/standort_model', 'StandortModel'); + $this->load->model('ressource/firma_model', 'FirmaModel'); + $this->load->model('person/Kontakt_model', 'KontaktModel'); + + // Extra Permissionchecks + $permsMa = []; + $permsStud = []; + switch ($this->router->method) { + case 'getBankverbindung': + case 'loadBankverbindung': + $permsMa = ['mitarbeiter/bankdaten:r']; + $permsStud = ['student/bankdaten:r']; + break; + case 'addNewBankverbindung': + case 'updateBankverbindung': + case 'deleteBankverbindung': + $permsMa = ['mitarbeiter/bankdaten:rw']; + $permsStud = ['student/bankdaten:rw']; + break; + case 'getAdressen': + case 'getKontakte': + case 'loadAddress': + case 'loadContact': + $permsMa = $permsStud = ['admin:r', 'assistenz:r']; + break; + case 'addNewAddress': + case 'addNewContact': + case 'updateAddress': + case 'updateContact': + case 'deleteAddress': + case 'deleteContact': + $permsMa = $permsStud = ['admin:rw', 'assistenz:rw']; + break; + } + if ($this->router->method == 'getAdressen' + || $this->router->method == 'getKontakte' + || $this->router->method == 'getBankverbindung' + || $this->router->method == 'addNewAddress' + || $this->router->method == 'addNewContact' + || $this->router->method == 'addNewBankverbindung' + ) { + $person_id = current(array_slice($this->uri->rsegments, 2)); + + $this->checkPermissionsForPerson($person_id, $permsMa, $permsStud); + } elseif ($this->router->method == 'loadAddress' + || $this->router->method == 'loadContact' + || $this->router->method == 'loadBankverbindung' + || $this->router->method == 'updateAddress' + || $this->router->method == 'updateContact' + || $this->router->method == 'updateBankverbindung' + || $this->router->method == 'deleteAddress' + || $this->router->method == 'deleteContact' + || $this->router->method == 'deleteBankverbindung' + ) { + $id = current(array_slice($this->uri->rsegments, 2)); + + $model = 'person/Adresse_model'; + if ($this->router->method == 'loadContact' + || $this->router->method == 'updateContact' + || $this->router->method == 'deleteContact' + ) { + $model = 'person/Kontakt_model'; + } elseif ($this->router->method == 'loadBankverbindung' + || $this->router->method == 'updateBankverbindung' + || $this->router->method == 'deleteBankverbindung' + ) { + $model = 'person/Bankverbindung_model'; + } + + $this->load->model($model, 'TempModel'); + $result = $this->TempModel->load($id); + $data = $this->getDataOrTerminateWithError($result); + if (!$result) + show_404(); + + $person_id = current($data)->person_id; + + $this->checkPermissionsForPerson($person_id, $permsMa, $permsStud); + } + } + public function getAdressen($person_id) + { + $this->AdresseModel->addSelect('public.tbl_adresse.*'); + $this->AdresseModel->addSelect('t.*'); + $this->AdresseModel->addSelect('f.firma_id'); + $this->AdresseModel->addSelect('f.name as firmenname'); + $this->AdresseModel->addJoin('public.tbl_adressentyp t', 'ON (t.adressentyp_kurzbz = public.tbl_adresse.typ)'); + $this->AdresseModel->addJoin('public.tbl_firma f', 'ON (f.firma_id = public.tbl_adresse.firma_id)', 'LEFT'); + + $result = $this->AdresseModel->loadWhere( + array('person_id' => $person_id) + ); + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess((getData($result) ?: [])); + } + + public function addNewAddress($person_id) + { + $this->form_validation->set_rules('plz', 'PLZ', 'required|numeric', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'PLZ']), + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'PLZ']) + ]); + + if(isset($_POST['gemeinde']) && isset($_POST['ort'])) + $this->form_validation->set_rules('plz', 'Postleitzahl', 'callback_validateLocationCombination', [ + 'validateLocationCombination' => $this->p->t('ui', 'error_location_combination') + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $uid = getAuthUID(); + $co_name = isset($_POST['co_name']) ? $_POST['co_name'] : null; + $strasse = isset($_POST['strasse']) ? $_POST['strasse'] : null; + $ort = isset($_POST['ort']) ? $_POST['ort'] : null; + $gemeinde = isset($_POST['gemeinde']) ? $_POST['gemeinde'] : null; + $nation = isset($_POST['nation']) ? $_POST['nation'] : null; + $name = isset($_POST['name']) ? $_POST['name'] : null; + $typ = isset($_POST['typ']) ? $_POST['typ'] : null; + $anmerkung = isset($_POST['anmerkung']) ? $_POST['anmerkung'] : null; + + if(isset($_POST['firma'])) + { + $firma_id = $_POST['firma']['firma_id']; + } + else + $firma_id = null; + + $result = $this->AdresseModel->insert( + [ + 'person_id' => $person_id, + 'strasse' => $strasse, + 'insertvon' => $uid, + 'insertamum' => date('c'), + 'plz' => $_POST['plz'], + 'ort' => $ort, + 'gemeinde' => $gemeinde, + 'nation' => $nation, + 'heimatadresse' => $_POST['heimatadresse'], + 'zustelladresse' => $_POST['zustelladresse'], + 'co_name' => $co_name, + 'typ' => $typ, + 'firma_id' => $firma_id, + 'name' => $name, + 'rechnungsadresse' => $_POST['rechnungsadresse'], + 'anmerkung' => $anmerkung + + ] + ); + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->outputJsonSuccess(true); + } + + public function updateAddress($address_id) + { + $uid = getAuthUID(); + $this->form_validation->set_rules('plz', 'PLZ', 'required|numeric', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'PLZ']), + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'PLZ']) + ]); + + if(isset($_POST['gemeinde']) && isset($_POST['ort'])) + $this->form_validation->set_rules('plz', 'Postleitzahl', 'callback_validateLocationCombination', [ + 'validateLocationCombination' => $this->p->t('ui', 'error_location_combination') + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $this->load->model('person/Adresse_model', 'AdresseModel'); + + if(!$address_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Adresse_id']), self::ERROR_TYPE_GENERAL); + } + + if(isset($_POST['firma'])) + { + $firma_id = $_POST['firma']['firma_id']; + } + elseif(isset($_POST['firma_id'])) + { + $firma_id = $_POST['firma_id']; + } + else + $firma_id = null; + + $person_id = isset($_POST['person_id']) ? $_POST['person_id'] : null; + $co_name = isset($_POST['co_name']) ? $_POST['co_name'] : null; + $strasse = isset($_POST['strasse']) ? $_POST['strasse'] : null; + $ort = isset($_POST['ort']) ? $_POST['ort'] : null; + $gemeinde = isset($_POST['gemeinde']) ? $_POST['gemeinde'] : null; + $nation = isset($_POST['nation']) ? $_POST['nation'] : null; + $name = isset($_POST['name']) ? $_POST['name'] : null; + $typ = isset($_POST['typ']) ? $_POST['typ'] : null; + $anmerkung = isset($_POST['anmerkung']) ? $_POST['anmerkung'] : null; + + $result = $this->AdresseModel->update( + [ + 'adresse_id' => $address_id + ], + [ 'person_id' => $person_id, + 'strasse' => $strasse, + 'updatevon' => $uid, + 'updateamum' => date('c'), + 'plz' => $_POST['plz'], + 'ort' => $ort, + 'gemeinde' => $gemeinde, + 'nation' => $nation, + 'heimatadresse' => $_POST['heimatadresse'], + 'zustelladresse' => $_POST['zustelladresse'], + 'co_name' => $co_name, + 'typ' => $typ, + 'firma_id' => $firma_id, + 'name' => $name, + 'rechnungsadresse' => $_POST['rechnungsadresse'], + 'anmerkung' => $anmerkung + ] + ); + + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->outputJsonSuccess(true); + } + + public function loadAddress($adresse_id) + { + $this->load->model('person/Adresse_model', 'AdresseModel'); + + $this->AdresseModel->addSelect('public.tbl_adresse.*'); + $this->AdresseModel->addSelect('t.*'); + $this->AdresseModel->addSelect('f.firma_id'); + $this->AdresseModel->addSelect('f.name as firmenname'); + $this->AdresseModel->addJoin('public.tbl_adressentyp t', 'ON (t.adressentyp_kurzbz = public.tbl_adresse.typ)'); + $this->AdresseModel->addJoin('public.tbl_firma f', 'ON (f.firma_id = public.tbl_adresse.firma_id)', 'LEFT'); + + $this->AdresseModel->addLimit(1); + + $result = $this->AdresseModel->loadWhere( + array('adresse_id' => $adresse_id) + ); + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + if (!hasData($result)) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Adresse_id']), self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess(current(getData($result)) ? : null); + } + + public function deleteAddress($adresse_id) + { + $this->load->model('person/Adresse_model', 'AdresseModel'); + $result = $this->AdresseModel->load([ + 'adresse_id'=> $adresse_id, + ]); + if(isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $result = current(getData($result)); + + if($result->heimatadresse) + + $this->terminateWithError($this->p->t('person', 'error_deleteHomeAdress'), self::ERROR_TYPE_GENERAL); + + $result = $this->AdresseModel->delete( + array('adresse_id' => $adresse_id) + ); + + if (isError($result)) + { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + if (!hasData($result)) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Adresse_id']), self::ERROR_TYPE_GENERAL); + } + + return $this->terminateWithSuccess(current(getData($result)) ? : null); + } + + public function getAdressentypen() + { + $this->load->model('person/Adressentyp_model', 'AdressentypModel'); + + $result = $this->AdressentypModel->load(); + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess(getData($result) ?: []); + } + + public function getFirmen($searchString) + { + $this->load->model('ressource/firma_model', 'FirmaModel'); + + $result = $this->FirmaModel->searchFirmen($searchString); + if (isError($result)) { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess($result ?: []); + } + + public function getStandorte($searchString) + { + $this->load->model('organisation/standort_model', 'StandortModel'); + + $result = $this->StandortModel->searchStandorte($searchString); + if (isError($result)) { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess($result ?: []); + } + + public function getStandorteByFirma($firma_id) + { + $this->load->model('organisation/standort_model', 'StandortModel'); + + $result = $this->StandortModel->getStandorteByFirma($firma_id); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getKontakte($person_id) + { + $this->KontaktModel->addSelect("public.tbl_kontakt.*, + TO_CHAR (CASE + WHEN public.tbl_kontakt.updateamum >= public.tbl_kontakt.insertamum + THEN public.tbl_kontakt.updateamum + ELSE public.tbl_kontakt.insertamum + END::timestamp, 'DD.MM.YYYY HH24:MI:SS') AS lastUpdate, st.bezeichnung, f.name"); + $this->StandortModel->addJoin('public.tbl_standort st', 'ON (public.tbl_kontakt.standort_id = st.standort_id)', 'LEFT'); + $this->FirmaModel->addJoin('public.tbl_firma f', 'ON (f.firma_id = st.firma_id)', 'LEFT'); + $result = $this->KontaktModel->loadWhere( + array('person_id' => $person_id) + ); + + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess((getData($result) ?: [])); + } + + public function getKontakttypen() + { + $this->load->model('person/Kontakttyp_model', 'KontakttypModel'); + + $result = $this->KontakttypModel->load(); + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + else + { + $this->terminateWithSuccess(getData($result) ?: []); + } + } + + public function loadContact($kontakt_id) + { + $this->load->model('person/Kontakt_model', 'KontaktModel'); + + $this->KontaktModel->addSelect('*, public.tbl_kontakt.*'); + $this->KontaktModel->addSelect('st.kurzbz'); + $this->KontaktModel->addJoin('public.tbl_standort st', 'ON (public.tbl_kontakt.standort_id = st.standort_id)', 'LEFT'); + $this->FirmaModel->addJoin('public.tbl_firma f', 'ON (f.firma_id = st.firma_id)', 'LEFT'); + + $this->KontaktModel->addLimit(1); + + $result = $this->KontaktModel->loadWhere( + array('kontakt_id' => $kontakt_id) + ); + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + if (!hasData($result)) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Kontakt_id']), self::ERROR_TYPE_GENERAL); + } + // $this->outputJsonSuccess(current(getData($result))); + $this->terminateWithSuccess(current(getData($result))); + } + + public function addNewContact($person_id) + { + if(($_POST['kontakttyp'] == 'email' && isset($_POST['kontakt']))) + { + $this->form_validation->set_rules('kontakt', 'Kontakt', 'required|valid_email', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Kontakt']), + 'valid_email' => $this->p->t('ui', 'error_fieldNoValidEmail', ['field' => 'Kontakt']) + ]); + } + else + { + $this->form_validation->set_rules('kontakt', 'Kontakt', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Kontakt']) + ]); + } + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $this->load->model('person/Kontakt_model', 'KontaktModel'); + + $uid = getAuthUID(); + + $kontakttyp = $this->input->post('kontakttyp'); + $anmerkung = $this->input->post('anmerkung'); + $kontakt = $this->input->post('kontakt'); + $ext_id = $this->input->post('ext_id'); + $standort_id = $this->input->post('standort_id'); + + $result = $this->KontaktModel->insert( + [ + 'person_id' => $person_id, + 'kontakttyp' => $kontakttyp, + 'anmerkung' => $anmerkung, + 'kontakt' => $kontakt, + 'zustellung' => $_POST['zustellung'], + 'insertvon' => $uid, + 'insertamum' => date('c'), + 'standort_id' => $standort_id, + 'ext_id' => $ext_id + ] + ); + + if (isError($result)) + { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + return $this->outputJsonSuccess(true); + } + + public function updateContact($kontakt_id) + { + $this->load->model('person/Kontakt_model', 'KontaktModel'); + + if(!$kontakt_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Kontakt_id']), self::ERROR_TYPE_GENERAL); + } + + if(($_POST['kontakttyp'] == 'email' && isset($_POST['kontakt']))) + { + $this->form_validation->set_rules('kontakt', 'Kontakt', 'required|valid_email', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Kontakt']), + 'valid_email' => $this->p->t('ui', 'error_fieldNoValidEmail', ['field' => 'Kontakt']) + ]); + } + else + { + $this->form_validation->set_rules('kontakt', 'Kontakt', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Kontakt']) + ]); + } + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + +/* if(isset($_POST['standort'])) + { + $standort_id = $_POST['standort']['standort_id']; + } + else + $standort_id = null;*/ + + $uid = getAuthUID(); + $kontakttyp = $this->input->post('kontakttyp'); + $anmerkung = $this->input->post('anmerkung'); + $kontakt = $this->input->post('kontakt'); + $ext_id = $this->input->post('ext_id'); + $person_id = $this->input->post('person_id'); + $standort_id = $this->input->post('standort_id'); + + //return $this->terminateWithError("in update " . $standort_id, self::ERROR_TYPE_GENERAL); + + $result = $this->KontaktModel->update( + [ + 'kontakt_id' => $kontakt_id + ], + [ + 'person_id' => $person_id, + 'kontakttyp' => $kontakttyp, + 'anmerkung' => $anmerkung, + 'kontakt' => $kontakt, + 'zustellung' => $_POST['zustellung'], + 'insertvon' => $uid, + 'insertamum' => date('c'), + 'standort_id' => $standort_id, + 'ext_id' => $ext_id + ] + ); + + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->outputJsonSuccess(true); + } + + public function deleteContact($kontakt_id) + { + $this->load->model('person/Kontakt_model', 'KontaktModel'); + + $result = $this->KontaktModel->delete( + array('kontakt_id' => $kontakt_id) + ); + + if (isError($result)) + { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + elseif (!hasData($result)) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Kontakt_id']), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(current(getData($result)) ? : null); + } + + public function getBankverbindung($person_id) + { + $this->load->model('person/Bankverbindung_model', 'BankverbindungModel'); + + $this->BankverbindungModel->addSelect('*'); + + $result = $this->BankverbindungModel->loadWhere( + array('person_id' => $person_id) + ); + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess((getData($result) ?: [])); + } + + public function addNewBankverbindung($person_id) + { + $this->form_validation->set_rules('iban', 'IBAN', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'IBAN']) + ]); + + $this->form_validation->set_rules('typ', 'TYP', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'TYP']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $this->load->model('person/Bankverbindung_model', 'BankverbindungModel'); + + $ext_id = $this->input->post('ext_id'); + $oe_kurzbz = $this->input->post('oe_kurzbz'); + $orgform_kurzbz = $this->input->post('orgform_kurzbz'); + $name = $this->input->post('name'); + $anschrift = $this->input->post('anschrift'); + $bic = $this->input->post('bic'); + $blz = $this->input->post('blz'); + $kontonr = $this->input->post('kontonr'); + + $result = $this->BankverbindungModel->insert( + [ + 'person_id' => $person_id, + 'name' => $name, + 'anschrift' => $anschrift, + 'bic' => $bic, + 'iban' => $_POST['iban'], + 'blz' => $blz, + 'kontonr' => $kontonr, + 'insertvon' => 'uid', + 'insertamum' => date('c'), + 'typ' => $_POST['typ'], + 'verrechnung' => $_POST['verrechnung'], + 'ext_id' => $ext_id, + 'oe_kurzbz' => $oe_kurzbz, + 'orgform_kurzbz' => $orgform_kurzbz + ] + ); + if (isError($result)) + { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + return $this->outputJsonSuccess(true); + } + + public function loadBankverbindung($bankverbindung_id) + { + $this->load->model('person/Bankverbindung_model', 'BankverbindungModel'); + + $this->BankverbindungModel->addSelect('*'); + + $this->BankverbindungModel->addLimit(1); + + $result = $this->BankverbindungModel->loadWhere( + array('bankverbindung_id' => $bankverbindung_id) + ); + if (isError($result)) + { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + if (!hasData($result)) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Bankverbindung_id']), self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess(current(getData($result))); + } + + public function updateBankverbindung($bankverbindung_id) + { + $this->form_validation->set_rules('iban', 'IBAN', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'IBAN']) + ]); + + $this->form_validation->set_rules('typ', 'TYP', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'TYP']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $this->load->model('person/Bankverbindung_model', 'BankverbindungModel'); + + if(!$bankverbindung_id) + { + return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Bankverbindung_id']), self::ERROR_TYPE_GENERAL); + } + + $uid = getAuthUID(); + + $result = $this->BankverbindungModel->update( + [ + 'bankverbindung_id' => $bankverbindung_id + ], + [ + 'person_id' => $_POST['person_id'], + 'name' => $_POST['name'], + 'anschrift' => $_POST['anschrift'], + 'bic' => $_POST['bic'], + 'iban' => $_POST['iban'], + 'blz' => $_POST['blz'], + 'kontonr' => $_POST['kontonr'], + 'updatevon' => $uid, + 'updateamum' => date('c'), + 'typ' => $_POST['typ'], + 'verrechnung' => $_POST['verrechnung'], + 'ext_id' => $_POST['ext_id'], + 'oe_kurzbz' => $_POST['oe_kurzbz'], + 'orgform_kurzbz' => $_POST['orgform_kurzbz'] + ] + ); + + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->outputJsonSuccess(true); + } + + public function deleteBankverbindung($bankverbindung_id) + { + $this->load->model('person/Bankverbindung_model', 'BankverbindungModel'); + + $result = $this->BankverbindungModel->delete( + array('bankverbindung_id' => $bankverbindung_id) + ); + + if (isError($result)) + { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + if (!hasData($result)) + { + $this->outputJson($result); + } + return $this->terminateWithSuccess(current(getData($result)) ? : null); + } + + public function validateLocationCombination() + { + $this->load->model('codex/Gemeinde_model', 'GemeindeModel'); + + return $this->GemeindeModel->checkLocation($_POST['plz'], $_POST['gemeinde'], $_POST['ort']); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Konto.php b/application/controllers/api/frontend/v1/stv/Konto.php new file mode 100644 index 000000000..ac36b5d8f --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Konto.php @@ -0,0 +1,495 @@ +. + */ + +if (!defined('BASEPATH')) exit('No direct script access allowed'); + +use CI3_Events as Events; + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * Provides data to the ajax get calls about a Konto + * Listens to ajax post calls to change the Konto data + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Konto extends FHCAPI_Controller +{ + /** + * Calls the parent's constructor and prepares libraries and phrases + */ + public function __construct() + { + parent::__construct([ + 'get' => 'student/stammdaten:r', + 'getBuchungstypen' => self::PERM_LOGGED, + 'checkDoubles' => ['admin:r', 'assistenz:r'], + 'insert' => ['admin:w', 'assistenz:w'], + 'counter' => ['admin:w', 'assistenz:w'], + 'update' => ['admin:w', 'assistenz:w'], + 'delete' => ['admin:w', 'assistenz:w'] + ]); + + // Load models + $this->load->model('crm/Konto_model', 'KontoModel'); + + // Load language phrases + $this->loadPhrases([ + 'konto' + ]); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Get details for a prestudent + * + * @return void + */ + public function get() + { + $this->load->library('form_validation'); + + $person_id = $this->input->post('person_id'); + if (!$person_id || !is_array($person_id)) { + $this->form_validation->set_rules('person_id', 'Person ID', 'required'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + + $studiengang_kz = $this->input->post('studiengang_kz'); + + if ($this->input->post('only_open')) { + $result = $this->KontoModel->getOffeneBuchungen($person_id, $studiengang_kz); + } else { + $result = $this->KontoModel->getAlleBuchungen($person_id, $studiengang_kz); + } + + $result = $this->getDataOrTerminateWithError($result); + + // sort into tree + $childs = []; + $data = []; + foreach ($result as $entry) { + if ($entry->buchungsnr_verweis) { + if (isset($data[$entry->buchungsnr_verweis])) { + if (!isset($data[$entry->buchungsnr_verweis]->_children)) + $data[$entry->buchungsnr_verweis]->_children = []; + $data[$entry->buchungsnr_verweis]->_children[] = $entry; + } else { + if (!isset($childs[$entry->buchungsnr_verweis])) + $childs[$entry->buchungsnr_verweis] = []; + $childs[$entry->buchungsnr_verweis][] = $entry; + } + } else { + $data[$entry->buchungsnr] = $entry; + if (isset($childs[$entry->buchungsnr])) + $entry->_children = $childs[$entry->buchungsnr]; + } + } + + $this->terminateWithSuccess(array_values($data)); + } + + /** + * Get list of Buchungstypen + * + * @return void + */ + public function getBuchungstypen() + { + $this->load->model('crm/Buchungstyp_model', 'BuchungstypModel'); + + $result = $this->BuchungstypModel->load(); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + /** + * Check double Buchungen + * + * @return void + */ + public function checkDoubles() + { + if (!defined('FAS_DOPPELTE_BUCHUNGSTYPEN_CHECK') || !FAS_DOPPELTE_BUCHUNGSTYPEN_CHECK) + $this->terminateWithSuccess(false); + + $this->load->library('form_validation'); + + $person_ids = $this->input->post('person_id'); + + if (!$person_ids || !is_array($person_ids)) { + $person_ids = [$person_ids]; + $this->form_validation->set_rules('person_id', 'Person ID', 'required'); + } + $this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester', 'required'); + $this->form_validation->set_rules('buchungstyp_kurzbz', 'Buchungstyp', 'required'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + $buchungstypen = unserialize(FAS_DOPPELTE_BUCHUNGSTYPEN_CHECK); + $buchung = $this->input->post('buchungstyp_kurzbz'); + + if (!isset($buchungstypen[$buchung])) + $this->terminateWithSuccess(false); + + $result = $this->KontoModel->checkDoubleBuchung($person_ids, $this->input->post('studiensemester_kurzbz'), $buchungstypen[$buchung]); + + $result = $this->getDataOrTerminateWithError($result); + + if (!$result) + $this->terminateWithSuccess(false); + + $persons = array_map(function ($row) { + return $row->nachname . ' ' . $row->vorname; + }, $result); + + $result = $this->p->t('konto', 'confirm_overwrite') . "\n"; + if (count($persons) > 10) { + $result .= "-" . implode("\n-", array_slice($persons, 0, 10)) . "\n"; + + if (count($persons) == 11) { + $result .= "\n" . $this->p->t('konto', 'confirm_overwrite_1_add_pers'); + } else { + $result .= "\n" . $this->p->t('konto', 'confirm_overwrite_x_add_pers', [ + 'x' => count($persons) - 10 + ]); + } + } else { + $result .= "-" . implode("\n-", $persons) . "\n"; + } + $result .= $this->p->t('konto', 'confirm_overwrite_proceed'); + + $this->addError($result, 'confirm'); + + $this->terminateWithSuccess(true); + } + + + /** + * Save Buchung + * + * @return void + */ + public function insert() + { + $this->load->library('form_validation'); + + $person_ids = $this->input->post('person_id'); + + if (!$person_ids || !is_array($person_ids)) { + $person_ids = [$person_ids]; + $this->form_validation->set_rules('person_id', 'Person ID', 'required'); + } + $this->form_validation->set_rules('betrag', 'Betrag', 'numeric'); + $this->form_validation->set_rules('buchungsdatum', 'Buchungsdatum', 'is_valid_date'); + $this->form_validation->set_rules('buchungstext', 'Buchungstext', 'max_length[256]'); + $this->form_validation->set_rules('mahnspanne', 'Mahnspanne', 'integer'); + $this->form_validation->set_rules('buchungstyp_kurzbz', 'Buchungstyp', 'required|max_length[32]'); + $this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester', 'required|max_length[16]'); + $this->form_validation->set_rules('studiengang_kz', 'Studiengang', 'required|has_permissions_for_stg[admin:rw,assistenz:rw]'); + $this->form_validation->set_rules('credit_points', 'Credit Points', 'numeric'); + + Events::trigger('konto_insert_validation', $this->form_validation); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + $allowed = [ + 'betrag', + 'buchungsdatum', + 'buchungstext', + 'mahnspanne', + 'buchungstyp_kurzbz', + 'studiensemester_kurzbz', + 'studiengang_kz', + 'credit_points', + 'anmerkung' + ]; + $data = [ + 'insertamum' => date('c'), + 'insertvon' => getAuthUID() + ]; + foreach ($allowed as $field) + if ($this->input->post($field) !== null) + $data[$field] = $this->input->post($field); + + if (defined('FAS_BUCHUNGSTYP_FIXE_KOSTENSTELLE') && isset(unserialize(FAS_BUCHUNGSTYP_FIXE_KOSTENSTELLE)[$data['buchungstyp_kurzbz']])) { + $data['kostenstelle'] = unserialize(FAS_BUCHUNGSTYP_FIXE_KOSTENSTELLE)[$data['buchungstyp_kurzbz']]; + } + + $result = []; + foreach ($person_ids as $person_id) { + $id = $this->KontoModel->insert(array_merge($data, ['person_id' => $person_id])); + if (isError($id)) { + $this->addError(getError($id), self::ERROR_TYPE_DB); + } else { + $kontodata = $this->KontoModel->withAdditionalInfo()->load(getData($id)); + if (isError($kontodata)) + $this->addError(getError($kontodata), self::ERROR_TYPE_DB); + else + $result[] = current(getData($kontodata)); + } + } + + if ($result) + $this->terminateWithSuccess($result); + + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + } + + /** + * Save Counter Buchung + * + * @return void + */ + public function counter() + { + $this->load->library('form_validation'); + + $buchungsnrs = $this->input->post('buchungsnr'); + + if (!$buchungsnrs || !is_array($buchungsnrs)) { + $buchungsnrs = $buchungsnrs ? [$buchungsnrs] : []; + $this->form_validation->set_rules('buchungsnr', 'Buchungsnr', 'required'); + } + $this->form_validation->set_rules('buchungsdatum', 'Buchungsdatum', 'is_valid_date'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $data = []; + $rules = []; + foreach ($buchungsnrs as $k => $buchungsnr) { + $result = $this->KontoModel->load($buchungsnr); + if (isError($result)) { + $rules[] = [ + 'field' => 'buchung[' . $k . ']', + 'label' => 'Buchung #' . $buchungsnr, + 'rules' => 'required', + 'errors' => [ + 'required' => getError($result) + ] + ]; + } elseif (!hasData($result)) { + $rules[] = [ + 'field' => 'buchung[' . $k . ']', + 'label' => 'Buchung #' . $buchungsnr, + 'rules' => 'required' + ]; + } else { + $data[$k] = get_object_vars(current(getData($result))); + $rules[] = [ + 'field' => 'buchung[' . $k . '][buchungsnr]', + 'label' => 'Buchung # ' . $buchungsnr, + 'rules' => 'required|numeric' + ]; + $rules[] = [ + 'field' => 'buchung[' . $k . '][studiengang_kz]', + 'label' => 'Buchung # ' . $buchungsnr, + 'rules' => 'required|has_permissions_for_stg[admin:rw,assistenz:rw]' + ]; + $rules[] = [ + 'field' => 'buchung[' . $k . '][buchungsnr_verweis]', + 'label' => 'Buchung # ' . $buchungsnr, + 'rules' => 'regex_match[/^$/]', + 'errors' => [ + 'regex_match' => $this->p->t('konto', 'error_counter_level') + ] + ]; + } + } + + $this->form_validation->reset_validation(); + $this->form_validation->set_data(['buchung' => $data]); + $this->form_validation->set_rules($rules); + + Events::trigger('konto_counter_validation', $this->form_validation); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $buchungsdatum = $this->input->post('buchungsdatum'); + + $newItems = []; + foreach ($data as $buchung) { + $result = $this->KontoModel->getDifferenz($buchung['buchungsnr']); + if (isError($result)) { + $this->addError(getError($result), self::ERROR_TYPE_GENERAL); + continue; + } + $betrag = $result->retval; + if ($betrag === null) { + $this->addError($this->p->t( + 'konto', + 'error_missing', + $buchung + ), self::ERROR_TYPE_GENERAL); + continue; + } + + + $result = $this->KontoModel->insert([ + 'person_id' => $buchung['person_id'], + 'studiengang_kz' => $buchung['studiengang_kz'], + 'studiensemester_kurzbz' => $buchung['studiensemester_kurzbz'], + 'buchungstext' => $buchung['buchungstext'], + 'buchungstyp_kurzbz' => $buchung['buchungstyp_kurzbz'], + 'credit_points' => $buchung['credit_points'], + 'zahlungsreferenz' => $buchung['zahlungsreferenz'], + 'betrag' => $betrag, + 'buchungsdatum' => $buchungsdatum, + 'mahnspanne' => '0', + 'buchungsnr_verweis' => $buchung['buchungsnr'], + 'insertamum' => date('c'), + 'insertvon' => getAuthUID(), + 'anmerkung' => '' + ]); + if (isError($result)) { + $this->addError(getError($result), self::ERROR_TYPE_GENERAL); + continue; + } + + $newItems = null; + // TODO(chris): get as tree? + /*$result = $this->KontoModel->withAdditionalInfo()->load($result->retval); + if (!hasData($result)) + $newItems = null; + elseif ($newItems !== null) + $newItems[] = current(getData($result));*/ + } + + $this->terminateWithSuccess($newItems); + } + + /** + * Save Buchung + * + * @return void + */ + public function update() + { + $this->load->library('form_validation'); + + $this->form_validation->set_rules('buchungsnr', 'Buchungsnr', 'required'); + $this->form_validation->set_rules('betrag', 'Betrag', 'numeric'); + $this->form_validation->set_rules('buchungsdatum', 'Buchungsdatum', 'is_valid_date'); + $this->form_validation->set_rules('buchungstext', 'Buchungstext', 'max_length[256]'); + $this->form_validation->set_rules('mahnspanne', 'Mahnspanne', 'integer'); + $this->form_validation->set_rules('buchungstyp_kurzbz', 'Buchungstyp', 'required|max_length[32]'); + $this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester', 'required|max_length[16]'); + $this->form_validation->set_rules('studiengang_kz', 'Studiengang', 'required|has_permissions_for_stg[admin:rw,assistenz:rw]'); + $this->form_validation->set_rules('credit_points', 'Credit Points', 'numeric'); + + Events::trigger('konto_update_validation', $this->form_validation); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + $id = $this->input->post('buchungsnr'); + $allowed = [ + 'betrag', + 'buchungsdatum', + 'buchungstext', + 'mahnspanne', + 'buchungstyp_kurzbz', + 'studiensemester_kurzbz', + 'studiengang_kz', + 'credit_points', + 'anmerkung' + ]; + $data = [ + 'updateamum' => date('c'), + 'updatevon' => getAuthUID() + ]; + foreach ($allowed as $field) + if ($this->input->post($field) !== null) + $data[$field] = $this->input->post($field); + + $result = $this->KontoModel->update($id, $data); + + $this->getDataOrTerminateWithError($result); + + $result = null; + // TODO(chris): get as tree? + /*$result = $this->KontoModel->withAdditionalInfo()->load($id); + + #$result = $this->getDataOrTerminateWithError($result); + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $result = $result->retval;*/ + + $this->terminateWithSuccess($result); + } + + /** + * Delete Buchung + * + * @return void + */ + public function delete() + { + $this->load->library('form_validation'); + + $this->form_validation->set_rules('buchungsnr', 'Buchungsnr', 'required'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + $buchungsnr = $this->input->post('buchungsnr'); + + $result = $this->KontoModel->load($buchungsnr); + + $result = $this->getDataOrTerminateWithError($result); + + if (!$result) + $this->terminateWithError($this->p->t('konto', 'error_missing', [ + 'buchungsnr' => $buchungsnr + ])); + + $_POST['studiengang_kz'] = current($result)->studiengang_kz; + + $this->form_validation->set_rules('studiengang_kz', 'Studiengang', 'has_permissions_for_stg[admin:rw,assistenz:rw]'); + + Events::trigger('konto_delete_validation', $this->form_validation); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + Events::trigger('konto_delete', $buchungsnr); + + $result = $this->KontoModel->delete($buchungsnr); + if (isError($result)) { + if (getCode($result) != 42) + $this->terminateWithError(getError($result)); + $this->terminateWithError($this->p->t('konto', 'error_delete_level')); + } + + $this->terminateWithSuccess(); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Lists.php b/application/controllers/api/frontend/v1/stv/Lists.php new file mode 100644 index 000000000..1c0c25db7 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Lists.php @@ -0,0 +1,147 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * Provides data to the ajax get calls about generally used lists + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Lists extends FHCAPI_Controller +{ + public function __construct() + { + parent::__construct([ + 'getStudiensemester' => self::PERM_LOGGED, + 'getStgs' => self::PERM_LOGGED, + 'getSprachen' => self::PERM_LOGGED, + 'getGeschlechter' => self::PERM_LOGGED, + 'getAusbildungen' => self::PERM_LOGGED, + 'getOrgforms' => self::PERM_LOGGED, + 'getStati' => self::PERM_LOGGED + ]); + } + + public function getStudiensemester() + { + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $this->StudiensemesterModel->addOrder('ende'); + + $result = $this->StudiensemesterModel->load(); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getStgs() + { + $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); + + $this->StudiengangModel->addSelect('*'); + $this->StudiengangModel->addSelect('UPPER(typ || kurzbz) AS kuerzel'); + + $this->StudiengangModel->addOrder('typ'); + $this->StudiengangModel->addOrder('kurzbz'); + + $result = $this->StudiengangModel->load(); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getSprachen() + { + $this->load->model('system/Sprache_model', 'SpracheModel'); + + $this->SpracheModel->addOrder('sprache'); + + $result = $this->SpracheModel->load(); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getGeschlechter() + { + $this->load->model('person/Geschlecht_model', 'GeschlechtModel'); + + $this->GeschlechtModel->addOrder('sort'); + $this->GeschlechtModel->addOrder('geschlecht'); + + $this->GeschlechtModel->addSelect('*'); + #$this->GeschlechtModel->addTranslatedSelect("bezeichnung_mehrsprachig", "bezeichnung"); + $this->GeschlechtModel->addSelect("bezeichnung_mehrsprachig[(SELECT index FROM public.tbl_sprache WHERE sprache=" . $this->GeschlechtModel->escape(DEFAULT_LANGUAGE) . " LIMIT 1)] AS bezeichnung"); + + $result = $this->GeschlechtModel->load(); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getAusbildungen() + { + $this->load->model('codex/Ausbildung_model', 'AusbildungModel'); + + $this->AusbildungModel->addOrder('ausbildungcode'); + + $result = $this->AusbildungModel->load(); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getOrgforms() + { + $this->load->model('codex/Orgform_model', 'OrgformModel'); + + $this->OrgformModel->addOrder('bezeichnung'); + + $result = $this->OrgformModel->loadWhere(['rolle' => true]); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getStati() + { + $lang = getUserLanguage(); + $this->load->model('crm/Status_model', 'StatusModel'); + + $this->StatusModel->addSelect('*'); + #$this->StatusModel->addTranslatedSelect('bezeichnung_mehrsprachig', 'bezeichnung'); + $this->StatusModel->addSelect( + 'bezeichnung_mehrsprachig[( + SELECT index + FROM public.tbl_sprache + WHERE sprache=' . $this->StatusModel->escape($lang) . ' + LIMIT 1 + )] AS bezeichnung', + false + ); + #$this->StatusModel->addOrder('ext_id'); + + $result = $this->StatusModel->load(); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Notiz.php b/application/controllers/api/frontend/v1/stv/Notiz.php new file mode 100644 index 000000000..19e568f33 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Notiz.php @@ -0,0 +1,384 @@ + ['admin:r', 'assistenz:r'], + 'getNotizen' => ['admin:r', 'assistenz:r'], + 'loadNotiz' => ['admin:r', 'assistenz:r'], // TODO(manu): self::PERM_LOGGED + 'addNewNotiz' => ['admin:rw', 'assistenz:rw'], // TODO(manu): self::PERM_LOGGED + 'updateNotiz' => ['admin:rw', 'assistenz:rw'], // TODO(manu): self::PERM_LOGGED + 'deleteNotiz' => ['admin:r', 'assistenz:r'], + 'loadDokumente' => ['admin:r', 'assistenz:r'], + 'getMitarbeiter' => ['admin:r', 'assistenz:r'] + ]); + + //Load Models + $this->load->model('person/Notiz_model', 'NotizModel'); + $this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel'); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + + // Load language phrases + $this->loadPhrases([ + 'ui' + ]); + } + +/* public function getUid() + { + $this->terminateWithSuccess(getAuthUID()); + }*/ + + + public function getNotizen($id, $type) + { + + //check if valid type + $result = $this->NotizzuordnungModel->isValidType($type); + if(isError($result)) + $this->terminateWithError($result->retval, self::ERROR_TYPE_GENERAL); + + //$this->terminateWithError(" after check type not valid", self::ERROR_TYPE_GENERAL); + $result = $this->NotizModel->getNotizWithDocEntries($id, $type); + + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result) ?: []); + + // return $this->terminateWithError("type not valid", self::ERROR_TYPE_GENERAL); + + } + +/* public function loadNotiz() + { + $_POST = json_decode(utf8_encode($this->input->raw_input_stream), true); + + $notiz_id = $this->input->post('notiz_id'); + + //$this->load->model('person/Notiz_model', 'NotizModel'); + $this->NotizModel->addJoin('public.tbl_notiz_dokument', 'notiz_id', 'LEFT'); + $this->NotizModel->addSelect('*'); + $this->NotizModel->addSelect("TO_CHAR(CASE WHEN public.tbl_notiz.updateamum >= public.tbl_notiz.insertamum + THEN public.tbl_notiz.updateamum ELSE public.tbl_notiz.insertamum END::timestamp, 'DD.MM.YYYY HH24:MI:SS') AS lastUpdate"); + $this->NotizModel->addLimit(1); + + $result = $this->NotizModel->loadWhere( + array('notiz_id' => $notiz_id) + ); + if (isError($result)) + { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + elseif (!hasData($result)) + { + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=>'Notiz_id']), self::ERROR_TYPE_GENERAL); + } + else + { + $this->terminateWithSuccess(current(getData($result))); + } + } + + + public function updateNotiz() + { + $this->load->library('form_validation'); + $this->load->library('DmsLib'); + + if (isset($_POST['data'])) + { + $data = json_decode($_POST['data']); + unset($_POST['data']); + foreach ($data as $k => $v) { + $_POST[$k] = $v; + } + } + + $notiz_id = $this->input->post('notiz_id'); + + if(!$notiz_id) + { + $this->terminateWithError($this->p->t('ui','error_missingId',['id'=>'Notiz_id']), self::ERROR_TYPE_GENERAL); + } + + //Form Validation + $this->form_validation->set_rules('titel', 'Titel', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Titel']) + ]); + + $this->form_validation->set_rules('text', 'Text', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Text']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + //update Notiz + $uid = getAuthUID(); + $titel = $this->input->post('titel'); + $text = $this->input->post('text'); + $verfasser_uid = $this->input->post('verfasser'); + $bearbeiter_uid = isset($_POST['bearbeiter']) ? $_POST['bearbeiter'] : $uid; + $erledigt = $this->input->post('erledigt'); + $start = $this->input->post('start'); + $ende = $this->input->post('ende'); + + $result = $this->NotizModel->update( + [ + 'notiz_id' => $notiz_id + ], + [ + 'titel' => $titel, + 'updatevon' => $uid, + 'updateamum' => date('c'), + 'text' => $text, + 'verfasser_uid' => $verfasser_uid, + 'bearbeiter_uid' => $bearbeiter_uid, + 'start' => $start, + 'ende' => $ende, + 'erledigt' => $erledigt + ] + ); + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + //update(1) laden aller bereits mit dieser notiz_id verknüpften DMS-Einträge + $this->load->model('person/Notizdokument_model', 'NotizdokumentModel'); + $this->NotizdokumentModel->addJoin('campus.tbl_dms_version', 'dms_id'); + $dms_uploaded = null; + + $result = $this->NotizdokumentModel->loadWhere(array('notiz_id' => $notiz_id)); + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + elseif (!hasData($result)) + { + $dms_id_arr = null; + } + else + { + $result = getData($result); + foreach($result as $doc) { + $dms_id_arr[] = array( + 'name' => $doc->name, + 'dms_id' => $doc->dms_id + ); + } + } + + foreach ($_FILES as $k => $file) + { + //update(2) alle neuen files (alle außer type application/x.fhc-dms+json) anhängen + if($file["type"] == 'application/x.fhc-dms+json') + { + $dms_uploaded[] = array( + 'name' => $file["name"] + ); + } + else + { + $dms = array( + 'kategorie_kurzbz' => 'notiz', + 'version' => 0, + 'name' => $file["name"], + 'mimetype' => $file["type"], + 'insertamum' => date('c'), + 'insertvon' => $uid + ); + + //Todo(manu) check if filetypes weiter eingeschränkt werden sollen + //Todo(manu)check name files: nicht gleiches file 2mal hochladen + $result = $this->dmslib->upload($dms, $k, array('*')); + + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $dms_id = $result->retval['dms_id']; + + $result = $this->NotizdokumentModel->insert(array('notiz_id' => $notiz_id, 'dms_id' => $dms_id)); + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + } + } + + //update(3) check if Dateien gelöscht wurden + if(count($dms_uploaded) != count($dms_id_arr)) + { + if (count($dms_uploaded) == 0) + { + $filesDeleted = $dms_id_arr; + } + else + { + $upload_new_names = array_column($dms_uploaded, "name"); + + $filesDeleted = array_filter($dms_id_arr, function ($file) use ($upload_new_names) { + return !in_array($file["name"], $upload_new_names); + }); + } + + foreach ($filesDeleted as $file) + { + $result = $this->dmslib->removeAll($file['dms_id']); + + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + else + $this->outputJson($result); + } + } + return $this->terminateWithSuccess($result); + }*/ + + +/* public function deleteNotiz() + { + $_POST = json_decode(utf8_encode($this->input->raw_input_stream), true); + $notiz_id = $this->input->post('notiz_id'); + $type = $this->input->post('type_id'); + $id = $this->input->post('id'); + + //dms_id auslesen aus notizdokument wenn vorhanden + $dms_id_arr = []; + $this->load->model('person/Notizdokument_model', 'NotizdokumentModel'); + + $result = $this->NotizdokumentModel->loadWhere(array('notiz_id' => $notiz_id)); + + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + if(hasData($result)) + { + $result = getData($result); + foreach ($result as $doc) { + $dms_id_arr[] = $doc->dms_id; + } + } + + if($dms_id_arr) + { + $this->load->library('DmsLib'); + foreach($dms_id_arr as $dms_id) + { + $result = $this->dmslib->removeAll($dms_id); + + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + $this->outputJson($result); + } + } + + //delete Notizzuordnung + if($type == "software_id") + { + // Loads extension Model + $this->load->model('extensions/FHC-Core-Softwarebereitstellung/Softwarenotizzuordnung_model', 'ExtensionnotizzuordnungModel'); + $result = $this->ExtensionnotizzuordnungModel->delete([ + 'notiz_id' => $notiz_id, + 'id' => strval($id) + ], + [ + 'type_id' => $type + ]); + + } + else + { + //notizzuordnungsid! + $result = $this->NotizzuordnungModel->delete(['notiz_id' => $notiz_id, $type => $id]); + } + + + $this->load->model('person/Notiz_model', 'NotizModel'); + //$this->NotizModel->addJoin('public.tbl_notizzuordnung', 'notiz_id'); + + //TODO (erweitern um Type_id) für Extensions, damit auch Notizzuordnung gelöscht werden kann + + //Löschen von Notiz + $result = $this->NotizModel->delete( + array('notiz_id' => $notiz_id) + ); + + if (isError($result)) + { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + if(!hasData($result)) + { + return $this->terminateWithError($this->p->t('ui','error_missingId', ['id'=> 'Notiz_id']), self::ERROR_TYPE_GENERAL); + } + + return $this->terminateWithSuccess(current(getData($result))); + }*/ + +/* public function loadDokumente() + { + $_POST = json_decode(utf8_encode($this->input->raw_input_stream), true); + $notiz_id = $this->input->post('notiz_id'); + + $this->NotizModel->addSelect('campus.tbl_dms_version.*'); + + $this->NotizModel->addJoin('public.tbl_notiz_dokument', 'ON (public.tbl_notiz_dokument.notiz_id = public.tbl_notiz.notiz_id)'); + $this->NotizModel->addJoin('campus.tbl_dms_version', 'ON (public.tbl_notiz_dokument.dms_id = campus.tbl_dms_version.dms_id)'); + + $result = $this->NotizModel->loadWhere( + array('public.tbl_notiz.notiz_id' => $notiz_id) + ); + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + if(!hasData($result)) + { + return $this->terminateWithError($this->p->t('ui','error_missingId', ['id'=> 'Notiz_id']), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result)); + }*/ + +/* public function getMitarbeiter($searchString) + { + $this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); + $result = $this->MitarbeiterModel->searchMitarbeiter($searchString); + if (isError($result)) { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess($result); + }*/ + + public function isBerechtigt($id, $typeId) + { + if(!$this->permissionlib->isBerechtigt('admin', 'suid') && !$this->permissionlib->isBerechtigt('assistenz', 'suid')) + { + $result = $this->p->t('lehre','error_keineSchreibrechte'); + + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + return success("berechtigt in überschreibender Funktion"); +/* return $this->terminateWithError('keine Berechtigung bro', self::ERROR_TYPE_GENERAL);*/ + } + +} \ No newline at end of file diff --git a/application/controllers/api/frontend/v1/stv/Prestudent.php b/application/controllers/api/frontend/v1/stv/Prestudent.php new file mode 100644 index 000000000..ef9aeb111 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Prestudent.php @@ -0,0 +1,299 @@ + ['admin:r', 'assistenz:r'], + 'updatePrestudent' => ['admin:rw', 'assistenz:rw'], + 'getHistoryPrestudents' => ['admin:r', 'assistenz:r'], + 'getBezeichnungZGV' => ['admin:r', 'assistenz:r'], + 'getBezeichnungDZgv' => ['admin:r', 'assistenz:r'], + 'getBezeichnungMZgv' => ['admin:r', 'assistenz:r'], + 'getAusbildung' => ['admin:r', 'assistenz:r'], + 'getAufmerksamdurch' => ['admin:r', 'assistenz:r'], + 'getBerufstaetigkeit' => ['admin:r', 'assistenz:r'], + 'getTypenStg' => ['admin:r', 'assistenz:r'], + 'getStudienplaene' => ['admin:r', 'assistenz:r'], + 'getStudiengang' => ['admin:r', 'assistenz:r'] + ]); + + if ($this->router->method == 'updatePrestudent') { + $prestudent_id = current(array_slice($this->uri->rsegments, 2)); + $this->checkPermissionsForPrestudent($prestudent_id, ['admin:rw', 'assistenz:rw']); + } elseif ($this->router->method == 'get' + || $this->router->method == 'getStudienplaene' + || $this->router->method == 'getStudiengang' + ) { + $prestudent_id = current(array_slice($this->uri->rsegments, 2)); + $this->checkPermissionsForPrestudent($prestudent_id, ['admin:r', 'assistenz:r']); + } elseif ($this->router->method == 'getHistoryPrestudents') { + $person_id = current(array_slice($this->uri->rsegments, 2)); + $this->checkPermissionsForPerson($person_id, ['admin:r', 'assistenz:r'], ['admin:r', 'assistenz:r']); + } + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + + // Load language phrases + $this->loadPhrases([ + 'ui', 'studierendenantrag', 'lehre' + ]); + } + + public function get($prestudent_id) + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + $this->PrestudentModel->addSelect('*'); + $result = $this->PrestudentModel->loadWhere(['prestudent_id' => $prestudent_id]); + + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + if(!hasData($result)) + { + return show_404(); + } + $this->terminateWithSuccess(current(getData($result))); + } + + public function updatePrestudent($prestudent_id) + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + // UDF + $this->load->library('UDFLib'); + + $result = $this->udflib->getCiValidations($this->PrestudentModel, $this->input->post()); + $udf_field_validations = $this->getDataOrTerminateWithError($result); + + //Form validation + $this->load->library('form_validation'); + + $this->form_validation->set_rules($udf_field_validations); + + $this->form_validation->set_rules('priorisierung', 'Priorisierung', 'numeric', [ + 'numeric' => $this->p->t('ui', 'error_fieldNotNumeric', ['field' => 'Priorisierung']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $uid = getAuthUID(); + + $array_allowed_props_prestudent = [ + 'aufmerksamdurch_kurzbz', + 'studiengang_kz', + 'gsstudientyp_kurzbz', + 'person_id', + 'berufstaetigkeit_code', + 'ausbildungcode', + 'zgv_code', + 'zgvort', + 'zgvdatum', + 'zgvnation', + 'zgvmas_code', + 'zgvmaort', + 'zgvmadatum', + 'zgvmanation', + 'facheinschlberuf', + 'bismelden', + 'anmerkung', + 'dual', + 'zgvdoktor_code', + 'zgvdoktorort', + 'zgvdoktordatum', + 'zgvdoktornation', + 'aufnahmegruppe_kurzbz', + 'priorisierung', + 'foerderrelevant', + 'zgv_erfuellt', + 'zgvmas_erfuellt', + 'zgvdoktor_erfuellt', + 'mentor', + 'aufnahmeschluessel', + 'standort_code' + ]; + + // add UDFs + $result = $this->udflib->getDefinitionForModel($this->PrestudentModel); + + $definitions = $this->getDataOrTerminateWithError($result); + + foreach ($definitions as $def) + $array_allowed_props_prestudent[] = $def['name']; + + $update_prestudent = array(); + foreach ($array_allowed_props_prestudent as $prop) + { + $val = $this->input->post($prop); + if ($val !== null || $prop == 'foerderrelevant') { + $update_prestudent[$prop] = $val; + } + } + + $update_prestudent['updateamum'] = date('c'); + $update_prestudent['updatevon'] = $uid; + + if (count($update_prestudent)) + { + $result = $this->PrestudentModel->update( + $prestudent_id, + $update_prestudent + ); + $this->getDataOrTerminateWithError($result); + + return $this->terminateWithSuccess(true); + } + return $this->terminateWithSuccess(false); + } + + public function getHistoryPrestudents($person_id) + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + $result = $this->PrestudentModel->getHistoryPrestudents($person_id); + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $this->terminateWithSuccess(getData($result) ?: []); + } + + public function getBezeichnungZGV() + { + $this->load->model('codex/Zgv_model', 'ZgvModel'); + + $this->ZgvModel->addOrder('zgv_code'); + + $result = $this->ZgvModel->load(); + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result) ?: []); + } + + public function getBezeichnungDZgv() + { + $this->load->model('codex/Zgvdoktor_model', 'ZgvdoktorModel'); + + $this->ZgvdoktorModel->addOrder('zgvdoktor_code'); + + $result = $this->ZgvdoktorModel->load(); + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result) ?: []); + } + + public function getBezeichnungMZgv() + { + $this->load->model('codex/Zgvmaster_model', 'ZgvmasterModel'); + + $this->ZgvmasterModel->addOrder('zgvmas_code'); + + $result = $this->ZgvmasterModel->load(); + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result) ?: []); + } + + public function getAusbildung() + { + $this->load->model('codex/Ausbildung_model', 'AusbildungModel'); + + $this->AusbildungModel->addOrder('ausbildungcode'); + + $result = $this->AusbildungModel->load(); + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result) ?: []); + } + + public function getAufmerksamdurch() + { + $this->load->model('codex/Aufmerksamdurch_model', 'AufmerksamdurchModel'); + + $this->AufmerksamdurchModel->addOrder('aufmerksamdurch_kurzbz'); + + $result = $this->AufmerksamdurchModel->load(); + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result) ?: []); + } + + public function getBerufstaetigkeit() + { + $this->load->model('codex/Berufstaetigkeit_model', 'BerufstaetigkeitModel'); + + $this->BerufstaetigkeitModel->addOrder('berufstaetigkeit_code'); + + $result = $this->BerufstaetigkeitModel->load(); + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result) ?: []); + } + + public function getTypenStg() + { + $this->load->model('education/Gsstudientyp_model', 'GsstudientypModel'); + + $this->GsstudientypModel->addOrder('gsstudientyp_kurzbz'); + + $result = $this->GsstudientypModel->load(); + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result) ?: []); + } + + public function getStudienplaene($prestudent_id) + { + $this->load->model('organisation/Studienplan_model', 'StudienplanModel'); + $result = $this->StudienplanModel->getStudienplaeneByPrestudents($prestudent_id); + + $data = $this->getDataOrTerminateWithError($result); + + return $this->terminateWithSuccess($data); + } + + /** + * Gets details for the Studiengang of the Prestudent + * + * @param integer $prestudent_id + * + * @return stdClass + */ + public function getStudiengang($prestudent_id) + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + $this->PrestudentModel->addSelect('stg.*'); + + $this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz'); + + $result = $this->PrestudentModel->load($prestudent_id); + + $stg = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(current($stg)); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Status.php b/application/controllers/api/frontend/v1/stv/Status.php new file mode 100644 index 000000000..074f4029e --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Status.php @@ -0,0 +1,1753 @@ + ['admin:r', 'assistenz:r'], + 'getMaxSemester' => ['admin:r', 'assistenz:r'], + 'changeStatus' => ['admin:rw', 'assistenz:rw'], + 'addStudent' => ['admin:rw', 'assistenz:rw'], + 'getStatusgruende' => self::PERM_LOGGED, + 'getLastBismeldestichtag' => self::PERM_LOGGED, + 'isLastStatus' => self::PERM_LOGGED, + 'getStatusarray' => self::PERM_LOGGED, + 'deleteStatus' => ['admin:rw','assistenz:rw'], + 'loadStatus' => ['admin:r', 'assistenz:r'], + 'insertStatus' => ['admin:rw', 'assistenz:rw'], + 'updateStatus' => ['admin:rw', 'assistenz:rw'], + 'advanceStatus' => ['admin:rw', 'assistenz:rw'], + 'confirmStatus' => ['admin:rw', 'assistenz:rw'], + + ]); + + //Load Models + $this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); + $this->load->model('person/Person_model', 'PersonModel'); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $this->load->library('PrestudentstatusCheckLib'); + + // Additional Permission Checks + if ($this->router->method == 'insertStatus' + || $this->router->method == 'updateStatus' + || $this->router->method == 'confirmStatus' + || $this->router->method == 'deleteStatus' + || $this->router->method == 'advanceStatus' + || $this->router->method == 'changeStatus' + || $this->router->method == 'addStudent' + ) { + $prestudent_id = current(array_slice($this->uri->rsegments, 2)); + $this->checkPermissionsForPrestudent($prestudent_id, ['admin:rw', 'assistenz:rw']); + } + + // Load language phrases + $this->loadPhrases([ + 'global', 'ui', 'bismeldestichtag','lehre','studierendenantrag' + ]); + } + + public function getHistoryPrestudent($prestudent_id) + { + $result = $this->PrestudentstatusModel->getHistoryPrestudent($prestudent_id); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + /** + * Gets the maximum possible semester for one or more Studiengaenge. + * If there are more than one Studiengang each maximum is calculated and + * the smallest result is returned. + * + * @return void + */ + public function getMaxSemester() + { + $studiengang_kzs = $this->input->post('studiengang_kzs'); + + if (!$studiengang_kzs || !is_array($studiengang_kzs)) { + $this->load->library('form_validation'); + + $this->form_validation->set_rules('studiengang_kzs', '', 'required|is_null', [ + 'is_null' => $this->p->t('ui', 'error_fieldMustBeArray') + ]); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + + if (defined('VORRUECKUNG_STATUS_MAX_SEMESTER') && VORRUECKUNG_STATUS_MAX_SEMESTER == false) + $this->terminateWithSuccess(100); + + $this->load->model('organisation/Lehrverband_model', 'LehrverbandModel'); + + $result = $this->LehrverbandModel->getMaxSemester($studiengang_kzs); + + $maxsem = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($maxsem ? current($maxsem)->maxsem : 10); + } + + public function getStatusgruende() + { + $this->load->model('crm/Statusgrund_model', 'StatusgrundModel'); + + $result = $this->StatusgrundModel->getAktiveGruende(); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function getLastBismeldestichtag() + { + $this->load->model('codex/Bismeldestichtag_model', 'BismeldestichtagModel'); + + $result = $this->BismeldestichtagModel->getLastReachedMeldestichtag(); + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function isLastStatus($prestudent_id) + { + $result = $this->PrestudentstatusModel->checkIfLastStatusEntry($prestudent_id); + + $result = $this->getDataOrTerminateWithError($result); + + return $this->terminateWithSuccess($result); + } + + public function getStudiensemesterOfStatus($prestudent_id, $status) + { + $result = $this->PrestudentstatusModel->loadWhere([ + "prestudent_id" => $prestudent_id, + "status_kurzbz" => $status + ]); + $this->PrestudentstatusModel->addLimit(1); + if (isError($result)) + { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + $studiensem = current(getData($result)); + + return $studiensem->studiensemester_kurzbz; + } + + public function getStatusarray() + { + $this->load->model('crm/Status_model', 'StatusModel'); + $result = $this->StatusModel->getAllStatiWithStatusgruende(); + + if(isError($result)) + { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + /** + * Changes the status of a prestudent with full additional logic. + * + * @param integer $prestudent_id + * + * @return stdClass + */ + public function changeStatus($prestudent_id) + { + $isBerechtigtNoStudstatusCheck = $this->permissionlib->isBerechtigt('student/keine_studstatuspruefung'); + + //GET lastStatus + $result = $this->PrestudentstatusModel->getLastStatus($prestudent_id); + + $lastStatusData = $this->getDataOrTerminateWithError($result); + $lastStatusData = current($lastStatusData); + + $this->load->model('person/Person_model', 'PersonModel'); + $this->PersonModel->addJoin('public.tbl_prestudent', 'person_id'); + $result = $this->PersonModel->loadWhere(['prestudent_id' => $prestudent_id]); + $prestudent_person = $this->getDataOrTerminateWithError($result); + $prestudent_person = current($prestudent_person); + + $studentName = trim($prestudent_person->vorname . ' ' . $prestudent_person->nachname); + + $status_kurzbz = $this->input->post('status_kurzbz'); + + $studiensemester_kurzbz = $lastStatusData->studiensemester_kurzbz; + if ($status_kurzbz == Prestudentstatus_model::STATUS_ABSOLVENT + || $status_kurzbz == Prestudentstatus_model::STATUS_DIPLOMAND + ) { + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + $studiensemester_kurzbz = $this->variablelib->getVar('semester_aktuell'); + } + + $ausbildungssemester = $lastStatusData->ausbildungssemester; + if ($status_kurzbz == Prestudentstatus_model::STATUS_STUDENT) { + $ausbildungssemester = $this->input->post('ausbildungssemester'); + } + + $statusgrund_id = $this->input->post('statusgrund_id'); + $datum_string = date('c'); + $datum = new DateTime($datum_string); + + //Form Validation + $this->load->library('form_validation'); + + $this->form_validation->set_rules( + 'status_kurzbz', + $this->p->t('global', 'status'), + [ + 'required', + //Check Reihungstest + ['reihungstest_check', function ($value) use ($prestudent_person) { + if (!REIHUNGSTEST_CHECK) + return true; + if ($value != Prestudentstatus_model::STATUS_BEWERBER) + return true; + $result = $this->prestudentstatuschecklib->checkIfAngetreten($prestudent_person); + return $this->getDataOrTerminateWithError($result); + }], + //Check ZGV + ['checkIfZGV', function ($value) use ($prestudent_person) { + if (defined("ZGV_CHECK") && !ZGV_CHECK) + return true; + if ($value != Prestudentstatus_model::STATUS_BEWERBER) + return true; + $result = $this->prestudentstatuschecklib->checkIfZGVEingetragen($prestudent_person); + return $this->getDataOrTerminateWithError($result); + }], + //Check ZGV Master + ['checkIfZGVMaster', function ($value) use ($prestudent_person) { + if (defined("ZGV_CHECK") && !ZGV_CHECK) + return true; + if ($value != Prestudentstatus_model::STATUS_BEWERBER) + return true; + $result = $this->prestudentstatuschecklib->checkIfZGVEingetragenMaster($prestudent_person); + return $this->getDataOrTerminateWithError($result); + }], + //Check Bewerberstatus + ['checkIfExistingBewerberstatus', function ($value) use ($prestudent_id) { + if ($value != Prestudentstatus_model::STATUS_AUFGENOMMENER + && $value != Prestudentstatus_model::STATUS_WARTENDER + ) + return true; + $result = $this->prestudentstatuschecklib->checkIfExistingBewerberstatus($prestudent_id); + return $this->getDataOrTerminateWithError($result); + }], + //Check If Student + ['status_stud_exists', function ($value) use ($prestudent_id) { + if ($value != Prestudentstatus_model::STATUS_STUDENT + && $value != Prestudentstatus_model::STATUS_ABBRECHER + ) + return true; // Only test if new status is Student + + $result = $this->prestudentstatuschecklib->checkIfExistingStudent($prestudent_id); + + return $this->getDataOrTerminateWithError($result); + }], + ], + [ + 'reihungstest_check' => $this->p->t('lehre', 'error_keinReihungstestverfahren', ['name' => $studentName]), + 'checkIfExistingBewerberstatus' => $this->p->t('lehre', 'error_keinBewerber', ['name' => $studentName]), + 'checkIfZGV' => $this->p->t('lehre', 'error_ZGVNichtEingetragen', ['name' => $studentName]), + 'checkIfZGVMaster' => $this->p->t('lehre', 'error_ZGVMasterNichtEingetragen', ['name' => $studentName]), + 'status_stud_exists' => $this->p->t('lehre', 'error_noStudstatus') + ] + ); + + if ($status_kurzbz == Prestudentstatus_model::STATUS_STUDENT) + $this->form_validation->set_rules('ausbildungssemester', $this->p->t('lehre', 'ausbildungssemester'), 'required|integer', [ + 'integer' => $this->p->t('ui', 'error_fieldNotInteger') + ]); + else + $this->form_validation->set_rules('ausbildungssemester', $this->p->t('lehre', 'ausbildungssemester'), 'integer', [ + 'integer' => $this->p->t('ui', 'error_fieldNotInteger') + ]); + + $this->form_validation->set_rules('statusgrund_id', $this->p->t('international', 'grund'), 'integer', [ + 'integer' => $this->p->t('ui', 'error_fieldNotInteger') + ]); + + $this->form_validation->set_rules('_default', '', [ + ['meldestichtag_not_exceeded', function () use ($datum, $isBerechtigtNoStudstatusCheck) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + + $result = $this->prestudentstatuschecklib->checkIfMeldestichtagErreicht($datum); + + return !$this->getDataOrTerminateWithError($result); + }], + //Check if Rolle already exists + ['rolle_doesnt_exist', function () use ($prestudent_id, $status_kurzbz, $studiensemester_kurzbz, $ausbildungssemester) { + if (!$status_kurzbz || !$studiensemester_kurzbz || !$ausbildungssemester) + return true; // Error will be handled by the required statements above + + $result = $this->PrestudentstatusModel->load([$ausbildungssemester, $studiensemester_kurzbz, $status_kurzbz, $prestudent_id]); + + return !$this->getDataOrTerminateWithError($result); + }], + ['history_timesequence', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$status_kurzbz) + return true; // Error will be handled by the required statement above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryTimesequence( + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester, + '', + '' + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_laststatus', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$status_kurzbz) + return true; // Error will be handled by the required statement above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryLaststatus( + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester, + '', + '' + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_unterbrecher', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$status_kurzbz) + return true; // Error will be handled by the required statement above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryUnterbrechersemester( + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester, + '', + '' + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_abbrecher', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$status_kurzbz) + return true; // Error will be handled by the required statement above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryAbbrechersemester( + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester, + '', + '' + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_diplomant', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$status_kurzbz) + return true; // Error will be handled by the required statement above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryDiplomant( + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester, + '', + '' + ); + + return $this->getDataOrTerminateWithError($result); + }] + ], [ + 'meldestichtag_not_exceeded' => $this->p->t('lehre', 'error_dataVorMeldestichtag'), + 'rolle_doesnt_exist' => $this->p->t('lehre', 'error_rolleBereitsVorhandenMitNamen', ['name' => $studentName]), + 'history_timesequence' => $this->p->t('lehre', 'error_statuseintrag_zeitabfolge'), + 'history_laststatus' => $this->p->t('lehre', 'error_endstatus'), + 'history_unterbrecher' => $this->p->t('lehre', 'error_consecutiveUnterbrecher'), + 'history_abbrecher' => $this->p->t('lehre', 'error_consecutiveUnterbrecherAbbrecher'), + 'history_diplomant' => $this->p->t('lehre', 'error_consecutiveDiplomandStudent') + ]); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + $this->load->library('PrestudentLib'); + + $this->db->trans_start(); + + switch($status_kurzbz){ + case Prestudentstatus_model::STATUS_ABBRECHER: + $result = $this->prestudentlib->setAbbrecher( + $prestudent_id, + $studiensemester_kurzbz, + null, + $statusgrund_id, + $datum_string, + null, + null + ); + break; + case Prestudentstatus_model::STATUS_UNTERBRECHER: + $result = $this->prestudentlib->setUnterbrecher( + $prestudent_id, + $studiensemester_kurzbz, + null, + null, + $ausbildungssemester, + $statusgrund_id + ); + break; + case Prestudentstatus_model::STATUS_STUDENT: + $result = $this->prestudentlib->setStudent( + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + break; + case Prestudentstatus_model::STATUS_DIPLOMAND: + $result = $this->prestudentlib->setDiplomand( + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + break; + case Prestudentstatus_model::STATUS_ABSOLVENT: + $result = $this->prestudentlib->setAbsolvent( + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + break; + case Prestudentstatus_model::STATUS_BEWERBER: + $result = $this->prestudentlib->setBewerber( + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + break; + case Prestudentstatus_model::STATUS_AUFGENOMMENER: + $result = $this->prestudentlib->setAufgenommener( + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + break; + case Prestudentstatus_model::STATUS_ABGEWIESENER: + $result = $this->prestudentlib->setAbgewiesener( + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + break; + case Prestudentstatus_model::STATUS_WARTENDER: + $result = $this->prestudentlib->setWartender( + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + break; + default: + $this->terminateWithError("Action not yet defined in Prestudentlib", self::ERROR_TYPE_GENERAL); + } + + $this->getDataOrTerminateWithError($result); + + $this->db->trans_complete(); + + $this->terminateWithSuccess($prestudent_id); + } + + public function addStudent($prestudent_id) + { + // Prepare lastAufgenommener Status + $this->PrestudentstatusModel->addOrder('datum', 'DESC'); + $this->PrestudentstatusModel->addOrder('insertamum', 'DESC'); + $this->PrestudentstatusModel->addLimit(1); + $result = $this->PrestudentstatusModel->loadWhere([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => Prestudentstatus_model::STATUS_AUFGENOMMENER + ]); + $lastAufgenommener = $this->getDataOrTerminateWithError($result); + + if ($lastAufgenommener) + $lastAufgenommener = current($lastAufgenommener); + + //get studentname for validations + $this->load->model('person/Person_model', 'PersonModel'); + $this->PersonModel->addJoin('public.tbl_prestudent', 'person_id'); + $result = $this->PersonModel->loadWhere(['prestudent_id' => $prestudent_id]); + $prestudent_person = $this->getDataOrTerminateWithError($result); + $prestudent_person = current($prestudent_person); + + $studentName = trim($prestudent_person->vorname . ' ' . $prestudent_person->nachname); + + + //Form Validation + $this->load->library('form_validation'); + + $this->form_validation->set_rules('statusgrund_id', $this->p->t('international', 'grund'), 'integer', [ + 'integer' => $this->p->t('ui', 'error_fieldNotInteger') + ]); + + $this->form_validation->set_rules('_default', '', [ + //Check ZGV + ['checkIfZGV', function () use ($prestudent_person) { + if (defined("ZGV_CHECK") && !ZGV_CHECK) + return true; + $result = $this->prestudentstatuschecklib->checkIfZGVEingetragen($prestudent_person); + return $this->getDataOrTerminateWithError($result); + }], + //Check ZGV Master + ['checkIfZGVMaster', function () use ($prestudent_person) { + if (defined("ZGV_CHECK") && !ZGV_CHECK) + return true; + $result = $this->prestudentstatuschecklib->checkIfZGVEingetragenMaster($prestudent_person); + return $this->getDataOrTerminateWithError($result); + }], + //Check Bewerberstatus + ['checkIfExistingBewerberstatus', function () use ($prestudent_id) { + $result = $this->prestudentstatuschecklib->checkIfExistingBewerberstatus($prestudent_id); + return $this->getDataOrTerminateWithError($result); + }], + //Check Aufgenommenerstatus + ['checkIfExistingAufgenommenerstatus', function () use ($lastAufgenommener) { + return !!$lastAufgenommener; + }], + //Check Bewerberstatus & Aufgenommenerstatus semester + ['checkIfLastBewerberAndAufgenommenerShareSemesters', function () use ($prestudent_id) { + $result = $this->prestudentstatuschecklib->checkIfLastBewerberAndAufgenommenerShareSemesters($prestudent_id); + return $this->getDataOrTerminateWithError($result); + }], + //Check If FirstStudent + ['check_isFirstStudStatus', function () use ($prestudent_id) { + $result = $this->prestudentstatuschecklib->checkIfExistingStudent($prestudent_id); + + return !$this->getDataOrTerminateWithError($result); + }], + //Check if Rolle already exists + ['rolle_doesnt_exist', function () use ($prestudent_id, $lastAufgenommener) { + if (!$lastAufgenommener) + return true; // Error will be handled by the checkIfExistingAufgenommenerstatus statement above + + $result = $this->PrestudentstatusModel->loadWhere([ + 'studiensemester_kurzbz' => $lastAufgenommener->studiensemester_kurzbz, + 'status_kurzbz' => Prestudentstatus_model::STATUS_STUDENT, + 'prestudent_id' => $prestudent_id + ]); + + return !$this->getDataOrTerminateWithError($result); + }] + ], [ + 'reihungstest_check' => $this->p->t('lehre', 'error_keinReihungstestverfahren', ['name' => $studentName]), + 'checkIfExistingBewerberstatus' => $this->p->t('lehre', 'error_keinBewerber', ['name' => $studentName]), + 'checkIfExistingAufgenommenerstatus' => $this->p->t('lehre', 'error_keinAufgenommener', ['name' => $studentName]), + 'checkIfLastBewerberAndAufgenommenerShareSemesters' => $this->p->t('lehre', 'error_lastBewerberAndAufgenommenerSemesters'), + 'checkIfZGV' => $this->p->t('lehre', 'error_ZGVNichtEingetragen', ['name' => $studentName]), + 'checkIfZGVMaster' => $this->p->t('lehre', 'error_ZGVMasterNichtEingetragen', ['name' => $studentName]), + 'check_isFirstStudStatus' => $this->p->t('lehre', 'error_personBereitsStudent', ['name' => $studentName]), + 'rolle_doesnt_exist' => $this->p->t('lehre', 'error_rolleBereitsVorhandenMitNamen', ['name' => $studentName]) + ]); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + // Start DB transaction + $this->db->trans_start(); + + $this->load->library('PrestudentLib'); + + $this->prestudentlib->setFirstStudent( + $prestudent_id, + $lastAufgenommener->studiensemester_kurzbz, + $lastAufgenommener->ausbildungssemester, + $lastAufgenommener->orgform_kurzbz, + $lastAufgenommener->studienplan_id, + $this->input->post('statusgrund_id') + ); + + $this->getDataOrTerminateWithError($result); + + $this->db->trans_commit(); + + return $this->outputJsonSuccess(true); + } + + public function loadStatus() + { + $_POST = json_decode(utf8_encode($this->input->raw_input_stream), true); + + $prestudent_id = $this->input->post('prestudent_id'); + $status_kurzbz = $this->input->post('status_kurzbz'); + $ausbildungssemester = $this->input->post('ausbildungssemester'); + $studiensemester_kurzbz = $this->input->post('studiensemester_kurzbz'); + + $result = $this->PrestudentstatusModel->loadWhere( + array( + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => $status_kurzbz, + 'ausbildungssemester' => $ausbildungssemester, + 'studiensemester_kurzbz' => $studiensemester_kurzbz + ) + ); + if (isError($result)) + { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + elseif (!hasData($result)) + { + $this->terminateWithError($this->p->t('lehre', 'error_noStatusFound'), self::ERROR_TYPE_GENERAL); + } + else + { + $this->terminateWithSuccess(current(getData($result))); + } + } + + /** + * Delete a status entry + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param string $studiensemester_kurzbz + * @param integer $ausbildungssemester + * + * @return void + */ + public function deleteStatus($prestudent_id, $status_kurzbz, $studiensemester_kurzbz, $ausbildungssemester) + { + $result = $this->PrestudentstatusModel->load([ + $ausbildungssemester, + $studiensemester_kurzbz, + $status_kurzbz, + $prestudent_id + ]); + $oldstatus = $this->getDataOrTerminateWithError($result); + if (!$oldstatus) + show_404(); // Status that should be updated does not exist + + $oldstatus = current($oldstatus); + + + $erweiterteBerechtigung = + $this->permissionlib->isBerechtigt('admin', null, 'suid') + || $this->permissionlib->isBerechtigt('student/keine_studstatuspruefung', null, 'suid'); + + + //check if last status + $result = $this->PrestudentstatusModel->checkIfLastStatusEntry($prestudent_id); + + $result = $this->getDataOrTerminateWithError($result); + + $deletePrestudent = $result; + + + //Berechtigungen nach Check prüfen! + if (!$erweiterteBerechtigung) { + if ($status_kurzbz == Prestudentstatus_model::STATUS_STUDENT) + $this->terminateWithError( + $this->p->t('lehre', 'error_onlyAdminDeleteRolleStudent'), + self::ERROR_TYPE_GENERAL, + REST_Controller::HTTP_FORBIDDEN + ); + + if ($deletePrestudent) + $this->terminateWithError( + $this->p->t('lehre', 'error_onlyAdminDeleteLastStatus'), + self::ERROR_TYPE_GENERAL, + REST_Controller::HTTP_FORBIDDEN + ); + + $result = $this->prestudentstatuschecklib->checkIfMeldestichtagErreicht($oldstatus->datum); + + if (!$this->getDataOrTerminateWithError($result)) + $this->terminateWithError( + $this->p->t('lehre', 'error_dataVorMeldestichtag'), + self::ERROR_TYPE_GENERAL, + REST_Controller::HTTP_FORBIDDEN + ); + } + + // Start DB transaction + $this->db->trans_begin(); + + //Delete Status + $result = $this->PrestudentstatusModel->delete( + [ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => $status_kurzbz, + 'ausbildungssemester' => $ausbildungssemester, + 'studiensemester_kurzbz' => $studiensemester_kurzbz + ] + ); + + $this->getDataOrTerminateWithError($result); + + //Delete Studentlehrverband if no Status left in this semester + $result = $this->PrestudentstatusModel->checkIfLastStatusEntry($prestudent_id, $studiensemester_kurzbz); + + $result = $this->getDataOrTerminateWithError($result); + if ($result) + { + //get student_uid + $this->load->model('crm/Student_model', 'StudentModel'); + $result = $this->StudentModel->loadWhere([ + 'prestudent_id' => $prestudent_id + ]); + + $student = $this->getDataOrTerminateWithError($result); + if ($student) + { + $student = current($student); + $this->load->model('education/Studentlehrverband_model', 'StudentlehrverbandModel'); + $result = $this->StudentlehrverbandModel->delete( + array( + 'student_uid' => $student->student_uid, + 'studiensemester_kurzbz' => $studiensemester_kurzbz + ) + ); + + $this->getDataOrTerminateWithError($result); + } + } + + //Delete Prestudent if no data is left + if ($deletePrestudent) + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $result = $this->PrestudentModel->delete($prestudent_id); + + $this->getDataOrTerminateWithError($result); + } + + $this->db->trans_commit(); + + return $this->terminateWithSuccess(true); + } + + /** + * Inserts a status with less validations and extra logic for manual + * manipulation + * + * @param integer $prestudent_id + * + * @return void + */ + public function insertStatus($prestudent_id) + { + $isBerechtigtNoStudstatusCheck = $this->permissionlib->isBerechtigt('student/keine_studstatuspruefung'); + $isBerechtigtBasisPrestudentstatus = $this->permissionlib->isBerechtigt('basis/prestudentstatus'); + + + $authUID = getAuthUID(); + $status_kurzbz = $this->input->post('status_kurzbz'); + $studiensemester_kurzbz = $this->input->post('studiensemester_kurzbz'); + $ausbildungssemester = $this->input->post('ausbildungssemester'); + $datum = $this->input->post('datum'); + $bestaetigtam = $this->input->post('bestaetigtam'); + $orgform_kurzbz = $this->input->post('orgform_kurzbz'); + $anmerkung = $this->input->post('anmerkung'); + $bewerbung_abgeschicktamum = $this->input->post('bewerbung_abgeschicktamum'); + $studienplan_id = $this->input->post('studienplan_id'); + $rt_stufe = $this->input->post('rt_stufe'); + $statusgrund_id = $this->input->post('statusgrund_id'); + + + $this->load->library('form_validation'); + + $this->form_validation->set_rules('statusgrund_id', $this->p->t('international', 'grund'), 'integer', [ + 'integer' => $this->p->t('ui', 'error_fieldNotInteger') + ]); + + if (!$isBerechtigtBasisPrestudentstatus) + $this->form_validation->set_rules( + 'bewerbung_abgeschicktamum', + $this->p->t('lehre', 'bewerbung_abgeschickt_am'), + 'is_null', + [ + 'is_null' => $this->p->t('ui', 'error_fieldWriteAccess') + ] + ); + + $this->form_validation->set_rules( + 'datum', + $this->p->t('global', 'datum'), + [ + 'required', // In FAS empty datum results in todays + 'is_valid_date', + ['is_date_not_before_today', function ($value) { + if (!is_valid_date($value)) + return true; // Error will be handled by the is_valid_date statement above + $today = new DateTime('today'); + return (new DateTime($value) >= $today); + }], + ['meldestichtag_not_exceeded', function ($value) use ($isBerechtigtNoStudstatusCheck) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$value) + return true; // Error will be handled by the required statement above + + $result = $this->prestudentstatuschecklib->checkIfMeldestichtagErreicht($value); + + return !$this->getDataOrTerminateWithError($result); + }] + ], + [ + 'meldestichtag_not_exceeded' => $this->p->t('lehre', 'error_dataVorMeldestichtag'), + 'is_date_not_before_today' => $this->p->t('lehre', 'error_entryInPast') + ] + ); + + $this->form_validation->set_rules( + 'status_kurzbz', + $this->p->t('lehre', 'status_rolle'), + [ + 'required', + ['status_stud_exists', function ($value) use ($prestudent_id) { + if ($value != Prestudentstatus_model::STATUS_STUDENT) + return true; // Only test if new status is Student + + $result = $this->prestudentstatuschecklib->checkIfExistingStudent($prestudent_id); + + return $this->getDataOrTerminateWithError($result); + }] + ], + [ + 'status_stud_exists' => $this->p->t('lehre', 'error_noStudstatus') + ] + ); + + $this->form_validation->set_rules('studiensemester_kurzbz', $this->p->t('lehre', 'studiensemester'), 'required'); + + $this->form_validation->set_rules('ausbildungssemester', $this->p->t('lehre', 'ausbildungssemester'), 'required'); + + $this->form_validation->set_rules('bestaetigtam', $this->p->t('lehre', 'bestaetigt_am'), 'is_valid_date'); + + // Set Datum to null to prevent multiple is_valid_date checks in the following validation rules + if (!$datum || !is_valid_date($datum)) + $datum = null; + + $this->form_validation->set_rules('_default', '', [ + ['rolle_doesnt_exist', function () use ($prestudent_id, $status_kurzbz, $studiensemester_kurzbz, $ausbildungssemester) { + if (!$status_kurzbz || !$studiensemester_kurzbz || !$ausbildungssemester) + return true; // Error will be handled by the required statements above + + $result = $this->PrestudentstatusModel->load([$ausbildungssemester, $studiensemester_kurzbz, $status_kurzbz, $prestudent_id]); + + return !$this->getDataOrTerminateWithError($result); + }], + ['history_timesequence', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$status_kurzbz || !$datum || !$studiensemester_kurzbz || !$ausbildungssemester) + return true; // Error will be handled by the required statements above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryTimesequence( + $prestudent_id, + $status_kurzbz, + new DateTime($datum), + $studiensemester_kurzbz, + $ausbildungssemester, + '', + '' + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_laststatus', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$status_kurzbz || !$datum || !$studiensemester_kurzbz || !$ausbildungssemester) + return true; // Error will be handled by the required statements above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryLaststatus( + $prestudent_id, + $status_kurzbz, + new DateTime($datum), + $studiensemester_kurzbz, + $ausbildungssemester, + '', + '' + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_unterbrecher', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$status_kurzbz || !$datum || !$studiensemester_kurzbz || !$ausbildungssemester) + return true; // Error will be handled by the required statements above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryUnterbrechersemester( + $prestudent_id, + $status_kurzbz, + new DateTime($datum), + $studiensemester_kurzbz, + $ausbildungssemester, + '', + '' + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_abbrecher', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$status_kurzbz || !$datum || !$studiensemester_kurzbz || !$ausbildungssemester) + return true; // Error will be handled by the required statements above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryAbbrechersemester( + $prestudent_id, + $status_kurzbz, + new DateTime($datum), + $studiensemester_kurzbz, + $ausbildungssemester, + '', + '' + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_diplomant', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$status_kurzbz || !$datum || !$studiensemester_kurzbz || !$ausbildungssemester) + return true; // Error will be handled by the required statements above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryDiplomant( + $prestudent_id, + $status_kurzbz, + new DateTime($datum), + $studiensemester_kurzbz, + $ausbildungssemester, + '', + '' + ); + + return $this->getDataOrTerminateWithError($result); + }] + ], [ + 'rolle_doesnt_exist' => $this->p->t('lehre', 'error_rolleBereitsVorhanden'), + 'history_timesequence' => $this->p->t('lehre', 'error_statuseintrag_zeitabfolge'), + 'history_laststatus' => $this->p->t('lehre', 'error_endstatus'), + 'history_unterbrecher' => $this->p->t('lehre', 'error_consecutiveUnterbrecher'), + 'history_abbrecher' => $this->p->t('lehre', 'error_consecutiveUnterbrecherAbbrecher'), + 'history_diplomant' => $this->p->t('lehre', 'error_consecutiveDiplomandStudent') + ]); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + // Start DB transaction + $this->db->trans_start(); + + $this->updateLehrverbandForInsertAndUpdate($prestudent_id, $status_kurzbz, $studiensemester_kurzbz, $ausbildungssemester, $authUID); + + //insert status + $result = $this->PrestudentstatusModel->insert([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => $status_kurzbz, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'ausbildungssemester' => $ausbildungssemester, + 'datum' => $datum, + 'insertamum' => date('c'), + 'insertvon' => $authUID, + 'orgform_kurzbz' => $orgform_kurzbz, + 'bestaetigtam' => $bestaetigtam, + 'bestaetigtvon' => $bestaetigtam ? $authUID : null, + 'anmerkung' => $anmerkung, + 'bewerbung_abgeschicktamum' => $bewerbung_abgeschicktamum, + 'studienplan_id' => $studienplan_id, + 'rt_stufe' => $rt_stufe, + 'statusgrund_id' => $statusgrund_id + ]); + + $this->getDataOrTerminateWithError($result); + + $this->db->trans_complete(); + + $this->terminateWithSuccess(true); + } + + /** + * Updates a status entry + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param string $key_studiensemester_kurzbz + * @param integer $key_ausbildungssemester + * + * @return void + */ + public function updateStatus($prestudent_id, $status_kurzbz, $key_studiensemester_kurzbz, $key_ausbildungssemester) + { + $result = $this->PrestudentstatusModel->load([ + $key_ausbildungssemester, + $key_studiensemester_kurzbz, + $status_kurzbz, + $prestudent_id + ]); + $oldstatus = $this->getDataOrTerminateWithError($result); + if (!$oldstatus) + show_404(); // Status that should be updated does not exist + + $oldstatus = current($oldstatus); + + + $isBerechtigtNoStudstatusCheck = $this->permissionlib->isBerechtigt('student/keine_studstatuspruefung'); + $isBerechtigtBasisPrestudentstatus = $this->permissionlib->isBerechtigt('basis/prestudentstatus'); + + + $authUID = getAuthUID(); + $studiensemester_kurzbz = $this->input->post('studiensemester_kurzbz') ?: $oldstatus->studiensemester_kurzbz; + $ausbildungssemester = $this->input->post('ausbildungssemester') ?: $oldstatus->ausbildungssemester; + $datum = $this->input->post('datum') ?: $oldstatus->datum; + + + //Form Validation + $this->load->library('form_validation'); + + $this->form_validation->set_rules('statusgrund_id', $this->p->t('international', 'grund'), 'integer', [ + 'integer' => $this->p->t('ui', 'error_fieldNotInteger') + ]); + + if (!$isBerechtigtBasisPrestudentstatus) + $this->form_validation->set_rules( + 'bewerbung_abgeschicktamum', + $this->p->t('lehre', 'bewerbung_abgeschickt_am'), + 'is_null', + [ + 'is_null' => $this->p->t('ui', 'error_fieldWriteAccess') + ] + ); + + $this->form_validation->set_rules( + 'datum', + $this->p->t('global', 'datum'), + [ + 'is_valid_date', + ['meldestichtag_not_exceeded', function ($value) use ($isBerechtigtNoStudstatusCheck) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$value) + return true; // Error will be handled by the required statement above + + $result = $this->prestudentstatuschecklib->checkIfMeldestichtagErreicht($value); + + return !$this->getDataOrTerminateWithError($result); + }] + ], + [ + 'meldestichtag_not_exceeded' => $this->p->t('lehre', 'error_dataVorMeldestichtag') + ] + ); + + $this->form_validation->set_rules('bestaetigtam', $this->p->t('lehre', 'bestaetigt_am'), 'is_valid_date'); + + if (!is_valid_date($datum)) + $datum = null; + + // Set Datum to null to prevent multiple is_valid_date checks in the following validation rules + $this->form_validation->set_rules('_default', '', [ + //Check if Rolle already exists + ['new_rolle_doesnt_exist', function () use ( + $prestudent_id, + $status_kurzbz, + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ) { + if ($key_studiensemester_kurzbz == $studiensemester_kurzbz + && $key_ausbildungssemester == $ausbildungssemester + ) + return true; // Primary key has not change we update in place + + $result = $this->PrestudentstatusModel->load([ + $ausbildungssemester, + $studiensemester_kurzbz, + $status_kurzbz, + $prestudent_id + ]); + return !$this->getDataOrTerminateWithError($result); + }], + ['history_timesequence', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$datum) + return true; // Error will be handled by the is_valid_date statement above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryTimesequence( + $prestudent_id, + $status_kurzbz, + new DateTime($datum), + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_laststatus', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$datum) + return true; // Error will be handled by the is_valid_date statement above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryLaststatus( + $prestudent_id, + $status_kurzbz, + new DateTime($datum), + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_unterbrecher', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$datum) + return true; // Error will be handled by the is_valid_date statement above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryUnterbrechersemester( + $prestudent_id, + $status_kurzbz, + new DateTime($datum), + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_abbrecher', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$datum) + return true; // Error will be handled by the is_valid_date statement above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryAbbrechersemester( + $prestudent_id, + $status_kurzbz, + new DateTime($datum), + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ); + + return $this->getDataOrTerminateWithError($result); + }], + ['history_diplomant', function () use ( + $isBerechtigtNoStudstatusCheck, + $prestudent_id, + $status_kurzbz, + $datum, + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ) { + if ($isBerechtigtNoStudstatusCheck) + return true; // Skip if access right says so + if (!$datum) + return true; // Error will be handled by the is_valid_date statement above + + $result = $this->prestudentstatuschecklib->checkStatusHistoryDiplomant( + $prestudent_id, + $status_kurzbz, + new DateTime($datum), + $studiensemester_kurzbz, + $ausbildungssemester, + $key_studiensemester_kurzbz, + $key_ausbildungssemester + ); + + return $this->getDataOrTerminateWithError($result); + }] + ], [ + 'new_rolle_doesnt_exist' => $this->p->t('lehre', 'error_rolleBereitsVorhanden'), + 'history_timesequence' => $this->p->t('lehre', 'error_statuseintrag_zeitabfolge'), + 'history_laststatus' => $this->p->t('lehre', 'error_endstatus'), + 'history_unterbrecher' => $this->p->t('lehre', 'error_consecutiveUnterbrecher'), + 'history_abbrecher' => $this->p->t('lehre', 'error_consecutiveUnterbrecherAbbrecher'), + 'history_diplomant' => $this->p->t('lehre', 'error_consecutiveDiplomandStudent') + ]); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + // Start DB transaction + $this->db->trans_start(); + + $this->updateLehrverbandForInsertAndUpdate($prestudent_id, $status_kurzbz, $studiensemester_kurzbz, $ausbildungssemester, $authUID); + + //update status + $updateData = [ + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'ausbildungssemester' => $ausbildungssemester, + 'datum' => $datum, + 'updateamum' => date('c'), + 'updatevon' => $authUID + ]; + foreach ([ + 'orgform_kurzbz', + 'anmerkung', + 'bewerbung_abgeschicktamum', + 'studienplan_id', + 'rt_stufe', + 'statusgrund_id' + ] as $key) + if ($this->input->post($key)) + $updateData[$key] = $this->input->post($key); + + if ($this->input->post('bestaetigtam')) { + $updateData['bestaetigtam'] = $this->input->post('bestaetigtam'); + $updateData['bestaetigtvon'] = $authUID; + } + + $result = $this->PrestudentstatusModel->update([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => $status_kurzbz, + 'studiensemester_kurzbz' => $key_studiensemester_kurzbz, + 'ausbildungssemester' => $key_ausbildungssemester, + ], $updateData); + + $this->getDataOrTerminateWithError($result); + + $this->db->trans_commit(); + + return $this->outputJsonSuccess(true); + } + + /** + * Advances a status entry + * must be of type Student, Diplomand or Unterbrecher + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param string $key_studiensemester_kurzbz + * @param integer $key_ausbildungssemester + * + * @return void + */ + public function advanceStatus($prestudent_id, $status_kurzbz, $key_studiensemester_kurzbz, $key_ausbildungssemester) + { + $result = $this->PrestudentstatusModel->load([ + $key_ausbildungssemester, + $key_studiensemester_kurzbz, + $status_kurzbz, + $prestudent_id + ]); + $oldstatus = $this->getDataOrTerminateWithError($result); + if (!$oldstatus) + show_404(); // Status that should be updated does not exist + + $oldstatus = current($oldstatus); + + + //Target studiensemester_kurzbz + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $result = $this->StudiensemesterModel->getNextFrom($key_studiensemester_kurzbz); + + $studiensemester_kurzbz = $this->getDataOrTerminateWithError($result); + $studiensemester_kurzbz = current($studiensemester_kurzbz)->studiensemester_kurzbz; + + + //Target ausbildungssemester + $ausbildungssemester = $key_ausbildungssemester + 1; + + + //Form Validation + $this->load->library('form_validation'); + + $this->form_validation->set_data([ + 'status_kurzbz' => $status_kurzbz + ]); + + $this->form_validation->set_rules('status_kurzbz', $this->p->t('lehre', 'status_rolle'), [ + 'in_list[' . + Prestudentstatus_model::STATUS_STUDENT . ',' . + Prestudentstatus_model::STATUS_DIPLOMAND . ',' . + Prestudentstatus_model::STATUS_UNTERBRECHER . ']', + ['status_stud_exists', function ($value) use ($prestudent_id) { + if ($value != Prestudentstatus_model::STATUS_STUDENT) + return true; + + $result = $this->prestudentstatuschecklib->checkIfExistingStudent($prestudent_id); + + return $this->getDataOrTerminateWithError($result); + }] + ], [ + 'status_stud_exists' => $this->p->t('lehre', 'error_noStudstatus') + ]); + + $this->form_validation->set_rules('_default', '', [ + //Check if Rolle already exists + ['rolle_doesnt_exist', function () use ( + $prestudent_id, + $status_kurzbz, + $studiensemester_kurzbz, + $ausbildungssemester + ) { + $result = $this->PrestudentstatusModel->load([$ausbildungssemester, $studiensemester_kurzbz, $status_kurzbz, $prestudent_id]); + + return !$this->getDataOrTerminateWithError($result); + }] + ], [ + 'rolle_doesnt_exist' => $this->p->t('lehre', 'error_rolleBereitsVorhanden') + ]); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + // Start DB transaction + $this->db->trans_begin(); + + $authUID = getAuthUID(); + $now = date('c'); + + //insert prestudentstatus + $result = $this->PrestudentstatusModel->insert([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => $status_kurzbz, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'ausbildungssemester' => $ausbildungssemester, + 'datum' => $now, + 'insertamum' => $now, + 'insertvon' => $authUID, + 'orgform_kurzbz' => $oldstatus->orgform_kurzbz, + 'studienplan_id' => $oldstatus->studienplan_id, + 'bestaetigtam' => $now, + 'bestaetigtvon' => $authUID, + 'anmerkung' => $oldstatus->anmerkung + ]); + + $this->getDataOrTerminateWithError($result); + + + //get student_uid + $this->load->model('crm/Student_model', 'StudentModel'); + $result = $this->StudentModel->loadWhere([ + 'prestudent_id' => $prestudent_id + ]); + + $student = $this->getDataOrTerminateWithError($result); + + if (!$student) + $this->terminateWithError($this->p->t('studierendenantrag', 'error_no_student_for_prestudent', ['prestudent_id' => $prestudent_id])); + $student = current($student); + + + //process studentlehrverband + $this->load->model('education/Studentlehrverband_model', 'StudentlehrverbandModel'); + $result = $this->StudentlehrverbandModel->load([ + $key_studiensemester_kurzbz, + $student->student_uid + ]); + + $studentlvb = $this->getDataOrTerminateWithError($result); + if (!$studentlvb) + $this->terminateWithError($this->p->t('lehre', 'error_noStudentlehrverband')); + + //Data of current Semester + $studentlvb = current($studentlvb); + + + $newStudentlvb = [ + 'student_uid' => $studentlvb->student_uid, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'studiengang_kz' => $studentlvb->studiengang_kz, + 'semester' => $studentlvb->semester, + 'verband' => $studentlvb->verband, + 'gruppe' => $studentlvb->gruppe, + 'insertamum' => $now, + 'insertvon' => $authUID, + 'ext_id' => $studentlvb->ext_id + + ]; + + + $this->load->model('organisation/Lehrverband_model', 'LehrverbandModel'); + + $result = $this->LehrverbandModel->load([ + $student->gruppe, + $student->verband, + $ausbildungssemester, + $student->studiengang_kz + ]); + + $lv = $this->getDataOrTerminateWithError($result); + if ($lv) { + $newStudentlvb['semester'] = $ausbildungssemester; + } // If there is no lehrverband just use the same as in the previous studiensemester + + + //add studentlehrverband + $result = $this->StudentlehrverbandModel->insert($newStudentlvb); + + $this->getDataOrTerminateWithError($result); + + $this->db->trans_commit(); + + return $this->outputJsonSuccess(true); + } + + /** + * Confirms a status entry + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param string $key_studiensemester_kurzbz + * @param integer $key_ausbildungssemester + * + * @return void + */ + public function confirmStatus($prestudent_id, $status_kurzbz, $studiensemester_kurzbz, $ausbildungssemester) + { + $result = $this->PrestudentstatusModel->load([ + $ausbildungssemester, + $studiensemester_kurzbz, + $status_kurzbz, + $prestudent_id + ]); + $oldstatus = $this->getDataOrTerminateWithError($result); + if (!$oldstatus) + show_404(); // Status that should be updated does not exist + + $oldstatus = current($oldstatus); + + + $authUID = getAuthUID(); + $now = date('c'); + + //Form Validation + $this->load->library('form_validation'); + + $this->form_validation->set_rules('Status', '', [ + ['status_not_yet_confirmed', function () use ($oldstatus) { + return !$oldstatus->bestaetigtam; + }], + ['bewerbung_abgeschickt', function () use ($oldstatus) { + return !!$oldstatus->bewerbung_abgeschicktamum; + }] + ], [ + 'status_not_yet_confirmed' => $this->p->t('lehre', 'error_statusConfirmedYet'), + 'bewerbung_abgeschickt' => $this->p->t('lehre', 'error_bewerbungNochNichtAbgeschickt') + ]); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + + //update status + $result = $this->PrestudentstatusModel->update([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => $status_kurzbz, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'ausbildungssemester' => $ausbildungssemester, + ], [ + 'bestaetigtam' => $now, + 'bestaetigtvon' => $authUID, + 'updateamum' => $now, + 'updatevon' => $authUID + ]); + + $this->getDataOrTerminateWithError($result); + + + //Send Message + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + $this->PrestudentModel->addSelect('p.*'); + $this->PrestudentModel->addSelect('stg.oe_kurzbz'); + $this->PrestudentModel->addSelect('stg.bezeichnung AS stg_bezeichnung'); + $this->PrestudentModel->addSelect('stg.email AS stg_email'); + $this->PrestudentModel->addSelect('plan.orgform_kurzbz'); + $this->PrestudentModel->addSelect('typ.bezeichnung AS typ_bezeichnung'); + + $this->PrestudentModel->addJoin('public.tbl_person p', 'person_id'); + $this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz'); + $this->PrestudentModel->addJoin('public.tbl_studiengangstyp typ', 'typ'); + $this->PrestudentModel->addJoin('public.tbl_studienplan plan', 'studienplan_id', 'LEFT'); + + $result = $this->PrestudentModel->load($prestudent_id); + + $studentdata = $this->getDataOrTerminateWithError($result); + + $this->load->library('MessageLib'); + $result = $this->messagelib->sendMessageUserTemplate( + $studentdata->person_id, // receiversPersonId + 'MailStatConfirm' . $status_kurzbz, // vorlage + [ + 'anrede' => $studentdata->anrede, + 'vorname' => $studentdata->vorname, + 'nachname' => $studentdata->nachname, + 'typ' => $studentdata->typ_bezeichnung, + 'studiengang' => $studentdata->stg_bezeichnung, + 'orgform' => $studentdata->orgform_kurzbz ?: $oldstatus->orgform_kurzbz, + 'stgMail' => $studentdata->stg_email + ], // parseData + null, // orgform + 1, // TODO + $studentdata->oe_kurzbz, // senderOU + null, // relationmessage_id + MSG_PRIORITY_NORMAL, // priority + true // multiPartMime + ); + + + $this->terminateWithSuccess(true); + } + + /** + * Helper function for insertStatus and updateStatus. + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param string $studiensemester_kurzbz + * @param integer $ausbildungssemester + * @param string $authUID + * + * @return void + */ + private function updateLehrverbandForInsertAndUpdate($prestudent_id, $status_kurzbz, $studiensemester_kurzbz, $ausbildungssemester, $authUID) + { + if (!in_array($status_kurzbz, [ + Prestudentstatus_model::STATUS_STUDENT, + Prestudentstatus_model::STATUS_DIPLOMAND, + Prestudentstatus_model::STATUS_ABSOLVENT, + Prestudentstatus_model::STATUS_INCOMING, + Prestudentstatus_model::STATUS_ABBRECHER, + Prestudentstatus_model::STATUS_UNTERBRECHER + ])) + return; // No Update necessary + + $result = $this->StudentModel->loadWhere([ + 'prestudent_id' => $prestudent_id + ]); + + $student = $this->getDataOrTerminateWithError($result); + + if (!$student) + return; // No Update necessary + + $student = current($student); + + $this->load->model('education/Studentlehrverband_model', 'StudentlehrverbandModel'); + $result = $this->StudentlehrverbandModel->loadWhere([ + 'student_uid' => $student->student_uid, + 'studiensemester_kurzbz' => $studiensemester_kurzbz + ]); + + $studentlvb = $this->getDataOrTerminateWithError($result); + + + $this->load->model('organisation/Lehrverband_model', 'LehrverbandModel'); + + $this->LehrverbandModel->addLimit(1); + $result = $this->LehrverbandModel->load([ + $student->gruppe, + $student->verband, + $ausbildungssemester, + $student->studiengang_kz + ]); + $lv = $this->getDataOrTerminateWithError($result); + + + if ($studentlvb && !$lv) + return; // No Update necessary + + if ($studentlvb) // Update current Student-Lehrverband entry + $this->StudentlehrverbandModel->update([ + 'student_uid' => $student->student_uid, + 'studiensemester_kurzbz' => $studiensemester_kurzbz + ], [ + 'studiengang_kz' => $student->studiengang_kz, + 'semester' => $ausbildungssemester, + 'verband' => $student->verband, + 'gruppe' => $student->gruppe, + 'updateamum' => date('c'), + 'updatevon' => $authUID + ]); + else // Add new Student-Lehrverband entry + $this->StudentlehrverbandModel->insert([ + 'student_uid' => $student->student_uid, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'studiengang_kz' => $student->studiengang_kz, + 'semester' => $lv ? $ausbildungssemester : $student->semester, + 'verband' => $student->verband, + 'gruppe' => $student->gruppe, + 'insertamum' => date('c'), + 'insertvon' => $authUID + ]); + } + + /** + * Helper function for sanitizing Alias Name + * replaces empty spaces with underlines + * + * @param string $str + * + * @return string + */ + private function _sanitizeAliasName($str) + { + $str = sanitizeProblemChars($str); + return mb_strtolower(str_replace(' ', '_', $str)); + } +} diff --git a/application/controllers/api/frontend/v1/stv/Student.php b/application/controllers/api/frontend/v1/stv/Student.php new file mode 100644 index 000000000..89c317ae4 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Student.php @@ -0,0 +1,562 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +use \DateTime as DateTime; + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * Provides data to the ajax get calls about a Student + * Listens to ajax post calls to change the Student data + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Student extends FHCAPI_Controller +{ + /** + * Calls the parent's constructor and prepares libraries and phrases + */ + public function __construct() + { + parent::__construct([ + 'get' => ['admin:r', 'assistenz:r'], + 'save' => ['admin:rw', 'assistenz:rw'], + 'check' => ['admin:rw', 'assistenz:rw'], + 'add' => ['admin:rw', 'assistenz:rw'] // TODO(chris): extra permissions + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + + if ($this->router->method == 'get' + || $this->router->method == 'save' + ) { + $prestudent_id = current(array_slice($this->uri->rsegments, 2)); + if ($this->router->method == 'get') + $this->checkPermissionsForPrestudent($prestudent_id, ['admin:r', 'assistenz:r']); + else + $this->checkPermissionsForPrestudent($prestudent_id, ['admin:rw', 'assistenz:rw']); + } + + // Load language phrases + $this->loadPhrases([ + 'ui' + ]); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Get details for a prestudent + * + * @param string $prestudent_id + * @return void + */ + public function get($prestudent_id) + { + $studiensemester_kurzbz = $this->variablelib->getVar('semester_aktuell'); + + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + $this->PrestudentModel->addSelect('p.*'); + $this->PrestudentModel->addSelect('s.student_uid'); + $this->PrestudentModel->addSelect('matrikelnr'); + $this->PrestudentModel->addSelect('b.aktiv'); + $this->PrestudentModel->addSelect('v.semester'); + $this->PrestudentModel->addSelect('v.verband'); + $this->PrestudentModel->addSelect('v.gruppe'); + $this->PrestudentModel->addSelect('b.alias'); + + if (defined('ACTIVE_ADDONS') && strpos(ACTIVE_ADDONS, 'bewerbung') !== false) { + $this->PrestudentModel->addSelect( + "( + SELECT kontakt + FROM public.tbl_kontakt + WHERE kontakttyp='email' + AND person_id=p.person_id + AND zustellung + ORDER BY kontakt_id + LIMIT 1 + ) AS email_privat", + false + ); + } + + $this->PrestudentModel->addJoin('public.tbl_student s', 'prestudent_id', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_benutzer b', 'student_uid = uid', 'LEFT'); + $this->PrestudentModel->addJoin( + 'public.tbl_studentlehrverband v', + 'b.uid = v.student_uid AND v.studiensemester_kurzbz = ' . $this->PrestudentModel->escape($studiensemester_kurzbz), + 'LEFT' + ); + $this->PrestudentModel->addJoin('public.tbl_person p', 'p.person_id = tbl_prestudent.person_id'); + + $result = $this->PrestudentModel->loadWhere(['prestudent_id' => $prestudent_id]); + + $student = $this->getDataOrTerminateWithError($result); + + if (!$student) + return show_404(); + + $this->terminateWithSuccess(current($student)); + } + + /** + * Saves data to a prestudent + * + * @param string $prestudent_id + * @return void + */ + public function save($prestudent_id) + { + $studiensemester_kurzbz = $this->variablelib->getVar('semester_aktuell'); + + $this->load->model('person/Person_model', 'PersonModel'); + $this->load->model('crm/Student_model', 'StudentModel'); + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $this->load->model('education/Studentlehrverband_model', 'StudentlehrverbandModel'); + + $this->load->library('form_validation'); + + $this->form_validation->set_rules('gebdatum', 'Geburtsdatum', 'is_valid_date'); + + $this->form_validation->set_rules('semester', 'Semester', 'integer'); + + $this->load->library('UDFLib'); + + $result = $this->udflib->getCiValidations($this->PersonModel, $this->input->post()); + + //TODO(Manu) check with Chris: input number not allowed + $udf_field_validations = $this->getDataOrTerminateWithError($result); + + $this->form_validation->set_rules($udf_field_validations); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $result = $this->StudentModel->loadWhere(['prestudent_id' => $prestudent_id]); + + $student = $this->getDataOrTerminateWithError($result); + + $uid = $student ? current($student)->student_uid : null; + + $result = $this->PrestudentModel->loadWhere(['prestudent_id' => $prestudent_id]); + + $person = $this->getDataOrTerminateWithError($result); + + $person_id = $person ? current($person)->person_id : null; + + + $array_allowed_props_lehrverband = ['verband', 'semester', 'gruppe']; + $update_lehrverband = array(); + foreach ($array_allowed_props_lehrverband as $prop) { + $val = $this->input->post($prop); + if ($val !== null) { + $update_lehrverband[$prop] = $val; + } + } + + $array_allowed_props_person = [ + 'anrede', + 'bpk', + 'titelpre', + 'titelpost', + 'nachname', + 'vorname', + 'vornamen', + 'wahlname', + 'gebdatum', + 'gebort', + 'geburtsnation', + 'svnr', + 'ersatzkennzeichen', + 'staatsbuergerschaft', + 'matr_nr', + 'sprache', + 'geschlecht', + 'familienstand', + 'foto', + 'anmerkung', + 'homepage' + ]; + + // add UDFs + $result = $this->udflib->getDefinitionForModel($this->PersonModel); + + $definitions = $this->getDataOrTerminateWithError($result); + + foreach ($definitions as $def) + $array_allowed_props_person[] = $def['name']; + + $update_person = array(); + foreach ($array_allowed_props_person as $prop) { + $val = $this->input->post($prop); + if ($val !== null) { + $update_person[$prop] = $val; + } + } + + $array_allowed_props_student = ['matrikelnr']; + $update_student = array(); + foreach ($array_allowed_props_student as $prop) { + $val = $this->input->post($prop); + if ($val !== null) { + $update_student[$prop] = $val; + } + } + + // Check PKs + if (count($update_lehrverband) + count($update_student) && $uid === null) { + // TODO(chris): phrase + $this->terminateWithValidationErrors(['' => "Kein/e StudentIn vorhanden!"]); + } + if (count($update_person) && $person_id === null) { + // TODO(chris): phrase + $this->terminateWithValidationErrors(['' => "Keine Person vorhanden!"]); + } + + // Do Updates + if (count($update_lehrverband)) { + $result = $this->StudentlehrverbandModel->update([ + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'student_uid' => $uid + ], $update_lehrverband); + $this->getDataOrTerminateWithError($result); + } + + if (count($update_person)) { + $result = $this->PersonModel->update( + $person_id, + $update_person + ); + $this->getDataOrTerminateWithError($result); + } + + + if (count($update_student)) { + $result = $this->StudentModel->update( + [$uid], + $update_student + ); + $this->getDataOrTerminateWithError($result); + } + + $this->terminateWithSuccess(array_fill_keys(array_merge( + array_keys($update_lehrverband), + array_keys($update_person), + array_keys($update_student) + ), '')); + } + + public function check() + { + $this->load->library('form_validation'); + + $this->form_validation->set_rules('gebdatum', 'Geburtsdatum', 'is_valid_date'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $vorname = $this->input->post('vorname'); + $nachname = $this->input->post('nachname'); + $gebdatum = $this->input->post('gebdatum'); + + if (!$vorname && !$nachname && !$gebdatum) + $this->terminateWithValidationErrors(['At least one of vorname, nachname or gebdatum must be set']); + + $this->load->model('person/Person_model', 'PersonModel'); + + if ($gebdatum) + $this->PersonModel->db->where('gebdatum', (new DateTime($gebdatum))->format('Y-m-d')); + if ($vorname && $nachname) { + $this->PersonModel->db->or_group_start(); + $this->PersonModel->db->where('LOWER(nachname)', 'LOWER(' . $this->PersonModel->db->escape($nachname) . ')', false); + $this->PersonModel->db->where('LOWER(vorname)', 'LOWER(' . $this->PersonModel->db->escape($vorname) . ')', false); + $this->PersonModel->db->group_end(); + } elseif ($nachname) { + $this->PersonModel->db->or_where('LOWER(nachname)', 'LOWER(' . $this->PersonModel->escape($nachname) . ')', false); + } + + $result = $this->PersonModel->load(); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + public function add() + { + if (!$this->input->post('person_id')) { + if (!isset($_POST['address']) || !is_array($_POST['address'])) + $_POST['address'] = []; + $_POST['address']['func'] = 1; + } + if ($this->input->post('incoming')) { + $_POST['ausbildungssemester'] = 0; + } + + $this->load->library('form_validation'); + + $this->form_validation->set_rules('nachname', 'Nachname', 'callback_requiredIfNotPersonId', [ + 'requiredIfNotPersonId' => $this->p->t('ui', 'error_required') + ]); + $this->form_validation->set_rules('geschlecht', 'Geschlecht', 'callback_requiredIfNotPersonId', [ + 'requiredIfNotPersonId' => $this->p->t('ui', 'error_required') + ]); + $this->form_validation->set_rules('gebdatum', 'Geburtsdatum', 'callback_isValidDate', [ + 'isValidDate' => $this->p->t('ui', 'error_invalid_date') + ]); + $this->form_validation->set_rules('address[func]', 'Address', 'required|integer|less_than[2]|greater_than[-2]'); + $this->form_validation->set_rules('address[plz]', 'PLZ', 'callback_requiredIfAddressFunc', [ + 'requiredIfAddressFunc' => $this->p->t('ui', 'error_required') + ]); + $this->form_validation->set_rules('address[gemeinde]', 'Gemeinde', 'callback_requiredIfAddressFunc', [ + 'requiredIfAddressFunc' => $this->p->t('ui', 'error_required') + ]); + $this->form_validation->set_rules('address[ort]', 'Ort', 'callback_requiredIfAddressFunc', [ + 'requiredIfAddressFunc' => $this->p->t('ui', 'error_required') + ]); + $this->form_validation->set_rules('address[address]', 'Adresse', 'callback_requiredIfAddressFunc', [ + 'requiredIfAddressFunc' => $this->p->t('ui', 'error_required') + ]); + $this->form_validation->set_rules('email', 'E-Mail', 'valid_email'); + $this->form_validation->set_rules('studiengang_kz', 'Studiengang', 'required'); + $this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester', 'required'); + $this->form_validation->set_rules('ausbildungssemester', 'Ausbildungssemester', 'required|integer|less_than[9]|greater_than[-1]'); + // TODO(chris): validate studienplan with studiengang, semester and orgform? + // TODO(chris): validate person_id, studiengang_kz, studiensemester_kurzbz, orgform_kurzbz, nation, gemeinde, ort, geschlecht? + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + // TODO(chris): This should be in a library + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $this->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); + + $this->db->trans_start(); + + $result = $this->addInteressent(); + + $this->db->trans_complete(); + + if ($this->db->trans_status() === FALSE) + $this->terminateWithError('TODO(chris): TEXT', self::ERROR_TYPE_GENERAL); + + $this->terminateWithSuccess($result); + } + + protected function addInteressent() + { + // Person anlegen wenn nötig + $person_id = $this->input->post('person_id'); + if (!$person_id) { + $this->load->model('person/Person_model', 'PersonModel'); + + $data = [ + 'nachname' => $this->input->post('nachname'), + 'insertamum' => date('c'), + 'insertvon' => getAuthUID(), + 'zugangscode' => uniqid(), + 'aktiv' => true + ]; + if ($this->input->post('anrede')) + $data['anrede'] = $this->input->post('anrede'); + if ($this->input->post('titelpre')) + $data['titelpre'] = $this->input->post('titelpre'); + if ($this->input->post('titelpost')) + $data['titelpost'] = $this->input->post('titelpost'); + if ($this->input->post('vorname')) + $data['vorname'] = $this->input->post('vorname'); + if ($this->input->post('vornamen')) + $data['vornamen'] = $this->input->post('vornamen'); + if ($this->input->post('wahlname')) + $data['wahlname'] = $this->input->post('wahlname'); + if ($this->input->post('geschlecht')) + $data['geschlecht'] = $this->input->post('geschlecht'); + if ($this->input->post('gebdatum')) + $data['gebdatum'] = (new DateTime($this->input->post('datum_obj')))->format('Y-m-d'); + if ($this->input->post('geburtsnation')) + $data['geburtsnation'] = $this->input->post('geburtsnation'); + if ($this->input->post('staatsbuergerschaft')) + $data['staatsbuergerschaft'] = $this->input->post('staatsbuergerschaft'); + + $result = $this->PersonModel->insert($data); + $person_id = $this->getDataOrTerminateWithError($result); + } + + // Addresse anlegen + $anlegen = $this->input->post('address[func]'); + if ($anlegen) { + $this->load->model('person/Adresse_model', 'AdresseModel'); + + $data = [ + 'nation' => $this->input->post('address[nation]'), + 'strasse' => $this->input->post('address[address]'), + 'plz' => $this->input->post('address[plz]'), + 'ort' => $this->input->post('address[ort]'), + 'gemeinde' => $this->input->post('address[gemeinde]'), + 'typ' => 'h', + 'zustelladresse' => true, + ]; + if ($anlegen < 0) { // Überschreiben + $this->AdresseModel->addOrder('zustelladresse', 'DESC'); + $this->AdresseModel->addOrder('sort'); + $result = $this->AdresseModel->loadWhere([ + 'person_id' => $person_id + ]); + $address = $this->getDataOrTerminateWithError($result); + if ($address) { + $address = current($address); + + $data['updateamum'] = date('c'); + $data['updatevon'] = getAuthUID(); + + $result = $this->AdresseModel->update($address->adresse_id, $data); + $this->getDataOrTerminateWithError($result); + } else { + //Wenn keine Adrese vorhanden ist dann eine neue Anlegen + $anlegen = 1; + $data['heimatadresse'] = true; + } + } + if ($anlegen > 0) { + $data['person_id'] = $person_id; + $data['insertamum'] = date('c'); + $data['insertvon'] = getAuthUID(); + if (!isset($data['heimatadresse'])) + $data['heimatadresse'] = !$this->input->post('person_id'); + + $result = $this->AdresseModel->insert($data); + $this->getDataOrTerminateWithError($result); + } + } + + // Kontaktdaten + $kontaktdaten = []; + foreach (['email', 'telefon', 'mobil'] as $k) { + $v = $this->input->post($k); + if ($v) + $kontaktdaten[$k] = $v; + } + if (count($kontaktdaten)) { + $this->load->model('person/Kontakt_model', 'KontaktModel'); + + foreach ($kontaktdaten as $typ => $kontakt) { + $data = [ + 'person_id' => $person_id, + 'kontakttyp' => $typ, + 'kontakt' => $kontakt, + 'zustellung' => true, + 'insertamum' => date('c'), + 'insertvon' => getAuthUID() + ]; + $result = $this->KontaktModel->insert($data); + $this->getDataOrTerminateWithError($result); + } + } + + // Prestudent anlegen + $data = [ + 'aufmerksamdurch_kurzbz' => 'k.A.', + 'person_id' => $person_id, + 'studiengang_kz' => $this->input->post('studiengang_kz'), + 'ausbildungcode' => $this->input->post('letzteausbildung'), + 'anmerkung' => $this->input->post('anmerkungen'), + 'reihungstestangetreten' => false, + 'bismelden' => true + ]; + $ausbildungsart = $this->input->post('ausbildungsart'); + if ($ausbildungsart) + $data['anmerkung'] .= ' Ausbildungsart:' . $ausbildungsart; + // Incomings und ausserordentliche sind bei Meldung nicht förderrelevant + $incoming = $this->input->post('incoming'); + if ($incoming || substr($data['studiengang_kz'], 0, 1) == '9') + $data['foerderrelevant'] = false; + // Wenn die Person schon im System erfasst ist, dann die ZGV des Datensatzes uebernehmen + $this->PrestudentModel->addOrder('zgvmas_code'); + $this->PrestudentModel->addOrder('zgv_code', 'DESC'); + $this->PrestudentModel->addLimit(1); + $result = $this->PrestudentModel->loadWhere([ + 'person_id' => $person_id + ]); + $prestudent = $this->getDataOrTerminateWithError($result); + if ($prestudent) { + $prestudent = current($prestudent); + if ($prestudent->zgv_code) { + $data['zgv_code'] = $prestudent->zgv_code; + $data['zgvort'] = $prestudent->zgvort; + $data['zgvdatum'] = $prestudent->zgvdatum; + + $data['zgvmas_code'] = $prestudent->zgvmas_code; + $data['zgvmaort'] = $prestudent->zgvmaort; + $data['zgvmadatum'] = $prestudent->zgvmadatum; + } + } + // Prestudent speichern + $result = $this->PrestudentModel->insert($data); + $prestudent_id = $this->getDataOrTerminateWithError($result); + + // Prestudent Rolle Anlegen + $data = [ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => $incoming ? 'Incoming' : 'Interessent', + 'studiensemester_kurzbz' => $this->input->post('studiensemester_kurzbz'), + 'ausbildungssemester' => $this->input->post('ausbildungssemester') ?: 0, + 'orgform_kurzbz' => $this->input->post('orgform_kurzbz') ?: null, + 'studienplan_id' => $this->input->post('studienplan_id') ?: null, + 'datum' => date('Y-m-d'), + 'insertamum' => date('c'), + 'insertvon' => getAuthUID() + ]; + $result = $this->PrestudentstatusModel->insert($data); + $this->getDataOrTerminateWithError($result); + + if ($incoming) { + // TODO(chris): IMPLEMENT! + //Matrikelnummer und UID generieren + //Benutzerdatensatz anlegen + //Studentendatensatz anlegen + //StudentLehrverband anlegen + } + + // TODO(chris): DEBUG + /*$result = $this->PrestudentModel->loadWhere([ + 'pestudent_id' => 1 + ]); + if (isError($result)) { + return $result; + }*/ + + $this->terminateWithSuccess(true); + } + + public function requiredIfNotPersonId($value) + { + if (isset($_POST['person_id'])) + return true; + return !!$value; + } + + public function requiredIfAddressFunc($value) + { + if (!$_POST['address']['func']) + return true; + return !!$value; + } +} diff --git a/application/controllers/api/frontend/v1/stv/Students.php b/application/controllers/api/frontend/v1/stv/Students.php new file mode 100644 index 000000000..5fb7b592c --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Students.php @@ -0,0 +1,743 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * Provides data to the ajax get calls about listing students + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Students extends FHCAPI_Controller +{ + private $allowedStgs = []; + + + public function __construct() + { + $permissions = []; + $router = load_class('Router'); + $permissions[$router->method] = ['admin:r', 'assistenz:r']; + parent::__construct($permissions); + + $this->allowedStgs = $this->permissionlib->getSTG_isEntitledFor('admin') ?: []; + $this->allowedStgs = array_merge($this->allowedStgs, $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []); + + if (!$this->allowedStgs) { + $this->_outputAuthError([$router->method => ['admin:r', 'assistenz:r']]); + exit; + } + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + } + + /** + * Remap calls: + * / => return [] + * /inout => return [] + * /inout/incoming => getIncoming + * /inout/outgoing => getOutgoing + * /inout/gemeinsamestudien => getGemeinsamestudien + * /(studiengang_kz) => getStudents + * /(studiengang_kz)/prestudent => getPrestudents + * /(studiengang_kz)/prestudent/* => getPrestudents + * /(studiengang_kz)/(semester) => getStudents + * /(studiengang_kz)/(semester)/grp/(gruppe_kurzbz) => getStudents + * /(studiengang_kz)/(semester)/(verband) => getStudents + * /(studiengang_kz)/(semester)/(verband)/(gruppe) => getStudents + * /(studiengang_kz)/(org_form) => getStudents + * /(studiengang_kz)/(org_form)/prestudent => getPrestudents + * /(studiengang_kz)/(org_form)/prestudent/* => getPrestudents + * /(studiengang_kz)/(org_form)/(semester) => getStudents + * /(studiengang_kz)/(org_form)/(semester)/grp/(gruppe_kurzbz) + * => getStudents + * /(studiengang_kz)/(org_form)/(semester)/(verband) => getStudents + * /(studiengang_kz)/(org_form)/(semester)/(verband)/(gruppe) + * => getStudents + * /uid/(student_uid) => getStudent + * /prestudent/(prestudent_id) => getPrestudent + * /person/(person_id) => getPerson + * + * @param string $method + * @param array $params (optional) + * + * @return void + */ + public function _remap($method, $params = []) + { + if ($method == '' || $method == 'index') + return $this->terminateWithSuccess([]); + + if ($method == 'inout') { + if (!count($params)) + return $this->terminateWithSuccess([]); + switch ($params[0]) { + case 'incoming': + return $this->getIncoming(); + case 'outgoing': + return $this->getOutgoing(); + case 'gemeinsamestudien': + return $this->getGemeinsamestudien(); + default: + return show_404(); + } + } + + $count = count($params); + if (!$count) + return $this->getStudents($method); + + if ($method == 'uid' && $count == 1) + return $this->getStudent($params[0]); + + if ($method == 'prestudent' && $count == 1) + return $this->getPrestudent($params[0]); + + if ($method == 'person' && $count == 1) + return $this->getPerson($params[0]); + + if (is_numeric($params[0])) { + $sem = $params[0]; + if ($count == 3 && $params[1] == 'grp') { + $g = $params[2]; + $ver = null; + $grp = null; + } else { + $g = null; + $ver = $count > 1 ? $params[1] : null; + $grp = $count > 2 ? $params[2] : null; + } + return $this->getStudents($method, $sem, $ver, $grp, $g); + } elseif ($params[0] == 'prestudent') { + if ($count == 1) + return $this->getPrestudents($method); + if ($count == 2) + return $this->getPrestudents($method, $params[1]); + return $this->getPrestudents($method, $params[1], $params[$count-1]); + } else { + $org = $params[0]; + if ($count > 1 && $params[1] == 'prestudent') { + if ($count == 2) + return $this->getPrestudents($method, null, null, $org); + if ($count == 3) + return $this->getPrestudents($method, $params[2], null, $org); + return $this->getPrestudents($method, $params[2], $params[$count-1], $org); + } + $sem = $count > 1 ? $params[1] : null; + if ($count == 4 && $params[2] == 'grp') { + $g = $params[3]; + $ver = null; + $grp = null; + } else { + $g = null; + $ver = $count > 2 ? $params[2] : null; + $grp = $count > 3 ? $params[3] : null; + } + + return $this->getStudents($method, $sem, $ver, $grp, $g, $org); + } + + show_404(); + } + + /** + * @return void + */ + protected function getIncoming() + { + // TODO(chris): IMPLEMENT! + $this->terminateWithSuccess([]); + } + + /** + * @return void + */ + protected function getOutgoing() + { + // TODO(chris): IMPLEMENT! + $this->terminateWithSuccess([]); + } + + /** + * @return void + */ + protected function getGemeinsamestudien() + { + // TODO(chris): IMPLEMENT! + $this->terminateWithSuccess([]); + } + + /** + * @param integer $studiengang_kz + * @param string $studiensemester_kurzbz (optional) + * @param string $filter (optional) + * @param string $orgform_kurzbz (optional) + * + * @return void + */ + protected function getPrestudents($studiengang_kz, $studiensemester_kurzbz = null, $filter = null, $orgform_kurzbz = null) + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + $stdsemEsc = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL'; + + $selectRT = " + SELECT 1 + FROM public.tbl_rt_person + JOIN public.tbl_reihungstest r ON (rt_id = reihungstest_id) + WHERE person_id=p.person_id + AND studienplan_id IN ( + SELECT studienplan_id + FROM lehre.tbl_studienplan + JOIN lehre.tbl_studienordnung o USING(studienordnung_id) + WHERE o.studiengang_kz=tbl_prestudent.studiengang_kz + ) + AND r.studiensemester_kurzbz=" . $stdsemEsc; + + + $where = ['tbl_prestudent.studiengang_kz' => $studiengang_kz]; + + if ($orgform_kurzbz) { + $where['ps.orgform_kurzbz'] = $orgform_kurzbz; + } + + switch ($filter) { + case "interessenten": + $where['ps.status_kurzbz'] = 'Interessent'; + break; + case "bewerbungnichtabgeschickt": + $where['ps.status_kurzbz'] = 'Interessent'; + $where['bewerbung_abgeschicktamum'] = null; + break; + case "bewerbungabgeschickt": + $where['ps.status_kurzbz'] = 'Interessent'; + $where['bewerbung_abgeschicktamum IS NOT NULL'] = null; + $where['bestaetigtam'] = null; + break; + case "statusbestaetigt": + $where['ps.status_kurzbz'] = 'Interessent'; + $where['bestaetigtam IS NOT NULL'] = null; + break; + case "statusbestaetigtrtnichtangemeldet": + $where['ps.status_kurzbz'] = 'Interessent'; + $where['bestaetigtam IS NOT NULL'] = null; + $this->PrestudentModel->db->where('NOT EXISTS(' . $selectRT . ')', null, false); + break; + case "statusbestaetigtrtangemeldet": + $where['ps.status_kurzbz'] = 'Interessent'; + $where['bestaetigtam IS NOT NULL'] = null; + $this->PrestudentModel->db->where('EXISTS(' . $selectRT . ')', null, false); + break; + case "zgv": + $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); + + $result = $this->StudiengangModel->load($studiengang_kz); + + $stg = $this->getDataOrTerminateWithError($result); + if (!$stg) + $this->terminateWithValidationErrors(['' => 'Studiengang does not exist']); // TODO(chris): phrase + $stg = current($stg); + + $where['ps.status_kurzbz'] = 'Interessent'; + + if ($stg->typ == 'm') { + $where['zgvmas_code IS NOT NULL'] = null; + if (defined('ZGV_ERFUELLT_ANZEIGEN') && ZGV_ERFUELLT_ANZEIGEN) + $where['zgvmas_erfuellt'] = true; + } elseif ($stg->typ == 'p') { + $where['zgvdoktor_code IS NOT NULL'] = null; + if (defined('ZGV_DOKTOR_ANZEIGEN') && ZGV_DOKTOR_ANZEIGEN) + $where['zgvdoktor_erfuellt'] = true; + } else { + $where['zgv_code IS NOT NULL'] = null; + if (defined('ZGV_ERFUELLT_ANZEIGEN') && ZGV_ERFUELLT_ANZEIGEN) + $where['zgv_erfuellt'] = true; + } + break; + case "reihungstestangemeldet": + $where['ps.status_kurzbz'] = 'Interessent'; + $this->PrestudentModel->db->where('EXISTS(' . $selectRT . ')', null, false); + break; + case "reihungstestnichtangemeldet": + $where['ps.status_kurzbz'] = 'Interessent'; + $this->PrestudentModel->db->where('NOT EXISTS(' . $selectRT . ')', null, false); + break; + case "bewerber": + $where['ps.status_kurzbz'] = 'Bewerber'; + break; + case "bewerberrtnichtangemeldet": + $where['ps.status_kurzbz'] = 'Bewerber'; + $this->PrestudentModel->db->where('NOT EXISTS(' . $selectRT . ')', null, false); + break; + case "bewerberrtangemeldet": + $where['ps.status_kurzbz'] = 'Bewerber'; + $this->PrestudentModel->db->where('EXISTS(' . $selectRT . ')', null, false); + break; + case "bewerberrtangemeldetteilgenommen": + $where['ps.status_kurzbz'] = 'Bewerber'; + $this->PrestudentModel->db->where('EXISTS(' . $selectRT . ')', null, false); + $where['reihungstestangetreten'] = true; + break; + case "bewerberrtangemeldetnichtteilgenommen": + $where['ps.status_kurzbz'] = 'Bewerber'; + $this->PrestudentModel->db->where('EXISTS(' . $selectRT . ')', null, false); + $where['reihungstestangetreten'] = false; + break; + case "aufgenommen": + $where['ps.status_kurzbz'] = 'Aufgenommener'; + break; + case "warteliste": + $where['ps.status_kurzbz'] = 'Wartender'; + break; + case "absage": + $where['ps.status_kurzbz'] = 'Abgewiesener'; + break; + case "incoming": + // NOTE(chris): in FAS it was not filtered for studiengang_kz + $where['ps.status_kurzbz'] = 'Incoming'; + break; + case "absolvent": + $where['ps.status_kurzbz'] = 'Absolvent'; + break; + case "diplomand": + $where['ps.status_kurzbz'] = 'Diplomand'; + break; + default: + if (!$studiensemester_kurzbz) { + // TODO(chris): this does not work with $orgform_kurzbz != null + $where['ps.status_kurzbz'] = null; + } else { + $this->PrestudentModel->db->where_in('ps.status_kurzbz', [ + 'Interessent', + 'Bewerber', + 'Aufgenommener', + 'Wartender', + 'Abgewiesener' + ]); + } + break; + } + + /* + $this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_person p', 'person_id'); + $this->PrestudentModel->addJoin('public.tbl_prestudentstatus pls', ' + pls.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) + AND pls.prestudent_id=tbl_prestudent.prestudent_id + AND pls.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, NULL) + AND pls.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)', 'LEFT'); + $this->PrestudentModel->addJoin('lehre.tbl_studienplan sp', 'studienplan_id', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_prestudentstatus ps', ' + ps.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ') + AND ps.prestudent_id=tbl_prestudent.prestudent_id + AND ps.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ') + AND ps.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')', 'LEFT');*/ + $this->prepareQuery($studiensemester_kurzbz); + + $this->PrestudentModel->addSelect(" + CASE WHEN ps.status_kurzbz IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent') + THEN ps.ausbildungssemester::text + ELSE ''::text END AS semester", false); + $this->PrestudentModel->addSelect("'' AS verband"); + $this->PrestudentModel->addSelect("'' AS gruppe"); + $this->addSelectPrioRel(); + + $this->addFilter($studiensemester_kurzbz); + + $result = $this->PrestudentModel->loadWhere($where); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + /** + * @param integer $studiengang_kz + * @param integer $semester (optional) + * @param string $verband (optional) + * @param integer $gruppe (optional) + * @param string $gruppe_kurzbz (optional) + * @param string $orgform_kurzbz (optional) + * + * @return void + */ + protected function getStudents($studiengang_kz, $semester = null, $verband = null, $gruppe = null, $gruppe_kurzbz = null, $orgform_kurzbz = null) + { + $studiensemester_kurzbz = $this->variablelib->getVar('semester_aktuell'); + + + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + /* + $this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_person p', 'person_id'); + $this->PrestudentModel->addJoin('public.tbl_student s', 'prestudent_id'); + $this->PrestudentModel->addJoin('public.tbl_prestudentstatus pls', ' + pls.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) + AND pls.prestudent_id=tbl_prestudent.prestudent_id + AND pls.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, NULL) + AND pls.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)', 'LEFT'); + $this->PrestudentModel->addJoin('lehre.tbl_studienplan sp', 'studienplan_id', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_benutzer b', 's.student_uid=b.uid'); + $this->PrestudentModel->addJoin( + 'public.tbl_studentlehrverband v', + 'v.student_uid=s.student_uid AND v.studiensemester_kurzbz=' . $this->PrestudentModel->escape($studiensemester_kurzbz) + );*/ + $this->prepareQuery($studiensemester_kurzbz, ''); + + $this->PrestudentModel->addSelect('v.semester'); + $this->PrestudentModel->addSelect('v.verband'); + $this->PrestudentModel->addSelect('v.gruppe'); + $this->PrestudentModel->addSelect("'' AS priorisierung_relativ"); + + + $where = []; + + if ($gruppe_kurzbz !== null) { + $this->PrestudentModel->addJoin('public.tbl_benutzergruppe g', 'uid'); + $where['g.gruppe_kurzbz'] = $gruppe_kurzbz; + $where['g.studiensemester_kurzbz'] = $studiensemester_kurzbz; + } else { + $where['v.studiengang_kz'] = $studiengang_kz; + + if ($semester !== null) + $where['v.semester'] = $semester; + + if ($verband !== null) + $where['v.verband'] = $verband; + + if ($gruppe !== null) + $where['v.gruppe'] = $gruppe; + + if (!$verband && !$gruppe && $orgform_kurzbz !== null) { + $this->PrestudentModel->db->where( + "( + SELECT orgform_kurzbz + FROM public.tbl_prestudentstatus + WHERE prestudent_id=tbl_prestudent.prestudent_id + AND studiensemester_kurzbz=" . $this->PrestudentModel->escape($studiensemester_kurzbz) . " + ORDER BY datum DESC, insertamum DESC, ext_id DESC LIMIT 1 + ) =", + $this->PrestudentModel->escape($orgform_kurzbz), + false + ); + } + + } + + $this->addFilter($studiensemester_kurzbz); + + $result = $this->PrestudentModel->loadWhere($where); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + /** + * @param string $prestudent_id + * + * @return void + */ + protected function getPrestudent($prestudent_id) + { + $studiensemester_kurzbz = $this->variablelib->getVar('semester_aktuell'); + + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + /* + $this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_person p', 'person_id'); + $this->PrestudentModel->addJoin('public.tbl_student s', 'prestudent_id', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_prestudentstatus pls', ' + pls.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) + AND pls.prestudent_id=tbl_prestudent.prestudent_id + AND pls.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, NULL) + AND pls.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)', 'LEFT'); + $this->PrestudentModel->addJoin('lehre.tbl_studienplan sp', 'studienplan_id', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_benutzer b', 's.student_uid=b.uid', 'LEFT'); + $this->PrestudentModel->addJoin( + 'public.tbl_studentlehrverband v', + 'v.student_uid=s.student_uid AND v.studiensemester_kurzbz=' . $this->PrestudentModel->escape($studiensemester_kurzbz), + 'LEFT' + );*/ + $this->prepareQuery($studiensemester_kurzbz); + + $this->PrestudentModel->addSelect("COALESCE(v.semester::text, CASE WHEN public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) IN ('Aufgenommener', 'Bewerber', 'Wartender', 'interessent') THEN public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)::text ELSE ''::text END) AS semester", false); + $this->PrestudentModel->addSelect('v.verband'); + $this->PrestudentModel->addSelect('v.gruppe'); + $this->addSelectPrioRel(); + + $this->addFilter($studiensemester_kurzbz); + + $result = $this->PrestudentModel->loadWhere([ + 'tbl_prestudent.prestudent_id' => $prestudent_id + ]); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + /** + * @param string $student_uid + * + * @return void + */ + protected function getStudent($student_uid) + { + $studiensemester_kurzbz = $this->variablelib->getVar('semester_aktuell'); + + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + /* + $this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_person p', 'person_id'); + $this->PrestudentModel->addJoin('public.tbl_student s', 'prestudent_id'); + $this->PrestudentModel->addJoin('public.tbl_prestudentstatus pls', ' + pls.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) + AND pls.prestudent_id=tbl_prestudent.prestudent_id + AND pls.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, NULL) + AND pls.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)', 'LEFT'); + $this->PrestudentModel->addJoin('lehre.tbl_studienplan sp', 'studienplan_id', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_benutzer b', 's.student_uid=b.uid'); + $this->PrestudentModel->addJoin( + 'public.tbl_studentlehrverband v', + 'v.student_uid=s.student_uid AND v.studiensemester_kurzbz=' . $this->PrestudentModel->escape($studiensemester_kurzbz), + 'LEFT' + );*/ + $this->prepareQuery($studiensemester_kurzbz); + + $this->PrestudentModel->addSelect('v.semester'); + $this->PrestudentModel->addSelect('v.verband'); + $this->PrestudentModel->addSelect('v.gruppe'); + $this->addSelectPrioRel(); + + $this->addFilter($studiensemester_kurzbz); + + $result = $this->PrestudentModel->loadWhere([ + 's.student_uid' => $student_uid + ]); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + /** + * @param integer $person_id + * + * @return void + */ + protected function getPerson($person_id) + { + $studiensemester_kurzbz = $this->variablelib->getVar('semester_aktuell'); + + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + + /* + $this->PrestudentModel->addJoin('public.tbl_person p', 'person_id'); + $this->PrestudentModel->addJoin('public.tbl_student s', 'prestudent_id'); + $this->PrestudentModel->addJoin('public.tbl_benutzer b', 's.student_uid=b.uid'); + $this->PrestudentModel->addJoin( + 'public.tbl_studentlehrverband v', + 'v.student_uid=s.student_uid AND v.studiensemester_kurzbz=' . $this->PrestudentModel->escape($studiensemester_kurzbz), + 'LEFT' + );*/ + $this->prepareQuery($studiensemester_kurzbz); + + $this->PrestudentModel->addSelect('v.semester'); + $this->PrestudentModel->addSelect('v.verband'); + $this->PrestudentModel->addSelect('v.gruppe'); + $this->addSelectPrioRel(); + + $this->addFilter($studiensemester_kurzbz); + + $result = $this->PrestudentModel->loadWhere([ + 'p.person_id' => $person_id + ]); + + $data = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($data); + } + + /** + * @param string|null $studiensemester_kurzbz + * @param string $type + * + * @return void + */ + protected function prepareQuery($studiensemester_kurzbz, $type = 'LEFT') + { + $stdsemEsc = $studiensemester_kurzbz ? $this->PrestudentModel->escape($studiensemester_kurzbz) : 'NULL'; + + + $this->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_person p', 'person_id'); + $this->PrestudentModel->addJoin('public.tbl_student s', 'prestudent_id', $type); + $this->PrestudentModel->addJoin('public.tbl_prestudentstatus pls', ' + pls.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) + AND pls.prestudent_id=tbl_prestudent.prestudent_id + AND pls.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, NULL) + AND pls.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, NULL)', 'LEFT'); + $this->PrestudentModel->addJoin('lehre.tbl_studienplan sp', 'studienplan_id', 'LEFT'); + $this->PrestudentModel->addJoin('public.tbl_benutzer b', 's.student_uid=b.uid', 'LEFT'); + $this->PrestudentModel->addJoin( + 'public.tbl_studentlehrverband v', + 'v.student_uid=s.student_uid AND v.studiensemester_kurzbz' . ($studiensemester_kurzbz ? '=' . $stdsemEsc : ' IS NULL'), + $type + ); + $this->PrestudentModel->addJoin('public.tbl_prestudentstatus ps', ' + ps.status_kurzbz=public.get_rolle_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ') + AND ps.prestudent_id=tbl_prestudent.prestudent_id + AND ps.studiensemester_kurzbz=public.get_stdsem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ') + AND ps.ausbildungssemester=public.get_absem_prestudent(tbl_prestudent.prestudent_id, ' . $stdsemEsc . ')', 'LEFT'); + + + $this->PrestudentModel->addSelect("b.uid"); + $this->PrestudentModel->addSelect('titelpre'); + $this->PrestudentModel->addSelect('nachname'); + $this->PrestudentModel->addSelect('vorname'); + $this->PrestudentModel->addSelect('wahlname'); + $this->PrestudentModel->addSelect('vornamen'); + $this->PrestudentModel->addSelect('titelpost'); + $this->PrestudentModel->addSelect('svnr'); + $this->PrestudentModel->addSelect('ersatzkennzeichen'); + $this->PrestudentModel->addSelect('gebdatum'); + $this->PrestudentModel->addSelect('geschlecht'); + + // semester + // verband + // gruppe + + $this->PrestudentModel->addSelect('UPPER(stg.typ || stg.kurzbz) AS studiengang'); + $this->PrestudentModel->addSelect('tbl_prestudent.studiengang_kz'); + $this->PrestudentModel->addSelect("s.matrikelnr"); + $this->PrestudentModel->addSelect('p.person_id'); + $this->PrestudentModel->addSelect('pls.status_kurzbz AS status'); + $this->PrestudentModel->addSelect('pls.datum AS status_datum'); + $this->PrestudentModel->addSelect('pls.bestaetigtam AS status_bestaetigung'); + $this->PrestudentModel->addSelect( + "(SELECT kontakt FROM public.tbl_kontakt WHERE kontakttyp='email' AND person_id=p.person_id AND zustellung LIMIT 1) AS mail_privat", + false + ); + $this->PrestudentModel->addSelect(" + CASE WHEN b.uid IS NOT NULL AND b.uid<>'' + THEN b.uid || " . $this->PrestudentModel->escape(DOMAIN) . " + ELSE '' END AS mail_intern", false); + $this->PrestudentModel->addSelect('p.anmerkung AS anmerkungen'); + $this->PrestudentModel->addSelect('tbl_prestudent.anmerkung'); + $this->PrestudentModel->addSelect('pls.orgform_kurzbz'); + $this->PrestudentModel->addSelect('aufmerksamdurch_kurzbz'); + $this->PrestudentModel->addSelect( + "(SELECT rt_gesamtpunkte AS punkte FROM public.tbl_prestudent WHERE prestudent_id=ps.prestudent_id) AS punkte", + false + ); + $this->PrestudentModel->addSelect('tbl_prestudent.aufnahmegruppe_kurzbz'); + $this->PrestudentModel->addSelect('tbl_prestudent.dual'); + $this->PrestudentModel->addSelect('p.matr_nr'); + $this->PrestudentModel->addSelect('sp.bezeichnung AS studienplan_bezeichnung'); + $this->PrestudentModel->addSelect('tbl_prestudent.prestudent_id'); + + // priorisierung_relativ + + $this->PrestudentModel->addSelect('mentor'); + $this->PrestudentModel->addSelect('b.aktiv AS bnaktiv'); + + /*$this->PrestudentModel->addSelect('tbl_prestudent.reihungstest_id'); + $this->PrestudentModel->addSelect('tbl_prestudent.anmeldungreihungstest'); + $this->PrestudentModel->addSelect('tbl_prestudent.gsstudientyp_kurzbz'); + $this->PrestudentModel->addSelect('tbl_prestudent.priorisierung'); + $this->PrestudentModel->addSelect('p.zugangscode'); + $this->PrestudentModel->addSelect('p.bpk');*/ + + $this->PrestudentModel->db->where_in('tbl_prestudent.studiengang_kz', $this->allowedStgs); + + $this->PrestudentModel->addOrder('nachname'); + $this->PrestudentModel->addOrder('vorname'); + } + + /** + * @return void + */ + protected function addSelectPrioRel() + { + $this->PrestudentModel->addSelect("( + SELECT count(*) + FROM ( + SELECT *, public.get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) AS laststatus + FROM PUBLIC.tbl_prestudent pss + JOIN PUBLIC.tbl_prestudentstatus USING (prestudent_id) + WHERE person_id = p.person_id + AND studiensemester_kurzbz = ( + SELECT studiensemester_kurzbz + FROM PUBLIC.tbl_prestudentstatus + WHERE prestudent_id = tbl_prestudent.prestudent_id + AND status_kurzbz = 'Interessent' + LIMIT 1 + ) + AND status_kurzbz = 'Interessent' + ) prest + WHERE laststatus NOT IN ('Abbrecher', 'Abgewiesener', 'Absolvent') + AND priorisierung <= tbl_prestudent.priorisierung + ) || ' (' || tbl_prestudent.priorisierung || ')' AS priorisierung_relativ", false); + } + + /** + * Adds additional filters to the query + * + * @param string $studiensemester_kurzbz + * + * @return void + */ + protected function addFilter($studiensemester_kurzbz) + { + $filter = $this->input->get('filter'); + if (isset($filter['konto_count_0'])) { + $bt = $this->PrestudentModel->escape($filter['konto_count_0']); + $stdsem = $this->PrestudentModel->escape($studiensemester_kurzbz); + + $this->PrestudentModel->db->where('( + SELECT count(*) + FROM public.tbl_konto + WHERE person_id=tbl_prestudent.person_id + AND buchungstyp_kurzbz=' . $bt . ' + AND studiensemester_kurzbz=' . $stdsem . ' + ) =', 0); + $this->PrestudentModel->db->where('get_rolle_prestudent(tbl_prestudent.prestudent_id, NULL) !=', 'Incoming'); + } + if (isset($filter['konto_missing_counter'])) { + $bt = $this->PrestudentModel->escape($filter['konto_missing_counter']); + $stg = ''; + if ($this->variablelib->getVar('kontofilterstg') == 'true') + $stg = ' AND studiengang_kz=tbl_prestudent.studiengang_kz'; + + $bt = $bt == 'alle' ? '' : ' AND buchungstyp_kurzbz=' . $bt; + + $this->PrestudentModel->db->where('( + SELECT sum(betrag) + FROM public.tbl_konto + WHERE person_id=tbl_prestudent.person_id' . + $bt . + $stg . ' + ) !=', 0); + } + } +} diff --git a/application/controllers/api/frontend/v1/stv/Verband.php b/application/controllers/api/frontend/v1/stv/Verband.php new file mode 100644 index 000000000..e8c532652 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Verband.php @@ -0,0 +1,493 @@ +. + */ + +if (! defined('BASEPATH')) exit('No direct script access allowed'); + +/** + * This controller operates between (interface) the JS (GUI) and the back-end + * Provides data to the ajax get calls about verbände + * This controller works with JSON calls on the HTTP GET or POST and the output is always JSON + */ +class Verband extends FHCAPI_Controller +{ + public function __construct() + { + $permissions = []; + $router = load_class('Router'); + $permissions[$router->method] = ['admin:r', 'assistenz:r']; + parent::__construct($permissions); + + // Load Models + $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); + } + + /** + * Remap calls: + * / + * /(studiengang_kz) => getStudiengang + * /(studiengang_kz)/(semester) => getSemester + * /(studiengang_kz)/(semester)/(verband) => getVerband + * /(studiengang_kz)/(org_form) => getStudiengang + * /(studiengang_kz)/(org_form)/(semester) => getSemester + * /(studiengang_kz)/(org_form)/(semester)/(verband) => getVerband + * + * @param string $method + * @param array $params (optional) + * + * @return void + */ + public function _remap($method, $params = []) + { + if ($method == '' || $method == 'index') + return $this->getBase(); + + // NOTE(chris): Test if access is allowed ($method is the Studiengang) + if (!$this->permissionlib->isBerechtigt('assistenz', 's', $method) + && !$this->permissionlib->isBerechtigt('admin', 's', $method) + ) { + return $this->_outputAuthError([$method => ['admin:r', 'assistenz:r']]); + } + + $count = count($params); + if (!$count) + return $this->getStudiengang($method); + + if ($count == 1) { + if (is_numeric($params[0])) + return $this->getSemester($method, $params[0]); + elseif ($params[0] == 'prestudent') + return $this->terminateWithSuccess($this->getStdSem($method . '/prestudent/', $method)); + else + return $this->getStudiengang($method, $params[0]); + } + if ($count == 2) { + if (is_numeric($params[0])) + return $this->getVerband($method, $params[0], $params[1]); + elseif ($params[1] == 'prestudent') + return $this->terminateWithSuccess($this->getStdSem($method . '/' . $params[0] . '/prestudent/', $method)); + else + return $this->getSemester($method, $params[1], $params[0]); + } + if ($count == 3 && !is_numeric($params[0]) && is_numeric($params[1]) && !is_numeric($params[2])) + return $this->getVerband($method, $params[1], $params[2], $params[0]); + + show_404(); + } + + /** + * @return void + */ + protected function getBase() + { + $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); + + $this->StudiengangModel->addDistinct(); + $this->StudiengangModel->addSelect("v.studiengang_kz AS link"); + $this->StudiengangModel->addSelect( + "CONCAT(kurzbzlang, ' (', UPPER(CONCAT(typ, kurzbz)), ') - ', tbl_studiengang.bezeichnung) AS name", + false + ); + $this->StudiengangModel->addSelect('erhalter_kz'); + $this->StudiengangModel->addSelect('typ'); + $this->StudiengangModel->addSelect('kurzbz'); + $this->StudiengangModel->addSelect('studiengang_kz'); + $this->StudiengangModel->addSelect('studiengang_kz AS stg_kz'); + + $this->StudiengangModel->addOrder('erhalter_kz'); + $this->StudiengangModel->addOrder('typ'); + $this->StudiengangModel->addOrder('kurzbz'); + + $stgs = $this->permissionlib->getSTG_isEntitledFor('admin') ?: []; + $stgs = array_merge($stgs, $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []); + + if (!$stgs) + $this->terminateWithSuccess([]); + + $this->StudiengangModel->db->where_in('studiengang_kz', $stgs); + + $result = $this->StudiengangModel->loadWhere(['v.aktiv' => true]); + + $list = $this->getDataOrTerminateWithError($result); + + if ($this->permissionlib->isBerechtigt('inout/uebersicht')) + $list[] = [ + 'name' => 'International', + 'link' => 'inout', + 'children' => [ + [ + 'name' => 'Incoming', + 'link' => 'inout/incoming', + 'leaf' => true + ], + [ + 'name' => 'Outgoing', + 'link' => 'inout/outgoing', + 'leaf' => true + ], + [ + 'name' => 'Gemeinsame Studien', + 'link' => 'inout/gemeinsamestudien', + 'leaf' => true + ] + ] + ]; + $this->terminateWithSuccess($list); + } + + /** + * @param integer $studiengang_kz + * @param string $orgform (optional) + * + * @return void + */ + 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('semester'); + $this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); + + $this->StudiengangModel->addOrder('semester'); + + if ($org_form !== null) { + $this->StudiengangModel->db->group_start(); + $this->StudiengangModel->db->where('v.semester', 0); + $this->StudiengangModel->db->or_where('v.orgform_kurzbz', $org_form); + $this->StudiengangModel->db->group_end(); + } + + $result = $this->StudiengangModel->loadWhere([ + 'v.studiengang_kz' => $studiengang_kz, + 'v.aktiv' => true + ]); + $list = $this->getDataOrTerminateWithError($result); + + array_unshift($list, [ + 'name' => 'PreStudent', + 'link' => $link . 'prestudent', + 'children' => $this->getStdSem($link . 'prestudent/', $studiengang_kz) + ]); + + if ($org_form === null) { + // NOTE(chris): if mischform show orgforms + $result = $this->StudiengangModel->load($studiengang_kz); + $result = $this->getDataOrTerminateWithError($result); + if ($result) { + if (current($result)->mischform) { + $this->load->model('organisation/Studienordnung_model', 'StudienordnungModel'); + + $this->StudienordnungModel->addDistinct(); + $this->StudienordnungModel->addSelect("CONCAT(studiengang_kz, '/', p.orgform_kurzbz) AS link"); + $this->StudienordnungModel->addSelect("p.orgform_kurzbz AS name"); + + $this->StudienordnungModel->addJoin('lehre.tbl_studienplan p', 'studienordnung_id'); + + $result = $this->StudienordnungModel->loadWhere([ + 'aktiv' => true, + 'studiengang_kz' => $studiengang_kz, + 'p.orgform_kurzbz !=' => 'DDP' + ]); + $result = $this->getDataOrTerminateWithError($result); + + $list = array_merge($list, $result); + } + } + + } + $this->terminateWithSuccess($list); + } + + /** + * @param integer $studiengang_kz + * @param integer $semester + * @param string $orgform + * + * @return void + */ + 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('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); + } + + /** + * @param integer $studiengang_kz + * @param integer $semester + * @param integer $verband + * @param string $orgform + * + * @return void + */ + 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('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) // NOTE(chris): on semester 0 show all? + $where['v.orgform_kurzbz'] = $org_form; + + $result = $this->StudiengangModel->loadWhere($where); + + $list = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($list); + } + + /** + * @param string $link + * @param integer $studiengang_kz + * + * @return array + */ + protected function getStdSem($link, $studiengang_kz) + { + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $this->load->model('system/Variable_model', 'VariableModel'); + $result = $this->VariableModel->getVariables(getAuthUID(), ['number_displayed_past_studiensemester']); + $data = $this->getDataOrTerminateWithError($result); + $number_displayed_past_studiensemester = $data['number_displayed_past_studiensemester'] ?? null; + + $this->StudiensemesterModel->addPlusMinus(null, $number_displayed_past_studiensemester); + $this->StudiensemesterModel->addOrder('ende'); + $result = $this->StudiensemesterModel->load(); + + $studiensemester = $this->getDataOrTerminateWithError($result); + $result = []; + + $studiengang_kz = (int)$studiengang_kz; + + foreach ($studiensemester as $sem) { + $semlink = $link . $sem->studiensemester_kurzbz; + $intlink = $semlink . '/interessenten'; + $result[] = [ + 'name' => $sem->studiensemester_kurzbz, + 'link' => $semlink, + 'stg_kz' => $studiengang_kz, + 'children' => [ + [ + 'name' => 'Interessenten', + 'link' => $intlink, + 'stg_kz' => $studiengang_kz, + 'children' => [ + [ + 'name' => 'Bewerbung nicht abgeschickt', + 'link' => $intlink . '/bewerbungnichtabgeschickt', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ], + [ + 'name' => 'Bewerbung abgeschickt, Status unbestätigt', + 'link' => $intlink . '/bewerbungabgeschickt', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ], + [ + 'name' => 'ZGV erfüllt', + 'link' => $intlink . '/zgv', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ], + [ + 'name' => 'Status bestätigt', + 'link' => $intlink . '/statusbestaetigt', + 'stg_kz' => $studiengang_kz, + 'children' => [ + [ + 'name' => 'Nicht zum Reihungstest angemeldet', + 'link' => $intlink . '/statusbestaetigtrtnichtangemeldet', + 'leaf' => true + ], + [ + 'name' => 'Reihungstest angemeldet', + 'link' => $intlink . '/statusbestaetigtrtangemeldet', + 'leaf' => true + ] + ] + ], + [ + 'name' => 'Nicht zum Reihungstest angemeldet', + 'link' => $intlink . '/reihungstestnichtangemeldet', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ], + [ + 'name' => 'Reihungstest angemeldet', + 'link' => $intlink . '/reihungstestangemeldet', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ] + ] + ], + [ + 'name' => 'Bewerber', + 'link' => $semlink . '/bewerber', + 'stg_kz' => $studiengang_kz, + 'children' => [ + [ + 'name' => 'Nicht zum Reihungstest angemeldet', + 'link' => $intlink . '/bewerberrtnichtangemeldet', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ], + [ + 'name' => 'Reihungstest angemeldet', + 'link' => $intlink . '/bewerberrtangemeldet', + 'stg_kz' => $studiengang_kz, + 'children' => [ + [ + 'name' => 'Teilgenommen', + 'link' => $intlink . '/bewerberrtangemeldetteilgenommen', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ], + [ + 'name' => 'Nicht teilgenommen', + 'link' => $intlink . '/bewerberrtangemeldetnichtteilgenommen', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ] + ] + ] + ] + ], + [ + 'name' => 'Aufgenommen', + 'link' => $semlink . '/aufgenommen', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ], + [ + 'name' => 'Warteliste', + 'link' => $semlink . '/warteliste', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ], + [ + 'name' => 'Absage', + 'link' => $semlink . '/absage', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ], + [ + 'name' => 'Incoming', + 'link' => $semlink . '/incoming', + 'stg_kz' => $studiengang_kz, + 'leaf' => true + ] + ] + ]; + } + + return $result; + } +} diff --git a/application/controllers/components/stv/Noten.php b/application/controllers/components/stv/Noten.php new file mode 100644 index 000000000..fb61de065 --- /dev/null +++ b/application/controllers/components/stv/Noten.php @@ -0,0 +1,168 @@ + 'student/noten:r', + 'getZeugnis' => 'student/noten:r', + 'update' => ['admin:w', 'assistenz:w'] + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + } + + public function get() + { + $this->load->model('codex/Note_model', 'NoteModel'); + + $result = $this->NoteModel->addOrder('note'); + + $result = $this->NoteModel->load(); + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + } + + return $this->outputJson($result); + } + + public function getZeugnis($prestudent_id, $all = null) + { + $this->load->model('crm/Student_model', 'StudentModel'); + $this->load->model('education/Zeugnisnote_model', 'ZeugnisnoteModel'); + + $result = $this->StudentModel->loadWhere([ + 'prestudent_id' => $prestudent_id + ]); + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + return $this->outputJson($result); + } + if (!hasData($result)) + return $this->outputJsonSuccess(null); + + $student_uid = current(getData($result))->student_uid; + + $studiensemester_kurzbz = ($all === null) ? $this->variablelib->getVar('semester_aktuell') : null; + + $result = $this->ZeugnisnoteModel->getZeugnisnoten($student_uid, $studiensemester_kurzbz); + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + } + + return $this->outputJson($result); + } + + public function update() + { + $this->load->model('crm/Student_model', 'StudentModel'); + $this->load->model('organisation/Studienplan_model', 'StudienplanModel'); + $this->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); + $this->load->model('education/Zeugnisnote_model', 'ZeugnisnoteModel'); + + $this->load->library('form_validation'); + + $_POST = json_decode(utf8_encode($this->input->raw_input_stream), true); + + if (empty($_POST) || !is_array(current($_POST))) { + $result = $this->hasPermissionUpdate($this->input->post('lehrveranstaltung_id'), $this->input->post('student_uid')); + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_FORBIDDEN); + return $this->outputJson($result); + } + + $this->form_validation->set_rules('lehrveranstaltung_id', 'Lehrverantaltung ID', 'required|numeric'); + $this->form_validation->set_rules('student_uid', 'Student UID', 'required'); + $this->form_validation->set_rules('studiensemester_kurzbz', 'Studiensemester Kurzbezeichnung', 'required'); + $this->form_validation->set_rules('note', 'Note', 'required|numeric'); + $post = [$_POST]; + } else { + foreach ($_POST as $i => $data) { + $lvid = isset($data['lehrveranstaltung_id']) ? $data['lehrveranstaltung_id'] : null; + $uid = isset($data['student_uid']) ? $data['student_uid'] : null; + $result = $this->hasPermissionUpdate($lvid, $uid); + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_FORBIDDEN); + return $this->outputJson($result); + } + + $this->form_validation->set_rules($i . '[lehrveranstaltung_id]', '#' . $i . ' Lehrverantaltung ID', 'required|numeric'); + $this->form_validation->set_rules($i . '[student_uid]', '#' . $i . ' Student UID', 'required'); + $this->form_validation->set_rules($i . '[studiensemester_kurzbz]', '#' . $i . ' Studiensemester Kurzbezeichnung', 'required'); + $this->form_validation->set_rules($i . '[note]', '#' . $i . ' Note', 'required|numeric'); + } + $post = $_POST; + } + if ($this->form_validation->run() == false) { + $this->output->set_status_header(REST_Controller::HTTP_BAD_REQUEST); + return $this->outputJsonError($this->form_validation->error_array()); + } + + $final_result = success(); + $this->ZeugnisnoteModel->db->trans_start(); + + foreach ($post as $i => $data) { + $note = $data['note']; + unset($data['note']); + $result = $this->ZeugnisnoteModel->update($data, [ + 'note' => $note, + 'benotungsdatum' => date('c'), + 'updateamum' => date('c'), + 'updatevon' => getAuthUID() + ]); + if (isError($result)) { + $final_result = $result; + break; + } + } + + $this->ZeugnisnoteModel->db->trans_complete(); + + if (isError($final_result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + } + + $this->outputJson($final_result); + } + + protected function hasPermissionUpdate($lehrveranstaltung_id, $student_uid) + { + // TODO(chris): error phrases! + if ($lehrveranstaltung_id === null || $student_uid === null) + return success(); + $result = $this->StudentModel->load([$student_uid]); + if (isError($result)) + return $result; + if (!hasData($result)) + return error('Fehler beim Ermitteln des Studenten'); + $student = current(getData($result)); + + if ($this->permissionlib->isBerechtigt('admin', 'suid', $student->studiengang_kz)) + return success(); + if ($this->permissionlib->isBerechtigt('assistenz', 'suid', $student->studiengang_kz)) + return success(); + + $result = $this->StudienplanModel->getAllOesForLv($lehrveranstaltung_id); + if (isError($result)) + return $result; + $oes = getData($result) ?: []; + $result = $this->LehrveranstaltungModel->getStg($lehrveranstaltung_id); + if (isError($result)) + return $result; + if (hasData($result)) + $oes[] = current(getData($result)); + + foreach ($oes as $oe) { + if ($this->permissionlib->isBerechtigt('admin', 'suid', $oe->oe_kurzbz)) + return success(); + if ($this->permissionlib->isBerechtigt('assistenz', 'suid', $oe->oe_kurzbz)) + return success(); + } + + return error('Forbidden'); + } +} diff --git a/application/controllers/components/stv/Studienplan.php b/application/controllers/components/stv/Studienplan.php new file mode 100644 index 000000000..b60388ac1 --- /dev/null +++ b/application/controllers/components/stv/Studienplan.php @@ -0,0 +1,43 @@ + self::PERM_LOGGED + ]); + } + + public function get() + { + $this->load->model('organisation/Studienplan_model', 'StudienplanModel'); + + $_POST = json_decode($this->input->raw_input_stream, true); + + $this->load->library('form_validation'); + + $this->form_validation->set_rules('studiengang_kz', 'StudiengangKz', 'required|numeric'); + $this->form_validation->set_rules('studiensemester_kurzbz', 'StudiensemesterKurbz', 'required'); + $this->form_validation->set_rules('ausbildungssemester', 'Ausbildungssemester', 'numeric'); + + if ($this->form_validation->run() == false) { + $this->output->set_status_header(REST_Controller::HTTP_BAD_REQUEST); + return $this->outputJsonError($this->form_validation->error_array()); + } + + $studiengang_kz = $this->input->post('studiengang_kz'); + $studiensemester_kurzbz = $this->input->post('studiensemester_kurzbz'); + $ausbildungssemester = $this->input->post('ausbildungssemester') ?: null; + $orgform_kurzbz = $this->input->post('orgform_kurzbz') ?: null; + + $result = $this->StudienplanModel->getStudienplaeneBySemester($studiengang_kz, $studiensemester_kurzbz, $ausbildungssemester, $orgform_kurzbz); + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + } + $this->outputJson($result); + } +} diff --git a/application/controllers/components/stv/Studiensemester.php b/application/controllers/components/stv/Studiensemester.php new file mode 100644 index 000000000..c3db99686 --- /dev/null +++ b/application/controllers/components/stv/Studiensemester.php @@ -0,0 +1,78 @@ + self::PERM_LOGGED, + 'now' => self::PERM_LOGGED, + 'set' => self::PERM_LOGGED + ]); + } + + public function index() + { + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $this->StudiensemesterModel->addOrder('start'); + + $result = $this->StudiensemesterModel->load(); + + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + } + $this->outputJson($result); + } + + public function now() + { + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $result = $this->StudiensemesterModel->getNearest(); + + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + $this->outputJson(getError($result)); + } + $result = getData($result) ?: []; + + if (count($result) != 1) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + $this->outputJsonError(count($result) ? 'Mehrere Studiensemester aktiv' : 'Kein Studiensemester aktiv'); + } else { + $this->outputJsonSuccess(current($result)->studiensemester_kurzbz); + } + } + + public function set() + { + $this->load->library('AuthLib'); + $this->load->library('form_validation'); + + $_POST = json_decode(utf8_encode($this->input->raw_input_stream), true); + + $this->form_validation->set_rules('studiensemester', 'Studiensemester', 'required'); + + if ($this->form_validation->run() == false) { + $this->output->set_status_header(REST_Controller::HTTP_BAD_REQUEST); + return $this->outputJsonError($this->form_validation->error_array()); + } + + $stdsem = $this->input->post('studiensemester'); + + $this->load->model('system/Variable_model', 'VariableModel'); + + $result = $this->VariableModel->setVariable(getAuthUID(), 'semester_aktuell', $stdsem); + + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + return $this->outputJson($result); + } + + $this->outputJsonSuccess(true); + } +} diff --git a/application/controllers/jobs/AntragJob.php b/application/controllers/jobs/AntragJob.php index 717561589..46a31f3d6 100755 --- a/application/controllers/jobs/AntragJob.php +++ b/application/controllers/jobs/AntragJob.php @@ -29,6 +29,10 @@ class AntragJob extends JOB_Controller $this->load->model('crm/Student_model', 'StudentModel'); $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + $this->loadPhrases([ + 'lehre' + ]); } /** @@ -412,10 +416,12 @@ class AntragJob extends JOB_Controller $this->StudierendenantragModel->addSelect('studiensemester_kurzbz'); $this->StudierendenantragModel->addSelect('s.insertamum'); $this->StudierendenantragModel->addSelect('s.insertvon'); + $this->StudierendenantragModel->addJoin('public.tbl_student pts', 'prestudent_id'); + $this->StudierendenantragModel->addSelect('pts.student_uid'); $this->StudierendenantragModel->db->where_in( 'public.get_rolle_prestudent(prestudent_id, studiensemester_kurzbz)', - $this->config->item('antrag_prestudentstatus_whitelist') + $this->config->item('antrag_prestudentstatus_whitelist_abmeldung') ); $result = $this->StudierendenantragModel->getWithLastStatusWhere([ @@ -449,11 +455,23 @@ class AntragJob extends JOB_Controller if (isError($result)) $this->logError(getError($result)); + $this->load->model('crm/Statusgrund_model', 'StatusgrundModel'); + $result = $this->StatusgrundModel->loadWhere(['statusgrund_kurzbz' => 'abbrecherStgl']); + if (isError($result)) { + $this->logError(getError($result)); + continue; + } elseif (!hasData($result)) { + $this->logError($this->p->t('lehre', 'error_noStatusgrund', ['statusgrund_kurzbz' => 'abbrecherStgl'])); + continue; + } + + $statusgrund = current(getData($result)); + $result = $this->prestudentlib->setAbbrecher( $antrag->prestudent_id, $antrag->studiensemester_kurzbz, 'AntragJob', - 'abbrecherStgl', + $statusgrund->statusgrund_id, $antrag->insertamum, null, $antrag->insertvon ?: $insertvon @@ -484,7 +502,7 @@ class AntragJob extends JOB_Controller $person = current(getData($result)); $email = $studiengang->email; $dataMail = array( - 'prestudent' => $antrag->prestudent_id, + 'prestudent' => 'UID: ' . $antrag->student_uid . ', PreStudentId: ' . $antrag->prestudent_id, 'studiensemester' => $antrag->studiensemester_kurzbz, 'name' => trim($person->vorname . ' '. $person->nachname), ); diff --git a/application/controllers/jobs/IssueResolver.php b/application/controllers/jobs/IssueResolver.php index cf97b7f68..be66a6b23 100755 --- a/application/controllers/jobs/IssueResolver.php +++ b/application/controllers/jobs/IssueResolver.php @@ -45,6 +45,7 @@ class IssueResolver extends IssueResolver_Controller 'CORE_STUDENTSTATUS_0013' => 'CORE_STUDENTSTATUS_0013', 'CORE_STUDENTSTATUS_0014' => 'CORE_STUDENTSTATUS_0014', 'CORE_STUDENTSTATUS_0015' => 'CORE_STUDENTSTATUS_0015', + 'CORE_STUDENTSTATUS_0016' => 'CORE_STUDENTSTATUS_0016', 'CORE_PERSON_0001' => 'CORE_PERSON_0001', 'CORE_PERSON_0002' => 'CORE_PERSON_0002', 'CORE_PERSON_0003' => 'CORE_PERSON_0003', diff --git a/application/controllers/lehre/anrechnung/RequestAnrechnung.php b/application/controllers/lehre/anrechnung/RequestAnrechnung.php index 3cba756cf..ebc272e3e 100755 --- a/application/controllers/lehre/anrechnung/RequestAnrechnung.php +++ b/application/controllers/lehre/anrechnung/RequestAnrechnung.php @@ -111,8 +111,13 @@ class requestAnrechnung extends Auth_Controller $lehrveranstaltung_id = $this->input->post('lv_id'); $studiensemester_kurzbz = $this->input->post('studiensemester'); $bestaetigung = $this->input->post('bestaetigung'); - $begruendung_ects = $this->input->post('begruendung_ects'); - $begruendung_lvinhalt = $this->input->post('begruendung_lvinhalt'); + $begruendung_ects = $this->config->item('explain_equivalence') === TRUE + ? $this->input->post('begruendung_ects') + : NULL; + $begruendung_lvinhalt = $this->config->item('explain_equivalence') === TRUE + ? $this->input->post('begruendung_lvinhalt') + : NULL; + // Validate data if (empty($_FILES['uploadfile']['name'])) @@ -124,8 +129,8 @@ class requestAnrechnung extends Auth_Controller isEmptyString($anmerkung) || isEmptyString($lehrveranstaltung_id) || isEmptyString($studiensemester_kurzbz) || - isEmptyString($begruendung_ects) || - isEmptyString($begruendung_lvinhalt)) + ($this->config->item('explain_equivalence') === TRUE && isEmptyString($begruendung_ects)) || + ($this->config->item('explain_equivalence') === TRUE && isEmptyString($begruendung_lvinhalt))) { return $this->outputJsonError($this->p->t('ui', 'errorFelderFehlen')); } @@ -168,7 +173,7 @@ class requestAnrechnung extends Auth_Controller // Hold just inserted DMS ID $lastInsert_dms_id = $result->retval['dms_id']; - + // Save Anrechnung and Anrechnungstatus $result = $this->AnrechnungModel->createAnrechnungsantrag( $prestudent_id, diff --git a/application/controllers/system/MigrateContract.php b/application/controllers/system/MigrateContract.php index f011be356..817eaa4f0 100644 --- a/application/controllers/system/MigrateContract.php +++ b/application/controllers/system/MigrateContract.php @@ -16,7 +16,9 @@ class MigrateContract extends CLI_Controller { private $matching_ba1_vertragsart; - private $OE_DEFAULT = 'gst'; + private $OE_DEFAULT; + + protected $configerrors; /** * Constructor @@ -28,29 +30,70 @@ class MigrateContract extends CLI_Controller $this->load->model('codex/bisverwendung_model', 'BisVerwendungModel'); $this->load->model('person/benutzerfunktion_model', 'BenutzerfunktionModel'); - $this->matching_ba1_vertragsart = array( - '101'=>'externerlehrender', - '102'=>'DV anderen Gebietskörperschaft', - '103'=>'echterdv', - '104'=>'studentischehilfskr', - '105'=>'externerlehrender', - '106'=>'Andere Bildungseinrichtung', - '107'=>'werkvertrag', - '108'=>'studentischehilfskr', - '109'=>'ueberlassungsvertrag', - '110'=>'echterfreier', - '111'=>'echterdv', //All-In - ); + $this->load->config('migratecontract'); + + $this->OE_DEFAULT = $this->config->item('migratecontract_oe_default'); + $this->matching_ba1_vertragsart = $this->config->item('migratecontract_matching_ba1_vertragsart'); + $this->configerrors = array(); } // ----------------------------------------------------------------------------------------------------------------- // Public methods + public function checkConfig() + { + echo "OE_DEFAULT: " . $this->OE_DEFAULT . "\n"; + echo "matching_ba1_vertragsart: " . print_r($this->matching_ba1_vertragsart, true); + + $this->checkOE_DEFAULT(); + $this->checkMatching_ba1_vertragsart(); + + if( count($this->configerrors) > 0 ) + { + foreach($this->configerrors AS $configerror) + { + echo $configerror . "\n"; + } + die("Fehler in der Konfiguration. Abbruch!\n"); + } + else + { + echo "Konfiguration OK.\n"; + } + } + + protected function checkOE_DEFAULT() + { + $db = new DB_Model(); + $oesql = 'SELECT * FROM public.tbl_organisationseinheit WHERE oe_kurzbz = ?'; + $oeres = $db->execReadOnlyQuery($oesql, array($this->OE_DEFAULT)); + if( !hasData($oeres) ) + { + $this->configerrors[] = 'Default Organisationseinheit: "' + . $this->OE_DEFAULT . '" nicht gefunden.'; + } + } + + protected function checkMatching_ba1_vertragsart() { + $db = new DB_Model(); + foreach( $this->matching_ba1_vertragsart AS $vertragsart_kurzbz ) + { + $vasql = 'SELECT * FROM hr.tbl_vertragsart WHERE vertragsart_kurzbz = ?'; + $vares = $db->execReadOnlyQuery($vasql, array($vertragsart_kurzbz)); + if( !hasData($vares) ) + { + $this->configerrors[] = 'Vertragsart "' . $vertragsart_kurzbz + . '" nicht gefunden.'; + } + } + } /** * Everything has a beginning */ public function index($user = null) { + $this->checkConfig(); + if (!is_null($user)) { $contracts = $this->_transformUser($user); @@ -400,6 +443,11 @@ class MigrateContract extends CLI_Controller */ private function _addVertragsbestandteilZeitaufzeichnung(&$contracts, $dv, $row_verwendung) { + if( is_null($row_verwendung->zeitaufzeichnungspflichtig) || is_null($row_verwendung->azgrelevant) ) + { + return; + } + if (isset($contracts['dv'][$dv]['vbs'])) { foreach ($contracts['dv'][$dv]['vbs'] as $index_vbs=>$row_vbs) diff --git a/application/controllers/system/MigrateHourlyRate.php b/application/controllers/system/MigrateHourlyRate.php index 4fed2f585..dbc8f1416 100644 --- a/application/controllers/system/MigrateHourlyRate.php +++ b/application/controllers/system/MigrateHourlyRate.php @@ -4,14 +4,15 @@ if (! defined('BASEPATH')) exit('No direct script access allowed'); class MigrateHourlyRate extends CLI_Controller { - - CONST DEFAULT_OE = 'gst'; CONST DEFAULT_DATE = '1970-01-01'; CONST STUNDENSTAZTYP_LEHRE = 'lehre'; CONST STUNDENSTAZTYP_KALKULATORISCH = 'kalkulatorisch'; + private $OE_DEFAULT; private $_ci; + protected $configerrors; + public function __construct() { parent::__construct(); @@ -21,10 +22,38 @@ class MigrateHourlyRate extends CLI_Controller $this->load->model('codex/Bisverwendung_model', 'BisVerwendungModel'); $this->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel'); $this->load->model('ressource/Stundensatz_model', 'StundensatzModel'); + + $this->load->config('migratecontract'); + + $this->OE_DEFAULT = $this->config->item('migratecontract_oe_default'); + $this->configerrors = array(); + } + + public function checkConfig() + { + echo "OE_DEFAULT: " . $this->OE_DEFAULT . "\n"; + + $this->checkOE_DEFAULT(); + + if( count($this->configerrors) > 0 ) + { + foreach($this->configerrors AS $configerror) + { + echo $configerror . "\n"; + } + die("Fehler in der Konfiguration. Abbruch!\n"); + } + else + { + echo "Konfiguration OK.\n"; + } } public function index($user = null) { + $this->checkConfig(); + + echo "Lehre Stundensaetze werden migriert.\n"; $mitarbeiterResult = $this->_getMitarbeiterStunden($user); if (isError($mitarbeiterResult)) return $mitarbeiterResult; if (!hasData($mitarbeiterResult)) return error('Keine Mitarbeiterstunden gefunden'); @@ -38,20 +67,71 @@ class MigrateHourlyRate extends CLI_Controller if (isError($insertResult)) return $insertResult; } - $sapResult = $this->_getSapStunden($user); - if (isError($sapResult)) return $sapResult; - if (!hasData($sapResult)) return error('Keinen kalkulatorischen Stundensaetze gefunden'); - - $mitarbeiterArray = getData($sapResult); - - foreach ($mitarbeiterArray as $mitarbeiter) + if( $this->checkIfSAPSyncTableExists() ) { - $this->_getUnternehmen($mitarbeiter); - $insertResult = $this->_addStundensatz($mitarbeiter, self::STUNDENSTAZTYP_KALKULATORISCH, date_format(date_create($mitarbeiter->beginn), 'Y-m-d')); - if (isError($insertResult)) return $insertResult; + echo "SAP Sync Tabelle gefunden. SAP Stundensaetze werden migriert.\n"; + $sapResult = $this->_getSapStunden($user); + if (isError($sapResult)) return $sapResult; + if (!hasData($sapResult)) return error('Keinen kalkulatorischen Stundensaetze gefunden'); + + $mitarbeiterArray = getData($sapResult); + + foreach ($mitarbeiterArray as $mitarbeiter) + { + $this->_getUnternehmen($mitarbeiter); + $insertResult = $this->_addStundensatz($mitarbeiter, self::STUNDENSTAZTYP_KALKULATORISCH, date_format(date_create($mitarbeiter->beginn), 'Y-m-d')); + if (isError($insertResult)) return $insertResult; + } + } + else + { + echo "SAP Sync Tabelle nicht gefunden. Ignoriere SAP Stundensaetze.\n"; } } + protected function checkOE_DEFAULT() + { + $db = new DB_Model(); + $oesql = 'SELECT * FROM public.tbl_organisationseinheit WHERE oe_kurzbz = ?'; + $oeres = $db->execReadOnlyQuery($oesql, array($this->OE_DEFAULT)); + if( !hasData($oeres) ) + { + $this->configerrors[] = 'Default Organisationseinheit: "' + . $this->OE_DEFAULT . '" nicht gefunden.'; + } + } + + protected function checkIfSAPSyncTableExists() + { + $dbModel = new DB_Model(); + $params = array( + DB_NAME, + 'sync', + 'tbl_sap_stundensatz' + ); + + $sql = "SELECT + 1 AS exists + FROM + information_schema.tables + WHERE + table_catalog = ? AND + table_schema = ? AND + table_name = ?"; + + $res = $dbModel->execReadOnlyQuery($sql, $params); + + if( hasData($res) ) + { + return true; + } + else + { + return false; + } + } + + private function _getSapStunden($user = null) { $dbModel = new DB_Model(); @@ -127,7 +207,7 @@ class MigrateHourlyRate extends CLI_Controller $unternehmenResult = $this->_findUnternehmen($mitarbeiter->uid, "'kstzuordnung', 'oezuordnung'"); } - $unternehmen = self::DEFAULT_OE; + $unternehmen = $this->OE_DEFAULT; if (hasData($unternehmenResult)) $unternehmen = getData($unternehmenResult)[0]->oe_kurzbz; diff --git a/application/core/Auth_Controller.php b/application/core/Auth_Controller.php index d170a7eca..466627fe3 100755 --- a/application/core/Auth_Controller.php +++ b/application/core/Auth_Controller.php @@ -67,6 +67,108 @@ abstract class Auth_Controller extends FHC_Controller } } + /** + * Checks for Permissions depending if the given person is a + * Mitarbeiter and/or Student + * and exits/outputs an error if they are not met. + * + * @param integer $person_id + * @param array $permMa Perms if the person is a Mitarbeiter + * @param array $permStud Perms if the person is a Student + * + * @return void + */ + protected function checkPermissionsForPerson($person_id, $permMa, $permStud) + { + $res = $this->hasPermissionsForPerson($person_id, $permMa, $permStud); + + if ($res) { + $perm = array_keys(array_flip(array_merge($res|1 ? $permMa : [], $res|2 ? $permStud : []))); + $this->_outputAuthError([$this->router->method => $perm]); + } + } + + /** + * Checks for Permissions depending on the Studiengang of a Prestudent + * and exits/outputs an error if they are not met. + * + * @param integer $prestudent_id + * @param array $permStud Perms if the person is a Student + * + * @return void + */ + protected function checkPermissionsForPrestudent($prestudent_id, $permStud) + { + if (!$this->hasPermissionsForPrestudent($prestudent_id, $permStud)) { + $this->_outputAuthError([$this->router->method => $permStud]); + } + } + + /** + * Checks for Permissions depending if the given person is a + * Mitarbeiter and/or Student + * and returns the result. + * + * @param integer $person_id + * @param array $permMa Perms if the person is a Mitarbeiter + * @param array $permStud Perms if the person is a Student + * + * @return integer 0 if permission is granted + */ + protected function hasPermissionsForPerson($person_id, $permMa, $permStud) + { + $res = 3; + $this->load->model('person/Person_model', 'PersonModel'); + $this->PersonModel->addJoin('public.tbl_benutzer', 'person_id'); + $this->PersonModel->addJoin('public.tbl_mitarbeiter', 'uid = mitarbeiter_uid'); + $result = $this->PersonModel->load($person_id); + if (hasData($result)) { + if ($this->permissionlib->isEntitled(['a' => $permMa], 'a')) + return 0; + $res = 1; + } + $this->PersonModel->addJoin('public.tbl_prestudent', 'person_id'); + $result = $this->PersonModel->load($person_id); + if (hasData($result)) { + $permStudConverted = []; + foreach (getData($result) as $row) { + foreach ($permStud as $k => $v) { + if (!isset($permStudConverted[$k])) { + $permStudConverted[$k] = $this->permissionlib->convertAccessType($v); + } + if ($this->permissionlib->isBerechtigt($permStudConverted[$k][0], $permStudConverted[$k][1], $row->studiengang_kz)) + return 0; + } + } + $res += 2; + } + return $res; + } + + /** + * Checks for Permissions depending on the Studiengang of a Prestudent + * and returns the result. + * + * @param integer $prestudent_id + * @param array $permStud Perms if the person is a Student + * + * @return boolean + */ + protected function hasPermissionsForPrestudent($prestudent_id, $permStud) + { + $this->load->model('crm/Prestudent_model', 'PrestudentModel'); + $result = $this->PrestudentModel->load($prestudent_id); + if (!hasData($result)) + show_404(); + $stg = current(getData($result))->studiengang_kz; + foreach ($permStud as $k => $v) { + $perm = $this->permissionlib->convertAccessType($v); + if ($this->permissionlib->isBerechtigt($perm[0], $perm[1], $stg)) + return true; + } + return false; + } + /** * Outputs an error message and sets the HTTP Header. * This function is protected so that it can be overwritten. diff --git a/application/core/DB_Model.php b/application/core/DB_Model.php index 901587893..36de01a4a 100755 --- a/application/core/DB_Model.php +++ b/application/core/DB_Model.php @@ -830,6 +830,23 @@ class DB_Model extends CI_Model return $result; } + public function getDbTable() + { + return $this->dbTable; + } + + public function getPk() + { + return $this->pk; + } + + public function getPks() + { + if (is_array($this->pk)) + return $this->pk; + return [$this->pk]; + } + // ------------------------------------------------------------------------------------------ // Protected methods diff --git a/application/core/FHCAPI_Controller.php b/application/core/FHCAPI_Controller.php index 647032795..36388e271 100644 --- a/application/core/FHCAPI_Controller.php +++ b/application/core/FHCAPI_Controller.php @@ -94,7 +94,7 @@ class FHCAPI_Controller extends Auth_Controller // --------------------------------------------------------------- /** - * @param array $data + * @param string|array|object $data * @param string $type (optional) * @return void */ @@ -110,6 +110,8 @@ class FHCAPI_Controller extends Auth_Controller $error['messages'] = $data; else $error = $data; + } elseif (is_object($data)) { + $error = (array)$data; } else { $error['message'] = $data; } @@ -117,6 +119,9 @@ class FHCAPI_Controller extends Auth_Controller if ($type) $error['type'] = $type; + if (!isset($error['type'])) + $error['type'] = self::ERROR_TYPE_GENERAL; + $this->returnObj['errors'][] = $error; } diff --git a/application/core/Notiz_Controller.php b/application/core/Notiz_Controller.php new file mode 100644 index 000000000..05f70ee85 --- /dev/null +++ b/application/core/Notiz_Controller.php @@ -0,0 +1,461 @@ + self::DEFAULT_PERMISSION_R, + 'getNotizen' => self::DEFAULT_PERMISSION_R, + 'loadNotiz' => self::DEFAULT_PERMISSION_R, + 'addNewNotiz' => self::DEFAULT_PERMISSION_RW, + 'updateNotiz' => self::DEFAULT_PERMISSION_RW, + 'deleteNotiz' => self::DEFAULT_PERMISSION_RW, + 'loadDokumente' => self::DEFAULT_PERMISSION_R, + 'getMitarbeiter' => self::DEFAULT_PERMISSION_R, + 'isBerechtigt' => self::DEFAULT_PERMISSION_R, + ]; + + if(!is_array($permissions)) + { + $this->terminateWithError("Notiz_controller construct: permissions must be an array"); + } + + $merged_permissions = array_merge($default_permissions, $permissions); + + parent::__construct($merged_permissions); + + //Load Models + $this->load->model('person/Notiz_model', 'NotizModel'); + $this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel'); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + + // Load language phrases + $this->loadPhrases([ + 'ui' + ]); + } + + public function getUid() + { + $this->terminateWithSuccess(getAuthUID()); + } + + + //Override function for extensions + protected function assignNotiz($notiz_id, $id, $type) + { + $this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel'); + $result = $this->NotizzuordnungModel->isValidType($type); + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $result = $this->NotizzuordnungModel->insert(array('notiz_id' => $notiz_id, $type => $id)); + if (isError($result)) + { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return success(getData($result)); + } + + //Override function for extensions + protected function deleteNotizzuordnung($notiz_id, $id, $type) + { + $this->load->model('person/Notizzuordnung_model', 'NotizzuordnungModel'); + $result = $this->NotizzuordnungModel->isValidType($type); + if (isError($result)) { + $this->terminateWithError('type not in table notizzuordnung enthalten..', self::ERROR_TYPE_GENERAL); + } + + $result = $this->NotizzuordnungModel->delete(['notiz_id' => $notiz_id, $type => $id]); + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return success(getData($result)); + } + + + //Override function for extensions + public function getNotizen($id, $type) + { + $result = $this->NotizzuordnungModel->isValidType($type); + if(isError($result)) + $this->terminateWithError($result->retval, self::ERROR_TYPE_GENERAL); + + $result = $this->NotizModel->getNotizWithDocEntries($id, $type); + + if (isError($result)) { + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result) ?: []); + } + + + //Override function + protected function isBerechtigt($id, $typeId){ + return $this->terminateWithError("in abstract function: define right in extension", self::ERROR_TYPE_GENERAL); + } + + public function loadNotiz() + { + $_POST = json_decode(utf8_encode($this->input->raw_input_stream), true); + + $notiz_id = $this->input->post('notiz_id'); + + //$this->load->model('person/Notiz_model', 'NotizModel'); + $this->NotizModel->addJoin('public.tbl_notiz_dokument', 'notiz_id', 'LEFT'); + $this->NotizModel->addSelect('*'); + $this->NotizModel->addSelect("TO_CHAR(CASE WHEN public.tbl_notiz.updateamum >= public.tbl_notiz.insertamum + THEN public.tbl_notiz.updateamum ELSE public.tbl_notiz.insertamum END::timestamp, 'DD.MM.YYYY HH24:MI:SS') AS lastUpdate"); + $this->NotizModel->addLimit(1); + + $result = $this->NotizModel->loadWhere( + array('notiz_id' => $notiz_id) + ); + if (isError($result)) + { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + elseif (!hasData($result)) + { + $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=>'Notiz_id']), self::ERROR_TYPE_GENERAL); + } + else + { + $this->terminateWithSuccess(current(getData($result))); + } + } + + public function addNewNotiz($id, $paramTyp = null) + { + $this->load->library('DmsLib'); + $this->load->library('form_validation'); + + $uid = getAuthUID(); + + if (isset($_POST['data'])) + { + $data = json_decode($_POST['data']); + unset($_POST['data']); + foreach ($data as $k => $v) { + $_POST[$k] = $v; + } + } + + //Form Validation + $this->form_validation->set_rules('titel', 'Titel', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Titel']) + ]); + + $this->form_validation->set_rules('text', 'Text', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Text']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $titel = $this->input->post('titel'); + $text = $this->input->post('text'); + $erledigt = $this->input->post('erledigt'); + $verfasser_uid = isset($_POST['verfasser']) ? $_POST['verfasser'] : $uid; + $bearbeiter_uid = isset($_POST['bearbeiter']) ? $_POST['bearbeiter'] : null; + $type = $this->input->post('typeId'); + $start = $this->input->post('start'); + $ende = $this->input->post('ende'); + + // Start DB transaction + $this->db->trans_start(); + + //Save note + $result = $this->NotizModel->insert(array('titel' => $titel, 'text' => $text, 'erledigt' => $erledigt, 'verfasser_uid' => $verfasser_uid, + "insertvon" => $verfasser_uid, 'start' => $start, 'ende' => $ende, 'bearbeiter_uid' => $bearbeiter_uid)); + + if (isError($result)) + { + $this->db->trans_rollback(); + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + $notiz_id = $result->retval; + + //save Notizzuordnung + $result = $this->assignNotiz($notiz_id, $id, $type); + + if (isError($result)) + { + $this->db->trans_rollback(); + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + //save Documents + $dms_id_arr = []; + foreach ($_FILES as $k => $file) + { + $dms = array( + 'kategorie_kurzbz' => 'notiz', + 'version' => 0, + 'name' => $file["name"], + 'mimetype' => $file["type"], + 'insertamum' => date('c'), + 'insertvon' => $uid + ); + + //Todo(manu) check if filetypes weiter eingeschränkt werden sollen + //Todo(manu)check name files: nicht gleiches file 2mal hochladen + //Todo define in dms component: readFile, downloadFile + $result = $this->dmslib->upload($dms, $k, ['*']); + /* $result = $this->dmslib->upload($dms, $k, ['application/pdf','application/x.fhc-dms+json']);*/ + if (isError($result)) + { + $this->db->trans_rollback(); + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + $dms_id_arr[] = $result->retval['dms_id']; + } + + //save entry in Notizdokument + if($dms_id_arr) + { + $this->load->model('person/Notizdokument_model', 'NotizdokumentModel'); + foreach($dms_id_arr as $dms_id) + { + $result = $this->NotizdokumentModel->insert(array('notiz_id' => $notiz_id, 'dms_id' => $dms_id)); + if (isError($result)) + { + $this->db->trans_rollback(); + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + } + } + $this->db->trans_commit(); + return $this->terminateWithSuccess($result); + } + + public function updateNotiz() + { + $this->load->library('form_validation'); + $this->load->library('DmsLib'); + + if (isset($_POST['data'])) + { + $data = json_decode($_POST['data']); + unset($_POST['data']); + foreach ($data as $k => $v) { + $_POST[$k] = $v; + } + } + + $notiz_id = $this->input->post('notiz_id'); + + if(!$notiz_id) + { + $this->terminateWithError($this->p->t('ui','error_missingId',['id'=>'Notiz_id']), self::ERROR_TYPE_GENERAL); + } + + //Form Validation + $this->form_validation->set_rules('titel', 'Titel', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Titel']) + ]); + + $this->form_validation->set_rules('text', 'Text', 'required', [ + 'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Text']) + ]); + + if ($this->form_validation->run() == false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + //update Notiz + $uid = getAuthUID(); + $titel = $this->input->post('titel'); + $text = $this->input->post('text'); + $verfasser_uid = isset($_POST['verfasser']) ? $_POST['verfasser'] : $uid; + $bearbeiter_uid = isset($_POST['bearbeiter']) ? $_POST['bearbeiter'] : $uid; + $erledigt = $this->input->post('erledigt'); + $start = $this->input->post('start'); + $ende = $this->input->post('ende'); + + $result = $this->NotizModel->update( + [ + 'notiz_id' => $notiz_id + ], + [ + 'titel' => $titel, + 'updatevon' => $uid, + 'updateamum' => date('c'), + 'text' => $text, + 'verfasser_uid' => $verfasser_uid, + 'bearbeiter_uid' => $bearbeiter_uid, + 'start' => $start, + 'ende' => $ende, + 'erledigt' => $erledigt + ] + ); + if (isError($result)) + { + return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + //update(1) loading all dms-entries with this notiz_id + $this->load->model('person/Notizdokument_model', 'NotizdokumentModel'); + $this->NotizdokumentModel->addJoin('campus.tbl_dms_version', 'dms_id'); + + $result = $this->NotizdokumentModel->loadWhere(array('notiz_id' => $notiz_id)); + $result = $this->getDataOrTerminateWithError($result); + foreach ($result as $doc) { + $dms_id_arr[$doc->dms_id] = array( + 'name' => $doc->name, + 'dms_id' => $doc->dms_id + ); + } + + foreach ($_FILES as $k => $file) + { + //update(2) attach all new files (except type application/x.fhc-dms+json) + if($file["type"] == 'application/x.fhc-dms+json') + { + $jsonFile = json_decode(file_get_contents($file['tmp_name'])); + unset($dms_id_arr[$jsonFile->dms_id]); + #$dms_uploaded[] = $jsonFile->dms_id; + } + else + { + $dms = array( + 'kategorie_kurzbz' => 'notiz', + 'version' => 0, + 'name' => $file["name"], + 'mimetype' => $file["type"], + 'insertamum' => date('c'), + 'insertvon' => $uid + ); + + //Todo(manu) check if filetypes weiter eingeschränkt werden sollen + //Todo(manu)check name files: nicht gleiches file 2mal hochladen + //Todo define in dms component: readFile, downloadFile + $result = $this->dmslib->upload($dms, $k, array('*')); + + $result = $this->getDataOrTerminateWithError($result); + $dms_id = $result['dms_id']; + + $result = $this->NotizdokumentModel->insert(array('notiz_id' => $notiz_id, 'dms_id' => $dms_id)); + + $this->getDataOrTerminateWithError($result); + } + } + + //update(3) check if all files have been deleted + foreach ($dms_id_arr as $file) + { + $result = $this->dmslib->removeAll($file['dms_id']); + + $this->getDataOrTerminateWithError($result); + } + + return $this->terminateWithSuccess($result); + } + + public function deleteNotiz() + { + $this->load->library('DmsLib'); + + $notiz_id = $this->input->post('notiz_id'); + $typeId = $this->input->post('type_id'); + $id = $this->input->post('id'); + + //TODO(manu): define Permissions for deletion document if filecomponent finished + + //get dms_id from notizdokument + $this->load->model('person/Notizdokument_model', 'NotizdokumentModel'); + + $result = $this->NotizdokumentModel->loadWhere(array('notiz_id' => $notiz_id)); + + $result = $this->getDataOrTerminateWithError($result); + + // Start DB transaction + $this->db->trans_start(); + + if ($result) + $this->load->library('DmsLib'); + + foreach ($result as $doc) { + $res = $this->dmslib->removeAll($doc->dms_id); + if (isError($result)) + { + $this->db->trans_rollback(); + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + } + + //delete Notizzuordnung + $result = $this-> deleteNotizzuordnung($notiz_id, $id, $typeId); + if (isError($result)) + { + $this->db->trans_rollback(); + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + $this->load->model('person/Notiz_model', 'NotizModel'); + + //Delete Note + $result = $this->NotizModel->delete($notiz_id); + + if (isError($result)) + { + $this->db->trans_rollback(); + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + if(!hasData($result)) + { + return $this->terminateWithError($this->p->t('ui','error_missingId', ['id'=> 'Notiz_id']), self::ERROR_TYPE_GENERAL); + } + + $this->db->trans_complete(); + return $this->terminateWithSuccess(getData($result)); + } + + public function loadDokumente() + { + $notiz_id = $this->input->post('notiz_id'); + + $this->NotizModel->addSelect('campus.tbl_dms_version.*'); + + $this->NotizModel->addJoin('public.tbl_notiz_dokument', 'ON (public.tbl_notiz_dokument.notiz_id = public.tbl_notiz.notiz_id)'); + $this->NotizModel->addJoin('campus.tbl_dms_version', 'ON (public.tbl_notiz_dokument.dms_id = campus.tbl_dms_version.dms_id)'); + + $result = $this->NotizModel->loadWhere( + array('public.tbl_notiz.notiz_id' => $notiz_id) + ); + if (isError($result)) { + return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + + if(!hasData($result)) + { + return $this->terminateWithError($this->p->t('ui','error_missingId', ['id'=> 'Notiz_id']), self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess(getData($result)); + } + + public function getMitarbeiter($searchString) + { + $this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); + $result = $this->MitarbeiterModel->searchMitarbeiter($searchString); + if (isError($result)) { + $this->terminateWithError($result, self::ERROR_TYPE_GENERAL); + } + return $this->terminateWithSuccess($result); + } + +} \ No newline at end of file diff --git a/application/helpers/hlp_common_helper.php b/application/helpers/hlp_common_helper.php index 3e682e56c..40aed007c 100755 --- a/application/helpers/hlp_common_helper.php +++ b/application/helpers/hlp_common_helper.php @@ -422,3 +422,79 @@ function isValidDate($dateString) return false; } } + + +// ------------------------------------------------------------------------ +// Collection of utility functions for form validation purposes +// ------------------------------------------------------------------------ + +/** + * check if string can be converted to a date + */ +function is_valid_date($dateString) +{ + try + { + return (new DateTime($dateString)) !== false; + } + catch(Exception $e) + { + return false; + } +} + +/** + * check if given permissions are met + */ +function has_write_permissions($value, $permissions = '') +{ + if (!$permissions) + $permissions = $value; + $permissions = explode(',', $permissions); + + $CI =& get_instance(); + $CI->load->library('AuthLib'); + $CI->load->library('PermissionLib'); + + return $CI->permissionlib->hasAtLeastOne( + $permissions, + 'sometable', + PermissionLib::WRITE_RIGHT + ); +} + +/** + * check if has permissions for a studiengang_kz + */ +function has_permissions_for_stg($studiengang_kz, $permissions = '') +{ + if (!$permissions) + return false; + $permissions = explode(',', $permissions); + + $CI =& get_instance(); + $CI->load->library('AuthLib'); + $CI->load->library('PermissionLib'); + + foreach ($permissions as $perm) { + if (strpos($perm, PermissionLib::PERMISSION_SEPARATOR) === false) { + $CI->addError( + 'The given permission does not use the correct format', + FHCAPI_Controller::ERROR_TYPE_GENERAL + ); + return false; + } + + list($perm, $accesstype) = explode(PermissionLib::PERMISSION_SEPARATOR, $perm); + $at = ''; + if (strpos($accesstype, PermissionLib::READ_RIGHT) !== false) + $at = PermissionLib::SELECT_RIGHT; // S + if (strpos($accesstype, PermissionLib::WRITE_RIGHT) !== false) + $at .= PermissionLib::REPLACE_RIGHT.PermissionLib::DELETE_RIGHT; // UID + + if ($CI->permissionlib->isBerechtigt($perm, $at, $studiengang_kz)) + return true; + } + + return false; +} diff --git a/application/language/english/form_validation_lang.php b/application/language/english/form_validation_lang.php new file mode 100644 index 000000000..b8918a721 --- /dev/null +++ b/application/language/english/form_validation_lang.php @@ -0,0 +1,43 @@ +p->t('studierendenantrag', 'error_no_right')); + return error($this->_ci->p->t('studierendenantrag', 'error_no_right')); if ($insertvon == Studierendenantragstatus_model::INSERTVON_ABMELDUNGSTGL) { return $this->_ci->StudierendenantragstatusModel->resumeAntraegeForAbmeldungStgl($antrag_id); } @@ -257,18 +257,28 @@ class AntragLib if (isError($result)) $errors[] = getError($result); + $this->_ci->load->model('crm/Statusgrund_model', 'StatusgrundModel'); + $result = $this->_ci->StatusgrundModel->loadWhere(['statusgrund_kurzbz' => 'abbrecherStud']); + if (isError($result)) { + $errors[] = getError($result); + continue; + } elseif (!hasData($result)) { + $errors[] = $this->_ci->p->t('lehre', 'error_noStatusgrund', ['statusgrund_kurzbz' => 'abbrecherStud']); + continue; + } + $statusgrund = current(getData($result)); + $result = $this->_ci->prestudentlib->setAbbrecher( $antrag->prestudent_id, $antrag->studiensemester_kurzbz, $insertvon, - 'abbrecherStud', + $statusgrund->statusgrund_id, $antrag->datum, $insertam ); - if (isError($result)) - { + if (isError($result)) { $errors[] = getError($result); - return $errors; + continue; } $result = $this->_ci->PersonModel->loadPrestudent($antrag->prestudent_id); @@ -421,11 +431,20 @@ class AntragLib // NOTE(chris): here we should have error handling but at the // moment there is no way to notify the user for "soft" errors + $this->_ci->load->model('crm/Statusgrund_model', 'StatusgrundModel'); + $result = $this->_ci->StatusgrundModel->loadWhere(['statusgrund_kurzbz' => 'abbrecherStgl']); + if (isError($result)) + return $result; + if (!hasData($result)) + return error($this->_ci->p->t('lehre', 'error_noStatusgrund', ['statusgrund_kurzbz' => 'abbrecherStgl'])); + + $statusgrund = current(getData($result)); + $result = $this->_ci->prestudentlib->setAbbrecher( $antrag->prestudent_id, $antrag->studiensemester_kurzbz, $insertvon, - 'abbrecherStgl', + $statusgrund->statusgrund_id, $status->insertamum ); diff --git a/application/libraries/PermissionLib.php b/application/libraries/PermissionLib.php index bf8174cf4..857defbf7 100755 --- a/application/libraries/PermissionLib.php +++ b/application/libraries/PermissionLib.php @@ -147,19 +147,7 @@ class PermissionLib if (strpos($permissions[$pCounter], PermissionLib::PERMISSION_SEPARATOR) !== false) { // Retrieves permission and required access type from the $requiredPermissions array - list($permission, $requiredAccessType) = explode(PermissionLib::PERMISSION_SEPARATOR, $permissions[$pCounter]); - - $accessType = ''; - - // Set the access type - if (strpos($requiredAccessType, PermissionLib::READ_RIGHT) !== false) - { - $accessType = PermissionLib::SELECT_RIGHT; // S - } - if (strpos($requiredAccessType, PermissionLib::WRITE_RIGHT) !== false) - { - $accessType .= PermissionLib::REPLACE_RIGHT.PermissionLib::DELETE_RIGHT; // UID - } + list($permission, $accessType) = $this->convertAccessType($permissions[$pCounter]); if (!isEmptyString($accessType)) // if compliant { @@ -209,6 +197,24 @@ class PermissionLib return $checkPermissions; } + /** + * Retrieves permission and required access type from the newly formatted permission string + * + * @param string $permission + * + * @return array + */ + public function convertAccessType($permission) + { + list($permission, $reqAccessType) = explode(PermissionLib::PERMISSION_SEPARATOR, $permission); + $accessType = ''; + if (strpos($reqAccessType, PermissionLib::READ_RIGHT) !== false) + $accessType = PermissionLib::SELECT_RIGHT; + if (strpos($reqAccessType, PermissionLib::WRITE_RIGHT) !== false) + $accessType = PermissionLib::REPLACE_RIGHT.PermissionLib::DELETE_RIGHT; + return [$permission, $accessType]; + } + /** * Checks if at least one of the permissions given as parameter (requiredPermissions) belongs to the authenticated user * It checks the given permissions against a given method (controller method name) and a given permission type (R and/or W) diff --git a/application/libraries/PrestudentLib.php b/application/libraries/PrestudentLib.php index ae4ad59c6..af62668cf 100755 --- a/application/libraries/PrestudentLib.php +++ b/application/libraries/PrestudentLib.php @@ -35,8 +35,15 @@ class PrestudentLib $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); } - public function setAbbrecher($prestudent_id, $studiensemester_kurzbz, $insertvon = null, $statusgrund_kurzbz = null, $datum = null, $bestaetigtam = null, $bestaetigtvon = null) - { + public function setAbbrecher( + $prestudent_id, + $studiensemester_kurzbz, + $insertvon = null, + $statusgrund_id = null, + $datum = null, + $bestaetigtam = null, + $bestaetigtvon = null + ) { if (!$insertvon) $insertvon = getAuthUID(); if (!$bestaetigtvon) @@ -70,8 +77,8 @@ class PrestudentLib if(!$bestaetigtam) $bestaetigtam = date('c'); - //Status und Statusgrund updaten - $result = $this->_ci->PrestudentstatusModel->withGrund($statusgrund_kurzbz)->insert([ + // Status und Statusgrund updaten + $result = $this->_ci->PrestudentstatusModel->insert([ 'prestudent_id' => $prestudent_id, 'status_kurzbz' => Prestudentstatus_model::STATUS_ABBRECHER, 'studiensemester_kurzbz' => $prestudent_status->studiensemester_kurzbz, @@ -82,13 +89,13 @@ class PrestudentLib 'orgform_kurzbz'=> $prestudent_status->orgform_kurzbz, 'studienplan_id'=> $prestudent_status->studienplan_id, 'bestaetigtvon' => $bestaetigtvon, - 'bestaetigtam' => $bestaetigtam + 'bestaetigtam' => $bestaetigtam, + 'statusgrund_id' => $statusgrund_id ]); if (isError($result)) return $result; - //Verband anlegen $result = $this->_ci->LehrverbandModel->load([ 'studiengang_kz' => $student->studiengang_kz, @@ -134,7 +141,7 @@ class PrestudentLib ]); } - //noch nicht eingetragene Zeugnisnoten auf 9 setzen + // noch nicht eingetragene Zeugnisnoten auf 9 setzen $result = $this->_ci->ZeugnisnoteModel->getZeugnisnoten($student->student_uid, $prestudent_status->studiensemester_kurzbz); if (isError($result)) return $result; @@ -166,9 +173,9 @@ class PrestudentLib } - //Update Aktionen + // Update Aktionen - //StudentModel updaten + // StudentModel updaten $this->_ci->StudentModel->update([ 'student_uid' => $student->student_uid ], [ @@ -192,7 +199,7 @@ class PrestudentLib 'updatevon' => $insertvon ]); - //Benutzer inaktiv setzen + // Benutzer inaktiv setzen $this->_ci->BenutzerModel->update([ 'uid' => $student->student_uid ], [ @@ -206,17 +213,28 @@ class PrestudentLib return success(); } - public function setUnterbrecher($prestudent_id, $studiensemester_kurzbz, $studierendenantrag_id, $insertvon = null) - { + public function setUnterbrecher( + $prestudent_id, + $studiensemester_kurzbz, + $studierendenantrag_id = null, + $insertvon = null, + $ausbildungssemester = null, + $statusgrund_id = null + ) { $ausbildungssemester_plus = 0; + if (!$insertvon) $insertvon = getAuthUID(); + $result = $this->_ci->PrestudentstatusModel->getLastStatus($prestudent_id, $studiensemester_kurzbz); + if (isError($result)) return $result; + $result = getData($result); - if (!$result) { + + if (!$result) { // NOTE(chris): no status in target stdsem //NOTE(manu): only valid if nextSemester focus max $result = $this->_ci->PrestudentstatusModel->getLastStatus($prestudent_id); @@ -224,7 +242,7 @@ class PrestudentLib return $result; $result = getData($result); - //check if ausbildungssemester is last + // check if ausbildungssemester is last $this->_ci->StudiengangModel->addJoin('public.tbl_prestudent p', 'studiengang_kz'); $res = $this->_ci->StudiengangModel->loadWhere(['p.prestudent_id' => $prestudent_id]); if(isError($res)) @@ -249,31 +267,47 @@ class PrestudentLib } $prestudent_status = current($result); + + $result = $this->_ci->StudentModel->loadWhere(['prestudent_id' => $prestudent_id]); if (isError($result)) return $result; + $result = getData($result); + if (!$result) return error($this->_ci->p->t('studierendenantrag', 'error_no_student_for_prestudent', ['prestudent_id' => $prestudent_id])); $student = current($result); - $resultAntrag = $this->_ci->StudierendenantragModel->load($studierendenantrag_id); - if (isError($resultAntrag)) - return $resultAntrag; - $resultAntrag = getData($resultAntrag); - if (!$resultAntrag) - return error($this->_ci->p->t('studierendenantrag', 'error_no_antrag_found', ['id' => $studierendenantrag_id])); - $antrag = current($resultAntrag); + if ($studierendenantrag_id) + { + $resultAntrag = $this->_ci->StudierendenantragModel->load($studierendenantrag_id); + if (isError($resultAntrag)) + return $resultAntrag; + $resultAntrag = getData($resultAntrag); + if (!$resultAntrag) + return error($this->_ci->p->t('studierendenantrag', 'error_no_antrag_found', ['id' => $studierendenantrag_id])); - //Status updaten + $antrag = current($resultAntrag); + $anmerkung = 'Wiedereinstieg ' . $antrag->datum_wiedereinstieg; + } + else + $anmerkung = ''; + + if ($ausbildungssemester) + $semester = $ausbildungssemester; + else + $semester = $prestudent_status->ausbildungssemester + $ausbildungssemester_plus; + + // Status updaten $result = $this->_ci->PrestudentstatusModel->insert([ 'prestudent_id' => $prestudent_id, 'status_kurzbz' => Prestudentstatus_model::STATUS_UNTERBRECHER, 'studiensemester_kurzbz' => $studiensemester_kurzbz, - 'ausbildungssemester' => $prestudent_status->ausbildungssemester + $ausbildungssemester_plus, + 'ausbildungssemester' => $semester, 'datum' => date('c'), 'insertvon' => $insertvon, 'insertamum' => date('c'), @@ -281,7 +315,8 @@ class PrestudentLib 'studienplan_id'=> $prestudent_status->studienplan_id, 'bestaetigtvon' => $insertvon, 'bestaetigtam' => date('c'), - 'anmerkung'=> 'Wiedereinstieg ' . $antrag->datum_wiedereinstieg + 'anmerkung'=> $anmerkung, + 'statusgrund_id' => $statusgrund_id ]); if (isError($result)) @@ -332,7 +367,7 @@ class PrestudentLib ]); } - //noch nicht eingetragene Zeugnisnoten auf 9 setzen + // noch nicht eingetragene Zeugnisnoten auf 9 setzen $result = $this->_ci->ZeugnisnoteModel->getZeugnisnoten($student->student_uid, $studiensemester_kurzbz); if (isError($result)) return $result; @@ -363,10 +398,9 @@ class PrestudentLib } } + // Update Aktionen - //Update Aktionen - - //StudentModel updaten + // StudentModel updaten $this->_ci->StudentModel->update([ 'student_uid' => $student->student_uid ], [ @@ -409,4 +443,463 @@ class PrestudentLib return success(); } + + public function setStudent($prestudent_id, $studiensemester_kurzbz, $ausbildungssemester, $statusgrund_id) + { + $authUID = getAuthUID(); + $now = date('c'); + + + $result = $this->_ci->PrestudentstatusModel->getLastStatus($prestudent_id); + + if (isError($result)) + return $result; + if (!hasData($result)) + return error($this->_ci->p->t('studierendenantrag', 'error_no_prestudentstatus', [ + 'prestudent_id' => $prestudent_id + ])); + + $prestudent_status = current(getData($result)); + + + $result = $this->_ci->StudentModel->loadWhere(['prestudent_id' => $prestudent_id]); + + if (isError($result)) + return $result; + if (!hasData($result)) + return error($this->_ci->p->t('studierendenantrag', 'error_no_student_for_prestudent', ['prestudent_id' => $prestudent_id])); + + $student = current(getData($result)); + + + $this->_ci->load->library('VariableLib', ['uid' => $authUID]); + $semester_aktuell = $this->_ci->variablelib->getVar('semester_aktuell'); + + + // Update Aktionen + + // Status updaten + $result = $this->_ci->PrestudentstatusModel->insert([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => Prestudentstatus_model::STATUS_STUDENT, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'statusgrund_id' => $statusgrund_id, + 'ausbildungssemester' => $ausbildungssemester, + 'datum' => $now, + 'insertvon' => $authUID, + 'insertamum' => $now, + 'orgform_kurzbz'=> $prestudent_status->orgform_kurzbz, + 'studienplan_id'=> $prestudent_status->studienplan_id, + 'bestaetigtvon' => $authUID, + 'bestaetigtam' => $now + ]); + + if (isError($result)) + return $result; + + + // Student updaten + $result = $this->_ci->StudentModel->update([ + 'student_uid' => $student->student_uid + ], [ + 'semester' => $ausbildungssemester, + 'verband' => '', + 'gruppe' => '', + 'updatevon' => $authUID, + 'updateamum' => $now + ]); + + if (isError($result)) + return $result; + + + // Studentlehrverband updaten + $result = $this->_ci->StudentlehrverbandModel->update([ + 'student_uid' => $student->student_uid, + 'studiensemester_kurzbz' => $semester_aktuell + ], [ + 'semester' => $ausbildungssemester, + 'verband' => '', + 'gruppe' => '', + 'updatevon' => $authUID, + 'updateamum' => $now + ]); + + if (isError($result)) + return $result; + + + // Benutzer updaten + $result = $this->_ci->BenutzerModel->load([$student->student_uid]); + + if (isError($result)) + return $result; + if (!hasData($result)) + return error($this->_ci->p->t('person', 'error_noBenutzer')); + + $benutzer = current(getData($result)); + $updateData = [ + 'aktiv' => true, + 'updateamum' => $now, + 'updatevon' => $authUID + ]; + if (!$benutzer->aktiv) { + $updateData['updateaktivam'] = $now; + $updateData['updateaktivvon'] = $authUID; + } + + + $this->_ci->BenutzerModel->update([$student->student_uid], $updateData); + + return success(); + } + + public function setFirstStudent( + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $orgform_kurzbz, + $studienplan_id, + $statusgrund_id + ) { + $this->_ci->PrestudentModel->addJoin('public.tbl_person p', 'person_id'); + $this->_ci->PrestudentModel->addJoin('public.tbl_studiengang stg', 'studiengang_kz'); + $result = $this->_ci->PrestudentModel->load($prestudent_id); + + if (isError($result)) + return $result; + + if (!hasData($result)) + return error('No prestudent'); + + $student_data = current(getData($result)); + + + $authUID = getAuthUID(); + $now = date('c'); + $today = date('Y-m-d'); + + $jahr = mb_substr($studiensemester_kurzbz, 4, 2); + + + // Genererate Personenkennzeichen + $personenkennzeichen = $this->_ci->StudentModel->generateMatrikelnummer2( + $student_data->studiengang_kz, + $studiensemester_kurzbz, + $student_data->typ + ); + if (isError($personenkennzeichen)) + return $personenkennzeichen; + $personenkennzeichen = getData($personenkennzeichen); + + + // Generate UID + $uid = $this->_ci->StudentModel->generateUID( + $student_data->kurzbz, + $jahr, + $student_data->typ, + $personenkennzeichen, + $student_data->vorname, + $student_data->nachname + ); + if (isError($uid)) + return $uid; + $uid = getData($uid); + + + // Generate Matrikelnummer + $matrikelnummer = $this->_ci->BenutzerModel->generateMatrikelnummer( + $student_data->oe_kurzbz + ); + if (isError($matrikelnummer)) + return $matrikelnummer; + $matrikelnummer = getData($matrikelnummer); + + + // Generate Alias + $alias = ''; + if (!defined('GENERATE_ALIAS_STUDENT') + || GENERATE_ALIAS_STUDENT === true + ) { + $result = $this->_ci->BenutzerModel->generateAliasFromName($student_data->vorname, $student_data->nachname); + if (isError($result)) + return $result; + $alias = getData($result); + } + + // Generate Activation Key + $activationkey = $this->_ci->BenutzerModel->generateActivationkey(); + + + // Overwrite stuff + if (defined('SET_UID_AS_MATRIKELNUMMER') + && SET_UID_AS_MATRIKELNUMMER) + $matrikelnummer = $uid; + if (defined('SET_UID_AS_PERSONENKENNZEICHEN') + && SET_UID_AS_PERSONENKENNZEICHEN) + $personenkennzeichen = $uid; + + + // Update Person + $this->_ci->load->model('person/Person_model', 'PersonModel'); + $result = $this->_ci->PersonModel->update([ + 'person_id' => $student_data->person_id, + 'matr_nr' => null + ], [ + 'matr_nr' => $matrikelnummer + ]); + + if (isError($result)) + return $result; + + + // Add Benutzer + $result = $this->_ci->BenutzerModel->insert([ + 'uid' => $uid, + 'person_id' => $student_data->person_id, + 'aktiv' => true, + 'aktivierungscode' => $activationkey, + 'alias' => $alias, + 'insertvon' => $authUID, + 'insertamum' => $now, + ]); + + if (isError($result)) + return $result; + + + // Add Student + $result = $this->_ci->StudentModel->insert([ + 'student_uid' => $uid, + 'matrikelnr' => $personenkennzeichen, + 'prestudent_id' => $prestudent_id, + 'studiengang_kz' => $student_data->studiengang_kz, + 'semester' => $ausbildungssemester, + 'verband' => ' ', + 'gruppe' => ' ', + 'insertvon' => $authUID, + 'insertamum' => $now + ]); + + if (isError($result)) + return $result; + + + // Add Lehrverband if it does not exist + $result = $this->_ci->LehrverbandModel->load([' ', ' ', $ausbildungssemester, $student_data->studiengang_kz]); + + if (isError($result)) + return $result; + + if (!hasData($result)) { + $result = $this->_ci->LehrverbandModel->insert([ + 'studiengang_kz' => $student_data->studiengang_kz, + 'semester' => $ausbildungssemester, + 'verband' => ' ', + 'gruppe' => ' ', + 'aktiv' => true + ]); + + if (isError($result)) + return $result; + } + + + // Add Rolle + $result = $this->_ci->PrestudentstatusModel->insert([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => Prestudentstatus_model::STATUS_STUDENT, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'ausbildungssemester' => $ausbildungssemester, + 'orgform_kurzbz'=> $orgform_kurzbz, + 'studienplan_id'=> $studienplan_id, + 'datum' => $today, + 'insertamum' => $now, + 'insertvon' => $authUID, + 'bestaetigtam' => $today, + 'bestaetigtvon' => $authUID, + 'statusgrund_id' => $statusgrund_id + ]); + + if (isError($result)) + return $result; + + + // Add Studentlehrverband + $result = $this->_ci->StudentlehrverbandModel->insert([ + 'student_uid' => $uid, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'studiengang_kz' => $student_data->studiengang_kz, + 'semester' => $ausbildungssemester, + 'verband' => ' ', + 'gruppe' => ' ', + 'insertamum' => $now, + 'insertvon' => $authUID + ]); + + if (isError($result)) + return $result; + + return success(); + } + + public function setDiplomand($prestudent_id, $studiensemester_kurzbz, $ausbildungssemester, $statusgrund_id) + { + return $this->setBasic( + getAuthUID(), + date('c'), + Prestudentstatus_model::STATUS_DIPLOMAND, + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + } + + public function setAbsolvent($prestudent_id, $studiensemester_kurzbz, $ausbildungssemester, $statusgrund_id) + { + $authUID = getAuthUID(); + $now = date('c'); + + + $result = $this->setBasic( + $authUID, + $now, + Prestudentstatus_model::STATUS_ABSOLVENT, + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + + if (isError($result)) + return $result; + + + // Load Student + $result = $this->_ci->StudentModel->loadWhere(['prestudent_id' => $prestudent_id]); + + if (isError($result)) + return $result; + if (!hasData($result)) + return error($this->_ci->p->t('studierendenantrag', 'error_no_student_for_prestudent', ['prestudent_id' => $prestudent_id])); + + $student = current(getData($result)); + + + // Benutzer inaktiv setzen + $this->_ci->BenutzerModel->update([ + 'uid' => $student->student_uid + ], [ + 'aktiv' => false, + 'updateaktivvon' => $authUID, + 'updateaktivam' => $now, + 'updatevon' => $authUID, + 'updateamum' => $now + ]); + + if (isError($result)) + return $result; + + return success(); + } + + public function setBewerber($prestudent_id, $studiensemester_kurzbz, $ausbildungssemester, $statusgrund_id) + { + $result = $this->setBasic( + getAuthUID(), + date('c'), + Prestudentstatus_model::STATUS_BEWERBER, + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + + if (isError($result)) + return $result; + + if (SEND_BEWERBER_INFOMAIL) { + // TODO(chris): IMPLEMENT! + } + + return success(); + } + + public function setAufgenommener($prestudent_id, $studiensemester_kurzbz, $ausbildungssemester, $statusgrund_id) + { + return $this->setBasic( + getAuthUID(), + date('c'), + Prestudentstatus_model::STATUS_AUFGENOMMENER, + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + } + + public function setAbgewiesener($prestudent_id, $studiensemester_kurzbz, $ausbildungssemester, $statusgrund_id) + { + return $this->setBasic( + getAuthUID(), + date('c'), + Prestudentstatus_model::STATUS_ABGEWIESENER, + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + } + + public function setWartender($prestudent_id, $studiensemester_kurzbz, $ausbildungssemester, $statusgrund_id) + { + return $this->setBasic( + getAuthUID(), + date('c'), + Prestudentstatus_model::STATUS_WARTENDER, + $prestudent_id, + $studiensemester_kurzbz, + $ausbildungssemester, + $statusgrund_id + ); + } + + protected function setBasic($authUID, $now, $status_kurzbz, $prestudent_id, $studiensemester_kurzbz, $ausbildungssemester, $statusgrund_id = null) + { + $result = $this->_ci->PrestudentstatusModel->getLastStatus($prestudent_id); + + if (isError($result)) + return $result; + if (!hasData($result)) + return error($this->_ci->p->t('studierendenantrag', 'error_no_prestudentstatus', [ + 'prestudent_id' => $prestudent_id + ])); + + $prestudent_status = current(getData($result)); + + + // Update Aktionen + + // Status updaten + $result = $this->_ci->PrestudentstatusModel->insert([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => $status_kurzbz, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'ausbildungssemester' => $ausbildungssemester, + 'datum' => $now, + 'insertvon' => $authUID, + 'insertamum' => $now, + 'orgform_kurzbz'=> $prestudent_status->orgform_kurzbz, + 'studienplan_id'=> $prestudent_status->studienplan_id, + 'bestaetigtvon' => $authUID, + 'bestaetigtam' => $now, + 'statusgrund_id' => $statusgrund_id + ]); + + if (isError($result)) + return $result; + + return success(); + } } diff --git a/application/libraries/PrestudentstatusCheckLib.php b/application/libraries/PrestudentstatusCheckLib.php new file mode 100644 index 000000000..5e3d8a307 --- /dev/null +++ b/application/libraries/PrestudentstatusCheckLib.php @@ -0,0 +1,922 @@ +_ci =& get_instance(); + + $this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $this->_ci->load->model('person/Person_model', 'PersonModel'); + $this->_ci->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); + $this->_ci->load->model('crm/Prestudent_model', 'PrestudentModel'); + $this->_ci->load->model('crm/Student_model', 'StudentModel'); + $this->_ci->load->model('organisation/Studienplan_model', 'StudienplanModel'); + $this->_ci->load->model('codex/Bismeldestichtag_model', 'BismeldestichtagModel'); + } + + /** + * Checks if a status add is valid. + * @return object error if invalid + */ + public function checkStatusAdd( + $prestudent_id, + $status_kurzbz, + $new_status_studiensemester_kurzbz, + $new_status_datum, + $new_status_ausbildungssemester, + $new_studienplan_id + ) { + $studentName = ''; + + $nameRes = $this->_ci->PersonModel->loadPrestudent($prestudent_id); + + if (hasData($nameRes)) + { + $nameData = getData($nameRes)[0]; + $studentName = $nameData->vorname.' '.$nameData->nachname; + } + + // Datum des neuen Status darf nicht in Vergangenheit liegen, sonst Probleme wenn neues Datum < Bismeldedatum + if (new DateTime($new_status_datum) < new DateTime('today')) + return error($studentName . $this->_ci->p->t('lehre', 'error_entryInPast')); + + return $this->_checkIfValidStatusHistory( + $prestudent_id, + $status_kurzbz, + $new_status_studiensemester_kurzbz, + $new_status_datum, + $new_status_ausbildungssemester, + $new_studienplan_id + ); + } + + /** + * Checks if a status update is valid. + * @return error if invalid + */ + public function checkStatusUpdate( + $prestudent_id, + $status_kurzbz, + $new_status_studiensemester_kurzbz, + $new_status_datum, + $new_status_ausbildungssemester, + $new_studienplan_id, + $old_status_studiensemester, + $old_status_ausbildungssemester + ) { + + return $this->_checkIfValidStatusHistory( + $prestudent_id, + $status_kurzbz, + $new_status_studiensemester_kurzbz, + $new_status_datum, + $new_status_ausbildungssemester, + $new_studienplan_id, + $old_status_studiensemester, + $old_status_ausbildungssemester + ); + } + + /** + * Checks if a student already exists. + * + * @param integer $prestudent_id + * + * @return stdClass + */ + public function checkIfExistingStudent($prestudent_id) + { + $result = $this->_ci->StudentModel->loadWhere([ + 'prestudent_id' => $prestudent_id + ]); + + if (isError($result)) + return $result; + + return success(hasData($result)); + } + + /** + * Check if Reihungstest was admitted + * + * @param stdClass $prestudent + * + * @return stdClass + */ + public function checkIfAngetreten($prestudent) + { + return success($prestudent->reihungstestangetreten); + } + + /** + * Check if ZGV-Code is registered + * + * @param stdClass $prestudent + * + * @return stdClass + */ + public function checkIfZGVEingetragen($prestudent_person) + { + return success((boolean)$prestudent_person->zgv_code); + } + + /** + * Check if Master ZGV-Code is registered + * + * @param stdClass $prestudent + * + * @return booleans $zgv_code, error if not registered + */ + public function checkIfZGVEingetragenMaster($prestudent) + { + $this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel'); + $result = $this->_ci->StudiengangModel->load($prestudent->studiengang_kz); + if (isError($result)) + return $result; + if (!hasData($result)) + return error($this->_ci->p->t('studierendenantrag', 'error_no_stg', ['studiengang_kz' => $prestudent->studiengang_kz])); + + if (current($result->retval)->typ != 'm') + return success(true); // NOTE(chris): we only test master stgs, all other stgs should default to true + + return success((boolean)$prestudent->zgvmas_code); + } + + /** + * Checks if a bewerber status already exists. + * + * @param integer $prestudent_id + * + * @return stdClass + */ + public function checkIfExistingBewerberstatus($prestudent_id) + { + $result = $this->_ci->PrestudentstatusModel->loadWhere([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => Prestudentstatus_model::STATUS_BEWERBER + ]); + if (isError($result)) + return $result; + + return success(hasData($result)); + } + + + /** + * Checks if status aufgenommen already exists. + * + * @param integer $prestudent_id + * + * @return stdClass + */ + public function checkIfExistingAufgenommenerstatus($prestudent_id) + { + $result = $this->_ci->PrestudentstatusModel->loadWhere([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => Prestudentstatus_model::STATUS_AUFGENOMMENER + ]); + if (isError($result)) + return $result; + + return success(hasData($result)); + } + + /** + * Checks if the last Bewerber status and the last Aufgenommener status + * have the same studiensemester and ausbildungssemester. + * + * Attention: + * If one of those two status is missing the function returns true! + * + * @param integer $prestudent_id + * + * @return stdClass + */ + public function checkIfLastBewerberAndAufgenommenerShareSemesters($prestudent_id) + { + $this->_ci->PrestudentstatusModel->addOrder('datum', 'DESC'); + $this->_ci->PrestudentstatusModel->addOrder('insertamum', 'DESC'); + $this->_ci->PrestudentstatusModel->addLimit(1); + $result = $this->_ci->PrestudentstatusModel->loadWhere([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => Prestudentstatus_model::STATUS_BEWERBER + ]); + + if (isError($result)) + return $result; + if (!hasData($result)) + return success(true); + + $bewerber = current(getData($result)); + + $this->_ci->PrestudentstatusModel->addOrder('datum', 'DESC'); + $this->_ci->PrestudentstatusModel->addOrder('insertamum', 'DESC'); + $this->_ci->PrestudentstatusModel->addLimit(1); + $result = $this->_ci->PrestudentstatusModel->loadWhere([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => Prestudentstatus_model::STATUS_AUFGENOMMENER + ]); + + if (isError($result)) + return $result; + if (!hasData($result)) + return success(true); + + $aufgenommener = current(getData($result)); + + return success( + $bewerber->studiensemester_kurzbz == $aufgenommener->studiensemester_kurzbz + && $bewerber->ausbildungssemester == $aufgenommener->ausbildungssemester + ); + } + + /** + * Check if Bismeldestichtag erreicht + * + * @param DateTime $statusDatum + * @param string $studiensemester_kurzbz + * + * @return stdClass + */ + public function checkIfMeldestichtagErreicht($statusDatum, $studiensemester_kurzbz = null) + { + $result = $this->_ci->BismeldestichtagModel->checkIfMeldestichtagErreicht($statusDatum, $studiensemester_kurzbz); + + if (isError($result)) + return $result; + + return success(getData($result) == "1"); + } + + /** + * Runs all checks on Status History and saves it in cache. + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param DateTime $new_date + * @param string $new_studiensemester_kurzbz + * @param integer $new_ausbildungssemester + * @param string $old_studiensemester_kurzbz + * @param integer $old_ausbildungssemester + * + * @return stdClass + */ + protected function prepareStatusHistory( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ) { + // Generate key for caching + $primary = implode('|', [ + $prestudent_id, + $status_kurzbz, + $new_date->format('Y-m-d'), + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ]); + + if (isset($this->_cache_history[$primary])) + return $this->_cache_history[$primary]; + + $this->_ci->load->model('crm/Prestudentstatus_model', 'PrestudentstatusModel'); + + // Get the history + $result = $this->_ci->PrestudentstatusModel->getHistoryWithNewOrEditedState( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ); + + if (isError($result)) + return $result; + + if (!hasData($result)) + return error('This is impossible'); + + $history = getData($result); + $historyCount = count($history); + + // Run checks + $checks = [ + 'timesequence' => true, + 'laststatus' => true, + 'unterbrechersemester' => true, + 'abbrechersemester' => true, + 'diplomant' => true, + 'student' => true + ]; + + for ($n = 0, $c = 1; $c < $historyCount; $n++, $c++) { + if (!$checks['timesequence'] + && !$checks['laststatus'] + && !$checks['unterbrechersemester'] + && !$checks['abbrechersemester'] + && !$checks['diplomant'] + && !$checks['student'] + ) + break; // early out + + $next = $history[$n]; + $current = $history[$c]; + + // Zeitabfolge ungültig? + if ($checks['timesequence'] + && $next->start < $current->start + ) + $checks['timesequence'] = false; + + // Abbrecher- oder Absolventenstatus muss Endstatus sein + if ($checks['laststatus'] + && in_array($current->status_kurzbz, [self::ABSOLVENT_STATUS, self::ABBRECHER_STATUS]) + ) + $checks['laststatus'] = false; + + // wenn Unterbrecher auf Unterbrecher folgt, muss Ausbildungssemester gleich sein + if ($checks['unterbrechersemester'] + && $current->status_kurzbz == self::UNTERBRECHER_STATUS + && $next->status_kurzbz == self::UNTERBRECHER_STATUS + && $current->ausbildungssemester != $next->ausbildungssemester + ) + $checks['unterbrechersemester'] = false; + + // wenn Abbrecher auf Unterbrecher folgt, muss Ausbildungssemester gleich sein + if ($checks['abbrechersemester'] + && $current->status_kurzbz == self::UNTERBRECHER_STATUS + && $next->status_kurzbz == self::ABBRECHER_STATUS + && $current->ausbildungssemester != $next->ausbildungssemester + ) + $checks['abbrechersemester'] = false; + + if (($checks['diplomant'] + || $checks['student']) + && $next->status_kurzbz == self::STUDENT_STATUS + ) { + $restl_stati = array_unique(array_column(array_slice($history, $c), 'status_kurzbz')); + + // keine Studenten nach Diplomand Status + if ($checks['diplomant'] + && in_array(self::DIPLOMAND_STATUS, $restl_stati) + ) + $checks['diplomant'] = false; + + // vor Studentenstatus müssen bestimmte Status vorhanden sein + if ($checks['student'] + && array_values(array_intersect($restl_stati, $this->_statusAbfolgeVorStudent)) != array_values($this->_statusAbfolgeVorStudent) + ) + $checks['student'] = false; + } + } + + $this->_cache_history[$primary] = success($checks); + + return success($checks); + } + + /** + * Checks if the time sequence of the status history is valid. + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param DateTime $new_date + * @param string $new_studiensemester_kurzbz + * @param integer $new_ausbildungssemester + * @param string $old_studiensemester_kurzbz + * @param integer $old_ausbildungssemester + * + * @return stdClass + */ + public function checkStatusHistoryTimesequence( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ) { + $result = $this->prepareStatusHistory( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ); + + if (isError($result)) + return $result; + + return success(getData($result)['timesequence']); + } + + /** + * Checks if the last status of the status history is not Abbrecher or + * Absolvent. + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param DateTime $new_date + * @param string $new_studiensemester_kurzbz + * @param integer $new_ausbildungssemester + * @param string $old_studiensemester_kurzbz + * @param integer $old_ausbildungssemester + * + * @return stdClass + */ + public function checkStatusHistoryLaststatus( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ) { + $result = $this->prepareStatusHistory( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ); + + if (isError($result)) + return $result; + + return success(getData($result)['laststatus']); + } + + /** + * Checks if two consecutively Unterbrecher have the same + * ausbildungssemester in the status history. + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param DateTime $new_date + * @param string $new_studiensemester_kurzbz + * @param integer $new_ausbildungssemester + * @param string $old_studiensemester_kurzbz + * @param integer $old_ausbildungssemester + * + * @return stdClass + */ + public function checkStatusHistoryUnterbrechersemester( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ) { + $result = $this->prepareStatusHistory( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ); + + if (isError($result)) + return $result; + + return success(getData($result)['unterbrechersemester']); + } + + /** + * Checks if an Unterbrecher followed by an Abbrecher have the same + * ausbildungssemester in the status history. + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param DateTime $new_date + * @param string $new_studiensemester_kurzbz + * @param integer $new_ausbildungssemester + * @param string $old_studiensemester_kurzbz + * @param integer $old_ausbildungssemester + * + * @return stdClass + */ + public function checkStatusHistoryAbbrechersemester( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ) { + $result = $this->prepareStatusHistory( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ); + + if (isError($result)) + return $result; + + return success(getData($result)['abbrechersemester']); + } + + /** + * Checks if no Diplomant is followed by a Student in the status history. + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param DateTime $new_date + * @param string $new_studiensemester_kurzbz + * @param integer $new_ausbildungssemester + * @param string $old_studiensemester_kurzbz + * @param integer $old_ausbildungssemester + * + * @return stdClass + */ + public function checkStatusHistoryDiplomant( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ) { + $result = $this->prepareStatusHistory( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ); + + if (isError($result)) + return $result; + + return success(getData($result)['diplomant']); + } + + /** + * Checks if a Student precedes given stati in the status history. + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param DateTime $new_date + * @param string $new_studiensemester_kurzbz + * @param integer $new_ausbildungssemester + * @param string $old_studiensemester_kurzbz + * @param integer $old_ausbildungssemester + * + * @return stdClass + */ + public function checkStatusHistoryStudent( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ) { + // TODO(chris): TEST + $result = $this->prepareStatusHistory( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ); + + if (isError($result)) + return $result; + + return success(getData($result)['student']); + } + + /** + * Checks if Personenkennzeichen is set correctly. + * + * @param integer $prestudent_id + * + * @return stdClass + */ + public function checkPersonenkennzeichen($prestudent_id) + { + // TODO(chris): TEST + $this->_ci->PrestudentstatusModel->addSelect('tbl_prestudentstatus.prestudent_id'); + $this->_ci->PrestudentstatusModel->addSelect('tbl_student.matrikelnr'); + + $this->_ci->PrestudentstatusModel->addJoin('public.tbl_student', 'prestudent_id'); + + $this->_ci->PrestudentstatusModel->addOrder('tbl_prestudentstatus.datum', 'DESC'); + $this->_ci->PrestudentstatusModel->addOrder('tbl_prestudentstatus.insertamum', 'DESC'); + $this->_ci->PrestudentstatusModel->addOrder('tbl_prestudentstatus.ext_id', 'DESC'); + + $this->_ci->PrestudentstatusModel->addLimit(1); + + $result = $this->_ci->PrestudentstatusModel->loadWhere([ + 'tbl_prestudentstatus.prestudent_id' => $prestudent_id, + 'tbl_prestudentstatus.status_kurzbz' => self::STATUS_STUDENT + ]); + + if (isError($result)) + return $result; + + if (!hasData($result)) + return success(true); // Not a student yet so no wrong personenkennzeichen + + $data = current(getData($result)); + + $jahr = $this->_ci->StudiensemesterModel->getStudienjahrNumberFromStudiensemester($data->studiensemester_kurzbz); + + + return success($jahr == mb_substr($data->matrikelnr, 0, 2)); + } + + /** + * Checks if Orgform of Student status and Bewerber status match. + * + * @param integer $prestudent_id + * + * @return stdClass + */ + public function checkStudentOrgform($prestudent_id) + { + // TODO(chris): TEST + $result = $this->_ci->PrestudentstatusModel->getBewerberWhereOrgformNotStudent($prestudent_id); + + if (isError($result)) + return $result; + + return success(!hasData($result)); + } + + /** + * Check if History of StatusData is valid + * @param integer $prestudent_id + * @return error if not valid, array StatusArr if valid + */ + private function _checkIfValidStatusHistory( + $prestudent_id, + $status_kurzbz, + $new_status_studiensemester_kurzbz, + $new_status_datum, + $new_status_ausbildungssemester, + $new_studienplan_id, + $old_status_studiensemester = null, + $old_status_ausbildungssemester = null + ) { + //get start studiensemester + $semResult = $this->_ci->StudiensemesterModel->load([ + 'studiensemester_kurzbz' => $new_status_studiensemester_kurzbz + ]); + + if (isError($semResult)) + { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + return $this->outputJson(getError($semResult)); + } + + if (!hasData($semResult)) { + return error($this->_ci->p->t('lehre', 'error_noStudiensemester') . $new_status_studiensemester_kurzbz); + } + + $studiensemester = getData($semResult)[0]; + $new_status_semesterstart = $studiensemester->start; + + // get studienplan orgform + $new_studienplan_orgform_kurzbz = ''; + $this->_ci->StudienplanModel->addSelect('orgform_kurzbz'); + $stplResult = $this->_ci->StudienplanModel->load([ + 'studienplan_id' => $new_studienplan_id + ]); + + if (isError($stplResult)) + { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); + return $this->outputJson(getError($stplResult)); + } + + if (hasData($stplResult)) $new_studienplan_orgform_kurzbz = getData($stplResult)[0]->orgform_kurzbz; + + + //get all prestudentstati + $resultPs = $this->_ci->PrestudentstatusModel->getAllPrestudentstatiWithStudiensemester($prestudent_id); + + if (isError($resultPs)) return $resultPs; + + $resultArr = hasData($resultPs) ? getData($resultPs) : []; + $statusArr = []; + + $newStatusInserted = false; + $new_status_datum_form = new DateTime($new_status_datum); + $new_status_semesterstart_form = new DateTime($new_status_semesterstart); + + if (!isEmptyArray($resultArr)) + { + // neuen Status zum Hinzufügen + $first_status = $resultArr[0]; + $neuer_status = new stdClass(); + $neuer_status->status_kurzbz = $status_kurzbz; + $neuer_status->studiensemester_kurzbz = $new_status_studiensemester_kurzbz; + $neuer_status->datum = $new_status_datum; + $neuer_status->ausbildungssemester = $new_status_ausbildungssemester; + $neuer_status->studienplan_orgform_kurzbz = $new_studienplan_orgform_kurzbz; + $neuer_status->matrikelnr = $first_status->matrikelnr; + $neuer_status->vorname = $first_status->vorname; + $neuer_status->nachname = $first_status->nachname; + + // Status, welcher gerade geändert wird, holen + $status_to_change = array_filter( + $resultArr, + function ($status) use ($status_kurzbz, $old_status_studiensemester, $old_status_ausbildungssemester) { + return + $status->status_kurzbz == $status_kurzbz + && $status->studiensemester_kurzbz == $old_status_studiensemester + && $status->ausbildungssemester == $old_status_ausbildungssemester; + } + ); + + if (!isEmptyArray($status_to_change)) + { + $status_to_change_index = key($status_to_change); + + // wenn sich Studiensemester und Ausbildungssemester nicht geändert haben... + if ($new_status_studiensemester_kurzbz == $old_status_studiensemester + && $new_status_ausbildungssemester == $old_status_ausbildungssemester) + { + // ...neuen status an selber stelle einfügen wie zu ändernder Status + $resultArr[$status_to_change_index] = (object)array_merge((array)$resultArr[$status_to_change_index], (array)$neuer_status); + $newStatusInserted = true; + } + else + { + // bei Status mit neuem Semester: alten Status entfernen + unset($resultArr[$status_to_change_index]); + } + } + } + + foreach ($resultArr as $row) + { + $studiensemester_start = new DateTime($row->studiensemester_start); + $status_datum = new DateTime($row->datum); + + if ($new_status_datum_form >= $status_datum && $new_status_semesterstart_form >= $studiensemester_start) + { + if (!$newStatusInserted) + { + // neuer Status erstmals größer als Datum eines bestehenden Status -> neuen Status EINMALIG einfügen für spätere Statusprüfung + $statusArr[] = $neuer_status; + $newStatusInserted = true; + } + $statusArr[] = $row; + } + elseif ($new_status_datum_form <= $status_datum && $new_status_semesterstart_form <= $studiensemester_start) + { + $statusArr[] = $row; + } + else + { + // Zeitabfolge ungültig, Fehler + return error($this->_ci->p->t('lehre', 'error_statuseintrag_zeitabfolge')); + } + } + + // erster Studentstatus + $ersterStudent = null; + + // Über alle gespeicherten Status gehen und Statusabfolge prüfen + for ($i = 0; $i < count($statusArr); $i++) + { + $curr_status = $statusArr[$i]; + $curr_status_kurzbz = $curr_status->status_kurzbz; + $curr_status_ausbildungssemester = $curr_status->ausbildungssemester; + $next_idx = $i - 1; //absteigend sortiert, nächster Status ist vorheriger Eintrag + $next_status = isset($statusArr[$next_idx]) ? $statusArr[$next_idx] : null; + + $studentName = $curr_status->vorname . ' ' . $curr_status->nachname; + + if ($curr_status_kurzbz == self::STUDENT_STATUS) $ersterStudent = $curr_status; + + // Abbrecher- oder Absolventenstatus muss Endstatus sein + if (isset($next_status) && in_array($curr_status_kurzbz, $this->_endStatusArr)) + { + return error($studentName . ' ' . $this->_ci->p->t('lehre', 'error_endstatus')); + } + + // wenn Unterbrecher auf Unterbrecher folgt, muss Ausbildungssemester gleich sein + if + ($curr_status_kurzbz == self::UNTERBRECHER_STATUS && isset($next_status) && $next_status->status_kurzbz == self::UNTERBRECHER_STATUS + && $curr_status_ausbildungssemester != $next_status->ausbildungssemester) + { + return error($studentName . ' ' . $this->_ci->p->t('lehre', 'error_consecutiveUnterbrecher')); + } + + // wenn Abbrecher auf Unterbrecher folgt, muss Ausbildungssemester gleich sein + if (isset($next_status) + && $curr_status_kurzbz == self::UNTERBRECHER_STATUS + && $next_status->status_kurzbz == self::ABBRECHER_STATUS && $curr_status_ausbildungssemester != $next_status->ausbildungssemester) + { + return error($studentName . ' ' . $this->_ci->p->t('lehre', 'error_consecutiveUnterbrecherAbbrecher')); + } + + if (isset($next_status) && $next_status->status_kurzbz == self::STUDENT_STATUS) + { + $restliche_status_obj = array_slice($statusArr, $i); + $restliche_status = array_unique(array_column($restliche_status_obj, 'status_kurzbz')); + $status_intersected = array_intersect($restliche_status, $this->_statusAbfolgeVorStudent); + + // Vor Studentstatus darf kein Diplomand Status vorhanden sein + if (in_array(self::DIPLOMAND_STATUS, $restliche_status)) + { + return error($studentName . ' ' . $this->_ci->p->t('lehre', 'error_consecutiveDiplomandStudent')); + } + + // Vor Studentstatus müssen bestimmte Status vorhanden sein + if (array_values($status_intersected) != array_values(array_reverse($this->_statusAbfolgeVorStudent))) + { + return error( + $studentName . ' ' + . $this->_ci->p->t('lehre', 'error_wrongStatusOrderBeforeStudent', array(implode(', ', $this->_statusAbfolgeVorStudent))) + ); + } + } + } + + if (isset($ersterStudent)) + { + $studentName = $ersterStudent->vorname . ' ' . $ersterStudent->nachname; + + // wenn erster Studentstatus, checken ob Personenkennzeichen passt + $studienjahrNumber = $this->_ci->StudiensemesterModel->getStudienjahrNumberFromStudiensemester($ersterStudent->studiensemester_kurzbz); + + if ($studienjahrNumber != mb_substr($ersterStudent->matrikelnr, 0, 2)) + { + return error($studentName . ' ' . $this->_ci->p->t('lehre', 'error_personenkennzeichenPasstNichtZuStudiensemester')); + } + + // wenn erster Studentstatus, checken ob Orgform des Bewerbers mit Studenten übereinstimmt + if (!isEmptyArray( + array_filter( + $restliche_status_obj, + function ($s) use ($ersterStudent) { + return + $s->status_kurzbz == self::BEWERBER_STATUS + && ( + $s->studienplan_orgform_kurzbz != $ersterStudent->studienplan_orgform_kurzbz + ); + } + ) + ) + ) + { + return error($studentName . ' ' . $this->_ci->p->t('lehre', 'error_bewerberOrgformUngleichStudentOrgform')); + } + } + + return $resultPs; + } +} diff --git a/application/libraries/SearchBarLib.php b/application/libraries/SearchBarLib.php index 7197eae6a..b725f6e90 100755 --- a/application/libraries/SearchBarLib.php +++ b/application/libraries/SearchBarLib.php @@ -358,6 +358,35 @@ EOSC; */ private function _student($searchstr, $type) { + $dbModel = new DB_Model(); + + $students = $dbModel->execReadOnlyQuery(' + SELECT + \''.$type.'\' AS type, + s.student_uid AS uid, + s.matrikelnr, + p.person_id AS person_id, + p.vorname || \' \' || p.nachname AS name, + k.kontakt as email , + p.foto + FROM public.tbl_student s + JOIN public.tbl_benutzer b ON(b.uid = s.student_uid) + JOIN public.tbl_person p USING(person_id) + LEFT JOIN ( + SELECT kontakt, person_id + FROM public.tbl_kontakt + WHERE kontakttyp = \'email\' + ) as k USING(person_id) + WHERE b.uid ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' + OR p.vorname ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' + OR p.nachname ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' + GROUP BY type, s.student_uid, s.matrikelnr, p.person_id, name, email, p.foto + '); + + // If something has been found then return it + if (hasData($students)) return getData($students); + + // Otherwise return an empty array return array(); } @@ -366,6 +395,41 @@ EOSC; */ private function _prestudent($searchstr, $type) { + $dbModel = new DB_Model(); + + $prestudent = $dbModel->execReadOnlyQuery(' + SELECT + \''.$type.'\' AS type, + ps.prestudent_id, + ps.studiengang_kz, + p.person_id AS person_id, + b.uid, + p.vorname || \' \' || p.nachname AS name, + ( + SELECT kontakt + FROM public.tbl_kontakt + WHERE kontakttyp = \'email\' + AND person_id = p.person_id + LIMIT 1 + ) as email, + p.foto, + sg.bezeichnung + FROM public.tbl_prestudent ps + LEFT JOIN public.tbl_student s USING (prestudent_id) + LEFT JOIN public.tbl_benutzer b ON (b.uid = s.student_uid) + JOIN public.tbl_person p ON (p.person_id = ps.person_id) + LEFT JOIN public.tbl_studiengang sg ON (sg.studiengang_kz = ps.studiengang_kz) + WHERE b.uid ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' + OR p.vorname ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' + OR p.nachname ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' + or cast(ps.prestudent_id as text) ILIKE \'%'.$dbModel->escapeLIKE($searchstr).'%\' + GROUP BY type, b.uid, ps.prestudent_id, ps.studiengang_kz, sg.bezeichnung, s.student_uid, s.matrikelnr, p.person_id, name, email, p.foto + '); + + // If something has been found then return it + if (hasData($prestudent)) return getData($prestudent); + + // Otherwise return an empty array return array(); } diff --git a/application/libraries/UDFLib.php b/application/libraries/UDFLib.php index c5f0d3e98..7437c58ff 100755 --- a/application/libraries/UDFLib.php +++ b/application/libraries/UDFLib.php @@ -65,6 +65,8 @@ class UDFLib private $_udfUniqueId; // Property that contains the UDF widget unique id + private $_definition_cache = []; + /** * Gets CI instance */ @@ -157,7 +159,7 @@ class UDFLib $found = false; // used to check if the field is found or not in the json schema $this->_sortJsonSchemas($jsonSchemasArray); // Sort the list of UDF by sort property - + // Loops through json schemas foreach ($jsonSchemasArray as $jsonSchema) { @@ -292,7 +294,7 @@ class UDFLib // Checks if the requiredPermissions is available and it is a valid array or a valid string if (isset($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}) && (!isEmptyArray($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}) - || !isEmptyString($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}))) + || !isEmptyString($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}))) { // Then check if the user has the permissions to read such UDF if (!$this->_readAllowed($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER})) @@ -353,7 +355,7 @@ class UDFLib // Checks if the requiredPermissions is available and it is a valid array or a valid string if (isset($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}) && (!isEmptyArray($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}) - || !isEmptyString($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}))) + || !isEmptyString($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER}))) { // Then check if the user has the permissions to write such UDF if (!$this->_writeAllowed($decodedUDFDefinition->{self::REQUIRED_PERMISSIONS_PARAMETER})) @@ -613,6 +615,162 @@ class UDFLib ); } + /** + * Gets the UDF definitions for a model + * + * @param DB_Model $targetModel + * + * @return stdClass + */ + public function getDefinitionForModel($targetModel) + { + $dbTable = $targetModel->getDbTable(); + if (!isset($this->_definition_cache[$dbTable])) { + $this->_ci->load->model('system/UDF_model', 'UDFModel'); + list($schema, $table) = explode('.', $dbTable); + $result = $this->_ci->UDFModel->loadWhere([ + 'schema' => $schema, + 'table' => $table + ]); + if (isError($result)) + return $result; + if (!hasData($result)) + $this->_definition_cache[$dbTable] = []; + else + $this->_definition_cache[$dbTable] = json_decode(current($result->retval)->jsons, true); + } + return success($this->_definition_cache[$dbTable]); + } + + /** + * Gets the UDFs for db entry with translated params and resolved listValues for dropdowns + * + * @param DB_Model $targetModel + * @param mixed $id + * + * @return stdClass + */ + public function getFieldArray($targetModel, $id) + { + // Load Libraries + $this->_ci->load->library('PhrasesLib'); + $this->_ci->load->library('PermissionLib'); + + $result = $this->getDefinitionForModel($targetModel); + if (isError($result)) + return $result; + $definitions = $result->retval; + + usort($definitions, function ($a, $b) { + return $a[self::SORT] - $b[self::SORT]; + }); + + $values = $targetModel->getUDFs($id); + + $fields = []; + foreach ($definitions as $field) { + // check read permissions + if (!$this->_ci->permissionlib->hasAtLeastOne( + $field[self::REQUIRED_PERMISSIONS_PARAMETER], + self::PERMISSION_TABLE_METHOD, + self::PERMISSION_TYPE_READ + )) + continue; + + // set value + if (isset($values[$field[self::NAME]])) { + $field['value'] = $values[$field[self::NAME]]; + } elseif (isset($field['defaultValue'])) { + $field['value'] = $field['defaultValue']; + } elseif (isset($field[self::TYPE]) && $field[self::TYPE] == 'checkbox') { + $field['value'] = false; + } else { + $field['value'] = ''; + } + + // translate params + foreach ([self::LABEL, self::TITLE, self::PLACEHOLDER] as $key) { + if (isset($field[$key])) { + $res = $this->_ci->phraseslib->getPhrases(self::PHRASES_APP_NAME, getUserLanguage(), $field[$key], null, null, 'no'); + if (hasData($res)) + $field[$key] = current(getData($res))->text; + } + } + + // check write permissions + $field['disabled'] = !$this->_ci->permissionlib->hasAtLeastOne( + $field[self::REQUIRED_PERMISSIONS_PARAMETER], + self::PERMISSION_TABLE_METHOD, + self::PERMISSION_TYPE_WRITE + ); + + // set listValues for dropdowns + if (isset($field[self::LIST_VALUES])) { + if (isset($field[self::LIST_VALUES]['enum'])) { + $field['options'] = $field[self::LIST_VALUES]['enum']; + } elseif (isset($field[self::LIST_VALUES]['sql'])) { + $res = $this->_ci->UDFModel->execReadOnlyQuery($field[self::LIST_VALUES]['sql']); + $field['options'] = hasData($res) ? getData($res) : []; + } + } + + // add to array + $fields[] = $field; + } + return success($fields); + } + + /** + * Gets a validation config array for CI form_validation + * + * @param DB_Model $targetModel + * @param array (optional) $filter + * + * @return stdClass + */ + public function getCiValidations($targetModel, $filter = null) + { + $result = $this->getDefinitionForModel($targetModel); + if (isError($result)) + return $result; + $definitions = getData($result); + + $result = []; + foreach ($definitions as $def) { + if ($filter && !isset($filter[$def['name']])) + continue; + $validations = []; + if (isset($def['requiredPermissions'])) + $validations[] = 'has_write_permissions[' . implode(',', $def['requiredPermissions']) . ']'; + if (isset($def['required'])) + $validations[] = 'required'; + if (isset($def['validation'])) { + if (isset($def['validation']['max-value'])) + $validations[] = 'less_than_equal_to[' . $def['validation']['max-value'] . ']'; + if (isset($def['validation']['min-value'])) + $validations[] = 'greater_than_equal_to[' . $def['validation']['min-value'] . ']'; + if (isset($def['validation']['max-length'])) + $validations[] = 'max_length[' . $def['validation']['max-length'] . ']'; + if (isset($def['validation']['min-length'])) + $validations[] = 'min_length[' . $def['validation']['min-length'] . ']'; + if (isset($def['validation']['regex']) && is_array($def['validation']['regex'])) { + foreach ($def['validation']['regex'] as $regex) { + if ($regex['language'] == 'php') { + $validations[] = 'regex_match[' . $regex['expression'] . ']'; + } + } + } + } + if ($validations) + $result[] = [ + 'field' => $def['name'], + 'label' => $def['title'], + 'rules' => $validations + ]; + } + return success($result); + } + // ------------------------------------------------------------------------------------------------- // Private methods // @@ -841,7 +999,7 @@ class UDFLib $htmlParameters[HTMLWidget::HTML_ID] = $jsonSchema->{self::NAME}; $htmlParameters[HTMLWidget::HTML_NAME] = $jsonSchema->{self::NAME}; } - + /** * Sort the list of UDF by sort property */ @@ -864,7 +1022,7 @@ class UDFLib return ($a->{self::SORT} < $b->{self::SORT}) ? -1 : 1; }); } - + /** * Loads the UDF description by the given schema and table */ diff --git a/application/libraries/issues/PlausicheckDefinitionLib.php b/application/libraries/issues/PlausicheckDefinitionLib.php index cef28a736..b44a5ce19 100755 --- a/application/libraries/issues/PlausicheckDefinitionLib.php +++ b/application/libraries/issues/PlausicheckDefinitionLib.php @@ -33,7 +33,8 @@ class PlausicheckDefinitionLib 'PrestudentMischformOhneOrgform' => 'PrestudentMischformOhneOrgform', 'StgPrestudentUngleichStgStudienplan' => 'StgPrestudentUngleichStgStudienplan', 'StgPrestudentUngleichStgStudent' => 'StgPrestudentUngleichStgStudent', - 'StudentstatusNachAbbrecher' => 'StudentstatusNachAbbrecher' + 'StudentstatusNachAbbrecher' => 'StudentstatusNachAbbrecher', + 'DualesStudiumOhneMarkierung' => 'DualesStudiumOhneMarkierung' //'StudienplanUngueltig' => 'StudienplanUngueltig' ); diff --git a/application/libraries/issues/PlausicheckProducerLib.php b/application/libraries/issues/PlausicheckProducerLib.php index c32f1f863..3a51e2b1e 100755 --- a/application/libraries/issues/PlausicheckProducerLib.php +++ b/application/libraries/issues/PlausicheckProducerLib.php @@ -12,8 +12,7 @@ class PlausicheckProducerLib private $_ci; // ci instance private $_extensionName; // name of extension - private $_app; // name of application - private $_konfiguration = array(); // konfigratio parameters + private $_konfiguration = array(); // configuration parameters public function __construct($params = null) { diff --git a/application/libraries/issues/plausichecks/DualesStudiumOhneMarkierung.php b/application/libraries/issues/plausichecks/DualesStudiumOhneMarkierung.php new file mode 100644 index 000000000..3951f6d76 --- /dev/null +++ b/application/libraries/issues/plausichecks/DualesStudiumOhneMarkierung.php @@ -0,0 +1,143 @@ +_config['exkludierteStudiengaenge']) ? $this->_config['exkludierteStudiengaenge'] : null; + + // pass parameters needed for plausicheck + $studiensemester_kurzbz = isset($params['studiensemester_kurzbz']) ? $params['studiensemester_kurzbz'] : null; + $studiengang_kz = isset($params['studiengang_kz']) ? $params['studiengang_kz'] : null; + + // get all students failing the plausicheck + $prestudentRes = $this->getDualesStudiumOhneMarkierung( + $studiensemester_kurzbz, + $studiengang_kz, + null, + $exkludierte_studiengang_kz + ); + + if (isError($prestudentRes)) return $prestudentRes; + + if (hasData($prestudentRes)) + { + $prestudents = getData($prestudentRes); + + // populate results with data necessary for writing issues + foreach ($prestudents as $prestudent) + { + $results[] = array( + 'person_id' => $prestudent->person_id, + 'oe_kurzbz' => $prestudent->prestudent_stg_oe_kurzbz, + 'fehlertext_params' => array( + 'prestudent_id' => $prestudent->prestudent_id, + 'studienplan' => $prestudent->studienplan + ), + 'resolution_params' => array( + 'prestudent_id' => $prestudent->prestudent_id, + 'studiensemester_kurzbz' => $prestudent->studiensemester_kurzbz + ) + ); + } + } + + // return the results + return success($results); + } + + /** + * All prestudents in dual Studiengang should have set the dual flag to true. + * @param studiensemester_kurzbz string check is to be executed for certain Studiensemester + * @param studiengang_kz int if check is to be executed for certain Studiengang + * @param prestudent_id int if check is to be executed only for one prestudent + * @param exkludierte_studiengang_kz array if certain Studiengänge have to be excluded from check + * @return success with prestudents or error + */ + public function getDualesStudiumOhneMarkierung( + $studiensemester_kurzbz, + $studiengang_kz = null, + $prestudent_id = null, + $exkludierte_studiengang_kz = null + ) { + $params = array($studiensemester_kurzbz); + + $qry = " + SELECT + DISTINCT pre.person_id, pre.prestudent_id, + stpl.bezeichnung AS studienplan, + status.studiensemester_kurzbz, + status.ausbildungssemester, + stg.oe_kurzbz AS prestudent_stg_oe_kurzbz + FROM + public.tbl_prestudent pre + JOIN public.tbl_prestudentstatus status USING(prestudent_id) + JOIN public.tbl_person USING(person_id) + JOIN lehre.tbl_studienplan stpl USING(studienplan_id) + JOIN public.tbl_studiengang stg ON pre.studiengang_kz = stg.studiengang_kz + JOIN public.tbl_studiensemester sem USING(studiensemester_kurzbz) + WHERE + (stpl.orgform_kurzbz = 'DUA' OR status.orgform_kurzbz = 'DUA') + AND pre.dual = FALSE + AND status.studiensemester_kurzbz=? + AND pre.bismelden + AND stg.melderelevant + AND NOT EXISTS ( + SELECT 1 + FROM + public.tbl_prestudentstatus + JOIN lehre.tbl_studienplan USING(studienplan_id) + JOIN public.tbl_studiensemester USING(studiensemester_kurzbz) + WHERE + prestudent_id = pre.prestudent_id + AND + ( + -- if there is a newer non-dual status, dual has not to be set + ( + ( + tbl_studienplan.orgform_kurzbz <> stpl.orgform_kurzbz + OR status.orgform_kurzbz <> tbl_prestudentstatus.orgform_kurzbz + ) + AND + ( + tbl_studiensemester.ende::date > sem.ende::date + OR (tbl_studiensemester.ende::date = sem.ende::date AND tbl_prestudentstatus.datum::date > status.datum::date) + ) + ) + OR + -- exclude Abgewiesene - they are not reported + tbl_prestudentstatus.status_kurzbz = 'Abgewiesener' + ) + )"; + + if (isset($studiengang_kz)) + { + $qry .= " AND stg.studiengang_kz = ?"; + $params[] = $studiengang_kz; + } + + if (isset($prestudent_id)) + { + $qry .= " AND pre.prestudent_id = ?"; + $params[] = $prestudent_id; + } + + if (isset($exkludierte_studiengang_kz) && !isEmptyArray($exkludierte_studiengang_kz)) + { + $qry .= " AND stg.studiengang_kz NOT IN ?"; + $params[] = $exkludierte_studiengang_kz; + } + + return $this->_db->execReadOnlyQuery($qry, $params); + } +} diff --git a/application/libraries/issues/plausichecks/InaktiverStudentAktiverStatus.php b/application/libraries/issues/plausichecks/InaktiverStudentAktiverStatus.php index dead2b1e7..59965e238 100755 --- a/application/libraries/issues/plausichecks/InaktiverStudentAktiverStatus.php +++ b/application/libraries/issues/plausichecks/InaktiverStudentAktiverStatus.php @@ -67,6 +67,7 @@ class InaktiverStudentAktiverStatus extends PlausiChecker $prestudent_id = null, $exkludierte_studiengang_kz = null ) { + $this->_ci->load->model('organisation/studiensemester_model', 'StudiensemesterModel'); $aktStudiensemesterRes = $this->_ci->StudiensemesterModel->getAkt(); if (isError($aktStudiensemesterRes)) return $aktStudiensemesterRes; diff --git a/application/libraries/issues/resolvers/CORE_STUDENTSTATUS_0016.php b/application/libraries/issues/resolvers/CORE_STUDENTSTATUS_0016.php new file mode 100644 index 000000000..0bba1ddff --- /dev/null +++ b/application/libraries/issues/resolvers/CORE_STUDENTSTATUS_0016.php @@ -0,0 +1,36 @@ +_ci =& get_instance(); // get code igniter instance + + $this->_ci->load->library('issues/plausichecks/DualesStudiumOhneMarkierung'); + + // check if issue persists + $checkRes = $this->_ci->dualesstudiumohnemarkierung->getDualesStudiumOhneMarkierung( + $params['studiensemester_kurzbz'], + null, + $params['prestudent_id'] + ); + + if (isError($checkRes)) return $checkRes; + + if (hasData($checkRes)) + return success(false); // not resolved if issue is still present + else + return success(true); // resolved otherwise + } +} diff --git a/application/libraries/vertragsbestandteil/Dienstverhaeltnis.php b/application/libraries/vertragsbestandteil/Dienstverhaeltnis.php index 309d3dfdc..07c417077 100644 --- a/application/libraries/vertragsbestandteil/Dienstverhaeltnis.php +++ b/application/libraries/vertragsbestandteil/Dienstverhaeltnis.php @@ -29,6 +29,9 @@ class Dienstverhaeltnis extends AbstractBestandteil { protected $updateamum; protected $updatevon; + protected $dvendegrund_kurzbz; + protected $dvendegrund_anmerkung; + public function __construct() { parent::__construct(); @@ -49,6 +52,8 @@ class Dienstverhaeltnis extends AbstractBestandteil { isset($data->insertvon) && $this->setInsertvon($data->insertvon); isset($data->updateamum) && $this->setUpdateamum($data->updateamum); isset($data->updatevon) && $this->setUpdatevon($data->updatevon); + isset($data->dvendegrund_kurzbz) && $this->setDvendegrund_kurzbz($data->dvendegrund_kurzbz); + isset($data->dvendegrund_anmerkung) && $this->setDvendegrund_anmerkung($data->dvendegrund_anmerkung); $this->fromdb = false; } @@ -64,7 +69,9 @@ class Dienstverhaeltnis extends AbstractBestandteil { 'insertamum' => $this->getInsertamum(), 'insertvon' => $this->getInsertvon(), 'updateamum' => $this->getUpdateamum(), - 'updatevon' => $this->getUpdatevon() + 'updatevon' => $this->getUpdatevon(), + 'dvendegrund_kurzbz' => $this->getDvendegrund_kurzbz(), + 'dvendegrund_anmerkung' => $this->getDvendegrund_anmerkung() ); $tmp = array_filter($tmp, function($k) { @@ -139,6 +146,16 @@ EOTXT; return $this->updatevon; } + public function getDvendegrund_kurzbz() + { + return $this->dvendegrund_kurzbz; + } + + public function getDvendegrund_anmerkung() + { + return $this->dvendegrund_anmerkung; + } + public function setDienstverhaeltnis_id($dienstverhaeltnis_id) { $this->markDirty('dienstverhaeltnis_id', $this->dienstverhaeltnis_id, $dienstverhaeltnis_id); @@ -214,6 +231,20 @@ EOTXT; return $this; } + public function setDvendegrund_kurzbz($dvendegrund_kurzbz) + { + $this->markDirty('dvendegrund_kurzbz', $this->dvendegrund_kurzbz, $dvendegrund_kurzbz); + $this->dvendegrund_kurzbz = $dvendegrund_kurzbz; + return $this; + } + + public function setDvendegrund_anmerkung($dvendegrund_anmerkung) + { + $this->markDirty('dvendegrund_anmerkung', $this->dvendegrund_anmerkung, $dvendegrund_anmerkung); + $this->dvendegrund_anmerkung = $dvendegrund_anmerkung; + return $this; + } + public function validate() { //do Validation here $ci = get_instance(); diff --git a/application/libraries/vertragsbestandteil/VertragsbestandteilLib.php b/application/libraries/vertragsbestandteil/VertragsbestandteilLib.php index 297896a02..b58c514e1 100644 --- a/application/libraries/vertragsbestandteil/VertragsbestandteilLib.php +++ b/application/libraries/vertragsbestandteil/VertragsbestandteilLib.php @@ -435,7 +435,7 @@ class VertragsbestandteilLib return $result; } - public function endDienstverhaeltnis(Dienstverhaeltnis $dv, $enddate) + public function endDienstverhaeltnis(Dienstverhaeltnis $dv, $enddate, $dvendegrund_kurzbz=null, $dvendegrund_anmerkung=null) { if( $dv->getBis() !== null && $dv->getBis() < $enddate ) { @@ -460,6 +460,14 @@ class VertragsbestandteilLib $this->endVertragsbestandteil($vb, $enddate); } + if( $dvendegrund_kurzbz !== null ) + { + $dv->setDvendegrund_kurzbz($dvendegrund_kurzbz); + } + if( $dvendegrund_anmerkung !== null ) + { + $dv->setDvendegrund_anmerkung($dvendegrund_anmerkung); + } $dv->setBis($enddate); $this->updateDienstverhaeltnis($dv); diff --git a/application/models/codex/Bismeldestichtag_model.php b/application/models/codex/Bismeldestichtag_model.php index 6ab755c8b..319aa7be7 100644 --- a/application/models/codex/Bismeldestichtag_model.php +++ b/application/models/codex/Bismeldestichtag_model.php @@ -1,7 +1,6 @@ pk = 'meldestichtag_id'; } + public function getLastReachedMeldestichtag($studiensemester_kurzbz = null) + { + $this->addSelect('meldestichtag_id'); + $this->addSelect('meldestichtag'); + $this->addSelect('studiensemester_kurzbz'); + $this->addSelect('insertamum'); + $this->addSelect('insertvon'); + $this->addSelect('updateamum'); + $this->addSelect('updatevon'); + + if ($studiensemester_kurzbz) { + $this->db->where('studiensemester_kurzbz', $studiensemester_kurzbz); + } + + $this->addOrder('meldestichtag', 'DESC'); + $this->addLimit(1); + + return $this->loadWhere([ + 'meldestichtag < NOW()' => null + ]); + } + + /** + * Prüft, ob Meldestichtag für ein bestimmtes Statusdatum und Studiensemester erreicht ist. + * + * @param $status_datum + * @return boolean true wenn erreicht, oder false + */ + public function checkIfMeldestichtagErreicht($status_datum, $studiensemester_kurzbz = null) + { + $erreicht = false; + + if (isset($studiensemester_kurzbz)) + { + // Studiensemesterende holen + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $result = $this->StudiensemesterModel->loadWhere( + array( + 'studiensemester_kurzbz' => $studiensemester_kurzbz + ) + ); + if(isError($result)) + { + return $result; + } + $result = current(getData($result)); + + $studiensemester_ende = new DateTime($result->ende); + } + + // letztes erreichtes Bismeldedatum holen + $result = $this->getLastReachedMeldestichtag(); + if (isError($result)) + { + return $result; + } + if (!hasData($result)) { + return success("0",'No Statusdata vorhanden'); + } + $stichtag = current(getData($result)); + $stichtag = new DateTime($stichtag->meldestichtag); + + $statusDatum = new DateTime($status_datum); + + // Prüfen, ob Studentstatusdatum oder Studiensemester vor dem Stichtagsdatum liegen + if (isset($statusDatum)) + { + if (isset($stichtag)) + $erreicht = $statusDatum < $stichtag; + } + + if (isset($studiensemester_ende)) + { + $erreicht = $erreicht || $studiensemester_ende < $stichtag; + } + + if ($erreicht) + return success("1", "Studentstatus mit Datum oder Semesterende vor erreichtem Meldestichtag können nicht hinzugefügt werden"); + + return success("0", "Meldestatus nicht erreicht"); + } + /** * Gets last Bismeldestichtag for a Studiensemester. * @param $studiensemester_kurzbz diff --git a/application/models/codex/Gemeinde_model.php b/application/models/codex/Gemeinde_model.php index 92f0e0ca4..069037cee 100755 --- a/application/models/codex/Gemeinde_model.php +++ b/application/models/codex/Gemeinde_model.php @@ -20,16 +20,17 @@ class Gemeinde_model extends DB_Model return $this->loadWhere(array("plz" => $plz)); } - public function getGemeindeByNation($nation, $zip){ - - + public function getGemeindeByNation($nation, $zip) + { $this->addSelect(["name"]); - if ($nation == "A") { - if (isset($zip) && $zip > 999 && $zip < 32000) { - + if ($nation == "A") + { + if (isset($zip) && $zip > 999 && $zip < 32000) + { $gemeinde_res = $this->GemeindeModel->loadWhere(['plz' => $zip]); - if (isError($gemeinde_res)) { + if (isError($gemeinde_res)) + { show_error("error while trying to query bis.tbl_gemeinde"); } $gemeinde_res = hasData($gemeinde_res) ? getData($gemeinde_res) : null; @@ -41,6 +42,15 @@ class Gemeinde_model extends DB_Model } else { echo json_encode(error("ortschaftskennziffer code was not valid")); } - } else {} + } } -} \ No newline at end of file + + public function checkLocation($plz, $gemeinde, $ort) + { + $this->db->where('ortschaftsname', $ort); + $this->db->where('name', $gemeinde); + $this->db->where('plz', $plz); + + return (boolean)$this->db->count_all_results($this->dbTable); + } +} diff --git a/application/models/crm/Konto_model.php b/application/models/crm/Konto_model.php index bc6ec4276..51d3117bc 100755 --- a/application/models/crm/Konto_model.php +++ b/application/models/crm/Konto_model.php @@ -1,4 +1,7 @@ pk = 'buchungsnr'; } + /** + * Insert Data into DB-Table + * + * @param array $data DataArray for Insert + * @return stdClass + */ + public function insert($data, $encryptedColumns = null) + { + if (isset($data['buchungsnr_verweis']) && $data['buchungsnr_verweis']) + return parent::insert($data, $encryptedColumns); + + $this->db->trans_begin(); + + $result = parent::insert($data, $encryptedColumns); + if (isError($result)) { + $this->db->trans_rollback(); + return $result; + } + + $buchungsnr = $result->retval; + // If studiengang_kz is not present in $data it will fail above since it is a not null field + $studiengang_kz = $data['studiengang_kz']; + + + $zahlungsreferenz = false; + Events::trigger('generate_zahlungsreferenz', $buchungsnr, $data, function ($value) use ($zahlungsreferenz) { + $zahlungsreferenz = $value; + }); + + if ($zahlungsreferenz === false) { + $result = $this->execQuery('SELECT UPPER(oe_kurzbz) || ? as zahlungsreferenz + FROM public.tbl_studiengang + WHERE studiengang_kz=?', [$buchungsnr, $studiengang_kz]); + if (isError($result)) { + $this->db->trans_rollback(); + return $result; + } + $zahlungsreferenz = current(getData($result))->zahlungsreferenz; + } elseif (isError($zahlungsreferenz)) { + $this->db->trans_rollback(); + return $zahlungsreferenz; + } + + + $result = $this->update($buchungsnr, [ + 'zahlungsreferenz' => $zahlungsreferenz + ]); + + if (isError($result)) { + $this->db->trans_rollback(); + return $result; + } + + $this->db->trans_commit(); + + return success($buchungsnr); + } + + /** + * Delete data from DB-Table + * + * @param string $id Primary Key for DELETE + * + * @return stdClass + */ + public function delete($id) + { + $this->db->where('buchungsnr_verweis', $id); + if ($this->db->count_all_results($this->dbTable)) + return error('Bitte zuerst die zugeordneten Buchungen loeschen', 42); + return parent::delete($id); + } + + /** + * Adds additional fields to the Query + * + * @return Konto_model + */ + public function withAdditionalInfo() + { + $this->addSelect($this->dbTable . '.*'); + $this->addSelect('UPPER(typ::varchar(1) || kurzbz) AS kuerzel'); + $this->addSelect('person.anrede'); + $this->addSelect('person.titelpost'); + $this->addSelect('person.titelpre'); + $this->addSelect('person.vorname'); + $this->addSelect('person.vornamen'); + $this->addSelect('person.nachname'); + + $this->addJoin('public.tbl_studiengang stg', 'studiengang_kz', 'LEFT'); + $this->addJoin('public.tbl_person person', 'person_id', 'LEFT'); + + Events::trigger('konto_query'); + + return $this; + } + + /** + * Get all accounting entries for a person optionally filtered by Studiengang + * + * @param integer|array $person_id + * @param string (optional) $studiengang_kz + * + * @return stdClass + */ + public function getAlleBuchungen($person_id, $studiengang_kz = '') + { + $this->withAdditionalInfo(); + + $this->addOrder('buchungsdatum'); + + if (is_array($person_id)) + $this->db->where_in('person_id', $person_id); + else + $this->db->where('person_id', $person_id); + + if ($studiengang_kz) + return $this->loadWhere([ + 'studiengang_kz' => $studiengang_kz + ]); + return $this->load(); + } + + /** + * Get all open accounting entries for a person optionally filtered by Studiengang + * + * @param integer|array $person_id + * @param string (optional) $studiengang_kz + * + * @return stdClass + */ + public function getOffeneBuchungen($person_id, $studiengang_kz = '') + { + $this->addSelect('buchungsnr'); + $this->db->where('(betrag + ( + SELECT CASE WHEN sum(betrag) is null THEN 0 ELSE sum(betrag) END + FROM ' . $this->dbTable . ' + WHERE buchungsnr_verweis=konto_a.buchungsnr + )) !=', 0, false); + if (is_array($person_id)) + $this->db->where_in('person_id', $person_id); + else + $this->db->where('person_id', $person_id); + $sql = $this->db->get_compiled_select($this->dbTable . ' konto_a'); + + $this->db->group_start(); + $this->db->where_in('buchungsnr', $sql, false); + $this->db->or_where_in('buchungsnr_verweis', $sql, false); + $this->db->group_end(); + + return $this->getAlleBuchungen($person_id, $studiengang_kz); + } + + /** + * Check double Buchungen + * + * @param array $person_ids + * @param string $studiensemester_kurzbz + * @param array $buchungstyp_kurzbzs + * + * @return stdClass + */ + public function checkDoubleBuchung($person_ids, $studiensemester_kurzbz, $buchungstyp_kurzbzs) + { + $this->addSelect('vorname'); + $this->addSelect('nachname'); + + $this->addJoin('public.tbl_person', 'person_id'); + + $this->db->where_in('person_id', $person_ids); + $this->db->where_in('buchungstyp_kurzbz', $buchungstyp_kurzbzs); + + $this->addGroupBy('vorname, nachname'); + $this->addOrder('nachname'); + $this->addOrder('vorname'); + + return $this->loadWhere([ + 'studiensemester_kurzbz' => $studiensemester_kurzbz + ]); + } + + /** + * Berechnet den offenen Betrag einer Buchung + * + * @param integer $buchungsnr + * + * @return stdClass + */ + public function getDifferenz($buchungsnr) + { + $this->addSelect('buchungsnr_verweis'); + $this->db->where('buchungsnr', $buchungsnr); + $sql = $this->db->get_compiled_select($this->dbTable); + + $this->addSelect('buchungsnr_verweis'); + $this->db->where('buchungsnr', $buchungsnr); + $this->db->or_where('buchungsnr_verweis', '(' . $sql . ')', false); + $sql = $this->db->get_compiled_select($this->dbTable); + + $this->addSelect('sum(betrag) differenz'); + $this->db->where('buchungsnr', $buchungsnr); + $this->db->or_where('buchungsnr_verweis', $buchungsnr); + $this->db->or_where('buchungsnr', '(' . $sql . ')', false); + + $result = $this->load(); + if (isError($result)) + return $result; + if (!hasData($result)) + return success(null); + return success(current(getData($result))->differenz * -1); + } + /** * Sets a Payment as paid */ diff --git a/application/models/crm/Prestudent_model.php b/application/models/crm/Prestudent_model.php index 7b24b8769..242c26518 100755 --- a/application/models/crm/Prestudent_model.php +++ b/application/models/crm/Prestudent_model.php @@ -14,6 +14,39 @@ class Prestudent_model extends DB_Model $this->load->model('crm/prestudentstatus_model', 'PrestudentstatusModel'); } + /** + * Update Data in DB-Table + * + * @param string $id PK for DB-Table + * @param array $data DataArray for Insert + * @return array + */ + public function update($id, $data, $encryptedColumns = null) + { + if (isset($data['zgvmas_code']) + || isset($data['zgvmanation']) + || isset($data['zgv_code']) + || isset($data['zgvnation']) + ) { + /** + * Falls ZGV vorhanden, setze Ausstellungsstaat (für BIS-Meldung) + * auf Nation der höchsten angegebenen ZGV + */ + $case = '(CASE + WHEN zgvmas_code IS NOT NULL AND zgvmanation IS NOT NULL THEN zgvmanation + WHEN zgv_code IS NOT NULL AND zgvnation IS NOT NULL THEN zgvnation + ELSE NULL END)'; + + foreach (['zgvmas_code', 'zgvmanation', 'zgv_code', 'zgvnation'] as $key) + if (isset($data[$key])) + $case = str_replace($key, $this->escape($data[$key]), $case); + + $this->db->set('ausstellungsstaat', $case, false); + } + + return parent::update($id, $data, $encryptedColumns); + } + /** * getLastStatuses */ @@ -700,4 +733,33 @@ class Prestudent_model extends DB_Model return $this->execQuery($query, array($prestudent_id)); } + /** + * Gets history of all prestudents, person_id given + * @param int $person_id + * @return object + */ + public function getHistoryPrestudents($person_id) + { + + $query = " + SELECT ps.studiensemester_kurzbz, p.priorisierung, p.studiengang_kz, sg.kurzbzlang, ps.orgform_kurzbz, + ps.status_kurzbz, s.student_uid, sp.bezeichnung, ps.ausbildungssemester, + CONCAT(ps.status_kurzbz, ' (', ps.ausbildungssemester, '. Semester)') as status, p.prestudent_id + FROM public.tbl_prestudent p + JOIN ( + SELECT DISTINCT ON(prestudent_id) * + FROM public.tbl_prestudentstatus + WHERE prestudent_id IN (SELECT prestudent_id FROM public.tbl_prestudent WHERE person_id = ?) + ORDER BY prestudent_id, datum desc, insertamum desc + ) ps USING(prestudent_id) + JOIN public.tbl_status USING(status_kurzbz) + LEFT JOIN public.tbl_status_grund g USING (statusgrund_id) + JOIN public.tbl_studiengang sg USING(studiengang_kz) + LEFT JOIN lehre.tbl_studienplan sp USING (studienplan_id) + LEFT JOIN public.tbl_student s USING (prestudent_id) + ORDER BY p.priorisierung + "; + + return $this->execQuery($query, array($person_id)); + } } diff --git a/application/models/crm/Prestudentstatus_model.php b/application/models/crm/Prestudentstatus_model.php index 30e4f1a42..eee8e3434 100755 --- a/application/models/crm/Prestudentstatus_model.php +++ b/application/models/crm/Prestudentstatus_model.php @@ -5,6 +5,15 @@ class Prestudentstatus_model extends DB_Model const STATUS_ABBRECHER = 'Abbrecher'; const STATUS_UNTERBRECHER = 'Unterbrecher'; + const STATUS_STUDENT = 'Student'; + const STATUS_DIPLOMAND = 'Diplomand'; + const STATUS_ABSOLVENT = 'Absolvent'; + const STATUS_BEWERBER = 'Bewerber'; + const STATUS_AUFGENOMMENER = 'Aufgenommener'; + const STATUS_WARTENDER = 'Wartender'; + const STATUS_ABGEWIESENER = 'Abgewiesener'; + const STATUS_INTERESSENT = 'Interessent'; + const STATUS_INCOMING = 'Incoming'; /** * Constructor @@ -401,13 +410,252 @@ class Prestudentstatus_model extends DB_Model */ public function withGrund($statusgrund_kurzbz) { - if($statusgrund_kurzbz) + if ($statusgrund_kurzbz) $this->db->set( 'statusgrund_id', - '(SELECT statusgrund_id FROM public.tbl_status_grund WHERE statusgrund_kurzbz =' . $this->db->escape($statusgrund_kurzbz) .')', + '(SELECT statusgrund_id FROM public.tbl_status_grund WHERE statusgrund_kurzbz=' . $this->db->escape($statusgrund_kurzbz) . ')', false ); return $this; } + + /** + * Check if there is only one prestudentstatus left + * + * @param integer $prestudent_id + * @param string $studiensemester_kurzbz + * + * @return stdClass + */ + public function checkIfLastStatusEntry($prestudent_id, $studiensemester_kurzbz = null) + { + $this->addSelect('COUNT(*) AS anzahl', false); + + if ($studiensemester_kurzbz) + $this->db->where('studiensemester_kurzbz', $studiensemester_kurzbz); + + $result = $this->loadWhere([ + 'prestudent_id' => $prestudent_id + ]); + + if (isError($result)) + return $result; + + $resultObject = current($result->retval); + + $anzahl = (int)$resultObject->anzahl; + + if ($anzahl <= 1) + return success(true, $this->p->t('lehre', 'error_lastRole')); + + return success(false, $this->p->t('lehre', 'anzahl_existingRoles', ['anzahl' => $anzahl])); + } + + public function getAllPrestudentstatiWithStudiensemester($prestudent_id) + { + $qry = " + SELECT + tbl_prestudentstatus.status_kurzbz, + tbl_prestudentstatus.studiensemester_kurzbz, + tbl_prestudentstatus.ausbildungssemester, + tbl_prestudentstatus.datum, + s.start AS studiensemester_start, + pl.orgform_kurzbz AS studienplan_orgform_kurzbz, + stud.matrikelnr, + pers.vorname, + pers.nachname + FROM + public.tbl_prestudentstatus + JOIN public.tbl_studiensemester s USING (studiensemester_kurzbz) + JOIN public.tbl_prestudent USING (prestudent_id) + JOIN public.tbl_person pers USING (person_id) + LEFT JOIN public.tbl_student stud USING (prestudent_id) + LEFT JOIN lehre.tbl_studienplan pl USING (studienplan_id) + WHERE + prestudent_id = ? + ORDER BY + public.tbl_prestudentstatus.datum DESC, + public.tbl_prestudentstatus.insertamum DESC, + public.tbl_prestudentstatus.ext_id DESC + "; + + return $this->execQuery($qry, array($prestudent_id)); + } + + /** + * Gets status history of a prestudent + * This function uses the language of the logged in user to + * translate the given statusgrund + * + * @param integer $prestudent_id + * + * @return stdClass + */ + public function getHistoryPrestudent($prestudent_id) + { + $lang= getUserLanguage(); + $this->addSelect('tbl_prestudentstatus.prestudent_id'); + $this->addSelect('tbl_prestudentstatus.status_kurzbz'); + $this->addSelect('tbl_prestudentstatus.studiensemester_kurzbz'); + $this->addSelect('tbl_prestudentstatus.ausbildungssemester'); + $this->addSelect('tbl_prestudentstatus.datum'); + $this->addSelect("TO_CHAR(tbl_prestudentstatus.datum::timestamp, 'DD.MM.YYYY') AS format_datum"); + $this->addSelect('tbl_prestudentstatus.insertamum'); + $this->addSelect('tbl_prestudentstatus.insertvon'); + $this->addSelect('tbl_prestudentstatus.updateamum'); + $this->addSelect('tbl_prestudentstatus.updatevon'); + $this->addSelect('tbl_prestudentstatus.orgform_kurzbz'); + $this->addSelect('tbl_prestudentstatus.bestaetigtam'); + $this->addSelect("TO_CHAR(tbl_prestudentstatus.bestaetigtam::timestamp, 'DD.MM.YYYY') AS format_bestaetigtam"); + $this->addSelect('tbl_prestudentstatus.bestaetigtvon'); + $this->addSelect('tbl_prestudentstatus.bewerbung_abgeschicktamum'); + $this->addSelect("TO_CHAR(tbl_prestudentstatus.bewerbung_abgeschicktamum::timestamp, 'DD.MM.YYYY') AS format_bewerbung_abgeschicktamum"); + $this->addSelect('tbl_prestudentstatus.anmerkung'); + $this->addSelect('plan.studienplan_id'); + $this->addSelect('plan.bezeichnung'); + + $this->addSelect('grund.beschreibung[( + SELECT index + FROM public.tbl_sprache + WHERE sprache=' . $this->escape($lang) . ' + )] AS statusgrund_bezeichnung', false); + $this->addSelect("CASE + WHEN s.student_uid IS NOT NULL + AND tbl_prestudentstatus.status_kurzbz IN (" . implode(",", $this->escape([ + 'Student', + 'Diplomand', + 'Abbrecher', + 'Absolvent', + 'Ausserodentlicher', + 'Incoming', + 'Outgoing', + 'Unterbrecher' + ])) . ") + THEN lv.semester || lv.verband || lv.gruppe + ELSE '-' + END AS lehrverband", false); + + + $this->addJoin('lehre.tbl_studienplan plan', 'studienplan_id', 'LEFT'); + $this->addJoin('public.tbl_status_grund grund', 'statusgrund_id', 'LEFT'); + $this->addJoin('public.tbl_student s', 'prestudent_id', 'LEFT'); + $this->addJoin( + 'public.tbl_studentlehrverband lv', + 's.student_uid IS NOT NULL AND s.student_uid=lv.student_uid AND tbl_prestudentstatus.studiensemester_kurzbz=lv.studiensemester_kurzbz', + 'LEFT' + ); + + $this->addOrder('tbl_prestudentstatus.datum', 'DESC'); + $this->addOrder('tbl_prestudentstatus.insertamum', 'DESC'); + $this->addOrder('tbl_prestudentstatus.ext_id', 'DESC'); + + return $this->loadWhere([ + 'tbl_prestudentstatus.prestudent_id' => $prestudent_id + ]); + } + + /** + * Gets status history of a prestudent for checking purposes. + * This function adds the new state or replaces the edited. + * + * @param integer $prestudent_id + * @param string $status_kurzbz + * @param DateTime $new_date + * @param string $new_studiensemester_kurzbz + * @param integer $new_ausbildungssemester + * @param string $old_studiensemester_kurzbz + * @param integer $old_ausbildungssemester + * + * @return stdClass + */ + public function getHistoryWithNewOrEditedState( + $prestudent_id, + $status_kurzbz, + $new_date, + $new_studiensemester_kurzbz, + $new_ausbildungssemester, + $old_studiensemester_kurzbz, + $old_ausbildungssemester + ) { + $new_date = $new_date->format('Y-m-d'); + + $this->addSelect('status_kurzbz'); + $this->addSelect('studiensemester_kurzbz'); + $this->addSelect('ausbildungssemester'); + $this->addSelect('datum'); + $this->addSelect('insertamum'); + $this->addSelect('ext_id'); + + if ($old_studiensemester_kurzbz || $old_ausbildungssemester) { + $this->db->not_group_start(); + $this->db->where('status_kurzbz', $status_kurzbz); + $this->db->where('studiensemester_kurzbz', $old_studiensemester_kurzbz); + $this->db->where('ausbildungssemester', $old_ausbildungssemester); + $this->db->group_end(); + } + + $this->db->where('prestudent_id', $prestudent_id); + + $tmpTable = $this->db->get_compiled_select($this->dbTable); + + $tmpTable .= "UNION + SELECT " . + $this->escape($status_kurzbz) . " AS status_kurzbz, " . + $this->escape($new_studiensemester_kurzbz) . " AS studiensemester_kurzbz, " . + $this->escape($new_ausbildungssemester) . " AS ausbildungssemester, " . + $this->escape($new_date) . "::date AS datum," . + $this->escape(date('c')) . "::date AS insertamum," . + "NULL AS ext_id"; + + $this->addJoin('public.tbl_studiensemester sem', 'studiensemester_kurzbz'); + + $this->addOrder('s.datum', 'DESC'); + $this->addOrder('s.insertamum', 'DESC'); + $this->addOrder('s.ext_id', 'DESC'); + + $dbTable = $this->dbTable; + $this->dbTable = "(" . $tmpTable . ") s"; + + $result = $this->load(); + + $this->dbTable = $dbTable; + + return $result; + } + + /** + * For checks if Orgform of Student status and Bewerber status match. + * Returns any Bewerber status that does not match the first Student + * status' Orgform. + * + * @param integer $prestudent_id + * + * @return stdClass + */ + public function getBewerberWhereOrgformNotStudent($prestudent_id) + { + $this->addSelect('plan.orgform_kurzbz'); + + $this->addJoin('lehre.tbl_studienplan plan', 'studienplan_id', 'LEFT'); + + $this->addOrder('tbl_prestudentstatus.datum', 'DESC'); + $this->addOrder('tbl_prestudentstatus.insertamum', 'DESC'); + $this->addOrder('tbl_prestudentstatus.ext_id', 'DESC'); + + $this->addLimit(1); + + $this->db->where('prestudent_id', $prestudent_id); + $this->db->where('status_kurzbz', self::STATUS_STUDENT); + + $sql = $this->db->get_compiled_select($this->dbTable); + + $this->addJoin('lehre.tbl_studienplan plan', 'studienplan_id', 'LEFT'); + + $this->db->where('plan.orgform_kurzbz !=', '(' . $sql . ')', false); + return $this->loadWhere([ + 'prestudent_id' => $prestudent_id, + 'status_kurzbz' => self::STATUS_BEWERBER + ]); + } } diff --git a/application/models/crm/Status_model.php b/application/models/crm/Status_model.php index 7b1b38ecb..1ee2a5199 100755 --- a/application/models/crm/Status_model.php +++ b/application/models/crm/Status_model.php @@ -11,4 +11,21 @@ class Status_model extends DB_Model $this->dbTable = 'public.tbl_status'; $this->pk = 'status_kurzbz'; } + + public function getAllStatiWithStatusgruende() + { + $lang = '[(SELECT index FROM public.tbl_sprache WHERE sprache=' . $this->escape(getUserLanguage()) . ' LIMIT 1)]'; + + $this->addSelect('sg.status_kurzbz'); + + $this->addSelect('statusgrund_id'); + $this->addSelect('sg.bezeichnung_mehrsprachig' . $lang . ' AS bezeichnung'); + $this->addSelect('sg.beschreibung' . $lang . ' AS beschreibung'); + + $this->addJoin('public.tbl_status_grund sg', 'ON (sg.status_kurzbz = public.tbl_status.status_kurzbz)', 'LEFT'); + + return $this->loadWhere([ + 'aktiv'=> true, + ]); + } } diff --git a/application/models/crm/Statusgrund_model.php b/application/models/crm/Statusgrund_model.php index d488e12d1..8fc2a3a62 100755 --- a/application/models/crm/Statusgrund_model.php +++ b/application/models/crm/Statusgrund_model.php @@ -27,4 +27,19 @@ class Statusgrund_model extends DB_Model return success($status->retval); } + + public function getAktiveGruende() + { + $lang = '[(SELECT index FROM public.tbl_sprache WHERE sprache=' . $this->escape(getUserLanguage()) . ' LIMIT 1)]'; + + $this->addSelect('tbl_status_grund.*'); + $this->addSelect('bezeichnung_mehrsprachig' . $lang . ' AS bezeichnung'); + $this->addSelect('beschreibung' . $lang . ' AS beschreibung'); + + $this->addOrder('bezeichnung_mehrsprachig' . $lang); + + return $this->loadWhere([ + 'aktiv' => true + ]); + } } diff --git a/application/models/crm/Student_model.php b/application/models/crm/Student_model.php index 6d4bc479b..539c3cf56 100755 --- a/application/models/crm/Student_model.php +++ b/application/models/crm/Student_model.php @@ -1,4 +1,8 @@ = 90010 && $studiengang_kz <= 90019) + { + $matrikelnummer = sprintf("%02d", $jahr).$art.substr($studiengang_kz, 0, 4); + } + else + { + $matrikelnummer = sprintf("%02d", $jahr).$art.sprintf("%04d", $studiengang_kz); + } + + $qry = "SELECT matrikelnr FROM public.tbl_student WHERE matrikelnr LIKE ? ORDER BY matrikelnr DESC LIMIT 1"; + $matrikelnrres = $this->execQuery($qry, array($matrikelnummer.'%')); + + $max = 0; + if ($matrikelnrres && hasData($matrikelnrres)) { + $max = mb_substr($matrikelnrres->retval[0]->matrikelnr, 7); + if (!is_numeric($max)) { + $max = (int)$max; + } + } + + $max += 1; + return success($matrikelnummer.sprintf("%03d", $max)); + } + + /** + * Generiert die UID + * FORMAT: el07b001 + * $stgkzl: el = studiengangskuerzel + * $jahr: 07 = Jahr + * $stgtyp: b/m/d/x = Bachelor/Master/Diplom/Incoming + * $matrikelnummer + * 001 = Laufende Nummer Wenn StSem==SS dann wird zur Nummer 500 dazugezaehlt + * Bei Incoming im Masterstudiengang wird auch 500 dazugezaehlt + * + * @param string $stgkzl + * @param string $jahr + * @param string $stgtyp + * @param string $matrikelnummer + * @param string $vorname + * @param string $nachname + * + * @return stdClass + */ + public function generateUID($stgkzl, $jahr, $stgtyp, $matrikelnummer, $vorname, $nachname) + { + $uid = false; + + Events::trigger( + 'generate_student_uid', + function ($value) use ($uid) { + $uid = $value; + }, + $stgkzl, + $jahr, + $stgtyp, + $matrikelnummer, + $vorname, + $nachname + ); + + if ($uid !== false) + return success($uid); + + $art = mb_substr($matrikelnummer, 2, 1); + $nr = mb_substr($matrikelnummer, mb_strlen(trim($matrikelnummer))-3); + if($art=='2') //Sommersemester + $nr = $nr+500; + elseif($art=='0' && $stgtyp=='m') //Incoming im Masterstudiengang + $nr = $nr+500; + elseif($art=='4' && $stgtyp=='l') // Lehrgangsteilnehmer im Sommersemester + $nr = $nr+500; + + + return success(mb_strtolower($stgkzl.$jahr.($art!='0'?$stgtyp:'x').$nr)); + } + + /** * Get students UID by PrestudentID. * @param $prestudent_id @@ -100,7 +264,8 @@ class Student_model extends DB_Model OR lower(person.nachname) like ".$this->db->escape('%'.$filter.'%')." OR lower(person.vorname) like ".$this->db->escape('%'.$filter.'%')." OR lower(person.nachname || ' ' || person.vorname) like ".$this->db->escape('%'.$filter.'%')." - OR lower(person.vorname || ' ' || person.nachname) like ".$this->db->escape('%'.$filter.'%')); + OR lower(person.vorname || ' ' || person.nachname) like ".$this->db->escape('%'.$filter.'%') + ); return $result; } diff --git a/application/models/education/Gsstudientyp_model.php b/application/models/education/Gsstudientyp_model.php new file mode 100644 index 000000000..ca9106d99 --- /dev/null +++ b/application/models/education/Gsstudientyp_model.php @@ -0,0 +1,14 @@ +dbTable = 'bis.tbl_gsstudientyp'; + $this->pk = 'gsstudientyp_kurzbz'; + } +} \ No newline at end of file diff --git a/application/models/education/Lehrveranstaltung_model.php b/application/models/education/Lehrveranstaltung_model.php index 500aea07d..b7241ce04 100755 --- a/application/models/education/Lehrveranstaltung_model.php +++ b/application/models/education/Lehrveranstaltung_model.php @@ -667,4 +667,10 @@ class Lehrveranstaltung_model extends DB_Model return $this->execQuery($qry, $binds); } + public function getStg($lehrveranstaltung_id) + { + $this->addSelect('stg.*'); + $this->addJoin('public.tbl_studiengang stg', 'studiengang_kz'); + return $this->load($lehrveranstaltung_id); + } } diff --git a/application/models/education/Studentlehrverband_model.php b/application/models/education/Studentlehrverband_model.php index 765429396..2ef14e58e 100755 --- a/application/models/education/Studentlehrverband_model.php +++ b/application/models/education/Studentlehrverband_model.php @@ -11,5 +11,7 @@ class Studentlehrverband_model extends DB_Model $this->dbTable = 'public.tbl_studentlehrverband'; $this->pk = array('studiensemester_kurzbz', 'student_uid'); $this->hasSequence = false; + + $this->load->model('crm/prestudentstatus_model', 'PrestudentstatusModel'); } } diff --git a/application/models/organisation/Lehrverband_model.php b/application/models/organisation/Lehrverband_model.php index 953e4b7b2..0e760a116 100755 --- a/application/models/organisation/Lehrverband_model.php +++ b/application/models/organisation/Lehrverband_model.php @@ -11,4 +11,34 @@ class Lehrverband_model extends DB_Model $this->dbTable = 'public.tbl_lehrverband'; $this->pk = array('gruppe', 'verband', 'semester', 'studiengang_kz'); } + + /** + * Gets the maximum possible semester for one or more Studiengaenge. + * If there are more than one Studiengang each maximum is calculated and + * the smallest result is returned. + * + * @param array $studiengang_kzs + * + * @return stdClass + */ + public function getMaxSemester($studiengang_kzs) + { + $sqls = []; + foreach ($studiengang_kzs as $studiengang_kz) { + $this->addSelect('MAX(semester) AS maxsem'); + $this->db->where('studiengang_kz', $studiengang_kz); + $sqls[] = $this->db->get_compiled_select($this->dbTable); + } + + $this->addSelect('MIN(a.maxsem) AS maxsem'); + + $dbTable = $this->dbTable; + $this->dbTable = '(' . implode(' UNION ', $sqls) . ') AS a'; + + $result = $this->load(); + + $this->dbTable = $dbTable; + + return $result; + } } diff --git a/application/models/organisation/Organisationseinheit_model.php b/application/models/organisation/Organisationseinheit_model.php index 86523cab9..1b1a826aa 100755 --- a/application/models/organisation/Organisationseinheit_model.php +++ b/application/models/organisation/Organisationseinheit_model.php @@ -202,4 +202,19 @@ class Organisationseinheit_model extends DB_Model return $this->load($oe_kurzbz); } + /** + * Get OEs by eventQuery string. Use with autocomplete event queries. + * @param $eventQuery String + * @return array + */ + public function getAutocompleteSuggestions($eventQuery) + { + $this->addSelect('oe_kurzbz'); + $this->addSelect('organisationseinheittyp_kurzbz, oe_kurzbz, bezeichnung, aktiv, lehre'); + $this->addOrder('organisationseinheittyp_kurzbz, bezeichnung'); + + return $this->loadWhere(" + oe_kurzbz ILIKE '%". $this->escapeLike($eventQuery). "%' + "); + } } diff --git a/application/models/organisation/Standort_model.php b/application/models/organisation/Standort_model.php index 382236e2f..aeeab4497 100755 --- a/application/models/organisation/Standort_model.php +++ b/application/models/organisation/Standort_model.php @@ -11,4 +11,29 @@ class Standort_model extends DB_Model $this->dbTable = 'public.tbl_standort'; $this->pk = 'standort_id'; } + + public function searchStandorte($filter) + { + $filter = strtoLower($filter); + $qry = " + SELECT + s.kurzbz, s.standort_id + FROM + public.tbl_standort s + WHERE + lower (s.kurzbz) LIKE '%". $this->db->escape_like_str($filter)."%' + OR + lower (s.bezeichnung) LIKE '%". $this->db->escape_like_str($filter)."%'"; + + + return $this->execQuery($qry); + } + + public function getStandorteByFirma($firma_id) + { + $this->addSelect("DISTINCT ON (standort_id) bezeichnung, standort_id"); + + return $this->loadWhere(array("firma_id" => $firma_id)); + } } + diff --git a/application/models/organisation/Studienplan_model.php b/application/models/organisation/Studienplan_model.php index 8422f4607..e35ba52fb 100755 --- a/application/models/organisation/Studienplan_model.php +++ b/application/models/organisation/Studienplan_model.php @@ -106,4 +106,32 @@ class Studienplan_model extends DB_Model 'tbl_studienplan_lehrveranstaltung.semester' => $semester )); } + + public function getAllOesForLv($lehrveranstaltung_id) + { + $this->addDistinct('oe_kurzbz'); + + $this->addJoin('lehre.tbl_studienplan_lehrveranstaltung lv', 'studienplan_id'); + $this->addJoin('lehre.tbl_studienordnung', 'studienordnung_id'); + $this->addJoin('public.tbl_studiengang', 'studiengang_kz'); + + return $this->loadWhere([ + 'lv.lehrveranstaltung_id' => $lehrveranstaltung_id + ]); + } + + public function getStudienplaeneByPrestudents($prestudent_id) + { + $this->addDistinct(); + $this->addSelect($this->dbTable . '.*'); + $this->addSelect('sem.start AS start_stsem'); + $this->addJoin('lehre.tbl_studienordnung o', 'studienordnung_id'); + $this->addJoin('public.tbl_prestudent p', 'studiengang_kz'); + $this->addJoin('public.tbl_studiensemester sem', 'sem.studiensemester_kurzbz = o.gueltigvon', 'LEFT'); + $this->addOrder('sem.start'); + + return $this->loadWhere([ + 'prestudent_id' => $prestudent_id + ]); + } } diff --git a/application/models/organisation/Studiensemester_model.php b/application/models/organisation/Studiensemester_model.php index af6f92268..0f8c3c620 100755 --- a/application/models/organisation/Studiensemester_model.php +++ b/application/models/organisation/Studiensemester_model.php @@ -13,35 +13,35 @@ class Studiensemester_model extends DB_Model $this->hasSequence = false; } - /** - * Get actual Studiensemester. - * - * @return array - */ - public function getAkt() - { - return $this->loadWhere(array( - 'start <= ' => 'NOW()', - 'ende >= ' => 'NOW()' - ) - ); - } + /** + * Get actual Studiensemester. + * + * @return array + */ + public function getAkt() + { + return $this->loadWhere(array( + 'start <= ' => 'NOW()', + 'ende >= ' => 'NOW()' + ) + ); + } // Get next study semester public function getNext() - { - $query = ' - SELECT * - FROM - public.tbl_studiensemester - WHERE - start > now() - ORDER BY start - LIMIT 1; - '; + { + $query = ' + SELECT * + FROM + public.tbl_studiensemester + WHERE + start > now() + ORDER BY start + LIMIT 1; + '; - return $this->execQuery($query); - } + return $this->execQuery($query); + } /** * getLastOrAktSemester @@ -182,10 +182,10 @@ class Studiensemester_model extends DB_Model return success(array()); $query = " - SELECT * - FROM public.tbl_studiensemester - WHERE ( ?::date < ende AND ?::date > start ) - ORDER BY start DESC"; + SELECT * + FROM public.tbl_studiensemester + WHERE ( ?::date < ende AND ?::date > start ) + ORDER BY start DESC"; return $this->execQuery($query, array($from, $to)); } @@ -200,7 +200,7 @@ class Studiensemester_model extends DB_Model { $query = "SELECT studiensemester_kurzbz, start, ende FROM public.vw_studiensemester WHERE studiensemester_kurzbz <> ? - ORDER BY delta, start LIMIT 1"; + ORDER BY delta, start LIMIT 1"; return $this->execQuery($query, array($studiensemester_kurzbz)); } @@ -230,7 +230,46 @@ class Studiensemester_model extends DB_Model FROM public.tbl_studiensemester WHERE start >= NOW() OR (start <= NOW() AND ende >= NOW()) ORDER BY start'; - + return $this->execQuery($query); } + + /** + * Liefert ausgehend von heutigen Datum $plus studiensemester in die Zukunft und $minus Studiensemester in die Vergangenheit + * + * @param integer $plus Optional. Wieviele Studiensemester in die Zukunft sollen ausgegeben werden. Wenn NULL werden alle zukuenftigen geliefert. + * @param integer $minus Optional. Wieviele Studiensemester in die Vergangenheit sollen ausgegeben werden. Wenn NULL werden alle vergangenen geliefert. + * + * @return stdClass + */ + public function addPlusMinus($plus = null, $minus = null) + { + $this->addSelect($this->pk); + $this->addOrder('ende'); + if ($plus) + $this->addLimit($plus); + $this->db->where('start >= NOW()', null, false); + $plus = $this->db->get_compiled_select($this->dbTable); + + $this->addSelect($this->pk); + $this->addOrder('start', 'DESC'); + if ($minus) + $this->addLimit($minus); + $this->db->where('start <= NOW()', null, false); + $minus = $this->db->get_compiled_select($this->dbTable); + + $this->db->where_in($this->pk, '(' . $plus . ') UNION (' . $minus . ')', false); + } + + /** + * Holt letzen zwei Ziffern des Studienjahres von Studiensemester, z.B. 24 für WS2024 und SS2025 + * @param studiensemester_kurzbz + * @return string Studienjahr Nummer + */ + public function getStudienjahrNumberFromStudiensemester($studiensemester_kurzbz) + { + $studienjahrNumber = mb_substr($studiensemester_kurzbz, 4, 2); + if (is_numeric($studienjahrNumber) && mb_substr($studiensemester_kurzbz, 0, 2) == 'SS') (int)$studienjahrNumber -= 1; + return $studienjahrNumber; + } } diff --git a/application/models/person/Adresse_model.php b/application/models/person/Adresse_model.php index fb5112a8d..4dd03ea6b 100755 --- a/application/models/person/Adresse_model.php +++ b/application/models/person/Adresse_model.php @@ -24,4 +24,4 @@ class Adresse_model extends DB_Model $this->addSelect($select); return $this->loadWhere(array('person_id' => $person_id, 'zustelladresse'=> true)); } -} +} \ No newline at end of file diff --git a/application/models/person/Benutzer_model.php b/application/models/person/Benutzer_model.php index eff1329a6..65121dbb5 100755 --- a/application/models/person/Benutzer_model.php +++ b/application/models/person/Benutzer_model.php @@ -1,4 +1,7 @@ addLimit(1); $this->addSelect('vorname, nachname'); $this->addJoin('public.tbl_person', 'person_id'); $nameresult = $this->loadWhere(array('uid' => $uid)); - if (hasData($nameresult)) - { - $aliasdata = getData($nameresult); - $alias = $this->_sanitizeAliasName($aliasdata[0]->vorname).'.'.$this->_sanitizeAliasName($aliasdata[0]->nachname); - $aliasexists = $this->aliasExists($alias); + if (isError($nameresult)) + return $nameresult; - if (hasData($aliasexists) && !getData($aliasexists)[0]) - $aliasres = $alias; - } - return success($aliasres); + if (!hasData($nameresult)) + return success(''); + + $aliasdata = current(getData($nameresult)); + + return $this->generateAliasFromName($aliasdata->vorname, $aliasdata->nachname); + } + + /** + * Generates alias for a vor- and nachname. + * + * @param string $vorname + * @param string $nachname + * + * @return stdClass + */ + public function generateAliasFromName($vorname, $nachname) + { + $alias = $this->_sanitizeAliasName($vorname . '.' . $nachname); + + $result = $this->aliasExists($alias); + + if (isError($result)) + return $result; + + if (current(getData($result))) + return success(''); + + return success($alias); + } + + /** + * Generates a matrikelnummer + * + * @param string $oe_kurzbz + * + * @return stdClass + */ + public function generateMatrikelnummer($oe_kurzbz) + { + $matrikelnummer = false; + + Events::trigger( + 'generate_matrikelnummer', + function ($value) use ($matrikelnummer) { + $matrikelnummer = $value; + }, + $oe_kurzbz + ); + + if ($matrikelnummer !== false) + return success($matrikelnummer); + + return success(null); + } + + /** + * Generates an activation key + * + * @return string + */ + public function generateActivationkey() + { + $this->load->library('CryptLib'); + + $key = ''; + for ($i=0; $i<32; $i++) + $key .= ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'][mt_rand(0, 15)]; + + $value = uniqid(mt_rand(), true); + $length = strlen($value); + $value = str_pad($value, $length + 32 - ($length % 32), chr(0)); + + return md5($this->cryptlib->RIJNDAEL_256_ECB($value, $key, true)); } // -------------------------------------------------------------------------------------------- @@ -100,9 +169,10 @@ class Benutzer_model extends DB_Model * @param string $str * @return string */ + private function _sanitizeAliasName($str) { $str = sanitizeProblemChars($str); - return mb_strtolower(str_replace(' ','_', $str)); + return mb_strtolower(str_replace(' ', '_', $str)); } } diff --git a/application/models/person/Notiz_model.php b/application/models/person/Notiz_model.php index bfd8aa258..349eaac60 100755 --- a/application/models/person/Notiz_model.php +++ b/application/models/person/Notiz_model.php @@ -139,12 +139,51 @@ class Notiz_model extends DB_Model */ public function getNotiz($person_id) { - // Join with the table public.tbl_notizzuordnung using notiz_id + $this->addSelect('public.tbl_notiz.*'); $this->addJoin('public.tbl_notizzuordnung', 'notiz_id'); return $this->loadWhere(array('person_id' => $person_id)); } + /** + * gets all Notizen with Documententries for a certain type and type_id + * @param String type of id eg. person_id, prestudent_id, mitarbeiter_uid, projekt_kurzbz, projektphase_id, projekttask_id, + * bestellung_id, lehreinheit_id, anrechnung_id, uid) + * @param $id the corresponding id, part of public.tbl_notizzuordnung + */ + public function getNotizWithDocEntries($id, $type) + { + $qry = " + SELECT + n.*, count(dms_id) as countDoc, z.notizzuordnung_id, + TO_CHAR (CASE + WHEN n.updateamum >= n.insertamum THEN n.updateamum + ELSE n.insertamum + END::timestamp, 'DD.MM.YYYY HH24:MI:SS') AS lastUpdate, + regexp_replace(n.text, '<[^>]*>', '', 'g') as text_stripped, + TO_CHAR(n.start::timestamp, 'DD.MM.YYYY') AS start_format, + TO_CHAR(n.ende::timestamp, 'DD.MM.YYYY') AS ende_format, + z.notiz_id, z.person_id as id, ? as type_id + + FROM + public.tbl_notiz n + JOIN + public.tbl_notizzuordnung z USING (notiz_id) + LEFT JOIN + public.tbl_notiz_dokument dok USING (notiz_id) + LEFT JOIN + campus.tbl_dms_version USING (dms_id) + WHERE + z.$type = ? + GROUP BY + notiz_id, z.notizzuordnung_id + "; + + return $this->execQuery($qry, array($type, $id)); + + } + + /** * gets all Notizen for a person with a specific title * @param $person_id @@ -231,6 +270,4 @@ class Notiz_model extends DB_Model return $this->loadWhere(array('anrechnung_id' => $anrechnung_id)); } - // ------------------------------------------------------------------------------------------------------ - } diff --git a/application/models/person/Notizdokument_model.php b/application/models/person/Notizdokument_model.php new file mode 100644 index 000000000..6b141307f --- /dev/null +++ b/application/models/person/Notizdokument_model.php @@ -0,0 +1,14 @@ +dbTable = 'public.tbl_notiz_dokument'; + $this->pk= array('notiz_id' , 'dms_id'); + } +} \ No newline at end of file diff --git a/application/models/person/Notizzuordnung_model.php b/application/models/person/Notizzuordnung_model.php index 187a8399b..b94ff3fb6 100755 --- a/application/models/person/Notizzuordnung_model.php +++ b/application/models/person/Notizzuordnung_model.php @@ -11,4 +11,38 @@ class Notizzuordnung_model extends DB_Model $this->dbTable = 'public.tbl_notizzuordnung'; $this->pk = 'notizzuordnung_id'; } + + public function isValidType($type) + { + $validTypes = []; + + $qry = " + SELECT column_name + FROM information_schema.columns + WHERE table_schema = 'public' + AND table_name = 'tbl_notizzuordnung' + AND column_name not in ('notizzuordnung_id', 'notiz_id') + "; + + $type_arr = $this->execQuery($qry); + $type_arr = $type_arr->retval; + + foreach ($type_arr as $t) + { + $validTypes[] = $t->column_name; + } + + //TODO(manu) param id + if (in_array($type, $validTypes) ) + //if (in_array($type, $validTypes) ||($type == 'software_id')) //Just for testing + { + return success("Type " . $type . " is valid"); + // $result = success('Type of Id is valid'); + } + else + { + return error("Type " . $type . " is NOT valid"); + } + //return $result; + } } diff --git a/application/models/ressource/Betriebsmittel_model.php b/application/models/ressource/Betriebsmittel_model.php index 849a9199f..290c3491d 100755 --- a/application/models/ressource/Betriebsmittel_model.php +++ b/application/models/ressource/Betriebsmittel_model.php @@ -11,4 +11,24 @@ class Betriebsmittel_model extends DB_Model $this->dbTable = 'wawi.tbl_betriebsmittel'; $this->pk = 'betriebsmittel_id'; } + + /** + * load Liste Inventarnummern + */ + public function loadInventarliste($filter) + { + $filter = urldecode(strtoLower($filter)); + + $qry = " + SELECT + bm.inventarnummer, bm.betriebsmitteltyp, bm.betriebsmittel_id, CONCAT(bm.inventarnummer, ' ', bm.beschreibung) as dropdowntext + FROM + wawi.tbl_betriebsmittel bm + WHERE + upper(bm.inventarnummer) LIKE '%" .$this->db->escape_like_str($filter)."%' + OR + lower(bm.inventarnummer) LIKE '%" .$this->db->escape_like_str($filter)."%'"; + + return $this->execQuery($qry); + } } diff --git a/application/models/ressource/Betriebsmittelperson_model.php b/application/models/ressource/Betriebsmittelperson_model.php index 04878a9ad..39f08b5cd 100755 --- a/application/models/ressource/Betriebsmittelperson_model.php +++ b/application/models/ressource/Betriebsmittelperson_model.php @@ -96,4 +96,49 @@ class Betriebsmittelperson_model extends DB_Model return $this->loadWhere($condition); } + + public function getBetriebsmittelData($id, $type_id) + { + switch ($type_id) { + case 'person_id': + $cond = 'bmp.person_id'; + break; + case 'uid': + $cond = 'bmp.uid'; + break; + case 'betriebsmittelperson_id': + $cond = 'bmp.betriebsmittelperson_id'; + break; + default: + return error("ID nicht gültig"); + } + + $query = " + SELECT + bm.nummer, bmp.person_id, bm.betriebsmitteltyp, bmp.anmerkung as anmerkung, bmp.retouram, TO_CHAR(bmp.retouram::timestamp, 'DD.MM.YYYY') AS format_retour, bmp.ausgegebenam, TO_CHAR(bmp.ausgegebenam::timestamp, 'DD.MM.YYYY') AS format_ausgabe, bm.beschreibung, bmp.uid, bmp.kaution, bm.betriebsmittel_id, bmp.betriebsmittelperson_id, bm.inventarnummer, bm.nummer2 + FROM + wawi.tbl_betriebsmittelperson bmp + JOIN + wawi.tbl_betriebsmittel bm ON (bmp.betriebsmittel_id = bm.betriebsmittel_id) + WHERE + " . $cond . " = ? "; + + return $this->execQuery($query, array($id)); + } + + /** + * Perform a loadWhere on the vw_betriebsmittelperson DB View + * + * @param array $where + * + * @return stdClass + */ + public function loadViewWhere($where) + { + $table = $this->dbTable; + $this->dbTable = 'public.vw_betriebsmittelperson'; + $result = $this->loadWhere($where); + $this->dbTable = $table; + return $result; + } } diff --git a/application/models/ressource/Firma_model.php b/application/models/ressource/Firma_model.php index 1b8dfb51d..431f0815f 100755 --- a/application/models/ressource/Firma_model.php +++ b/application/models/ressource/Firma_model.php @@ -11,4 +11,18 @@ class Firma_model extends DB_Model $this->dbTable = 'public.tbl_firma'; $this->pk = 'firma_id'; } + + public function searchFirmen($filter) + { + $filter = strtoLower($filter); + $qry = " + SELECT + f.name, f.firma_id + FROM + public.tbl_firma f + WHERE + lower (f.name) LIKE '%". $this->db->escape_like_str($filter)."%'"; + + return $this->execQuery($qry); + } } diff --git a/application/models/ressource/Mitarbeiter_model.php b/application/models/ressource/Mitarbeiter_model.php index 900b88684..c38fcf054 100755 --- a/application/models/ressource/Mitarbeiter_model.php +++ b/application/models/ressource/Mitarbeiter_model.php @@ -216,4 +216,26 @@ class Mitarbeiter_model extends DB_Model return success($kurzbz); } + + public function searchMitarbeiter($filter) + { + $filter = strtoLower($filter); + $qry = " + SELECT + ma.mitarbeiter_uid, CONCAT(p.nachname, ' ', p.vorname, ' (', ma.mitarbeiter_uid , ')') as mitarbeiter + FROM + public.tbl_mitarbeiter ma + JOIN + public.tbl_benutzer b on (ma.mitarbeiter_uid = b.uid) + JOIN + public.tbl_person p on (p.person_id = b.person_id) + WHERE + lower (p.nachname) LIKE '%". $this->db->escape_like_str($filter)."%' + OR + lower (p.vorname) LIKE '%". $this->db->escape_like_str($filter)."%' + OR + (ma.mitarbeiter_uid) LIKE '%". $this->db->escape_like_str($filter)."%'"; + + return $this->execQuery($qry); + } } diff --git a/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php b/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php index 2fdfcffe2..6827beaa4 100644 --- a/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php +++ b/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php @@ -31,9 +31,13 @@ class Dienstverhaeltnis_model extends DB_Model org.bezeichnung oe_bezeichnung, dv.von, dv.bis, + dv.dvendegrund_kurzbz, + dv.dvendegrund_anmerkung, dv.vertragsart_kurzbz, dv.updateamum, - dv.updatevon + dv.updatevon, + dv.dvendegrund_kurzbz, + dv.dvendegrund_anmerkung FROM tbl_mitarbeiter JOIN tbl_benutzer ON tbl_mitarbeiter.mitarbeiter_uid::text = tbl_benutzer.uid::text JOIN tbl_person USING (person_id) diff --git a/application/views/Studentenverwaltung.php b/application/views/Studentenverwaltung.php new file mode 100644 index 000000000..2d0d22346 --- /dev/null +++ b/application/views/Studentenverwaltung.php @@ -0,0 +1,55 @@ + 'Studentenverwaltung', + 'axios027' => true, + 'bootstrap5' => true, + 'fontawesome6' => true, + 'vue3' => true, + 'primevue3' => true, + #'filtercomponent' => true, + 'tabulator5' => true, + 'tinymce5' => true, + 'phrases' => array( + 'global', + 'ui', + 'notiz', + ), + 'customCSSs' => [ + 'public/css/components/vue-datepicker.css', + 'public/css/components/primevue.css', + 'public/css/Studentenverwaltung.css' + ], + 'customJSs' => [ + #'vendor/npm-asset/primevue/tree/tree.min.js', + #'vendor/npm-asset/primevue/toast/toast.min.js' + ], + 'customJSModules' => [ + 'public/js/apps/Studentenverwaltung.js' + ] + ); + + $this->load->view('templates/FHC-Header', $includesArray); +?> + + !defined('GENERATE_ALIAS_STUDENT') ? true : GENERATE_ALIAS_STUDENT, + 'showZgvDoktor' => !defined('ZGV_DOKTOR_ANZEIGEN') ? false : ZGV_DOKTOR_ANZEIGEN, + 'showZgvErfuellt' => !defined('ZGV_ERFUELLT_ANZEIGEN') ? false : ZGV_ERFUELLT_ANZEIGEN +]; +?> + +
+ + +
+ +load->view('templates/FHC-Footer', $includesArray); ?> + diff --git a/application/views/lehre/Antrag/Student/List.php b/application/views/lehre/Antrag/Student/List.php index e2a4511c5..2be4f63d7 100755 --- a/application/views/lehre/Antrag/Student/List.php +++ b/application/views/lehre/Antrag/Student/List.php @@ -150,8 +150,6 @@ $this->load->view( break; case Studierendenantrag_model::TYP_ABMELDUNG_STGL: $allowed = [ - Studierendenantragstatus_model::STATUS_APPROVED, - Studierendenantragstatus_model::STATUS_OBJECTED, Studierendenantragstatus_model::STATUS_OBJECTION_DENIED, Studierendenantragstatus_model::STATUS_DEREGISTERED ]; diff --git a/application/views/lehre/anrechnung/approveAnrechnungDetail.php b/application/views/lehre/anrechnung/approveAnrechnungDetail.php index 0970b6edd..c96631781 100755 --- a/application/views/lehre/anrechnung/approveAnrechnungDetail.php +++ b/application/views/lehre/anrechnung/approveAnrechnungDetail.php @@ -1,4 +1,5 @@ load->config('anrechnung'); $this->load->view( 'templates/FHC-Header', array( @@ -172,14 +173,16 @@ $this->load->view( p->t('global', 'begruendung'); ?> begruendung ?> - - p->t('anrechnung', 'begruendungEctsLabel'); ?> - begruendung_ects ?> - - - p->t('anrechnung', 'begruendungLvinhaltLabel'); ?> - begruendung_lvinhalt ?> - + config->item('explain_equivalence')): ?> + + p->t('anrechnung', 'begruendungEctsLabel'); ?> + begruendung_ects ?> + + + p->t('anrechnung', 'begruendungLvinhaltLabel'); ?> + begruendung_lvinhalt ?> + + diff --git a/application/views/lehre/anrechnung/requestAnrechnung.php b/application/views/lehre/anrechnung/requestAnrechnung.php index 18fd66a67..bb3c48235 100755 --- a/application/views/lehre/anrechnung/requestAnrechnung.php +++ b/application/views/lehre/anrechnung/requestAnrechnung.php @@ -4,6 +4,7 @@ const CHAR_LENGTH150 = 150; const CHAR_LENGTH500 = 500; const CHAR_LENGTH1000 = 1000; +$this->load->config('anrechnung'); $this->load->view( 'templates/FHC-Header', array( @@ -200,27 +201,29 @@ $this->load->view( - -
-
-
-
- p->t('anrechnung', 'begruendungEcts'); ?>  - - - -
-
- - p->t('ui', 'maxZeichen'); ?> : + + config->item('explain_equivalence')): ?> + +
+
+
+
+ p->t('anrechnung', 'begruendungEcts'); ?>  + + + +
+
+ + p->t('ui', 'maxZeichen'); ?> : +
-
- -
+ +
@@ -240,6 +243,8 @@ $this->load->view(
+ +
diff --git a/application/views/lehre/anrechnung/reviewAnrechnungDetail.php b/application/views/lehre/anrechnung/reviewAnrechnungDetail.php index 08d23d8c4..98fee67a3 100755 --- a/application/views/lehre/anrechnung/reviewAnrechnungDetail.php +++ b/application/views/lehre/anrechnung/reviewAnrechnungDetail.php @@ -1,4 +1,5 @@ load->config('anrechnung'); $this->load->view( 'templates/FHC-Header', array( @@ -143,14 +144,16 @@ $this->load->view( target="_blank">dokumentname) ?> - - p->t('anrechnung', 'begruendungEctsLabel'); ?> - begruendung_ects ?> - - - p->t('anrechnung', 'begruendungLvinhaltLabel'); ?> - begruendung_lvinhalt ?> - + config->item('explain_equivalence')): ?> + + p->t('anrechnung', 'begruendungEctsLabel'); ?> + begruendung_ects ?> + + + p->t('anrechnung', 'begruendungLvinhaltLabel'); ?> + begruendung_lvinhalt ?> + + diff --git a/application/views/templates/FHC-Footer.php b/application/views/templates/FHC-Footer.php index 3daac26cd..31e610289 100755 --- a/application/views/templates/FHC-Footer.php +++ b/application/views/templates/FHC-Footer.php @@ -127,6 +127,11 @@ generateJSsInclude('vendor/npm-asset/primevue/autocomplete/autocomplete.min.js'); generateJSsInclude('vendor/npm-asset/primevue/overlaypanel/overlaypanel.min.js'); generateJSsInclude('vendor/npm-asset/primevue/datatable/datatable.min.js'); + // TODO check ob notwendig + generateJSsInclude('vendor/npm-asset/primevue/toast/toast.min.js'); + generateJSsInclude('vendor/npm-asset/primevue/toastservice/toastservice.min.js'); + generateJSsInclude('vendor/npm-asset/primevue/confirmdialog/confirmdialog.min.js'); + generateJSsInclude('vendor/npm-asset/primevue/confirmationservice/confirmationservice.min.js'); } // -------------------------------------------------------------------------------------------------------- diff --git a/application/views/templates/FHC-Header.php b/application/views/templates/FHC-Header.php index 39ddd7e7e..3ad161ef2 100755 --- a/application/views/templates/FHC-Header.php +++ b/application/views/templates/FHC-Header.php @@ -41,6 +41,7 @@ { generateCSSsInclude('vendor/fortawesome/font-awesome6/css/fontawesome.min.css'); generateCSSsInclude('vendor/fortawesome/font-awesome6/css/solid.min.css'); + generateCSSsInclude('vendor/fortawesome/font-awesome6/css/regular.min.css'); // NOTE(chris): for favorites in stv generateCSSsInclude('vendor/fortawesome/font-awesome6/css/brands.min.css'); } diff --git a/cis/private/lvplan/stpl_week.php b/cis/private/lvplan/stpl_week.php index e58ce03ed..f600c6db5 100755 --- a/cis/private/lvplan/stpl_week.php +++ b/cis/private/lvplan/stpl_week.php @@ -270,7 +270,7 @@ if (isset($_POST['titel'])) foreach($addon_obj->result as $addon) { if(file_exists('../../../addons/'.$addon->kurzbz.'/cis/init.js.php')) - echo ''; + echo ''; } // Wenn Seite fertig geladen ist Addons aufrufen diff --git a/cis/private/tools/zeitaufzeichnung.php b/cis/private/tools/zeitaufzeichnung.php index 46fd2c4c3..7b1fb1fbb 100755 --- a/cis/private/tools/zeitaufzeichnung.php +++ b/cis/private/tools/zeitaufzeichnung.php @@ -1222,7 +1222,6 @@ if ($projekt->getProjekteMitarbeiter($user, true)) +
+
+ +
+ + + +
+ +
+
+ +
+
+
+ + +
+
+ +
+ + +
+
+
+ + +
+
+ + +
+ +
+
+ +
+ + +
+ +
+
+ +
+ + +
+ +
+ +
+ +
+ + + +
+ + +
+
+ +
+ +
+ +
+
+
+ +
+ +
+

{{notizData.lastupdate}}

+
+
+ + + + +
+ +
+ + + + + + + + +
+
+
+ + +
+ +
+ + +
+
+

{{$p.t('notiz','notiz_new')}} [{{notizData.typeId}}]

+

{{$p.t('notiz','notiz_edit')}} [{{notizData.typeId}}]

+
+ +
+ + +
+ +
+ + +
+ +
+ +
+ + +
+ +
+ + +
+
+ + +
+
+
+ + + +
+
+
+ + +
+
+ + + + + +
+ +
+ + + + + + + + + + + +
+ +
+
+ + +
+ +
+
+ +
+ +
+

{{notizData.lastupdate}}

+
+
+
+
+
+
+ +
+ + + + + + + +
+
+
+
+

{{$p.t('notiz','notiz_new')}} [{{notizData.typeId}}]

+

{{$p.t('notiz','notiz_edit')}} [{{notizData.typeId}}]

+
+ +
+ + +
+ +
+ +
+ + +
+ +
+ + +
+
+ + +
+
+
+ + + +
+
+
+ + +
+
+ + + + + +
+ + +
+ + + + + + + + + + + +
+ +
+
+ + +
+ +
+
+ +
+ +
+

{{notizData.lastupdate}}

+
+
+ +
+ + +
+
+
+ +
+
+ + +
+
+
+ +
+ + + + + + + + + + + + +
+ + +
+
+ +
+

Falsches Layout übergeben: {{notizLayout}}

+

Kein Layout übergeben

+
+
`, +} \ No newline at end of file diff --git a/public/js/components/Studierendenantrag/Leitung/Table.js b/public/js/components/Studierendenantrag/Leitung/Table.js index 45c8f373a..778f91c00 100755 --- a/public/js/components/Studierendenantrag/Leitung/Table.js +++ b/public/js/components/Studierendenantrag/Leitung/Table.js @@ -265,7 +265,7 @@ export default { allowed_status_for_download = ['Genehmigt']; break; case 'AbmeldungStgl': - allowed_status_for_download = ['Genehmigt', 'Beeinsprucht', 'EinspruchAbgelehnt', 'Abgemeldet']; + allowed_status_for_download = ['EinspruchAbgelehnt', 'Abgemeldet']; break; case 'Unterbrechung': allowed_status_for_download = ['Genehmigt', 'EmailVersandt']; diff --git a/public/js/components/Stv/Studentenverwaltung.js b/public/js/components/Stv/Studentenverwaltung.js new file mode 100644 index 000000000..e2ca8e349 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung.js @@ -0,0 +1,211 @@ +/** + * Copyright (C) 2022 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 . + */ + +import CoreSearchbar from "../searchbar/searchbar.js"; +import VerticalSplit from "../verticalsplit/verticalsplit.js"; +import StvVerband from "./Studentenverwaltung/Verband.js"; +import StvList from "./Studentenverwaltung/List.js"; +import StvDetails from "./Studentenverwaltung/Details.js"; +import StvStudiensemester from "./Studentenverwaltung/Studiensemester.js"; + + +export default { + components: { + CoreSearchbar, + VerticalSplit, + StvVerband, + StvList, + StvDetails, + StvStudiensemester + }, + props: { + defaultSemester: String, + config: Object, + permissions: Object, + stvRoot: String, + cisRoot: String, + activeAddons: String // semicolon separated list of active addons + }, + provide() { + return { + cisRoot: this.cisRoot, + activeAddonBewerbung: this.activeAddons.split(';').includes('bewerbung'), + configGenerateAlias: this.config.generateAlias, + configShowZgvDoktor: this.config.showZgvDoktor, + configShowZgvErfuellt: this.config.showZgvErfuellt, + hasBpkPermission: this.permissions['student/bpk'], + hasAliasPermission: this.permissions['student/alias'], + hasPrestudentPermission: this.permissions['basis/prestudent'], + hasPrestudentstatusPermission: this.permissions['basis/prestudentstatus'], + hasAssistenzPermissionForStgs: this.permissions['assistenz_stgs'], + hasSchreibrechtAss: this.permissions['assistenz_schreibrechte'], + hasAdminPermission: this.permissions['admin'], + hasPermissionToSkipStatusCheck: this.permissions['student/keine_studstatuspruefung'], + hasPermissionRtAufsicht: this.permissions['lehre/reihungstestAufsicht'], + lists: this.lists, + defaultSemester: this.defaultSemester, + $reloadList: () => { + this.$refs.stvList.reload(); + } + } + }, + data() { + return { + selected: [], + searchbaroptions: { + types: [ + "student", + "prestudent" + ], + actions: { + student: { + defaultaction: { + type: "link", + action: function(data) { + return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/studentenverwaltung/student/' + data.uid; + } + }, + childactions: [ + ] + }, + prestudent: { + defaultaction: { + type: "link", + action: function(data) { + return FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/studentenverwaltung/prestudent/' + data.prestudent_id; + } + }, + childactions: [ + ] + } + } + }, + studiengangKz: undefined, + studiensemesterKurzbz: this.defaultSemester, + lists: { + nations: [], + sprachen: [], + geschlechter: [] + } + } + }, + methods: { + onSelectVerband({link, studiengang_kz}) { + this.studiengangKz = studiengang_kz; + this.$refs.stvList.updateUrl(this.$fhcApi.factory.stv.students.verband(link)); + }, + studiensemesterChanged(v) { + this.studiensemesterKurzbz = v; + this.$refs.stvList.updateUrl(); + this.$refs.details.reload(); + }, + reloadList() { + this.$refs.stvList.reload(); + } + }, + created() { + this.$fhcApi + .get('api/frontend/v1/stv/address/getNations') + .then(result => { + this.lists.nations = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/lists/getSprachen') + .then(result => { + this.lists.sprachen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/lists/getGeschlechter') + .then(result => { + this.lists.geschlechter = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/lists/getAusbildungen') + .then(result => { + this.lists.ausbildungen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/lists/getStgs') + .then(result => { + this.lists.stgs = result.data; + this.lists.active_stgs = this.lists.stgs.filter(stg => stg.aktiv); + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/lists/getOrgforms') + .then(result => { + this.lists.orgforms = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .factory.stv.konto.getBuchungstypen() + .then(result => { + this.lists.buchungstypen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/lists/getStudiensemester') + .then(result => { + this.lists.studiensemester = result.data; + this.lists.studiensemester_desc = result.data.toReversed(); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + mounted() { + if (this.$route.params.id) { + this.$refs.stvList.updateUrl(this.$fhcApi.factory.stv.students.uid(this.$route.params.id), true); + } else if (this.$route.params.prestudent_id) { + this.$refs.stvList.updateUrl(this.$fhcApi.factory.stv.students.prestudent(this.$route.params.prestudent_id), true); + } else if (this.$route.params.person_id) { + this.$refs.stvList.updateUrl(this.$fhcApi.factory.stv.students.person(this.$route.params.person_id), true); + } + + }, + template: ` +
+ +
+
+ +
+ + + + +
+
+
+
` +}; diff --git a/public/js/components/Stv/Studentenverwaltung/Details.js b/public/js/components/Stv/Studentenverwaltung/Details.js new file mode 100644 index 000000000..4df148063 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details.js @@ -0,0 +1,60 @@ +import FhcTabs from "../../Tabs.js"; + +// TODO(chris): alt & title +// TODO(chris): phrasen + +export default { + components: { + FhcTabs + }, + data() { + return { + configStudent: null, + configStudents: null + }; + }, + props: { + students: Array + }, + computed: { + appRoot() { + return FHC_JS_DATA_STORAGE_OBJECT.app_root; + } + }, + methods: { + reload() { + if (this.$refs.tabs?.$refs?.current?.reload) + this.$refs.tabs.$refs.current.reload(); + } + }, + created() { + this.$fhcApi + .factory.stv.configStudent() + .then(result => { + this.configStudent = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .factory.stv.configStudents() + .then(result => { + this.configStudents = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` +
+
+ Bitte StudentIn auswählen! +
+
+
+ profilbild +
+

{{students[0].titlepre}} {{students[0].vorname}} {{students[0].nachname}} {{students[0].titlepost}}

+
+
+ + +
+
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Betriebsmittel.js b/public/js/components/Stv/Studentenverwaltung/Details/Betriebsmittel.js new file mode 100644 index 000000000..9d2970a54 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Betriebsmittel.js @@ -0,0 +1,23 @@ +import CoreBetriebsmittel from "../../../Betriebsmittel/Betriebsmittel.js"; + +export default { + components: { + CoreBetriebsmittel + }, + props: { + modelValue: Object + }, + template: ` +
+ + +
+ ` +}; + diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Details.js new file mode 100644 index 000000000..ae4f92b20 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Details.js @@ -0,0 +1,462 @@ +import CoreForm from '../../../Form/Form.js'; +import FormInput from '../../../Form/Input.js'; +import FormUploadImage from '../../../Form/Upload/Image.js'; + +import CoreUdf from '../../../Udf/Udf.js'; + + +export default { + components: { + CoreForm, + FormInput, + FormUploadImage, + CoreUdf + }, + inject: { + showBpk: { + from: 'hasBpkPermission', + default: false + }, + showZugangscode: { + from: 'activeAddonBewerbung', + default: false + }, + cisRoot: { + from: 'cisRoot' + }, + generateAlias: { + from: 'configGenerateAlias', + default: false + }, + hasAliasPermission: { + from: 'hasAliasPermission', + default: false + }, + lists: { + from: 'lists' + } + }, + props: { + modelValue: Object + }, + data() { + return { + test: {udf_viaf: 'TEST'}, + familienstaende: { + "": "--keine Auswahl--", + "g": "geschieden", + "l": "ledig", + "v": "verheiratet", + "w": "verwitwet" + }, + original: null, + data: null, + changed: {}, + udfChanges: false, + studentIn: null, + gebDatumIsValid: false, + gebDatumIsInvalid: false + } + }, + computed: { + aliasNotAllowed() { + return this.generateAlias === false && !this.hasAliasPermission; + }, + changedLength() { + return Object.keys(this.changed).length; + }, + noImageSrc() { + return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'skin/images/profilbild_dummy.jpg'; + } + }, + watch: { + modelValue(n) { + this.updateStudent(n); + }, + data: { + // TODO(chris): use @input instead? + handler(n) { + let res = {}; + for (var k in this.original) { + if (k == 'gebdatum') { + if (new Date(this.original[k]).toString() != new Date(n[k]).toString()) + res[k] = n[k]; + } else { + // TODO(chris): null && ""? should there be an exception for this? + if (this.original[k] !== n[k] && !(this.original[k] === null && n[k] === "")) + res[k] = n[k]; + } + } + this.changed = res; + }, + deep: true + } + }, + methods: { + updateStudent(n) { + // TODO(chris): move to fhcapi.factory + this.$fhcApi + .get('api/frontend/v1/stv/student/get/' + n.prestudent_id) + .then(result => { + this.data = result.data; + if (!this.data.familienstand) + this.data.familienstand = ''; + this.original = {...(this.original || {}), ...this.data}; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + save() { + if (!this.changedLength) + return; + + this.$refs.form.clearValidation(); + this.$refs.form + .post('api/frontend/v1/stv/student/save/' + this.modelValue.prestudent_id, this.changed) + .then(result => { + this.original = {...this.data}; + this.changed = {}; + this.$refs.form.setFeedback(true, result.data); + }) + .catch(this.$fhcAlert.handleSystemError) + }, + udfsLoaded(udfs) { + this.original = {...(this.original || {}), ...udfs}; + }, + reload(){ + this.updateStudent(this.modelValue); + } + }, + created() { + this.updateStudent(this.modelValue); + }, + //TODO(chris): Phrasen + //TODO(chris): Geburtszeit? Anzahl der Kinder? + template: ` + +
+ +
+
+ Person + +
+ Loading... +
+ +
+
+ StudentIn + +
+ Loading... +
+
+
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Kontakt.js b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt.js new file mode 100644 index 000000000..a32de8df4 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt.js @@ -0,0 +1,39 @@ +import AddressList from "./Kontakt/Address.js"; +import ContactList from "./Kontakt/Contact.js"; +import BankaccountList from "./Kontakt/Bankaccount.js"; + +export default { + components: { + AddressList, + ContactList, + BankaccountList, + }, + props: { + modelValue: Object, + config: Object + }, + data() { + return { + adressen: [], + kontakte: [], + bankverbindungen: [] + } + }, + template: ` +
+
+ {{this.$p.t('person', 'adressen')}} + +
+
+
+ {{this.$p.t('global', 'kontakt')}} + +
+
+
+ {{this.$p.t('person', 'bankverbindungen')}} + +
+
` +}; diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Address.js b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Address.js new file mode 100644 index 000000000..c6bd07be4 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Address.js @@ -0,0 +1,583 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import PvAutoComplete from "../../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; +import FhcFormValidation from '../../../../Form/Validation.js'; +import BsModal from "../../../../Bootstrap/Modal.js"; +import FormForm from '../../../../Form/Form.js'; +import FormInput from '../../../../Form/Input.js'; + +export default{ + components: { + CoreFilterCmpt, + PvAutoComplete, + FhcFormValidation, + BsModal, + FormForm, + FormInput + }, + props: { + uid: Number + }, + data() { + return{ + tabulatorOptions: { + ajaxURL: 'api/frontend/v1/stv/kontakt/getAdressen/' + this.uid, + ajaxRequestFunc: this.$fhcApi.get, + ajaxResponse: (url, params, response) => response.data, + //autoColumns: true, + columns:[ + {title:"Typ", field:"bezeichnung"}, + {title:"Strasse", field:"strasse"}, + {title:"Plz", field:"plz"}, + {title:"Ort", field:"ort"}, + {title:"Gemeinde", field:"gemeinde"}, + {title:"Nation", field:"nation"}, + { + title:"Heimatadresse", + field:"heimatadresse", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + } + }, + { + title:"Zustelladresse", + field:"zustelladresse", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + } + }, + {title:"Abweich.Empf", field:"co_name"}, + {title:"Firma", field:"firmenname"}, + {title:"Firma_id", field:"firma_id", visible:false}, + {title:"Adresse_id", field:"adresse_id", visible:false}, + {title:"Person_id", field:"person_id", visible:false}, + {title:"Name", field:"name", visible:false}, + {title:"letzte Änderung", field:"updateamum", visible:false}, + {title:"Rechnungsadresse", field:"rechnungsadresse", visible:false, + formatter: (cell, formatterParams, onRendered) => { + let output = cell.getValue() ? "ja" : "nein"; + return output; + } + }, + {title:"Anmerkung", field:"anmerkung", 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"; + + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.addEventListener('click', (event) => + this.actionEditAdress(cell.getData().adresse_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.addEventListener('click', () => + this.actionDeleteAdress(cell.getData().adresse_id) + ); + container.append(button); + + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + height: 'auto', + selectable: true, + index: 'adresse_id', + persistenceID: 'stv-details-kontakt-address' + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async () => { + await this.$p.loadCategory(['notiz','global','person', 'ui']); + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('bezeichnung').component.updateDefinition({ + title: this.$p.t('global', 'typ') + }); + cm.getColumnByField('strasse').component.updateDefinition({ + title: this.$p.t('person', 'strasse') + }); + cm.getColumnByField('plz').component.updateDefinition({ + title: this.$p.t('person', 'plz') + }); + cm.getColumnByField('ort').component.updateDefinition({ + title: this.$p.t('person', 'ort') + }); + cm.getColumnByField('gemeinde').component.updateDefinition({ + title: this.$p.t('person', 'gemeinde') + }); + cm.getColumnByField('nation').component.updateDefinition({ + title: this.$p.t('person', 'nation') + }); + cm.getColumnByField('heimatadresse').component.updateDefinition({ + title: this.$p.t('person', 'heimatadresse') + }); + cm.getColumnByField('co_name').component.updateDefinition({ + title: this.$p.t('person', 'co_name') + }); + cm.getColumnByField('name').component.updateDefinition({ + title: this.$p.t('person', 'firma_zusatz') + }); + cm.getColumnByField('firmenname').component.updateDefinition({ + title: this.$p.t('person', 'firma') + }); + cm.getColumnByField('updateamum').component.updateDefinition({ + title: this.$p.t('notiz', 'letzte_aenderung') + }); + cm.getColumnByField('rechnungsadresse').component.updateDefinition({ + title: this.$p.t('person', 'rechnungsadresse') + }); + cm.getColumnByField('anmerkung').component.updateDefinition({ + title: this.$p.t('global', 'anmerkung') + }); + } + } + ], + addressData: { + zustelladresse: true, + heimatadresse: true, + rechnungsadresse: false, + typ: 'h', + nation: 'A' + }, + statusNew: true, + places: [], + suggestions: {}, + nations: [], + adressentypen: [], + firmen: [], + filteredFirmen: [], + abortController: { + suggestions: null, + places: null + } + } + }, + computed:{ + orte() { + return this.places.filter(ort => ort.name == this.addressData.gemeinde); + }, + gemeinden() { + return Object.values(this.places.reduce((res,place) => { + res[place.name] = place; + return res; + }, {})); + } + }, + watch: { + uid() { + this.$refs.table.tabulator.setData('api/frontend/v1/stv/Kontakt/getAdressen/' + this.uid); + }, + }, + methods:{ + actionNewAdress() { + this.resetModal(); + this.$refs.adressModal.show(); + }, + actionEditAdress(adress_id) { + this.statusNew = false; + this.loadAdress(adress_id).then(() => { + if(this.addressData.adresse_id) + { + this.loadPlaces(this.addressData.plz); + this.$refs.adressModal.show(); + + } + }); + }, + actionDeleteAdress(adress_id) { + this.loadAdress(adress_id).then(() => { + if(this.addressData.adresse_id) + if(this.addressData.heimatadresse) + this.$fhcAlert.alertError(this.$p.t('person', 'error_deleteHomeAdress')); + else { + this.$fhcAlert + .confirmDelete() + .then(result => result + ? adress_id + : Promise.reject({handled: true})) + .then(this.deleteAddress) + .catch(this.$fhcAlert.handleSystemError); + } + }); + }, + addNewAddress(addressData) { + this.$fhcApi.post('api/frontend/v1/stv/kontakt/addNewAddress/' + this.uid, + this.addressData + ).then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal('adressModal'); + this.resetModal(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + window.scrollTo(0, 0); + this.reload(); + }); + }, + reload() { + this.$refs.table.reloadTable(); + }, + loadAdress(adress_id) { + this.statusNew = false; + return this.$fhcApi.get('api/frontend/v1/stv/kontakt/loadAddress/' + adress_id) + .then(result => { + this.addressData = result.data; + return result; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + updateAddress(adress_id) { + this.$fhcApi.post('api/frontend/v1/stv/kontakt/updateAddress/' + adress_id, + this.addressData + ).then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal('adressModal'); + this.resetModal(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + window.scrollTo(0, 0); + this.reload(); + }); + }, + deleteAddress(adress_id) { + this.$fhcApi.post('api/frontend/v1/stv/kontakt/deleteAddress/' + adress_id) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }).catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + window.scrollTo(0, 0); + this.reload(); + }); + }, + loadPlaces() { + if (this.abortController.places) + this.abortController.places.abort(); + if (this.addressData.nation != 'A' || !this.addressData.plz) + return; + + this.abortController.places = new AbortController(); + this.$fhcApi + .get('api/frontend/v1/stv/address/getPlaces/' + this.addressData.plz, undefined, { + signal: this.abortController.places.signal + }) + .then(result => { + this.places = result.data; + }); +/* .catch(error => { + if (error.code != "ERR_CANCELED") + window.setTimeout(this.loadPlaces, 100); + else + this.$fhcAlert.handleSystemError(error); + });*/ + }, + search(event) { + return this.$fhcApi + .get('api/frontend/v1/stv/kontakt/getFirmen/' + event.query) + .then(result => { + this.filteredFirmen = result.data.retval; + }); + }, + hideModal(modalRef) { + this.$refs[modalRef].hide(); + }, + resetModal() { + this.addressData = {}; + + this.addressData.strasse = null; + this.addressData.zustelladresse = true; + this.addressData.heimatadresse = true; + this.addressData.rechnungsadresse = false; + this.addressData.co_name = null; + this.addressData.firma_id = null; + this.addressData.name = null; + this.addressData.anmerkung = null; + this.addressData.typ = 'h'; + this.addressData.nation = 'A'; + this.addressData.plz = null; + + this.statusNew = true; + }, + }, + created() { + this.$fhcApi + .get('api/frontend/v1/stv/address/getNations') + .then(result => { + this.nations = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/kontakt/getAdressentypen') + .then(result => { + this.adressentypen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError) + }, + template: ` +
+ + + + + + +
+ + + +
+ +
+ + +
+ +
+ + + +
+ +
+ + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+ + +
+ +
+
+ + +
+
+ +
+ + +
+ +
+ + + + +
+ +
+ +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + + +
` +}; + diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Bankaccount.js b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Bankaccount.js new file mode 100644 index 000000000..7eb1229f7 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Bankaccount.js @@ -0,0 +1,336 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import BsModal from "../../../../Bootstrap/Modal.js"; +import FormForm from '../../../../Form/Form.js'; +import FormInput from '../../../../Form/Input.js'; + +export default{ + components: { + CoreFilterCmpt, + BsModal, + FormForm, + FormInput + }, + props: { + uid: Number + }, + data() { + return{ + tabulatorOptions: { + ajaxURL: 'api/frontend/v1/stv/Kontakt/getBankverbindung/' + this.uid, + ajaxRequestFunc: this.$fhcApi.get, + ajaxResponse: (url, params, response) => response.data, + columns:[ + {title:"Name", field:"name"}, + {title:"Anschrift", field:"anschrift", visible:false}, + {title:"BIC", field:"bic"}, + {title:"BLZ", field:"blz", visible:false}, + {title:"IBAN", field:"iban"}, + {title:"Kontonummer", field:"kontonr", visible:false}, + {title:"Typ", field:"typ", visible:false, + formatter: (cell, formatterParams, onRendered) => { + let output; + switch(cell.getValue()){ + case "p": + output = "Privatkonto"; + break; + case "f": + output = "Firmenkonto"; + break; + default: + output = cell.getValue(); + } + return output;} + }, + { + title:"Verrechnung", + field:"verrechnung", + visible:false, + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + } + }, + {title:"Person_id", field:"person_id", visible:false}, + {title:"Bankverbindung_id", field:"bankverbindung_id", 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"; + + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.addEventListener('click', (event) => + this.actionEditBankverbindung(cell.getData().bankverbindung_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.addEventListener('click', () => + this.actionDeleteBankverbindung(cell.getData().bankverbindung_id) + ); + container.append(button); + + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + height: 'auto', + selectable: true, + index: 'bankverbindung_id', + persistenceID: 'stv-details-kontakt-bankaccount' + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async() => { + await this.$p.loadCategory(['global','person']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('anschrift').component.updateDefinition({ + title: this.$p.t('person', 'anschrift') + }); + cm.getColumnByField('kontonr').component.updateDefinition({ + title: this.$p.t('person', 'kontonr') + }); + cm.getColumnByField('blz').component.updateDefinition({ + title: this.$p.t('person', 'blz') + }); + cm.getColumnByField('typ').component.updateDefinition({ + title: this.$p.t('global', 'typ') + }); + cm.getColumnByField('verrechnung').component.updateDefinition({ + title: this.$p.t('person', 'verrechnung') + }); + } + } + ], + lastSelected: null, + bankverbindungData: { + verrechnung: true, + typ: 'p' + }, + statusNew: true + } + }, + watch: { + uid(){ + this.$refs.table.tabulator.setData('api/frontend/v1/stv/Kontakt/getBankverbindung/' + this.uid); + } + }, + methods:{ + actionNewBankverbindung(){ + this.resetModal(); + this.$refs.bankverbindungModal.show(); + }, + actionEditBankverbindung(bankverbindung_id){ + this.statusNew = false; + this.loadBankverbindung(bankverbindung_id).then(() => { + if(this.bankverbindungData.bankverbindung_id) + this.$refs.bankverbindungModal.show(); + }); + }, + actionDeleteBankverbindung(bankverbindung_id){ + this.loadBankverbindung(bankverbindung_id).then(() => { + this.$fhcAlert + .confirmDelete() + .then(result => result + ? bankverbindung_id + : Promise.reject({handled: true})) + .then(this.deleteBankverbindung) + .catch(this.$fhcAlert.handleSystemError); + }); + }, + addNewBankverbindung(bankverbindungData) { + this.$fhcApi.post('api/frontend/v1/stv/kontakt/addNewBankverbindung/' + this.uid, + this.bankverbindungData + ).then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal('bankverbindungModal'); + this.resetModal(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + window.scrollTo(0, 0); + this.reload(); + }); + }, + loadBankverbindung(bankverbindung_id){ + this.statusNew = false; + return this.$fhcApi.get('api/frontend/v1/stv/kontakt/loadBankverbindung/' + bankverbindung_id) + .then( + result => { + this.bankverbindungData = result.data; + return result; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + updateBankverbindung(bankverbindung_id){ + this.$fhcApi.post('api/frontend/v1/stv/kontakt/updateBankverbindung/' + bankverbindung_id, + this.bankverbindungData) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal('bankverbindungModal'); + this.resetModal(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + window.scrollTo(0, 0); + this.reload(); + }); + }, + deleteBankverbindung(bankverbindung_id){ + this.$fhcApi.post('api/frontend/v1/stv/kontakt/deleteBankverbindung/' + bankverbindung_id) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }).catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + window.scrollTo(0, 0); + this.resetModal(); + this.reload(); + }); + }, + hideModal(modalRef){ + this.$refs[modalRef].hide(); + }, + reload(){ + this.$refs.table.reloadTable(); + }, + resetModal(){ + this.bankverbindungData = {}; + this.bankverbindungData.name = ""; + this.bankverbindungData.anschrift = ""; + this.bankverbindungData.iban = ""; + this.bankverbindungData.bic = ""; + this.bankverbindungData.kontonr = ""; + this.bankverbindungData.blz = ""; + this.bankverbindungData.bic = ""; + this.bankverbindungData.verrechnung = true; + this.bankverbindungData.typ = 'p'; + + this.statusNew = true; + }, + }, + template: ` +
+ + + + + + + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+
+ + + + +
+
+ + +
+
+ + + +
+ + + +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Contact.js b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Contact.js new file mode 100644 index 000000000..3acb6353d --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Contact.js @@ -0,0 +1,401 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import BsModal from "../../../../Bootstrap/Modal.js"; +import PvAutoComplete from "../../../../../../../index.ci.php/public/js/components/primevue/autocomplete/autocomplete.esm.min.js"; +import FormForm from '../../../../Form/Form.js'; +import FormInput from '../../../../Form/Input.js'; + +export default{ + components: { + CoreFilterCmpt, + PvAutoComplete, + BsModal, + FormForm, + FormInput + }, + props: { + uid: Number + }, + data() { + return{ + tabulatorOptions: { + ajaxURL: 'api/frontend/v1/stv/Kontakt/getKontakte/' + this.uid, + ajaxRequestFunc: this.$fhcApi.get, + ajaxResponse: (url, params, response) => response.data, + columns:[ + {title:"Typ", field:"kontakttyp"}, + {title:"Kontakt", field:"kontakt"}, + { + title:"Zustellung", + field:"zustellung", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + } + }, + {title:"Anmerkung", field:"anmerkung"}, + {title:"Firma", field:"name", visible:false}, + {title:"Standort", field:"bezeichnung", visible:false}, + {title:"Firma_id", field:"firma_id", visible:false}, + {title:"Person_id", field:"person_id", visible:false}, + {title:"Kontakt_id", field:"kontakt_id", visible:false}, + {title:"Standort_id", field:"standort_id", visible:false}, + {title:"letzte Änderung", field:"lastupdate", 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"; + + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.addEventListener('click', (event) => + this.actionEditContact(cell.getData().kontakt_id) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.addEventListener('click', () => + this.actionDeleteContact(cell.getData().kontakt_id) + ); + container.append(button); + + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + height: 'auto', + selectable: true, + index: 'kontakt_id', + persistenceID: 'stv-details-kontakt-contact' + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async() => { + await this.$p.loadCategory(['notiz','global','person']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('kontakttyp').component.updateDefinition({ + title: this.$p.t('global', 'typ') + }); + cm.getColumnByField('kontakt').component.updateDefinition({ + title: this.$p.t('global', 'kontakt') + }); + cm.getColumnByField('zustellung').component.updateDefinition({ + title: this.$p.t('person', 'zustellung') + }); + cm.getColumnByField('anmerkung').component.updateDefinition({ + title: this.$p.t('global', 'anmerkung') + }); + + cm.getColumnByField('lastupdate').component.updateDefinition({ + title: this.$p.t('notiz', 'letzte_aenderung') + }); + cm.getColumnByField('name').component.updateDefinition({ + title: this.$p.t('person', 'firma') + }); + cm.getColumnByField('bezeichnung').component.updateDefinition({ + title: this.$p.t('person', 'standort') + }); + }} + ], + lastSelected: null, + contactData: { + zustellung: true, + kontakttyp: 'email', + firma_id: null + }, + statusNew: true, + kontakttypen: [], + firmen: [], + filteredFirmen: [], + filteredOrte: null, + } + }, + watch: { + uid() { + this.$refs.table.tabulator.setData('api/frontend/v1/stv/Kontakt/getKontakte/' + this.uid); + }, + contactData: { + handler(newVal) { + if (newVal.firma && newVal.firma.firma_id !== null && typeof newVal.firma.firma_id !== 'undefined') { + this.loadStandorte(this.contactData.firma.firma_id); + } + }, + deep: true + } + }, + methods:{ + actionNewContact(){ + this.resetModal(); + this.$refs.contactModal.show(); + }, + actionEditContact(contact_id){ + this.statusNew = false; + this.loadContact(contact_id); + this.$refs.contactModal.show(); + }, + actionDeleteContact(contact_id){ + this.loadContact(contact_id); + + this.$fhcAlert + .confirmDelete() + .then(result => result + ? contact_id + : Promise.reject({handled: true})) + .then(this.deleteContact) + .catch(this.$fhcAlert.handleSystemError); + }, + addNewContact(formData) { + this.$fhcApi.post('api/frontend/v1/stv/kontakt/addNewContact/' + this.uid, + this.contactData) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal("contactModal"); + this.resetModal(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(() => { + window.scrollTo(0, 0); + this.reload(); + }); + }, + loadContact(contact_id){ + this.statusNew = false; + if(this.contactData.firma_id) + this.loadStandorte(this.contactData.firma_id); + return this.$fhcApi.get('api/frontend/v1/stv/kontakt/loadContact/' + contact_id) + .then( + result => { + this.contactData = result.data; + return result; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + deleteContact(kontakt_id){ + this.$fhcApi.post('api/frontend/v1/stv/kontakt/deleteContact/' + kontakt_id) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + window.scrollTo(0, 0); + this.resetModal(); + this.reload(); + }); + }, + updateContact(kontakt_id){ + this.$fhcApi.post('api/frontend/v1/stv/kontakt/updateContact/' + kontakt_id, + this.contactData). + then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.hideModal('contactModal'); + this.resetModal(); + this.reload(); + }).catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + window.scrollTo(0, 0); + this.reload(); + }); + }, + + hideModal(modalRef){ + this.$refs[modalRef].hide(); + }, + reload(){ + this.$refs.table.reloadTable(); + }, + searchFirma(event) { + return this.$fhcApi + .get('api/frontend/v1/stv/kontakt/getFirmen/' + event.query) + .then(result => { + this.filteredFirmen = result.data.retval; + }); + }, + loadStandorte(firmen_id) { + return this.$fhcApi + .get('api/frontend/v1/stv/kontakt/getStandorteByFirma/' + firmen_id) + .then(result => { + this.filteredOrte = result.data; + }); + }, + resetModal(){ + this.contactData = {}; + this.contactData.zustellung = true; + this.contactData.kontakttyp = 'email'; + this.contactData.kontakt = ''; + this.contactData.anmerkung = null; + this.contactData.firma_id = null; + this.contactData.name = null; + this.contactData.standort_id = null; + this.contactData.bezeichnung = null; + + this.statusNew = true; + }, + }, + created(){ + this.$fhcApi + .get('api/frontend/v1/stv/kontakt/getKontakttypen') + .then(result => { + this.kontakttypen = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` +
+ + + + + + + +
+ + + > + + + +
+ +
+ + required + > + +
+ +
+ + > + +
+ +
+
+ + +
+
+ +
+ + +
+ +
+ + + + +
+ + + + + +
+ + + + + + +
+ +
+ + +
+ + + +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Konto.js b/public/js/components/Stv/Studentenverwaltung/Details/Konto.js new file mode 100644 index 000000000..30fbcd448 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Konto.js @@ -0,0 +1,257 @@ +import {CoreFilterCmpt} from "../../../filter/Filter.js"; +import FormInput from "../../../Form/Input.js"; +import KontoNew from "./Konto/New.js"; +import KontoEdit from "./Konto/Edit.js"; + +const LOCAL_STORAGE_ID_FILTER = 'stv_details_konto_2024-01-11_filter'; + +export default { + components: { + CoreFilterCmpt, + FormInput, + KontoNew, + KontoEdit + }, + props: { + modelValue: Object, + config: { + type: Object, + default: {} + } + }, + data() { + return { + filter: false, + studiengang_kz: false, + counterdate: new Date() + }; + }, + computed: { + personIds() { + if (this.modelValue.person_id) + return [this.modelValue.person_id]; + return this.modelValue.map(e => e.person_id); + }, + stg_kz() { + if (this.modelValue.studiengang_kz) + return this.modelValue.studiengang_kz; + let values = this.modelValue.map(e => e.studiengang_kz).filter((v,i,a) => a.indexOf(v) === i); + if (values.length != 1) + return ''; + return values[0]; + }, + studiengang_kz_intern: { + get() { + if (this.stg_kz) + return this.studiengang_kz; + else + return false; + }, + set(value) { + this.studiengang_kz = value; + } + }, + tabulatorColumns() { + const columns = { ...this.config.columns }; + if (!columns.actions) + columns.actions = { + title: '', + frozen: true + }; + columns.actions.formatter = cell => { + let container = document.createElement('div'); + container.className = "d-flex gap-2"; + + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary'; + button.innerHTML = ''; + button.addEventListener('click', () => + this.$refs.edit.open(cell.getData()) + ); + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary'; + button.innerHTML = ''; + button.addEventListener('click', evt => { + evt.stopPropagation(); + this.$fhcAlert + .confirmDelete() + .then(result => result ? cell.getData().buchungsnr : Promise.reject({handled:true})) + .then(this.$fhcApi.factory.stv.konto.delete) + .then(() => { + // TODO(chris): deleting a child also removes the siblings! + //cell.getRow().delete(); + this.reload(); + }) + .catch(this.$fhcAlert.handleSystemError); + }); + container.append(button); + + return container; + }; + + return Object.values(columns); + }, + tabulatorOptions() { + return this.$fhcApi.factory.stv.konto.tabulatorConfig({ + dataTree: true, + columns: this.tabulatorColumns, + selectable: true, + selectableRangeMode: 'click', + index: 'buchungsnr', + persistenceID: 'stv-details-konto' + }, this); + } + }, + watch: { + modelValue() { + this.$refs.table.reloadTable(); + } + }, + methods: { + reload() { + this.$refs.table.reloadTable(); + }, + updateData(data) { + if (!data) + return this.reload(); + // TODO(chris): check children (!delete?, multiple children) + //this.$refs.table.tabulator.updateOrAddData(data.map(row => row.buchungsnr_verweis ? {buchungsnr:row.buchungsnr_verweis, _children:row} : row)); + this.$refs.table.tabulator.updateOrAddData(data); + }, + actionNew() { + this.$refs.new.open(); + }, + actionCounter(selected) { + this.$fhcApi + .factory.stv.konto.counter({ + buchungsnr: selected.map(e => e.buchungsnr), + buchungsdatum: this.counterdate + }) + .then(result => result.data) + .then(this.updateData) + .then(() => this.$p.t('ui/gespeichert')) + .then(this.$fhcAlert.alertSuccess) + .catch(this.$fhcAlert.handleSystemError); + }, + downloadPdf(selected) { + if (Array.isArray(this.modelValue)) { + let id_uid = this.modelValue.reduce((a,c) => { + if (c.uid) + a[c.person_id] = c.uid; + return a + }, {}); + let persons = selected.reduce((a,c) => { + if (!a[c.person_id]) { + let uid = id_uid[c.person_id] || ''; + a[c.person_id] = uid + '&buchungsnummern=' + c.buchungsnr; + } else { + a[c.person_id] += ';' + c.buchungsnr; + } + return a; + }, {}); + Object.values(persons).forEach(part => window.open( + FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'content/pdfExport.php?xml=konto.rdf.php&xsl=Zahlung&uid=' + + part, + '_blank' + )); + } else { + window.open( + FHC_JS_DATA_STORAGE_OBJECT.app_root + + 'content/pdfExport.php?xml=konto.rdf.php&xsl=Zahlung&uid=' + + (this.modelValue.uid || '') + + '&buchungsnummern=' + + selected.map(row => row.buchungsnr).join(';'), + '_blank' + ); + } + }, + setFilter(type) { + if (type == 'open') + window.localStorage.setItem(LOCAL_STORAGE_ID_FILTER, this.filter ? 1 : 0); + else if (type == 'current_stg') + this.$fhcApi.factory + .stv.filter.setStg(this.studiengang_kz) + .catch(this.$fhcAlert.handleSystemError); + + this.$nextTick(this.$refs.table.reloadTable); + } + }, + created() { + this.filter = window.localStorage.getItem(LOCAL_STORAGE_ID_FILTER) == 1; + this.$fhcApi.factory + .stv.filter.getStg() + .then(result => this.studiengang_kz = result.data) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` +
+
+
+ + +
+
+ + +
+
+ + + + + +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Konto/Edit.js b/public/js/components/Stv/Studentenverwaltung/Details/Konto/Edit.js new file mode 100644 index 000000000..26b8f0891 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Konto/Edit.js @@ -0,0 +1,164 @@ +import BsModal from "../../../../Bootstrap/Modal.js"; +import CoreForm from "../../../../Form/Form.js"; +import FormValidation from "../../../../Form/Validation.js"; +import FormInput from "../../../../Form/Input.js"; + + +export default { + components: { + BsModal, + CoreForm, + FormValidation, + FormInput + }, + inject: { + lists: { + from: 'lists' + } + }, + props: { + config: { + type: Object, + default: {} + } + }, + data() { + return { + loading: false, + data: {} + }; + }, + methods: { + save() { + this.$refs.form.clearValidation(); + this.loading = true; + + this.$refs.form + .factory.stv.konto.edit(this.data) + .then(result => { + this.$emit('saved', result.data); + this.loading = false; + this.$refs.modal.hide(); + this.$fhcAlert.alertSuccess(this.$p.t('ui/gespeichert')); + }) + .catch(error => { + this.$fhcAlert.handleSystemError(error); + this.loading = false; + }); + }, + open(data) { + this.data = {...data}; + this.$refs.modal.show(); + }, + preventCloseOnLoading(ev) { + if (this.loading) + ev.returnValue = false; + } + }, + template: ` + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Konto/New.js b/public/js/components/Stv/Studentenverwaltung/Details/Konto/New.js new file mode 100644 index 000000000..ddbb59faa --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Konto/New.js @@ -0,0 +1,203 @@ +import BsModal from "../../../../Bootstrap/Modal.js"; +import BsConfirm from "../../../../Bootstrap/Confirm.js"; +import CoreForm from "../../../../Form/Form.js"; +import FormValidation from "../../../../Form/Validation.js"; +import FormInput from "../../../../Form/Input.js"; + + +export default { + components: { + BsModal, + CoreForm, + FormValidation, + FormInput + }, + inject: { + lists: { + from: 'lists' + }, + defaultSemester: { + from: 'defaultSemester' + } + }, + props: { + personIds: { + type: Array, + required: true + }, + stgKz: { + type: Number, + required: true + }, + config: { + type: Object, + default: {} + } + }, + data() { + return { + loading: false, + data: {} + }; + }, + computed: { + reversedSems() { + return this.lists.studiensemester.toReversed(); + }, + activeBuchungstypen() { + return this.lists.buchungstypen.filter(e => e.aktiv); + } + }, + methods: { + save() { + this.$refs.form.clearValidation(); + this.loading = true; + + const data = {...{ + person_id: this.personIds, + studiengang_kz: this.stgKz + }, ...this.data}; + + this.$refs.form + .factory.stv.konto.checkDoubles(data) + .then(result => result.data + ? Promise.all( + result.errors + .filter(e => e.type == 'confirm') + .map(e => BsConfirm.popup(Vue.h('div', {class:'text-preline'}, e.message))) + ) + : Promise.resolve()) + .then(() => data) + .then(this.$refs.form.factory.stv.konto.insert) + .then(result => { + this.$emit('saved', result.data); + this.loading = false; + this.$refs.modal.hide(); + this.$fhcAlert.alertSuccess(this.$p.t('ui/gespeichert')); + }) + .catch(error => { + if (error) + this.$fhcAlert.handleSystemError(error); + this.loading = false; + }); + }, + open() { + this.data = { + buchungstyp_kurzbz: '', + betrag: '-0.00', + buchungsdatum: new Date(), + buchungstext: '', + mahnspanne: 30, + studiensemester_kurzbz: this.defaultSemester, + credit_points: null, + anmerkung: '' + }; + this.$refs.modal.show(); + }, + preventCloseOnLoading(ev) { + if (this.loading) + ev.returnValue = false; + }, + checkDefaultBetrag(ev) { + const typ = this.lists.buchungstypen.filter(e => e.buchungstyp_kurzbz == ev).pop(); + const amount = typ.standardbetrag || '-0.00'; + const text = typ.standardtext || ''; + const creditpoints = typ.credit_points || ''; + + if (!this.data.betrag || this.data.betrag == '-0.00') + this.data.betrag = amount; + + if (!this.data.buchungstext) + this.data.buchungstext = text; + + if (this.config.showCreditpoints && (this.data.credit_points == '0.00' || this.data.credit_points === null)) + this.data.credit_points = creditpoints; + } + }, + template: ` + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + +
+
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/MultiStatus.js b/public/js/components/Stv/Studentenverwaltung/Details/MultiStatus.js new file mode 100644 index 000000000..83788f611 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/MultiStatus.js @@ -0,0 +1,15 @@ +import TblMultiStatus from "./Prestudent/MultiStatus.js"; + +export default { + components: { + TblMultiStatus + }, + props: { + modelValue: Object, + }, + template: ` +
+ +
+ ` +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Noten.js b/public/js/components/Stv/Studentenverwaltung/Details/Noten.js new file mode 100644 index 000000000..8e8269ee5 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Noten.js @@ -0,0 +1,19 @@ +import NotenZeugnis from './Noten/Zeugnis.js'; + +export default { + components: { + NotenZeugnis + }, + props: { + modelValue: Object + }, + methods: { + reload() { + this.$refs.zeugnis.$refs.table.reloadTable(); + } + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js new file mode 100644 index 000000000..caeb0cfaa --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis.js @@ -0,0 +1,111 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import {CoreRESTClient} from '../../../../../RESTClient.js'; +import ZeugnisActions from './Zeugnis/Actions.js'; + +const LOCAL_STORAGE_ID = 'stv_details_noten_zeugnis_2024-01-11_stdsem_all'; + +export default { + components: { + CoreFilterCmpt, + ZeugnisActions + }, + props: { + student: Object + }, + data() { + return { + validStudent: true, + tabulatorEvents: [], + stdsem: '' + }; + }, + computed: { + ajaxURL() { + return CoreRESTClient._generateRouterURI('components/stv/Noten/getZeugnis/' + this.student.prestudent_id + this.stdsem); + }, + tabulatorOptions() { + return { + ajaxURL: this.ajaxURL, + ajaxResponse: (url, params, response) => { + if (!response.retval) + this.validStudent = false; + else + this.validStudent = true; + return response.retval || []; + }, + columns: [ + { field: 'zeugnis', title: 'Zeugnis', formatter: 'tickCross' }, + { field: 'lehrveranstaltung_bezeichnung', title: 'Lehrveranstaltung' }, + { field: 'note_bezeichnung', title: 'Note' }, + { field: 'uebernahmedatum', title: 'Übernahmedatum', visible: false }, + { field: 'benotungsdatum', title: 'Benotungsdatum', visible: false }, + { field: 'benotungsdatum-iso', title: 'Benotungsdatum ISO', visible: false }, + { field: 'studiensemester_kurzbz', title: 'Studiensemester', visible: false }, + { field: 'note', title: 'Note Numerisch', visible: false }, + { field: 'lehrveranstaltung_id', title: 'Lehrveranstaltung ID', visible: false }, + { field: 'studiengang', title: 'Studiengang', visible: false }, + { field: 'studiengang_kz', title: 'Studiengang Kennzahl', visible: false }, + { field: 'studiengang_lv', title: 'StudiengangLV', visible: false }, + { field: 'studiengang_kz_lv', title: 'Studiengang_kzLV', visible: false }, + { field: 'semester_lv', title: 'SemesterLV', visible: false }, + { field: 'ects_lv', title: 'ECTS', visible: false }, + { field: 'lehrform', title: 'Lehrform', visible: false }, + { field: 'kurzbz', title: 'Kurzbz', visible: false }, + { field: 'punkte', title: 'Punkte', visible: false }, + { field: 'lehrveranstaltung_bezeichnung_english', title: 'Englisch', visible: false } + ], + layout: 'fitDataStretch', + height: '100%', + selectable: true, + selectableRangeMode: 'click', + persistenceID: 'stv-details-noten-zeugnis' + }; + } + }, + watch: { + ajaxURL(n) { + if (this.$refs.table) + this.$refs.table.tabulator.setData(n); + } + }, + methods: { + setGrades(selected) { + CoreRESTClient + .post('components/stv/Noten/update', selected) + .then(this.$refs.table.reloadTable) + .catch(this.$fhcAlert.handleFormValidation); + }, + saveStdsem(event) { + window.localStorage.setItem(LOCAL_STORAGE_ID, event.target.value ? 'true' : ''); + } + }, + created() { + const savedPath = window.localStorage.getItem(LOCAL_STORAGE_ID); + this.stdsem = savedPath ? '/all' : ''; + }, + // TODO(chris): phrasen + template: ` +
+
Kein Student
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis/Actions.js b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis/Actions.js new file mode 100644 index 000000000..7e8e2cbe5 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Noten/Zeugnis/Actions.js @@ -0,0 +1,54 @@ +import {CoreRESTClient} from '../../../../../../RESTClient.js'; + +export default { + emits: [ + 'setGrades' + ], + props: { + selected: Array + }, + data() { + return { + grades: [] + }; + }, + computed: { + current: { + get() { + if (!this.selected.length) + return ''; + if (this.selected.length == 1) + return this.selected[0].note; + const grades = Object.keys(this.selected.reduce((a,c) => { + a[c.note] = true; + return a; + }, {})); + if (grades.length == 1) + return grades[0]; + return ''; + }, + set(note) { + this.$emit('setGrades', this.selected.map(zeugnis => { + const { lehrveranstaltung_id, uid: student_uid, studiensemester_kurzbz } = zeugnis; + return { lehrveranstaltung_id, student_uid, studiensemester_kurzbz, note }; + })); + } + } + }, + created() { + CoreRESTClient + .get('components/stv/Noten/get') + .then(result => result.data) + .then(result => { + this.grades = result.retval; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Notizen.js b/public/js/components/Stv/Studentenverwaltung/Details/Notizen.js new file mode 100644 index 000000000..ec8c18711 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Notizen.js @@ -0,0 +1,109 @@ +import CoreNotiz from "../../../Notiz/Notiz.js"; + +export default { + components: { + CoreNotiz + }, + props: { + modelValue: Object + }, + template: ` +
+ + + + + + + + + + + + +
+ ` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Prestudent.js b/public/js/components/Stv/Studentenverwaltung/Details/Prestudent.js new file mode 100644 index 000000000..e6db926cc --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Prestudent.js @@ -0,0 +1,523 @@ +import FormForm from '../../../Form/Form.js'; +import FormInput from '../../../Form/Input.js'; +import TblHistory from "./Prestudent/History.js"; + +import CoreUdf from '../../../Udf/Udf.js'; + +export default { + components: { + FormForm, + FormInput, + TblHistory, + CoreUdf + }, + inject: { + lists: { + from: 'lists' + }, + showZgvErfuellt: { + from: 'configShowZgvErfuellt', + default: false + }, + showZgvDoktor: { + from: 'configShowZgvDoktor', + default: false + }, + hasPrestudentPermission: { + from: 'hasPrestudentPermission', + default: false + }, + hasAssistenzPermission: { + from: 'hasAssistenzPermission', + default: false + }, + hasAdminPermission: { + from: 'hasAdminPermission', + default: false + }, + defaultSemester: { + from: 'defaultSemester', + } + }, + props: { + modelValue: Object, + }, + data() { + return { + data: [], + listZgvs: [], + listZgvsmaster: [], + listZgvsdoktor: [], + listStgs: [], + listAusbildung: [], + listAufmerksamdurch: [], + listBerufe: [], + listFoerderrelevant: [ + { text: 'wie Studiengang', value: null }, + { text: 'Ja', value: true }, + { text: 'Nein', value: false } + ], + listStgTyp: [], + initialFormData: {}, + deltaArray: {}, + actionUpdate: false + }; + }, + computed: { + deltaLength() { + return Object.keys(this.deltaArray).length; + } + }, + watch: { + data: { + // TODO(chris): use @input instead? + handler(n) { + + const delta = {}; + for (const key in this.data) { + if (this.data[key] !== this.initialFormData[key]) { + delta[key] = this.data[key]; + this.actionUpdate = true; + } + } + this.deltaArray = delta; + }, + deep: true + }, + modelValue(n){ + this.loadPrestudent(n); + } + }, + + methods: { + loadPrestudent() { + this.$fhcApi + .get('api/frontend/v1/stv/prestudent/get/' + this.modelValue.prestudent_id) + .then(result => result.data) + .then(result => { + this.data = result; + //neue DataVariable um ein Delta der vorgenommenen Änderungen berechnen zu können + this.initialFormData = {...this.data}; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + udfsLoaded(udfs) { + this.initialFormData = {...(this.initialFormData || {}), ...udfs}; + }, + updatePrestudent(){ + this.$refs.form + .post('api/frontend/v1/stv/prestudent/updatePrestudent/' + this.modelValue.prestudent_id, this.deltaArray) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.deltaArray = []; + this.actionUpdate = false; + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(() => { + window.scrollTo(0, 0); + }); + }, + }, + created() { + this.loadPrestudent(); + this.$fhcApi + .get('api/frontend/v1/stv/prestudent/getBezeichnungZGV') + .then(result => result.data) + .then(result => { + this.listZgvs = result; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/prestudent/getBezeichnungMZgv') + .then(result => result.data) + .then(result => { + this.listZgvsmaster = result; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/prestudent/getBezeichnungDZgv') + .then(result => result.data) + .then(result => { + this.listZgvsdoktor = result; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/lists/getStgs') + .then(result => result.data) + .then(result => { + this.listStgs = result; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/prestudent/getAusbildung') + .then(result => result.data) + .then(result => { + this.listAusbildung = result; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/prestudent/getAufmerksamdurch') + .then(result => result.data) + .then(result => { + this.listAufmerksamdurch = result; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/prestudent/getBerufstaetigkeit') + .then(result => result.data) + .then(result => { + this.listBerufe = result; + }) + .catch(this.$fhcAlert.handleSystemError); + this.$fhcApi + .get('api/frontend/v1/stv/prestudent/getTypenStg') + .then(result => result.data) + .then(result => { + this.listStgTyp = result; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` +
+ +
+ +
+
+ {{$p.t('lehre', 'title_zgv')}} {{modelValue.nachname}} {{modelValue.vorname}} +
+ + + + +
+
+ + + + + + + + + + + +
+
+ + + + + + + + + + + +
+ +
+ + + + + + + + + + + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ PrestudentIn +
+ + + + + + + + + +
+ + ` + /* TODO(chris): Ausgeblendet für Testing +
+ + + +
+ + +
+ + + + + +
+ */` + +
+ + + + + + +
+ +
+ + +
+ + +
+
+ + +
+ ` + /* TODO(chris): Ausgeblendet für Testing + + + + */` + + + +
+ +
+
+
+ Gesamthistorie + +
+
+ ` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Prestudent/History.js b/public/js/components/Stv/Studentenverwaltung/Details/Prestudent/History.js new file mode 100644 index 000000000..ac071d306 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Prestudent/History.js @@ -0,0 +1,80 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; + +export default{ + components: { + CoreFilterCmpt + }, + props: { + personId: Number, + prestudentId: Number + }, + data() { + return { + tabulatorOptions: { + ajaxURL: 'api/frontend/v1/stv/Prestudent/getHistoryPrestudents/' + this.personId, + ajaxRequestFunc: this.$fhcApi.get, + ajaxResponse: (url, params, response) => response.data, + //autoColumns: true, + columns:[ + {title:"StSem", field:"studiensemester_kurzbz"}, + {title:"Prio", field:"priorisierung"}, + {title:"Stg", field:"kurzbzlang"}, + {title:"Orgform", field:"orgform_kurzbz"}, + {title:"Studienplan", field:"bezeichnung"}, + {title:"UID", field:"student_uid"}, + {title:"Status", field:"status"}, + {title:"PrestudentId", field:"prestudent_id", visible:false} + ], + rowFormatter: row => { + const rowData = row.getData(); + const element = row.getElement(); + if (["Abgewiesener","Abbrecher","Absolvent"].includes(rowData.status_kurzbz)) { + element.classList.add('disabled'); + } + if (rowData.prestudent_id == this.prestudentId) { + element.classList.add('fw-bold'); + } + }, + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + height: 'auto', + selectable: false, + persistenceID: 'stv-details-prestudent-history' + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async () => { + await this.$p.loadCategory(['lehre']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('orgform_kurzbz').component.updateDefinition({ + title: this.$p.t('lehre', 'organisationsform') + }); + + cm.getColumnByField('bezeichnung').component.updateDefinition({ + title: this.$p.t('lehre', 'studienplan') + }); + } + } + ] + } + }, + watch: { + personId() { + this.$refs.table.tabulator.setData('api/frontend/v1/stv/Prestudent/getHistoryPrestudents/' + this.personId); + } + }, + template: ` +
+ + +
` +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Prestudent/MultiStatus.js b/public/js/components/Stv/Studentenverwaltung/Details/Prestudent/MultiStatus.js new file mode 100644 index 000000000..ac4a2dd9e --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Prestudent/MultiStatus.js @@ -0,0 +1,362 @@ +import {CoreFilterCmpt} from "../../../../filter/Filter.js"; +import BsModal from "../../../../Bootstrap/Modal.js"; +import BsConfirm from "../../../../Bootstrap/Confirm.js"; +import FormInput from '../../../../Form/Input.js'; +import StatusModal from '../Status/Modal.js'; +import StatusDropdown from '../Status/Dropdown.js'; + +export default{ + components: { + CoreFilterCmpt, + BsModal, + FormInput, + StatusModal, + StatusDropdown + }, + inject: { + defaultSemester: { + from: 'defaultSemester', + }, + hasPermissionToSkipStatusCheck: { + from: 'hasPermissionToSkipStatusCheck', + default: false + }, + $reloadList: { + from: '$reloadList', + required: true + } + }, + computed: { + prestudentIds() { + if (this.modelValue.prestudent_id) + { + return [this.modelValue.prestudent_id]; + } + return this.modelValue.map(e => e.prestudent_id); + }, + showToolbarStudent() { + if (Array.isArray(this.modelValue)) { + if (!this.modelValue.length) + return false; + return this.modelValue.every(item => item.uid); + } + return !!this.modelValue.uid; + }, + showToolbarInteressent() { + if (Array.isArray(this.modelValue)) { + if (!this.modelValue.length) + return false; + return !this.modelValue.some(item => item.uid); + } + return !this.modelValue.uid; + } + }, + props: { + modelValue: Object + }, + data() { + return { + tabulatorOptions: { + ajaxURL: 'api/frontend/v1/stv/Status/getHistoryPrestudent/' + this.modelValue.prestudent_id, + ajaxRequestFunc: this.$fhcApi.get, + ajaxResponse: (url, params, response) => response.data, + columns: [ + {title: "Kurzbz", field: "status_kurzbz", tooltip: true}, + {title: "StSem", field: "studiensemester_kurzbz"}, + {title: "Sem", field: "ausbildungssemester"}, + {title: "Lehrverband", field: "lehrverband", width: 72}, + {title: "Datum", field: "format_datum"}, + {title: "Studienplan", field: "bezeichnung"}, + {title: "BestätigtAm", field: "format_bestaetigtam"}, + {title: "AbgeschicktAm", field: "format_bewerbung_abgeschicktamum", visible:false}, + {title: "Statusgrund", field: "statusgrund_bezeichnung"}, + {title: "Organisationsform", field: "orgform_kurzbz", visible: false}, + {title: "PrestudentInId", field: "prestudent_id", visible: false}, + {title: "StudienplanId", field: "studienplan_id", visible: false}, + {title: "Anmerkung", field: "anmerkung", visible: false}, + {title: "BestätigtVon", field: "bestaetigtvon", visible: false}, + {title: "InsertAmUm", field: "format_insertamum", visible: false}, + {title: "InsertVon", field: "insertvon", visible: false}, + {title: "UpdateAmUm", field: "format_updateamum", visible: false}, + {title: "UpdateVon", field: "updatevon", visible: false}, + { + title: 'Aktionen', field: 'actions', + minWidth: 150, // Ensures Action-buttons will be always fully displayed + formatter: (cell, formatterParams, onRendered) => { + + const container = document.createElement('div'); + container.className = "d-flex gap-2"; + + const data = cell.getData(); + + let button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = 'Status vorrücken'; + button.addEventListener('click', () => + this.actionAdvanceStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester) + ); + if (!['Student', 'Diplomand', 'Unterbrecher'].includes(data.status_kurzbz)) + button.disabled = true; + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = 'Status bestätigen'; + button.addEventListener('click', () => + this.actionConfirmStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester) + ); + if (data.bestaetigtam || !data.bewerbung_abgeschicktamum) + button.disabled = true; + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = 'Status bearbeiten'; + button.addEventListener('click', () => + this.actionEditStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester) + ); + if (this.dataMeldestichtag && this.dataMeldestichtag > data.datum && !this.hasPermissionToSkipStatusCheck) + button.disabled = true; + container.append(button); + + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = 'Status löschen'; + button.addEventListener('click', () => + this.actionDeleteStatus(data.status_kurzbz, data.studiensemester_kurzbz, data.ausbildungssemester) + ); + if (this.dataMeldestichtag && this.dataMeldestichtag > data.datum && !this.hasPermissionToSkipStatusCheck) + button.disabled = true; + container.append(button); + + return container; + }, + frozen: true + }, + ], + rowFormatter: (row) => { + const rowData = row.getData(); + if (this.dataMeldestichtag && this.dataMeldestichtag > rowData.datum) + { + row.getElement().classList.add('disabled'); + } + }, + layout: 'fitDataFill', + layoutColumnsOnNewData: false, + height: 'auto', + selectable: false, + }, + tabulatorEvents: [ + { + event: 'tableBuilt', + handler: async () => { + await this.$p.loadCategory(['lehre','global','person']); + + let cm = this.$refs.table.tabulator.columnManager; + + cm.getColumnByField('lehrverband').component.updateDefinition({ + title: this.$p.t('lehre', 'lehrverband') + }); + + cm.getColumnByField('format_bestaetigtam').component.updateDefinition({ + title: this.$p.t('lehre', 'bestaetigt_am') + }); + + cm.getColumnByField('format_bewerbung_abgeschicktamum').component.updateDefinition({ + title: this.$p.t('lehre', 'bewerbung_abgeschickt_am') + }); + + cm.getColumnByField('bezeichnung').component.updateDefinition({ + title: this.$p.t('lehre', 'studienplan') + }); + + cm.getColumnByField('actions').component.updateDefinition({ + title: this.$p.t('global', 'aktionen') + }); + + cm.getColumnByField('format_datum').component.updateDefinition({ + title: this.$p.t('global', 'datum') + }); + + cm.getColumnByField('anmerkung').component.updateDefinition({ + title: this.$p.t('global', 'anmerkung') + }); + + cm.getColumnByField('bestaetigtvon').component.updateDefinition({ + title: this.$p.t('lehre', 'bestaetigt_von') + }); + + cm.getColumnByField('format_insertamum').component.updateDefinition({ + title: this.$p.t('lehre', 'insert_am') + }); + + cm.getColumnByField('insertvon').component.updateDefinition({ + title: this.$p.t('lehre', 'insert_von') + }); + } + } + ], + statusData: {}, + statusId: {}, + dataMeldestichtag: null, + statusNew: true, + maxSem: 0 + }; + }, + watch: { + modelValue() { + if (this.$refs.table) { + if (this.$refs.table.tableBuilt) + this.$refs.table.tabulator.setData('api/frontend/v1/stv/Status/getHistoryPrestudent/' + this.modelValue.prestudent_id); + else + this.data.tabulatorOptions.ajaxURL = 'api/frontend/v1/stv/Status/getHistoryPrestudent/' + this.modelValue.prestudent_id; + } + this.getMaxSem(); + } + }, + methods: { + getMaxSem() { + const studiengang_kzs = this.modelValue.studiengang_kz + ? [this.modelValue.studiengang_kz] + : this.modelValue.map(prestudent => prestudent.studiengang_kz); + this.maxSem = 0; + this.$fhcApi + .post('api/frontend/v1/stv/status/getMaxSemester/', {studiengang_kzs}) + .then(result => this.maxSem = result.data) + .catch(this.$fhcAlert.handleSystemError); + }, + actionNewStatus() { + this.$refs.test.open(this.modelValue); + }, + actionEditStatus(status, stdsem, ausbildungssemester) { + this.$refs.test.open(this.modelValue, status, stdsem, ausbildungssemester); + }, + actionDeleteStatus(status, stdsem, ausbildungssemester) { + const statusId = { + prestudent_id: this.modelValue.prestudent_id, + status_kurzbz: status, + studiensemester_kurzbz: stdsem, + ausbildungssemester: ausbildungssemester + }; + + this.$fhcAlert + .confirmDelete() + .then(result => result + ? 'api/frontend/v1/stv/status/isLastStatus/' + statusId.prestudent_id + : Promise.reject({handled: true}) + ) + .then(this.$fhcApi.get) + .then(result => result.data + ? new Promise((resolve, reject) => { BsConfirm.popup(this.$p.t('lehre', 'last_status_confirm_delete')).then(resolve).catch(() => reject({handled:true})) }) + : true + ) + .then(result => result + ? 'api/frontend/v1/stv/status/deleteStatus/' + Object.values(statusId).join('/') + : Promise.reject({handled: true}) + ) + .then(this.$fhcApi.post) + .then(() => this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'))) + .then(this.reload) + .then(this.$reloadList) + .catch(this.$fhcAlert.handleSystemError); + }, + actionAdvanceStatus(status, stdsem, ausbildungssemester) { + const statusId = { + prestudent_id: this.modelValue.prestudent_id, + status_kurzbz: status, + studiensemester_kurzbz: stdsem, + ausbildungssemester: ausbildungssemester + }; + this.$fhcApi + .post('api/frontend/v1/stv/status/advanceStatus/' + Object.values(statusId).join('/')) + .then(() => this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successAdvance'))) + .then(this.reload) + .catch(this.$fhcAlert.handleSystemError); + }, + actionConfirmStatus(status, stdsem, ausbildungssemester) { + BsConfirm + .popup(this.$p.t('stv', 'status_confirm_popup')) + .then(() => this.$fhcApi.post( + 'api/frontend/v1/stv/status/confirmStatus/' + + this.modelValue.prestudent_id + '/' + + status + '/' + + stdsem + '/' + + ausbildungssemester + )) + .then(() => this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successConfirm'))) + .then(this.reload) + .catch(this.$fhcAlert.handleSystemError); + }, + reload() { + if (this.$refs.table) + this.$refs.table.reloadTable(); + } + }, + created() { + this.getMaxSem(); + + this.$fhcApi + .get('api/frontend/v1/stv/status/getLastBismeldestichtag/') + .then(result => { + this.dataMeldestichtag = result.data[0].meldestichtag; + if (this.$refs.table && this.$refs.table.tableBuilt) + this.$refs.table.tabulator.redraw(true); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` +
+ + + + + + + + + + +
+ + + +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Status/Dropdown.js b/public/js/components/Stv/Studentenverwaltung/Details/Status/Dropdown.js new file mode 100644 index 000000000..77e1db67b --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Status/Dropdown.js @@ -0,0 +1,336 @@ +import BsModal from "../../../../Bootstrap/Modal.js"; +import BsConfirm from "../../../../Bootstrap/Confirm.js"; +import BsPrompt from "../../../../Bootstrap/Prompt.js"; +import FormInput from '../../../../Form/Input.js'; + +export default { + components: { + BsModal, + FormInput + }, + inject: { + $reloadList: { + from: '$reloadList', + required: true + } + }, + emits: [ + 'reloadTable' + ], + props: { + showToolbarStudent: { + type: Boolean, + required: true + }, + showToolbarInteressent: { + type: Boolean, + required: true + }, + prestudentIds: { + type: Array, + required: true, + default: () => [] + } + }, + data() { + return { + listDataToolbar: [], + //TODO(Manu) get from config + statiInteressent: ["Bewerber", "Aufgenommener", "Student" , "Wartender", "Abgewiesener"], + statiStudent: ["Abbrecher", "Unterbrecher", "Student" , "Diplomand", "Absolvent"] + }; + }, + computed: { + showToolbar() { + return this.showToolbarStudent || this.showToolbarInteressent; + }, + sortedGruende() { + return this.listDataToolbar.reduce((result,current) => { + if (!result[current.status_kurzbz]) + result[current.status_kurzbz] = []; + result[current.status_kurzbz].push(current); + return result; + }, {}); + }, + resultInteressentArray() { + const result = []; + this.statiInteressent.forEach(status => { + const defaultObject = { + status_kurzbz: status, + statusgrund_id: null, + link: () => this['changeStatusTo' + status](), + children: [] + }; + + if (status === "Student") { + defaultObject.link = () => this.changeInteressentToStudent(); + + } + result.push(defaultObject); + if(this.sortedGruende[status]) { + this.sortedGruende[status].forEach(item => { + const itemObject = { + status_kurzbz: item.status_kurzbz, + statusgrund_id: item.statusgrund_id, + beschreibung: item.beschreibung, + link: () => this['changeStatusTo' + item.status_kurzbz](item.statusgrund_id), + }; + + if (item.status_kurzbz === "Student") { + itemObject.link = () => this['changeInteressentTo' + item.status_kurzbz](item.statusgrund_id); + } + defaultObject.children.push(itemObject); + }); + //push one item object if student is in the array + const hasStudentChild = defaultObject.children.some(child => child.status_kurzbz === "Student"); + + if (hasStudentChild) { + defaultObject.children.push({ + status_kurzbz: 'Student', + statusgrund_id: null, + beschreibung: 'Student', + link: () => this.changeInteressentToStudent() + }); + } + } + }); + return result; + }, + resultStudentArray() { + const result = []; + this.statiStudent.forEach(status => { + const defaultObject = { + status_kurzbz: status, + statusgrund_id: null, + link: () => this['changeStatusTo' + status](), + children: [] + }; + result.push(defaultObject); + if(this.sortedGruende[status]) { + this.sortedGruende[status].forEach(item => { + const itemObject = { + status_kurzbz: item.status_kurzbz, + statusgrund_id: item.statusgrund_id, + beschreibung: item.beschreibung, + link: () => this['changeStatusTo' + item.status_kurzbz](item.statusgrund_id) + }; + defaultObject.children.push(itemObject); + }); + } + //push one item object if student is in the array + const hasStudentChild = defaultObject.children.some(child => child.status_kurzbz === "Student"); + + if (hasStudentChild) { + defaultObject.children.push({ + status_kurzbz: 'Student', + statusgrund_id: null, + beschreibung: 'Student', + link: () => this.changeStatusToStudent() + }); + } + }); + return result; + } + }, + methods: { + changeInteressentToStudent(statusgrund_id) { + this.addStudent({status_kurzbz: 'student', statusgrund_id}); + }, + addStudent(data) { + Promise + .allSettled( + this.prestudentIds.map(prestudent_id => this.$fhcApi.post( + 'api/frontend/v1/stv/status/addStudent/' + prestudent_id, + data, + { errorHeader: prestudent_id } + )) + ) + .then(res => this.showFeedback(res, data.status_kurzbz)); + }, + changeStatusToAbbrecher(statusgrund_id) { + this + .confirmStatusChange('Abbrecher', statusgrund_id) + .then(this.changeStatus) + .catch(this.$fhcAlert.handleSystemError); + }, + changeStatusToUnterbrecher(statusgrund_id) { + this + .confirmStatusChange('Unterbrecher', statusgrund_id) + .then(this.changeStatus) + .catch(this.$fhcAlert.handleSystemError); + }, + changeStatusToStudent(statusgrund_id) { + this + .promtAusbildungssemester('Student', statusgrund_id) + .then(this.changeStatus) + .catch(this.$fhcAlert.handleSystemError); + }, + changeStatusToDiplomand(statusgrund_id) { + this.changeStatus({status_kurzbz: 'Diplomand', statusgrund_id}); + }, + changeStatusToAbsolvent(statusgrund_id) { + this.changeStatus({status_kurzbz: 'Absolvent', statusgrund_id}); + }, + changeStatusToBewerber(statusgrund_id) { + this.changeStatus({status_kurzbz: 'Bewerber', statusgrund_id}); + }, + changeStatusToAufgenommener(statusgrund_id) { + this + .confirmStatusChange('Aufgenommener', statusgrund_id) + .then(this.changeStatus) + .catch(this.$fhcAlert.handleSystemError); + }, + changeStatusToAbgewiesener(statusgrund_id) { + this + .confirmStatusChange('Abgewiesener', statusgrund_id) + .then(this.changeStatus) + .catch(this.$fhcAlert.handleSystemError); + }, + changeStatusToWartender(statusgrund_id) { + this + .confirmStatusChange('Wartender', statusgrund_id) + .then(this.changeStatus) + .catch(this.$fhcAlert.handleSystemError); + }, + confirmStatusChange(status, statusgrund_id) { + const count = this.prestudentIds.length; + return BsConfirm + .popup(this.$p.t( + 'lehre', + count > 1 ? 'modal_StatusactionPlural' : 'modal_StatusactionSingle', + { count, status } + )) + .then(() => ({ + status_kurzbz: status, + statusgrund_id + })); + }, + promtAusbildungssemester(status, statusgrund_id) { + const count = this.prestudentIds.length; + return BsPrompt + .popup(this.$p.t( + 'lehre', + count > 1 ? 'modal_askAusbildungssemPlural' : 'modal_askAusbildungssem', + { count, status } + )) + .then(ausbildungssemester => ({ + status_kurzbz: status, + ausbildungssemester, + statusgrund_id + })); + }, + changeStatus(data) { + Promise + .allSettled( + this.prestudentIds.map(prestudent_id => this.$fhcApi.post( + 'api/frontend/v1/stv/status/changeStatus/' + prestudent_id, + data, + { errorHeader: prestudent_id } + )) + ) + .then(res => this.showFeedback(res, data.status_kurzbz)); + }, + showFeedback(results, status_kurzbz) { + const countSuccess = results.filter(result => result.status == "fulfilled").length; + const countError = results.length - countSuccess; + + //Feedback Success als infoalert + this.$fhcAlert.alertInfo(this.$p.t('ui', 'successNewStatus', { + countSuccess, + status: status_kurzbz, + countError + })); + + if(results.length == 1 && countSuccess > 0){ + this.$emit('reloadTable'); + } + this.$reloadList(); + } + }, + created() { + this.$fhcApi + .get('api/frontend/v1/stv/status/getStatusarray/') + .then(result => result.data) + .then(result => { + this.listDataToolbar = result; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` +
+ +
+ + + +
+
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Status/Modal.js b/public/js/components/Stv/Studentenverwaltung/Details/Status/Modal.js new file mode 100644 index 000000000..0b0736ea1 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Details/Status/Modal.js @@ -0,0 +1,398 @@ +import BsModal from "../../../../Bootstrap/Modal.js"; +import CoreForm from '../../../../Form/Form.js'; +import FormValidation from '../../../../Form/Validation.js'; +import FormInput from '../../../../Form/Input.js'; + +export default{ + components: { + BsModal, + CoreForm, + FormValidation, + FormInput + }, + inject: { + defaultSemester: { + from: 'defaultSemester', + }, + hasPermissionToSkipStatusCheck: { + from: 'hasPermissionToSkipStatusCheck', + default: false + }, + hasPrestudentstatusPermission: { + from: 'hasPrestudentstatusPermission', + default: false + }, + lists: { + from: 'lists' + }, + $reloadList: { + from: '$reloadList', + required: true + } + }, + emit: [ + 'saved' + ], + props: { + meldestichtag: { + type: Date, + required: true + }, + maxSem: { + type: Number, + required: true + } + }, + data() { + return { + prestudent: {}, + originalDatum: null, + statusNew: true, + mischform: false, + statusId: {}, + formData: {}, + studienplaene: [], + statusgruende: [], + stati: [], + allowedNewStatus: [ + 'Interessent', + 'Bewerber', + 'Aufgenommener', + 'Student', + 'Unterbrecher', + 'Diplomand', + 'Incoming' + ] + }; + }, + computed: { + semester() { + return Array.from({length: this.maxSem}, (_, index) => index); + }, + bisLocked() { + if (this.statusNew || this.hasPermissionToSkipStatusCheck) + return false; + + if (!this.originalDatum || !this.meldestichtag) + return true; + + return this.originalDatum < this.meldestichtag; + }, + isStatusBeforeStudent() { + let isStatusStudent = ['Student', 'Absolvent', 'Diplomand']; + return !isStatusStudent.includes(this.formData.status_kurzbz); + }, + allowedStati() { + if (!this.stati) + return []; + + if (this.statusNew) + return this.stati.filter(status => this.allowedNewStatus.includes(status.status_kurzbz)); + + return this.stati.filter(status => this.statusId.status_kurzbz == status.status_kurzbz); + }, + gruende() { + return this.statusgruende.filter(grund => grund.status_kurzbz == this.formData.status_kurzbz); + } + }, + methods: { + open(prestudent, status_kurzbz, studiensemester_kurzbz, ausbildungssemester) { + this.$refs.modal.hide(); + + if (!status_kurzbz && !studiensemester_kurzbz && !ausbildungssemester) { + this.statusNew = true; + this.statusId = prestudent.prestudent_id; + this.formData = { + status_kurzbz: 'Interessent', + studiensemester_kurzbz: this.defaultSemester, + ausbildungssemester: 1, + datum: new Date(), + bestaetigtam: new Date(), + bewerbung_abgeschicktamum: null, + studienplan_id: null, + anmerkung: null, + rt_stufe: null, + statusgrund_id: null + }; + this.originalDatum = null; + + this.loadStudienplaeneAndSetPrestudent(prestudent) + .then(this.$refs.form.clearValidation) + .then(this.$refs.modal.show) + .catch(this.$fhcAlert.handleSystemError); + } else { + this.statusId = { + prestudent_id: prestudent.prestudent_id, + status_kurzbz, + studiensemester_kurzbz, + ausbildungssemester + }; + + this.$fhcApi + .post('api/frontend/v1/stv/status/loadStatus/', this.statusId) + .then(result => { + this.statusNew = false; + this.formData = result.data; + this.originalDatum = new Date(result.data.datum); + return prestudent; + }) + .then(this.loadStudienplaeneAndSetPrestudent) + .then(this.$refs.form.clearValidation) + .then(this.$refs.modal.show) + .catch(this.$fhcAlert.handleSystemError); + } + }, + insertStatus() { + this.$refs.form + .post( + 'api/frontend/v1/stv/status/insertStatus/' + this.statusId, + this.formData + ) + .then(result => { + this.$reloadList(); + this.$emit('saved'); + this.$refs.modal.hide(); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + editStatus() { + this.$refs.form + .post( + 'api/frontend/v1/stv/status/updateStatus/' + Object.values(this.statusId).join('/'), + this.formData + ) + .then(result => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave')); + this.$reloadList(); + this.$emit('saved'); + this.$refs.modal.hide(); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + loadStudienplaeneAndSetPrestudent(prestudent) { + const old_id = this.prestudent.prestudent_id; + this.prestudent = prestudent; + if (old_id == prestudent.prestudent_id) + return Promise.resolve(); + + return this.$fhcApi + .get('api/frontend/v1/stv/prestudent/getStudienplaene/' + prestudent.prestudent_id) + .then(result => this.studienplaene = result.data) + .then(() => this.$fhcApi.get('api/frontend/v1/stv/prestudent/getStudiengang/' + prestudent.prestudent_id)) + .then(result => this.mischform = result.data.mischform); + } + }, + created() { + this.$fhcApi + .get('api/frontend/v1/stv/status/getStatusgruende') + .then(result => this.statusgruende = result.data) + .catch(this.$fhcAlert.handleSystemError); + /*this.$fhcApi + .get('api/frontend/v1/stv/lists/getStati') + .then(result => this.stati = result.data) + .catch(this.$fhcAlert.handleSystemError);*/ + this.stati = [ + { status_kurzbz: 'Interessent', bezeichnung: 'Interessent'}, + { status_kurzbz: 'Bewerber', bezeichnung: 'Bewerber'}, + { status_kurzbz: 'Aufgenommener', bezeichnung: 'Aufgenommener'}, + { status_kurzbz: 'Student', bezeichnung: 'Student'}, + { status_kurzbz: 'Unterbrecher', bezeichnung: 'Unterbrecher'}, + { status_kurzbz: 'Diplomand', bezeichnung: 'Diplomand'}, + { status_kurzbz: 'Incoming', bezeichnung: 'Incoming'}, + { status_kurzbz: 'Absolvent', bezeichnung: 'Absolvent'}, + { status_kurzbz: 'Abbrecher', bezeichnung: 'Abbrecher'}, + { status_kurzbz: 'Abgewiesener', bezeichnung: 'Abgewiesener'}, + { status_kurzbz: 'Wartender', bezeichnung: 'Wartender'} + ]; + }, + template: ` + + + + + + + +

+ {{$p.t('bismeldestichtag', 'info_MeldestichtagStatusgrund')}} +

+

+ {{$p.t('bismeldestichtag', 'info_MeldestichtagStatusgrundSemester')}} +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/List.js b/public/js/components/Stv/Studentenverwaltung/List.js new file mode 100644 index 000000000..0eac360d9 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/List.js @@ -0,0 +1,278 @@ +import {CoreFilterCmpt} from "../../filter/Filter.js"; +import ListNew from './List/New.js'; + + +export default { + components: { + CoreFilterCmpt, + ListNew + }, + inject: [ + 'lists' + ], + props: { + selected: Array, + studiengangKz: Number, + studiensemesterKurzbz: String + }, + emits: [ + 'update:selected' + ], + data() { + function dateFormatter(cell) + { + let val = cell.getValue(); + if (!val) + return ' '; + let date = new Date(val); + return date.toLocaleDateString(); + } + + return { + tabulatorOptions: { + columns:[ + {title:"UID", field:"uid"}, + {title:"TitelPre", field:"titelpre"}, + {title:"Nachname", field:"nachname"}, + {title:"Vorname", field:"vorname"}, + {title:"Wahlname", field:"wahlname", visible:false}, + {title:"Vornamen", field:"vornamen", visible:false}, + {title:"TitelPost", field:"titelpost"}, + {title:"SVNR", field:"svnr"}, + {title:"Ersatzkennzeichen", field:"ersatzkennzeichen"}, + {title:"Geburtsdatum", field:"gebdatum", formatter:dateFormatter}, + {title:"Geschlecht", field:"geschlecht"}, + {title:"Sem.", field:"semester"}, + {title:"Verb.", field:"verband"}, + {title:"Grp.", field:"gruppe"}, + {title:"Studiengang", field:"studiengang"}, + {title:"Studiengang_kz", field:"studiengang_kz", visible:false}, + {title:"Personenkennzeichen", field:"matrikelnr"}, + {title:"PersonID", field:"person_id"}, + {title:"Status", field:"status"}, + {title:"Status Datum", field:"status_datum", visible:false, formatter:dateFormatter}, + {title:"Status Bestaetigung", field:"status_bestaetigung", visible:false, formatter:dateFormatter}, + {title:"EMail (Privat)", field:"mail_privat", visible:false}, + {title:"EMail (Intern)", field:"mail_intern", visible:false}, + {title:"Anmerkungen", field:"anmerkungen", visible:false}, + {title:"AnmerkungPre", field:"anmerkung", visible:false}, + {title:"OrgForm", field:"orgform_kurzbz"}, + {title:"Aufmerksamdurch", field:"aufmerksamdurch_kurzbz", visible:false}, + {title:"Gesamtpunkte", field:"punkte", visible:false}, + {title:"Aufnahmegruppe", field:"aufnahmegruppe_kurzbz", visible:false}, + {title:"Dual", field:"dual", visible:false, formatter:'tickCross', formatterParams: { + tickElement: '', + crossElement: '' + }}, + {title:"Matrikelnummer", field:"matr_nr", visible:false}, + {title:"Studienplan", field:"studienplan_bezeichnung"}, + {title:"PreStudentInnenID", field:"prestudent_id"}, + {title:"Priorität", field:"priorisierung_relativ"}, + {title:"Mentor", field:"mentor", visible:false}, + {title:"Aktiv", field:"bnaktiv", visible:false, formatter:'tickCross', formatterParams: { + allowEmpty:true, + tickElement: '', + crossElement: '' + }}, + ], + rowFormatter(row) { + if (row.getData().bnaktiv === false) { + row.getElement().classList.add('text-muted'); + } + }, + + ajaxResponse: (url, params, response) => response.data, + + layout: 'fitDataStretch', + layoutColumnsOnNewData: false, + height: '100%', + selectable: true, + selectableRangeMode: 'click', + index: 'prestudent_id', + persistenceID: 'stv-list' + }, + tabulatorEvents: [ + { + event: 'rowSelectionChanged', + handler: this.rowSelectionChanged + }, + { + event: 'dataProcessed', + handler: this.autoSelectRows + }, + { + event: 'rowClick', + handler: this.handleRowClick // TODO(chris): this should be in the filter component + } + ], + focusObj: null, // TODO(chris): this should be in the filter component + lastSelected: null, + filterKontoCount0: undefined, + filterKontoMissingCounter: undefined + } + }, + methods: { + reload() { + this.$refs.table.reloadTable(); + }, + actionNewPrestudent() { + this.$refs.new.open(); + }, + rowSelectionChanged(data) { + this.lastSelected = this.selected; + this.$emit('update:selected', data); + }, + autoSelectRows(data) { + if (this.lastSelected) { + // NOTE(chris): reselect rows on refresh + let selected = this.lastSelected.map(el => this.$refs.table.tabulator.getRow(el.prestudent_id)) + // TODO(chris): unselect current item if it's no longer in the table? + // or maybe reselect only the last one? + selected = selected.filter(el => el); + + if (selected.length) + this.$refs.table.tabulator.selectRow(selected); + } else if(this.lastSelected === undefined) { + // NOTE(chris): select row if it's the only one (preferably only on startup) + if (data.length == 1) { + this.$refs.table.tabulator.selectRow(this.$refs.table.tabulator.getRows()); + } + } + }, + updateUrl(url, first) { + this.lastSelected = first ? undefined : this.selected; + + const params = {}, filter = {}; + if (this.filterKontoCount0) + filter.konto_count_0 = this.filterKontoCount0; + if (this.filterKontoMissingCounter) + filter.konto_missing_counter = this.filterKontoMissingCounter; + + if (filter.konto_count_0 || filter.konto_missing_counter) + params.filter = filter; + + if (!this.$refs.table.tableBuilt) { + if (!this.$refs.table.tabulator) { + this.tabulatorOptions.ajaxURL = url; + this.tabulatorOptions.ajaxParams = params; + } else + this.$refs.table.tabulator.on("tableBuilt", () => { + this.$refs.table.tabulator.setData(url, params); + }); + } else + this.$refs.table.tabulator.setData(url, params); + }, + onKeydown(e) { // TODO(chris): this should be in the filter component + if (!this.focusObj) + return; + switch (e.code) { + case 'Enter': + case 'Space': + e.preventDefault(); + const e2 = new Event('click', e); + e2.altKey = e.altKey; + e2.ctrlKey = e.ctrlKey; + e2.shiftKey = e.shiftKey; + this.focusObj.dispatchEvent(e2); + //row.component.toggleSelect(); + break; + case 'ArrowUp': + e.preventDefault(); + var next = this.focusObj.previousElementSibling; + if (next) + this.changeFocus(this.focusObj, next); + break; + case 'ArrowDown': + e.preventDefault(); + var next = this.focusObj.nextElementSibling; + if (next) + this.changeFocus(this.focusObj, next); + break; + } + }, + changeFocus(a, b) { // TODO(chris): this should be in the filter component + if (b) { + b.tabIndex = 0; + this.focusObj = b; + b.focus(); + } else { + this.focusObj = null; + } + a.tabIndex = -1; + return this.focusObj; + }, + onFocus(e) { // TODO(chris): this should be in the filter component + if (!this.focusObj) { + var container, target; + if (e.target.classList.contains('tabulator-container')) { + container = e.target; + target = container.querySelector('.tabulator-row'); + } else if (e.target.classList.contains('tabulator-row')) { + container = e.target.closest('.tabulator-container'); + target = e.target; + } + if (container && target) { + this.changeFocus(container, target); + } + } + }, + handleRowClick(e, row) { // TODO(chris): this should be in the filter component + if (this.focusObj) { + let el = row.getElement(); + if (el != this.focusObj) + this.changeFocus(this.focusObj, el); + } + } + }, + // TODO(chris): focusin, focusout, keydown and tabindex should be in the filter component + // TODO(chris): filter component column chooser has no accessibilty features + template: ` +
+
+ + + +
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/List/New.js b/public/js/components/Stv/Studentenverwaltung/List/New.js new file mode 100644 index 000000000..c02d9ba29 --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/List/New.js @@ -0,0 +1,681 @@ +import {CoreRESTClient} from '../../../../RESTClient.js'; +import BsModal from '../../../Bootstrap/Modal.js'; +import FhcForm from '../../../Form/Form.js'; +import FormValidation from '../../../Form/Validation.js'; +import FormInput from '../../../Form/Input.js'; +import accessibility from '../../../../directives/accessibility.js'; + +var _uuid = 0; +const FORMDATA_DEFAULT = { + address: { + func: 0, + nation: 'A' + }, + geburtsnation: 'A', + staatsbuergerschaft: 'A', + ausbildungssemester: 1, + orgform_kurzbz: '', + studienplan_id: '' +}; + +export default { + components: { + BsModal, + FhcForm, + FormValidation, + FormInput + }, + directives: { + accessibility + }, + inject: [ + 'lists' + ], + props: { + studiengangKz: Number, + studiensemesterKurzbz: String + }, + data() { + return { + places: [], + formData: FORMDATA_DEFAULT, + suggestions: {}, + person: null, + semester: [], + studienplaene: [], + abortController: { + suggestions: null, + places: null + } + } + }, + computed: { + formDataPerson() { + if (this.person) + return this.person; + return this.formData; + }, + orte() { + return this.places.filter(ort => ort.name == this.formData.address.gemeinde); + }, + gemeinden() { + return Object.values(this.places.reduce((res,place) => { + res[place.name] = place; + return res; + }, {})); + }, + formDataStg: { + get() { + return this.formData.studiengang_kz !== undefined ? this.formData.studiengang_kz : this.studiengangKz; + }, + set(v) { + this.formData.studiengang_kz = v; + } + }, + formDataSem: { + get() { + return this.formData.studiensemester_kurzbz !== undefined ? this.formData.studiensemester_kurzbz : this.studiensemesterKurzbz; + }, + set(v) { + this.formData.studiensemester_kurzbz = v; + } + } + }, + watch: { + formDataStg() { + this.loadStudienplaene(); + }, + formDataSem() { + this.loadStudienplaene(); + } + }, + methods: { + open() { + this.$refs.modal.show(); + }, + reset() { + this.formData = FORMDATA_DEFAULT; + this.person = null; + this.suggestions = []; + this.$refs.form.clearValidation(); + }, + loadSuggestions() {console.log('loadSuggestions'); + if (this.abortController.suggestions) + this.abortController.suggestions.abort(); + if (this.person !== null) + return; + + this.abortController.suggestions = new AbortController(); + // TODO(chris): move to fhcapi.factory + this.$fhcApi + .post('api/frontend/v1/stv/student/check', { + vorname: this.formData.vorname, + nachname: this.formData.nachname, + gebdatum: this.formData.gebdatum + }, { + signal: this.abortController.suggestions.signal + }) + .then(result => this.suggestions = result.data) + .catch(error => { + // NOTE(chris): repeat request + if (error.code != "ERR_CANCELED") + window.setTimeout(this.loadSuggestions, 100); + }); + }, + loadPlaces() { + if (this.abortController.places) + this.abortController.places.abort(); + if (this.formData.address.nation != 'A' || !this.formData.address.plz) + return; + + this.abortController.places = new AbortController(); + this.$refs.form + .get( + 'api/frontend/v1/stv/address/getPlaces/' + this.formData.address.plz, + undefined, + { + signal: this.abortController.places.signal + } + ) + .then(result => { + this.places = result.data + }) + .catch(error => { + if (error.code != "ERR_CANCELED") + window.setTimeout(this.loadPlaces, 100); + else + this.$fhcAlert.handleSystemError(error); + }); + }, + loadStudienplaene() { + if (this.formDataStg) + CoreRESTClient + .post('components/stv/studienplan/get', { + studiengang_kz: this.formDataStg, + studiensemester_kurzbz: this.formDataSem, + ausbildungssemester: this.formData.ausbildungssemester, + orgform_kurzbz: this.formData.orgform_kurzbz + }) + .then(result => CoreRESTClient.getData(result.data) || []) + .then(result => { + this.studienplaene = result; + if (this.formData.studienplan_id !== '' && !this.studienplaene.filter(plan => plan.studienplan_id == this.formData.studienplan_id).length) + this.formData.studienplan_id = ''; + }) + .catch(error => { + if (error.code == 'ERR_BAD_REQUEST') { + return this.studienplaene = []; + } + // NOTE(chris): repeat request + if (error.code != "ERR_CANCELED") + window.setTimeout(this.loadStudienplaene, 100); + }) + }, + changeAddressNation(e) { + if (this.formData['geburtsnation'] == this.formData['address']['nation']) + this.formData['geburtsnation'] = e.target.value; + if (this.formData['staatsbuergerschaft'] == this.formData['address']['nation']) + this.formData['staatsbuergerschaft'] = e.target.value; + this.loadPlaces(); + }, + send(e) { + if (this.person === null) + return this.person = 0; + + //this.$fhcAlert.resetFormValidation(this.$refs.form); + const data = {...this.formData, ...(this.person || {})}; + if (data.studiengang_kz === undefined) + data.studiengang_kz = this.studiengangKz; + if (data.studiensemester_kurzbz === undefined) + data.studiensemester_kurzbz = this.studiensemesterKurzbz; + + // TODO(chris): move to fhcapi.factory + this.$refs.form + .send('api/frontend/v1/stv/student/add', data) + .then(result => { + this.$fhcAlert.alertSuccess('Gespeichert'); + this.$refs.modal.hide(); + }) + .catch(this.$fhcAlert.handleSystemError); + } + }, + created() { + this.uuid = _uuid++; + CoreRESTClient + .get('components/stv/Studiensemester') + .then(result => CoreRESTClient.getData(result.data) || []) + .then(result => { + this.semester = result; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` + + + + + + + ` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Studiensemester.js b/public/js/components/Stv/Studentenverwaltung/Studiensemester.js new file mode 100644 index 000000000..c52d584fd --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Studiensemester.js @@ -0,0 +1,113 @@ +import {CoreRESTClient} from '../../../RESTClient.js'; + +export default { + emits: [ + 'changed' + ], + props: { + default: { + type: String, + default: '' + } + }, + data() { + return { + current: 0, + loading: true, + list: [], + today: -1 + }; + }, + methods: { + set(n) { + this.loading = true; + let fallback = this.current; + this.current = n; + this.save(fallback); + }, + next() { + this.loading = true; + let fallback = this.current; + if (this.current++ >= this.list.length) + this.current = this.list.length - 1; + this.save(fallback); + }, + prev() { + this.loading = true; + let fallback = this.current; + if (this.current-- < 0) + this.current = 0; + this.save(fallback); + }, + setToToday() { + if (this.today > 0) { + if (this.today == this.current) + return; + return this.set(this.today); + } + + this.loading = true; + CoreRESTClient + .get('components/stv/studiensemester/now') + .then(result => CoreRESTClient.getData(result.data)) + .then(result => { + this.today = this.list.indexOf(result); + if (this.today >= 0) { + if (this.today != this.current) + this.set(this.today); + } else { + // TODO(chris): handle error (list might not be loaded yet) + } + }) + .catch(this.$fhcAlert.handleSystemError); + }, + save(fallback) { + CoreRESTClient + .post('components/stv/studiensemester/set', { + studiensemester: this.list[this.current] + }) + .then(() => { + this.loading = false; + this.$emit('changed', this.list[this.current]); + }) + .catch(error => { + this.current = fallback; + this.loading = false; + this.$fhcAlert.handleFormValidation(error); + }); + } + }, + created() { + CoreRESTClient + .get('components/stv/studiensemester') + .then(result => CoreRESTClient.getData(result.data) || []) + .then(result => { + this.list = result.map(el => el.studiensemester_kurzbz); + this.loading = false; + this.current = this.list.indexOf(this.default); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` +
+ +
+ ` +} \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung/Verband.js b/public/js/components/Stv/Studentenverwaltung/Verband.js new file mode 100644 index 000000000..d3562b5da --- /dev/null +++ b/public/js/components/Stv/Studentenverwaltung/Verband.js @@ -0,0 +1,258 @@ +import {CoreRESTClient} from '../../../RESTClient.js'; + + +import PvTree from "../../../../../index.ci.php/public/js/components/primevue/tree/tree.esm.min.js"; +import PvTreetable from "../../../../../index.ci.php/public/js/components/primevue/treetable/treetable.esm.min.js"; +import PvColumn from "../../../../../index.ci.php/public/js/components/primevue/column/column.esm.min.js"; + + +export default { + components: { + PvTree, + PvTreetable, + PvColumn + }, + emits: [ + 'selectVerband' + ], + data() { + return { + loading: true, + nodes: [], + selectedKey: [], + filters: {}, // TODO(chris): filter only 1st level? + favnodes: [], + favorites: {on: false, list: []} + } + }, + computed: { + filteredNodes() { + // TODO(chris): what to display actually? + return this.favorites.on ? this.favnodes : this.nodes; + } + }, + methods: { + findNodeByKey(key, arr) { + if (!arr) + arr = this.nodes; + let res = arr.filter(n => n.key == key); + if (res.length) + return res.pop(); + res = arr.map(n => n.children ? this.findNodeByKey(key, n.children) : null).filter(a => a); + if (res.length) + return res.pop(); + return null; + }, + onExpandTreeNode(node) { + if (!node.children) { + if (node.data.link) { + let activeEl = null; + this.$nextTick(() => { + this.$nextTick(() => { + activeEl = document.activeElement; + }); + }); + this.loading = true; + + this.$fhcApi + .get('api/frontend/v1/stv/verband/' + node.data.link) + .then(result => result.data) + .then(result => { + const subNodes = result.map(this.mapResultToTreeData); + const realNode = this.findNodeByKey(node.key); + if (realNode) + realNode.children = subNodes; + else + node.children = subNodes; // NOTE(chris): fallback should never be the case + + let treeitem = this.$refs.tree.$el.querySelector('[data-tree-item-key="' + node.key + '"]'); + treeitem = treeitem.closest('[role="row"]'); + + this.$nextTick(() => { + if (activeEl == document.activeElement) + treeitem.dispatchEvent(new KeyboardEvent('keydown', { + code: 'ArrowDown', + key: 'ArrowDown' + })); + }); + + this.loading = false; + }) + .catch(this.$fhcAlert.handleSystemError); + } + } + }, + onSelectTreeNode(node) { + if (node.data.link) + this.$emit('selectVerband', {link: node.data.link, studiengang_kz: node.data.stg_kz}); + }, + mapResultToTreeData(el) { + const cp = { + key: ("" + el.link).replace('/', '-'), + data: el, + label: el.name + }; + + if (el.children) + cp.children = el.children.map(this.mapResultToTreeData); + else + cp.leaf = el.leaf || false; + + return cp; + }, + async filterFav() { + if (!this.favorites.on && !this.favnodes.length && this.favorites.list.length) { + this.loading = true; + this.favnodes = await this.loadNodes(this.favorites.list); + } + this.favorites.on = !this.favorites.on; + this.$fhcApi + .factory.stv.verband.favorites.set(JSON.stringify(this.favorites)); + this.loading = false; + }, + async loadNodes(links) { + let sortedInParents = links.reduce((o, link) => { + link = link + ''; + let parent, + parts = link.split('/'); + if (parts.length == 1) { + parent = '_'; + } else { + parts.pop(); + parent = parts.join('/'); + } + if (!o[parent]) + o[parent] = [link]; + else + o[parent].push(link); + return o; + }, {}); + + let promises = []; + for (let parent in sortedInParents) + promises.push( + this.$fhcApi + .get('api/frontend/v1/stv/verband/' + (parent == '_' ? '' : parent)) + .then(res => res.data) + .then(res => res.filter(node => sortedInParents[parent].includes(node.link + ''))) + ); + + // NOTE(chris): merge the resulting arrays and transform them to an associative one + let result = [].concat.apply([], await Promise.all(promises)).reduce((o, node) => { + o[node.link + ''] = this.mapResultToTreeData({...node, leaf: true, children: undefined}); + return o; + }, {}); + + return links.map(link => result[link]); + }, + async markFav(key) { + let index = this.favorites.list.indexOf(key.data.link + ''); + + if (index != -1) { + if (this.favnodes.length) + this.favnodes = this.favnodes.filter(node => node.data.link != key.data.link); + this.favorites.list.splice(index, 1); + } else { + if (this.favnodes.length || this.favorites.on) + this.favnodes.push((await this.loadNodes([key.data.link])).pop()); + this.favorites.list.push(key.data.link + ''); + } + + this.$fhcApi + .factory.stv.verband.favorites.set(JSON.stringify(this.favorites)); + }, + unsetFavFocus(e) { + if (e.target.dataset?.linkFavAdd !== undefined) { + e.target.tabIndex = -1; + } else { + let items = e.target.querySelectorAll('[data-link-fav-add]:not([tabindex="-1"])'); + items.forEach(el => el.tabIndex = document.activeElement == el ? 0 : -1); + } + }, + setFavFocus(e) { + if (e.target.dataset?.linkFavAdd !== undefined) { + e.target.tabIndex = 0; + } else { + let items = e.target.querySelectorAll('[data-link-fav-add][tabindex="-1"]'); + items.forEach(el => el.tabIndex = 0); + } + } + }, + mounted() { + this.$fhcApi + .factory.stv.verband.get() + .then(result => { + this.nodes = result.data.map(this.mapResultToTreeData); + this.loading = false; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$fhcApi + .factory.stv.verband.favorites.get() + .then(result => { + if (result.data) { + let f = JSON.parse(result.data); + if (f.on) { + this.loading = true; + this.favorites = f; + this.loadNodes(this.favorites.list).then(res => { + this.favnodes = res; + this.loading = false; + }); + } else + this.favorites = f; + } + }) + .catch(this.$fhcAlert.handleSystemError); + }, + template: ` +
+ + + + + + + + + + + +
` +}; \ No newline at end of file diff --git a/public/js/components/Tabs.js b/public/js/components/Tabs.js index b9a07e370..cde12e02b 100644 --- a/public/js/components/Tabs.js +++ b/public/js/components/Tabs.js @@ -75,7 +75,7 @@ export default { tabs[key] = { component: Vue.markRaw(Vue.defineAsyncComponent(() => import(item.component))), - title: item.title || key, + title: Vue.computed(() => item.title || key), config: item.config, key } diff --git a/public/js/components/Udf/Udf.js b/public/js/components/Udf/Udf.js new file mode 100644 index 000000000..89f3a2fbc --- /dev/null +++ b/public/js/components/Udf/Udf.js @@ -0,0 +1,156 @@ +import { CoreFetchCmpt } from '../Fetch.js'; +import FormInput from '../Form/Input.js'; + + +export default { + components: { + CoreFetchCmpt, + FormInput + }, + emits: [ + 'update:modelValue', + 'load' + ], + props: { + // CodeIgniter model (eg: crm/prestudent) + ciModel: { + type: String, + required: true + }, + // Primarykey(s) of the record (eg: {prestudent_id: 12345}) + pk: { + type: Object, + required: true + }, + // The values as associative array + modelValue: Object, + // Show only fields with a name that exists in the filter + filter: [String, Array] + }, + data() { + return { + fields: [], + backupModelValue: {} + }; + }, + computed: { + filterArray() { + if (!this.filter || Array.isArray(this.filter)) + return this.filter; + return [this.filter]; + }, + filteredFields() { + if (!this.filterArray) + return this.fields; + return this.fields.filter(el => this.filterArray.includes(el.name)); + }, + filteredValues() { + return this.filteredFields.reduce((r,e) => (r[e.name] = this.internModelValue[e.name], r), {}); + }, + internModelValue: { + get() { + return this.modelValue || this.backupModelValue; + }, + set(value) { + this.backupModelValue = value; + this.$emit('update:modelValue', value); + this.originalValues + } + } + }, + watch: { + pk(n, o) { + if (!this.$refs.fetch) + return; // NOTE(chris): no initial load yet + + if (Object.keys(o).length == Object.keys(n).length + && Object.keys(o).every(key => n.hasOwnProperty(key) && o[key] === n[key])) + return; // NOTE(chris): old and new are the same + + this.$nextTick(this.$refs.fetch.fetchData); + } + }, + methods: { + loadF(params) { + // TODO(chris): move to fhcapi.factory + return this.$fhcApi + .post('/api/frontend/v1/udf/load/' + params.ciModel, params.pk); + }, + init(result) { + const fields = result.map(el => { + switch (el.type) { + case 'textfield': + el.type = 'text'; + break; + case 'date': + el.type = 'Datepicker'; + el.clearable = el.hasOwnProperty('clearable') ? el.clearable : false + el.autoApply = el.hasOwnProperty('autoApply') ? el.autoApply : true + el.enableTimePicker = el.hasOwnProperty('enableTimePicker') ? el.enableTimePicker : false + el.format = el.hasOwnProperty('format') ? el.format : "dd.MM.yyyy" + el.previewFormat = el.hasOwnProperty('previewFormat') ? el.previewFormat : "dd.MM.yyyy" + el.teleport = el.hasOwnProperty('teleport') ? el.teleport : true + break; + case 'multipledropdown': + el.multiple = true; + case 'dropdown': + el.type = 'select'; + el.options = el.options.map(item => { + if (Array.isArray(item)) + return { + id: item[0], + description: item[1] + }; + if (typeof item === 'object') + return item; + return { + id: item, + description: item + }; + }); + break; + } + return el; + }); + const values = fields.reduce((a,c) => { + a[c.name] = c.value; + return a; + }, {}); + + this.internModelValue = {...this.internModelValue, ...values}; + this.fields = fields; + this.$emit('load', values); + } + }, + template: ` +
+ + + +
` +} \ No newline at end of file diff --git a/public/js/components/filter/API.js b/public/js/components/filter/API.js index 58afc5bb3..1a79dfc9e 100755 --- a/public/js/components/filter/API.js +++ b/public/js/components/filter/API.js @@ -17,7 +17,7 @@ import {CoreRESTClient} from '../../RESTClient.js'; -// +// const CORE_FILTER_CMPT_TIMEOUT = 7000; /** diff --git a/public/js/components/filter/Filter.js b/public/js/components/filter/Filter.js index 047a3d0ec..cff692c21 100755 --- a/public/js/components/filter/Filter.js +++ b/public/js/components/filter/Filter.js @@ -19,6 +19,7 @@ import {CoreFetchCmpt} from '../../components/Fetch.js'; import FilterConfig from './Filter/Config.js'; import FilterColumns from './Filter/Columns.js'; import TableDownload from './Table/Download.js'; +import collapseAutoClose from '../../directives/collapseAutoClose.js'; // const FILTER_COMPONENT_NEW_FILTER = 'Filter Component New Filter'; @@ -36,6 +37,9 @@ export const CoreFilterCmpt = { FilterColumns, TableDownload }, + directives: { + collapseAutoClose + }, emits: [ 'nwNewEntry', 'click:new', @@ -49,8 +53,7 @@ export const CoreFilterCmpt = { default: true }, filterType: { - type: String, - required: true + type: String }, tabulatorOptions: Object, tabulatorEvents: Array, @@ -64,7 +67,11 @@ export const CoreFilterCmpt = { newBtnShow: Boolean, newBtnClass: [String, Array, Object], newBtnDisabled: Boolean, - newBtnLabel: String + newBtnLabel: String, + uniqueId: String, + // TODO soll im master kommen? + idField: String, + parentIdField: String }, data: function() { return { @@ -209,8 +216,15 @@ export const CoreFilterCmpt = { tabulatorOptions.columns = this.filteredColumns; } - if (tabulatorOptions.columns && tabulatorOptions.columns.filter(el => el.formatter == 'rowSelection').length) + if (tabulatorOptions.selectable || (tabulatorOptions.columns && tabulatorOptions.columns.filter(el => el.formatter == 'rowSelection').length)) this.tabulatorHasSelector = true; + // TODO check ob im core bleiben soll + if (this.idField) { + // enable nested tabulator if parent Id given + if (this.parentIdField) tabulatorOptions.dataTree = true; + // set tabulator index + tabulatorOptions.index = this.idField; + } // Start the tabulator with the build options this.tabulator = new Tabulator( @@ -228,6 +242,33 @@ export const CoreFilterCmpt = { this.tabulator.on("rowSelectionChanged", data => { this.selectedData = data; }); + // TODO check ob im core so bleiben soll + // if nested tabulator, restructure data + if (this.parentIdField && this.idField) { + this.tabulator.on("dataLoading", data => { + let toDelete = []; + + // loop through all data + for (let childIdx = 0; childIdx < data.length; childIdx++) + { + let child = data[childIdx]; + + // if it has parent id, it is a child + if (child[this.parentIdField]) + { + // append the child on the right place. If parent found, mark original sw child on 0 level for deleting + if (this.appendChild(data, child)) toDelete.push(childIdx); + } + } + + // delete the marked children from 0 level + for (let counter = 0; counter < toDelete.length; counter++) + { + // decrease index by counter as index of data array changes after every deletion + data.splice(toDelete[counter] - counter, 1); + } + }); + } if (this.tableOnly) { this.tabulator.on('tableBuilt', () => { const cols = this.tabulator.getColumns(); @@ -248,7 +289,7 @@ export const CoreFilterCmpt = { } }, _updateTabulator() { - this.tabulatorHasSelector = this.filteredColumns.filter(el => el.formatter == 'rowSelection').length; + this.tabulatorHasSelector = this.tabulatorOptions.selectable || this.filteredColumns.filter(el => el.formatter == 'rowSelection').length; this.tabulator.setColumns(this.filteredColumns); this.tabulator.setData(this.filteredData); }, @@ -411,6 +452,9 @@ export const CoreFilterCmpt = { apiFunctionParameters.filterUniqueId = FHC_JS_DATA_STORAGE_OBJECT.called_path + "/" + FHC_JS_DATA_STORAGE_OBJECT.called_method; apiFunctionParameters.filterType = this.filterType; + if (this.uniqueId) + apiFunctionParameters.filterUniqueId += '_' + this.uniqueId; + // Assign parameters to the FetchCmpt binded properties this.fetchCmptApiFunctionParams = apiFunctionParameters; // Assign data fetch callback to the FetchCmpt binded properties @@ -489,6 +533,36 @@ export const CoreFilterCmpt = { }, this.getFilter ); + }, + // TODO check ob im core so bleiben soll + // append child to it's parent + appendChild(data, child) { + // get parent id + let parentId = child[this.parentIdField]; + + // loop thorugh all data + for (let parentIdx = 0; parentIdx < data.length; parentIdx++) + { + let parent = data[parentIdx]; + + // if it's the parent + if (parent[this.idField] == parentId) + { + // create children array if not done yet + if (!parent._children) parent._children = []; + + // if child is not included in children array, append the child + if (!parent._children.includes(child)) parent._children.push(child); + + // parent found + return true; + } + // search children for parents + else if (parent._children) this.appendChild(parent._children, child); + } + + // parent not found + return false; } }, beforeCreate() { @@ -517,7 +591,7 @@ export const CoreFilterCmpt = {
-
@@ -526,7 +600,7 @@ export const CoreFilterCmpt = {
-
+
- Mit {{selectedData.length}} ausgewählten: - + Mit {{selectedData.length}} ausgewählten: + +
diff --git a/public/js/components/searchbar/prestudent.js b/public/js/components/searchbar/prestudent.js new file mode 100644 index 000000000..0f7429075 --- /dev/null +++ b/public/js/components/searchbar/prestudent.js @@ -0,0 +1,88 @@ +import action from "./action.js"; +import actions from "./actions.js"; + +export default { + props: [ "res", "actions" ], + components: { + action: action, + actions: actions + }, + emits: [ 'actionexecuted' ], + template: ` + + `, + methods: { + }, + computed: { + mailtourl: function() { + return 'mailto:' + this.res.email; + } + } +}; \ No newline at end of file diff --git a/public/js/components/searchbar/searchbar.js b/public/js/components/searchbar/searchbar.js index 80659d5bb..fbfa2926c 100755 --- a/public/js/components/searchbar/searchbar.js +++ b/public/js/components/searchbar/searchbar.js @@ -2,6 +2,8 @@ import person from "./person.js"; import raum from "./raum.js"; import employee from "./employee.js"; import organisationunit from "./organisationunit.js"; +import student from "./student.js"; +import prestudent from "./prestudent.js"; export default { props: [ "searchoptions", "searchfunction" ], @@ -24,7 +26,9 @@ export default { person: person, raum: raum, employee: employee, - organisationunit: organisationunit + organisationunit: organisationunit, + student: student, + prestudent: prestudent }, template: `
Es wurden keine Ergebnisse gefunden.