From 701ccadff3910a045fc93544b6fd6f0416241814 Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Thu, 12 Feb 2026 13:56:56 +0100 Subject: [PATCH] approveGrades phrase with counter; computed maxAntritte by config settings; block illegal pruefung creation in frontend (backend was already working); --- .../controllers/api/frontend/v1/Noten.php | 12 ++- .../Cis/Benotungstool/Benotungstool.js | 99 +++++++++++++++---- system/phrasesupdate.php | 6 +- 3 files changed, 91 insertions(+), 26 deletions(-) diff --git a/application/controllers/api/frontend/v1/Noten.php b/application/controllers/api/frontend/v1/Noten.php index 13f63a689..8ec5191ff 100644 --- a/application/controllers/api/frontend/v1/Noten.php +++ b/application/controllers/api/frontend/v1/Noten.php @@ -95,7 +95,8 @@ class Noten extends FHCAPI_Controller // 'CIS_GESAMTNOTE_GEWICHTUNG' => CIS_GESAMTNOTE_GEWICHTUNG, // this one should always be set true since fh prüfungsordnung requires at least 3 antritte (t1+t2+kP) -// 'CIS_GESAMTNOTE_PRUEFUNG_TERMIN2' => CIS_GESAMTNOTE_PRUEFUNG_TERMIN2, + // send it anyway to use in maxAntritte calculation + 'CIS_GESAMTNOTE_PRUEFUNG_TERMIN2' => CIS_GESAMTNOTE_PRUEFUNG_TERMIN2, // TODO @@ -561,7 +562,7 @@ class Noten extends FHCAPI_Controller } - $result = $this->LvgesamtnoteModel->getLvGesamtNote($lva_id, $student_uid, $stsem); + $result = $this->LvgesamtnoteModel->getLvGesamtNoten($lva_id, $student_uid, $stsem); if(!isError($result) && !hasData($result)) { $id = $this->LvgesamtnoteModel->insert( @@ -670,8 +671,6 @@ class Noten extends FHCAPI_Controller $pruefungenChanged = []; - $this->load->model('education/Lvgesamtnote_model', 'LvgesamtnoteModel'); - if($typ == "Termin2" && defined('CIS_GESAMTNOTE_PRUEFUNG_TERMIN2') && CIS_GESAMTNOTE_PRUEFUNG_TERMIN2) { @@ -726,9 +725,12 @@ class Noten extends FHCAPI_Controller $res = $this->LePruefungModel->load($id->retval); if(hasData($res)) $pruefungenChanged['extraPruefung'] = getData($res); } + + $this->logLib->logInfoDB(array('termin1 created',$res, getAuthUID(), getAuthPersonId())); + } - $this->logLib->logInfoDB(array('termin1 created',$res, getAuthUID(), getAuthPersonId())); + // Die Pruefung wird als Termin2 eingetragen diff --git a/public/js/components/Cis/Benotungstool/Benotungstool.js b/public/js/components/Cis/Benotungstool/Benotungstool.js index e832f5a09..9df7cf46f 100644 --- a/public/js/components/Cis/Benotungstool/Benotungstool.js +++ b/public/js/components/Cis/Benotungstool/Benotungstool.js @@ -231,14 +231,28 @@ export const Benotungstool = { } }, validatePruefungBulk(pruefungen) { + console.log('validatePruefungBulk') + // need to check pruefungen for validity in respect to the students nr of antritte // pruefungsdatum will be validated aswell so we dont get a termin 3 chronologically before // a termin 2 which is totally possible in the old tool const validatedPruefungen = [] pruefungen.forEach( p => { const student = this.studenten.find(s => s.uid === p.uid) + + // if a student doesnt have a lv_note entered definitely dont allow to create pruefung + if(!student.lv_note) { + this.$fhcAlert.alertWarning('Student ' + student.uid + ' hat noch keine LV-Note eingetragen! Es wird keine Prüfung angelegt.') + return + } + + if(!student.note) { + this.$fhcAlert.alertWarning('Student ' + student.uid + ' hat noch keine Zeugnis Note eingetragen! Es wird keine Prüfung angelegt.') + return + } + // check if student antrittCount is too high already - if(student.hoechsterAntritt >= 3) { + if(student.hoechsterAntritt >= this.maxAntrittCount) { this.$fhcAlert.alertWarning('Student ' + student.uid + ' hat bereits ' + student.hoechsterAntritt + ' Prüfungsantritte abgelegt. Die Zeile wurde übersprungen.') return } @@ -386,6 +400,7 @@ export const Benotungstool = { }) }, savePruefungBulk(pruefungenbulk) { + console.log('pruefungenbulk', pruefungenbulk) this.loading = true this.$api.call(ApiNoten.saveStudentPruefungBulk(this.lv_id, this.sem_kurzbz, pruefungenbulk)) .then((res)=> { @@ -467,7 +482,8 @@ export const Benotungstool = { widthGrow: 1, minWidth: 150, originalNote, - visible: true + visible: true, + tooltip: false }) }) @@ -476,6 +492,8 @@ export const Benotungstool = { this.loading = false + // TODO: find some solution so the tool does not appear "jumpy" after pruefung calls + this.$refs.notenTable.tabulator.clearSort() this.$refs.notenTable.tabulator.setColumns(cols) this.$refs.notenTable.tabulator.setData(this.studenten); @@ -548,7 +566,7 @@ export const Benotungstool = { const data = row.getData(); if(data['kommPruef']) return false - else if(data.hoechsterAntritt >= 3) return false // 3 pruefungen counted + else if(data.hoechsterAntritt >= this.maxAntrittCount) return false // 3 pruefungen counted return true; // student can be selected to add pruefung }, @@ -701,7 +719,8 @@ export const Benotungstool = { formatter: this.pruefungFormatter, topCalc: this.terminCalcFunc, topCalcFormatter: this.terminCalcFormatter, - hozAlign:"center", minWidth: 150, visible: false + hozAlign:"center", minWidth: 150, visible: false, + tooltip: false }) return columns @@ -742,7 +761,7 @@ export const Benotungstool = { const data = row.getData() - const notSelectable = data.pruefungen?.find(p => p.pruefungstyp_kurzbz == 'kommPruef') || data.hoechsterAntritt >= 3 + const notSelectable = data.pruefungen?.find(p => p.pruefungstyp_kurzbz == 'kommPruef') || data.hoechsterAntritt >= this.maxAntrittCount if(notSelectable) { row.getElement().children[0]?.children[0]?.remove() } @@ -898,10 +917,12 @@ export const Benotungstool = { return '
'+val+'
' }, pruefungFormatter(cell) { + console.log('pruefungFormatter') const data = cell.getData() const noteDef = data.note ? this.notenOptions.find(n => n.note == data.note) : null if(!data.note || !noteDef?.lkt_ueberschreibbar) { + console.log('!data.note || !noteDef?.lkt_ueberschreibbar') return '' } @@ -963,9 +984,12 @@ export const Benotungstool = { return colDiv; } + + console.log(data) + console.log(field) if(data[field]) { - + console.log(data[field]) // showing date in // const dateParts = data[field].datum.split('-') @@ -1001,7 +1025,7 @@ export const Benotungstool = { return rowDiv; } else if (canAdd) { // return new btn action - + console.log('canAdd') // dont render the add button in cells where a younger pruefung exists for the students const youngerPruefung = data.pruefungen.find(p => p.datum > field) if(youngerPruefung) return rowDiv @@ -1016,7 +1040,10 @@ export const Benotungstool = { rowDiv.appendChild(createCol(button), 'col-4 d-flex justify-content-center align-items-center'); return rowDiv; - } else return '' + } else { + console.log('return empty else') + return '' + } }, openPruefungModal(student, pruefung = null, field) { this.pruefungStudent = student @@ -1188,7 +1215,7 @@ export const Benotungstool = { Object.defineProperty(s, 'selectable', { get() { const kP = s.pruefungen?.find(p => p.pruefungstyp_kurzbz == 'kommPruef') - return !(kP || s.hoechsterAntritt >= 3) + return !(kP || s.hoechsterAntritt >= this.maxAntrittCount) }, set() { // empty setter so tabulator doesnt scream @@ -1228,7 +1255,8 @@ export const Benotungstool = { widthGrow: 1, minWidth: 200, originalNote, - visible: true + visible: true, + tooltip: false }) }) @@ -1517,7 +1545,8 @@ export const Benotungstool = { widthGrow: 1, minWidth: 200, originalNote, - visible: true + visible: true, + tooltip: false }) }) @@ -1581,12 +1610,41 @@ export const Benotungstool = { const dateStrDb = `${year}-${month}-${day}`; const dateStrFront = `${day}.${month}.${year}`; - const uids = this.selectedUids.map(student => { - return { + const uids = [] + // const uids = this.selectedUids.map(student => { + this.selectedUids.forEach(student => { + + // if a student doesnt have a lv_note entered definitely dont allow to create pruefung + if(!student.lv_note) { + this.$fhcAlert.alertWarning('Student ' + student.uid + ' hat noch keine LV-Note eingetragen! Es wird keine Prüfung angelegt.') + return + } + + if(!student.note) { + this.$fhcAlert.alertWarning('Student ' + student.uid + ' hat noch keine Zeugnis Note eingetragen! Es wird keine Prüfung angelegt.') + return + } + + // check if student antrittCount is too high already + if(student.hoechsterAntritt >= this.maxAntrittCount) { + this.$fhcAlert.alertWarning('Student ' + student.uid + ' hat bereits ' + student.hoechsterAntritt + ' Prüfungsantritte abgelegt. Es wird keine Prüfung angelegt.') + return + } + + // get student for pruefung and check if proposed datum does not conflict (no new pruefungen before existing ones) + const youngerPruefung = student.pruefungen.find(pr => { + return pr.dateObj >= this.selectedPruefungDate + }) + if(youngerPruefung) { + this.$fhcAlert.alertWarning('Student ' + student.uid + ' hat bereits eine Prüfung am '+ youngerPruefung.datum +' eingetragen. Es wird keine Prüfung angelegt.') + return + } + + uids.push({ uid: student.uid, lehreinheit_id: student.lehreinheit_id, typ: this.getPruefungstypForStudentByAntritt(student)//student.hoechsterAntritt - } + }) }) this.loading = true; @@ -1710,6 +1768,14 @@ export const Benotungstool = { } }, computed: { + maxAntrittCount() { + let maxAntritte = 1; + + if(this.config?.CIS_GESAMTNOTE_PRUEFUNG_TERMIN2) maxAntritte++ + if(this.config?.CIS_GESAMTNOTE_PRUEFUNG_TERMIN3) maxAntritte++ + + return maxAntritte; + }, getFreigabeCounter() { return this.studenten ? this.studenten.reduce((acc, cur) => { if(cur.freigegeben == 'changed') { @@ -1980,12 +2046,9 @@ export const Benotungstool = { {{$capitalize($p.t('benotungstool/c4notenImportieren'))}} - - -

{{ getFreigabeCounter > 0 ? $capitalize($p.t('benotungstool/freigabecounterPositiv', [getFreigabeCounter])) : '' }}

diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 8e151bcf9..8d8303545 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -54020,18 +54020,18 @@ and represent the current state of research on the topic. The prescribed citatio array( 'app' => 'core', 'category' => 'benotungstool', - 'phrase' => 'approveGrades', + 'phrase' => 'approveGradesv2', 'insertvon' => 'system', 'phrases' => array( array( 'sprache' => 'German', - 'text' => 'Noten freigeben', + 'text' => '{0} Noten freigeben', 'description' => '', 'insertvon' => 'system' ), array( 'sprache' => 'English', - 'text' => 'Approve Grades', + 'text' => 'Approve {0} Grades', 'description' => '', 'insertvon' => 'system' )