diff --git a/application/config/Events.php b/application/config/Events.php new file mode 100644 index 000000000..191a1eb98 --- /dev/null +++ b/application/config/Events.php @@ -0,0 +1,14 @@ + 'TEST', + 'component' => './Stv/Studentenverwaltung/Details/Notizen.js' + ]; + }); + */ diff --git a/application/config/db_crypt.php b/application/config/db_crypt.php new file mode 100644 index 000000000..b9360861b --- /dev/null +++ b/application/config/db_crypt.php @@ -0,0 +1,29 @@ +. + */ + +if (!defined('BASEPATH')) exit('No direct script access allowed'); + +// NOTE: if database encryption is _not_ used then leave this array empty! +$config['encryption_passwords'] = array( + // 'password name 1' => 'password 1' + // 'password name 2' => 'password 2' + // 'password name ...' => 'password ...' + // 'password name N' => 'password N' +); + diff --git a/application/config/navigation.php b/application/config/navigation.php index 56d142d08..3680930d0 100644 --- a/application/config/navigation.php +++ b/application/config/navigation.php @@ -31,6 +31,14 @@ $config['navigation_header'] = array( 'expand' => true, 'sort' => 20, 'requiredPermissions' => 'admin:w' + ), + 'bismeldestichtagsverwaltung' => array( + 'link' => site_url('codex/Bismeldestichtag'), + 'icon' => '', + 'description' => 'BIS-Meldestichtagsverwaltung', + 'expand' => true, + 'sort' => 30, + 'requiredPermissions' => 'admin:w' ) ) ), diff --git a/application/config/studierendenantrag.php b/application/config/studierendenantrag.php index 3f28e5d50..4e25aef28 100644 --- a/application/config/studierendenantrag.php +++ b/application/config/studierendenantrag.php @@ -126,6 +126,7 @@ $config['antrag_job_systemuser'] = ''; * @var array Array of tbl_status.status_kurzbz's */ $config['antrag_prestudentstatus_whitelist'] = ['Student', 'Diplomand']; +$config['antrag_prestudentstatus_whitelist_abmeldung'] = ['Student', 'Diplomand', 'Unterbrecher']; /** diff --git a/application/controllers/Test.php b/application/controllers/Test.php new file mode 100644 index 000000000..2a7aa4e4e --- /dev/null +++ b/application/controllers/Test.php @@ -0,0 +1,16 @@ + 'admin:r', + 'getStudiensemester' => 'admin:r', + 'getBismeldestichtage' => 'admin:r', + 'addBismeldestichtag' => 'admin:rw', + 'deleteBismeldestichtag' => 'admin:rw' + ) + ); + + // Load models + $this->load->model('codex/Bismeldestichtag_model', 'BismeldestichtagModel'); + $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + + // Loads phrases system + $this->loadPhrases( + array( + 'bismeldestichtag' + ) + ); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Public methods + + /** + * Everything has a beginning + */ + public function index() + { + $this->load->view('codex/bismeldestichtag.php'); + } + + public function getStudiensemester() + { + // load semester list + $semList = array(); + $this->StudiensemesterModel->addSelect('studiensemester_kurzbz'); + $this->StudiensemesterModel->addOrder('start', 'DESC'); + $semRes = $this->StudiensemesterModel->load(); + + if (hasData($semRes)) + { + $semList = getData($semRes); + } + + // load current semester + $currSem = null; + $semRes = $this->StudiensemesterModel->getAkt(); + + if (hasData($semRes)) + { + $currSem = getData($semRes)[0]->studiensemester_kurzbz; + } + + // output data + $this->outputJsonSuccess( + array('semList' => $semList, 'currSem' => $currSem) + ); + } + + public function getBismeldestichtage() + { + $this->BismeldestichtagModel->addSelect( + 'meldestichtag_id, meldestichtag, + tbl_bismeldestichtag.studiensemester_kurzbz, sem.start AS semester_start, + tbl_bismeldestichtag.insertamum, tbl_bismeldestichtag.insertvon, tbl_bismeldestichtag.updateamum, tbl_bismeldestichtag.updatevon' + ); + $this->BismeldestichtagModel->addJoin('public.tbl_studiensemester sem', 'studiensemester_kurzbz', 'LEFT'); + $this->BismeldestichtagModel->addOrder('semester_start'); + $this->BismeldestichtagModel->addOrder('meldestichtag', 'DESC'); + $this->BismeldestichtagModel->addOrder('meldestichtag_id', 'DESC'); + $this->outputJson($this->BismeldestichtagModel->load()); + } + + public function addBismeldestichtag() + { + // get request data + $request = $this->getPostJSON(); + + // check request data + if (!property_exists($request, 'meldestichtag') || isEmptyString($request->meldestichtag)) + $this->terminateWithJsonError('Error occured: Meldestichtag missing'); + if (!property_exists($request, 'studiensemester_kurzbz') || isEmptyString($request->studiensemester_kurzbz)) + $this->terminateWithJsonError('Error occured: Studiensemester missing'); + + $meldestichtag = $request->meldestichtag; + $studiensemester_kurzbz = $request->studiensemester_kurzbz; + + // check if Bismeldestichtag already exists + $this->BismeldestichtagModel->addSelect('1'); + $bismeldestichtagRes = $this->BismeldestichtagModel->loadWhere( + array('meldestichtag' => $meldestichtag, 'studiensemester_kurzbz' => $studiensemester_kurzbz) + ); + + // return success if already exists + if (hasData($bismeldestichtagRes)) + $this->outputJsonSuccess('Bismeldestichtag already exists'); + else + { + // insert new if Stichtag does not exist + $this->outputJson($this->BismeldestichtagModel->insert( + array( + 'meldestichtag' => $request->meldestichtag, + 'studiensemester_kurzbz' => $request->studiensemester_kurzbz, + 'insertvon' => getAuthUID() + ) + )); + } + } + + public function deleteBismeldestichtag() + { + // get request data + $request = $this->getPostJSON(); + + // check request data + if (!property_exists($request, 'meldestichtag_id')) + $this->terminateWithJsonError('Error occured: Meldestichtag Id missing'); + + $meldestichtag_id = $request->meldestichtag_id; + + // deletetion + $this->outputJson($this->BismeldestichtagModel->delete($meldestichtag_id)); + } +} diff --git a/application/controllers/components/Antrag/Leitung.php b/application/controllers/components/Antrag/Leitung.php index f6b184351..8d333d5b8 100644 --- a/application/controllers/components/Antrag/Leitung.php +++ b/application/controllers/components/Antrag/Leitung.php @@ -33,54 +33,28 @@ class Leitung extends FHC_Controller public function getActiveStgs() { - $studiengaenge = $this->permissionlib->getSTG_isEntitledFor('student/antragfreigabe'); - $stgsNeuanlage = $this->permissionlib->getSTG_isEntitledFor('student/studierendenantrag'); - - $stgs = []; - - if ($studiengaenge) { - $result = $this->StudierendenantragModel->loadForStudiengaenge($studiengaenge); - - if (isError($result)) - return $this->outputJson($result); - $antraege = getData($result) ?: []; - - foreach ($antraege as $antrag) { - if (!isset($stgs[$antrag->studiengang_kz])) { - $stgs[$antrag->studiengang_kz] = new stdClass(); - $stgs[$antrag->studiengang_kz]->bezeichnung = $antrag->bezeichnung; - $stgs[$antrag->studiengang_kz]->orgform = $antrag->orgform; - $stgs[$antrag->studiengang_kz]->studiengang_kz = $antrag->studiengang_kz; - } - } + $studiengaenge = $this->permissionlib->getSTG_isEntitledFor('student/antragfreigabe') ?: []; + $studiengaenge = array_merge($studiengaenge, $this->permissionlib->getSTG_isEntitledFor('student/studierendenantrag') ?: []); + + $result = $this->StudierendenantragModel->loadStgsWithAntraege($studiengaenge); + if (isError($result)) { + $this->output->set_status_header(REST_Controller::HTTP_INTERNAL_SERVER_ERROR); } - - if ($stgsNeuanlage) { - $result = $this->StudierendenantragModel->loadForStudiengaenge($stgsNeuanlage); - - if (isError($result)) - return $this->outputJson($result); - $antraege = getData($result) ?: []; - - foreach ($antraege as $antrag) { - if (!isset($stgs[$antrag->studiengang_kz])) { - $stgs[$antrag->studiengang_kz] = new stdClass(); - $stgs[$antrag->studiengang_kz]->bezeichnung = $antrag->bezeichnung; - $stgs[$antrag->studiengang_kz]->orgform = $antrag->orgform; - $stgs[$antrag->studiengang_kz]->studiengang_kz = $antrag->studiengang_kz; - } - } - } - - $this->outputJsonSuccess($stgs); + $this->outputJson($result); } - public function getAntraege($studiengang = null) + public function getAntraege($studiengang = null, $extra = null) { + if ($studiengang && $studiengang == 'todo') { + $studiengang = $extra; + $extra = true; + } else { + $extra = false; + } - if($studiengang) + if ($studiengang) { $studiengaenge = [$studiengang]; - else { + } else { $studiengaenge =$this->permissionlib->getSTG_isEntitledFor('student/antragfreigabe'); if(!is_array($studiengaenge)) $studiengaenge = []; @@ -96,7 +70,9 @@ class Leitung extends FHC_Controller $antraege = []; if ($studiengaenge) { - $result = $this->StudierendenantragModel->loadForStudiengaenge($studiengaenge); + $result = $extra + ? $this->StudierendenantragModel->loadActiveForStudiengaenge($studiengaenge) + : $this->StudierendenantragModel->loadForStudiengaenge($studiengaenge); if (isError($result)) { $this->output->set_status_header(500); return $this->outputJson('Internal Server Error'); diff --git a/application/controllers/components/Antrag/Wiederholung.php b/application/controllers/components/Antrag/Wiederholung.php index 515771224..418d05f45 100644 --- a/application/controllers/components/Antrag/Wiederholung.php +++ b/application/controllers/components/Antrag/Wiederholung.php @@ -76,10 +76,9 @@ class Wiederholung extends FHC_Controller if (isError($result)) { return $this->outputJsonError(getError($result)); } - $data = getData($result); - $result = $this->antraglib->getFailedExamForPrestudent($prestudent_id); + $result = $this->antraglib->getFailedExamForPrestudent($prestudent_id, $data->datum, $data->studiensemester_kurzbz); // NOTE(chris): error handling for this function should already happenden in antraglib->getPrestudentWiederholungsBerechtigt() $pruefungsdata = current(getData($result)); diff --git a/application/controllers/components/SearchBar.php b/application/controllers/components/SearchBar.php index dd3c22690..d19113177 100644 --- a/application/controllers/components/SearchBar.php +++ b/application/controllers/components/SearchBar.php @@ -17,11 +17,17 @@ class SearchBar extends FHC_Controller { parent::__construct(); - // Loads the AuthLib and starts the authentication - $this->load->library('AuthLib'); + // Loads the AuthLib _without_ starting the authentication + // NOTE: + // - A user must be authenticated via another controller to access this one + // - It is loaded to be able to call the isLogged function later + $this->load->library('AuthLib', array(false)); // Load the library SearchBarLib $this->load->library('SearchBarLib'); + + // Checks if the user is authenticated, otherwise returns an error code in JSON format + if (!isLogged()) $this->terminateWithJsonError(SearchBarLib::ERROR_NOT_AUTH); } //------------------------------------------------------------------------------------------------------------------ diff --git a/application/controllers/jobs/AntragJob.php b/application/controllers/jobs/AntragJob.php index 2e72041ff..131cfdced 100644 --- a/application/controllers/jobs/AntragJob.php +++ b/application/controllers/jobs/AntragJob.php @@ -286,7 +286,6 @@ class AntragJob extends JOB_Controller $result = $this->PruefungModel->getAllPrestudentsWhereCommitteeExamFailed( [ - null, Studierendenantragstatus_model::STATUS_REQUESTSENT_1, Studierendenantragstatus_model::STATUS_REQUESTSENT_2 ], @@ -346,6 +345,7 @@ class AntragJob extends JOB_Controller $dateDeadline = new DateTime(); $dateDeadline->sub(DateInterval::createFromDateString($modifier_deadline)); + $this->StudierendenantragModel->addSelect('tbl_studierendenantrag.studierendenantrag_id'); $this->StudierendenantragModel->addSelect('prestudent_id'); $this->StudierendenantragModel->addSelect('studiensemester_kurzbz'); $this->StudierendenantragModel->addSelect('s.insertamum'); @@ -370,50 +370,62 @@ class AntragJob extends JOB_Controller foreach ($antraege as $antrag) { - $result = $this->prestudentlib->setAbbrecher( - $antrag->prestudent_id, - $antrag->studiensemester_kurzbz, - 'AntragJob', - 'abbrecherStgl', - $antrag->insertamum, - null, - $antrag->insertvon ?: $insertvon - ); + $result = $this->StudierendenantragstatusModel->insert([ + 'studierendenantrag_id' => $antrag->studierendenantrag_id, + 'studierendenantrag_statustyp_kurzbz' => Studierendenantragstatus_model::STATUS_DEREGISTERED, + 'insertvon' => 'AntragJob' + ]); if (isError($result)) $this->logError(getError($result)); - else - { - $count++; - $result = $this->PrestudentModel->load($antrag->prestudent_id); - if(!hasData($result)) { - $this->logWarning('No Prestudent found'); - continue; - } - $prestudent = current(getData($result)); - $result = $this->StudiengangModel->load($prestudent->studiengang_kz); - if(!hasData($result)) { - $this->logWarning('No Studiengang found'); - continue; - } - $studiengang = current(getData($result)); - $result = $this->PersonModel->loadPrestudent($antrag->prestudent_id); - if(!hasData($result)) - { - $this->logWarning('No Person found'); - continue; - } - $person = current(getData($result)); - $email = $studiengang->email; - $dataMail = array( - 'prestudent' => $antrag->prestudent_id, - 'studiensemester' => $antrag->studiensemester_kurzbz, - 'name' => trim($person->vorname . ' '. $person->nachname), - ); + else { + $deregisterStatus = getData($result); - if(!sendSanchoMail('Sancho_Mail_Antrag_A_Assist', $dataMail, $email, 'Einspruchsfrist abgelaufen')) - { - $this->logWarning("Failed to send Notification to " . $email); + $result = $this->prestudentlib->setAbbrecher( + $antrag->prestudent_id, + $antrag->studiensemester_kurzbz, + 'AntragJob', + 'abbrecherStgl', + $antrag->insertamum, + null, + $antrag->insertvon ?: $insertvon + ); + if (isError($result)) { + $this->StudierendenantragstatusModel->delete($deregisterStatus); + $this->logError(getError($result)); + } else { + $count++; + $result = $this->PrestudentModel->load($antrag->prestudent_id); + if(!hasData($result)) { + $this->logWarning('No Prestudent found'); + continue; + } + $prestudent = current(getData($result)); + $result = $this->StudiengangModel->load($prestudent->studiengang_kz); + if(!hasData($result)) { + $this->logWarning('No Studiengang found'); + continue; + } + $studiengang = current(getData($result)); + $result = $this->PersonModel->loadPrestudent($antrag->prestudent_id); + if(!hasData($result)) + { + $this->logWarning('No Person found'); + continue; + } + $person = current(getData($result)); + $email = $studiengang->email; + $dataMail = array( + 'prestudent' => $antrag->prestudent_id, + 'studiensemester' => $antrag->studiensemester_kurzbz, + 'name' => trim($person->vorname . ' '. $person->nachname), + ); + + if(!sendSanchoMail('Sancho_Mail_Antrag_A_Assist', $dataMail, $email, 'Einspruchsfrist abgelaufen')) + { + $this->logWarning("Failed to send Notification to " . $email); + } } + } } $this->logInfo($count . "/" . count($antraege) . " Students set to Abbrecher"); diff --git a/application/controllers/jobs/ReihungstestJob.php b/application/controllers/jobs/ReihungstestJob.php index 431ac5b04..c31ed54c9 100644 --- a/application/controllers/jobs/ReihungstestJob.php +++ b/application/controllers/jobs/ReihungstestJob.php @@ -467,7 +467,7 @@ class ReihungstestJob extends JOB_Controller $this->PrestudentstatusModel->addJoin('public.tbl_person', 'person_id'); $yesterdays_applicants_arr = $this->PrestudentstatusModel->loadWhere(' - status_kurzbz = \'Interessent\' AND + status_kurzbz IN (\'Interessent\', \'Bewerber\') AND typ = \'b\' AND bestaetigtam = current_date - 1 '); @@ -730,33 +730,27 @@ class ReihungstestJob extends JOB_Controller tbl_reihungstest.reihungstest_id, tbl_studienplan.studienplan_id, tbl_reihungstest.studiensemester_kurzbz, - tbl_studienordnung.studiengang_kz + tbl_studienordnung.studiengang_kz, + tbl_studienplan.orgform_kurzbz FROM public.tbl_reihungstest - JOIN public.tbl_rt_studienplan ON(tbl_rt_studienplan.reihungstest_id=tbl_reihungstest.reihungstest_id) - JOIN lehre.tbl_studienplan USING(studienplan_id) - JOIN lehre.tbl_studienordnung USING(studienordnung_id) + JOIN public.tbl_rt_studienplan ON(tbl_rt_studienplan.reihungstest_id=tbl_reihungstest.reihungstest_id) + JOIN lehre.tbl_studienplan USING(studienplan_id) + JOIN lehre.tbl_studienordnung USING(studienordnung_id) WHERE - NOT EXISTS( - SELECT 1 FROM lehre.tbl_studienplan_semester - WHERE studienplan_id=tbl_rt_studienplan.studienplan_id - AND tbl_studienplan_semester.studiensemester_kurzbz=tbl_reihungstest.studiensemester_kurzbz + EXISTS ( + SELECT studienplan_id + FROM lehre.tbl_studienordnung sordnung + JOIN lehre.tbl_studienplan USING (studienordnung_id) + JOIN lehre.tbl_studienplan_semester USING (studienplan_id) + WHERE sordnung.studiengang_kz = tbl_studienordnung.studiengang_kz + AND tbl_studienplan_semester.studiensemester_kurzbz = tbl_reihungstest.studiensemester_kurzbz + AND tbl_studienplan.studienplan_id NOT IN + ( + SELECT studienplan_id FROM tbl_rt_studienplan WHERE reihungstest_id = tbl_reihungstest.reihungstest_id + ) ) - AND tbl_reihungstest.datum >= now() - AND NOT EXISTS( - SELECT - 1 - FROM - public.tbl_rt_studienplan rtstp - JOIN lehre.tbl_studienplan stp USING(studienplan_id) - JOIN lehre.tbl_studienordnung sto USING(studienordnung_id) - JOIN lehre.tbl_studienplan_semester stpsem USING(studienplan_id) - WHERE - sto.studiengang_kz=tbl_studienordnung.studiengang_kz - AND rtstp.reihungstest_id=tbl_reihungstest.reihungstest_id - AND stpsem.studiensemester_kurzbz=tbl_reihungstest.studiensemester_kurzbz - ) - "; + AND tbl_reihungstest.datum >= now()"; $db = new DB_Model(); $result_rt = $db->execReadOnlyQuery($qry); @@ -766,7 +760,9 @@ class ReihungstestJob extends JOB_Controller // find an active studyplan for the same degree program with is valid in this semester $result_stpl = $this->StudienplanModel->getStudienplaeneBySemester( $row_rt->studiengang_kz, - $row_rt->studiensemester_kurzbz + $row_rt->studiensemester_kurzbz, + null, + $row_rt->orgform_kurzbz ); if (hasData($result_stpl)) { diff --git a/application/controllers/jobs/vertragsbestandteil_test/VertragsbestandteilTest.php b/application/controllers/jobs/vertragsbestandteil_test/VertragsbestandteilTest.php new file mode 100644 index 000000000..d22ddb85f --- /dev/null +++ b/application/controllers/jobs/vertragsbestandteil_test/VertragsbestandteilTest.php @@ -0,0 +1,114 @@ +load->library('vertragsbestandteil/VertragsbestandteilLib', + null, 'VertragsbestandteilLib'); + $this->load->library('vertragsbestandteil/GehaltsbestandteilLib', + null, 'GehaltsbestandteilLib'); + } + + public function testFetch() + { + $dienstverhaeltnis_id = 1; + $stichtag = null; + + foreach($this->VertragsbestandteilLib->fetchVertragsbestandteile( + $dienstverhaeltnis_id, $stichtag) as $vertragsbestandteil) + { + //print_r($vertragsbestandteil); + echo $vertragsbestandteil . "\n"; + } + } + + public function testUpdate() + { + $now = new DateTime(); + + $data = new stdClass(); + $data->vertragsbestandteil_id = 32; + $data->von = '2022-12-05'; + + $data->wochenstunden = 45.0; + $data->vertragsbestandteiltyp_kurzbz = VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_STUNDEN; + + $vb = VertragsbestandteilFactory::getVertragsbestandteil($data); + + try + { + $this->VertragsbestandteilLib->storeVertragsbestandteil($vb); + echo "Update successful.\n"; + } + catch( Exception $ex ) + { + echo "Update failed.\n"; + } + } + + + public function testInsert() + { + $now = new DateTime(); + + $data = new stdClass(); + $data->dienstverhaeltnis_id = 1; + $data->von = '2022-12-01'; + $data->insertamum = $now->format(DateTime::ATOM); + $data->insertvon = 'ma0080'; + $data->vertragsbestandteiltyp_kurzbz = VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_FUNKTION; + + $data->benutzerfunktion_id = 112667; + $data->anmerkung = 'test funkton'; + $data->kuendigungsrelevant = false; + + $vb = VertragsbestandteilFactory::getVertragsbestandteil($data); + + try + { + $this->VertragsbestandteilLib->storeVertragsbestandteil($vb); + echo "Insert successful.\n"; + } + catch( Exception $ex ) + { + echo "Insert failed.\n"; + } + } + + public function testGehaltsbestandteilInsert() + { + $data = new stdClass(); + $data->gehaltsbestandteil_id = 2; + /* + $data->dienstverhaeltnis_id = 39; + $data->vertragsbestandteil_id = 123; + $data->gehaltstyp_kurzbz = 'zulage'; + $data->von = '2023-04-01'; + $data->bis = '2023-08-31'; + $data->anmerkung = 'test anmerkung'; + $data->grundbetrag = 100; + $data->betrag_valorisiert = 100; + $data->valorisierung = true; + */ + $data->auszahlungen = 12; + + $gb = new \vertragsbestandteil\Gehaltsbestandteil(); + $gb->hydrateByStdClass($data); + + print_r($gb->toStdClass()); + + $this->GehaltsbestandteilLib->storeGehaltsbestandteil($gb); + } +} diff --git a/application/controllers/lehre/anrechnung/RequestAnrechnung.php b/application/controllers/lehre/anrechnung/RequestAnrechnung.php index 1922bacda..3cba756cf 100644 --- a/application/controllers/lehre/anrechnung/RequestAnrechnung.php +++ b/application/controllers/lehre/anrechnung/RequestAnrechnung.php @@ -152,10 +152,10 @@ class requestAnrechnung extends Auth_Controller return $this->outputJsonError($this->p->t('anrechnung', 'antragBereitsGestellt')); } - // Exit if application is not for actual studysemester - if (!self::_applicationIsForActualSS($studiensemester_kurzbz)) + // Exit if application is a past ( < actual ) studysemester + if (self::_applicationIsPastSS($studiensemester_kurzbz)) { - return $this->outputJsonError($this->p->t('anrechnung', 'antragNurImAktSS')); + return $this->outputJsonError($this->p->t('anrechnung', 'antragNichtFuerVerganganeSS')); } // Upload document @@ -312,18 +312,21 @@ class requestAnrechnung extends Auth_Controller } /** - * Check if applications' study semester is actual study semester. + * Check if applications' study semester is < actual study semester. * * @param $studiensemester_kurzbz * @return bool */ - private function _applicationIsForActualSS($studiensemester_kurzbz) + private function _applicationIsPastSS($studiensemester_kurzbz) { $this->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); $result = $this->StudiensemesterModel->getNearest(); - $actual_ss = getData($result)[0]->studiensemester_kurzbz; + $actual_ss = getData($result)[0]; - return $studiensemester_kurzbz == $actual_ss; + $result = $this->StudiensemesterModel->load($studiensemester_kurzbz); + $anrechnung_ss = getData($result)[0]; + + return $anrechnung_ss->ende < $actual_ss->start; } private function _LVhasBlockingGrades($studiensemester_kurzbz, $lehrveranstaltung_id) diff --git a/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php b/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php index 6ac2da887..4abb1c400 100644 --- a/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php +++ b/application/controllers/lehre/lehrauftrag/LehrauftragAkzeptieren.php @@ -35,6 +35,7 @@ class LehrauftragAkzeptieren extends Auth_Controller $this->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); $this->load->model('codex/Bisverwendung_model', 'BisverwendungModel'); $this->load->model('person/Benutzer_model', 'BenutzerModel'); + $this->load->model('vertragsbestandteil/Dienstverhaeltnis_model', 'DienstverhaeltnisModel'); // Load libraries $this->load->library('WidgetLib'); @@ -94,9 +95,9 @@ class LehrauftragAkzeptieren extends Auth_Controller 'lektor' => true, 'aktiv' => true )); - + $is_external_lector = hasData($result) ? true : false; - + $view_data = array( 'studiensemester_selected' => $studiensemester_kurzbz, 'is_external_lector' => $is_external_lector @@ -207,15 +208,41 @@ class LehrauftragAkzeptieren extends Auth_Controller */ public function checkInkludierteLehre() { - $result = $this->BisverwendungModel->getLast($this->_uid, false); - - if (hasData($result)) + if(defined('DIENSTVERHAELTNIS_SUPPORT') && DIENSTVERHAELTNIS_SUPPORT) { - $this->outputJsonSuccess(!is_null($result->retval[0]->inkludierte_lehre) && $result->retval[0]->inkludierte_lehre != 0); + // Bei neuer Vertragsstruktur wird nur anhand des echten DVs entschieden ob eine Anzeige + // des Stundensatzes erfolgt oder nicht. + $result = $this->DienstverhaeltnisModel->getDVByPersonUID($this->_uid, null, date('Y-m-d')); + + if (hasData($result)) + { + $data = getData($result); + foreach($data as $row) + { + if($row->vertragsart_kurzbz == 'echterdv') + $this->outputJsonSuccess(true); + else + $this->outputJsonSuccess(false); + } + } + else + { + $this->outputJsonError(getError($result)); + } } else { - $this->outputJsonError(getError($result)); + // DEPRECATED + $result = $this->BisverwendungModel->getLast($this->_uid, false); + + if (hasData($result)) + { + $this->outputJsonSuccess(!is_null($result->retval[0]->inkludierte_lehre) && $result->retval[0]->inkludierte_lehre != 0); + } + else + { + $this->outputJsonError(getError($result)); + } } } diff --git a/application/controllers/public/js/Components.php b/application/controllers/public/js/Components.php new file mode 100644 index 000000000..830e7ea65 --- /dev/null +++ b/application/controllers/public/js/Components.php @@ -0,0 +1,43 @@ +output->set_content_type('text/javascript'); + $this->output->set_output($contents); + } +} diff --git a/application/controllers/system/MigrateContract.php b/application/controllers/system/MigrateContract.php new file mode 100644 index 000000000..99b894473 --- /dev/null +++ b/application/controllers/system/MigrateContract.php @@ -0,0 +1,680 @@ +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 + ); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Public methods + + /** + * Everything has a beginning + */ + public function index($user = null) + { + if (!is_null($user)) + { + $contracts = $this->_transformUser($user); + + /* + Format: + $contracts['dv'][]['vbs'][] + */ + //$this->outputJson($contracts); + var_dump($contracts); + $this->_saveJSON($contracts); + } + else + { + $qry = "SELECT distinct mitarbeiter_uid FROM bis.tbl_bisverwendung"; + $db = new DB_Model(); + + $resultUser = $db->execReadOnlyQuery($qry); + if (hasData($resultUser)) + { + $users = getData($resultUser); + foreach($users as $user) + { + $contracts = $this->_transformUser($user->mitarbeiter_uid); + $this->_saveJSON($contracts); + } + } + + } + } + + private function _saveJSON($contracts) + { + $this->load->model('vertragsbestandteil/Dienstverhaeltnis_model','DienstverhaeltnisModel'); + $this->load->model('vertragsbestandteil/Vertragsbestandteil_model','VertragsbestandteilModel'); + $this->load->model('vertragsbestandteil/VertragsbestandteilStunden_model','VertragsbestandteilStundenModel'); + $this->load->model('vertragsbestandteil/VertragsbestandteilZeitaufzeichnung_model','VertragsbestandteilZeitaufzeichnungModel'); + $this->load->model('vertragsbestandteil/VertragsbestandteilFreitext_model','VertragsbestandteilFreitextModel'); + $this->load->model('vertragsbestandteil/VertragsbestandteilFunktion_model','VertragsbestandteilFunktionModel'); + $this->load->model('vertragsbestandteil/VertragsbestandteilKarenz_model','VertragsbestandteilKarenzModel'); + + $failed = false; + $this->db->trans_begin(); + + foreach($contracts['dv'] as $row_dv) + { + // Dienstvertrag erstellen + $resultDV = $this->DienstverhaeltnisModel->insert( + array( + 'mitarbeiter_uid' => $row_dv['mitarbeiter_uid'], + 'vertragsart_kurzbz' => $row_dv['vertragsart_kurzbz'], + 'oe_kurzbz' => $row_dv['oe_kurzbz'], + 'von' => $row_dv['von'], + 'bis' => $row_dv['bis'], + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => 'MigrateContract' + ) + ); + + if (isSuccess($resultDV) && hasData($resultDV)) + { + $dv_id = getData($resultDV); + + // Vertragsbetandteile erstellen + foreach($row_dv['vbs'] as $row_vbs) + { + $resultVBS = $this->VertragsbestandteilModel->insert( + array( + 'dienstverhaeltnis_id' => $dv_id, + 'vertragsbestandteiltyp_kurzbz' => $row_vbs['vertragsbestandteiltyp_kurzbz'], + 'von' => $row_vbs['von'], + 'bis' => $row_vbs['bis'], + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => 'MigrateContract' + ) + ); + + if (isSuccess($resultVBS) && hasData($resultVBS)) + { + $vbs_id = getData($resultVBS); + echo 'VBS:'.$vbs_id; + + switch($row_vbs['vertragsbestandteiltyp_kurzbz']) + { + case 'stunden': + $resultVBS = $this->_insertVBSStunden($vbs_id, $row_vbs); + break; + case 'zeitaufzeichnung': + $resultVBS = $this->_insertVBSZeitaufzeichnung($vbs_id, $row_vbs); + break; + case 'funktion': + $resultVBS = $this->_insertVBSFunktion($vbs_id, $row_vbs); + break; + case 'freitext': + $resultVBS = $this->_insertVBSFreitext($vbs_id, $row_vbs); + break; + case 'karenz': + $resultVBS = $this->_insertVBSKarenz($vbs_id, $row_vbs); + break; + } + + if (isError($resultVBS)) + { + echo "FAILED:".getError($resultVBS); + $failed = true; + } + } + else + { + $failed = true; + } + } + } + else + { + $failed = true; + } + } + + if(!$failed) + { + $this->db->trans_commit(); + } + else + { + echo "ROLLBACK"; + $this->db->trans_rollback(); + } + } + + private function _insertVBSKarenz($vbs_id, $row_vbs) + { + return $this->VertragsbestandteilKarenzModel->insert( + array( + 'vertragsbestandteil_id' => $vbs_id, + 'karenztyp_kurzbz' => $row_vbs['karenztyp_kurzbz'] + ) + ); + } + + private function _insertVBSFreitext($vbs_id, $row_vbs) + { + return $this->VertragsbestandteilFreitextModel->insert( + array( + 'vertragsbestandteil_id' => $vbs_id, + 'freitexttyp_kurzbz' => $row_vbs['freitexttyp_kurzbz'], + 'titel' => $row_vbs['titel'], + 'anmerkung' => $row_vbs['anmerkung'] + ) + ); + } + + private function _insertVBSFunktion($vbs_id, $row_vbs) + { + return $this->VertragsbestandteilFunktionModel->insert( + array( + 'vertragsbestandteil_id' => $vbs_id, + 'benutzerfunktion_id' => $row_vbs['benutzerfunktion_id'] + ) + ); + } + + private function _insertVBSZeitaufzeichnung($vbs_id, $row_vbs) + { + return $this->VertragsbestandteilZeitaufzeichnungModel->insert( + array( + 'vertragsbestandteil_id' => $vbs_id, + 'zeitaufzeichnung' => $row_vbs['zeitaufzeichnung'], + 'azgrelevant' => $row_vbs['azgrelevant'], + 'homeoffice' => $row_vbs['homeoffice'] + ) + ); + } + + private function _insertVBSStunden($vbs_id, $row_vbs) + { + return $this->VertragsbestandteilStundenModel->insert( + array( + 'vertragsbestandteil_id' => $vbs_id, + 'wochenstunden' => $row_vbs['wochenstunden'], + 'teilzeittyp_kurzbz' => $row_vbs['teilzeittyp_kurzbz'] + ) + ); + } + + /** + * Ermittelt die neue Vertragsstruktur fuer einen User + */ + private function _transformUser($user) + { + $contracts = array(); + $this->BisVerwendungModel->addOrder('beginn'); + $result_verwendung = $this->BisVerwendungModel->loadWhere(array("mitarbeiter_uid" => $user)); + + if (isError($result_verwendung)) + die("Failed to load Verwendung"); + + if (hasData($result_verwendung)) + { + $verwendung = getData($result_verwendung); + + foreach ($verwendung as $row_verwendung) + { + $dv = $this->_getOrCreateDV($contracts, $row_verwendung); + + // Ende des DV aktualisieren + if ($contracts['dv'][$dv]['bis'] < $row_verwendung->ende || $row_verwendung->ende == '') + $contracts['dv'][$dv]['bis'] = $row_verwendung->ende; + + // Stundenbestandteil pruefen + $this->_addVertragsbestandteilStunden($contracts, $dv, $row_verwendung); + + // Befristung + $this->_addVertragsbestandteilFreitextBefristung($contracts, $dv, $row_verwendung); + + // All-In + $this->_addVertragsbestandteilFreitextAllIn($contracts, $dv, $row_verwendung); + + // Zeitaufzeichnung + $this->_addVertragsbestandteilZeitaufzeichnung($contracts, $dv, $row_verwendung); + + // Karenz + $this->_addVertragsbestandteilKarenz($contracts, $dv, $row_verwendung); + + // Inkludierte Lehre + // Kuendigungsfrist + // Urlaubsanspruch + } + + // Funktion + $this->_addVertragsbestandteilFunktion($contracts, $user); + + } + + return $contracts; + } + + /** + * Fuegt Karenzierungseintraege zu bestehenden Dienstverhaeltnissen hinzu + */ + private function _addVertragsbestandteilKarenz(&$contracts, $dv, $row_verwendung) + { + if ($row_verwendung->beschausmasscode == 5) + { + $dtstart = new DateTime($row_verwendung->beginn); + $dtende = new DateTime($row_verwendung->ende); + $interval = $dtende->diff($dtstart); + $dauer = $interval->format('%a'); + + // TODO: klären ob das so machbar ist + if ($dauer < 65) + $karenztyp = 'papamonat'; + elseif ($dauer < 120) + $karenztyp = 'bildungskarenz'; + else + $karenztyp = 'elternkarenz'; + + // VBS anlegen und Funktion zuweisen + $newVBSIndex = $this->_getNewVBSIndex($contracts, $dv); + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['vertragsbestandteiltyp_kurzbz'] = 'karenz'; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['von'] = $row_verwendung->beginn; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['bis'] = $row_verwendung->ende; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['karenztyp_kurzbz'] = $karenztyp; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['geplanter_geburtstermin'] = null; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['tatsaechlicher_geburtstermin'] = null; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['hint'] = 'Dauer:'.$dauer; + } + } + + /** + * Holt die Funktionen die Vertragsrelevant sind und verknüpft diese + */ + private function _addVertragsbestandteilFunktion(&$contracts, $user) + { + // Alle Funktionen holen die Vertragsrelevant sind + $this->BenutzerfunktionModel->addOrder('datum_von'); + $this->BenutzerfunktionModel->addJoin('public.tbl_funktion','funktion_kurzbz'); + $resultFunktionen = $this->BenutzerfunktionModel->loadWhere(array('uid' => $user, 'vertragsrelevant' => true)); + + if (isSuccess($resultFunktionen) && hasData($resultFunktionen)) + { + $funktionen = getData($resultFunktionen); + + foreach ($funktionen as $row_funktion) + { + $funktion_added = 0; + $dv = ''; + + // Passendes DV suchen + foreach ($contracts['dv'] as $key_dv => $row_contract) + { + // Eine Funktion kann zu mehreren DV zugeordnet sein + // es werden daher alle durchsucht ob es reinfaellt und ggf mehrfach zugeordnet + if ((isset($row_funktion->datum_von) && $row_funktion->datum_von >= $row_contract['von']) + && ($row_contract['bis'] == '' || $row_contract['bis'] >= $row_funktion->datum_von) + && ( + ( + isset($row_funktion->datum_bis) && isset($row_contract['bis']) + && $row_funktion->datum_bis <= $row_contract['bis'] + ) + || $row_funktion->datum_bis == '' + || (isset($row_funktion->datum_bis) && !isset($row_contract['bis'])) + ) + ) + { + + $dv = $key_dv; + + // Startdatum und Endedatum ermitteln wenn die Funktion ueber das DV hinausgeht + // Wenn die Dauer laenger ist, wird beim Beginn/Ende des DV abgegrenzt + $dtstart_fkt = new DateTime($row_funktion->datum_von); + $dtstart_dv = new DateTime($row_contract['von']); + if ($dtstart_fkt < $dtstart_dv) + $startdatum = $row_contract['von']; + else + $startdatum = $row_funktion->datum_von; + + $dtende_fkt = new DateTime($row_funktion->datum_bis); + $dtende_dv = new DateTime($row_contract['bis']); + if ($dtende_fkt < $dtende_dv) + $endedatum = $row_funktion->datum_bis; + else + $endedatum = $row_contract['bis']; + + // VBS anlegen und Funktion zuweisen + $newVBSIndex = $this->_getNewVBSIndex($contracts, $dv); + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['vertragsbestandteiltyp_kurzbz'] = 'funktion'; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['von'] = $startdatum; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['bis'] = $endedatum; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['benutzerfunktion_id'] = $row_funktion->benutzerfunktion_id; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['hint'] = $row_funktion->funktion_kurzbz.' '.$row_funktion->datum_von.' - '.$row_funktion->datum_bis; + $funktion_added++; + } + } + if ($funktion_added == 0) + { + echo "\nFunktion nicht zugeordnet: ".$row_funktion->funktion_kurzbz.' '.$row_funktion->datum_von.' - '.$row_funktion->datum_bis; + } + } + } + } + + /** + * Prueft ob schon ein Vertragsbestandteil fuer Zeitaufzeichnung vorhanden ist das in den Zeitraum passt + * bzw direkt anschließt. Wenn es direkt anschließend ist und die Art gleich sind wird die Laufzeit verlaengert + * Ansonsten wird ein neuer VBS angelegt + */ + private function _addVertragsbestandteilZeitaufzeichnung(&$contracts, $dv, $row_verwendung) + { + if (isset($contracts['dv'][$dv]['vbs'])) + { + foreach ($contracts['dv'][$dv]['vbs'] as $index_vbs=>$row_vbs) + { + if ($row_vbs['vertragsbestandteiltyp_kurzbz'] == 'zeitaufzeichnung') + { + if ($this->_isVBSAngrenzend($row_verwendung, $row_vbs) + && $row_vbs['zeitaufzeichnung'] == $row_verwendung->zeitaufzeichnungspflichtig + && $row_vbs['azgrelevant'] == $row_verwendung->azgrelevant + && $row_vbs['homeoffice'] == $row_verwendung->homeoffice + ) + { + // Zeitaufzeichnungsarten bleiben gleich - Ende des VBS verlaengern + $contracts['dv'][$dv]['vbs'][$index_vbs]['bis'] = $row_verwendung->ende; + return true; + } + } + } + } + + // kein passender VBS gefunden - neuen anlegen + $newVBSIndex = $this->_getNewVBSIndex($contracts, $dv); + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['vertragsbestandteiltyp_kurzbz'] = 'zeitaufzeichnung'; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['von'] = $row_verwendung->beginn; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['bis'] = $row_verwendung->ende; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['zeitaufzeichnung'] = $row_verwendung->zeitaufzeichnungspflichtig; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['azgrelevant'] = $row_verwendung->azgrelevant; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['homeoffice'] = $row_verwendung->homeoffice; + + return true; + } + + /** + * Fueg einen Freitextbestandteil fuer All-In zum DV hinzu + */ + private function _addVertragsbestandteilFreitextAllIn(&$contracts, $dv, $row_verwendung) + { + if ($row_verwendung->ba1code == 111) // All-In + { + $newVBSIndex = $this->_getNewVBSIndex($contracts, $dv); + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['vertragsbestandteiltyp_kurzbz'] = 'freitext'; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['von'] = $row_verwendung->beginn; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['bis'] = $row_verwendung->ende; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['freitexttyp_kurzbz'] = 'allin'; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['titel'] = 'allin'; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['anmerkung'] = 'allin'; + } + return true; + } + + /** + * Fueg einen Freitextbestandteil fuer die Berfristung zum DV hinzu + */ + private function _addVertragsbestandteilFreitextBefristung(&$contracts, $dv, $row_verwendung) + { + if ($row_verwendung->ba2code == 1) // Befristung + { + $newVBSIndex = $this->_getNewVBSIndex($contracts, $dv); + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['vertragsbestandteiltyp_kurzbz'] = 'freitext'; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['von'] = $row_verwendung->beginn; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['bis'] = $row_verwendung->ende; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['freitexttyp_kurzbz'] = 'befristung'; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['titel'] = 'befristung'; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['anmerkung'] = 'befristung'; + } + return true; + } + + /** + * Prueft ob schon ein Vertragsbestandteil mit diesem Stundenausmass vorhanden ist das in den Zeitraum passt + * bzw direkt anschließt. Wenn es direkt anschließend ist und die Stunden gleich sind wird die Laufzeit verlaengert + * Ansonsten wird ein neuer VBS angelegt + */ + private function _addVertragsbestandteilStunden(&$contracts, $dv, $row_verwendung) + { + // Nur anlegen wenn im aktuellen Eintrag auch Stunden eingetragen sind + if ($row_verwendung->vertragsstunden != '') + { + if (isset($contracts['dv'][$dv]['vbs'])) + { + foreach ($contracts['dv'][$dv]['vbs'] as $index_vbs=>$row_vbs) + { + if ($row_vbs['vertragsbestandteiltyp_kurzbz'] == 'stunden' || ($row_vbs['vertragsbestandteiltyp_kurzbz'] == 'karenz' && $row_verwendung->vertragsstunden === '0.00')) + { + if ($this->_isVBSAngrenzend($row_verwendung, $row_vbs) && ((isset($row_vbs['wochenstunden']) && $row_vbs['wochenstunden'] == $row_verwendung->vertragsstunden) || $row_verwendung->vertragsstunden === '0.00')) + { + // stunden bleiben gleich - Ende des VBS verlaengern + $contracts['dv'][$dv]['vbs'][$index_vbs]['bis'] = $row_verwendung->ende; + return true; + } + } + } + } + + // kein passender VBS gefunden - neuen anlegen + $newVBSIndex = $this->_getNewVBSIndex($contracts, $dv); + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['vertragsbestandteiltyp_kurzbz'] = 'stunden'; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['von'] = $row_verwendung->beginn; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['bis'] = $row_verwendung->ende; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['wochenstunden'] = $row_verwendung->vertragsstunden; + $contracts['dv'][$dv]['vbs'][$newVBSIndex]['teilzeittyp_kurzbz'] = null; + } + return true; + } + + /** + * Prueft ob die Verwendung direkt an den Vertragsbestandteil angrenzt + * @return boolean true wenn ja, sonst false + */ + private function _isVBSAngrenzend($verwendung, $vbs) + { + // Beginn Minus 1 Tag + $dtstart = new DateTime($verwendung->beginn); + $dtstartMinus1 = $dtstart->sub(new DateInterval('P1D'))->format('Y-m-d'); + + if ($vbs['bis'] == '' + || $vbs['bis'] == $dtstartMinus1) + { + return true; + } + + return false; + } + + /** + * Create a new DV or Returns the Index of an existing + */ + private function _getOrCreateDV(&$contracts, $row_verwendung) + { + $unternehmen = $this->OE_DEFAULT; + $resultUnternehmen = $this->_getUnternehmen($row_verwendung); + if(hasData($resultUnternehmen)) + { + $unternehmen = getData($resultUnternehmen)[0]->oe_kurzbz; + } + else + { + // Fallback Unternehmen wird verwendet falls keine Zuordnung ermittelt werden kann + } + + if (isset($contracts['dv']) && is_array($contracts['dv'])) + { + foreach($contracts['dv'] as $indexdv => $row_dv) + { + // Vertragsart ist die selbe und selbes Unternehmen + if ($row_dv['vertragsart_kurzbz'] == $this->matching_ba1_vertragsart[$row_verwendung->ba1code] + && $row_dv['oe_kurzbz'] == $unternehmen + ) + { + + $dtstart = new DateTime($row_verwendung->beginn); + + // Zeitraum passt zur Verwendung + if ($row_dv['von'] <= $row_verwendung->beginn // Beginn Datum Pruefen + && ( // Ende innerhalb des DV + (isset($row_dv['bis']) && $row_verwendung->ende != '' && ($row_dv['bis'] == '' || $row_dv['bis'] >= $row_verwendung->ende) + ) + || // direkt angrenzend an dieses DV + (isset($row_dv['bis']) + && ($row_dv['bis'] == '' + || $row_dv['bis'] == $dtstart->sub(new DateInterval('P1D'))->format('Y-m-d') + ) + ) + ) + ) + { + return $indexdv; + } + } + } + } + + $newDvIndex = $this->_getNewDVIndex($contracts); + $contracts['dv'][$newDvIndex]['mitarbeiter_uid'] = $row_verwendung->mitarbeiter_uid; + $contracts['dv'][$newDvIndex]['von'] = $row_verwendung->beginn; + $contracts['dv'][$newDvIndex]['bis'] = $row_verwendung->ende; + $contracts['dv'][$newDvIndex]['oe_kurzbz'] = $unternehmen; + $contracts['dv'][$newDvIndex]['vertragsart_kurzbz'] = $this->matching_ba1_vertragsart[$row_verwendung->ba1code]; + + return $newDvIndex; + } + + /** + * Ermittelt in welchem Unternehmen die Person zum betreffenden Zeitpunkt ist. + */ + private function _getUnternehmen($row_verwendung) + { + + $resultUnternehmen = $this->_findUnternehmen($row_verwendung->mitarbeiter_uid, "'kstzuordnung', 'oezuordnung'", $row_verwendung->beginn); + + // Wenn zeitlich keine passende Unternehmenszuordnung vorhanden ist, dann suchen ob generell eine Zuordnung ermittelt werden kann + if(!hasData($resultUnternehmen)) + { + $resultUnternehmen = $this->_findUnternehmen($row_verwendung->mitarbeiter_uid, "'kstzuordnung', 'oezuordnung'"); + + // Falls nicht wird nach erweiterten Funktionen gesucht um die Zuordnung zu ermitteln. + if(!hasData($resultUnternehmen)) + { + $resultUnternehmen = $this->_findUnternehmen($row_verwendung->mitarbeiter_uid, "'kstzuordnung', 'oezuordnung','hilfskraft','Leitung','fbk','fbl'"); + } + } + + return $resultUnternehmen; + } + + /** + * Detailsuche fuer die Ermittlung des Unternehmenszuordnung einer Person + */ + private function _findUnternehmen($uid, $fkt=null, $datum=null) + { + $db = new DB_Model(); + + $qry = " + WITH RECURSIVE meine_oes(oe_kurzbz, oe_parent_kurzbz, organisationseinheittyp_kurzbz) as + ( + SELECT + oe_kurzbz, oe_parent_kurzbz, organisationseinheittyp_kurzbz + FROM + public.tbl_organisationseinheit + WHERE + oe_kurzbz=(SELECT + oe_kurzbz + FROM + public.tbl_benutzerfunktion + WHERE + uid=".$db->escape($uid); + + if(!is_null($datum)) + $qry.=" AND ".$db->escape($datum)." BETWEEN datum_von AND COALESCE(datum_bis, '2999-12-31')"; + + if(!is_null($fkt)) + $qry.=" AND funktion_kurzbz in ($fkt)"; + + $qry.=" + ORDER BY funktion_kurzbz, datum_von LIMIT 1) + UNION ALL + SELECT + o.oe_kurzbz, o.oe_parent_kurzbz, o.organisationseinheittyp_kurzbz + FROM + public.tbl_organisationseinheit o, meine_oes + WHERE + o.oe_kurzbz=meine_oes.oe_parent_kurzbz + ) + SELECT + oe_kurzbz + FROM + meine_oes + WHERE + oe_parent_kurzbz is null + LIMIT 1 + "; + + $resultUnternehmen = $db->execReadOnlyQuery($qry); + return $resultUnternehmen; + } + + /** + * Ermittelt den nächsten (freien) Index für den Vertragsbetandteil + */ + private function _getNewVBSIndex($contracts, $dv) + { + if (isset($contracts['dv'][$dv]['vbs'])) + return max(array_keys($contracts['dv'][$dv]['vbs'])) + 1; + else + return 0; + } + + /** + * Ermittelt den nächsten (freien) Index für das Dienstverhältnis + */ + private function _getNewDVIndex($contracts) + { + if (isset($contracts['dv']) && is_array($contracts['dv'])) + return max(array_keys($contracts['dv'])) + 1; + else + return 0; + } +} diff --git a/application/controllers/system/MigrateHourlyRate.php b/application/controllers/system/MigrateHourlyRate.php new file mode 100644 index 000000000..4fed2f585 --- /dev/null +++ b/application/controllers/system/MigrateHourlyRate.php @@ -0,0 +1,188 @@ +_ci = & get_instance(); + + $this->load->model('codex/Bisverwendung_model', 'BisVerwendungModel'); + $this->load->model('person/Benutzerfunktion_model', 'BenutzerfunktionModel'); + $this->load->model('ressource/Stundensatz_model', 'StundensatzModel'); + } + + public function index($user = null) + { + $mitarbeiterResult = $this->_getMitarbeiterStunden($user); + if (isError($mitarbeiterResult)) return $mitarbeiterResult; + if (!hasData($mitarbeiterResult)) return error('Keine Mitarbeiterstunden gefunden'); + + $mitarbeiterArray = getData($mitarbeiterResult); + + foreach ($mitarbeiterArray as $mitarbeiter) + { + $this->_getUnternehmen($mitarbeiter); + $insertResult = $this->_addStundensatz($mitarbeiter, self::STUNDENSTAZTYP_LEHRE, self::DEFAULT_DATE); + 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) + { + $this->_getUnternehmen($mitarbeiter); + $insertResult = $this->_addStundensatz($mitarbeiter, self::STUNDENSTAZTYP_KALKULATORISCH, date_format(date_create($mitarbeiter->beginn), 'Y-m-d')); + if (isError($insertResult)) return $insertResult; + } + } + + private function _getSapStunden($user = null) + { + $dbModel = new DB_Model(); + $params = array(); + + $qry = "SELECT ss.mitarbeiter_uid as uid, + ss.sap_kalkulatorischer_stundensatz as stundensatz, + ss.insertamum as beginn + FROM sync.tbl_sap_stundensatz ss + WHERE ss.sap_kalkulatorischer_stundensatz IS NOT NULL"; + + if (!is_null($user)) + { + $qry .= " AND ss.mitarbeiter_uid = ? "; + $params[] = $user; + } + $qry .= " ORDER BY ss.mitarbeiter_uid"; + + return $dbModel->execReadOnlyQuery($qry, $params); + } + + private function _getMitarbeiterStunden($user = null) + { + $dbModel = new DB_Model(); + $params = array(); + + $qry = "SELECT mitarbeiter.mitarbeiter_uid as uid, + stundensatz + FROM public.tbl_mitarbeiter mitarbeiter + WHERE mitarbeiter.stundensatz != 0.00 + AND mitarbeiter.stundensatz IS NOT NULL"; + + if (!is_null($user)) + { + $qry .= " AND mitarbeiter.mitarbeiter_uid = ?"; + $params[] = $user; + } + + $qry .= " ORDER BY mitarbeiter.mitarbeiter_uid"; + + return $dbModel->execReadOnlyQuery($qry, $params); + } + + private function _addStundensatz($mitarbeiter, $stundensatztyp, $gueltig_von) + { + return $this->_ci->StundensatzModel->insert( + array( + 'uid' => $mitarbeiter->uid, + 'stundensatztyp' => $stundensatztyp, + 'stundensatz' => $mitarbeiter->stundensatz, + 'oe_kurzbz' => $mitarbeiter->unternehmen, + 'gueltig_von' => $gueltig_von, + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => 'MigrateHours' + ) + ); + } + + private function _getUnternehmen(&$mitarbeiter) + { + $bvResult = $this->_ci->BisVerwendungModel->getLast($mitarbeiter->uid); + + $beginn = null; + if (hasData($bvResult)) + { + $beginn = getData($bvResult)[0]->beginn; + } + + $unternehmenResult = $this->_findUnternehmen($mitarbeiter->uid, "'kstzuordnung', 'oezuordnung'", $beginn); + + if(!hasData($unternehmenResult)) //&& hasData($bvResult) + { + $unternehmenResult = $this->_findUnternehmen($mitarbeiter->uid, "'kstzuordnung', 'oezuordnung'"); + } + + $unternehmen = self::DEFAULT_OE; + + if (hasData($unternehmenResult)) + $unternehmen = getData($unternehmenResult)[0]->oe_kurzbz; + + $mitarbeiter->unternehmen = $unternehmen; + } + + /** + * Detailsuche fuer die Ermittlung des Unternehmenszuordnung einer Person + */ + private function _findUnternehmen($uid, $fkt=null, $datum=null) + { + $dbModel = new DB_Model(); + + $qry = " + WITH RECURSIVE meine_oes(oe_kurzbz, oe_parent_kurzbz, organisationseinheittyp_kurzbz) as + ( + SELECT + oe_kurzbz, oe_parent_kurzbz, organisationseinheittyp_kurzbz + FROM + public.tbl_organisationseinheit + WHERE + oe_kurzbz=(SELECT + oe_kurzbz + FROM + public.tbl_benutzerfunktion + WHERE + uid=".$dbModel->escape($uid); + + if(!is_null($datum)) + $qry.=" AND ".$dbModel->escape($datum)." BETWEEN datum_von AND COALESCE(datum_bis, '2999-12-31')"; + + if(!is_null($fkt)) + $qry.=" AND funktion_kurzbz in ($fkt)"; + + $qry.=" + ORDER BY funktion_kurzbz, datum_von LIMIT 1) + UNION ALL + SELECT + o.oe_kurzbz, o.oe_parent_kurzbz, o.organisationseinheittyp_kurzbz + FROM + public.tbl_organisationseinheit o, meine_oes + WHERE + o.oe_kurzbz=meine_oes.oe_parent_kurzbz + ) + SELECT + oe_kurzbz + FROM + meine_oes + WHERE + oe_parent_kurzbz is null + LIMIT 1 + "; + + return $dbModel->execReadOnlyQuery($qry); + } + +} diff --git a/application/controllers/system/MigrateSalary.php b/application/controllers/system/MigrateSalary.php new file mode 100644 index 000000000..e8771f913 --- /dev/null +++ b/application/controllers/system/MigrateSalary.php @@ -0,0 +1,465 @@ + G + private $INDEX_LOHNART = 4; + private $INDEX_BEZEICHNUNG = 5; + + /** + * Constructor + */ + public function __construct() + { + parent::__construct(); + + $this->load->model('vertragsbestandteil/Gehaltsbestandteil_model', 'GehaltsbestandteilModel'); + $this->load->model('vertragsbestandteil/Dienstverhaeltnis_model','DienstverhaeltnisModel'); + $this->load->model('vertragsbestandteil/Vertragsbestandteil_model','VertragsbestandteilModel'); + $this->load->model('vertragsbestandteil/VertragsbestandteilStunden_model','VertragsbestandteilStundenModel'); + $this->load->model('vertragsbestandteil/VertragsbestandteilFreitext_model','VertragsbestandteilFreitextModel'); + $this->load->model('vertragsbestandteil/VertragsbestandteilFunktion_model','VertragsbestandteilFunktionModel'); + + } + + // ----------------------------------------------------------------------------------------------------------------- + // Public methods + + /** + * Everything has a beginning + */ + public function import($file) + { + + // CSV Laden + $file = urldecode($file); + if($handle = fopen($file, "r")) + { + $csvrow = -1; + $lastuser = ''; + $monate = array(); + $gehaltsarr = array(); + $gehaltsindex = 0; + + while (($data = fgetcsv($handle, null, ';')) !== FALSE) + { + $csvrow++; + // Kopfzeile ueberspringen + if($csvrow == 0) + { + for($i = $this->GEHALT_BEGINN_SPALTE; $i < count($data); $i++) + { + $monate[] = $data[$i]; + } + continue; + } + + // User zur SVNR ermitteln + $svnr = str_replace(' ', '',$data[0]); + $resultuser = $this->_getUser($svnr); + + if(!hasData($resultuser)) + { + echo getError($resultuser); + break; + } + + $user = getData($resultuser)[0]->mitarbeiter_uid; + echo "\nUser:".$user; + + if($user != $lastuser && $lastuser != '') + { + $this->_saveGehalt($lastuser, $gehaltsarr); + $gehaltsarr = array(); + $gehaltsindex = 0; + $lastuser = $user; + } + else + { + $lastuser = $user; + } + + // Gehalt Clustern + + $monat = 0; + for ($i = $this->GEHALT_BEGINN_SPALTE; $i < count($data); $i++) + { + if (count($gehaltsarr) == 0 && $data[$i] != '') + { + $gehaltsarr[$gehaltsindex]['betrag'] = $data[$i]; + $gehaltsarr[$gehaltsindex]['lohnart'] = $data[$this->INDEX_LOHNART]; + $gehaltsarr[$gehaltsindex]['bezeichnung'] = $data[$this->INDEX_BEZEICHNUNG]; + $gehaltsarr[$gehaltsindex]['beginn'] = $monate[$monat]; + } + else + { + if ($data[$i] != '' + && isset($gehaltsarr[$gehaltsindex]) && isset($gehaltsarr[$gehaltsindex]['betrag']) + && $gehaltsarr[$gehaltsindex]['betrag'] == $data[$i]) + { + // Gehalt bleibt gleich + } + else + { + if ($data[$i] != '') + { + // Gehalt hat sich geändert + if ($monat != 0 && isset($gehaltsarr[$gehaltsindex])) + $gehaltsarr[$gehaltsindex]['ende'] = $monate[$monat-1]; + + $gehaltsindex++; + + $gehaltsarr[$gehaltsindex]['betrag'] = $data[$i]; + $gehaltsarr[$gehaltsindex]['lohnart'] = $data[$this->INDEX_LOHNART]; + $gehaltsarr[$gehaltsindex]['bezeichnung'] = $data[$this->INDEX_BEZEICHNUNG]; + $gehaltsarr[$gehaltsindex]['beginn'] = $monate[$monat]; + } + elseif(isset($gehaltsarr[$gehaltsindex])) + { + // Gehalt wurde beendet + if($monat!=0) + $gehaltsarr[$gehaltsindex]['ende'] = $monate[$monat-1]; + $gehaltsindex++; + } + } + } + + $monat++; + } + + // Zeile zu Ende - Ende Datum setzen wenn nicht für alle Monate ein Eintrag vorhanden ist + if($monat < count($monate) && isset($gehaltsarr[$gehaltsindex])) + $gehaltsarr[$gehaltsindex]['ende'] == $monate[$monat-1]; + + } + $this->_saveGehalt($lastuser, $gehaltsarr); + } + } + + /** + * Ermittelt das passende Dienstverhaeltnis uns speichert den + * Gehaltsbestandteil + */ + private function _saveGehalt($uid, $gehaltsarr) + { + $failed = false; + $this->db->trans_begin(); + + foreach($gehaltsarr as $row_gehalt) + { + $auszahlungen = 14; + $dvid = ''; + $vbsid = ''; + $typ = ''; + $allin = false; + + //DV und VBS Ermitteln + $dv = $this->DienstverhaeltnisModel->getDVByPersonUID($uid, $this->OE_DEFAULT, $row_gehalt['beginn']); + + if (!hasData($dv)) + { + $date = new DateTime($row_gehalt['beginn']); + $date->modify('last day of this month'); + $last_day_this_month = $date->format('Y-m-d'); + + // Wenn mit Monatsersten kein DV gefunden wird, wird stattdessen mit Monatsletzten gesucht um DVs zu finden + // für Personen die erst später im Monat in ihr DV einsteigen + $dv = $this->DienstverhaeltnisModel->getDVByPersonUID($uid, $this->OE_DEFAULT, $last_day_this_month); + + if (!hasData($dv)) + { + echo "\nKein passendes DV gefunden für User ".$uid." und Datum ".$row_gehalt['beginn']." -> ROLLBACK\n"; + $failed = true; + break; + } + else + { + // Gehaltsstart wird auf den Start des DV korrigiert wenn nicht der Monatserste + $row_gehalt['beginn'] = getData($dv)[0]->von; + } + } + + $resultdata = getData($dv); + if (count($resultdata) !== 1) + { + echo "Kein oder Mehrere DVs gefunden -> ROLLBACK"; + $failed = true; + break; + } + + $dvid = $resultdata[0]->dienstverhaeltnis_id; + + $allin = $this->_isAllIn($dvid, $row_gehalt['beginn']); + + $db = new DB_Model(); + + $resultVBS = $this->_getVBS($dvid, $row_gehalt['beginn']); + + if (hasData($resultVBS)) + { + $vbsid = getData($resultVBS)[0]->vertragsbestandteil_id; + } + else + { + echo "Vertragsbestandteil wurde nicht gefunden -> ROLLBACK"; + $failed = true; + break; + } + + if ($row_gehalt['lohnart'] == 1000) + { + if($allin) + $typ = 'grundgehalt'; + else + $typ = 'basisgehalt'; + } + elseif ($row_gehalt['lohnart']==1041 // 14x + || $row_gehalt['lohnart']==1042 // 12x + || $row_gehalt['lohnart']==3410) // USTDPausch + { + $typ = 'zusatzvereinbarung'; + + // Freitextbestandteil anlegen fuer die Zulage + // Gaehalt wird der Zuglage zugeordnet + + $data = array( + 'dienstverhaeltnis_id' => $dvid, + 'von' => $row_gehalt['beginn'], + 'vertragsbestandteiltyp_kurzbz' => 'freitext', + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => 'MigrateSalary' + ); + if (isset($row_gehalt['ende']) && $row_gehalt['ende']!='') + $data['bis'] = $row_gehalt['ende']; + + $resultVBS = $this->VertragsbestandteilModel->Insert($data); + if(!isSuccess($resultVBS)) + { + echo "VBS kann nicht erstellt werden -> ROLLBACK"; + $failed = true; + break; + } + $vbsid = getData($resultVBS); + + $data = array( + 'vertragsbestandteil_id' => $vbsid, + 'freitexttyp_kurzbz' => 'zusatzvereinbarung', + 'titel' => $row_gehalt['bezeichnung'], + 'anmerkung' => $row_gehalt['bezeichnung'], + ); + $resultVBSFreitext = $this->VertragsbestandteilFreitextModel->Insert($data); + if(!isSuccess($resultVBSFreitext)) + { + echo "VBS Freitext Zusatz kann nicht erstellt werden -> ROLLBACK"; + $failed = true; + break; + } + } + elseif ($row_gehalt['lohnart']==9999) // All-In Custom Lohnart nicht per Default vorhanden + { + $typ = 'zulage'; + + // Freitextbestandteil anlegen fuer die Zulage + // Gaehalt wird der Zuglage zugeordnet + + $data = array( + 'dienstverhaeltnis_id' => $dvid, + 'von' => $row_gehalt['beginn'], + 'vertragsbestandteiltyp_kurzbz' => 'freitext', + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => 'MigrateSalary' + ); + if (isset($row_gehalt['ende']) && $row_gehalt['ende']!='') + $data['bis'] = $row_gehalt['ende']; + + $resultVBS = $this->VertragsbestandteilModel->Insert($data); + if(!isSuccess($resultVBS)) + { + echo "VBS AllIn kann nicht erstellt werden -> ROLLBACK"; + $failed = true; + break; + } + $vbsid = getData($resultVBS); + + $data = array( + 'vertragsbestandteil_id' => $vbsid, + 'freitexttyp_kurzbz' => 'allin', + 'titel' => $row_gehalt['bezeichnung'], + 'anmerkung' => $row_gehalt['bezeichnung'], + ); + $resultVBSFreitext = $this->VertragsbestandteilFreitextModel->Insert($data); + if(!isSuccess($resultVBSFreitext)) + { + echo "VBS Freitext AllIn Zusatz kann nicht erstellt werden -> ROLLBACK"; + $failed = true; + break; + } + } + elseif($row_gehalt['lohnart']==5500) // ATZ + { + $typ = 'lohnausgleichatz'; + } + else + { + $typ = 'unbekannt - '.$row_gehalt['lohnart']; + echo "\nGehaltstyp unbekannt Lohnart: ".$row_gehalt['lohnart']." -> ROLLBACK"; + $failed = true; + break; + } + + // Zulage 12x und Zulage 14x aus der Bezeichnung ermitteln + if(strstr($row_gehalt['bezeichnung'], '12x')) + { + $auszahlungen = 12; + } + + // Format ist 7.777,77 und wird umformattiert in 7777.77 + $betrag = str_replace('.','', $row_gehalt['betrag']); + $betrag = str_replace(',','.',$betrag); + + $data = array( + 'dienstverhaeltnis_id' => $dvid, + 'vertragsbestandteil_id' => $vbsid, + 'gehaltstyp_kurzbz' => $typ, + 'von' => $row_gehalt['beginn'], + 'grundbetrag' => $betrag, + 'betrag_valorisiert' => $betrag, + 'anmerkung' => $row_gehalt['bezeichnung'], + 'valorisierung' => true, + 'auszahlungen' => $auszahlungen, + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => 'MigrateSalary', + 'updateamum' => date('Y-m-d H:i:s'), + 'updatevon' => 'MigrateSalary' + ); + + if (isset($row_gehalt['ende']) && $row_gehalt['ende'] != '') + { + // Im Ende steht noch der Monatserste des letzten Monats + // Das muss geaendert werden auf den Monatsletzten oder das Ende des DVs + $date = new DateTime($row_gehalt['ende']); + $date->modify('last day of this month'); + $last_day_this_month = $date->format('Y-m-d'); + + // TODO: wenn das Dienstverhaeltnis in diesem Monat endet und nicht der Monatsletzte ist, + // dann muss hier das Ende Datum des DV stehen bzw das Ende + // oder das Ende des VBS falls die Person in der Monatsmitte Stunden wechselt + $data['bis'] = $last_day_this_month; + } + + $ret = $this->GehaltsbestandteilModel->insert($data, + $this->GehaltsbestandteilModel->getEncryptedColumns() + ); + } + + if(!$failed) + { + $this->db->trans_commit(); + } + else + { + echo "ROLLBACK"; + $this->db->trans_rollback(); + } + } + + /** + * Prueft ob ein AllIn Vertrag vorhanden ist + */ + private function _isAllIn($dvid, $datum) + { + $db = new DB_Model(); + + $qry = " + SELECT + * + FROM + hr.tbl_vertragsbestandteil + JOIN hr.tbl_vertragsbestandteil_freitext USING(vertragsbestandteil_id) + WHERE + dienstverhaeltnis_id=".$db->escape($dvid)." + AND vertragsbestandteiltyp_kurzbz='freitext' + AND ".$db->escape($datum)." BETWEEN von AND COALESCE(bis, '2999-12-31') + AND freitexttyp_kurzbz='allin'"; + + $resultAllIn = $db->execReadOnlyQuery($qry); + + if (hasData($resultAllIn)) + return true; + else + return false; + } + + private function _getVBS($dvid, $datum) + { + $db = new DB_Model(); + + $qry = " + SELECT + * + FROM + hr.tbl_vertragsbestandteil + WHERE + dienstverhaeltnis_id=".$db->escape($dvid)." + AND vertragsbestandteiltyp_kurzbz='stunden' + AND ".$db->escape($datum)." BETWEEN von AND COALESCE(bis, '2999-12-31')"; + + $resultVBS = $db->execReadOnlyQuery($qry); + + return $resultVBS; + } + + /** + * Ermittelt den User zu einer SVNR + */ + private function _getUser($svnr) + { + $db = new DB_Model(); + + $qry = " + SELECT + mitarbeiter_uid + FROM + public.tbl_person + JOIN public.tbl_benutzer using(person_id) + JOIN public.tbl_mitarbeiter ON(uid=mitarbeiter_uid) + WHERE + tbl_person.svnr = ". $db->escape($svnr)." + AND EXISTS( + SELECT + 1 + FROM + hr.tbl_dienstverhaeltnis + WHERE + mitarbeiter_uid=tbl_mitarbeiter.mitarbeiter_uid + AND oe_kurzbz=". $db->escape($this->OE_DEFAULT)." + ) + ORDER BY tbl_benutzer.aktiv DESC + LIMIT 1; + "; + + $result = $db->execReadOnlyQuery($qry); + + if (hasdata($result)) + { + return $result; + } + else + return error('Kein Benutzer mit DV und SVNR:'.$svnr.' gefunden'); + } +} diff --git a/application/controllers/system/TestVBform.php b/application/controllers/system/TestVBform.php new file mode 100644 index 000000000..9923bf05b --- /dev/null +++ b/application/controllers/system/TestVBform.php @@ -0,0 +1,32 @@ + 'system/developer:r' + ) + ); + } + + // ----------------------------------------------------------------------------------------------------------------- + // Public methods + + /** + * Everything has a beginning + */ + public function index() + { + $this->load->view('system/logs/testVBform.php'); + } +} diff --git a/application/controllers/system/messages/FASMessages.php b/application/controllers/system/messages/FASMessages.php index 55d1da25f..e2169af9b 100644 --- a/application/controllers/system/messages/FASMessages.php +++ b/application/controllers/system/messages/FASMessages.php @@ -37,7 +37,7 @@ class FASMessages extends Auth_Controller // Loads the view to write a new message with a template $this->load->view( - 'system/messages/htmlWriteTemplate', + 'system/messages/FAShtmlWriteTemplate', $this->CLMessagesModel->prepareHtmlWriteTemplatePrestudents($prestudents) ); } @@ -53,7 +53,7 @@ class FASMessages extends Auth_Controller // Loads the view to write a new message with a template $this->load->view( - 'system/messages/htmlWriteTemplate', + 'system/messages/FAShtmlWriteTemplate', $this->CLMessagesModel->prepareHtmlWriteTemplatePrestudents($prestudents, $message_id, $recipient_id) ); } diff --git a/application/core/CI3_Events.php b/application/core/CI3_Events.php new file mode 100644 index 000000000..33a96b89e --- /dev/null +++ b/application/core/CI3_Events.php @@ -0,0 +1,51 @@ +. + */ + +use \stdClass as stdClass; + if (!defined('BASEPATH')) exit('No direct script access allowed'); /** @@ -27,6 +46,15 @@ class DB_Model extends CI_Model const PGSQL_INT8_TYPE = 'int8'; const PGSQL_FLOAT4_TYPE = 'float4'; const PGSQL_FLOAT8_TYPE = 'float8'; + const PGSQL_BYTEA_TYPE = 'bytea'; + + // Name of the config entry containing an array of password that can be used to encrypt/decrypt + const CRYPT_CONF_PASSWORDS = 'encryption_passwords'; + const CRYPT_CAST = 'cast'; + const CRYPT_PASSWORD_NAME = 'passwordName'; + const CRYPT_SELECT_TEMPLATE = 'PGP_SYM_DECRYPT(%s, \'%s\')::%s AS %s'; + const CRYPT_WHERE_TEMPLATE = 'PGP_SYM_DECRYPT(%s, \'%s\')::%s'; + const CRYPT_WRITE_TEMPLATE = 'PGP_SYM_ENCRYPT(\'%s\', \'%s\')'; protected $dbTable; // Name of the DB-Table for CI-Insert, -Update, ... protected $pk; // Name of the PrimaryKey for DB-Update, Load, ... @@ -36,7 +64,7 @@ class DB_Model extends CI_Model private $executedQueryMetaData; private $executedQueryListFields; - private $debugMode; + private $debugMode; // Debug mode enable (true) or disabled (false) /** * Constructor @@ -46,20 +74,23 @@ class DB_Model extends CI_Model // Call parent constructor parent::__construct(); - // Set properties - $this->hasSequence = true; - - // Loads DB conns and confs + // Loads DB connections and configs $this->load->database($dbtype); + // Loads the DB config to encrypt/decrypt data + $this->config->load('db_crypt'); + + // Set properties + $this->hasSequence = true; + $this->debugMode = isset($this->db->db_debug) && $this->db->db_debug === true; + + // Loads UDF model $this->load->model('system/UDF_model', 'UDFModel'); // Loads the UDF library $this->load->library('UDFLib'); // Loads the logs library $this->load->library('LogLib'); - - $this->debugMode = isset($this->db->db_debug) && $this->db->db_debug === true; } // ------------------------------------------------------------------------------------------ @@ -85,13 +116,20 @@ class DB_Model extends CI_Model * @param array $data DataArray for Insert * @return array */ - public function insert($data) + public function insert($data, $encryptedColumns = null) { // Check class properties if (is_null($this->dbTable)) return error('The given database table name is not valid', EXIT_MODEL); // If this table has UDF and the validation of them is ok - if (isError($validate = $this->_prepareUDFsWrite($data, $this->dbTable))) return $validate; + $validate = $this->_prepareUDFsWrite($data, $this->dbTable); + if (isError($validate)) return $validate; + + // Add the pgp_sym_eccrypt postgresql function to the set clause if needed + $this->_addEncrypt($encryptedColumns, $data); + + // Add the pgp_sym_eccrypt postgresql function to the set clause if needed + if (!empty($encryptedColumns)) $this->_addEncrypt($encryptedColumns, $data); // DB-INSERT $insert = $this->db->insert($this->dbTable, $data); @@ -135,14 +173,15 @@ class DB_Model extends CI_Model * @param array $data DataArray for Insert * @return array */ - public function update($id, $data) + public function update($id, $data, $encryptedColumns = null) { // Check class properties if (is_null($this->pk)) return error('The given primary key is not valid', EXIT_MODEL); if (is_null($this->dbTable)) return error('The given database table name is not valid', EXIT_MODEL); // If this table has UDF and the validation of them is ok - if (isError($validate = $this->_prepareUDFsWrite($data, $this->dbTable, $id))) return $validate; + $validate = $this->_prepareUDFsWrite($data, $this->dbTable, $id); + if (isError($validate)) return $validate; $tmpId = $id; @@ -161,6 +200,9 @@ class DB_Model extends CI_Model $this->db->where($tmpId); + // Add the pgp_sym_eccrypt postgresql function to the set clause if needed + $this->_addEncrypt($encryptedColumns, $data); + // DB-UPDATE $update = $this->db->update($this->dbTable, $data); @@ -224,7 +266,7 @@ class DB_Model extends CI_Model * @param string $id ID (Primary Key) for SELECT ... WHERE * @return array */ - public function load($id = null) + public function load($id = null, $encryptedColumns = null) { // Check class properties if (is_null($this->pk)) return error('The given primary key is not valid', EXIT_MODEL); @@ -245,7 +287,7 @@ class DB_Model extends CI_Model $tmpId = array($this->pk => $id); } - return $this->loadWhere($tmpId); + return $this->loadWhere($tmpId, $encryptedColumns); } /** @@ -253,11 +295,14 @@ class DB_Model extends CI_Model * * @return array */ - public function loadWhere($where = null) + public function loadWhere($where = null, $encryptedColumns = null) { // Check class properties if (is_null($this->dbTable)) return error('The given database table name is not valid', EXIT_MODEL); + // Add the pgp_sym_decrypt postgresql function to the select and where clause if needed + $this->_addDecryptLoad($encryptedColumns, $where); + // Execute query $result = $this->db->get_where($this->dbTable, $where); @@ -265,7 +310,7 @@ class DB_Model extends CI_Model if ($result) { - return success($this->_toPhp($result)); + return success($this->_toPhp($result, $encryptedColumns)); } else { @@ -303,7 +348,8 @@ class DB_Model extends CI_Model // NOTE: $this->db->list_fields($tables[$t]) doesn't work if there are two tables with // the same name in two different schemas, use this workaround $fields = array(); - if (isSuccess($lstColumns = $this->_list_columns($schemaAndTable->schema, $schemaAndTable->table))) + $lstColumns = $this->_list_columns($schemaAndTable->schema, $schemaAndTable->table); + if (isSuccess($lstColumns)) { $fields = $lstColumns->retval; } @@ -381,7 +427,8 @@ class DB_Model extends CI_Model $tmpFilteredArray = array_filter(get_object_vars($sideTableObj)); if (isset($tmpFilteredArray) && count($tmpFilteredArray) > 0) { - if (($k = $this->_findMainTable($mainTableObj, $returnArray)) === false) + $k = $this->_findMainTable($mainTableObj, $returnArray); + if ($k === false) { $mainTableObj->{$sideTableProperty} = array($sideTableObj); $returnArray[$returnArrayCounter++] = $mainTableObj; @@ -758,14 +805,13 @@ class DB_Model extends CI_Model /** * Like execQuery, but it allows only to perform queries to read data */ - public function execReadOnlyQuery($query, $parametersArray = null) + public function execReadOnlyQuery($query, $parametersArray = null, $encryptedColumns = null) { $result = error('You are allowed to run only query for reading data'); // $cleanedQuery = trim(preg_replace('/\t|\n|\r|;/', '', $query)); // // - if ( - (stripos($cleanedQuery, 'INSERT') > 0 || stripos($cleanedQuery, 'INSERT') == false) + if ((stripos($cleanedQuery, 'INSERT') > 0 || stripos($cleanedQuery, 'INSERT') == false) && (stripos($cleanedQuery, 'UPDATE') > 0 || stripos($cleanedQuery, 'UPDATE') == false) && (stripos($cleanedQuery, 'CREATE') > 0 || stripos($cleanedQuery, 'CREATE') == false) && (stripos($cleanedQuery, 'DELETE') > 0 || stripos($cleanedQuery, 'DELETE') == false) @@ -775,7 +821,7 @@ class DB_Model extends CI_Model { $queryToExec = str_replace(';', '', $query); // - $result = $this->execQuery($queryToExec, $parametersArray); + $result = $this->execQuery($queryToExec, $parametersArray, $encryptedColumns); } return $result; @@ -790,13 +836,16 @@ class DB_Model extends CI_Model * boolean if the query is of the write type (INSERT, UPDATE, DELETE...) * array that represents DB data */ - protected function execQuery($query, $parametersArray = null) + protected function execQuery($query, $parametersArray = null, $encryptedColumns = null) { $result = null; // If the query is empty don't lose time if (!isEmptyString($query)) { + // Add the pgp_sym_decrypt postgresql function to the given query + $this->_addDecryptQuery($encryptedColumns, $query); + // If there are parameters to bind to the query if (is_array($parametersArray) && count($parametersArray) > 0) { @@ -812,7 +861,7 @@ class DB_Model extends CI_Model // If no errors occurred if ($resultDB) { - $result = success($this->_toPhp($resultDB)); + $result = success($this->_toPhp($resultDB, $encryptedColumns)); } else { @@ -840,7 +889,8 @@ class DB_Model extends CI_Model $result->schema = DB_Model::DEFAULT_SCHEMA; // If a schema is specified - if (($pos = strpos($schemaAndTable, '.')) !== false) + $pos = strpos($schemaAndTable, '.'); + if ($pos !== false) { $result->schema = substr($schemaAndTable, 0, $pos); $result->table = substr($schemaAndTable, $pos + 1); @@ -851,6 +901,207 @@ class DB_Model extends CI_Model // ------------------------------------------------------------------------------------------ // Private methods + // + // + + /** + * To add the pgp_sym_encrypt function to the set clause where needed + */ + private function _addEncrypt($encryptedColumns, &$data) + { + // If encryptedColumns is not defined then exit + if (isEmptyArray($encryptedColumns)) return; + + $tmpData = array(); // Temporary array used to copy not encrypted columns + + // For each column that is going to be inserted/updated + foreach ($data as $column => $value) + { + // If the current column is in the list of the columns to be encrypted + // and contains the password name element + if (array_key_exists($column, $encryptedColumns) + && array_key_exists(self::CRYPT_PASSWORD_NAME, $encryptedColumns[$column])) + { + // Password to encrypt data + $cryptConfPasswords = $this->config->item(self::CRYPT_CONF_PASSWORDS); + $encryptionPassword = $cryptConfPasswords[$encryptedColumns[$column][self::CRYPT_PASSWORD_NAME]]; + + // Add the encrypted column to the set clause without escaping + $this->db->set( + $column, + sprintf( + self::CRYPT_WRITE_TEMPLATE, + $value, + $encryptionPassword + ), + false // no escaping + ); + } + else // otherwise copy this element as it is + { + $tmpData[$column] = $value; + } + } + + $data = $tmpData; // this array does not contain encrypted columns + } + + /** + * To add the pgp_sym_decrypt function to the given query + */ + private function _addDecryptQuery($encryptedColumns, &$query) + { + // If it is request to get encrypted columns + if (!isEmptyArray($encryptedColumns)) + { + // For each requested encrypted column + foreach ($encryptedColumns as $encryptedColumn => $definition) + { + // If the requested encrypted column is well defined + if (!isEmptyArray($definition) + && array_key_exists(self::CRYPT_CAST, $definition) + && array_key_exists(self::CRYPT_PASSWORD_NAME, $definition)) + { + // And if exists the wanted password to decrypt in the configs + if (array_key_exists($definition[self::CRYPT_PASSWORD_NAME], $this->config->item(self::CRYPT_CONF_PASSWORDS))) + { + // Password to decrypt data + $cryptConfPasswords = $this->config->item(self::CRYPT_CONF_PASSWORDS); + $decryptionPassword = $cryptConfPasswords[$definition[self::CRYPT_PASSWORD_NAME]]; + + // Find and replace all the occurrences of the provided encrypted columns + // with the postgresql decryption function + $query = str_replace( + $encryptedColumn, + sprintf( + self::CRYPT_WHERE_TEMPLATE, + $encryptedColumn, + $decryptionPassword, + $definition[self::CRYPT_CAST] + ), + $query + ); + } + } + } + } + } + + /** + * To add the pgp_sym_decrypt function to the select and where clause where needed + */ + private function _addDecryptLoad($encryptedColumns, &$where) + { + // If it is request to get encrypted columns + if (!isEmptyArray($encryptedColumns)) + { + // For each requested encrypted column + foreach ($encryptedColumns as $encryptedColumn => $definition) + { + // If the requested encrypted column is well defined + if (!isEmptyArray($definition) + && array_key_exists(self::CRYPT_CAST, $definition) + && array_key_exists(self::CRYPT_PASSWORD_NAME, $definition)) + { + // And if exists the wanted password to decrypt in the configs + if (array_key_exists($definition[self::CRYPT_PASSWORD_NAME], $this->config->item(self::CRYPT_CONF_PASSWORDS))) + { + // Password to decrypt data + $cryptConfPasswords = $this->config->item(self::CRYPT_CONF_PASSWORDS); + $decryptionPassword = $cryptConfPasswords[$definition[self::CRYPT_PASSWORD_NAME]]; + + // ----------------------------------------- + // SELECT + + // Add to the select clause the column to be decrypted + // NOTE: this is going to override any previously added column with the same name + $this->addSelect( + sprintf( + self::CRYPT_SELECT_TEMPLATE, + $encryptedColumn, + $decryptionPassword, + $definition[self::CRYPT_CAST], + $encryptedColumn + ) + ); + + // ----------------------------------------- + // WHERE + + // If the where parameter is a valid array + if (!isEmptyArray($where)) + { + $tmpWhere = array(); + + // For each condition of the where clause + foreach ($where as $column => $condition) + { + $operator = null; // operator not found in the column name + + // Custom operators with 2 chars + if (strpos($column, '>=') != false + || strpos($column, '<=') != false + || strpos($column, '!=') != false + || strpos($column, '<>') != false + ) + { + $operator = ' '.substr(trim($column), -2).' '; + } + // Custom operators with 1 chars + elseif (strpos($column, '>') != false + || strpos($column, '<') != false + || strpos($column, '=') != false + ) + { + $operator = ' '.substr(trim($column), -1).' '; + } + else // default operator + { + $operator = ' = '; + } + + // If the column from the where clause is the same from the encrypted columns definition + if (trim($column) == $encryptedColumn + || ($operator != null && substr(trim($column), 0, strlen(trim($column)) - 2) == $encryptedColumn) + ) + { + // Then rename the column using the postgresql decryption function + $tmpWhere[sprintf( + self::CRYPT_WHERE_TEMPLATE, + $encryptedColumn, + $decryptionPassword, + $definition[self::CRYPT_CAST] + ).$operator] = $condition; + } + else // otherwise copy the column as it is + { + $tmpWhere[$column] = $condition; + } + } + + $where = $tmpWhere; // replace with the new where + } + // Otherwise if the where parameter is a valid string + elseif (!isEmptyString($where)) + { + // Find and replace all the occurrences of the provided encrypted columns + // with the postgresql decryption function + $where = str_replace( + $encryptedColumn, + sprintf( + self::CRYPT_WHERE_TEMPLATE, + $encryptedColumn, + $decryptionPassword, + $definition[self::CRYPT_CAST] + ), + $where + ); + } + } + } + } + } + } /** * Invalid ID @@ -877,11 +1128,11 @@ class DB_Model extends CI_Model { if ($id != null) { - $prepareUDFsWrite = $this->udflib->prepareUDFsWrite($data, $this->dbTable, $this->_getUDFsNoPerms($id)); + $prepareUDFsWrite = $this->udflib->prepareUDFsWrite($data, $schemaAndTable, $this->_getUDFsNoPerms($id)); } else { - $prepareUDFsWrite = $this->udflib->prepareUDFsWrite($data, $this->dbTable); + $prepareUDFsWrite = $this->udflib->prepareUDFsWrite($data, $schemaAndTable); } } @@ -895,7 +1146,7 @@ class DB_Model extends CI_Model * - A FALSE value on failure * - Otherwise an object filled with data on success */ - private function _toPhp($result) + private function _toPhp($result, $encryptedColumns = null) { $udfs = false; // if UDFs are inside the given result set $toPhp = $result; // if there is nothing to convert then return the result from DB @@ -911,7 +1162,9 @@ class DB_Model extends CI_Model // Looking for booleans, arrays and UDFs foreach ($this->executedQueryMetaData as $eqmd) { - // If array type, boolean type OR a UDF + // If array type, boolean type, numeric type + // Or bytea type + // Or UDF type if (strpos($eqmd->type, DB_Model::PGSQL_ARRAY_TYPE) !== false || $eqmd->type == DB_Model::PGSQL_BOOLEAN_TYPE || $eqmd->type == DB_Model::PGSQL_INT2_TYPE @@ -919,6 +1172,7 @@ class DB_Model extends CI_Model || $eqmd->type == DB_Model::PGSQL_INT8_TYPE || $eqmd->type == DB_Model::PGSQL_FLOAT4_TYPE || $eqmd->type == DB_Model::PGSQL_FLOAT8_TYPE + || $eqmd->type == DB_Model::PGSQL_BYTEA_TYPE || $this->udflib->isUDFColumn($eqmd->name, $eqmd->type)) { // If UDFs are inside this result set @@ -981,6 +1235,21 @@ class DB_Model extends CI_Model { $resultElement->{$toBeConverted->name} = $this->pgFloatPhp($resultElement->{$toBeConverted->name}); } + // Byte A type + elseif ($toBeConverted->type == DB_Model::PGSQL_BYTEA_TYPE) + { + // If encrypted columns are defined + // and if the byte a column is defined as encrypted column + if (!isEmptyArray($encryptedColumns) + && array_key_exists($toBeConverted->name, $encryptedColumns)) + { + // keep the column + } + else // otherwise remove the column from the result + { + unset($resultElement->{$toBeConverted->name}); + } + } } } } diff --git a/application/core/IEncryption.php b/application/core/IEncryption.php new file mode 100644 index 000000000..6b9132c23 --- /dev/null +++ b/application/core/IEncryption.php @@ -0,0 +1,24 @@ +. + */ + +interface IEncryption +{ + public function getEncryptedColumns(): array; +} + diff --git a/application/helpers/hlp_header_helper.php b/application/helpers/hlp_header_helper.php index 05bba48c4..ea1795ad5 100644 --- a/application/helpers/hlp_header_helper.php +++ b/application/helpers/hlp_header_helper.php @@ -96,7 +96,8 @@ function generateJSDataStorageObject($indexPage, $calledPath, $calledMethod) app_root: "'.APP_ROOT.'", ci_router: "'.$indexPage.'", called_path: "'.$calledPath.'", - called_method: "'.$calledMethod.'" + called_method: "'.$calledMethod.'", + user_language: "'.$user_language.'" };'; $toPrint .= "\n"; $toPrint .= ''; diff --git a/application/libraries/AntragLib.php b/application/libraries/AntragLib.php index ff4d5dc63..298c3652f 100644 --- a/application/libraries/AntragLib.php +++ b/application/libraries/AntragLib.php @@ -62,6 +62,24 @@ class AntragLib 'insertvon' => $insertvon ]); + // NOTE(chris): remove "preabbrecher" statusgrund for Stgl-Abmeldungen if set + $res = $this->_ci->StudierendenantragModel->load($antrag_id); + if (hasData($res) && current(getData($res))->typ == Studierendenantrag_model::TYP_ABMELDUNG_STGL) { + $this->_ci->PrestudentstatusModel->addSelect('tbl_status_grund.statusgrund_kurzbz'); + $res = $this->_ci->PrestudentstatusModel->getLastStatusWithStgEmail(current(getData($res))->prestudent_id, '', 'Student'); + if (hasData($res) && current(getData($res))->statusgrund_kurzbz == 'preabbrecher') { + $prestudentstatus = current(getData($res)); + $this->_ci->PrestudentstatusModel->update([ + 'prestudent_id' => $prestudentstatus->prestudent_id, + 'status_kurzbz'=>$prestudentstatus->status_kurzbz, + 'studiensemester_kurzbz'=>$prestudentstatus->studiensemester_kurzbz, + 'ausbildungssemester'=>$prestudentstatus->ausbildungssemester + ], [ + 'statusgrund_id' => null + ]); + } + } + return $result; } @@ -967,6 +985,7 @@ class AntragLib $studiengang_kz = $result->studiengang_kz; $orgform_kurzbz = $result->orgform_kurzbz; $ausbildungssemester = $result->ausbildungssemester; + $sprache = $result->sprache; // NOTE(chris): check permission $allowedStgs = $this->_ci->permissionlib->getSTG_isEntitledFor('student/studierendenantrag') ?: []; @@ -1012,11 +1031,12 @@ class AntragLib $semA, $ausbildungssemester + 1, $antrag->prestudent_id, - $antrag->studiensemester_kurzbz + $sprache ); if (isError($result)) return $result; $lvsA = $result->retval; // NOTE(chris): don't use getData() because we want to differenciate [] and null + $repeat_last = false; if ($lvsA) { foreach($lvsA as $lv) { @@ -1027,6 +1047,81 @@ class AntragLib $lv->antrag_anmerkung = $lvszugewiesen[$lv->lehrveranstaltung_id]->anmerkung; } } + } elseif ($lvsA === null) { + // NOTE(chris): We are repeating the last semester + $repeat_last = true; + + $result = $this->_ci->PrestudentstatusModel->getStatusByFilter($antrag->prestudent_id, 'Student', $ausbildungssemester - 1); + if (isError($result)) + return $result; + + $stdsems = getData($result) ?: []; + $stdsem = null; + + $result = $this->_ci->StudiensemesterModel->load($antrag->studiensemester_kurzbz); + if (isError($result)) + return $result; + if (!hasData($result)) + return error($this->_ci->p->t('studierendenantrag', 'error_no_stdsem', ['studiensemester_kurzbz' => $antrag->studiensemester_kurzbz])); + $asem = current(getData($result)); + + foreach ($stdsems as $sem) { + $result = $this->_ci->StudiensemesterModel->load($sem->studiensemester_kurzbz); + if (isError($result)) + return $result; + if (hasData($result)) { + if (current(getData($result))->start < $asem->start) { + $stdsem = $sem->studiensemester_kurzbz; + break; + } + } + } + + // NOTE(chris): if we don't find a status in the previous semester there is something wrong + if (!$stdsem) + return error($this->_ci->p->t('studierendenantrag', 'error_no_status_in_prev_sem')); + + $result = $this->getLvsByStgStsemAndSem( + $studiengang_kz, + $orgform_kurzbz, + $semA, + $ausbildungssemester - 1, + $antrag->prestudent_id, + $sprache + ); + if (isError($result)) + return $result; + + $lvsA = getData($result) ?: []; + + $result = $this->getLvsByStgStsemAndSem( + $studiengang_kz, + $orgform_kurzbz, + $stdsem, + $ausbildungssemester - 1, + $antrag->prestudent_id, + $sprache + ); + if (isError($result)) + return $result; + + $lvsAtest = getData($result) ?: []; + + if (count(array_intersect(array_map(function ($a) { + return $a->lehrveranstaltung_id; + }, $lvsA), array_map(function ($a) { + return $a->lehrveranstaltung_id; + }, $lvsAtest)))) { + foreach ($lvsA as $lv) { + if (isset($lvszugewiesen[$lv->lehrveranstaltung_id]) && ($lvszugewiesen[$lv->lehrveranstaltung_id]->note == 0)) { + $lv->antrag_anmerkung = $lvszugewiesen[$lv->lehrveranstaltung_id]->anmerkung; + $lv->antrag_zugelassen = true; + } + + } + } else { + $lvsA = null; + } } $result = $this->getLvsByStgStsemAndSem( @@ -1035,7 +1130,7 @@ class AntragLib $semB, $ausbildungssemester, $antrag->prestudent_id, - $antrag->studiensemester_kurzbz + $sprache ); if (isError($result)) return $result; @@ -1050,10 +1145,14 @@ class AntragLib // TODO(manu): eventuelle Änderungen taggen } - return success([ + $result = [ '1' . $semA => $lvsA, '2' . $semB => $lvsB ?: [] - ]); + ]; + if ($repeat_last) + $result['repeat_last'] = true; + + return success($result); } public function getLvsByStgStsemAndSem( @@ -1062,7 +1161,7 @@ class AntragLib $studiensemester_kurzbz, $ausbildungssemester, $prestudent_id, - $note_stsem + $sprache ) { $this->_ci->load->model('organisation/Studienplan_model', 'StudienplanModel'); @@ -1091,19 +1190,31 @@ class AntragLib 'semester' => $ausbildungssemester ])); } - if (count($result) > 1) - return error($this->_ci->p->t('studierendenantrag', 'error_multiple_studienplan', [ - 'studiengang_kz' => $studiengang_kz, - 'studiensemester_kurzbz' => $studiensemester_kurzbz, - 'semester' => $ausbildungssemester - ])); + if (count($result) > 1) { + $langmap = array_unique(array_map(function ($a) { + return $a->sprache; + }, $result)); + if ($sprache + && count($langmap) == count($result) + && in_array($sprache, $langmap) + ) { + $result = array_filter($result, function ($a) use ($sprache) { + return $a->sprache == $sprache; + }); + } else { + return error($this->_ci->p->t('studierendenantrag', 'error_multiple_studienplan', [ + 'studiengang_kz' => $studiengang_kz, + 'studiensemester_kurzbz' => $studiensemester_kurzbz, + 'semester' => $ausbildungssemester + ])); + } + } $studienplan = current($result); return $this->_ci->StudienplanModel->getStudienplanLehrveranstaltungForPrestudent( $studienplan->studienplan_id, $ausbildungssemester, - $prestudent_id, - $note_stsem + $prestudent_id ); } @@ -1138,7 +1249,7 @@ class AntragLib $result = current(getData($result)); $datumStatus = $result->datum; - if (!in_array($result->status_kurzbz, $this->_ci->config->item('antrag_prestudentstatus_whitelist'))) { + if (!in_array($result->status_kurzbz, $this->_ci->config->item('antrag_prestudentstatus_whitelist_abmeldung'))) { $result = $this->_ci->StudierendenantragModel->loadWithStatusWhere([ 'prestudent_id' => $prestudent_id, 'campus.get_status_studierendenantrag(studierendenantrag_id)' => Studierendenantragstatus_model::STATUS_APPROVED @@ -1388,6 +1499,8 @@ class AntragLib $resultDetails->grund = $resultAntrag->grund; $resultDetails->studierendenantrag_id = $resultAntrag->studierendenantrag_id; $resultDetails->typ = $resultAntrag->typ; + $resultDetails->datum = $resultAntrag->datum; + $resultDetails->studiensemester_kurzbz = $resultAntrag->studiensemester_kurzbz; return success($resultDetails); } @@ -1489,9 +1602,9 @@ class AntragLib ); } - public function getFailedExamForPrestudent($prestudent_id) + public function getFailedExamForPrestudent($prestudent_id, $max_date = null, $studiensemester_kurzbz = null) { - return $this->_ci->PruefungModel->loadWhereCommitteeExamFailedForPrestudent($prestudent_id); + return $this->_ci->PruefungModel->loadWhereCommitteeExamFailedForPrestudent($prestudent_id, $max_date, $studiensemester_kurzbz); } public function saveLvs($lvArray) @@ -1605,6 +1718,7 @@ class AntragLib if ($student_uid) { $email = $this->_ci->StudentModel->getEmailFH($student_uid); + $vorlage = 'Sancho_Mail_Antrag_W_Student'; $sem_not_allowed = $sem_to_repeat = ''; $list_not_allowed = $list_to_repeat = $this->_ci->p->t('studierendenantrag', 'mail_part_error_no_lvs'); @@ -1612,6 +1726,12 @@ class AntragLib $result = $this->getLvsForAntrag($antrag_id); if (hasData($result)) { $lvs = getData($result); + $repeat_last = false; + if (isset($lvs['repeat_last'])) { + $repeat_last = true; + unset($lvs['repeat_last']); + $vorlage .= '_Lst'; + } foreach ($lvs as $sem => $lv_list) { $lvs_filtered = array_filter($lv_list, function ($el) { return property_exists($el, 'antrag_zugelassen') && $el->antrag_zugelassen; @@ -1634,7 +1754,7 @@ class AntragLib // NOTE(chris): Sancho mail sendSanchoMail( - 'Sancho_Mail_Antrag_W_Student', + $vorlage, [ 'antrag_id' => $antrag_id, 'stg' => $stg->bezeichnung, diff --git a/application/libraries/FilterCmptLib.php b/application/libraries/FilterCmptLib.php index 9d6dfa681..8b13ae3e5 100644 --- a/application/libraries/FilterCmptLib.php +++ b/application/libraries/FilterCmptLib.php @@ -1,4 +1,5 @@ _setSessionElement(FilterCmptLib::SESSION_SIDE_MENU, - $this->_generateFilterMenu($this->_app, $this->_datasetName)); + $this->_setSessionElement( + FilterCmptLib::SESSION_SIDE_MENU, + $this->_generateFilterMenu($this->_app, $this->_datasetName) + ); } return $saveCustomFilter; @@ -717,6 +723,7 @@ class FilterCmptLib $this->_filterKurzbz = null; $this->_query = null; $this->_requiredPermissions = null; + $this->_encryptedColumns = null; $this->_reloadDataset = true; // by default the dataset is NOT cached in session $this->_sessionTimeout = FilterCmptLib::SESSION_DEFAULT_TIMEOUT; @@ -727,6 +734,12 @@ class FilterCmptLib $this->_requiredPermissions = $filterCmptArray[FilterCmptLib::REQUIRED_PERMISSIONS]; } + // Retrieved the encrypted columns parameter if present + if (isset($filterCmptArray[FilterCmptLib::ENCRYPTED_COLUMNS])) + { + $this->_encryptedColumns = $filterCmptArray[FilterCmptLib::ENCRYPTED_COLUMNS]; + } + // Parameters needed to retrieve univocally a filter from DB if (isset($filterCmptArray[FilterCmptLib::APP])) { @@ -1129,7 +1142,7 @@ class FilterCmptLib $this->_ci->load->model('system/Filters_model', 'FiltersModel'); // Execute the given SQL statement suppressing error messages - $dataset = @$this->_ci->FiltersModel->execReadOnlyQuery($datasetQuery); + $dataset = @$this->_ci->FiltersModel->execReadOnlyQuery($datasetQuery, null, $this->_encryptedColumns); } return $dataset; diff --git a/application/libraries/FilterWidgetLib.php b/application/libraries/FilterWidgetLib.php index 19cdec848..9968767d9 100644 --- a/application/libraries/FilterWidgetLib.php +++ b/application/libraries/FilterWidgetLib.php @@ -1,7 +1,26 @@ . + */ + if (! defined('BASEPATH')) exit('No direct script access allowed'); +use \stdClass as stdClass; + /** * FilterWidget logic */ @@ -16,6 +35,7 @@ class FilterWidgetLib const SESSION_SELECTED_FIELDS = 'selectedFields'; const SESSION_COLUMNS_ALIASES = 'columnsAliases'; const SESSION_ADDITIONAL_COLUMNS = 'additionalColumns'; + const SESSION_ENCRYPTED_COLUMNS = 'encryptedColumns'; const SESSION_CHECKBOXES = 'checkboxes'; const SESSION_FILTERS = 'filters'; const SESSION_METADATA = 'datasetMetadata'; @@ -56,6 +76,7 @@ class FilterWidgetLib const ADDITIONAL_COLUMNS = 'additionalColumns'; const CHECKBOXES = 'checkboxes'; const COLUMNS_ALIASES = 'columnsAliases'; + const ENCRYPTED_COLUMNS = 'encryptedColumns'; // ...to format/mark records of a dataset const FORMAT_ROW = 'formatRow'; @@ -120,7 +141,7 @@ class FilterWidgetLib /** * Gets the CI instance and loads message helper */ - public function __construct($params = null) + public function __construct() { $this->_ci =& get_instance(); // get code igniter instance } @@ -367,7 +388,7 @@ class FilterWidgetLib /** * Retrieves the dataset from the DB */ - public function getDataset($datasetQuery) + public function getDataset($datasetQuery, $encryptedColumns) { $dataset = null; @@ -376,7 +397,7 @@ class FilterWidgetLib $this->_ci->load->model('system/Filters_model', 'FiltersModel'); // Execute the given SQL statement suppressing error messages - $dataset = @$this->_ci->FiltersModel->execReadOnlyQuery($datasetQuery); + $dataset = @$this->_ci->FiltersModel->execReadOnlyQuery($datasetQuery, null, $encryptedColumns); } return $dataset; @@ -390,7 +411,7 @@ class FilterWidgetLib public function getFilterName($filterJson) { $filterName = $filterJson->name; // always present, used as default - $trimedname = (isset($filterJson->namePhrase)?trim($filterJson->namePhrase):''); + // Filter name from phrases system if (isset($filterJson->namePhrase) && !isEmptyString($filterJson->namePhrase)) { @@ -451,7 +472,8 @@ class FilterWidgetLib if (in_array($selectedField, $fields)) { // If the selected field is present in the list of the selected fields by the current filter - if (($pos = array_search($selectedField, $selectedFields)) !== false) + $pos = array_search($selectedField, $selectedFields); + if ($pos !== false) { // Then remove it and shift the rest of elements by one if needed array_splice($selectedFields, $pos, 1); @@ -750,7 +772,6 @@ class FilterWidgetLib $this->_ci->load->library('NavigationLib', array(self::NAVIGATION_PAGE => $navigationPage)); $filterMenu = null; - $currentMenu = $this->_ci->navigationlib->getSessionMenu(); // The navigation menu currently stored in session $session = $this->getSession(); // The filter currently stored in session (the one that is currently used) if ($session != null) diff --git a/application/libraries/SearchBarLib.php b/application/libraries/SearchBarLib.php index 3a9d06d13..7197eae6a 100644 --- a/application/libraries/SearchBarLib.php +++ b/application/libraries/SearchBarLib.php @@ -30,9 +30,10 @@ class SearchBarLib const ERROR_WRONG_SEARCHSTR = 'ERR002'; const ERROR_NO_TYPES = 'ERR003'; const ERROR_WRONG_TYPES = 'ERR004'; + const ERROR_NOT_AUTH = 'ERR005'; // List of allowed types of search - const ALLOWED_TYPES = ['mitarbeiter', 'organisationunit', 'raum', 'person', 'student', 'prestudent', 'document', 'cms']; + const ALLOWED_TYPES = ['mitarbeiter', 'mitarbeiter_ohne_zuordnung', 'organisationunit', 'raum', 'person', 'student', 'prestudent', 'document', 'cms']; const PHOTO_IMG_URL = '/cis/public/bild.php?src=person&person_id='; @@ -108,6 +109,92 @@ class SearchBarLib return $result; } + private function _mitarbeiter_ohne_zuordnung($searchstr, $type) + { + $dbModel = new DB_Model(); + + $sql = ' + SELECT + \''.$type.'\' AS type, + b.uid AS uid, + p.person_id AS person_id, + p.vorname || \' \' || p.nachname AS name, + ARRAY_AGG(DISTINCT(org.bezeichnung)) AS organisationunit_name, + COALESCE(b.alias, b.uid) || \''.'@'.DOMAIN.'\' AS email, + TRIM(COALESCE(k.kontakt, \'\') || \' \' || COALESCE(m.telefonklappe, \'\')) AS phone, + \''.base_url(self::PHOTO_IMG_URL).'\' || p.person_id AS photo_url, + ARRAY_AGG(DISTINCT(stdkst.bezeichnung)) AS standardkostenstelle + FROM public.tbl_mitarbeiter m + JOIN public.tbl_benutzer b ON(b.uid = m.mitarbeiter_uid) + LEFT JOIN ( + SELECT \'[\' || ot.bezeichnung || \'] \' || o.bezeichnung AS bezeichnung, bf.uid + FROM public.tbl_benutzerfunktion bf + JOIN public.tbl_organisationseinheit o USING(oe_kurzbz) + JOIN public.tbl_organisationseinheittyp ot USING(organisationseinheittyp_kurzbz) + WHERE bf.funktion_kurzbz = \'kstzuordnung\' + AND (bf.datum_von IS NULL OR bf.datum_von <= NOW()) + AND (bf.datum_bis IS NULL OR bf.datum_bis >= NOW()) + GROUP BY o.bezeichnung, ot.bezeichnung, bf.uid + ) stdkst ON stdkst.uid = b.uid + JOIN public.tbl_person p USING(person_id) + LEFT JOIN ( + SELECT \'[\' || ot.bezeichnung || \'] \' || o.bezeichnung AS bezeichnung, bf.uid + FROM public.tbl_benutzerfunktion bf + JOIN public.tbl_organisationseinheit o USING(oe_kurzbz) + JOIN public.tbl_organisationseinheittyp ot USING(organisationseinheittyp_kurzbz) + WHERE bf.funktion_kurzbz = \'oezuordnung\' + AND (bf.datum_von IS NULL OR bf.datum_von <= NOW()) + AND (bf.datum_bis IS NULL OR bf.datum_bis >= NOW()) + GROUP BY o.bezeichnung, ot.bezeichnung, bf.uid + ) org ON org.uid = b.uid + LEFT JOIN ( + SELECT kontakt, standort_id + FROM public.tbl_kontakt + WHERE kontakttyp = \'telefon\' + ) k ON(k.standort_id = m.standort_id) + WHERE + (stdkst.bezeichnung IS NULL + OR org.bezeichnung IS NULL) + AND ( + ' . + $this->buildSearchClause( + $dbModel, + array('b.uid', 'p.vorname', 'p.nachname'), + $searchstr + ) . + ' + ) + GROUP BY type, b.uid, p.person_id, name, email, m.telefonklappe, phone + '; + + $employees = $dbModel->execReadOnlyQuery($sql); + + // If something has been found then return it + if (hasData($employees)) return getData($employees); + + // Otherwise return an empty array + return array(); + } + + protected function buildSearchClause(DB_Model $dbModel, array $columns, $searchstr) + { + $document = implode(' || \' \' || ', $columns); + $query = '\'' . implode(':* & ', explode(' ', trim($searchstr))) . ':*\''; + $reversequery = '\'*:' . implode(' & *:', explode(' ', trim($searchstr))) . '\''; + $nospacequery = '\'' . implode('', explode(' ', trim($searchstr))) . ':*\''; + + $searchclause = <<= NOW()) - GROUP BY o.bezeichnung, bf.uid + GROUP BY o.bezeichnung, ot.bezeichnung, bf.uid ) stdkst ON stdkst.uid = b.uid JOIN public.tbl_person p USING(person_id) JOIN ( - SELECT o.bezeichnung, bf.uid + SELECT \'[\' || ot.bezeichnung || \'] \' || o.bezeichnung AS bezeichnung, bf.uid FROM public.tbl_benutzerfunktion bf JOIN public.tbl_organisationseinheit o USING(oe_kurzbz) + JOIN public.tbl_organisationseinheittyp ot USING(organisationseinheittyp_kurzbz) WHERE bf.funktion_kurzbz = \'oezuordnung\' AND (bf.datum_von IS NULL OR bf.datum_von <= NOW()) AND (bf.datum_bis IS NULL OR bf.datum_bis >= NOW()) - GROUP BY o.bezeichnung, bf.uid + GROUP BY o.bezeichnung, ot.bezeichnung, bf.uid ) org ON org.uid = b.uid LEFT JOIN ( SELECT kontakt, standort_id FROM public.tbl_kontakt WHERE kontakttyp = \'telefon\' ) k ON(k.standort_id = m.standort_id) - WHERE b.uid ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' - OR p.vorname ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' - OR p.nachname ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' - OR org.bezeichnung ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' - OR stdkst.bezeichnung ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' + WHERE ' . + $this->buildSearchClause( + $dbModel, + array('b.uid', 'p.vorname', 'p.nachname', 'org.bezeichnung', 'stdkst.bezeichnung'), + $searchstr + ) . + ' GROUP BY type, b.uid, p.person_id, name, email, m.telefonklappe, phone '); @@ -178,15 +269,17 @@ class SearchBarLib SELECT \''.$type.'\' AS type, o.oe_kurzbz AS oe_kurzbz, - o.bezeichnung AS name, + \'[\' || ot.bezeichnung || \'] \' || o.bezeichnung AS name, oParent.oe_kurzbz AS parentoe_kurzbz, - oParent.bezeichnung AS parentoe_name, + (CASE WHEN oParent.bezeichnung IS NOT NULL THEN \'[\' || otParent.bezeichnung || \'] \' || oParent.bezeichnung END) AS parentoe_name, ARRAY_AGG(DISTINCT(bfLeader.uid)) AS leader_uid, ARRAY_AGG(DISTINCT(bfLeader.vorname || \' \' || bfLeader.nachname)) AS leader_name, COUNT(bfCount.benutzerfunktion_id) AS number_of_people, (CASE WHEN o.mailverteiler = TRUE THEN o.oe_kurzbz || \''.'@'.DOMAIN.'\' END) AS mailgroup FROM public.tbl_organisationseinheit o + JOIN public.tbl_organisationseinheittyp ot USING(organisationseinheittyp_kurzbz) LEFT JOIN public.tbl_organisationseinheit oParent ON(oParent.oe_kurzbz = o.oe_parent_kurzbz) + LEFT JOIN public.tbl_organisationseinheittyp otParent ON(oParent.organisationseinheittyp_kurzbz = otParent.organisationseinheittyp_kurzbz) LEFT JOIN ( SELECT benutzerfunktion_id, oe_kurzbz FROM public.tbl_benutzerfunktion @@ -204,9 +297,14 @@ class SearchBarLib AND (datum_bis IS NULL OR datum_bis >= NOW()) AND b.aktiv = TRUE ) bfLeader ON(bfLeader.oe_kurzbz = o.oe_kurzbz) - WHERE o.oe_kurzbz ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' - OR o.bezeichnung ILIKE \'%'.$dbModel->escapeLike($searchstr).'%\' - GROUP BY type, o.oe_kurzbz, o.bezeichnung, oParent.oe_kurzbz, oParent.bezeichnung + WHERE ' . + $this->buildSearchClause( + $dbModel, + array('o.oe_kurzbz', 'o.bezeichnung', 'ot.bezeichnung'), + $searchstr + ) . + ' + GROUP BY type, o.oe_kurzbz, o.bezeichnung, ot.bezeichnung, oParent.oe_kurzbz, oParent.bezeichnung, otParent.bezeichnung '); // If something has been found diff --git a/application/libraries/TableWidgetLib.php b/application/libraries/TableWidgetLib.php index dc746b6d5..3af99cca7 100644 --- a/application/libraries/TableWidgetLib.php +++ b/application/libraries/TableWidgetLib.php @@ -1,5 +1,22 @@ . + */ + if (! defined('BASEPATH')) exit('No direct script access allowed'); /** @@ -16,6 +33,7 @@ class TableWidgetLib const SESSION_FIELDS = 'fields'; const SESSION_COLUMNS_ALIASES = 'columnsAliases'; const SESSION_ADDITIONAL_COLUMNS = 'additionalColumns'; + const SESSION_ENCRYPTED_COLUMNS = 'encryptedColumns'; const SESSION_CHECKBOXES = 'checkboxes'; const SESSION_METADATA = 'datasetMetadata'; const SESSION_ROW_NUMBER = 'rowNumber'; @@ -49,6 +67,7 @@ class TableWidgetLib const ADDITIONAL_COLUMNS = 'additionalColumns'; const CHECKBOXES = 'checkboxes'; const COLUMNS_ALIASES = 'columnsAliases'; + const ENCRYPTED_COLUMNS = 'encryptedColumns'; // ...to format/mark records of a dataset const FORMAT_ROW = 'formatRow'; @@ -74,7 +93,7 @@ class TableWidgetLib /** * Gets the CI instance and loads message helper */ - public function __construct($params = null) + public function __construct() { $this->_ci =& get_instance(); // get code igniter instance } @@ -177,7 +196,7 @@ class TableWidgetLib /** * Retrieves the dataset from the DB */ - public function getDataset($datasetQuery) + public function getDataset($datasetQuery, $encryptedColumns) { $dataset = null; @@ -186,7 +205,7 @@ class TableWidgetLib $this->_ci->load->model('system/Filters_model', 'FiltersModel'); // Execute the given SQL statement suppressing error messages - $dataset = @$this->_ci->FiltersModel->execReadOnlyQuery($datasetQuery); + $dataset = @$this->_ci->FiltersModel->execReadOnlyQuery($datasetQuery, null, $encryptedColumns); } return $dataset; diff --git a/application/libraries/vertragsbestandteil/AbstractBestandteil.php b/application/libraries/vertragsbestandteil/AbstractBestandteil.php new file mode 100644 index 000000000..ccd05f5e2 --- /dev/null +++ b/application/libraries/vertragsbestandteil/AbstractBestandteil.php @@ -0,0 +1,69 @@ +isvalid = false; + $this->validationerrors = array(); + + $this->modifiedcolumns = array(); + $this->fromdb = false; + } + + public function isDirty() { + return count($this->modifiedcolumns) > 0; + } + + protected function markDirty($columnname, $old_value, $new_value) { + if( $this->fromdb ) { + // data comes from db dont check for changes + if( isset($this->modifiedcolumns[$columnname]) ) { + unset($this->modifiedcolumns[$columnname]); + } + return; + } + + if( is_bool($new_value) && ($old_value !== $new_value) ) { + $this->modifiedcolumns[$columnname] = $columnname; + } else if($old_value != $new_value) { + $this->modifiedcolumns[$columnname] = $columnname; + } + } + + public function isValid() + { + return $this->isvalid; + } + + public function getValidationErrors() + { + return $this->validationerrors; + } + + + public function addValidationError($errormsg) + { + if( !in_array($errormsg, $this->validationerrors, true) ) + { + $this->validationerrors[] = $errormsg; + } + $this->isvalid = false; + } + + abstract public function hydrateByStdClass($data, $fromdb=false); +} diff --git a/application/libraries/vertragsbestandteil/Dienstverhaeltnis.php b/application/libraries/vertragsbestandteil/Dienstverhaeltnis.php new file mode 100644 index 000000000..5745c2196 --- /dev/null +++ b/application/libraries/vertragsbestandteil/Dienstverhaeltnis.php @@ -0,0 +1,265 @@ +checkoverlap = true; + } + + public function hydrateByStdClass($data, $fromdb=false) + { + $this->fromdb = $fromdb; + isset($data->dienstverhaeltnis_id) && $this->setDienstverhaeltnis_id($data->dienstverhaeltnis_id); + isset($data->mitarbeiter_uid) && $this->setMitarbeiter_uid($data->mitarbeiter_uid); + isset($data->vertragsart_kurzbz) && $this->setVertragsart_kurzbz($data->vertragsart_kurzbz); + isset($data->checkoverlap) && $this->setCheckoverlap($data->checkoverlap); + isset($data->oe_kurzbz) && $this->setOe_kurzbz($data->oe_kurzbz); + isset($data->von) && $this->setVon($data->von); + isset($data->bis) && $this->setBis($data->bis); + isset($data->insertamum) && $this->setInsertamum($data->insertamum); + isset($data->insertvon) && $this->setInsertvon($data->insertvon); + isset($data->updateamum) && $this->setUpdateamum($data->updateamum); + isset($data->updatevon) && $this->setUpdatevon($data->updatevon); + $this->fromdb = false; + } + + public function toStdClass(): \stdClass + { + $tmp = array( + 'dienstverhaeltnis_id' => $this->getDienstverhaeltnis_id(), + 'mitarbeiter_uid' => $this->getMitarbeiter_uid(), + 'vertragsart_kurzbz' => $this->getVertragsart_kurzbz(), + 'oe_kurzbz' => $this->getOe_kurzbz(), + 'von' => $this->getVon(), + 'bis' => $this->getBis(), + 'insertamum' => $this->getInsertamum(), + 'insertvon' => $this->getInsertvon(), + 'updateamum' => $this->getUpdateamum(), + 'updatevon' => $this->getUpdatevon() + ); + + $tmp = array_filter($tmp, function($k) { + return in_array($k, $this->modifiedcolumns); + }, ARRAY_FILTER_USE_KEY); + + return (object) $tmp; + } + + + public function __toString() + { + $txt = <<getDienstverhaeltnis_id()} + mitarbeiter_uid: {$this->getMitarbeiter_uid()} + vertragsart_kurzbz: {$this->getVertragsart_kurzbz()} + oe_kurzbz: {$this->getOe_kurzbz()} + von: {$this->getVon()} + bis: {$this->getBis()} + +EOTXT; + return $txt; + } + + public function getDienstverhaeltnis_id() + { + return $this->dienstverhaeltnis_id; + } + + public function getMitarbeiter_uid() + { + return $this->mitarbeiter_uid; + } + + public function getVertragsart_kurzbz() + { + return $this->vertragsart_kurzbz; + } + + public function getOe_kurzbz() + { + return $this->oe_kurzbz; + } + + public function getVon() + { + return $this->von; + } + + public function getBis() + { + return $this->bis; + } + + public function getInsertamum() + { + return $this->insertamum; + } + + public function getInsertvon() + { + return $this->insertvon; + } + + public function getUpdateamum() + { + return $this->updateamum; + } + + public function getUpdatevon() + { + return $this->updatevon; + } + + public function setDienstverhaeltnis_id($dienstverhaeltnis_id) + { + $this->markDirty('dienstverhaeltnis_id', $this->dienstverhaeltnis_id, $dienstverhaeltnis_id); + $this->dienstverhaeltnis_id = $dienstverhaeltnis_id; + return $this; + } + + public function setMitarbeiter_uid($mitarbeiter_uid) + { + $this->markDirty('mitarbeiter_uid', $this->mitarbeiter_uid, $mitarbeiter_uid); + $this->mitarbeiter_uid = $mitarbeiter_uid; + return $this; + } + + public function setVertragsart_kurzbz($vertragsart_kurzbz) + { + $this->markDirty('vertragsart_kurzbz', $this->vertragsart_kurzbz, $vertragsart_kurzbz); + $this->vertragsart_kurzbz = $vertragsart_kurzbz; + return $this; + } + + public function setCheckoverlap(bool $checkoverlap) + { + $this->checkoverlap = $checkoverlap; + } + + public function setOe_kurzbz($oe_kurzbz) + { + $this->markDirty('oe_kurzbz', $this->oe_kurzbz, $oe_kurzbz); + $this->oe_kurzbz = $oe_kurzbz; + return $this; + } + + public function setVon($von) + { + $this->markDirty('von', $this->von, $von); + $this->von = $von; + return $this; + } + + public function setBis($bis) + { + $this->markDirty('bis', $this->bis, $bis); + $this->bis = $bis; + return $this; + } + + public function setInsertamum($insertamum) + { + $this->markDirty('insertamum', $this->insertamum, $insertamum); + $this->insertamum = $insertamum; + return $this; + } + + public function setInsertvon($insertvon) + { + $this->markDirty('insertvon', $this->insertvon, $insertvon); + $this->insertvon = $insertvon; + return $this; + } + + public function setUpdateamum($updateamum) + { + $this->markDirty('updateamum', $this->updateamum, $updateamum); + $this->updateamum = $updateamum; + return $this; + } + + public function setUpdatevon($updatevon) + { + $this->markDirty('updatevon', $this->updatevon, $updatevon); + $this->updatevon = $updatevon; + return $this; + } + + public function validate() { + //do Validation here + $ci = get_instance(); + $ci->load->library('vertragsbestandteil/VertragsbestandteilLib', + null, 'VertragsbestandteilLib'); + + if( empty($this->mitarbeiter_uid) ) { + $this->validationerrors[] = 'Mitarbeiter_UID fehlt.'; + } + + if( empty($this->oe_kurzbz) ) { + $this->validationerrors[] = 'Unternehmen fehlt.'; + } + + if( empty($this->vertragsart_kurzbz) ) { + $this->validationerrors[] = 'Vertragsart fehlt.'; + } + + $von = \DateTimeImmutable::createFromFormat('Y-m-d', $this->von); + $bis = \DateTimeImmutable::createFromFormat('Y-m-d', $this->bis); + + if( false === $von ) { + $this->validationerrors[] = 'Beginn muss ein gültiges Datum sein.'; + } + + if( $this->bis !== null && $bis === false ) { + $this->validationerrors[] = 'Ende muss ein gültiges Datum oder leer sein.'; + } + + if( $this-> bis !== null && $von && $bis && $von > $bis ) { + $this->validationerrors[] = 'Das Beginndatum muss vor dem Endedatum liegen.'; + } + + if( $this->checkoverlap && !($this->vertragsart_kurzbz === 'werkvertrag') + && $ci->VertragsbestandteilLib->isOverlappingExistingDV($this) ) + { + $this->validationerrors[] = 'Es existiert bereits ein überlappendes Dienstverhältnis'; + } + + // return status after Validation + if( count($this->validationerrors) > 0 ) { + $this->isvalid = false; + } else { + $this->isvalid = true; + } + + return $this->isvalid; + } +} \ No newline at end of file diff --git a/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php b/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php new file mode 100644 index 000000000..22f8ee2ae --- /dev/null +++ b/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php @@ -0,0 +1,360 @@ +fromdb = $fromdb; + isset($data->gehaltsbestandteil_id) && $this->setGehaltsbestandteil_id($data->gehaltsbestandteil_id); + isset($data->dienstverhaeltnis_id) && $this->setDienstverhaeltnis_id($data->dienstverhaeltnis_id); + isset($data->vertragsbestandteil_id) && $this->setVertragsbestandteil_id($data->vertragsbestandteil_id); + isset($data->gehaltstyp_kurzbz) && $this->setGehaltstyp_kurzbz($data->gehaltstyp_kurzbz); + isset($data->von) && $this->setVon($data->von); + isset($data->bis) && $this->setBis($data->bis); + isset($data->anmerkung) && $this->setAnmerkung($data->anmerkung); + isset($data->grundbetrag) && $this->setGrundbetrag($data->grundbetrag); + isset($data->betrag_valorisiert) && $this->setBetrag_valorisiert($data->betrag_valorisiert); + isset($data->valorisierungssperre) && $this->setValorisierungssperre($data->valorisierungssperre); + isset($data->valorisierung) && $this->setValorisierung($data->valorisierung); + isset($data->auszahlungen) && $this->setAuszahlungen($data->auszahlungen); + + isset($data->insertamum) && $this->setInsertamum($data->insertamum); + isset($data->insertvon) && $this->setInsertvon($data->insertvon); + isset($data->updateamum) && $this->setUpdateamum($data->updateamum); + isset($data->updatevon) && $this->setUpdatevon($data->updatevon); + $this->fromdb = false; + } + + public function getGehaltsbestandteil_id() + { + return $this->gehaltsbestandteil_id; + } + + public function getDienstverhaeltnis_id() + { + return $this->dienstverhaeltnis_id; + } + + public function getVertragsbestandteil_id() + { + return $this->vertragsbestandteil_id; + } + + public function getGehaltstyp_kurzbz() + { + return $this->gehaltstyp_kurzbz; + } + + public function getVon() + { + return $this->von; + } + + public function getBis() + { + return $this->bis; + } + + public function getVonDateTime() + { + return $this->toDateTime($this->von); + } + + public function getBisDateTime() + { + return $this->toDateTime($this->bis); + } + + protected function toDateTime($d) { + if ($d == null) return null; + return new DateTimeImmutable($d); + } + + public function getAnmerkung() + { + return $this->anmerkung; + } + + public function getGrundbetrag() + { + return $this->grundbetrag; + } + + public function getBetrag_valorisiert() + { + return $this->betrag_valorisiert; + } + + public function getValorisierungssperre() + { + return $this->valorisierungssperre; + } + + public function getValorisierung() + { + return $this->valorisierung; + } + + public function getAuszahlungen() + { + return $this->auszahlungen; + } + + public function getInsertamum() + { + return $this->insertamum; + } + + public function getInsertvon() + { + return $this->insertvon; + } + + public function getUpdateamum() + { + return $this->updateamum; + } + + public function getUpdatevon() + { + return $this->updatevon; + } + + public function setGehaltsbestandteil_id($gehaltsbestandteil_id) + { + $this->markDirty('gehaltsbestandteil_id', $this->gehaltsbestandteil_id, $gehaltsbestandteil_id); + $this->gehaltsbestandteil_id = $gehaltsbestandteil_id; + return $this; + } + + public function setDienstverhaeltnis_id($dienstverhaeltnis_id) + { + $this->markDirty('dienstverhaeltnis_id', $this->dienstverhaeltnis_id, $dienstverhaeltnis_id); + $this->dienstverhaeltnis_id = $dienstverhaeltnis_id; + return $this; + } + + public function setVertragsbestandteil_id($vertragsbestandteil_id) + { + $this->markDirty('vertragsbestandteil_id', $this->vertragsbestandteil_id, $vertragsbestandteil_id); + $this->vertragsbestandteil_id = $vertragsbestandteil_id; + return $this; + } + + public function setGehaltstyp_kurzbz($gehaltstyp_kurzbz) + { + $this->markDirty('gehaltstyp_kurzbz', $this->gehaltstyp_kurzbz, $gehaltstyp_kurzbz); + $this->gehaltstyp_kurzbz = $gehaltstyp_kurzbz; + return $this; + } + + public function setVon($von) + { + $this->markDirty('von', $this->von, $von); + $this->von = $von; + return $this; + } + + public function setBis($bis) + { + $this->markDirty('bis', $this->bis, $bis); + $this->bis = $bis; + return $this; + } + + public function setAnmerkung($anmerkung) + { + $this->markDirty('anmerkung', $this->anmerkung, $anmerkung); + $this->anmerkung = $anmerkung; + return $this; + } + + public function setGrundbetrag($grundbetrag) + { + $this->markDirty('grundbetrag', $this->grundbetrag, $grundbetrag); + $this->grundbetrag = $grundbetrag; + return $this; + } + + public function setBetrag_valorisiert($betrag_valorisiert) + { + $this->markDirty('betrag_valorisiert', $this->betrag_valorisiert, $betrag_valorisiert); + $this->betrag_valorisiert = $betrag_valorisiert; + return $this; + } + + public function setValorisierungssperre($valorisierungssperre) + { + $this->markDirty('valorisierungssperre', $this->valorisierungssperre, $valorisierungssperre); + $this->valorisierungssperre = $valorisierungssperre; + return $this; + } + + public function setValorisierung($valorisierung) + { + $this->markDirty('valorisierung', $this->valorisierung, $valorisierung); + $this->valorisierung = $valorisierung; + return $this; + } + + public function setAuszahlungen($auszahlungen) + { + $this->markDirty('auszahlungen', $this->auszahlungen, $auszahlungen); + $this->auszahlungen = $auszahlungen; + return $this; + } + + public function setInsertamum($insertamum) + { + $this->markDirty('insertamum', $this->insertamum, $insertamum); + $this->insertamum = $insertamum; + return $this; + } + + public function setInsertvon($insertvon) + { + $this->markDirty('insertvon', $this->insertvon, $insertvon); + $this->insertvon = $insertvon; + return $this; + } + + public function setUpdateamum($updateamum) + { + $this->markDirty('updateamum', $this->updateamum, $updateamum); + $this->updateamum = $updateamum; + return $this; + } + + public function setUpdatevon($updatevon) + { + $this->markDirty('updatevon', $this->updatevon, $updatevon); + $this->updatevon = $updatevon; + return $this; + } + + public function jsonSerialize() + { + $vars = get_object_vars($this); + unset($vars['CI']); + return $vars; + } + + public function toStdClass(): \stdClass + { + $tmp = array( + 'gehaltsbestandteil_id' => $this->getGehaltsbestandteil_id(), + 'dienstverhaeltnis_id' => $this->getDienstverhaeltnis_id(), + 'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(), + 'gehaltstyp_kurzbz' => $this->getGehaltstyp_kurzbz(), + 'von' => $this->getVon(), + 'bis' => $this->getBis(), + 'anmerkung' => $this->getAnmerkung(), + 'grundbetrag' => $this->getGrundbetrag(), + 'betrag_valorisiert' => $this->getBetrag_valorisiert(), + 'valorisierungssperre' => $this->getValorisierungssperre(), + 'valorisierung' => $this->getValorisierung(), + 'auszahlungen' => $this->getAuszahlungen(), + 'insertamum' => $this->getInsertamum(), + 'insertvon' => $this->getInsertvon(), + 'updateamum' => $this->getUpdateamum(), + 'updatevon' => $this->getUpdatevon() + ); + + $tmp = array_filter($tmp, function($k) { + return in_array($k, $this->modifiedcolumns); + }, ARRAY_FILTER_USE_KEY); + + return (object) $tmp; + } + + public function __toString() + { + $txt = <<getGehaltsbestandteil_id()} + dienstverhaeltnis_id: {$this->getDienstverhaeltnis_id()} + vertragsbestandteil_id: {$this->getVertragsbestandteil_id()} + gehaltstyp_kurzbz: {$this->getGehaltstyp_kurzbz()} + von: {$this->getVon()} + bis: {$this->getBis()} + anmerkung: {$this->getAnmerkung()} + grundbetrag: {$this->getGrundbetrag()} + betrag_valorisiert: {$this->getBetrag_valorisiert()} + valorisierungssperre: {$this->getValorisierungssperre()} + valorisierung: {$this->getValorisierung()} + auszahlungen: {$this->getAuszahlungen()} + insertamum: {$this->getInsertamum()} + insertvon: {$this->getInsertvon()} + updateamum: {$this->getUpdateamum()} + updatevon: {$this->getUpdatevon()} + +EOTXT; + return $txt; + } + + public function validate() { + //do Validation here + if( empty($this->gehaltstyp_kurzbz) ) + { + $this->validationerrors[] = "Ein Gehaltstyp muss ausgewählt sein."; + } + + if( empty($this->grundbetrag) ) + { + $this->validationerrors[] = "Betrag fehlt."; + } + + $von = \DateTimeImmutable::createFromFormat('Y-m-d', $this->von); + $bis = \DateTimeImmutable::createFromFormat('Y-m-d', $this->bis); + + if( false === $von ) { + $this->validationerrors[] = 'Beginn muss ein gültiges Datum sein.'; + } + + if( $this->bis !== null && $bis === false ) { + $this->validationerrors[] = 'Ende muss ein gültiges Datum oder leer sein.'; + } + + if( $this-> bis !== null && $von && $bis && $von > $bis ) { + $this->validationerrors[] = 'Das Beginndatum muss vor dem Endedatum liegen.'; + } + + // return status after Validation + if( count($this->validationerrors) > 0 ) { + $this->isvalid = false; + } else { + $this->isvalid = true; + } + + return $this->isvalid; + } +} diff --git a/application/libraries/vertragsbestandteil/GehaltsbestandteilLib.php b/application/libraries/vertragsbestandteil/GehaltsbestandteilLib.php new file mode 100644 index 000000000..b75bdd722 --- /dev/null +++ b/application/libraries/vertragsbestandteil/GehaltsbestandteilLib.php @@ -0,0 +1,149 @@ +loggedInUser = getAuthUID(); + $this->CI = get_instance(); + $this->CI->load->model('vertragsbestandteil/Gehaltsbestandteil_model', + 'GehaltsbestandteilModel'); + $this->CI->load->library('extensions/FHC-Core-Personalverwaltung/abrechnung/GehaltsLib'); + $this->GehaltsbestandteilModel = $this->CI->GehaltsbestandteilModel; + } + + public function fetchGehaltsbestandteile($dienstverhaeltnis_id, $stichtag=null, $includefuture=false) + { + return $this->GehaltsbestandteilModel->getGehaltsbestandteile($dienstverhaeltnis_id, $stichtag, $includefuture); + } + + public function fetchGehaltsbestandteil($gehaltsbestandteil_id) + { + return $this->GehaltsbestandteilModel->getGehaltsbestandteil($gehaltsbestandteil_id); + } + + public function storeGehaltsbestandteile($gehaltsbestandteile) + { + foreach( $gehaltsbestandteile as $gehaltsbestandteil ) + { + $this->storeGehaltsbestandteil($gehaltsbestandteil); + } + } + + public function storeGehaltsbestandteil(Gehaltsbestandteil $gehaltsbestandteil) + { + try + { + $this->setUIDtoPGSQL(); + if( intval($gehaltsbestandteil->getGehaltsbestandteil_id()) > 0 ) + { + $this->updateGehaltsbestandteil($gehaltsbestandteil); + } + else + { + $this->insertGehaltsbestandteil($gehaltsbestandteil); + } + } + catch (Exception $ex) + { + log_message('debug', "Storing Gehaltsbestandteil failed. " . $ex->getMessage()); + throw new Exception('Storing Gehaltsbestandteil failed.'); + } + } + + protected function insertGehaltsbestandteil(Gehaltsbestandteil $gehaltsbestandteil) + { + $gehaltsbestandteil->setInsertvon($this->loggedInUser) + ->setInsertamum(strftime('%Y-%m-%d %H:%M:%S')); + $ret = $this->GehaltsbestandteilModel->insert($gehaltsbestandteil->toStdClass(), + $this->GehaltsbestandteilModel->getEncryptedColumns()); + if( hasData($ret) ) + { + $gehaltsbestandteil->setGehaltsbestandteil_id(getData($ret)); + } + else + { + throw new Exception('error inserting gehaltsbestandteil'); + } + } + + protected function updateGehaltsbestandteil(Gehaltsbestandteil $gehaltsbestandteil) + { + if(!$gehaltsbestandteil->isDirty()) { + return; + } + + $gehaltsbestandteil->setUpdatevon($this->loggedInUser) + ->setUpdateamum(strftime('%Y-%m-%d %H:%M:%S')); + $ret = $this->GehaltsbestandteilModel->update($gehaltsbestandteil->getGehaltsbestandteil_id(), + $gehaltsbestandteil->toStdClass(), + $this->GehaltsbestandteilModel->getEncryptedColumns()); + + if(isError($ret) ) + { + throw new Exception('error updating gehaltsbestandteil'); + } + } + + public function deleteGehaltsbestandteile($gehaltsbestandteile) + { + foreach( $gehaltsbestandteile as $gehaltsbestandteil ) + { + $this->deleteGehaltsbestandteil($gehaltsbestandteil); + } + } + + public function deleteGehaltsbestandteil(Gehaltsbestandteil $gehaltsbestandteil) + { + $this->setUIDtoPGSQL(); + + // delete Gehaltsabrechnung + $ret = $this->CI->gehaltslib->deleteAbrechnung($gehaltsbestandteil); + + // + $ret = $this->GehaltsbestandteilModel->delete($gehaltsbestandteil->getGehaltsbestandteil_id()); + + if (isError($ret)) + { + throw new Exception('error deleting gehaltsbestandteil'); + } + } + + public function endGehaltsbestandteil(Gehaltsbestandteil $gehaltsbestandteil, $enddate) + { + $this->setUIDtoPGSQL(); + if( $gehaltsbestandteil->getBis() !== null && $gehaltsbestandteil->getBis() < $enddate ) + { + return; + } + + $gehaltsbestandteil->setBis($enddate); + $this->updateGehaltsbestandteil($gehaltsbestandteil); + } + + protected function setUIDtoPGSQL() { + $ret = $this->GehaltsbestandteilModel + ->execReadOnlyQuery('SET LOCAL pv21.uid TO \'' + . $this->loggedInUser . '\''); + if(isError($ret)) + { + throw new Exception('error setting uid to pgsql'); + } + } +} diff --git a/application/libraries/vertragsbestandteil/IValidation.php b/application/libraries/vertragsbestandteil/IValidation.php new file mode 100644 index 000000000..c55e33bcd --- /dev/null +++ b/application/libraries/vertragsbestandteil/IValidation.php @@ -0,0 +1,18 @@ +CI = get_instance(); + $this->CI->load->model('vertragsbestandteil/Vertragsbestandteil_model', + 'VertragsbestandteilModel'); + $this->VertragsbestandteilModel = $this->CI->VertragsbestandteilModel; + $this->CI->load->model('vertragsbestandteil/VertragsbestandteilFreitext_model', + 'VertragsbestandteilFreitextModel'); + $this->VertragsbestandteilFreitextModel = $this->CI->VertragsbestandteilFreitextModel; + $this->CI->load->model('vertragsbestandteil/Vertragsbestandteiltyp_model', + 'VertragsbestandteilTypModel'); + $this->VertragsbestandteilTypModel = $this->CI->VertragsbestandteilTypModel; + $this->CI->load->model('vertragsbestandteil/VertragsbestandteilFreitexttyp_model', + 'VertragsbestandteilFreitexttypModel'); + $this->VertragsbestandteilFreitexttypModel = $this->CI->VertragsbestandteilFreitexttypModel; + } + + public function overlapsVB(Vertragsbestandteil $vb) + { + $result = $this->VertragsbestandteilTypModel->load($vb->getVertragsbestandteiltyp_kurzbz()); + if( null === ($vertragsbestandteiltyp = getData($result)) ) + { + throw new Exception('vertragsbestandteiltyp: ' + . $vb->getVertragsbestandteiltyp_kurzbz() . ' not found.'); + } + + if( true === $vertragsbestandteiltyp[0]->ueberlappend ) + { + // vertragsbestandteiltyp can overlap + return false; + } + + if( $this->VertragsbestandteilModel->countOverlappingVBsOfSameType($vb) === 0 ) + { + return false; + } + else + { + return true; + } + } + + public function overlapsFreitext(VertragsbestandteilFreitext $vbft) + { + $result = $this->VertragsbestandteilFreitexttypModel->load($vbft->getFreitexttypKurzbz()); + if( null === ($vertragsbestandteilfreitexttyp = getData($result)) ) + { + throw new Exception('vertragsbestandteilfreitexttyp: ' + . $vbft->getFreitexttypKurzbz() . ' not found.'); + } + + if( true === $vertragsbestandteilfreitexttyp[0]->ueberlappend ) + { + // freitexttyp can overlap + return false; + } + + if( $this->VertragsbestandteilFreitextModel->countOverlappingVBFreitextsOfSameType($vbft) === 0 ) + { + return false; + } + else + { + return true; + } + } + + private function __clone() {} +} diff --git a/application/libraries/vertragsbestandteil/Vertragsbestandteil.php b/application/libraries/vertragsbestandteil/Vertragsbestandteil.php new file mode 100644 index 000000000..bf5ec6211 --- /dev/null +++ b/application/libraries/vertragsbestandteil/Vertragsbestandteil.php @@ -0,0 +1,265 @@ +gehaltsbestandteile = array(); + } + + public function hydrateByStdClass($data, $fromdb=false) + { + $this->fromdb = $fromdb; + isset($data->vertragsbestandteil_id) && $this->setVertragsbestandteil_id($data->vertragsbestandteil_id); + isset($data->dienstverhaeltnis_id) && $this->setDienstverhaeltnis_id($data->dienstverhaeltnis_id); + isset($data->von) && $this->setVon($data->von); + isset($data->bis) && $this->setBis($data->bis); + isset($data->vertragsbestandteiltyp_kurzbz) && $this->setVertragsbestandteiltyp_kurzbz($data->vertragsbestandteiltyp_kurzbz); + isset($data->insertamum) && $this->setInsertamum($data->insertamum); + isset($data->insertvon) && $this->setInsertvon($data->insertvon); + isset($data->updateamum) && $this->setUpdateamum($data->updateamum); + isset($data->updatevon) && $this->setUpdatevon($data->updatevon); + $this->fromdb = false; + } + + public function addGehaltsbestandteil(Gehaltsbestandteil $gehaltsbestandteil) + { + $gehaltsbestandteil->setDienstverhaeltnis_id($this->getDienstverhaeltnis_id()); + $gehaltsbestandteil->setVertragsbestandteil_id($this->getVertragsbestandteil_id()); + $this->gehaltsbestandteile[] = $gehaltsbestandteil; + return $this; + } + + public function getGehaltsbestandteile() + { + return $this->gehaltsbestandteile; + } + + public function getVertragsbestandteil_id() + { + return $this->vertragsbestandteil_id; + } + + public function getDienstverhaeltnis_id() + { + return $this->dienstverhaeltnis_id; + } + + public function getVon() + { + return $this->von; + } + + public function getBis() + { + return $this->bis; + } + + public function getVertragsbestandteiltyp_kurzbz() + { + return $this->vertragsbestandteiltyp_kurzbz; + } + + public function getInsertamum() + { + return $this->insertamum; + } + + public function getInsertvon() + { + return $this->insertvon; + } + + public function getUpdateamum() + { + return $this->updateamum; + } + + public function getUpdatevon() + { + return $this->updatevon; + } + + public function setGehaltsbestandteile($gehaltsbestandteile) + { + $this->gehaltsbestandteile = $gehaltsbestandteile; + return $this; + } + + public function setVertragsbestandteil_id($vertragsbestandteil_id) + { + $this->markDirty('vertragsbestandteil_id', $this->vertragsbestandteil_id, $vertragsbestandteil_id); + $this->vertragsbestandteil_id = $vertragsbestandteil_id; + foreach ($this->gehaltsbestandteile as $gehaltsbestandteil) + { + $gehaltsbestandteil->setVertragsbestandteil_id($vertragsbestandteil_id); + } + return $this; + } + + public function setDienstverhaeltnis_id($dienstverhaeltnis_id) + { + $this->markDirty('dienstverhaeltnis_id', $this->dienstverhaeltnis_id, $dienstverhaeltnis_id); + $this->dienstverhaeltnis_id = $dienstverhaeltnis_id; + foreach ($this->gehaltsbestandteile as $gehaltsbestandteil) + { + $gehaltsbestandteil->setDienstverhaeltnis_id($dienstverhaeltnis_id); + } + return $this; + } + + public function setVon($von) + { + $this->markDirty('von', $this->von, $von); + $this->von = $von; + return $this; + } + + public function setBis($bis) + { + $this->markDirty('bis', $this->bis, $bis); + $this->bis = $bis; + return $this; + } + + public function setVertragsbestandteiltyp_kurzbz($vertragsbestandteiltyp_kurzbz) + { + $this->markDirty('vertragsbestandteiltyp_kurzbz', $this->vertragsbestandteiltyp_kurzbz, $vertragsbestandteiltyp_kurzbz); + $this->vertragsbestandteiltyp_kurzbz = $vertragsbestandteiltyp_kurzbz; + return $this; + } + + public function setInsertamum($insertamum) + { + $this->markDirty('insertamum', $this->insertamum, $insertamum); + $this->insertamum = $insertamum; + return $this; + } + + public function setInsertvon($insertvon) + { + $this->markDirty('insertvon', $this->insertvon, $insertvon); + $this->insertvon = $insertvon; + return $this; + } + + public function setUpdateamum($updateamum) + { + $this->markDirty('updateamum', $this->updateamum, $updateamum); + $this->updateamum = $updateamum; + return $this; + } + + public function setUpdatevon($updatevon) + { + $this->markDirty('updatevon', $this->updatevon, $updatevon); + $this->updatevon = $updatevon; + return $this; + } + + public function baseToStdClass() { + $tmp = array( + 'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(), + 'dienstverhaeltnis_id' => $this->getDienstverhaeltnis_id(), + 'von' => $this->getVon(), + 'bis' => $this->getBis(), + 'vertragsbestandteiltyp_kurzbz' => $this->getVertragsbestandteiltyp_kurzbz(), + 'insertamum' => $this->getInsertamum(), + 'insertvon' => $this->getInsertvon(), + 'updateamum' => $this->getUpdateamum(), + 'updatevon' => $this->getUpdatevon(), + ); + + $tmp = array_filter($tmp, function($k) { + return in_array($k, $this->modifiedcolumns); + }, ARRAY_FILTER_USE_KEY); + + return (object) $tmp; + } + + public function jsonSerialize() + { + $vars = get_object_vars($this); + unset($vars['CI']); + + // TODO cleanup workaroung for vb freitext where db column is anmerkung and formfield is freitext + if( isset($vars['anmerkung']) ) { + $vars['freitext'] = $vars['anmerkung']; + } + + return $vars; + } + + public function __toString() + { + return <<getVertragsbestandteil_id()} + dienstverhaeltnis_id: {$this->getDienstverhaeltnis_id()} + von: {$this->getVon()} + bis: {$this->getBis()} + vertragsbestandteiltyp_kurzbz: {$this->getVertragsbestandteiltyp_kurzbz()} + insertamum: {$this->getInsertamum()} + insertvon: {$this->getInsertvon()} + updateamum: {$this->getUpdateamum()} + updatevon: {$this->getUpdatevon()} + +EOTXT; + + } + + public function beforePersist() { + // can be overridden in childs + } + + public function afterDelete() { + // can be overridden in childs + } + + public function validate() { + $von = \DateTimeImmutable::createFromFormat('Y-m-d', $this->von); + $bis = \DateTimeImmutable::createFromFormat('Y-m-d', $this->bis); + + if( false === $von ) { + $this->validationerrors[] = 'Beginn muss ein gültiges Datum sein.'; + } + + if( $this->bis !== null && $bis === false ) { + $this->validationerrors[] = 'Ende muss ein gültiges Datum oder leer sein.'; + } + + if( $this-> bis !== null && $von && $bis && $von > $bis ) { + $this->validationerrors[] = 'Das Beginndatum muss vor dem Endedatum liegen.'; + } + + if( count($this->validationerrors) > 0 ) { + $this->isvalid = false; + } else { + $this->isvalid = true; + } + + return $this->isvalid; + } + + public abstract function toStdClass(); +} diff --git a/application/libraries/vertragsbestandteil/VertragsbestandteilFactory.php b/application/libraries/vertragsbestandteil/VertragsbestandteilFactory.php new file mode 100644 index 000000000..6e7b0af06 --- /dev/null +++ b/application/libraries/vertragsbestandteil/VertragsbestandteilFactory.php @@ -0,0 +1,137 @@ +vertragsbestandteiltyp_kurzbz) + ? $data->vertragsbestandteiltyp_kurzbz : false; + if( false === $vertragsbestandteiltyp_kurzbz ) + { + throw new Exception('Missing Parameter vertragsbestandteiltyp_kurzbz'); + } + + $vertragsbestandteil = null; + switch ($vertragsbestandteiltyp_kurzbz) + { + case self::VERTRAGSBESTANDTEIL_FREITEXT: + $vertragsbestandteil = new VertragsbestandteilFreitext(); + $vertragsbestandteil->hydrateByStdClass($data, $fromdb); + break; + + case self::VERTRAGSBESTANDTEIL_FUNKTION: + $vertragsbestandteil = new VertragsbestandteilFunktion(); + $vertragsbestandteil->hydrateByStdClass($data, $fromdb); + break; + + case self::VERTRAGSBESTANDTEIL_KARENZ: + $vertragsbestandteil = new VertragsbestandteilKarenz(); + $vertragsbestandteil->hydrateByStdClass($data, $fromdb); + break; + + case self::VERTRAGSBESTANDTEIL_KUENDIGUNGSFRIST: + $vertragsbestandteil = new VertragsbestandteilKuendigungsfrist(); + $vertragsbestandteil->hydrateByStdClass($data, $fromdb); + break; + + case self::VERTRAGSBESTANDTEIL_STUNDEN: + $vertragsbestandteil = new VertragsbestandteilStunden(); + $vertragsbestandteil->hydrateByStdClass($data, $fromdb); + break; + + case self::VERTRAGSBESTANDTEIL_URLAUBSANSPRUCH: + $vertragsbestandteil = new VertragsbestandteilUrlaubsanspruch(); + $vertragsbestandteil->hydrateByStdClass($data, $fromdb); + break; + + case self::VERTRAGSBESTANDTEIL_ZEITAUFZEICHNUNG: + $vertragsbestandteil = new VertragsbestandteilZeitaufzeichnung(); + $vertragsbestandteil->hydrateByStdClass($data, $fromdb); + break; + + default: + throw new Exception('Unknown vertragsbestandteiltyp_kurzbz ' + . $vertragsbestandteiltyp_kurzbz); + } + + return $vertragsbestandteil; + } + + public static function getVertragsbestandteilDBModel($vertragsbestandteil_kurzbz): \DB_model + { + $CI = get_instance(); + + $vertragsbestandteildbmodel = null; + switch ($vertragsbestandteil_kurzbz) + { + case self::VERTRAGSBESTANDTEIL_FREITEXT: + $CI->load->model('vertragsbestandteil/VertragsbestandteilFreitext_model', + 'VertragsbestandteilFreitext_model'); + $vertragsbestandteildbmodel = $CI->VertragsbestandteilFreitext_model; + break; + + case self::VERTRAGSBESTANDTEIL_FUNKTION: + $CI->load->model('vertragsbestandteil/VertragsbestandteilFunktion_model', + 'VertragsbestandteilFunktion_model'); + $vertragsbestandteildbmodel = $CI->VertragsbestandteilFunktion_model; + break; + + case self::VERTRAGSBESTANDTEIL_KARENZ: + $CI->load->model('vertragsbestandteil/VertragsbestandteilKarenz_model', + 'VertragsbestandteilKarenz_model'); + $vertragsbestandteildbmodel = $CI->VertragsbestandteilKarenz_model; + break; + + case self::VERTRAGSBESTANDTEIL_KUENDIGUNGSFRIST: + $CI->load->model('vertragsbestandteil/VertragsbestandteilKuendigungsfrist_model', + 'VertragsbestandteilKuendigungsfrist_model'); + $vertragsbestandteildbmodel = $CI->VertragsbestandteilKuendigungsfrist_model; + break; + + case self::VERTRAGSBESTANDTEIL_STUNDEN: + $CI->load->model('vertragsbestandteil/VertragsbestandteilStunden_model', + 'VertragsbestandteilStunden_model'); + $vertragsbestandteildbmodel = $CI->VertragsbestandteilStunden_model; + break; + + case self::VERTRAGSBESTANDTEIL_URLAUBSANSPRUCH: + $CI->load->model('vertragsbestandteil/VertragsbestandteilUrlaubsanspruch_model', + 'VertragsbestandteilUrlaubsanspruch_model'); + $vertragsbestandteildbmodel = $CI->VertragsbestandteilUrlaubsanspruch_model; + break; + + case self::VERTRAGSBESTANDTEIL_ZEITAUFZEICHNUNG: + $CI->load->model('vertragsbestandteil/VertragsbestandteilZeitaufzeichnung_model', + 'VertragsbestandteilZeitaufzeichnung_model'); + $vertragsbestandteildbmodel = $CI->VertragsbestandteilZeitaufzeichnung_model; + break; + + default: + throw new Exception('Unknown vertragsbestandteil_kurzbz ' + . $vertragsbestandteil_kurzbz); + } + + return $vertragsbestandteildbmodel; + } +} diff --git a/application/libraries/vertragsbestandteil/VertragsbestandteilFreitext.php b/application/libraries/vertragsbestandteil/VertragsbestandteilFreitext.php new file mode 100644 index 000000000..07e8a3c58 --- /dev/null +++ b/application/libraries/vertragsbestandteil/VertragsbestandteilFreitext.php @@ -0,0 +1,134 @@ +setVertragsbestandteiltyp_kurzbz( + VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_FREITEXT); + } + + public function hydrateByStdClass($data, $fromdb=false) + { + parent::hydrateByStdClass($data, $fromdb); + $this->fromdb = $fromdb; + isset($data->freitexttyp) && $this->setFreitexttypKurzbz($data->freitexttyp); + isset($data->freitexttyp_kurzbz) && $this->setFreitexttypKurzbz($data->freitexttyp_kurzbz); + isset($data->titel) && $this->setTitel($data->titel); + isset($data->freitext) && $this->setAnmerkung($data->freitext); + isset($data->anmerkung) && $this->setAnmerkung($data->anmerkung); + $this->fromdb = false; + } + + public function toStdClass(): \stdClass + { + $tmp = array( + 'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(), + 'freitexttyp_kurzbz' => $this->getFreitexttypKurzbz(), + 'titel' => $this->getTitel(), + 'anmerkung' => $this->getAnmerkung() + ); + + $tmp = array_filter($tmp, function($k) { + return in_array($k, $this->modifiedcolumns); + }, ARRAY_FILTER_USE_KEY); + + return (object) $tmp; + } + + public function __toString() + { + $txt = <<getAnmerkung()} + titel: {$this->getTitel()} + freitexttyp_kurzbz: {$this->getFreitexttypKurzbz()} + +EOTXT; + return parent::__toString() . $txt; + } + + /** + * Get the value of anmerkung + */ + public function getAnmerkung() + { + return $this->anmerkung; + } + + /** + * Set the value of anmerkung + */ + public function setAnmerkung($anmerkung): self + { + $this->markDirty('anmerkung', $this->anmerkung, $anmerkung); + $this->anmerkung = $anmerkung; + + return $this; + } + + /** + * Get the value of titel + */ + public function getTitel() + { + return $this->titel; + } + + /** + * Set the value of titel + */ + public function setTitel($titel): self + { + $this->markDirty('titel', $this->titel, $titel); + $this->titel = $titel; + + return $this; + } + + /** + * Get the value of freitexttyp_kurzbz + */ + public function getFreitexttypKurzbz() + { + return $this->freitexttyp_kurzbz; + } + + /** + * Set the value of freitexttyp_kurzbz + */ + public function setFreitexttypKurzbz($freitexttyp_kurzbz): self + { + $this->markDirty('freitexttyp_kurzbz', $this->freitexttyp_kurzbz, $freitexttyp_kurzbz); + $this->freitexttyp_kurzbz = $freitexttyp_kurzbz; + + return $this; + } + + public function validate() + { + if( empty($this->freitexttyp_kurzbz) ) { + $this->validationerrors[] = 'Bitte einen gültigen Freitexttyp auswählen.'; + } + + if( empty($this->titel) ) { + $this->validationerrors[] = 'Bitte einen Titel angeben.'; + } + + if( empty($this->anmerkung) ) { + $this->validationerrors[] = 'Bitte eine Beschreibung eingeben.'; + } + + return parent::validate(); + } + + +} diff --git a/application/libraries/vertragsbestandteil/VertragsbestandteilFunktion.php b/application/libraries/vertragsbestandteil/VertragsbestandteilFunktion.php new file mode 100644 index 000000000..ee5cd713f --- /dev/null +++ b/application/libraries/vertragsbestandteil/VertragsbestandteilFunktion.php @@ -0,0 +1,369 @@ +benutzerfunktiondata = null; + + $this->setVertragsbestandteiltyp_kurzbz( + VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_FUNKTION); + + $this->CI = get_instance(); + $this->CI->load->model('person/Benutzerfunktion_model', + 'BenutzerfunktionModel'); + $this->CI->load->model('vertragsbestandteil/VertragsbestandteilFunktion_model', + 'VertragsbestandteilFunktionModel'); + $this->CI->load->library('vertragsbestandteil/VertragsbestandteilLib', + null, 'VertragsbestandteilLib'); + } + + public function isDirty() + { + $isdirty = parent::isDirty(); + if( !$isdirty ) { + $bf = $this->loadBenutzerfunktion($this->getBenutzerfunktion_id()); + if( !$this->areVbAndBfInSync($bf) ) + { + $isdirty = true; + } + } + return $isdirty; + } + + public function beforePersist() + { + if( isset($this->benutzerfunktion_id) && intval($this->benutzerfunktion_id) > 0 ) + { + $this->beforePersitExisting(); + } + else + { + $this->beforePersitNew(); + } + } + + protected function loadBenutzerfunktion($bfid) + { + $bfres = $this->CI->BenutzerfunktionModel->load($bfid); + if(!hasData($bfres)) + { + throw new Exception('failed to load existing Benutzerfunktion'); + } + return (getData($bfres))[0]; + } + + protected function loadPersitedVB($vbid) + { + $vb = $this->CI->VertragsbestandteilLib->fetchVertragsbestandteil($vbid); + if( $vb === null ) + { + throw new Exception('failed to load persited Vertragsbestandteil'); + } + return $vb; + } + + protected function areVbAndBfInSync($bf) + { + $vbvon = $this->getVon(); + $vbbis = $this->getBis(); + if( intval($this->getVertragsbestandteil_id()) > 0 ) + { + $vb = $this->loadPersitedVB($this->getVertragsbestandteil_id()); + $vbvon = $vb->getVon(); + $vbbis = $vb->getBis(); + } + + if( ($bf->datum_von === $vbvon) && ($bf->datum_bis === $vbbis) ) + { + return true; + } + return false; + } + + protected function isBefore($a, $b) + { + if($a === null) { + return false; + } + elseif($b === null) { + return true; + } + else { + return $a < $b; + } + } + + protected function isAfter($a, $b) + { + if($b === null) { + return false; + } + elseif($a === null) { + return true; + } + else { + return $a > $b; + } + } + + protected function beforePersitExisting() + { + $bf = $this->loadBenutzerfunktion($this->getBenutzerfunktion_id()); + if( $this->areVbAndBfInSync($bf) ) + { + // vb or stored vb von bis is in sync so update benutzerfunktion + $this->updateBenutzerfunktion($bf, $this->getVon(), $this->getBis()); + } + else + { + $daybeforevon = \DateTime::createFromFormat('Y-m-d', $this->getVon(), + new \DateTimeZone('Europe/Vienna')); + $daybeforevon->sub(new \DateInterval('P1D')); + + if( $this->isBefore($bf->datum_von, $this->getVon()) && + $this->isBefore($bf->datum_von, $this->getBis()) ) + { + $data = (object) array( + 'mitarbeiter_uid' => $bf->uid, + 'funktion' => $bf->funktion_kurzbz, + 'orget' => $bf->oe_kurzbz + ); + $this->createBenutzerfunktionData($data); + $bfid = $this->insertBenutzerfunktion($this->getBenutzerfunktionData4Insert()); + $this->setBenutzerfunktion_id($bfid); + } + elseif( $this->isBefore($bf->datum_von, $this->getVon()) && + $this->isAfter($this->getBis(), $bf->datum_von) ) + { + $this->updateBenutzerfunktion($bf, $bf->datum_von, $daybeforevon->format('Y-m-d')); + $data = (object) array( + 'mitarbeiter_uid' => $bf->uid, + 'funktion' => $bf->funktion_kurzbz, + 'orget' => $bf->oe_kurzbz + ); + $this->createBenutzerfunktionData($data); + $bfid = $this->insertBenutzerfunktion($this->getBenutzerfunktionData4Insert()); + $this->setBenutzerfunktion_id($bfid); + } + else + { + $this->updateBenutzerfunktion($bf, $this->getVon(), $this->getBis()); + } + } + } + + protected function updateBenutzerfunktion($bf, $von, $bis) + { + $data = array(); + + if($von !== $bf->datum_von) + { + $data['datum_von'] = $von; + } + if($bis !== $bf->datum_bis) + { + $data['datum_bis'] = $bis; + } + + if( count($data) === 0 ) + { + return; + } + + $data['updateamum'] = strftime('%Y-%m-%d %H:%M:%S'); + $data['updatevon'] = getAuthUID(); + + $ret = $this->CI->BenutzerfunktionModel->update($bf->benutzerfunktion_id, $data); + + if(isError($ret) ) + { + throw new Exception('failed to update Benutzerfunktion'); + } + } + + protected function insertBenutzerfunktion($benutzerfunktiondata) + { + $ret = $this->CI->BenutzerfunktionModel->insert($benutzerfunktiondata); + + if(isError($ret) ) + { + throw new Exception('failed to create Benutzerfunktion'); + } + + return getData($ret); + } + + protected function deleteBenutzerfunktion($benutzerfunktion_id) + { + $ret = $this->CI->BenutzerfunktionModel->delete($benutzerfunktion_id); + + if(isError($ret) ) + { + throw new Exception('failed to delete Benutzerfunktion'); + } + } + + protected function beforePersitNew() { + if( $this->benutzerfunktiondata === null) + { + return; + } + + $bfid = $this->insertBenutzerfunktion($this->getBenutzerfunktionData4Insert()); + + $this->setBenutzerfunktion_id($bfid); + } + + public function afterDelete() + { + if( !(intval($this->getBenutzerfunktion_id()) > 0) ) + { + return; + } + + $this->deleteBenutzerfunktion($this->getBenutzerfunktion_id()); + } + + public function toStdClass() + { + $tmp = array( + 'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(), + 'benutzerfunktion_id' => $this->getBenutzerfunktion_id() + ); + + $tmp = array_filter($tmp, function($k) { + return in_array($k, $this->modifiedcolumns); + }, ARRAY_FILTER_USE_KEY); + + return (object) $tmp; + } + + public function __toString() + { + $txt = <<getBenutzerfunktion_id()} + +EOTXT; + return parent::__toString() . $txt; + } + + public function hydrateByStdClass($data, $fromdb=false) + { + parent::hydrateByStdClass($data, $fromdb); + $this->fromdb = $fromdb; + isset($data->benutzerfunktionid) && $this->setBenutzerfunktion_id($data->benutzerfunktionid); + isset($data->benutzerfunktion_id) && $this->setBenutzerfunktion_id($data->benutzerfunktion_id); + isset($data->funktion) && isset($data->orget) + && isset($data->mitarbeiter_uid) && $this->createBenutzerfunktionData($data); + isset($data->funktion_bezeichnung) && isset($data->oe_bezeichnung) + && $this->createBenutzerfunktionData4Display($data); + $this->fromdb = false; + + } + + public function getBenutzerfunktion_id() + { + return $this->benutzerfunktion_id; + } + + public function setBenutzerfunktion_id($benutzerfunktion_id) + { + $this->markDirty('benutzerfunktion_id', $this->benutzerfunktion_id, $benutzerfunktion_id); + $this->benutzerfunktion_id = $benutzerfunktion_id; + return $this; + } + + protected function getBenutzerfunktionData4Insert() + { + if( null === $this->benutzerfunktiondata ) { + return null; + } + + $benutzerfunktiondata = (object) array( + 'funktion_kurzbz' => $this->benutzerfunktiondata->funktion_kurzbz, + 'oe_kurzbz' => $this->benutzerfunktiondata->oe_kurzbz, + 'uid' => $this->benutzerfunktiondata->uid, + 'datum_von' => $this->getVon(), + 'datum_bis' => $this->getBis(), + 'insertamum' => strftime('%Y-%m-%d %H:%M:%S'), + 'insertvon' => getAuthUID() + ); + + return $benutzerfunktiondata; + } + + protected function createBenutzerfunktionData($data) + { + if( empty($data->funktion) || empty($data->orget) ) + { + return; + } + + $this->benutzerfunktiondata = (object) array( + 'funktion_kurzbz' => $data->funktion, + 'oe_kurzbz' => $data->orget, + 'uid' => $data->mitarbeiter_uid + ); + } + + protected function createBenutzerfunktionData4Display($data) + { + if( empty($data->funktion_bezeichnung) || empty($data->oe_bezeichnung) ) + { + return; + } + + $this->benutzerfunktiondata = (object) array( + 'funktion_kurzbz' => $data->funktion_kurzbz, + 'funktion_bezeichnung' => $data->funktion_bezeichnung, + 'oe_kurzbz' => $data->oe_kurzbz, + 'oe_bezeichnung' => $data->oe_bezeichnung, + 'oe_kurzbz_sap' => $data->oe_kurzbz_sap, + 'oe_typ_kurzbz' => $data->oe_typ_kurzbz, + 'oe_typ_bezeichnung' => $data->oe_typ_bezeichnung, + 'uid' => $data->mitarbeiter_uid + ); + } + + public function validate() + { + if( (intval($this->benutzerfunktion_id) < 1) + && ($this->benutzerfunktiondata === NULL) ) { + $this->validationerrors[] = 'Eine bestehende Funktion oder eine ' + . 'Funktion und eine Organisationseinheit müssen ausgewählt sein.'; + } + + // TODO check if Benutzerfunktion is assigned to another vb + if( intval($this->benutzerfunktion_id) > 0 ) + { + if ( $this->CI->VertragsbestandteilFunktionModel + ->isBenutzerfunktionAlreadyAttachedToAnotherVB( + $this->benutzerfunktion_id, + $this->getVertragsbestandteil_id()) ) + { + $this->validationerrors[] = 'Die Benutzerfunktion ist bereits ' + . 'mit einem anderen Vertragsbestandteil verknüpft und kann ' + . 'nicht mehrfach verknüft werden.'; + } + } + + return parent::validate(); + } +} diff --git a/application/libraries/vertragsbestandteil/VertragsbestandteilKarenz.php b/application/libraries/vertragsbestandteil/VertragsbestandteilKarenz.php new file mode 100644 index 000000000..7b49bfe4c --- /dev/null +++ b/application/libraries/vertragsbestandteil/VertragsbestandteilKarenz.php @@ -0,0 +1,141 @@ +setVertragsbestandteiltyp_kurzbz( + VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_KARENZ); + } + + public function hydrateByStdClass($data, $fromdb=false) + { + parent::hydrateByStdClass($data, $fromdb); + $this->fromdb = $fromdb; + isset($data->karenztyp_kurzbz) && $this->setKarenztypKurzbz($data->karenztyp_kurzbz); + isset($data->geplanter_geburtstermin) && $this->setGeplanterGeburtstermin($data->geplanter_geburtstermin); + isset($data->tatsaechlicher_geburtstermin) && $this->setTatsaechlicherGeburtstermin($data->tatsaechlicher_geburtstermin); + $this->fromdb = false; + } + + /** + * Get the value of karenztyp_kurzbz + */ + public function getKarenztypKurzbz() + { + return $this->karenztyp_kurzbz; + } + + /** + * Set the value of karenztyp_kurzbz + */ + public function setKarenztypKurzbz($karenztyp_kurzbz): self + { + $this->markDirty('karenztyp_kurzbz', $this->karenztyp_kurzbz, $karenztyp_kurzbz); + $this->karenztyp_kurzbz = $karenztyp_kurzbz; + + return $this; + } + + /** + * Get the value of tatsaechlicher_geburtstermin + */ + public function getTatsaechlicherGeburtstermin() + { + return $this->tatsaechlicher_geburtstermin; + } + + /** + * Set the value of tatsaechlicher_geburtstermin + */ + public function setTatsaechlicherGeburtstermin($tatsaechlicher_geburtstermin): self + { + $this->markDirty('tatsaechlicher_geburtstermin', $this->tatsaechlicher_geburtstermin, $tatsaechlicher_geburtstermin); + $this->tatsaechlicher_geburtstermin = $tatsaechlicher_geburtstermin; + + return $this; + } + + /** + * Get the value of geplanter_geburtstermin + */ + public function getGeplanterGeburtstermin() + { + return $this->geplanter_geburtstermin; + } + + /** + * Set the value of geplanter_geburtstermin + */ + public function setGeplanterGeburtstermin($geplanter_geburtstermin): self + { + $this->markDirty('geplanter_geburtstermin', $this->geplanter_geburtstermin, $geplanter_geburtstermin); + $this->geplanter_geburtstermin = $geplanter_geburtstermin; + + return $this; + } + + public function toStdClass(): \stdClass + { + $tmp = array( + 'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(), + 'karenztyp_kurzbz' => $this->getKarenztypKurzbz(), + 'tatsaechlicher_geburtstermin' => $this->getTatsaechlicherGeburtstermin(), + 'geplanter_geburtstermin' => $this->getGeplanterGeburtstermin() + ); + + $tmp = array_filter($tmp, function($k) { + return in_array($k, $this->modifiedcolumns); + }, ARRAY_FILTER_USE_KEY); + + return (object) $tmp; + } + + public function __toString() + { + $txt = <<getKarenztypKurzbz()} + tatsaechlicher_geburtstermin: {$this->getTatsaechlicherGeburtstermin()} + geplanter_geburtstermin: {$this->getGeplanterGeburtstermin()} + +EOTXT; + return parent::__toString() . $txt; + } + + public function validate() + { + if( empty($this->karenztyp_kurzbz) ) { + $this->validationerrors[] = 'Ein Karenztyp muss ausgewählt sein.'; + } + + if( $this->karenztyp_kurzbz === 'elternkarenz' ) { + $geplant = \DateTimeImmutable::createFromFormat('Y-m-d', $this->geplanter_geburtstermin); + $tatsaechlich = \DateTimeImmutable::createFromFormat('Y-m-d', $this->tatsaechlicher_geburtstermin); + + if( false === $geplant ) { + $this->validationerrors[] = 'Bei Elternkarenz muss der geplanter Geburtstermin ein gültiges Datum sein.'; + } + + if( !empty($this->tatsaechlicher_geburtstermin) && $tatsaechlich === false ) { + $this->validationerrors[] = 'Bei Elternkarenz muss der tatsaechliche Geburtstermin leer oder ein gültiges Datum sein.'; + } + } + + $bis = \DateTimeImmutable::createFromFormat('Y-m-d', $this->bis); + + if( false === $bis ) { + $this->validationerrors[] = 'Bei einer Karenz muss ein gültiges Ende-Datum angegeben werden.'; + } + + return parent::validate(); + } +} diff --git a/application/libraries/vertragsbestandteil/VertragsbestandteilKuendigungsfrist.php b/application/libraries/vertragsbestandteil/VertragsbestandteilKuendigungsfrist.php new file mode 100644 index 000000000..81ea0dcec --- /dev/null +++ b/application/libraries/vertragsbestandteil/VertragsbestandteilKuendigungsfrist.php @@ -0,0 +1,117 @@ +setVertragsbestandteiltyp_kurzbz( + VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_KUENDIGUNGSFRIST); + } + + public function hydrateByStdClass($data, $fromdb=false) + { + parent::hydrateByStdClass($data, $fromdb); + $this->fromdb = $fromdb; + isset($data->arbeitgeber_frist) && $this->setArbeitgeberFrist($data->arbeitgeber_frist); + isset($data->arbeitnehmer_frist) && $this->setArbeitnehmerFrist($data->arbeitnehmer_frist); + $this->fromdb = false; + } + + /** + * Get the value of arbeitgeber_frist + */ + public function getArbeitgeberFrist() + { + return $this->arbeitgeber_frist; + } + + /** + * Set the value of arbeitgeber_frist + */ + public function setArbeitgeberFrist($arbeitgeber_frist): self + { + $this->markDirty('arbeitgeber_frist', $this->arbeitgeber_frist, $arbeitgeber_frist); + $this->arbeitgeber_frist = $arbeitgeber_frist; + + return $this; + } + + /** + * Get the value of arbeitnehmer_frist + */ + public function getArbeitnehmerFrist() + { + return $this->arbeitnehmer_frist; + } + + /** + * Set the value of arbeitnehmer_frist + */ + public function setArbeitnehmerFrist($arbeitnehmer_frist): self + { + $this->markDirty('arbeitnehmer_frist', $this->arbeitnehmer_frist, $arbeitnehmer_frist); + $this->arbeitnehmer_frist = $arbeitnehmer_frist; + + return $this; + } + + public function toStdClass(): \stdClass + { + $tmp = array( + 'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(), + 'arbeitgeber_frist' => $this->getArbeitgeberFrist(), + 'arbeitnehmer_frist' => $this->getArbeitnehmerFrist() + ); + + $tmp = array_filter($tmp, function($k) { + return in_array($k, $this->modifiedcolumns); + }, ARRAY_FILTER_USE_KEY); + + return (object) $tmp; + } + + public function __toString() + { + $txt = <<getArbeitgeberFrist()} + arbeitnehmer_frist: {$this->getArbeitnehmerFrist()} + +EOTXT; + return parent::__toString() . $txt; + } + + public function validate() + { + if( !(filter_var($this->arbeitgeber_frist, FILTER_VALIDATE_INT, + array( + 'options' => array( + 'min_range' => 0, + 'max_range' => 52 + ) + ) + )) ) { + $this->validationerrors[] = 'Arbeitgeberfrist muss eine Wochenanzahl im Bereich 1 bis 52 sein.'; + } + + if( !(filter_var($this->arbeitnehmer_frist, FILTER_VALIDATE_INT, + array( + 'options' => array( + 'min_range' => 1, + 'max_range' => 52 + ) + ) + )) ) { + $this->validationerrors[] = 'Arbeitnehmerfrist muss eine Wochenanzahl im Bereich 1 bis 52 sein.'; + } + + return parent::validate(); + } +} diff --git a/application/libraries/vertragsbestandteil/VertragsbestandteilLib.php b/application/libraries/vertragsbestandteil/VertragsbestandteilLib.php new file mode 100644 index 000000000..8fb3900d5 --- /dev/null +++ b/application/libraries/vertragsbestandteil/VertragsbestandteilLib.php @@ -0,0 +1,452 @@ +loggedInUser = getAuthUID(); + $this->CI = get_instance(); + $this->CI->load->model('vertragsbestandteil/Dienstverhaeltnis_model', + 'DienstverhaeltnisModel'); + $this->DienstverhaeltnisModel = $this->CI->DienstverhaeltnisModel; + $this->CI->load->model('vertragsbestandteil/Vertragsbestandteil_model', + 'VertragsbestandteilModel'); + $this->VertragsbestandteilModel = $this->CI->VertragsbestandteilModel; + $this->CI->load->library('vertragsbestandteil/GehaltsbestandteilLib', + null, 'GehaltsbestandteilLib'); + $this->GehaltsbestandteilLib = $this->CI->GehaltsbestandteilLib; + } + + public function handleGUIData($guidata, $employeeUID, $userUID) + { + $guiHandler = new GUIHandler($employeeUID, $userUID); + $ret = false; + try { + $ret = $guiHandler->handle($guidata, $employeeUID, $userUID); + } catch (Exception $ex) + { + log_message('debug', "Error handling json data from GUI. " . $ex->getMessage()); + } + + return $ret; + } + + public function fetchDienstverhaeltnis($dienstverhaeltnis_id) + { + $result = $this->DienstverhaeltnisModel->load($dienstverhaeltnis_id); + $dv = null; + if(null !== ($row = getData($result))) + { + $dv = new Dienstverhaeltnis(); + $dv->hydrateByStdClass($row[0], true); + } + return $dv; + } + + public function fetchVertragsbestandteile($dienstverhaeltnis_id, $stichtag=null, $includefuture=false) + { + $vbs = $this->VertragsbestandteilModel->getVertragsbestandteile($dienstverhaeltnis_id, $stichtag, $includefuture); + $gbs = $this->GehaltsbestandteilLib->fetchGehaltsbestandteile($dienstverhaeltnis_id, $stichtag, $includefuture); + + $gbsByVBid = array(); + foreach( $gbs as $gb ) + { + if( intval($gb->getVertragsbestandteil_id()) > 0 ) + { + if( !isset($gbsByVBid[$gb->getVertragsbestandteil_id()]) + || !is_array($gbsByVBid[$gb->getVertragsbestandteil_id()]) ) { + $gbsByVBid[$gb->getVertragsbestandteil_id()] = array(); + } + $gbsByVBid[$gb->getVertragsbestandteil_id()][] = $gb; + } + } + + foreach ($vbs as $vb) + { + if( isset($gbsByVBid[$vb->getVertragsbestandteil_id()]) ) + { + $vb->setGehaltsbestandteile($gbsByVBid[$vb->getVertragsbestandteil_id()]); + } + } + + return $vbs; + } + + public function fetchVertragsbestandteil($vertragsbestandteil_id) + { + return $this->VertragsbestandteilModel->getVertragsbestandteil($vertragsbestandteil_id); + } + + public function storeDienstverhaeltnis(Dienstverhaeltnis $dv) + { + if( intval($dv->getDienstverhaeltnis_id()) > 0 ) + { + $this->updateDienstverhaeltnis($dv); + } + else + { + $this->insertDienstverhaeltnis($dv); + } + } + + public function storeVertragsbestandteil(Vertragsbestandteil $vertragsbestandteil) + { + $this->CI->db->trans_begin(); + try + { + $this->setUIDtoPGSQL(); + if( intval($vertragsbestandteil->getVertragsbestandteil_id()) > 0 ) + { + $this->updateVertragsbestandteil($vertragsbestandteil); + } + else + { + $this->insertVertragsbestandteil($vertragsbestandteil); + } + if( $this->CI->db->trans_status() === false ) + { + log_message('debug', "Transaction failed"); + throw new Exception("Transaction failed"); + } + $this->CI->db->trans_commit(); + } + catch (Exception $ex) + { + log_message('debug', "Transaction rolled back. " . $ex->getMessage()); + $this->CI->db->trans_rollback(); + throw new Exception('Storing Vertragsbestandteil failed.'); + } + } + + public function deleteDienstverhaeltnis(Dienstverhaeltnis $dv) + { + $this->CI->db->trans_begin(); + try + { + $this->setUIDtoPGSQL(); + if( intval($dv->getDienstverhaeltnis_id()) > 0 ) + { + $vbs = $this->fetchVertragsbestandteile($dv->getDienstverhaeltnis_id()); + foreach ($vbs as $vb) + { + $this->deleteVertragsbestandteil($vb); + } + + $ret = $this->DienstverhaeltnisModel->delete($dv->getDienstverhaeltnis_id()); + if(isError($ret) ) + { + log_message('debug', "Delete DV failed"); + throw new Exception('error deleting dienstverhaeltnis ' + . $dv->getDienstverhaeltnis_id()); + } + + if( $this->CI->db->trans_status() === false ) + { + log_message('debug', "Transaction failed"); + throw new Exception("Transaction failed"); + } + $this->CI->db->trans_commit(); + } + } + catch (Exception $ex) + { + log_message('debug', "Transaction rolled back. " . $ex->getMessage()); + $this->CI->db->trans_rollback(); + return $ex->getMessage(); + } + + return true; + + } + + public function deleteVertragsbestandteil(Vertragsbestandteil $vertragsbestandteil) + { + $this->CI->db->trans_begin(); + try + { + $this->setUIDtoPGSQL(); + if( intval($vertragsbestandteil->getVertragsbestandteil_id()) > 0 ) + { + $this->deleteVertragsbestandteilHelper($vertragsbestandteil); + } + if( $this->CI->db->trans_status() === false ) + { + log_message('debug', "Transaction failed"); + throw new Exception("Transaction failed"); + } + $this->CI->db->trans_commit(); + } + catch (Exception $ex) + { + log_message('debug', "Transaction rolled back. " . $ex->getMessage()); + $this->CI->db->trans_rollback(); + throw new Exception('Delete Vertragsbestandteil failed.'); + } + } + + protected function insertDienstverhaeltnis(Dienstverhaeltnis $dv) + { + $dv->setInsertvon($this->loggedInUser) + ->setInsertamum(strftime('%Y-%m-%d %H:%M:%S')); + $ret = $this->DienstverhaeltnisModel->insert($dv->toStdClass()); + if( hasData($ret) ) + { + $dv->setDienstverhaeltnis_id(getData($ret)); + } + else + { + throw new Exception('error inserting dienstverhaeltnis'); + } + } + + protected function insertVertragsbestandteil(Vertragsbestandteil $vertragsbestandteil) + { + $vertragsbestandteil->setInsertvon($this->loggedInUser) + ->setInsertamum(strftime('%Y-%m-%d %H:%M:%S')); + $vertragsbestandteil->beforePersist(); + $ret = $this->VertragsbestandteilModel->insert($vertragsbestandteil->baseToStdClass()); + if( hasData($ret) ) + { + $vertragsbestandteil->setVertragsbestandteil_id(getData($ret)); + } + else + { + throw new Exception('error inserting vertragsbestandteil'); + } + + $specialisedModel = VertragsbestandteilFactory::getVertragsbestandteilDBModel( + $vertragsbestandteil->getVertragsbestandteiltyp_kurzbz()); + $retspecial = $specialisedModel->insert($vertragsbestandteil->toStdClass()); + + if(isError($retspecial) ) + { + throw new Exception('error updating vertragsbestandteil ' + . $vertragsbestandteil->getVertragsbestandteiltyp_kurzbz()); + } + + try + { + $gehaltsbestandteile = $vertragsbestandteil->getGehaltsbestandteile(); + $this->GehaltsbestandteilLib->storeGehaltsbestandteile($gehaltsbestandteile); + } + catch(Exception $ex) + { + throw new Exception('VertragsbestandteilLib insertVertragsbestandteil ' + . 'failed to store Gehaltsbestandteile. ' . $ex->getMessage()); + } + } + + protected function updateDienstverhaeltnis(Dienstverhaeltnis $dv) + { + if(!$dv->isDirty()) { + return; + } + + $dv->setUpdatevon($this->loggedInUser) + ->setUpdateamum(strftime('%Y-%m-%d %H:%M:%S')); + $ret = $this->DienstverhaeltnisModel->update($dv->getDienstverhaeltnis_id(), + $dv->toStdClass()); + if(isError($ret) ) + { + throw new Exception('error updating dienstverhaeltnis'); + } + } + + private function deleteVertragsbestandteilHelper(Vertragsbestandteil $vertragsbestandteil) + { + + $specialisedModel = VertragsbestandteilFactory::getVertragsbestandteilDBModel( + $vertragsbestandteil->getVertragsbestandteiltyp_kurzbz()); + $retspecial = $specialisedModel->delete($vertragsbestandteil->getVertragsbestandteil_id()); + + if(isError($retspecial) ) + { + throw new Exception('error deleting vertragsbestandteil ' + . $vertragsbestandteil->getVertragsbestandteiltyp_kurzbz()); + } + + try + { + $gehaltsbestandteile = $vertragsbestandteil->getGehaltsbestandteile(); + $this->GehaltsbestandteilLib->deleteGehaltsbestandteile($gehaltsbestandteile); + } + catch(Exception $ex) + { + throw new Exception('VertragsbestandteilLib deleteVertragsbestandteil ' + . 'failed to delete Gehaltsbestandteile. ' . $ex->getMessage()); + } + + + $ret = $this->VertragsbestandteilModel->delete($vertragsbestandteil->getVertragsbestandteil_id()); + + if(isError($ret) ) + { + throw new Exception('error deleting vertragsbestandteil'); + } + + $vertragsbestandteil->afterDelete(); + } + + protected function updateVertragsbestandteil(Vertragsbestandteil $vertragsbestandteil) + { + if($vertragsbestandteil->isDirty()) { + $vertragsbestandteil->setUpdatevon($this->loggedInUser) + ->setUpdateamum(strftime('%Y-%m-%d %H:%M:%S')); + $vertragsbestandteil->beforePersist(); + $basedata = $vertragsbestandteil->baseToStdClass(); + if( count((array) $basedata) > 0 ) + { + $ret = $this->VertragsbestandteilModel->update( + $vertragsbestandteil->getVertragsbestandteil_id(), + $basedata); + + if(isError($ret) ) + { + throw new Exception('error updating vertragsbestandteil'); + } + } + + $specialisedData = $vertragsbestandteil->toStdClass(); + if( count((array) $specialisedData) > 0 ) + { + $specialisedModel = VertragsbestandteilFactory::getVertragsbestandteilDBModel( + $vertragsbestandteil->getVertragsbestandteiltyp_kurzbz()); + $retspecial = $specialisedModel->update( + $vertragsbestandteil->getVertragsbestandteil_id(), + $specialisedData); + + if(isError($retspecial) ) + { + throw new Exception('error updating vertragsbestandteil ' + . $vertragsbestandteil->getVertragsbestandteiltyp_kurzbz()); + } + } + } + + try + { + $gehaltsbestandteile = $vertragsbestandteil->getGehaltsbestandteile(); + $this->GehaltsbestandteilLib->storeGehaltsbestandteile($gehaltsbestandteile); + } + catch(Exception $ex) + { + throw new Exception('VertragsbestandteilLib updateVertragsbestandteil ' + . 'failed to store Gehaltsbestandteile. ' . $ex->getMessage()); + } + } + + public function isOverlappingExistingDV(Dienstverhaeltnis $dv) + { + return $this->DienstverhaeltnisModel->isOverlappingExistingDV( + $dv->getMitarbeiter_uid(), + $dv->getOe_kurzbz(), + $dv->getVon(), + $dv->getBis(), + $dv->getDienstverhaeltnis_id() + ); + } + + public function endDienstverhaeltnis(Dienstverhaeltnis $dv, $enddate) + { + if( $dv->getBis() !== null && $dv->getBis() < $enddate ) + { + return 'Dienstverhältnis ist bereits beendet.'; + } + + $this->CI->db->trans_begin(); + try + { + $this->setUIDtoPGSQL(); + if( intval($dv->getDienstverhaeltnis_id()) > 0 ) + { + $gbs = $this->GehaltsbestandteilLib->fetchGehaltsbestandteile($dv->getDienstverhaeltnis_id()); + foreach ($gbs as $gb) + { + $this->GehaltsbestandteilLib->endGehaltsbestandteil($gb, $enddate); + } + + $vbs = $this->fetchVertragsbestandteile($dv->getDienstverhaeltnis_id()); + foreach ($vbs as $vb) + { + $this->endVertragsbestandteil($vb, $enddate); + } + + $dv->setBis($enddate); + $this->updateDienstverhaeltnis($dv); + + if( $this->CI->db->trans_status() === false ) + { + log_message('debug', "Transaction failed"); + throw new Exception("Transaction failed"); + } + $this->CI->db->trans_commit(); + } + } + catch (Exception $ex) + { + log_message('debug', "end DV failed " . $dv->getDienstverhaeltnis_id()); + log_message('debug', "Transaction rolled back. " . $ex->getMessage()); + $this->CI->db->trans_rollback(); + return $ex->getMessage(); + } + return true; + } + + public function endVertragsbestandteil(Vertragsbestandteil $vertragsbestandteil, $enddate) + { + if( $vertragsbestandteil->getBis() !== null && $vertragsbestandteil->getBis() < $enddate ) + { + return; + } + + $vertragsbestandteil->setBis($enddate); + $this->updateVertragsbestandteil($vertragsbestandteil); + } + + protected function setUIDtoPGSQL() { + $ret = $this->VertragsbestandteilModel + ->execReadOnlyQuery('SET LOCAL pv21.uid TO \'' + . $this->loggedInUser . '\''); + if(isError($ret)) + { + throw new Exception('error setting uid to pgsql'); + } + } +} diff --git a/application/libraries/vertragsbestandteil/VertragsbestandteilStunden.php b/application/libraries/vertragsbestandteil/VertragsbestandteilStunden.php new file mode 100644 index 000000000..f2d8c8081 --- /dev/null +++ b/application/libraries/vertragsbestandteil/VertragsbestandteilStunden.php @@ -0,0 +1,110 @@ +setVertragsbestandteiltyp_kurzbz( + VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_STUNDEN); + } + + public function hydrateByStdClass($data, $fromdb=false) + { + parent::hydrateByStdClass($data, $fromdb); + $this->fromdb = $fromdb; + isset($data->wochenstunden) && $this->setWochenstunden($data->wochenstunden); + isset($data->teilzeittyp_kurzbz) && $this->setTeilzeittyp_kurzbz($data->teilzeittyp_kurzbz); + $this->fromdb = false; + } + + public function getWochenstunden() + { + return $this->wochenstunden; + } + + public function getTeilzeittyp_kurzbz() + { + return $this->teilzeittyp_kurzbz; + } + + public function setWochenstunden($wochenstunden) + { + $this->markDirty('wochenstunden', $this->wochenstunden, $wochenstunden); + $this->wochenstunden = $wochenstunden; + return $this; + } + + public function setTeilzeittyp_kurzbz($teilzeittyp_kurzbz) + { + $teilzeittyp_kurzbz = ($teilzeittyp_kurzbz !== '') + ? $teilzeittyp_kurzbz : null; + $this->markDirty('teilzeittyp_kurzbz', $this->teilzeittyp_kurzbz, $teilzeittyp_kurzbz); + $this->teilzeittyp_kurzbz = $teilzeittyp_kurzbz; + return $this; + } + + public function toStdClass(): \stdClass + { + $tmp = array( + 'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(), + 'wochenstunden' => $this->getWochenstunden(), + 'teilzeittyp_kurzbz' => $this->getTeilzeittyp_kurzbz() + ); + + $tmp = array_filter($tmp, function($k) { + return in_array($k, $this->modifiedcolumns); + }, ARRAY_FILTER_USE_KEY); + + return (object) $tmp; + } + + public function __toString() + { + $txt = <<getWochenstunden()} + teilzeittyp_kurzbz: {$this->getTeilzeittyp_kurzbz()} + +EOTXT; + return parent::__toString() . $txt; + } + + public function validate() + { + if( false === filter_var($this->wochenstunden, FILTER_VALIDATE_FLOAT, + array( + 'options' => array( + 'min_range' => 0, + 'max_range' => 100 + ) + ) + ) ) { + $this->validationerrors[] = 'Stunden muss eine Kommazahl im Bereich 0 bis 100 sein.'; + } + else + { + if( floatval($this->wochenstunden) < floatval('0.01') && + $this->teilzeittyp_kurzbz !== 'altersteilzeit' ) + { + $this->validationerrors[] = '0 Wochenstunden ist nur in Kombination mit Altersteilzeit zulässig.'; + } + } + + return parent::validate(); + } +} diff --git a/application/libraries/vertragsbestandteil/VertragsbestandteilUrlaubsanspruch.php b/application/libraries/vertragsbestandteil/VertragsbestandteilUrlaubsanspruch.php new file mode 100644 index 000000000..fe683211d --- /dev/null +++ b/application/libraries/vertragsbestandteil/VertragsbestandteilUrlaubsanspruch.php @@ -0,0 +1,83 @@ +setVertragsbestandteiltyp_kurzbz( + VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_URLAUBSANSPRUCH); + } + + public function hydrateByStdClass($data, $fromdb=false) + { + parent::hydrateByStdClass($data, $fromdb); + $this->fromdb = $fromdb; + isset($data->tage) && $this->setTage($data->tage); + $this->fromdb = false; + } + + /** + * Get the value of tage + */ + public function getTage() + { + return $this->tage; + } + + /** + * Set the value of tage + */ + public function setTage($tage): self + { + $this->markDirty('tage', $this->tage, $tage); + $this->tage = $tage; + + return $this; + } + + public function toStdClass(): \stdClass + { + $tmp = array( + 'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(), + 'tage' => $this->getTage(), + ); + + $tmp = array_filter($tmp, function($k) { + return in_array($k, $this->modifiedcolumns); + }, ARRAY_FILTER_USE_KEY); + + return (object) $tmp; + } + + public function __toString() + { + $txt = <<getTage()} + +EOTXT; + return parent::__toString() . $txt; + } + + public function validate() + { + if( !(filter_var($this->tage, FILTER_VALIDATE_INT, + array( + 'options' => array( + 'min_range' => 1, + 'max_range' => 50 + ) + ) + )) ) { + $this->validationerrors[] = 'Urlaubsanspruch muss eine Tagesanzahl im Bereich 1 bis 50 sein.'; + } + + return parent::validate(); + } +} diff --git a/application/libraries/vertragsbestandteil/VertragsbestandteilZeitaufzeichnung.php b/application/libraries/vertragsbestandteil/VertragsbestandteilZeitaufzeichnung.php new file mode 100644 index 000000000..5bbdaa36f --- /dev/null +++ b/application/libraries/vertragsbestandteil/VertragsbestandteilZeitaufzeichnung.php @@ -0,0 +1,118 @@ +setVertragsbestandteiltyp_kurzbz( + VertragsbestandteilFactory::VERTRAGSBESTANDTEIL_ZEITAUFZEICHNUNG); + } + + public function hydrateByStdClass($data, $fromdb=false) + { + parent::hydrateByStdClass($data, $fromdb); + $this->fromdb = $fromdb; + isset($data->zeitaufzeichnung) && $this->setZeitaufzeichnung($data->zeitaufzeichnung); + isset($data->azgrelevant) && $this->setAzgrelevant($data->azgrelevant); + isset($data->homeoffice) && $this->setHomeoffice($data->homeoffice); + $this->fromdb = false; + } + + /** + * Get the value of zeitaufzeichnung + */ + public function getZeitaufzeichnung() + { + return $this->zeitaufzeichnung; + } + + /** + * Set the value of zeitaufzeichnung + */ + public function setZeitaufzeichnung($zeitaufzeichnung): self + { + $this->markDirty('zeitaufzeichnung', $this->zeitaufzeichnung, $zeitaufzeichnung); + $this->zeitaufzeichnung = $zeitaufzeichnung; + + return $this; + } + + /** + * Get the value of azgrelevant + */ + public function getAzgrelevant() + { + return $this->azgrelevant; + } + + /** + * Set the value of azgrelevant + */ + public function setAzgrelevant($azgrelevant): self + { + $this->markDirty('azgrelevant', $this->azgrelevant, $azgrelevant); + $this->azgrelevant = $azgrelevant; + + return $this; + } + + /** + * Get the value of homeoffice + */ + public function getHomeoffice() + { + return $this->homeoffice; + } + + /** + * Set the value of homeoffice + */ + public function setHomeoffice($homeoffice): self + { + $this->markDirty('homeoffice', $this->homeoffice, $homeoffice); + $this->homeoffice = $homeoffice; + + return $this; + } + + public function toStdClass(): \stdClass + { + $tmp = array( + 'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(), + 'zeitaufzeichnung' => $this->getZeitaufzeichnung(), + 'azgrelevant' => $this->getAzgrelevant(), + 'homeoffice' => $this->getHomeoffice() + ); + + $tmp = array_filter($tmp, function($k) { + return in_array($k, $this->modifiedcolumns); + }, ARRAY_FILTER_USE_KEY); + + return (object) $tmp; + } + + public function __toString() + { + $txt = <<getZeitaufzeichnung()} + azgrelevant: {$this->getAzgrelevant()} + homeoffice: {$this->getHomeoffice()} + +EOTXT; + return parent::__toString() . $txt; + } + + public function validate() + { + return parent::validate(); + } +} diff --git a/application/models/codex/Bismeldestichtag_model.php b/application/models/codex/Bismeldestichtag_model.php new file mode 100644 index 000000000..1a45f0fbd --- /dev/null +++ b/application/models/codex/Bismeldestichtag_model.php @@ -0,0 +1,14 @@ +dbTable = 'bis.tbl_bismeldestichtag'; + $this->pk = 'meldestichtag_id'; + } +} diff --git a/application/models/crm/Reihungstest_model.php b/application/models/crm/Reihungstest_model.php index ec1982ea6..86ebfd0af 100644 --- a/application/models/crm/Reihungstest_model.php +++ b/application/models/crm/Reihungstest_model.php @@ -322,7 +322,7 @@ class Reihungstest_model extends DB_Model JOIN lehre.tbl_studienplan ON (tbl_prestudentstatus.studienplan_id = tbl_studienplan.studienplan_id) LEFT JOIN bis.tbl_zgv ON (ps.zgv_code = tbl_zgv.zgv_code) WHERE rt_id = ? - AND get_rolle_prestudent(prestudent_id, rt.studiensemester_kurzbz) = \'Interessent\' + AND get_rolle_prestudent(prestudent_id, rt.studiensemester_kurzbz) IN (\'Interessent\', \'Bewerber\') AND tbl_prestudentstatus.studiensemester_kurzbz = rt.studiensemester_kurzbz AND bewerbung_abgeschicktamum IS NOT NULL AND bestaetigtam IS NOT NULL @@ -411,7 +411,7 @@ class Reihungstest_model extends DB_Model JOIN lehre.tbl_studienplan ON (tbl_prestudentstatus.studienplan_id = tbl_studienplan.studienplan_id) LEFT JOIN bis.tbl_zgv ON (ps.zgv_code = tbl_zgv.zgv_code) WHERE rt.studiengang_kz = ? - AND get_rolle_prestudent(prestudent_id, rt.studiensemester_kurzbz) = \'Interessent\' + AND get_rolle_prestudent(prestudent_id, rt.studiensemester_kurzbz) IN (\'Interessent\', \'Bewerber\') AND tbl_prestudentstatus.studiensemester_kurzbz = rt.studiensemester_kurzbz AND bewerbung_abgeschicktamum IS NOT NULL AND bestaetigtam IS NOT NULL @@ -462,7 +462,7 @@ class Reihungstest_model extends DB_Model LEFT JOIN bis.tbl_zgv ON (ps.zgv_code = tbl_zgv.zgv_code) LEFT JOIN PUBLIC.tbl_ort ON (tbl_rt_person.ort_kurzbz = tbl_ort.ort_kurzbz) WHERE rt_id = ? - AND get_rolle_prestudent(prestudent_id, rt.studiensemester_kurzbz) = \'Interessent\' + AND get_rolle_prestudent(prestudent_id, rt.studiensemester_kurzbz) IN (\'Interessent\', \'Bewerber\') AND tbl_prestudentstatus.studiensemester_kurzbz = rt.studiensemester_kurzbz AND bewerbung_abgeschicktamum IS NOT NULL AND bestaetigtam IS NOT NULL diff --git a/application/models/education/Pruefung_model.php b/application/models/education/Pruefung_model.php index e1d668293..50109d2f1 100644 --- a/application/models/education/Pruefung_model.php +++ b/application/models/education/Pruefung_model.php @@ -139,6 +139,8 @@ class Pruefung_model extends DB_Model $this->db->where_not_in("n.note", $note_blacklist); $this->db->where_in("p.pruefungstyp_kurzbz", ['kommPruef','zusKommPruef']); + $this->addOrder('p.datum', 'DESC'); + return $this->load(); } @@ -201,12 +203,19 @@ class Pruefung_model extends DB_Model * * @return stdClass */ - public function loadWhereCommitteeExamFailedForPrestudent($prestudent_id) + public function loadWhereCommitteeExamFailedForPrestudent($prestudent_id, $max_date = null, $studiensemester_kurzbz = null) { $this->withDetailsForStudierendenAntrag(); $this->db->where('ps.prestudent_id', $prestudent_id); + if ($max_date !== null) { + $this->db->where('p.datum <', $max_date); + } + if ($studiensemester_kurzbz !== null) { + $this->db->where('le.studiensemester_kurzbz', $studiensemester_kurzbz); + } + return $this->loadWhereCommitteeExamsFailed(); } diff --git a/application/models/education/Studierendenantrag_model.php b/application/models/education/Studierendenantrag_model.php index 4931896cd..23d69b13b 100644 --- a/application/models/education/Studierendenantrag_model.php +++ b/application/models/education/Studierendenantrag_model.php @@ -26,11 +26,12 @@ class Studierendenantrag_model extends DB_Model return $this->loadForStudiengaenge($studiengaenge, $typ, $this->StudierendenantragstatusModel::STATUS_CREATED); } - public function loadForStudiengaenge($studiengaenge, $typ = null, $status = null) + public function loadForStudiengaenge($studiengaenge, $typ = null, $status = null, $sql = null) { - $sql = "SELECT index FROM public.tbl_sprache WHERE sprache='" . getUserLanguage() . "' LIMIT 1"; + if ($sql == null) + $sql = "SELECT index FROM public.tbl_sprache WHERE sprache='" . getUserLanguage() . "' LIMIT 1"; - $this->addSelect('stg.bezeichnung'); + $this->addSelect('UPPER(stg.typ) || UPPER(stg.kurzbz) || \' \' || stg.bezeichnung AS bezeichnung'); $this->addSelect('bezeichnung_mehrsprachig[(' . $sql . ')] AS orgform', false); $this->addSelect('s.studierendenantrag_id'); $this->addSelect('matrikelnr'); @@ -73,6 +74,44 @@ class Studierendenantrag_model extends DB_Model return $this->loadWhere($where); } + public function loadActiveForStudiengaenge($studiengaenge) + { + // NOTE(chris): get language before changing things in the global db object because getUserLanguage() might use it and it should not have been tampered with + $sql = "SELECT index FROM public.tbl_sprache WHERE sprache='" . getUserLanguage() . "' LIMIT 1"; + + $this->db->group_start(); + $this->db->where_not_in('s.studierendenantrag_statustyp_kurzbz', [ + Studierendenantragstatus_model::STATUS_CANCELLED, + Studierendenantragstatus_model::STATUS_APPROVED, + Studierendenantragstatus_model::STATUS_REJECTED, + Studierendenantragstatus_model::STATUS_OBJECTION_DENIED, + Studierendenantragstatus_model::STATUS_DEREGISTERED + ]); + $this->db->or_group_start(); + $this->db->where('s.studierendenantrag_statustyp_kurzbz', Studierendenantragstatus_model::STATUS_APPROVED); + $this->db->where('tbl_studierendenantrag.typ', Studierendenantrag_model::TYP_ABMELDUNG_STGL); + $this->db->group_end(); + $this->db->group_end(); + + return $this->loadForStudiengaenge($studiengaenge, null, null, $sql); + } + + public function loadStgsWithAntraege($studiengaenge) + { + $this->addDistinct(); + $this->addSelect('UPPER(stg.typ) || UPPER(stg.kurzbz) || \' \' || stg.bezeichnung AS bezeichnung'); + $this->addSelect('p.studiengang_kz'); + + $this->addJoin('public.tbl_prestudent p', 'prestudent_id'); + $this->addJoin('public.tbl_studiengang stg', 'p.studiengang_kz=stg.studiengang_kz'); + + $this->addOrder('UPPER(stg.typ) || UPPER(stg.kurzbz) || \' \' || stg.bezeichnung'); + + $this->db->where_in('p.studiengang_kz', $studiengaenge); + + return $this->load(); + } + public function isInStudiengang($studierendenantrag_id, $studiengaenge) { $this->addJoin('public.tbl_prestudent', 'prestudent_id'); @@ -124,6 +163,7 @@ class Studierendenantrag_model extends DB_Model $this->addSelect('p.studiengang_kz'); $this->addSelect('stg.bezeichnung'); $this->addSelect('s.ausbildungssemester'); + $this->addSelect('plan.sprache'); $this->addSelect('COALESCE(plan.orgform_kurzbz, s.orgform_kurzbz, stg.orgform_kurzbz) AS orgform_kurzbz'); $this->addJoin( diff --git a/application/models/education/Studierendenantraglehrveranstaltung_model.php b/application/models/education/Studierendenantraglehrveranstaltung_model.php index 47a07ecfe..4318c773e 100644 --- a/application/models/education/Studierendenantraglehrveranstaltung_model.php +++ b/application/models/education/Studierendenantraglehrveranstaltung_model.php @@ -65,20 +65,40 @@ class Studierendenantraglehrveranstaltung_model extends DB_Model 'stat.studierendenantrag_status_id = campus.get_status_id_studierendenantrag(a.studierendenantrag_id)' ); $this->addJoin('public.tbl_student s', 'prestudent_id'); - $this->addJoin( - 'lehre.tbl_zeugnisnote z', - 'z.lehrveranstaltung_id=lv.lehrveranstaltung_id AND z.student_uid=s.student_uid AND z.studiensemester_kurzbz=a.studiensemester_kurzbz', - 'LEFT' - ); + + // NOTE(chris): last offizell note + $this->addJoin('( + SELECT z.* + FROM lehre.tbl_zeugnisnote z + LEFT JOIN public.tbl_studiensemester zs + USING(studiensemester_kurzbz) + JOIN ( + SELECT zi.lehrveranstaltung_id, zi.student_uid, MAX(zis.start) AS start + FROM lehre.tbl_zeugnisnote zi + LEFT JOIN lehre.tbl_note zin + USING(note) + LEFT JOIN public.tbl_studiensemester zis + USING(studiensemester_kurzbz) + WHERE zin.aktiv AND zin.offiziell + GROUP BY zi.lehrveranstaltung_id, zi.student_uid + ) zx + ON ( + z.lehrveranstaltung_id=zx.lehrveranstaltung_id + AND z.student_uid=zx.student_uid + AND zs.start = zx.start + )) z', 'z.lehrveranstaltung_id=lv.lehrveranstaltung_id AND z.student_uid=s.student_uid', 'LEFT'); $this->addJoin('lehre.tbl_note zn', 'z.note = zn.note', 'LEFT'); + $this->load->config('studierendenantrag'); + $note_intern_angerechntet = $this->config->item('wiederholung_note_angerechnet'); + return $this->loadWhere([ 'ps.prestudent_id' => $prestudent_id, 'a.typ' => Studierendenantrag_model::TYP_WIEDERHOLUNG, 'stat.studierendenantrag_statustyp_kurzbz' => Studierendenantragstatus_model::STATUS_APPROVED, 'n.note <> ' => 0, $this->dbTable . '.studiensemester_kurzbz' => $studiensemester_kurzbz, - '(n.note<>19 OR (z.note IS NOT NULL AND zn.positiv))' => null + '(n.note<>' . $this->db->escape($note_intern_angerechntet) . ' OR (z.note IS NOT NULL AND zn.positiv))' => null ]); } } diff --git a/application/models/education/Studierendenantragstatus_model.php b/application/models/education/Studierendenantragstatus_model.php index b4bf3938b..c134cc4ee 100644 --- a/application/models/education/Studierendenantragstatus_model.php +++ b/application/models/education/Studierendenantragstatus_model.php @@ -14,6 +14,7 @@ class Studierendenantragstatus_model extends DB_Model const STATUS_REQUESTSENT_2 = 'ZweiteAufforderungVersandt'; const STATUS_OBJECTED = 'Beeinsprucht'; const STATUS_OBJECTION_DENIED = 'EinspruchAbgelehnt'; + const STATUS_DEREGISTERED = 'Abgemeldet'; /** * Constructor diff --git a/application/models/organisation/Studienplan_model.php b/application/models/organisation/Studienplan_model.php index 66ec06ba8..8422f4607 100644 --- a/application/models/organisation/Studienplan_model.php +++ b/application/models/organisation/Studienplan_model.php @@ -60,7 +60,7 @@ class Studienplan_model extends DB_Model )); } - public function getStudienplanLehrveranstaltungForPrestudent($studienplan_id, $semester, $prestudent_id, $note_stsem) + public function getStudienplanLehrveranstaltungForPrestudent($studienplan_id, $semester, $prestudent_id) { $lang = 'SELECT index FROM public.tbl_sprache WHERE sprache=' . $this->escape(getUserLanguage()); $sql = 'SELECT student_uid FROM public.tbl_student WHERE prestudent_id=' . $this->escape($prestudent_id); @@ -75,11 +75,27 @@ class Studienplan_model extends DB_Model $this->addJoin('lehre.tbl_studienplan_lehrveranstaltung', 'studienplan_id'); $this->addJoin('lehre.tbl_lehrveranstaltung lv', 'lehrveranstaltung_id'); - $this->addJoin( - 'lehre.tbl_zeugnisnote zn', - 'zn.lehrveranstaltung_id=lv.lehrveranstaltung_id AND zn.student_uid=(' . $sql . ') AND zn.studiensemester_kurzbz=' . $this->escape($note_stsem), - 'LEFT' - ); + // NOTE(chris): last offizell note + $this->addJoin('( + SELECT z.* + FROM lehre.tbl_zeugnisnote z + LEFT JOIN public.tbl_studiensemester zs + USING(studiensemester_kurzbz) + JOIN ( + SELECT zi.lehrveranstaltung_id, zi.student_uid, MAX(zis.start) AS start + FROM lehre.tbl_zeugnisnote zi + LEFT JOIN lehre.tbl_note zin + USING(note) + LEFT JOIN public.tbl_studiensemester zis + USING(studiensemester_kurzbz) + WHERE zin.aktiv AND zin.offiziell + GROUP BY zi.lehrveranstaltung_id, zi.student_uid + ) zx + ON ( + z.lehrveranstaltung_id=zx.lehrveranstaltung_id + AND z.student_uid=zx.student_uid + AND zs.start = zx.start + )) zn', 'zn.lehrveranstaltung_id=lv.lehrveranstaltung_id AND zn.student_uid=( ' . $sql . ')', 'LEFT'); $this->addJoin('lehre.tbl_note n', 'n.note=zn.note', 'LEFT'); $this->addOrder('lehre.tbl_studienplan_lehrveranstaltung.sort'); diff --git a/application/models/person/Benutzerfunktion_model.php b/application/models/person/Benutzerfunktion_model.php index 27f9b6184..e44281a92 100644 --- a/application/models/person/Benutzerfunktion_model.php +++ b/application/models/person/Benutzerfunktion_model.php @@ -180,4 +180,60 @@ class Benutzerfunktion_model extends DB_Model return $this->execQuery($query, $parameters_array); } + + + public function insertBenutzerfunktion($Json) + { + unset($Json['benutzerfunktion_id']); + unset($Json['updateamum']); + $Json['insertvon'] = getAuthUID(); + $Json['insertamum'] = $this->escape('NOW()'); + + if ($Json['datum_bis']=='') + { + unset($Json['datum_bis']); + } + + $result = $this->insert($Json); + + if (isError($result)) + { + return error($result->msg, EXIT_ERROR); + } + + $record = $this->load($result->retval); + + return $record; + } + + function updateBenutzerfunktion($funktionJson) + { + $funktionJson['updatevon'] = getAuthUID(); + $funktionJson['updateamum'] = $this->escape('NOW()'); + + $result = $this->update($funktionJson['benutzerfunktion_id'], $funktionJson); + + if (isError($result)) + { + return error($result->msg, EXIT_ERROR); + } + + $result = $this->load($funktionJson['benutzerfunktion_id']); + + return $result; + } + + function deleteBenutzerfunktion($funktionJson) + { + $result = $this->delete($funktionJson); + + if (isError($result)) + { + return error($result->msg, EXIT_ERROR); + } + + return success($funktionJson); + } + + } diff --git a/application/models/person/Person_model.php b/application/models/person/Person_model.php index 2063505bf..88813220e 100644 --- a/application/models/person/Person_model.php +++ b/application/models/person/Person_model.php @@ -1,5 +1,22 @@ . + */ + class Person_model extends DB_Model { /** @@ -8,6 +25,7 @@ class Person_model extends DB_Model public function __construct() { parent::__construct(); + $this->dbTable = 'public.tbl_person'; $this->pk = 'person_id'; @@ -70,7 +88,7 @@ class Person_model extends DB_Model if (isset($person['svnr']) && $person['svnr'] != '') { $this->PersonModel->addOrder('svnr', 'DESC'); - $result = $this->PersonModel->loadWhere(array( + $result = $this->PersonModel->loadWhere(array( 'person_id != ' => $person['person_id'], 'SUBSTRING(svnr FROM 1 FOR 10) = ' => $person['svnr']) ); @@ -138,7 +156,8 @@ class Person_model extends DB_Model 'lower(nachname) like '.$this->db->escape('%'.$filter.'%')." OR lower(vorname) like ".$this->db->escape('%'.$filter.'%')." OR lower(nachname || ' ' || vorname) like ".$this->db->escape('%'.$filter.'%')." - OR lower(vorname || ' ' || nachname) like ".$this->db->escape('%'.$filter.'%')); + OR lower(vorname || ' ' || nachname) like ".$this->db->escape('%'.$filter.'%') + ); return $result; } @@ -152,8 +171,12 @@ class Person_model extends DB_Model */ public function getPersonStammdaten($person_id, $zustellung_only = false) { - $this->addSelect('public.tbl_person.*, tbl_person.staatsbuergerschaft AS staatsbuergerschaft_code, tbl_person.geburtsnation AS geburtsnation_code, - s.kurztext as staatsbuergerschaft, g.kurztext as geburtsnation'); + $this->addSelect('public.tbl_person.*, + tbl_person.staatsbuergerschaft AS staatsbuergerschaft_code, + tbl_person.geburtsnation AS geburtsnation_code, + s.kurztext as staatsbuergerschaft, + g.kurztext as geburtsnation' + ); $this->addJoin('bis.tbl_nation s', 'public.tbl_person.staatsbuergerschaft = s.nation_code', 'LEFT'); $this->addJoin('bis.tbl_nation g', 'public.tbl_person.geburtsnation = g.nation_code', 'LEFT'); @@ -258,7 +281,8 @@ class Person_model extends DB_Model */ public function getFullName($uid) { - if (!$result = getData($this->getByUid($uid))[0]) + $result = getData($this->getByUid($uid))[0]; + if (!$result) { show_error('Failed loading person'); } @@ -351,3 +375,4 @@ class Person_model extends DB_Model ]); } } + diff --git a/application/models/ressource/Mitarbeiter_model.php b/application/models/ressource/Mitarbeiter_model.php index 90c30927f..900b88684 100644 --- a/application/models/ressource/Mitarbeiter_model.php +++ b/application/models/ressource/Mitarbeiter_model.php @@ -144,10 +144,15 @@ class Mitarbeiter_model extends DB_Model * Checks if alias exists * @param $kurzbz */ - public function kurzbzExists($kurzbz) + public function kurzbzExists($kurzbz, $uid=null) { $this->addSelect('1'); - $result = $this->loadWhere(array('kurzbz' => $kurzbz)); + $where = array('kurzbz' => $kurzbz); + if ($uid != null) + { + $where['mitarbeiter_uid<>'] = $uid; + } + $result = $this->loadWhere($where); if (isSuccess($result)) { @@ -171,7 +176,6 @@ class Mitarbeiter_model extends DB_Model */ public function generateKurzbz($uid) { - $kurzbz = ''; $this->addLimit(1); $this->addSelect('vorname, nachname'); $this->addJoin('public.tbl_benutzer', 'tbl_mitarbeiter.mitarbeiter_uid = tbl_benutzer.uid'); @@ -181,25 +185,35 @@ class Mitarbeiter_model extends DB_Model if (hasData($nameresult)) { $kurzbzdata = getData($nameresult); - $nachname_clean = sanitizeProblemChars($kurzbzdata[0]->nachname); - $vorname_clean = sanitizeProblemChars($kurzbzdata[0]->vorname); + $genKurzbz = $this->generateKurzbzHelper($kurzbzdata[0]->vorname, $kurzbzdata[0]->nachname); - for ($nn = 6, $vn = 2; $nn != 0; $nn--, $vn++) - { - $kurzbz = mb_substr($nachname_clean, 0, $nn); - $kurzbz .= mb_substr($vorname_clean, 0, $vn); + return $genKurzbz; + } + return error('No Kurzbezeichnung could be generated'); + } - $kurzbzexists = $this->kurzbzExists($kurzbz); + public function generateKurzbzHelper($vorname, $nachname) + { + $nachname_clean = sanitizeProblemChars($nachname); + $vorname_clean = sanitizeProblemChars($vorname); + $kurzbz = ''; - if (hasData($kurzbzexists) && !getData($kurzbzexists)[0]) - break; - } + for ($nn = 6, $vn = 2; $nn != 0; $nn--, $vn++) + { + $kurzbz = mb_substr($nachname_clean, 0, $nn); + $kurzbz .= mb_substr($vorname_clean, 0, $vn); $kurzbzexists = $this->kurzbzExists($kurzbz); - if (hasData($kurzbzexists) && getData($kurzbzexists)[0]) - return error('No Kurzbezeichnung could be generated'); + if (hasData($kurzbzexists) && !getData($kurzbzexists)[0]) + break; } + + $kurzbzexists = $this->kurzbzExists($kurzbz); + + if (hasData($kurzbzexists) && getData($kurzbzexists)[0]) + return error('No Kurzbezeichnung could be generated'); + return success($kurzbz); } } diff --git a/application/models/ressource/Stundensatz_model.php b/application/models/ressource/Stundensatz_model.php new file mode 100644 index 000000000..c397d8573 --- /dev/null +++ b/application/models/ressource/Stundensatz_model.php @@ -0,0 +1,17 @@ +dbTable = 'hr.tbl_stundensatz'; + $this->pk = 'stundensatz_id'; + $this->hasSequence = true; + } + +} \ No newline at end of file diff --git a/application/models/ressource/Stundensatztyp_model.php b/application/models/ressource/Stundensatztyp_model.php new file mode 100644 index 000000000..8dfd54c7d --- /dev/null +++ b/application/models/ressource/Stundensatztyp_model.php @@ -0,0 +1,16 @@ +dbTable = 'hr.tbl_stundensatztyp'; + $this->pk = 'stundensatztyp'; + } + +} \ No newline at end of file diff --git a/application/models/system/PersonLog_model.php b/application/models/system/PersonLog_model.php index 7a66958b8..88b50487a 100644 --- a/application/models/system/PersonLog_model.php +++ b/application/models/system/PersonLog_model.php @@ -1,5 +1,22 @@ . + */ + class PersonLog_model extends DB_Model { /** @@ -17,7 +34,7 @@ class PersonLog_model extends DB_Model * @param array $data Data of Log Entry to save. * @return success object if true */ - public function insert($data) + public function insert($data, $encryptedColumns = null) { $result = $this->db->insert($this->dbTable, $data); if ($result) diff --git a/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php b/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php new file mode 100644 index 000000000..5b276c55e --- /dev/null +++ b/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php @@ -0,0 +1,176 @@ +dbTable = 'hr.tbl_dienstverhaeltnis'; + $this->pk = 'dienstverhaeltnis_id'; + } + + /** + * @return list of DV + */ + public function getDVByPersonUID($uid, $oe_kurzbz=null, $datum=null) + { + $result = null; + + $qry = " + SELECT + dv.dienstverhaeltnis_id, + tbl_benutzer.uid, + tbl_mitarbeiter.personalnummer, + tbl_mitarbeiter.kurzbz, + tbl_mitarbeiter.lektor, + tbl_mitarbeiter.fixangestellt, + tbl_person.person_id, + tbl_benutzer.alias, + org.oe_kurzbz, + org.bezeichnung oe_bezeichnung, + dv.von, + dv.bis, + dv.vertragsart_kurzbz, + dv.updateamum, + dv.updatevon + FROM tbl_mitarbeiter + JOIN tbl_benutzer ON tbl_mitarbeiter.mitarbeiter_uid::text = tbl_benutzer.uid::text + JOIN tbl_person USING (person_id) + JOIN hr.tbl_dienstverhaeltnis dv ON(tbl_benutzer.uid::text = dv.mitarbeiter_uid::text) + JOIN public.tbl_organisationseinheit org USING(oe_kurzbz) + WHERE tbl_benutzer.uid=?"; + $data = array($uid); + + if(!is_null($oe_kurzbz)) + { + $qry.=" AND oe_kurzbz=?"; + $data[] = $oe_kurzbz; + } + + if (!is_null($datum)) + { + $qry.=" AND ? BETWEEN dv.von AND COALESCE(dv.bis, '2999-12-31')"; + $data[] = $datum; + } + + $qry .=" + ORDER BY dv.von desc + "; + + return $this->execQuery($qry, $data); + + } + + public function getDVByID($dvid) { + $this->addSelect('hr.tbl_dienstverhaeltnis.*, public.tbl_organisationseinheit.bezeichnung as unternehmen'); + $this->addJoin('public.tbl_organisationseinheit', 'hr.tbl_dienstverhaeltnis.oe_kurzbz = public.tbl_organisationseinheit.oe_kurzbz'); + $result = $this->load($dvid); + + if (hasData($result)) { + return $result; + } + return error('could not fetch DV by ID'); + } + + + public function getCurrentDVByPersonUID($uid, $dateAsUnixTS) + { + + $date = DateTime::createFromFormat( 'U', $dateAsUnixTS ); + $datestring = $date->format("Y-m-d"); + + $qry = " + SELECT + dv.dienstverhaeltnis_id, + tbl_benutzer.uid, + tbl_mitarbeiter.personalnummer, + tbl_mitarbeiter.kurzbz, + tbl_mitarbeiter.lektor, + tbl_mitarbeiter.fixangestellt, + tbl_person.person_id, + tbl_benutzer.alias, + dv.von, + dv.bis, + dv.vertragsart_kurzbz, + dv.updateamum, + dv.updatevon + FROM tbl_mitarbeiter + JOIN tbl_benutzer ON tbl_mitarbeiter.mitarbeiter_uid::text = tbl_benutzer.uid::text + JOIN tbl_person USING (person_id) + JOIN hr.tbl_dienstverhaeltnis dv ON(tbl_benutzer.uid::text = dv.mitarbeiter_uid::text) + WHERE tbl_benutzer.uid=? and (dv.von<=? and (dv.bis is null OR dv.bis>=?)) + ORDER BY dv.von desc + "; + + return $this->execQuery($qry, array($uid, $datestring, $datestring)); + } + + public function isOverlappingExistingDV($mitarbeiter_uid, $oe_kurzbz, $von, $bis, $dvid=null) + { + $params = array($mitarbeiter_uid, $oe_kurzbz, $von, $bis, $von, $bis); + $dvidclause = ''; + if (intval($dvid) > 0) + { + $params = array_merge($params, array($dvid, $dvid)); + $dvidclause = <<= COALESCE(vb.von, '1970-01-01'::date) + AND + COALESCE(dv.bis::date, '2170-12-31'::date) <= COALESCE(vb.bis, '2170-12-31') + ) = 0 + AND dv.dienstverhaeltnis_id != ? +EODVIDC; + + } + + $query = <<= dv.von + AND ( + SELECT + COUNT(*) AS karenzen + FROM + hr.tbl_vertragsbestandteil vb + WHERE + vb.dienstverhaeltnis_id = dv.dienstverhaeltnis_id + AND + vb.vertragsbestandteiltyp_kurzbz = 'karenz' + AND + ?::date >= COALESCE(vb.von, '1970-01-01'::date) + AND + COALESCE(?::date, '2170-12-31'::date) <= COALESCE(vb.bis, '2170-12-31') + ) = 0 + {$dvidclause} +EOSQL; + + $ret = $this->execReadOnlyQuery($query, $params); + + if( ($dvcount = getData($ret)) && ($dvcount[0]->dvcount > 0) ) { + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php b/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php new file mode 100644 index 000000000..e9006dfc0 --- /dev/null +++ b/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php @@ -0,0 +1,147 @@ +dbTable = 'hr.tbl_gehaltsbestandteil'; + $this->pk = 'gehaltsbestandteil_id'; + } + + public function getEncryptedColumns(): array + { + return array( + 'grundbetrag' => array( + DB_Model::CRYPT_CAST => 'numeric', + DB_Model::CRYPT_PASSWORD_NAME => 'ENCRYPTIONKEYGEHALT' + ), + 'betrag_valorisiert' => array( + DB_Model::CRYPT_CAST => 'numeric', + DB_Model::CRYPT_PASSWORD_NAME => 'ENCRYPTIONKEYGEHALT' + ) + ); + } + + public function getCurrentGBTByDV($dienstverhaeltnis_id, $dateAsUnixTS) + { + $date = DateTime::createFromFormat( 'U', $dateAsUnixTS ); + $datestring = $date->format("Y-m-d"); + + $qry = " + SELECT + gehaltsbestandteil_id, + gbt.von, + gbt.bis, + gbt.anmerkung, + gbt.dienstverhaeltnis_id, + gehaltstyp_kurzbz, + valorisierungssperre, + gbt.valorisierung, + grundbetrag as grund_betrag_decrypted, + betrag_valorisiert as betrag_val_decrypted, + gt.bezeichnung as gehaltstyp_bezeichnung, + vb.vertragsbestandteiltyp_kurzbz, + bf.funktion_kurzbz, + bf.oe_kurzbz, + fkt.beschreibung as fkt_beschreibung, + fb.bezeichnung as fb_bezeichnung, + org.bezeichnung as org_bezeichnung, + freitext.freitexttyp_kurzbz, + freitext.titel as freitext_titel + FROM hr.tbl_gehaltsbestandteil gbt LEFT JOIN hr.tbl_gehaltstyp gt using(gehaltstyp_kurzbz) + LEFT JOIN hr.tbl_vertragsbestandteil vb using(vertragsbestandteil_id) + LEFT JOIN hr.tbl_vertragsbestandteil_funktion vbf using(vertragsbestandteil_id) + LEFT JOIN public.tbl_benutzerfunktion bf using(benutzerfunktion_id) + LEFT JOIN public.tbl_funktion fkt using(funktion_kurzbz) + LEFT JOIN public.tbl_fachbereich fb using(fachbereich_kurzbz) + LEFT JOIN public.tbl_organisationseinheit org on (bf.oe_kurzbz=org.oe_kurzbz) + LEFT JOIN hr.tbl_vertragsbestandteil_freitext freitext on(vb.vertragsbestandteil_id=freitext.vertragsbestandteil_id) + WHERE gbt.dienstverhaeltnis_id=? AND + (gbt.von<=? and (gbt.bis is null OR gbt.bis>=?)) + ORDER BY gt.sort + "; + + return $this->execQuery($qry, + array($dienstverhaeltnis_id, $datestring, $datestring), + $this->getEncryptedColumns()); + } + + public function getGBTChartDataByDV_old($dienstverhaeltnis_id) + { + + $qry = " + WITH gbt as + (select von,bis,grundbetrag as grund_betrag_decrypted from hr.tbl_gehaltsbestandteil where dienstverhaeltnis_id=?) + select von,bis, (select sum(gbt.grund_betrag_decrypted) as sum_betrag + from gbt where gbt.von<=gbtmeta.von and (gbt.bis is null or gbt.bis>=gbtmeta.von) + ) as summe from gbt as gbtmeta order by von,bis + "; + + return $this->execQuery($qry, + array($dienstverhaeltnis_id), + $this->getEncryptedColumns()); + } + + + public function getGehaltsbestandteile($dienstverhaeltnis_id, $stichtag=null, $includefuture=false) + { + $stichtagclause = ''; + if( !is_null($stichtag) ) + { + $date = strftime('%Y-%m-%d', strtotime($stichtag)); + $stichtagclause = 'AND (' . $this->escape($date) + . ' BETWEEN COALESCE(von, \'1970-01-01\'::date)' + . ' AND COALESCE(bis, \'2170-01-01\'::date)'; + if( $includefuture ) + { + $stichtagclause .= ' OR COALESCE(von, \'1970-01-01\'::date) > ' + . $this->escape($date); + } + $stichtagclause .= ')'; + } + + $this->addSelect('*'); + $where = <<escape($dienstverhaeltnis_id)} + {$stichtagclause} +EOSQL; + + $query = $this->loadWhere( + $where, + $this->getEncryptedColumns() + ); + + $gehaltsbestandteile = array(); + if( null !== ($rows = getData($query)) ) + { + foreach( $rows as $row ) { + $tmpgb = new Gehaltsbestandteil(); + $tmpgb->hydrateByStdClass($row, true); + $gehaltsbestandteile[] = $tmpgb; + } + } + + return $gehaltsbestandteile; + } + + + public function getGehaltsbestandteil($id) + { + $this->addSelect('*'); + $query = $this->load($id, $this->getEncryptedColumns()); + $gehaltsbestandteil = null; + + if( null !== ($row = getData($query)) ) + { + $gehaltsbestandteil = new Gehaltsbestandteil(); + $gehaltsbestandteil->hydrateByStdClass($row[0], true); + } + + return $gehaltsbestandteil; + } +} diff --git a/application/models/vertragsbestandteil/IEncryption.php b/application/models/vertragsbestandteil/IEncryption.php new file mode 100644 index 000000000..ebfb437ea --- /dev/null +++ b/application/models/vertragsbestandteil/IEncryption.php @@ -0,0 +1,7 @@ +dbTable = 'hr.tbl_vertragsbestandteil_freitext'; + $this->pk = 'vertragsbestandteil_id'; + } + + public function countOverlappingVBFreitextsOfSameType(vertragsbestandteil\VertragsbestandteilFreitext $vbft) + { + $notselfclause = (intval($vbft->getVertragsbestandteil_id()) > 0) + ? 'AND v.vertragsbestandteil_id <> ' . $this->escape($vbft->getVertragsbestandteil_id()) + : ''; + $sql = <<= COALESCE(v.von, '1970-01-01'::date) + AND + ?::date <= COALESCE(v.bis, '2170-12-31') + {$notselfclause} +EOSQL; + $ret = $this->execReadOnlyQuery($sql, array( + $vbft->getDienstverhaeltnis_id(), + $vbft->getVertragsbestandteiltyp_kurzbz(), + $vbft->getFreitexttypKurzbz(), + $vbft->getBis(), + $vbft->getVon() + )); + + if( null === ($vbcount = getData($ret)) ) { + throw new Exception('failed to fetch overlappingvbs count'); + } + + return $vbcount[0]->overlappingvbs; + } +} diff --git a/application/models/vertragsbestandteil/VertragsbestandteilFreitexttyp_model.php b/application/models/vertragsbestandteil/VertragsbestandteilFreitexttyp_model.php new file mode 100644 index 000000000..09d2380b6 --- /dev/null +++ b/application/models/vertragsbestandteil/VertragsbestandteilFreitexttyp_model.php @@ -0,0 +1,12 @@ +dbTable = 'hr.tbl_vertragsbestandteil_freitexttyp'; + $this->pk = 'freitexttyp_kurzbz'; + } +} diff --git a/application/models/vertragsbestandteil/VertragsbestandteilFunktion_model.php b/application/models/vertragsbestandteil/VertragsbestandteilFunktion_model.php new file mode 100644 index 000000000..7263ac893 --- /dev/null +++ b/application/models/vertragsbestandteil/VertragsbestandteilFunktion_model.php @@ -0,0 +1,35 @@ +dbTable = 'hr.tbl_vertragsbestandteil_funktion'; + $this->pk = 'vertragsbestandteil_id'; + } + + public function isBenutzerfunktionAlreadyAttachedToAnotherVB($benutzerfunktion_id, $vertragsbestandteil_id) + { + $where = array('benutzerfunktion_id' => $benutzerfunktion_id); + if( intval($vertragsbestandteil_id) > 0 ) + { + $where['vertragsbestandteil_id != '] = $vertragsbestandteil_id; + } + $this->addSelect('count(*) AS vbscount'); + $res = $this->loadWhere($where); + if(isError($res)) + { + throw new Exception('failed to check if benutzerfunktionid is already attached to another vertragsbestanteil'); + } + $count = (getData($res))[0]->vbscount; + return $count > 0; + } +} diff --git a/application/models/vertragsbestandteil/VertragsbestandteilKarenz_model.php b/application/models/vertragsbestandteil/VertragsbestandteilKarenz_model.php new file mode 100644 index 000000000..525291439 --- /dev/null +++ b/application/models/vertragsbestandteil/VertragsbestandteilKarenz_model.php @@ -0,0 +1,14 @@ +dbTable = 'hr.tbl_vertragsbestandteil_karenz'; + $this->pk = 'vertragsbestandteil_id'; + } +} diff --git a/application/models/vertragsbestandteil/VertragsbestandteilKuendigungsfrist_model.php b/application/models/vertragsbestandteil/VertragsbestandteilKuendigungsfrist_model.php new file mode 100644 index 000000000..ccb02dd88 --- /dev/null +++ b/application/models/vertragsbestandteil/VertragsbestandteilKuendigungsfrist_model.php @@ -0,0 +1,14 @@ +dbTable = 'hr.tbl_vertragsbestandteil_kuendigungsfrist'; + $this->pk = 'vertragsbestandteil_id'; + } +} diff --git a/application/models/vertragsbestandteil/VertragsbestandteilStunden_model.php b/application/models/vertragsbestandteil/VertragsbestandteilStunden_model.php new file mode 100644 index 000000000..569c9a601 --- /dev/null +++ b/application/models/vertragsbestandteil/VertragsbestandteilStunden_model.php @@ -0,0 +1,18 @@ +dbTable = 'hr.tbl_vertragsbestandteil_stunden'; + $this->pk = 'vertragsbestandteil_id'; + } +} diff --git a/application/models/vertragsbestandteil/VertragsbestandteilTyp_model.php b/application/models/vertragsbestandteil/VertragsbestandteilTyp_model.php new file mode 100644 index 000000000..f64cb70f4 --- /dev/null +++ b/application/models/vertragsbestandteil/VertragsbestandteilTyp_model.php @@ -0,0 +1,12 @@ +dbTable = 'hr.tbl_vertragsbestandteiltyp'; + $this->pk = 'vertragsbestandteiltyp_kurzbz'; + } +} diff --git a/application/models/vertragsbestandteil/VertragsbestandteilUrlaubsanspruch_model.php b/application/models/vertragsbestandteil/VertragsbestandteilUrlaubsanspruch_model.php new file mode 100644 index 000000000..561ed2932 --- /dev/null +++ b/application/models/vertragsbestandteil/VertragsbestandteilUrlaubsanspruch_model.php @@ -0,0 +1,11 @@ +dbTable = 'hr.tbl_vertragsbestandteil_urlaubsanspruch'; + $this->pk = 'vertragsbestandteil_id'; + } +} diff --git a/application/models/vertragsbestandteil/VertragsbestandteilZeitaufzeichnung_model.php b/application/models/vertragsbestandteil/VertragsbestandteilZeitaufzeichnung_model.php new file mode 100644 index 000000000..8e2d45e1a --- /dev/null +++ b/application/models/vertragsbestandteil/VertragsbestandteilZeitaufzeichnung_model.php @@ -0,0 +1,12 @@ +dbTable = 'hr.tbl_vertragsbestandteil_zeitaufzeichnung'; + $this->pk = 'vertragsbestandteil_id'; + } +} diff --git a/application/models/vertragsbestandteil/Vertragsbestandteil_model.php b/application/models/vertragsbestandteil/Vertragsbestandteil_model.php new file mode 100644 index 000000000..6d8c18859 --- /dev/null +++ b/application/models/vertragsbestandteil/Vertragsbestandteil_model.php @@ -0,0 +1,181 @@ +dbTable = 'hr.tbl_vertragsbestandteil'; + $this->pk = 'vertragsbestandteil_id'; + } + + protected function getVertragsbestandteilSQL() + { + $sql = <<escape($date) + . ' BETWEEN COALESCE(v.von, \'1970-01-01\'::date)' + . ' AND COALESCE(v.bis, \'2170-01-01\'::date)'; + if( $includefuture ) + { + $stichtagclause .= ' OR COALESCE(v.von, \'1970-01-01\'::date) > ' + . $this->escape($date); + } + $stichtagclause .= ')'; + } + + $sql = <<getVertragsbestandteilSQL()} + WHERE + v.dienstverhaeltnis_id = {$this->escape($dienstverhaeltnis_id)} + {$stichtagclause} + ; +EOSQL; + + // echo $sql . "\n\n"; + $query = $this->execReadOnlyQuery($sql); // TODO add decryption + $data = getData($query); + + if ($data == null) + { + return array(); + } + + $vertragsbestandteile = array(); + foreach( $data as $row ) { + try + { + $vertragsbestandteile[] = VertragsbestandteilFactory::getVertragsbestandteil($row, true); + } + catch (Exception $ex) + { + echo $ex->getMessage() . "\n"; + } + } + + $dummy = json_encode($vertragsbestandteile); + return $vertragsbestandteile; + } + + + public function getVertragsbestandteil($id) + { + + $sql = <<getVertragsbestandteilSQL()} + WHERE + v.vertragsbestandteil_id = {$this->escape($id)} + ; +EOSQL; + + $query = $this->execReadOnlyQuery($sql); + + $vertragsbestandteil = null; + + if( hasData($query) ) + { + $data = getData($query)[0]; + try + { + $vertragsbestandteil = VertragsbestandteilFactory::getVertragsbestandteil($data, true); // TODO add decryption + } + catch (Exception $ex) + { + echo $ex->getMessage() . "\n"; + } + } + + return $vertragsbestandteil; + + } + + public function countOverlappingVBsOfSameType(vertragsbestandteil\Vertragsbestandteil $vb) + { + $notselfclause = (intval($vb->getVertragsbestandteil_id()) > 0) + ? 'AND v.vertragsbestandteil_id <> ' . $this->escape($vb->getVertragsbestandteil_id()) + : ''; + $sql = <<= COALESCE(v.von, '1970-01-01'::date) + AND + ?::date <= COALESCE(v.bis, '2170-12-31') + {$notselfclause} +EOSQL; + $ret = $this->execReadOnlyQuery($sql, array( + $vb->getDienstverhaeltnis_id(), + $vb->getVertragsbestandteiltyp_kurzbz(), + $vb->getBis(), + $vb->getVon() + )); + + if( null === ($vbcount = getData($ret)) ) { + throw new Exception('failed to fetch overlappingvbs count'); + } + + return $vbcount[0]->overlappingvbs; + } +} diff --git a/application/views/codex/bismeldestichtag.php b/application/views/codex/bismeldestichtag.php new file mode 100644 index 000000000..37af16cc6 --- /dev/null +++ b/application/views/codex/bismeldestichtag.php @@ -0,0 +1,75 @@ + 'Bismeldestichtage', + 'axios027' => true, + 'bootstrap5' => true, + 'fontawesome6' => true, + 'vue3' => true, + 'filtercomponent' => true, + 'navigationcomponent' => true, + 'tabulator5' => true, + 'customCSSs' => array('vendor/vuejs/vuedatepicker_css/main.css'), + 'customJSs' => array('vendor/vuejs/vuedatepicker_js/vue-datepicker.iife.js'), + 'customJSModules' => array('public/js/apps/Bismeldestichtag/Bismeldestichtag.js') + ); + + $this->load->view('templates/FHC-Header', $includesArray); +?> +
+ + + + + + + + +
+ +
+
+ + +
+
+ +
+
+ +
+
+
+ +
+
+ + +
+
+
+
+ +load->view('templates/FHC-Footer', $includesArray); ?> diff --git a/application/views/codex/uhstat1.php b/application/views/codex/uhstat1.php index a09f9c70a..78a30b3e5 100644 --- a/application/views/codex/uhstat1.php +++ b/application/views/codex/uhstat1.php @@ -47,6 +47,9 @@ $saved = isset($saved) && $saved === true;

p->t('uhstat', 'uhstat1AnmeldungEinleitungstext') ?>

+

+ p->t('uhstat', 'uhstat1EinleitungSvnrtext') ?> +


diff --git a/application/views/person/bpk/bpkDetails.php b/application/views/person/bpk/bpkDetails.php index 198065c24..bd6191c6a 100644 --- a/application/views/person/bpk/bpkDetails.php +++ b/application/views/person/bpk/bpkDetails.php @@ -9,7 +9,6 @@ 'jqueryui1' => true, 'ajaxlib' => true, 'tablesorter2' => true, - 'tinymce4' => true, 'sbadmintemplate3' => true, 'addons' => true, 'navigationwidget' => true, @@ -126,10 +125,18 @@
-
+ - +
diff --git a/application/views/system/infocenter/infocenterAbgewiesenData.php b/application/views/system/infocenter/infocenterAbgewiesenData.php index 2307ea87e..da816b2c7 100644 --- a/application/views/system/infocenter/infocenterAbgewiesenData.php +++ b/application/views/system/infocenter/infocenterAbgewiesenData.php @@ -31,21 +31,35 @@ $query = ' ORDER BY l.log_id DESC LIMIT 1 ) - AND '. $LOGDATA_VON .' = ( + AND ('. $LOGDATA_VON .' = ( SELECT l.insertvon FROM system.tbl_log l WHERE l.person_id = p.person_id ORDER BY l.log_id DESC LIMIT 1 ) + OR + ( + ( + SELECT l.insertvon + FROM system.tbl_log l + WHERE l.person_id = p.person_id + ORDER BY l.log_id DESC + LIMIT 1 + ) IS NULL + ) + ) AND l.zeitpunkt >= pss.insertamum ORDER BY l.log_id DESC LIMIT 1 ) AS "Nachricht", ( - SELECT SUM(konto.betrag) + SELECT + CASE + WHEN COUNT(CASE WHEN konto.betrag != 0 THEN 1 END) = 0 THEN null + ELSE SUM(konto.betrag) + END AS "Kaution" FROM public.tbl_konto konto - LEFT JOIN tbl_konto skonto ON (skonto.buchungsnr_verweis = konto.buchungsnr) WHERE konto.person_id = p.person_id AND konto.studiensemester_kurzbz = '. $STUDIENSEMESTER .' AND konto.buchungstyp_kurzbz = '. $STUDIENGEBUEHR_ANZAHLUNG .' diff --git a/application/views/system/infocenter/infocenterData.php b/application/views/system/infocenter/infocenterData.php index bb5b84479..61dc5a575 100644 --- a/application/views/system/infocenter/infocenterData.php +++ b/application/views/system/infocenter/infocenterData.php @@ -292,9 +292,12 @@ rueck.datum_bis AS "HoldDate", rueck.bezeichnung AS "Rueckstellgrund", ( - SELECT SUM(konto.betrag) + SELECT + CASE + WHEN COUNT(CASE WHEN konto.betrag != 0 THEN 1 END) = 0 THEN null + ELSE SUM(konto.betrag) + END AS "Kaution" FROM public.tbl_konto konto - LEFT JOIN tbl_konto skonto ON (skonto.buchungsnr_verweis = konto.buchungsnr) WHERE konto.person_id = p.person_id AND konto.studiensemester_kurzbz = '. $STUDIENSEMESTER .' AND konto.buchungstyp_kurzbz = '. $STUDIENGEBUEHR_ANZAHLUNG .' diff --git a/application/views/system/infocenter/infocenterDetails.php b/application/views/system/infocenter/infocenterDetails.php index c61bb3cd2..a8e6e3e13 100644 --- a/application/views/system/infocenter/infocenterDetails.php +++ b/application/views/system/infocenter/infocenterDetails.php @@ -8,7 +8,7 @@ 'dialoglib' => true, 'ajaxlib' => true, 'tablesorter2' => true, - 'tinymce4' => true, + 'tinymce5' => true, 'sbadmintemplate3' => true, 'addons' => true, 'navigationwidget' => true, diff --git a/application/views/system/infocenter/infocenterFreigegebenData.php b/application/views/system/infocenter/infocenterFreigegebenData.php index 32315c145..8003b42e0 100644 --- a/application/views/system/infocenter/infocenterFreigegebenData.php +++ b/application/views/system/infocenter/infocenterFreigegebenData.php @@ -267,9 +267,12 @@ $query = ' LIMIT 1 ) AS "AktenId", ( - SELECT SUM(konto.betrag) + SELECT + CASE + WHEN COUNT(CASE WHEN konto.betrag != 0 THEN 1 END) = 0 THEN null + ELSE SUM(konto.betrag) + END AS "Kaution" FROM public.tbl_konto konto - LEFT JOIN tbl_konto skonto ON (skonto.buchungsnr_verweis = konto.buchungsnr) WHERE konto.person_id = p.person_id AND konto.studiensemester_kurzbz = '. $STUDIENSEMESTER .' AND konto.buchungstyp_kurzbz = '. $STUDIENGEBUEHR_ANZAHLUNG .' diff --git a/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php b/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php index e6b6d2495..7f9ee1288 100644 --- a/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php +++ b/application/views/system/infocenter/infocenterReihungstestAbsolviertData.php @@ -198,7 +198,11 @@ $query = ' LIMIT 1 ) AS "InfoCenterMitarbeiter", ( - SELECT SUM(konto.betrag) + SELECT + CASE + WHEN COUNT(CASE WHEN konto.betrag != 0 THEN 1 END) = 0 THEN null + ELSE SUM(konto.betrag) + END AS "Kaution" FROM public.tbl_konto konto WHERE konto.person_id = p.person_id AND konto.studiensemester_kurzbz = '. $STUDIENSEMESTER .' diff --git a/application/views/system/infocenter/infocenterZgvDetails.php b/application/views/system/infocenter/infocenterZgvDetails.php index 7636647ab..aefd95da0 100644 --- a/application/views/system/infocenter/infocenterZgvDetails.php +++ b/application/views/system/infocenter/infocenterZgvDetails.php @@ -10,7 +10,7 @@ 'dialoglib' => true, 'ajaxlib' => true, 'tablesorter2' => true, - 'tinymce4' => true, + 'tinymce5' => true, 'sbadmintemplate3' => true, 'addons' => true, 'navigationwidget' => true, @@ -131,7 +131,11 @@ p->t('infocenter', 'zgvNichtErfuellt') ?> - diff --git a/application/views/system/infocenter/zgvpruefungen.php b/application/views/system/infocenter/zgvpruefungen.php index 1d26b9d55..b021379a8 100644 --- a/application/views/system/infocenter/zgvpruefungen.php +++ b/application/views/system/infocenter/zgvpruefungen.php @@ -447,7 +447,6 @@
diff --git a/application/views/system/logs/testVBform.php b/application/views/system/logs/testVBform.php new file mode 100644 index 000000000..566abb1cb --- /dev/null +++ b/application/views/system/logs/testVBform.php @@ -0,0 +1,16 @@ + 'Test VBform', + 'bootstrap5' => true, + 'fontawesome6' => true, + 'vue3' => true, + 'customJSModules' => array('public/js/apps/vbform/vbform.js') + ); + + $this->load->view('templates/FHC-Header', $includesArray); +?> + +
+ +load->view('templates/FHC-Footer', $includesArray); ?> + diff --git a/application/views/system/messages/FAShtmlWriteTemplate.php b/application/views/system/messages/FAShtmlWriteTemplate.php new file mode 100644 index 000000000..83f895d14 --- /dev/null +++ b/application/views/system/messages/FAShtmlWriteTemplate.php @@ -0,0 +1,197 @@ +load->view( + 'templates/FHC-Header', + array( + 'title' => 'Write a new message or reply using templates', + 'jquery3' => true, + 'jqueryui1' => true, + 'bootstrap3' => true, + 'ajaxlib' => true, + 'fontawesome4' => true, + 'tinymce3' => true, + 'sbadmintemplate3' => true, + 'dialoglib' => true, + 'widgets' => true, + 'customCSSs' => array('public/css/sbadmin2/admintemplate_contentonly.css', 'public/css/messaging/message.css'), + 'customJSs' => array('public/js/bootstrapper.js', 'public/js/messaging/fasMessageWrite.js') + ) + ); +?> + +
+
+
+
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+   +
+ +
+
+
+
+
+
+ + +
+
+
+ + + 19 ? 19 : count($variables); + echo $this->widgetlib->widget( + 'MultipleDropdown_widget', + array('elements' => success($variables)), + array( + 'name' => 'variables[]', + 'id' => 'variables', + 'size' => $size, + 'multiple' => true + ) + ); + ?> +
+
+
+ + + 5 ? 5 : count($user_fields); + echo $this->widgetlib->widget( + 'MultipleDropdown_widget', + array('elements' => success($user_fields)), + array( + 'name' => 'user_fields[]', + 'id' => 'user_fields', + 'size' => $size, + 'multiple' => true + ) + ); + ?> +
+
+
+
+
+
+ + widgetlib->widget( + 'Vorlage_widget', + array('oe_kurzbz' => $organisationUnits, 'isAdmin' => $senderIsAdmin), + array('name' => 'vorlage', 'id' => 'vorlageDnD') + ); + ?> + +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+ widgetlib->widget( + 'Dropdown_widget', + array( + 'elements' => success($recipientsArray), + 'emptyElement' => ucfirst($this->p->t('global', 'empfaenger')).'...' + ), + array( + 'name' => 'recipients[]', + 'id' => 'recipients' + ) + ); + ?> + + + p->t('ui', 'refresh')); ?> + + +
+
+
+
+
+ +
+ + + + + +
+
+
+
+ + +load->view("templates/FHC-Footer"); ?> + diff --git a/application/views/system/messages/ajaxRead.php b/application/views/system/messages/ajaxRead.php index 2cb88708e..4c1a77deb 100644 --- a/application/views/system/messages/ajaxRead.php +++ b/application/views/system/messages/ajaxRead.php @@ -12,7 +12,7 @@ 'tabulator4' => true, 'ajaxlib' => true, 'dialoglib' => true, - 'tinymce4' => true, + 'tinymce5' => true, 'phrases' => array('global', 'ui'), 'customCSSs' => array('public/css/sbadmin2/admintemplate_contentonly.css', 'public/css/messaging/message.css'), 'customJSs' => array('public/js/bootstrapper.js', 'public/js/messaging/read.js') diff --git a/application/views/system/messages/ajaxWrite.php b/application/views/system/messages/ajaxWrite.php index 3b1582f22..b3a598506 100644 --- a/application/views/system/messages/ajaxWrite.php +++ b/application/views/system/messages/ajaxWrite.php @@ -10,7 +10,7 @@ 'sbadmintemplate3' => true, 'ajaxlib' => true, 'dialoglib' => true, - 'tinymce4' => true, + 'tinymce5' => true, 'phrases' => array('global', 'ui'), 'customCSSs' => array('public/css/sbadmin2/admintemplate_contentonly.css', 'public/css/messaging/message.css'), 'customJSs' => array('public/js/bootstrapper.js', 'public/js/messaging/write.js') diff --git a/application/views/system/messages/ajaxWriteReply.php b/application/views/system/messages/ajaxWriteReply.php index 0a496c93e..08dc188fa 100644 --- a/application/views/system/messages/ajaxWriteReply.php +++ b/application/views/system/messages/ajaxWriteReply.php @@ -10,7 +10,7 @@ 'sbadmintemplate3' => true, 'ajaxlib' => true, 'dialoglib' => true, - 'tinymce4' => true, + 'tinymce5' => true, 'phrases' => array('global', 'ui'), 'customCSSs' => array('public/css/sbadmin2/admintemplate_contentonly.css', 'public/css/messaging/message.css'), 'customJSs' => array('public/js/bootstrapper.js', 'public/js/messaging/writeReply.js') diff --git a/application/views/system/messages/htmlWriteReply.php b/application/views/system/messages/htmlWriteReply.php index 9106d802b..d2150c1fb 100644 --- a/application/views/system/messages/htmlWriteReply.php +++ b/application/views/system/messages/htmlWriteReply.php @@ -6,7 +6,7 @@ 'jquery3' => true, 'bootstrap3' => true, 'fontawesome4' => true, - 'tinymce4' => true, + 'tinymce5' => true, 'sbadmintemplate3' => true, 'customCSSs' => array('public/css/sbadmin2/admintemplate_contentonly.css', 'public/css/messaging/message.css'), 'customJSs' => array('public/js/bootstrapper.js', 'public/js/messaging/messageWriteReply.js') diff --git a/application/views/system/messages/htmlWriteTemplate.php b/application/views/system/messages/htmlWriteTemplate.php index 761e05f96..42a31f374 100644 --- a/application/views/system/messages/htmlWriteTemplate.php +++ b/application/views/system/messages/htmlWriteTemplate.php @@ -8,7 +8,7 @@ 'bootstrap3' => true, 'ajaxlib' => true, 'fontawesome4' => true, - 'tinymce4' => true, + 'tinymce5' => true, 'sbadmintemplate3' => true, 'dialoglib' => true, 'widgets' => true, diff --git a/application/views/system/vorlage/templatetextEdit.php b/application/views/system/vorlage/templatetextEdit.php index 42efc1519..cc2487959 100644 --- a/application/views/system/vorlage/templatetextEdit.php +++ b/application/views/system/vorlage/templatetextEdit.php @@ -1,5 +1,5 @@ load->view('templates/header', array('title' => 'VorlageEdit', 'tinymce4' => true, 'jsonforms' => true)); + $this->load->view('templates/header', array('title' => 'VorlageEdit', 'tinymce5' => true, 'jsonforms' => true)); ?>
diff --git a/application/views/templates/FHC-Common.php b/application/views/templates/FHC-Common.php index 0928f516a..072ff1d7f 100644 --- a/application/views/templates/FHC-Common.php +++ b/application/views/templates/FHC-Common.php @@ -23,7 +23,7 @@ $tablesorter2 = isset($tablesorter2) ? $tablesorter2 : false; $tabulator4 = isset($tabulator4) ? $tabulator4 : false; $tabulator5 = isset($tabulator5) ? $tabulator5 : false; - $tinymce4 = isset($tinymce4) ? $tinymce4 : false; + $tinymce3 = isset($tinymce3) ? $tinymce3 : false; $tinymce5 = isset($tinymce5) ? $tinymce5 : false; $vue3 = isset($vue3) ? $vue3 : false; $primevue3 = isset($primevue3) ? $primevue3 : false; diff --git a/application/views/templates/FHC-Footer.php b/application/views/templates/FHC-Footer.php index f4d66a9b9..3daac26cd 100644 --- a/application/views/templates/FHC-Footer.php +++ b/application/views/templates/FHC-Footer.php @@ -100,14 +100,14 @@ // Tabulator 5 JS if ($tabulator5 === true) generateJSsInclude('vendor/olifolkerd/tabulator5/dist/js/tabulator.min.js'); - // Tinymce 4 JS - if ($tinymce4 === true) generateJSsInclude('vendor/tinymce/tinymce4/tinymce.min.js'); + // Tinymce 3 JS + if ($tinymce3 === true) generateJSsInclude('include/tiny_mce/tiny_mce.js'); // Tinymce 5 JS if ($tinymce5 === true) generateJSsInclude('vendor/tinymce/tinymce5/tinymce.min.js'); // Vue 3 JS - if ($vue3 === true) + if ($vue3 === true) { generateJSsInclude('vendor/vuejs/vuejs3/vue.global.prod.js'); generateJSsInclude('vendor/vuejs/vuerouter4/vue-router.global.js'); @@ -122,7 +122,11 @@ generateJSsInclude('vendor/npm-asset/primevue/column/column.min.js'); generateJSsInclude('vendor/npm-asset/primevue/calendar/calendar.min.js'); generateJSsInclude('vendor/npm-asset/primevue/skeleton/skeleton.min.js'); + generateJSsInclude('vendor/npm-asset/primevue/timeline/timeline.min.js'); + generateJSsInclude('vendor/npm-asset/primevue/multiselect/multiselect.min.js'); 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'); } // -------------------------------------------------------------------------------------------------------- diff --git a/application/views/templates/FHC-Header.php b/application/views/templates/FHC-Header.php index 20216328a..ed9fa97b9 100644 --- a/application/views/templates/FHC-Header.php +++ b/application/views/templates/FHC-Header.php @@ -79,9 +79,6 @@ // Tabulator 5 CSS if ($tabulator5 === true) generateCSSsInclude('public/css/Tabulator5.css'); - // Tinymce 4 CSS - if ($tinymce4 === true) generateCSSsInclude('public/css/TinyMCE4.css'); - // Tinymce 5 CSS if ($tinymce5 === true) generateCSSsInclude('public/css/TinyMCE5.css'); diff --git a/application/views/templates/header.php b/application/views/templates/header.php index 637eb3c7a..e75acca4f 100644 --- a/application/views/templates/header.php +++ b/application/views/templates/header.php @@ -95,7 +95,7 @@ if($jqueryV1 && $jqueryV2) show_error("Two JQuery versions used: composer and in - + diff --git a/application/views/widgets/tinymce.php b/application/views/widgets/tinymce.php index 3e2093e55..618cb4836 100644 --- a/application/views/widgets/tinymce.php +++ b/application/views/widgets/tinymce.php @@ -5,5 +5,6 @@ plugins: [], toolbar: "" }); - - < name="" style="">> + +< name="" style="">> + diff --git a/application/widgets/FilterWidget.php b/application/widgets/FilterWidget.php index 1cef91c15..45bcf7e04 100644 --- a/application/widgets/FilterWidget.php +++ b/application/widgets/FilterWidget.php @@ -1,5 +1,22 @@ . + */ + /** * To filter data using a SQL statement */ @@ -59,6 +76,8 @@ class FilterWidget extends Widget private $_sessionTimeout; // session expiring time + private $_encryptedColumns; // contains info about encrypted columns + private static $_FilterWidgetInstance; // static property that contains the instance of itself /** @@ -195,6 +214,7 @@ class FilterWidget extends Widget $this->_formatRow = null; $this->_markRow = null; $this->_checkboxes = null; + $this->_encryptedColumns = null; $this->_hideOptions = null; $this->_hideSelectFields = null; $this->_hideSelectFilters = null; @@ -252,6 +272,14 @@ class FilterWidget extends Widget $this->_additionalColumns = $args[FilterWidgetLib::ADDITIONAL_COLUMNS]; } + // Parameter is used to define the ecrypted columns + if (isset($args[FilterWidgetLib::ENCRYPTED_COLUMNS]) + && is_array($args[FilterWidgetLib::ENCRYPTED_COLUMNS]) + && count($args[FilterWidgetLib::ENCRYPTED_COLUMNS]) > 0) + { + $this->_encryptedColumns = $args[FilterWidgetLib::ENCRYPTED_COLUMNS]; + } + // Parameter is used to add use aliases for the columns fo the dataset if (isset($args[FilterWidgetLib::COLUMNS_ALIASES]) && is_array($args[FilterWidgetLib::COLUMNS_ALIASES]) @@ -441,7 +469,7 @@ class FilterWidget extends Widget ); // Then retrieve dataset from DB - $dataset = $this->filterwidgetlib->getDataset($datasetQuery); + $dataset = $this->filterwidgetlib->getDataset($datasetQuery, $this->_encryptedColumns); // Save changes into session if data are valid if (!isError($dataset)) @@ -476,7 +504,7 @@ class FilterWidget extends Widget $datasetQuery = $this->filterwidgetlib->generateDatasetQuery($this->_query, $parsedFilterJson->filters); // Then retrieve dataset from DB - $dataset = $this->filterwidgetlib->getDataset($datasetQuery); + $dataset = $this->filterwidgetlib->getDataset($datasetQuery, $this->_encryptedColumns); // Try to load the name of the filter using the PhrasesLib $filterName = $this->filterwidgetlib->getFilterName($parsedFilterJson); @@ -497,6 +525,7 @@ class FilterWidget extends Widget FilterWidgetLib::SESSION_SELECTED_FIELDS => $this->_getColumnsNames($parsedFilterJson->columns), // all the selected fields FilterWidgetLib::SESSION_COLUMNS_ALIASES => $this->_columnsAliases, // all the fields aliases FilterWidgetLib::SESSION_ADDITIONAL_COLUMNS => $this->_additionalColumns, // additional columns + FilterWidgetLib::SESSION_ENCRYPTED_COLUMNS => $this->_encryptedColumns, // encrypted columns FilterWidgetLib::SESSION_CHECKBOXES => $this->_checkboxes, // the name of the field used to build the checkboxes column FilterWidgetLib::SESSION_FILTERS => $parsedFilterJson->filters, // all the filters used to filter the dataset FilterWidgetLib::SESSION_METADATA => $this->FiltersModel->getExecutedQueryMetaData(), // the metadata of the dataset @@ -525,7 +554,7 @@ class FilterWidget extends Widget private function _setFilterMenu() { // Generates the filters structure array - $filterMenu = $this->filterwidgetlib->generateFilterMenu( + $this->filterwidgetlib->generateFilterMenu( $this->router->directory.$this->router->class.'/'.$this->router->method ); } @@ -604,7 +633,7 @@ class FilterWidget extends Widget { $columnsNames = array(); - foreach ($columns as $key => $obj) + foreach ($columns as $obj) { if (isset($obj->name)) { diff --git a/application/widgets/TableWidget.php b/application/widgets/TableWidget.php index 5a000601f..e59efce10 100644 --- a/application/widgets/TableWidget.php +++ b/application/widgets/TableWidget.php @@ -1,5 +1,22 @@ . + */ + /** * To display a table that shows data retriev by a SQL statement */ @@ -40,6 +57,8 @@ class TableWidget extends Widget private $_sessionTimeout; // session expiring time + private $_encryptedColumns; // contains info about encrypted columns + private static $_TableWidgetInstance; // static property that contains the instance of itself /** @@ -127,6 +146,7 @@ class TableWidget extends Widget $this->_datasetRepresentationOptions = null; $this->_datasetRepFieldsDefs = null; $this->_sessionTimeout = TableWidgetLib::SESSION_DEFAULT_TIMEOUT; + $this->_encryptedColumns = null; // Retrieved the required permissions parameter if present if (isset($args[TableWidgetLib::REQUIRED_PERMISSIONS])) @@ -206,6 +226,14 @@ class TableWidget extends Widget { $this->_sessionTimeout = $args[TableWidgetLib::SESSION_TIMEOUT]; } + + // Parameter is used to define the ecrypted columns + if (isset($args[TableWidgetLib::ENCRYPTED_COLUMNS]) + && is_array($args[TableWidgetLib::ENCRYPTED_COLUMNS]) + && count($args[TableWidgetLib::ENCRYPTED_COLUMNS]) > 0) + { + $this->_encryptedColumns = $args[TableWidgetLib::ENCRYPTED_COLUMNS]; + } } /** @@ -288,7 +316,7 @@ class TableWidget extends Widget $datasetQuery = $this->tablewidgetlib->generateDatasetQuery($this->_query); // Then retrieve dataset from DB - $dataset = $this->tablewidgetlib->getDataset($datasetQuery); + $dataset = $this->tablewidgetlib->getDataset($datasetQuery, $this->_encryptedColumns); // Save changes into session if data are valid if (!isError($dataset)) @@ -310,7 +338,7 @@ class TableWidget extends Widget $datasetQuery = $this->tablewidgetlib->generateDatasetQuery($this->_query); // Then retrieve dataset from DB - $dataset = $this->tablewidgetlib->getDataset($datasetQuery); + $dataset = $this->tablewidgetlib->getDataset($datasetQuery, $this->_encryptedColumns); // Save changes into session if data are valid if (!isError($dataset)) @@ -324,6 +352,7 @@ class TableWidget extends Widget TableWidgetLib::SESSION_FIELDS => $this->tablewidgetlib->getExecutedQueryListFields(), // all the fields of the dataset TableWidgetLib::SESSION_COLUMNS_ALIASES => $this->_columnsAliases, // all the fields aliases TableWidgetLib::SESSION_ADDITIONAL_COLUMNS => $this->_additionalColumns, // additional columns + TableWidgetLib::SESSION_ENCRYPTED_COLUMNS => $this->_encryptedColumns, // encrypted columns TableWidgetLib::SESSION_CHECKBOXES => $this->_checkboxes, // the name of the field used to build the checkboxes column TableWidgetLib::SESSION_METADATA => $this->tablewidgetlib->getExecutedQueryMetaData(), // the metadata of the dataset TableWidgetLib::SESSION_ROW_NUMBER => count($dataset->retval), // the number of loaded rows by this table @@ -411,24 +440,6 @@ class TableWidget extends Widget return !isset($class) ? '' : $class; } - /** - * Utility method that retrieves the name of the columns present in a table JSON definition - */ - private function _getColumnsNames($columns) - { - $columnsNames = array(); - - foreach ($columns as $key => $obj) - { - if (isset($obj->name)) - { - $columnsNames[] = $obj->name; - } - } - - return $columnsNames; - } - /** * Loads a view using the given viewName and eventually other parameters */ @@ -438,3 +449,4 @@ class TableWidget extends Widget $ci->load->view($viewName, $parameters); } } + diff --git a/cis/private/lehre/abgabe_student.php b/cis/private/lehre/abgabe_student.php index 9b3cec6f6..2512d9831 100644 --- a/cis/private/lehre/abgabe_student.php +++ b/cis/private/lehre/abgabe_student.php @@ -124,7 +124,6 @@ $sql_query = "SELECT (SELECT nachname FROM public.tbl_person WHERE person_id=tb AND tbl_projektarbeit.student_uid=".$db->db_add_param($uid)." ORDER BY studiensemester_kurzbz desc, tbl_lehrveranstaltung.kurzbz"; -//AND tbl_projektarbeit.student_uid='$getuid' 'ie07m102'; if(!$erg=$db->db_query($sql_query)) { $errormsg=$p->t('global/fehlerBeimLesenAusDatenbank'); diff --git a/cis/private/lehre/abgabe_student_details.php b/cis/private/lehre/abgabe_student_details.php index 9171a978c..860eb7579 100644 --- a/cis/private/lehre/abgabe_student_details.php +++ b/cis/private/lehre/abgabe_student_details.php @@ -395,15 +395,15 @@ if($command=="update" && $error!=true) } $htmlstr .= "\n"; $htmlstr .= ''.$p->t('abgabetool/deutscheSchlagwoerter').':* - '."\n"; + '."\n"; $htmlstr .= ''.$p->t('abgabetool/englischeSchlagwoerter').':* - '."\n"; + '."\n"; $htmlstr .= ''.$p->t('abgabetool/abstract').' '.$p->t('abgabetool/maxZeichen').':* - '."\n"; + '."\n"; $htmlstr .= ''.$p->t('abgabetool/abstractEng').''.$p->t('abgabetool/maxZeichen').':* - '."\n"; + '."\n"; $htmlstr .= ''.$p->t('abgabetool/seitenanzahl').':* - '."\n"; + '."\n"; $htmlstr .=" \n"; // If there are info about the signed document diff --git a/cis/private/profile/index.php b/cis/private/profile/index.php index ed3295287..26312d5be 100644 --- a/cis/private/profile/index.php +++ b/cis/private/profile/index.php @@ -276,15 +276,22 @@ if (!$ansicht) { if ($type === 'mitarbeiter') { - $verwendung = new bisverwendung(); - if($verwendung->getLastVerwendung($uid)) + if(defined('DIENSTVERHAELTNIS_SUPPORT') && DIENSTVERHAELTNIS_SUPPORT) { - if (!$verwendung->hauptberuflich) - { - echo 'Hauptberuf: '. $verwendung->hauptberuf; - } + // TODO Hauptberuf wieder anzeigen sobald verfuegbar } - echo "

"; + else + { + $verwendung = new bisverwendung(); + if($verwendung->getLastVerwendung($uid)) + { + if (!$verwendung->hauptberuflich) + { + echo 'Hauptberuf: '. $verwendung->hauptberuf; + } + } + echo "

"; + } } } @@ -606,9 +613,36 @@ function printFunctionsTable($query, $headingphrase, $tableid, $showVertragsstun if ($showVertragsstunden === true && $adminOrOwnUser) { $vertragsstunden = 0.00; - $qry = "SELECT sum(vertragsstunden) AS vertragsstdsumme from bis.tbl_bisverwendung - WHERE mitarbeiter_uid = ".$db->db_add_param($uid)." - AND (ende > now() OR ende IS NULL)"; + if(defined('DIENSTVERHAELTNIS_SUPPORT') && DIENSTVERHAELTNIS_SUPPORT) + { + $qry = "SELECT + sum(wochenstunden) AS vertragsstdsumme + FROM + hr.tbl_vertragsbestandteil_stunden vbs + JOIN + hr.tbl_vertragsbestandteil vb USING(vertragsbestandteil_id) + JOIN + hr.tbl_dienstverhaeltnis dv USING(dienstverhaeltnis_id) + WHERE + dv.mitarbeiter_uid = ".$db->db_add_param($uid)." + AND NOW() BETWEEN COALESCE(vb.von, '1970-01-01'::date) AND COALESCE(vb.bis, '2170-12-31'::date) + AND NOT EXISTS ( + SELECT + 1 + FROM + hr.tbl_vertragsbestandteil + WHERE + dienstverhaeltnis_id = dv.dienstverhaeltnis_id + AND vertragsbestandteiltyp_kurzbz = 'karenz' + AND NOW() BETWEEN COALESCE(von, '1970-01-01'::date) AND COALESCE(bis, '2170-12-31'::date) + )"; + } + else + { + $qry = "SELECT sum(vertragsstunden) AS vertragsstdsumme from bis.tbl_bisverwendung + WHERE mitarbeiter_uid = ".$db->db_add_param($uid)." + AND (ende > now() OR ende IS NULL)"; + } if ($result_vertragsstd = $db->db_query($qry)) { diff --git a/cis/private/tools/suche.php b/cis/private/tools/suche.php index 52dbc2385..54c912ae5 100644 --- a/cis/private/tools/suche.php +++ b/cis/private/tools/suche.php @@ -172,9 +172,6 @@ function searchPerson($searchItems) '; foreach($bn->result as $row) { - $bisverwendung = new bisverwendung(); - $bisverwendung->getLastAktVerwendung($row->uid); - echo ''; //echo '',$row->titelpre,''; echo '',$row->anrede,''; @@ -199,7 +196,7 @@ function searchPerson($searchItems) echo '',$row->nachname,''; if($row->aktiv==false) echo ' (ausgeschieden)'; - elseif($bisverwendung->beschausmasscode=='5') + elseif(isKarenziert($row->uid)) echo ' (karenziert)'; echo ''; //echo '',$row->titelpost,''; @@ -262,6 +259,47 @@ function searchPerson($searchItems) else return false; } + +function isKarenziert($uid) +{ + global $db; + + if(defined('DIENSTVERHAELTNIS_SUPPORT') && DIENSTVERHAELTNIS_SUPPORT) + { + $qry =" + SELECT + 1 + FROM + hr.tbl_dienstverhaeltnis + JOIN hr.tbl_vertragsbestandteil USING(dienstverhaeltnis_id) + JOIN hr.tbl_vertragsbestandteil_karenz USING(vertragsbestandteil_id) + WHERE + tbl_dienstverhaeltnis.mitarbeiter_uid=".$db->db_add_param($uid)." + AND tbl_vertragsbestandteil.von<=now() AND tbl_vertragsbestandteil.bis>=now() + "; + + if($result = $db->db_query($qry)) + { + if($db->db_num_rows($result)>0) + return true; + else + return false; + } + else + return false; + } + else + { + $bisverwendung = new bisverwendung(); + $bisverwendung->getLastAktVerwendung($uid); + + if($bisverwendung->beschausmasscode=='5') + return true; + else + return false; + } +} + function searchOE($searchItems) { global $db, $p, $noalias; @@ -332,8 +370,6 @@ function searchOE($searchItems) $mitarbeiter->load($bf->uid); $kontakt = new kontakt(); $kontakt->loadFirmaKontakttyp($mitarbeiter->standort_id,'telefon'); - $bisverwendung = new bisverwendung(); - $bisverwendung->getLastAktVerwendung($bf->uid); $benutzer = new benutzer($bf->uid); if ($benutzer->bnaktiv) { @@ -341,8 +377,8 @@ function searchOE($searchItems) echo ''.$person->vorname.''; echo '',$person->nachname,''; echo ''.$bf->bezeichnung; - if($bisverwendung->beschausmasscode=='5') - echo ' (karenziert)'; + if( isKarenziert($bf->uid)) + echo ' (karenziert)'; echo ''; // Display phone number diff --git a/cis/private/tools/zeitaufzeichnung.php b/cis/private/tools/zeitaufzeichnung.php index 0eb86bdb1..f87ca2be3 100644 --- a/cis/private/tools/zeitaufzeichnung.php +++ b/cis/private/tools/zeitaufzeichnung.php @@ -41,11 +41,10 @@ require_once('../../../include/service.class.php'); require_once('../../../include/mitarbeiter.class.php'); require_once('../../../include/betriebsmittelperson.class.php'); require_once('../../../include/globals.inc.php'); -require_once('../../../include/bisverwendung.class.php'); -require_once('../../../include/studiensemester.class.php'); require_once('../../../include/benutzerberechtigung.class.php'); require_once('../../../include/zeitaufzeichnung_import_csv.class.php'); require_once('../../../include/zeitaufzeichnung_import_post.class.php'); +require_once('../../../include/vertragsbestandteil.class.php'); $sprache = getSprache(); $p=new phrasen($sprache); @@ -229,6 +228,21 @@ $( document ).ready(function() '; +echo << + $(document).ready(function() { + const scrollDiv = document.createElement('div'); + scrollDiv.style.cssText = 'width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;'; + document.body.appendChild(scrollDiv); + const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; + document.body.removeChild(scrollDiv); + var marginright = Math.max((20 - scrollbarWidth), 0); + document.body.style.setProperty('width', 'calc(100% - ' + marginright + 'px)'); + }); + + +EOSBJS; + echo '