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..101d34863 --- /dev/null +++ b/application/controllers/api/frontend/v1/stv/Student.php @@ -0,0 +1,588 @@ +. + */ + +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() + { + // TODO(chris): permissions + parent::__construct([ + 'get' => ['admin:r', 'assistenz:r'], + 'save' => ['admin:w', 'assistenz:w'], + 'check' => ['admin:w', 'assistenz:w'], + 'add' => ['admin:w', 'assistenz:w'] + ]); + + // Load Libraries + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + + // 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 (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $student = $result->retval; + + 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()); + + #$fieldValidations = $this->getDataOrTerminateWithError($result); + if (isError($result)) + $this->terminateWithError(getError($result)); + $fieldvalidations = $result->retval; + + $this->form_validation->set_rules($fieldvalidations); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $result = $this->StudentModel->loadWhere(['prestudent_id' => $prestudent_id]); + + #$student = $this->getDataOrTerminateWithError($result); + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $student = $result->retval; + + $uid = $student ? current($student)->student_uid : null; + + $result = $this->PrestudentModel->loadWhere(['prestudent_id' => $prestudent_id]); + + #$person = $this->getDataOrTerminateWithError($result); + if (isError($result)) + $this->terminateWithError(getError($result)); + $person = $result->retval; + + $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); + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $definitions = $result->retval; + + 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 (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + if (count($update_person)) { + $result = $this->PersonModel->update( + $person_id, + $update_person + ); + #$this->getDataOrTerminateWithError($result); + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + + if (count($update_student)) { + $result = $this->StudentModel->update( + [$uid], + $update_student + ); + #$this->getDataOrTerminateWithError($result); + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + } + + $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', 'callback_isValidDate', [ + 'isValidDate' => $this->p->t('ui', 'error_invalid_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); + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $data = $result->retval; + + $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); + if (isError($result)) + return $result; + $person_id = getData($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 + ]); + if (isError($result)) + return $result; + if (hasData($result)) { + $address = current(getData($result)); + + $data['updateamum'] = date('c'); + $data['updatevon'] = getAuthUID(); + + $result = $this->AdresseModel->update($address->adresse_id, $data); + if (isError($result)) + return $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); + if (isError($result)) + return $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); + if (isError($result)) + return $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 + ]); + if (isError($result)) + return $result; + if (hasData($result)) { + $prestudent = current(getData($result)); + 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); + if (isError($result)) + return $result; + $prestudent_id = getData($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); + if (isError($result)) + return $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; + }*/ + + return success(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/public/js/components/Stv/Studentenverwaltung/Details/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Details.js index 0c988179f..7866f1c97 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Details.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Details.js @@ -1,14 +1,17 @@ import {CoreRESTClient} from '../../../../RESTClient.js'; -import FormForm from '../../../Form/Form.js'; +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: { - FormForm, + CoreForm, FormInput, - FormUploadImage + FormUploadImage, + CoreUdf }, inject: { showBpk: { @@ -39,6 +42,7 @@ export default { }, data() { return { + test: {udf_viaf: 'TEST'}, familienstaende: { "": "--keine Auswahl--", "g": "geschieden", @@ -49,6 +53,7 @@ export default { original: null, data: null, changed: {}, + udfChanges: false, studentIn: null, gebDatumIsValid: false, gebDatumIsInvalid: false @@ -90,25 +95,33 @@ export default { }, methods: { updateStudent(n) { - CoreRESTClient - .get('components/stv/Student/get/' + n.prestudent_id) - .then(result => result.data) + // TODO(chris): move to fhcapi.factory + this.$fhcApi + .get('api/frontend/v1/stv/student/get/' + n.prestudent_id) .then(result => { - this.data = result; + this.data = result.data; if (!this.data.familienstand) this.data.familienstand = ''; - this.original = {...this.data}; + this.original = {...(this.original || {}), ...this.data}; }) .catch(this.$fhcAlert.handleSystemError); }, save() { + if (!this.changedLength) + return; + + this.$refs.form.clearValidation(); this.$refs.form - .send(CoreRESTClient.post('components/stv/Student/save/' + this.modelValue.prestudent_id, this.changed)) + .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); + .catch(this.$fhcAlert.handleSystemError) + }, + udfsLoaded(udfs) { + this.original = {...(this.original || {}), ...udfs}; } }, created() { @@ -117,7 +130,7 @@ export default { //TODO(chris): Phrasen //TODO(chris): Geburtszeit? Anzahl der Kinder? template: ` - +
@@ -235,6 +248,7 @@ export default { :enable-time-picker="false" format="dd.MM.yyyy" preview-format="dd.MM.yyyy" + teleport > Loading... +
StudentIn @@ -441,5 +456,5 @@ export default { Loading...
-
` + ` }; \ 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 index 7bba76e51..acc9781de 100644 --- a/public/js/components/Stv/Studentenverwaltung/List/New.js +++ b/public/js/components/Stv/Studentenverwaltung/List/New.js @@ -106,18 +106,16 @@ export default { return; this.abortController.suggestions = new AbortController(); - CoreRESTClient - .post('components/stv/student/check', { + // 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 => CoreRESTClient.getData(result.data) || []) - .then(result => { - this.suggestions = result; - }) + .then(result => this.suggestions = result.data) .catch(error => { // NOTE(chris): repeat request if (error.code != "ERR_CANCELED") @@ -191,13 +189,14 @@ export default { if (data.studiensemester_kurzbz === undefined) data.studiensemester_kurzbz = this.studiensemesterKurzbz; + // TODO(chris): move to fhcapi.factory this.$refs.form - .send(CoreRESTClient.post('components/stv/student/add', data)) + .send('api/frontend/v1/stv/student/add', data) .then(result => { this.$fhcAlert.alertSuccess('Gespeichert'); this.$refs.modal.hide(); }) - .catch(console.error); + .catch(this.$fhcAlert.handleSystemError); } }, created() {