Merge branch 'bug-69548/FHC4_Studierendenverwaltung_Aufnahmetermine_Gesamtnote_berechnen' into studvw_2026-02_rc4

This commit is contained in:
Harald Bamberger
2026-02-03 10:48:06 +01:00
8 changed files with 202 additions and 49 deletions
@@ -28,7 +28,7 @@ class Studentenverwaltung extends Auth_Controller
'basis/prestudentstatus' => $this->permissionlib->isBerechtigt('basis/prestudentstatus'),
'assistenz_stgs' => $this->permissionlib->getSTG_isEntitledFor('assistenz'),
'admin' => $this->permissionlib->isBerechtigt('admin'),
'assistenz_schreibrechte' => $this->permissionlib->isBerechtigt('assistenz','suid'),
'assistenz_schreibrechte' => $this->permissionlib->isBerechtigt('assistenz', 'suid'),
'student/keine_studstatuspruefung' => $this->permissionlib->isBerechtigt('student/keine_studstatuspruefung'),
'lehre/reihungstestAufsicht' => $this->permissionlib->isBerechtigt('lehre/reihungstestAufsicht'),
'system/change_outputformat' => $this->permissionlib->getOE_isEntitledFor('system/change_outputformat'),
@@ -43,3 +43,5 @@ class Studentenverwaltung extends Auth_Controller
]);
}
}
@@ -36,15 +36,44 @@ class Aufnahmetermine extends FHCAPI_Controller
// Load models
$this->load->model('crm/Reihungstest_model', 'ReihungstestModel');
$this->load->model('crm/RtPerson_model', 'RtPersonModel');
$this->load->model('organisation/Studienplan_model', 'StudienplanModel');
$this->load->model('organisation/Studienordnung_model', 'StudienordnungModel');
$this->load->model('organisation/Studiengang_model', 'StudiengangModel');
}
public function getAufnahmetermine($person_id)
{
$result = $this->ReihungstestModel->getReihungstestPerson($person_id);
$arrayRt = $this->getDataOrTerminateWithError($result);
$data = $this->getDataOrTerminateWithError($result);
foreach ($arrayRt as $item) {
//Studienplan
$result = $this->StudienplanModel->loadWhere([
'studienplan_id' => $item->studienplan_id
]);
$data = $this->getDataOrTerminateWithError($result);
$studienordnung_id_ber = current($data)->studienordnung_id;
$this->terminateWithSuccess($data);
//Studienordnung
$result = $this->StudienordnungModel->loadWhere([
'studienordnung_id' => $studienordnung_id_ber
]);
$data = $this->getDataOrTerminateWithError($result);
$studiengang_kz_ber = current($data)->studiengang_kz;
//Studiengang von studiengang_kz_ber
$result = $this->StudiengangModel->load($studiengang_kz_ber);
$data = $this->getDataOrTerminateWithError($result);
$studiengangkurzbzlang_ber = current($data)->kurzbzlang;
$typ_ber = current($data)->typ;
//add to Array
$item->studiengang_kz_ber = $studiengang_kz_ber;
$item->studiengangkurzbzlang_ber = $studiengangkurzbzlang_ber;
$item->studiengangtyp_ber = $typ_ber;
}
$this->terminateWithSuccess($arrayRt);
}
public function insertAufnahmetermin()
@@ -60,7 +89,6 @@ class Aufnahmetermine extends FHCAPI_Controller
return $this->terminateWithError($this->p->t('ui', 'error_missingId', ['id'=> 'Person ID']), self::ERROR_TYPE_GENERAL);
}
$rt_id = (isset($formData['rt_id']) && !empty($formData['rt_id'])) ? $formData['rt_id'] : null;
$anmeldedatum = (isset($formData['anmeldedatum']) && !empty($formData['anmeldedatum'])) ? $formData['anmeldedatum'] : null;
$teilgenommen = (isset($formData['teilgenommen']) && !empty($formData['teilgenommen'])) ? $formData['teilgenommen'] : false;
@@ -224,7 +252,11 @@ class Aufnahmetermine extends FHCAPI_Controller
)
);
$data = $this->getDataOrTerminateWithError($result);
//check if existing placementtest
if(!hasData($result))
$this->terminateWithSuccess([]);
else
$data = getData($result);
$studienplan_arr = [];
$include_ids = [];
@@ -233,12 +265,18 @@ class Aufnahmetermine extends FHCAPI_Controller
if($item->studienplan_id != null)
$studienplan_arr[] = $item->studienplan_id;
}
if(!hasData($studienplan_arr))
$this->terminateWithSuccess([]);
//get Placementtests Person
$person_id = $this->_getPersonId($prestudent_id);
$resultRt = $this->ReihungstestModel->getReihungstestPerson($person_id);
$dataRt = $this->getDataOrTerminateWithError($resultRt);
//check if existing placementtest
if(!hasData($result))
$this->terminateWithSuccess([]);
else
$dataRt = getData($resultRt);
foreach ($dataRt as $item)
{
@@ -354,6 +392,7 @@ class Aufnahmetermine extends FHCAPI_Controller
$person_id = $this->input->get('person_id');
$punkte = $this->input->get('punkte');
$reihungstest_id = $this->input->get('reihungstest_id');
$has_excluded_gebiete = $this->input->get('hasExcludedAreas');
if(!$reihungstest_id)
{
@@ -364,22 +403,27 @@ class Aufnahmetermine extends FHCAPI_Controller
$studiengang_kz = $this->input->get('studiengang_kz');
$this->load->model('testtool/Ablauf_model', 'AblaufModel');
$result = $this->AblaufModel->getAblaufGebieteAndGewichte($studiengang_kz);
$result = $this->AblaufModel->getAblaufGebieteAndGewichte($studiengang_kz, 1);
$data = $this->getDataOrTerminateWithError($result);
$weightedArray = [];
$basis_gebiet_id_arr = [];
$basis_gebiet_id_toString = '';
foreach ($data as $abl)
{
$weightedArray[$abl->gebiet_id] = $abl->gewicht;
$basis_gebiet_id_arr[]= $abl->gebiet_id;
}
$basis_gebiet_id_toString = implode(', ', $basis_gebiet_id_arr);
$result = $this->ReihungstestModel->getReihungstestErgebnisPerson($person_id, $punkte, $reihungstest_id, $weightedArray);
/* if (isError($result))
{
$this->terminateWithError($result, self::ERROR_TYPE_GENERAL);
}*/
$result = $this->ReihungstestModel->getReihungstestErgebnisPerson(
$person_id,
$punkte,
$reihungstest_id,
$weightedArray,
$has_excluded_gebiete,
$basis_gebiet_id_toString
);
$this->terminateWithSuccess($result);
}
+53 -15
View File
@@ -10,7 +10,7 @@ class Reihungstest_model extends DB_Model
parent::__construct();
$this->dbTable = 'public.tbl_reihungstest';
$this->pk = 'reihungstest_id';
}
}
/**
* Gets a test from a test id only if it is available
@@ -42,8 +42,8 @@ class Reihungstest_model extends DB_Model
/**
* Checks if there are active studyplans which have no public placement tests assigned yet.
* Only check assignment to studyplans that are
* - Bachelor,
* - active,
* - Bachelor,
* - active,
* - set as online application
* - valid for 1st terms
* @return array Returns object array with studyplans that have no public placement tests assigned yet.
@@ -97,7 +97,7 @@ class Reihungstest_model extends DB_Model
USING (reihungstest_id)
WHERE
datum >= now()
AND
AND
oeffentlich = \'t\'
)
';
@@ -105,7 +105,7 @@ class Reihungstest_model extends DB_Model
return $this->execQuery($query);
}
/**
/**
* Gets amount of free places.
* @return array Returns object array with faculty and amount of free places
* for each public actual placement test date.
@@ -432,10 +432,10 @@ class Reihungstest_model extends DB_Model
}
/**
* Loads all applicants of a placement test
* @param integer $reihungstest_id ID of placement test
* @return array Returns object array with data of applicants.
*/
* Loads all applicants of a placement test
* @param integer $reihungstest_id ID of placement test
* @return array Returns object array with data of applicants.
*/
public function getApplicantsOfPlacementTest($reihungstest_id)
{
$query = '
@@ -556,13 +556,22 @@ class Reihungstest_model extends DB_Model
* Calculates Result of Placement Test for a given Person and given placementtest
* and with taking account of weighting per area
*
* @param $person_id ID of Person
* @param $punkte if true result is points else result is percentage of sum
* @param $reihungstest_id ID of Placementtest
* @param $weightedArray array of weighting per area (gewicht per gebiet_id)
* @return float result
* @param Number $person_id ID of Person
* @param Boolean $punkte if true result is points else result is percentage of sum
* @param Number $reihungstest_id ID of Placementtest
* @param Array $weightedArray array of weighting per area (gewicht per gebiet_id)
* @param Boolean $has_excluded_gebiete if true, areas in the configArray will be excluded
* @param Array $basis_gebiet_id_toString areas to exclude
* @return float result points of RT
*/
public function getReihungstestErgebnisPerson($person_id, $punkte, $reihungstest_id, $weightedArray = null)
public function getReihungstestErgebnisPerson(
$person_id,
$punkte,
$reihungstest_id,
$weightedArray = null,
$has_excluded_gebiete = false,
$basis_gebiet_id_toString = null
)
{
$parametersArray = array($reihungstest_id);
@@ -577,6 +586,35 @@ class Reihungstest_model extends DB_Model
WHERE
reihungstest_id = ? ";
//areas of Studiengang
if (!empty($basis_gebiet_id_toString))
{
$qry .= "
AND
gebiet_id IN (". $basis_gebiet_id_toString. ")
";
}
//areas to exclude
if($has_excluded_gebiete)
{
if (defined('FAS_REIHUNGSTEST_EXCLUDE_GEBIETE') && !empty(FAS_REIHUNGSTEST_EXCLUDE_GEBIETE))
{
$excluded_gebiete = unserialize(FAS_REIHUNGSTEST_EXCLUDE_GEBIETE);
$exclude_gebiet_id_arr = $excluded_gebiete;
if (is_array($exclude_gebiet_id_arr) && count($exclude_gebiet_id_arr) > 0)
{
$exclude_gebiet_id_toString = implode(', ', $exclude_gebiet_id_arr);
$qry .= "
AND
gebiet_id NOT IN (". $exclude_gebiet_id_toString. ")
-- AND
-- typ = 'b'
";
}
}
}
//using prestudent Status to avoid to get the sum of more than 1 placement tests
$qry .= "
AND prestudent_id = (
@@ -47,6 +47,7 @@ $configArray = [
'showAufnahmegruppen' => !defined('FAS_REIHUNGSTEST_AUFNAHMEGRUPPEN') ? false : FAS_REIHUNGSTEST_AUFNAHMEGRUPPEN,
'allowUebernahmePunkte' => !defined('FAS_REIHUNGSTEST_PUNKTEUEBERNAHME') ? true : FAS_REIHUNGSTEST_PUNKTEUEBERNAHME,
'useReihungstestPunkte' => !defined('FAS_REIHUNGSTEST_PUNKTE') ? true : FAS_REIHUNGSTEST_PUNKTE,
'hasExcludedAreas' => defined('FAS_REIHUNGSTEST_EXCLUDE_GEBIETE') && !empty(FAS_REIHUNGSTEST_EXCLUDE_GEBIETE),
];
?>
+6
View File
@@ -74,6 +74,12 @@ html.fs_huge {
color: var(--gray-500);
}
/* Aufnahme Termine: background color green*/
.stv-details-admission-table .row-green{
background-color: lightgreen !important;
//color: var(--green-200);
}
/* Dropdown Toolbar Interessent, submenu */
.dropend .dropdown-toggle.d-flex::after {
height: 0;
@@ -84,6 +84,7 @@ export default {
configShowAufnahmegruppen: this.config.showAufnahmegruppen,
configAllowUebernahmePunkte: this.config.allowUebernahmePunkte,
configUseReihungstestPunkte: this.config.useReihungstestPunkte,
configHasExcludedAreas: this.config.hasExcludedAreas,
appConfig: Vue.computed(() => this.appconfig),
hasZGVBakkPermission: this.permissions['student/editBakkZgv'],
hasZGVMasterPermission: this.permissions['student/editMakkZgv'],
@@ -23,6 +23,10 @@ export default {
from: 'configUseReihungstestPunkte',
default: true
},
hasExcludedAreas: {
from: 'configHasExcludedAreas',
default: false
},
$reloadList: {
from: '$reloadList',
required: true
@@ -35,13 +39,46 @@ export default {
student: Object
},
data() {
let self = this;
return {
tabulatorOptions: {
ajaxURL: 'dummy',
ajaxRequestFunc: () => this.$api.call(
ApiStvAdmissionDates.getAufnahmetermine(this.student.person_id)
),
ajaxResponse: (url, params, response) => response.data,
ajaxResponse: (url, params, response) => {
const data = response.data;
const filtered = data.filter(item =>
item.studiengang_kz_ber === this.student.studiengang_kz
);
if (filtered.length > 0) {
filtered.sort((a, b) =>
this.parseSemester(b.studiensemester) - this.parseSemester(a.studiensemester)
);
self.youngestSemester = filtered[0].studiensemester;
} else {
self.youngestSemester = null;
}
return data;
},
rowFormatter: function(row) {
let data = row.getData();
if (data.studiengang_kz_ber === self.student.studiengang_kz &&
data.studiensemester === self.youngestSemester) {
let cells = row.getCells();
cells.forEach((c) => {
c.getElement().classList.add("row-green");
}
);
}
},
dataLoaded: function() {
this.redraw(true);
},
columns: [
{title: "rt_id", field: "rt_id", visible: false},
{title: "rt_person_id", field: "rt_person_id", visible: false},
@@ -88,8 +125,9 @@ export default {
{title: "ort", field: "ort", visible: false},
{title: "studienplan", field: "studienplan", visible: false},
{title: "studienplan_id", field: "studienplan_id", visible: false},
{title: "stg", field: "studiengangkurzbzlang"},
{title: "Stg", field: "stg_kuerzel"},
//{title: "stg", field: "studiengangkurzbzlang"},
{title: "stg_ber", field: "studiengangkurzbzlang_ber"},
{title: "Stg_Kz", field: "studiengang_kz_ber", visible: false},
{
title: 'Aktionen', field: 'actions',
minWidth: 150, // Ensures Action-buttons will be always fully displayed
@@ -102,7 +140,7 @@ export default {
button.innerHTML = '<i class="fa fa-edit"></i>';
button.title = this.$p.t('ui', 'bearbeiten');
button.addEventListener('click', (event) =>
this.actionEditPlacementTest(cell.getData().rt_person_id)
this.actionEditPlacementTest(cell.getData().rt_person_id, cell.getData().studiengang_kz_ber)
);
container.append(button);
@@ -173,12 +211,9 @@ export default {
cm.getColumnByField('studienplan_id').component.updateDefinition({
title: this.$p.t('ui', 'studienplan_id')
});
cm.getColumnByField('studiengangkurzbzlang').component.updateDefinition({
cm.getColumnByField('studiengangkurzbzlang_ber').component.updateDefinition({
title: this.$p.t('projektarbeitsbeurteilung', 'studiengang')
});
cm.getColumnByField('stg_kuerzel').component.updateDefinition({
title: this.$p.t('admission', 'stg_kurz')
});
}
}
],
@@ -187,7 +222,9 @@ export default {
listPlacementTests: [],
listStudyPlans: [],
filterOnlyFutureTestsSet: false,
filteredPlacementTests: []
filteredPlacementTests: [],
youngestSemester: null,
stgRtPers: null
}
},
methods: {
@@ -197,11 +234,12 @@ export default {
this.formData.anmeldedatum = new Date();
this.$refs.placementTestModal.show();
},
actionEditPlacementTest(rt_person_id) {
actionEditPlacementTest(rt_person_id, stg_kz) {
this.resetForm();
this.statusNew = false;
this.loadPlacementTest(rt_person_id);
this.$refs.placementTestModal.show();
this.stgRtPers = stg_kz;
},
actionDeletePlacementTest(rt_person_id) {
this.$fhcAlert
@@ -271,12 +309,13 @@ export default {
this.reload();
});
},
getResultReihungstest(reihungstest_id){
getResultReihungstest(reihungstest_id, stg_kz){
const paramsRt = {
reihungstest_id: reihungstest_id,
person_id: this.student.person_id,
punkte: this.useReihungstestPunkte,
studiengang_kz: this.student.studiengang_kz
studiengang_kz: stg_kz,
hasExcludedAreas: this.hasExcludedAreas
};
return this.$api
@@ -330,13 +369,22 @@ export default {
},
resetForm() {
this.formData = {};
this.stgRtPers = null;
},
parseSemester(semester) {
const type = semester.slice(0, 2).toUpperCase(); // "WS" or "SS"
const year = parseInt(semester.slice(2), 10);
// WS > SS
return year * 10 + (type === 'SS' ? 1 : 2);
}
},
created() {
this.$api
.call(ApiStvAdmissionDates.getListPlacementTests(this.student.prestudent_id))
.then(result => {
this.listPlacementTests = this.filteredPlacementTests = result.data;
if(result.data)
this.listPlacementTests = this.filteredPlacementTests = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
@@ -350,7 +398,7 @@ export default {
template: `
<div class="stv-details-admission-table h-100 pb-3">
<h4>{{$p.t('admission', 'allgemein')}}</h4>
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
@@ -488,7 +536,7 @@ export default {
<div v-if="allowUebernahmePunkte" class="col-4">
<label class="form-label" style="color:transparent;">getPunkte</label>
<button class="btn btn-outline-secondary w-100" @click="getResultReihungstest(formData.rt_id)">{{ $p.t('admission', 'getRTErgebnis') }}</button>
<button class="btn btn-outline-secondary w-100" @click="getResultReihungstest(formData.rt_id, stgRtPers)">{{ $p.t('admission', 'getRTErgebnis') }}</button>
</div>
</div>
@@ -50,11 +50,24 @@ export default {
this.listAufnahmetermine = result.data;
const listAufnahmetermineFiltered = this.listAufnahmetermine
.filter(item => item.studiengangkurzbzlang == this.student.studiengang)
.filter(item => item.studiengang_kz_ber == this.student.studiengang_kz)
.sort((a, b) => this.parseSemester(b.studiensemester) - this.parseSemester(a.studiensemester));
const elementSemYoungest = listAufnahmetermineFiltered[0];
this.formData.rt_gesamtpunkte = elementSemYoungest.punkte;
let pointsSemStg = 0;
if(listAufnahmetermineFiltered.length > 0){
const youngestSemester = listAufnahmetermineFiltered[0].studiensemester;
//sum of all rt-points of studiengang of youngest sem
pointsSemStg = listAufnahmetermineFiltered
.filter(item => item.studiensemester === youngestSemester)
.reduce((sum, item) => sum + (Number(item.punkte) || 0), 0);
}
else
pointsSemStg = 0;
this.formData.rt_gesamtpunkte = pointsSemStg;
})
.catch(this.$fhcAlert.handleSystemError);
@@ -91,8 +104,8 @@ export default {
},
template: `
<div class="stv-details-admission-header-placement h-100 pb-3">
<h4>{{ $p.t('lehre', 'studiengang') }}</h4>
<h4>{{ $p.t('lehre', 'studiengang') }}</h4> {{student.studiengang}}
<form-form class="mt-3" ref="formRtGesamtData" @submit.prevent>
<div v-if="showAufnahmegruppen" class="row mb-3">
<div class="col-1">