From db75cd2f627703694b78d06cbaf5b7ccdbf97aae Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Tue, 3 Mar 2026 10:42:47 +0100 Subject: [PATCH 1/6] also skip email loop/relevant abgaben loop when every occurance is filtered out to avoid empty notification emails; --- application/controllers/jobs/AbgabetoolJob.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/application/controllers/jobs/AbgabetoolJob.php b/application/controllers/jobs/AbgabetoolJob.php index 9b59a72e7..b81053032 100644 --- a/application/controllers/jobs/AbgabetoolJob.php +++ b/application/controllers/jobs/AbgabetoolJob.php @@ -495,6 +495,10 @@ class AbgabetoolJob extends JOB_Controller // get all new or changed termine in interval $result = $this->_ci->PaabgabeModel->findAbgabenNewOrUpdatedSince($interval, $relevantTypes); $retval = getData($result); + if(!$retval) { + $this->_ci->logInfo("Keine Emails an Betreuer über neue oder veränderte Termine versandt"); + return; + } // group changed/new abgaben for projektarbeiten $projektarbeiten = []; @@ -557,6 +561,8 @@ class AbgabetoolJob extends JOB_Controller $anredeFillString = $data->anrede == "Herr" ? "r" : ""; $fullFormattedNameString = $data->first; + $relevantCounter = 0; // workaround to check if a betreuer needs to have any notification about relevant + // abgaben at all to avoid sending empty emails since we filter on certain conditions forEach($tupelArr as $tupel) { $projektarbeit_id = $tupel[0]; $betreuerRow = $tupel[1]; @@ -575,6 +581,8 @@ class AbgabetoolJob extends JOB_Controller continue; } + $relevantCounter++; + // format the Student Name $s = $relevantAbgaben[0]; $nameParts = []; @@ -633,6 +641,11 @@ class AbgabetoolJob extends JOB_Controller // done with building the change list, now send it $betreuerRow = $tupelArr[0][1]; + if($relevantCounter == 0) { + $this->_ci->logInfo('No Relevant Abgaben to notify Betreuer PersonID: "'.$betreuerRow->person_id.'".'); + continue; + } + $path = $this->_ci->config->item('URL_MITARBEITER'); $url = CIS_ROOT.$path; From 56a6aa993e7c8c9d8d01c3aebfdc39bd04994745 Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Tue, 3 Mar 2026 10:52:12 +0100 Subject: [PATCH 2/6] getMitarbeiterProjektarbeiten safeguard in case a person without any assigned betreuungen opens the page for some reason to avoid nasty confusing sql error messages from querying with empty parameters --- application/controllers/api/frontend/v1/Abgabe.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/application/controllers/api/frontend/v1/Abgabe.php b/application/controllers/api/frontend/v1/Abgabe.php index af598a345..0b82b7c20 100644 --- a/application/controllers/api/frontend/v1/Abgabe.php +++ b/application/controllers/api/frontend/v1/Abgabe.php @@ -511,10 +511,11 @@ class Abgabe extends FHCAPI_Controller return $projektarbeit->projektarbeit_id; }; $projektarbeiten_ids = array_map($mapFunc, $projektarbeiten->retval); - - $ret = $this->ProjektarbeitModel->getProjektarbeitenAbgabetermine($projektarbeiten_ids); - $projektabgaben = $this->getDataOrTerminateWithError($ret, 'general'); + if(count($projektarbeiten_ids) > 0) { + $ret = $this->ProjektarbeitModel->getProjektarbeitenAbgabetermine($projektarbeiten_ids); + $projektabgaben = $this->getDataOrTerminateWithError($ret, 'general'); + } forEach($projektarbeiten->retval as $pa) { From b43f1ec920f76a07cc40241a075b1624920d06ec Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Wed, 11 Mar 2026 17:00:56 +0100 Subject: [PATCH 3/6] AbgabetoolAssistenz download latest uploaded file action button; UX changes Projektarbeit Tab Stv; fix stv form input bug after invalidation for selects; --- .../controllers/api/frontend/v1/Abgabe.php | 7 ++-- .../Cis/Abgabetool/AbgabetoolAssistenz.js | 32 ++++++++++++++- .../Cis/Abgabetool/AbgabetoolMitarbeiter.js | 4 +- public/js/components/Form/Input.js | 7 ++-- .../Details/Projektarbeit/Details.js | 10 +++-- .../Details/Projektarbeit/Projektbetreuer.js | 1 - system/phrasesupdate.php | 40 +++++++++++++++++++ 7 files changed, 89 insertions(+), 12 deletions(-) diff --git a/application/controllers/api/frontend/v1/Abgabe.php b/application/controllers/api/frontend/v1/Abgabe.php index 0b82b7c20..43dc18d1c 100644 --- a/application/controllers/api/frontend/v1/Abgabe.php +++ b/application/controllers/api/frontend/v1/Abgabe.php @@ -847,9 +847,10 @@ class Abgabe extends FHCAPI_Controller private function getProjektbetreuerEmailByProjektarbeitID($projektarbeit_id) { $this->load->model('education/Projektarbeit_model', 'ProjektarbeitModel'); $result = $this->ProjektarbeitModel->getProjektbetreuerEmail($projektarbeit_id); - $email = $this->getDataOrTerminateWithError($result, 'general'); - - return $email[0]->uid ? $email[0]->uid.'@'.DOMAIN : $email[0]->private_email; + if(count($result->retval) > 0) { + $email = getData($result); + return $email[0]->uid ? $email[0]->uid.'@'.DOMAIN : $email[0]->private_email; + } else return ''; } diff --git a/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js b/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js index d5caf97a6..85ca901d9 100644 --- a/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js +++ b/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js @@ -675,8 +675,20 @@ export const AbgabetoolAssistenz = { createButton('fa fa-timeline', 'abgabetool/c4termineTimeLine', () => this.openTimeline(val)) ); + if(val.latestTerminWithUpload) { + actionButtons.append( + createButton('fa fa-download', 'abgabetool/c4downloadLatestAbgabe', () => this.downloadAbgabe(val.latestTerminWithUpload.paabgabe_id, val.student_uid, val.projektarbeit_id)) + ) + } + return actionButtons; }, + downloadAbgabe(paabgabe_id, student_uid, projektarbeit_id) { + const url = `/api/frontend/v1/Abgabe/getStudentProjektarbeitAbgabeFile?paabgabe_id=${paabgabe_id}&student_uid=${student_uid}&projektarbeit_id=${projektarbeit_id}`; + + window.open(FHC_JS_DATA_STORAGE_OBJECT.app_root + FHC_JS_DATA_STORAGE_OBJECT.ci_router + url) + // this.$api.call(ApiAbgabe.getStudentProjektarbeitAbgabeFile(termin.paabgabe_id, this.projektarbeit.student_uid)) + }, undoSelection(cell) { // checks if cells row is selected and unselects -> imitates columns which dont trigger row selection @@ -780,6 +792,8 @@ export const AbgabetoolAssistenz = { // TODO: mehrsprachig englisch projekt.note_bez = opt.bezeichnung } + + const latestTerminWithUpload = this.findLatestTerminWithUpload(projekt) return { ...projekt, @@ -787,6 +801,7 @@ export const AbgabetoolAssistenz = { details: { student_uid: projekt.student_uid, projektarbeit_id: projekt.projektarbeit_id, + latestTerminWithUpload: latestTerminWithUpload ?? null }, pkz: this.buildPKZ(projekt), beurteilung: projekt.beurteilungLink ?? null, @@ -800,6 +815,15 @@ export const AbgabetoolAssistenz = { } }) }, + findLatestTerminWithUpload(projekt) { + const withAbgabedatumSorted = projekt?.abgabetermine?.filter(t => t.abgabedatum != null)?.sort((a,b) => a < b) + + if(withAbgabedatumSorted.length) { + return withAbgabedatumSorted[0] + } + + return null + }, createInfoString(data) { let str = ''; @@ -1413,9 +1437,12 @@ export const AbgabetoolAssistenz = {
-
+

{{$p.t('abgabetool/abgabetoolTitle')}}

+
+ +
+
+ +
projekarbeit.projektarbeit_id == details.projektarbeit_id) + const projektarbeiten = this.projektarbeiten?.retval ?? this.projektarbeiten + const pa = projektarbeiten.find(projekarbeit => projekarbeit.projektarbeit_id == details.projektarbeit_id) + let paIsBenotet = false if(pa.note !== undefined && pa.note !== null) { // check if the note is not defined as a non final projektarbeit note diff --git a/public/js/components/Form/Input.js b/public/js/components/Form/Input.js index 3c3fa45d5..4ad555ab7 100644 --- a/public/js/components/Form/Input.js +++ b/public/js/components/Form/Input.js @@ -170,6 +170,7 @@ export default { return this.$attrs.modelValue; }, set(v) { + this.clearValidationForThisName() if (!this.$attrs.hasOwnProperty('modelValue')) this.modelValueDummy = v; this.$emit('update:modelValue', v); @@ -242,9 +243,9 @@ export default { template: ` - - - + + 'core', + 'category' => 'abgabetool', + 'phrase' => 'c4downloadLatestAbgabe', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => "Zuletzt getätigte Abgabe herunterladen", + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Download latest uploaded File', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'abgabetool', + 'phrase' => 'c4termineTimeLine', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Zeitstrahl Termine', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Timeline Deadlines', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'core', 'category' => 'abgabetool', From 5ef1dccfc97a340df7d2f99b1ce1691f03ba156a Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Thu, 12 Mar 2026 14:58:35 +0100 Subject: [PATCH 4/6] added missing phrase c4noZuordnungBetreuerStudent --- system/phrasesupdate.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 11dbe5a8c..14dd0a26c 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -46735,6 +46735,26 @@ array( ) ) ), + array( + 'app' => 'core', + 'category' => 'abgabetool', + 'phrase' => 'c4noZuordnungBetreuerStudent', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Keine Zuordnung oder Berechtigung für die Projektarbeit gefunden!', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'No assignment or authorization found for the project!', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), // ABGABETOOL PHRASEN END array( 'app' => 'core', From 4778bb82c3f60a1d8cf8729fe66e7ff677aa2d70 Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Mon, 16 Mar 2026 10:56:51 +0100 Subject: [PATCH 5/6] assistenz action buttons lefthand alignment & lower minwidth --- public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js b/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js index 85ca901d9..1a4e4171d 100644 --- a/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js +++ b/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js @@ -180,7 +180,7 @@ export const AbgabetoolAssistenz = { // frozen: true, // width: 40 // }, - {title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4details'))), field: 'details', headerFilter: false, headerSort: false, formatter: this.formAction, tooltip:false, minWidth: 150, cssClass: 'sticky-col'}, + {title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4details'))), field: 'details', headerFilter: false, headerSort: false, formatter: this.formAction, tooltip:false, minWidth: 100, cssClass: 'sticky-col'}, {title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4personenkennzeichen'))), headerFilter: true, field: 'pkz', formatter: this.pkzTextFormatter, widthGrow: 1, tooltip: false}, {title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4vorname'))), field: 'student_vorname', headerFilter: true, formatter: this.centeredTextFormatter,widthGrow: 1}, {title: Vue.computed(() => this.$capitalize(this.$p.t('abgabetool/c4nachname'))), field: 'student_nachname', headerFilter: true, formatter: this.centeredTextFormatter, widthGrow: 1}, @@ -645,7 +645,7 @@ export const AbgabetoolAssistenz = { actionButtons.className = "d-flex gap-3"; // you can keep Bootstrap gap if loaded actionButtons.style.display = "flex"; actionButtons.style.alignItems = "stretch"; // buttons stretch to full height - actionButtons.style.justifyContent = "center"; + actionButtons.style.justifyContent = "start"; actionButtons.style.height = "100%"; // full grid cell height const val = cell.getValue(); From 6ec32b0ca39e377a70184d311e5f72b294ce041e Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Mon, 16 Mar 2026 11:05:48 +0100 Subject: [PATCH 6/6] update tabulator persistence id --- public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js b/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js index 1a4e4171d..bb5c6a710 100644 --- a/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js +++ b/public/js/components/Cis/Abgabetool/AbgabetoolAssistenz.js @@ -226,7 +226,7 @@ export const AbgabetoolAssistenz = { field: 'qgate2Status', formatter: this.centeredTextFormatter, widthGrow: 1, width: 220, tooltip: false}, ], persistence: false, - persistenceID: "abgabetool_2026_02_26" + persistenceID: "abgabetool_2026_03_16" }, abgabeTableEventHandlers: [ {