diff --git a/application/controllers/components/Antrag/Unterbrechung.php b/application/controllers/components/Antrag/Unterbrechung.php index 33bd0035d..efc2c3a88 100644 --- a/application/controllers/components/Antrag/Unterbrechung.php +++ b/application/controllers/components/Antrag/Unterbrechung.php @@ -86,7 +86,7 @@ class Unterbrechung extends FHC_Controller $data = getData($result); - $data->studiensemester = $this->antraglib->getSemesterForUnterbrechung($data->studiensemester_kurzbz); + $data->studiensemester = $this->antraglib->getSemesterForUnterbrechung($prestudent_id, $data->studiensemester_kurzbz); $this->outputJsonSuccess($data); } @@ -136,7 +136,7 @@ class Unterbrechung extends FHC_Controller $datum_wiedereinstieg = $this->input->post('datum_wiedereinstieg'); $dms_id = null; - $result = $this->antraglib->getPrestudentUnterbrechungsBerechtigt($prestudent_id); + $result = $this->antraglib->getPrestudentUnterbrechungsBerechtigt($prestudent_id, $studiensemester, $datum_wiedereinstieg); if (isError($result)) { return $this->outputJsonError(['db' => getError($result)]); } diff --git a/application/libraries/AntragLib.php b/application/libraries/AntragLib.php index f094440e2..d8ef224db 100644 --- a/application/libraries/AntragLib.php +++ b/application/libraries/AntragLib.php @@ -1302,7 +1302,7 @@ class AntragLib * retval -2 means other Antrag pending; * retval -3 means in blacklist stg */ - public function getPrestudentUnterbrechungsBerechtigt($prestudent_id, $studiensemester_kurzbz = null) + public function getPrestudentUnterbrechungsBerechtigt($prestudent_id, $studiensemester_kurzbz = null, $datum_wiedereinstieg = null) { $result = $this->_ci->PrestudentModel->load($prestudent_id); if (isError($result)) @@ -1320,18 +1320,10 @@ class AntragLib if (!hasData($result)) return success(0); $result = current(getData($result)); + $prestudent_stdsem = $result->studiensemester_kurzbz; $datumStatus = $result->datum; - if (!in_array($result->status_kurzbz, $this->_ci->config->item('antrag_prestudentstatus_whitelist'))) { - $result = $this->_ci->StudierendenantragModel->loadWithStatusWhere([ - 'prestudent_id' => $prestudent_id, - 'typ' => Studierendenantrag_model::TYP_UNTERBRECHUNG, - 'campus.get_status_studierendenantrag(studierendenantrag_id)' => Studierendenantragstatus_model::STATUS_APPROVED - ]); - if (isError($result)) - return $result; - if (hasData($result)) - return success(-1); - + if (!in_array($result->status_kurzbz, $this->_ci->config->item('antrag_prestudentstatus_whitelist')) + && $result->status_kurzbz != 'Unterbrecher') { return success(0); } $result = $this->_ci->StudierendenantragModel->loadWithStatusWhere(['prestudent_id' => $prestudent_id]); @@ -1339,7 +1331,8 @@ class AntragLib return $result; if (!hasData($result)) return success(1); - $result= getData($result); + + $result = getData($result); foreach ($result as $antrag) { if ($antrag->typ == Studierendenantrag_model::TYP_ABMELDUNG || $antrag->typ == Studierendenantrag_model::TYP_ABMELDUNG_STGL) @@ -1349,11 +1342,11 @@ class AntragLib elseif($antrag->status == Studierendenantragstatus_model::STATUS_APPROVED && $antrag->datum > $datumStatus) return success(-2); } - if ($studiensemester_kurzbz && $antrag->typ == Studierendenantrag_model::TYP_UNTERBRECHUNG) + if ($antrag->typ == Studierendenantrag_model::TYP_UNTERBRECHUNG) { - // NOTE(chris): check if this is an old or canceled one - if ($antrag->studiensemester_kurzbz == $studiensemester_kurzbz && $antrag->status != Studierendenantragstatus_model::STATUS_CANCELLED) - return success(-1); + // NOTE(chris): Ignore canceled ones + if ($antrag->status == Studierendenantragstatus_model::STATUS_CANCELLED) + continue; } if ($antrag->typ == Studierendenantrag_model::TYP_WIEDERHOLUNG) { @@ -1362,6 +1355,17 @@ class AntragLib } } + if (!$studiensemester_kurzbz) { + $sems = $this->getSemesterForUnterbrechung($prestudent_id, $prestudent_stdsem); + if (!count(array_filter($sems, function ($item) { + return !$item['disabled']; + }))) + return success(-1); + } else { + if ($this->_ci->StudierendenantragModel->hasRunningUnterbrechungBetween($prestudent_id, $studiensemester_kurzbz, $datum_wiedereinstieg)) + return success(-1); + } + return success(1); } @@ -1552,53 +1556,43 @@ class AntragLib return success($resultDetails); } - public function getSemesterForUnterbrechung($studiensemester_kurzbz) + /** + * Rearrange the free semester slots for a new Unterbrechung + * + * @param integer $prestudent_id + * @param string $studiensemester_kurzbz + * + * @return array + */ + public function getSemesterForUnterbrechung($prestudent_id, $studiensemester_kurzbz) { - $this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); - - $semester = []; - - $result = $this->_ci->StudiensemesterModel->getNextFrom($studiensemester_kurzbz); - if (!hasData($result)) - return $semester; - $nextSem = current(getData($result)); - - $semester[0] = [ - 'studiensemester_kurzbz' => $studiensemester_kurzbz, - 'wiedereinstieg' => [$nextSem] - ]; - - $result = $this->_ci->StudiensemesterModel->getNextFrom($nextSem->studiensemester_kurzbz); - if (!hasData($result)) - return $semester; - - $currSemester = current(getData($result)); - $followingSemester = [$currSemester]; - - $max = $this->_ci->config->item('unterbrecher_semester_max_length'); - if(!$max || $max < 1) - $max = 2; - - for ($i = 1; $i < $max; $i++) { - $result = $this->_ci->StudiensemesterModel->getNextFrom($currSemester->studiensemester_kurzbz); - if (!hasData($result)) - break; - $currSemester = current(getData($result)); - $followingSemester[] = $currSemester; - } - - $semester[1] = [ - 'studiensemester_kurzbz' => $nextSem->studiensemester_kurzbz, - 'wiedereinstieg' => $followingSemester - ]; - - //remove last Semester of the array - array_pop($followingSemester); - - foreach ($followingSemester as $sem) - $semester[0]['wiedereinstieg'][] = $sem; - - return $semester; + $result = $this->_ci->StudierendenantragModel->getFreeSlotsForUnterbrechung($prestudent_id, $studiensemester_kurzbz); + if (isError($result)) + return []; + $result = getData($result); + if (!$result) + return []; + return array_reduce($result, function ($carry, $item) { + if (!isset($carry[$item->von])) + $carry[$item->von] = [ + 'studiensemester_kurzbz' => $item->von, + 'wiedereinstieg' => [], + 'disabled' => true + ]; + + $carry[$item->von]['wiedereinstieg'][] = [ + 'studiensemester_kurzbz' => $item->bis, + 'start' => $item->ende, + 'disabled' => (boolean)$item->studierendenantrag_id + ]; + + if ($carry[$item->von]['disabled'] && !$item->studierendenantrag_id) { + $carry[$item->von]['disabled'] = false; + } + + return $carry; + }, []); + return $result; } public function getAktivePrestudentenInStgs($studiengaenge, $query) diff --git a/application/models/education/Studierendenantrag_model.php b/application/models/education/Studierendenantrag_model.php index ea481ebef..9edc7ef91 100644 --- a/application/models/education/Studierendenantrag_model.php +++ b/application/models/education/Studierendenantrag_model.php @@ -287,4 +287,98 @@ class Studierendenantrag_model extends DB_Model return $this->loadWhere($where); } + + /** + * Checks if the Prestudent has an active Unterbrechung between + * the start of the given semester and the given enddate. + * If the enddate is omitted the end of the given semester is used. + * + * @param integer $prestudent_id + * @param string $studiensemester_kurzbz + * @param string $enddate (optional) + * + * @return boolean + */ + public function hasRunningUnterbrechungBetween($prestudent_id, $studiensemester, $enddate = null) + { + $start = '(SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=' . $this->db->escape($studiensemester) . ')'; + $end = $enddate + ? $this->db->escape($enddate) + : '(SELECT ende FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=' . $this->db->escape($studiensemester) . ')'; + + $this->addJoin('public.tbl_studiensemester', 'studiensemester_kurzbz'); + $this->db->where([ + 'prestudent_id' => $prestudent_id, + 'typ' => Studierendenantrag_model::TYP_UNTERBRECHUNG, + 'campus.get_status_studierendenantrag(studierendenantrag_id) !=' => Studierendenantragstatus_model::STATUS_CANCELLED, + 'start < ' . $end => null, + 'datum_wiedereinstieg > ' . $start => null, + ]); + return (boolean)$this->db->count_all_results($this->dbTable); + } + + /** + * Gets free semester slots for a new Unterbrechung. + * + * @param integer $prestudent_id + * @param string $studiensemester_kurzbz (optional) + * + * @return stdClass + */ + public function getFreeSlotsForUnterbrechung($prestudent_id, $studiensemester = null) + { + $max_starters = 2; + $max_length = max( + 2, + (integer)$this->config->item('unterbrecher_semester_max_length') + ); + + + $subquery = ''; + if ($studiensemester) + $subquery = 'SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=?'; + else + $subquery = 'SELECT start FROM public.tbl_studiensemester WHERE studiensemester_kurzbz=public.get_stdsem_prestudent (?, null)'; + + $sql = "WITH numbered_sems AS ( + SELECT + a.studiensemester_kurzbz AS von, + b.studiensemester_kurzbz AS bis, + a.start AS start, + b.start AS ende, + ROW_NUMBER() OVER ( + PARTITION BY a.studiensemester_kurzbz + ORDER BY b.start + ) AS row_number + FROM public.tbl_studiensemester a + LEFT JOIN public.tbl_studiensemester b ON (b.start > a.ende) + ), + last_sems AS ( + SELECT * + FROM numbered_sems + WHERE numbered_sems.row_number <= ? + ) + SELECT s.von, s.bis, s.start, s.ende, studierendenantrag_id + FROM last_sems s + LEFT JOIN ( + SELECT studierendenantrag_id, start, datum_wiedereinstieg AS ende + FROM campus.tbl_studierendenantrag + LEFT JOIN public.tbl_studiensemester USING(studiensemester_kurzbz) + WHERE typ=? + AND campus.get_status_studierendenantrag(studierendenantrag_id) != ? + AND prestudent_id=? + ) a ON (s.start < a.ende AND s.ende > a.start) + WHERE s.start >= (" . $subquery . ") + ORDER BY s.start, s.ende + LIMIT ?;"; + + return $this->execQuery($sql, [ + $max_length, + self::TYP_UNTERBRECHUNG, + Studierendenantragstatus_model::STATUS_CANCELLED, + $prestudent_id, + $studiensemester ?: $prestudent_id, + $max_length * $max_starters + ]); + } } diff --git a/public/js/components/Studierendenantrag/Form/Unterbrechung.js b/public/js/components/Studierendenantrag/Form/Unterbrechung.js index a0e84af63..b0544dd3f 100644 --- a/public/js/components/Studierendenantrag/Form/Unterbrechung.js +++ b/public/js/components/Studierendenantrag/Form/Unterbrechung.js @@ -256,7 +256,7 @@ export default { :id="'studierendenantrag-form-abmeldung-' + uuid + '-stsem'" @input="currentWiedereinstieg = ''" > - @@ -280,7 +280,7 @@ export default {