diff --git a/application/controllers/jobs/AbgabetoolJob.php b/application/controllers/jobs/AbgabetoolJob.php
index 51b2b4920..3e0774538 100644
--- a/application/controllers/jobs/AbgabetoolJob.php
+++ b/application/controllers/jobs/AbgabetoolJob.php
@@ -22,11 +22,272 @@ class AbgabetoolJob extends JOB_Controller
$this->_ci->load->model('crm/Student_model', 'StudentModel');
$this->_ci->load->model('organisation/Studiengang_model', 'StudiengangModel');
$this->_ci->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel');
-
+
+ $this->_ci->load->library('SignatureLib');
+
$this->_ci->load->config('abgabe');
$this->loadPhrases([
'abgabetool'
]);
+
+
+ }
+
+ // basically the notifyBetreuerMail function but email goes to assistenz
+ // and new abgaben are further evaluated for missing signature status
+ public function notifyAssistenzAboutMissingSignatureUploads() {
+ $this->_ci->logInfo('Start job FHC-Core->notifyAssistenzAboutMissingSignatureUploads');
+
+ $interval = $this->_ci->config->item('PAABGABE_EMAIL_JOB_INTERVAL');
+ $relevantTypes = $this->_ci->config->item('RELEVANT_PAABGABETYPEN_SAMMELMAIL_ASSISTENZ');
+
+ $result = $this->_ci->PaabgabeModel->findAbgabenNewOrUpdatedSinceByAbgabedatum($interval, $relevantTypes);
+ $retval = getData($result);
+
+ // retval are paabgaben joined with projektarbeit and betreuer
+ if(count($retval) == 0) {
+ $this->logInfo("Keine Emails über neue Paabgaben an Assistenzen versandt");
+ return;
+ }
+
+ // group changed/new abgaben for projektarbeiten
+ $projektarbeiten = [];
+ foreach($retval as $abgabeWithNewUpload) {
+ // Check if the current item has a 'projektarbeit_id' field.
+ // Replace 'projektarbeit_id' with the actual key name if it's different.
+ if (isset($abgabeWithNewUpload->projektarbeit_id)) {
+ $projektarbeitId = $abgabeWithNewUpload->projektarbeit_id;
+
+ // If the 'projektarbeit_id' is not yet a key in $projektarbeiten,
+ // initialize it as an empty array.
+ if (!isset($projektarbeiten[$projektarbeitId])) {
+ $projektarbeiten[$projektarbeitId] = [];
+ }
+
+ // check signature for that abgabe, main point of this job
+ $this->checkAbgabeSignatur($abgabeWithNewUpload, $abgabeWithNewUpload->student_uid);
+
+ // Add the current row to the array associated with its 'projektarbeit_id'.
+ $projektarbeiten[$projektarbeitId][] = $abgabeWithNewUpload;
+ }
+ }
+
+ // for each projektarbeit fetch their assistenz and same them in their own dictionary to avoid too many mails
+ $assistenzMap = [];
+ // for each projektarbeit fetch their betreuer and save them in their own dictionary to avoid too many mails
+ $projektarbeitBetreuerMap = [];
+ forEach($projektarbeiten as $projektarbeit_id => $abgaben) {
+
+ $assistenzResult = $this->_ci->OrganisationseinheitModel->getAssistenzForOE($abgaben[0]->stg_oe_kurzbz);
+
+ forEach($assistenzResult->retval as $assistenzRow) {
+ if (!isset($assistenzMap[$assistenzRow->person_id])) {
+ $assistenzMap[$assistenzRow->person_id] = [];
+ }
+
+ // Add the current $assistenzRow to the $assistenzMap as an array associated with its projektarbeit_id.
+ $assistenzMap[$assistenzRow->person_id][] = [$projektarbeit_id, $assistenzRow];
+ }
+
+ $betreuerResult = $this->_ci->ProjektbetreuerModel->getAllBetreuerOfProjektarbeit($projektarbeit_id);
+
+ forEach($betreuerResult->retval as $betreuerRow) {
+ if (!isset($projektarbeitBetreuerMap[$projektarbeit_id])) {
+ $projektarbeitBetreuerMap[$projektarbeit_id] = [];
+ }
+
+ // Add the current betreuerRow to the betreuerMap as an array associated with its projektarbeit_id.
+ $projektarbeitBetreuerMap[$projektarbeit_id][] = $betreuerRow;
+ }
+
+ }
+
+ $count = 0;
+ foreach($assistenzMap as $assistenz_person_id => $tupelArr) {
+
+ $abgabenString = '
';
+ $hasIssues = false; // Track if this assistant actually needs an email
+
+ foreach($tupelArr as $tupel) {
+ $projektarbeit_id = $tupel[0];
+ $assistenzRow = $tupel[1];
+
+ $betreuerArray = $projektarbeitBetreuerMap[$projektarbeit_id] ?? [];
+ $allAbgaben = $projektarbeiten[$projektarbeit_id];
+
+ // only keep abgaben that are not correctly signed
+ $issueAbgaben = array_filter($allAbgaben, function($abgabe) {
+ // We only care about cases where it's explicitly NOT true (false, error, or null)
+ return $abgabe->signatur !== true;
+ });
+
+ // if this specific project has no signature issues, skip to the next project
+ if(empty($issueAbgaben)) {
+ continue;
+ }
+
+ // If we reached here, we have at least one issue to report
+ $hasIssues = true;
+
+ // Format the Student Name (using the first available abgabe object)
+ $s = reset($issueAbgaben);
+ $nameParts = array_filter([$s->titelpre, $s->vorname, $s->nachname, $s->titelpost]);
+ $studentFullName = implode(' ', $nameParts);
+
+ // Format the Supervisors string
+ $betreuerStrings = [];
+ foreach($betreuerArray as $b) {
+ $bNameParts = array_filter([$b->titelpre, $b->vorname, $b->nachname, $b->titelpost]);
+ $bFullName = implode(' ', $bNameParts);
+ $betreuerStrings[] = "{$bFullName} ({$b->betreuerart_kurzbz})";
+ }
+ $allBetreuerFormatted = implode(', ', $betreuerStrings);
+
+ $projektarbeit_titel = $s->titel ?? 'Kein Titel vergeben';
+
+ // Project Header Section
+ $abgabenString .= "
+
+
Projekt: {$projektarbeit_titel}
+
+ Studierende/r: {$studentFullName}
+
+
+ Betreuer: {$allBetreuerFormatted}
+
+
+ ID: {$projektarbeit_id} | Stg: {$s->stgtyp}{$s->stgkz} ({$s->studiensemester_kurzbz})
+
+
";
+
+ // Start Table
+ $abgabenString .= '
+
+
+
+ | Datum |
+ Abgabe/Bezeichnung |
+ Status |
+
+
+ ';
+
+ $printed = []; // lazy hack to avoid duplicate rows
+ foreach ($issueAbgaben as $abgabe) {
+ // if we had this paabgabe already (erstbetreuer/zweitbetreuer fetch achieves duplicates
+ if(in_array($abgabe->paabgabe_id, $printed)) {
+ continue; // skip this forEach iteration
+ }
+
+ $printed[] = $abgabe->paabgabe_id;
+
+ $abgabedatumFormatted = (new DateTime($abgabe->abgabedatum))->format('d.m.Y');
+
+ // label and color
+ if ($abgabe->signatur === false) {
+ $sigLabel = "FEHLENDE SIGNATUR";
+ $sigBg = "#dc3545";
+ } elseif ($abgabe->signatur === 'error') {
+ $sigLabel = "PRÜFUNG FEHLGESCHLAGEN";
+ $sigBg = "#fd7e14";
+ } else {
+ $sigLabel = "DATEI NICHT GEFUNDEN";
+ $sigBg = "#6c757d";
+ }
+
+ $abgabenString .= "
+
+ | {$abgabedatumFormatted} |
+
+ {$abgabe->bezeichnung}
+ |
+
+
+ {$sigLabel}
+
+ |
+
";
+ }
+
+ $abgabenString .= '
';
+ }
+
+ $abgabenString .= '
';
+
+ // only send the email if at least one project had an issue
+ if ($hasIssues) {
+ $assistenzRow = $tupelArr[0][1];
+ $anrede = $assistenzRow->anrede;
+ $anredeFillString = $assistenzRow->anrede == "Herr" ? "r" : "";
+ $fullFormattedNameString = $assistenzRow->first;
+
+ $path = $this->_ci->config->item('URL_ASSISTENZ');
+ $url = CIS_ROOT . $path;
+
+ $body_fields = array(
+ 'anrede' => $anrede,
+ 'anredeFillString' => $anredeFillString,
+ 'fullFormattedNameString' => $fullFormattedNameString,
+ 'abgabenString' => $abgabenString,
+ 'linkAbgabetool' => $url
+ );
+
+ $email = $assistenzRow->uid . "@" . DOMAIN;
+
+ sendSanchoMail(
+ 'PAANoSigAssSM',
+ $body_fields,
+ $email,
+ $this->p->t('abgabetool', 'c4missingSignatureNotification')
+ );
+
+ $count++;
+ }
+ }
+
+ $this->_ci->logInfo($count . " Emails bezüglich fehlender Signaturen erfolgreich versandt");
+ $this->_ci->logInfo('End job FHC-Core->notifyAssistenzAboutMissingSignatureUploads');
+ }
+
+ /**
+ * helper function to check the signature status of uploaded files for zwischenabgabe & endupload
+ */
+ private function checkAbgabeSignatur($abgabe, $student_uid) {
+ $paabgabetypenToCheck = $this->config->item('SIGNATUR_CHECK_PAABGABETYPEN');
+
+ if(!in_array($abgabe->paabgabetyp_kurzbz, $paabgabetypenToCheck)) {
+ return;
+ }
+
+ if (!defined('SIGNATUR_URL')) {
+ $abgabe->signatur = 'error';
+ return;
+ }
+
+ $path = PAABGABE_PATH.$abgabe->paabgabe_id.'_'.$student_uid.'.pdf';
+
+ $signaturVorhanden = null; // if frontend receives null -> indicates no file found at path
+ if(file_exists($path)) {
+
+ // Check if the document is signed
+ $signList = SignatureLib::list($path);
+ if (is_array($signList) && count($signList) > 0)
+ {
+ // The document is signed
+ $signaturVorhanden = true;
+ }
+ elseif ($signList === null)
+ {
+ // frontend knows to handle it this way for signatures
+ $signaturVorhanden = 'error';
+ }
+ else
+ {
+ $signaturVorhanden = false;
+ }
+
+ $abgabe->signatur = $signaturVorhanden;
+ }
}
public function notifyAssistenzAboutChangedAbgaben() {
diff --git a/application/models/education/Paabgabe_model.php b/application/models/education/Paabgabe_model.php
index a883043d3..be42b7660 100644
--- a/application/models/education/Paabgabe_model.php
+++ b/application/models/education/Paabgabe_model.php
@@ -86,27 +86,38 @@ class Paabgabe_model extends DB_Model
return $this->execQuery($query, [$interval, $interval, $relevantTypes]);
}
- public function findAbgabenNewOrUpdatedSinceByAbgabedatum($interval) {
-
- $query = "SELECT projektarbeit_id, paabgabe_id, paabgabetyp_kurzbz, fixtermin, datum, kurzbz, campus.tbl_paabgabetyp.bezeichnung, campus.tbl_paabgabe.abgabedatum,
- campus.tbl_paabgabe.insertvon, campus.tbl_paabgabe.insertamum, campus.tbl_paabgabe.updatevon, campus.tbl_paabgabe.updateamum,
- campus.tbl_paabgabe.note, upload_allowed, beurteilungsnotiz, student_uid, tbl_projektarbeit.note, lehre.tbl_projektarbeit.titel,
- lehre.tbl_projektbetreuer.betreuerart_kurzbz, lehre.tbl_projektbetreuer.person_id,
- public.tbl_person.anrede, public.tbl_person.titelpre, public.tbl_person.vorname, public.tbl_person.nachname, public.tbl_person.titelpost
+ public function findAbgabenNewOrUpdatedSinceByAbgabedatum($interval, $relevantTypes = null) {
+
+ $queryParams = [$interval];
+ $query = "SELECT projektarbeit_id, paabgabe_id, paabgabetyp_kurzbz, fixtermin, datum, campus.tbl_paabgabe.kurzbz, campus.tbl_paabgabetyp.bezeichnung, campus.tbl_paabgabe.abgabedatum,
+ campus.tbl_paabgabe.insertvon, campus.tbl_paabgabe.insertamum, campus.tbl_paabgabe.updatevon, campus.tbl_paabgabe.updateamum,
+ campus.tbl_paabgabe.note, upload_allowed, beurteilungsnotiz, student_uid, tbl_projektarbeit.note, lehre.tbl_projektarbeit.titel,
+ UPPER(tbl_studiengang.typ) as stgtyp, UPPER(tbl_studiengang.kurzbz) as stgkz, public.tbl_studiengang.studiengang_kz,
+ public.tbl_studiengang.oe_kurzbz as stg_oe_kurzbz, tbl_lehreinheit.studiensemester_kurzbz,
+ lehre.tbl_projektbetreuer.betreuerart_kurzbz, lehre.tbl_projektbetreuer.person_id,
+ public.tbl_person.anrede, public.tbl_person.titelpre, public.tbl_person.vorname, public.tbl_person.nachname, public.tbl_person.titelpost
- FROM campus.tbl_paabgabe
- JOIN campus.tbl_paabgabetyp USING (paabgabetyp_kurzbz)
- JOIN lehre.tbl_projektarbeit USING (projektarbeit_id)
- JOIN lehre.tbl_projektbetreuer USING (projektarbeit_id)
- JOIN public.tbl_benutzer ON (public.tbl_benutzer.uid = student_uid)
- JOIN public.tbl_person ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
+ FROM campus.tbl_paabgabe
+ JOIN campus.tbl_paabgabetyp USING (paabgabetyp_kurzbz)
+ JOIN lehre.tbl_projektarbeit USING (projektarbeit_id)
+ JOIN lehre.tbl_projektbetreuer USING (projektarbeit_id)
+ JOIN lehre.tbl_lehreinheit using(lehreinheit_id)
+ JOIN lehre.tbl_lehrveranstaltung using(lehrveranstaltung_id)
+ JOIN public.tbl_studiengang on(lehre.tbl_lehrveranstaltung.studiengang_kz = public.tbl_studiengang.studiengang_kz)
+ JOIN public.tbl_benutzer ON (public.tbl_benutzer.uid = student_uid)
+ JOIN public.tbl_person ON (public.tbl_benutzer.person_id = public.tbl_person.person_id)
WHERE campus.tbl_paabgabe.abgabedatum IS NOT NULL
- AND campus.tbl_paabgabe.abgabedatum >= NOW() - INTERVAL ?
- ORDER BY abgabedatum DESC
- ";
+ AND campus.tbl_paabgabe.abgabedatum >= NOW() - INTERVAL ?";
+
+ if($relevantTypes !== null) {
+ $query .= " AND campus.tbl_paabgabe.paabgabetyp_kurzbz IN ?";
+ $queryParams[]= $relevantTypes;
+ }
- return $this->execQuery($query, [$interval]);
+ $query .= " ORDER BY abgabedatum DESC";
+
+ return $this->execQuery($query, $queryParams);
}
public function loadByIDs($paabgabe_ids) {
diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php
index 8860e2cf6..e21a167a3 100644
--- a/system/phrasesupdate.php
+++ b/system/phrasesupdate.php
@@ -46393,6 +46393,26 @@ array(
)
)
),
+ array(
+ 'app' => 'core',
+ 'category' => 'abgabetool',
+ 'phrase' => 'c4missingSignatureNotification',
+ 'insertvon' => 'system',
+ 'phrases' => array(
+ array(
+ 'sprache' => 'German',
+ 'text' => 'Abgabetool: Fehlende Signatur bei Endupload',
+ 'description' => '',
+ 'insertvon' => 'system'
+ ),
+ array(
+ 'sprache' => 'English',
+ 'text' => 'Submission tool: Missing signature at final upload',
+ 'description' => '',
+ 'insertvon' => 'system'
+ )
+ )
+ ),
// ABGABETOOL PHRASEN END
array(
'app' => 'core',