Merge branch 'master' into feature-68684/PHPMailer

This commit is contained in:
Paolo
2026-01-13 17:08:41 +01:00
11 changed files with 233 additions and 75 deletions
+88 -4
View File
@@ -200,13 +200,14 @@ class AntragJob extends JOB_Controller
}
/**
* Send reminder to Assistant for Wiedereinstieg Unterbrecher
* Send reminder to Assistant and to Student for Wiedereinstieg Unterbrecher
*
*/
public function sendReminderWiedereinstieg()
{
$now = new DateTime();
$modifier = $this->config->item('unterbrechung_job_remind_wiedereinstieg_date_modifier');
if (!$modifier)
return $this->logError('Konnte Job nicht starten: Config "unterbrechung_job_remind_wiedereinstieg_date_modifiers" nicht gesetzt');
@@ -230,6 +231,7 @@ class AntragJob extends JOB_Controller
$antraege = getData($result) ?: [];
$count = 0;
$countReminderStudent = 0;
foreach ($antraege as $antrag)
{
$res = $this->StudierendenantragModel->getStgAndSem($antrag->studierendenantrag_id);
@@ -257,10 +259,92 @@ class AntragJob extends JOB_Controller
$data['UID'] = $student->student_uid;
}
// NOTE(chris): Sancho mail
if(sendSanchoMail('Sancho_Mail_Antrag_U_Reminder', $data, $antrag->email, 'Reminder: Unterbrechung Wiedereinstieg'))
//Data für Email Student
$result = $this->PrestudentModel->load($antrag->prestudent_id);
$dataPrestudent = current(getData($result));
$person_id = $dataPrestudent->person_id;
$this->KontaktModel->addSelect('kontakt');
$result = $this->KontaktModel->loadWhere([
'person_id'=> $person_id,
'zustellung' => true,
'kontakttyp' => 'email'
]);
$email_student_privat = null;
$dataKontakt = getData($result);
if ($dataKontakt) {
$stud_private_zustell_emails = array_map(function($kontakt) {
return $kontakt->kontakt;
}, $dataKontakt);
$email_student_privat = implode(', ', $stud_private_zustell_emails);
}
$email_student_FH = $this->StudentModel->getEmailFH($this->StudentModel->getUID($antrag->prestudent_id));
//studiensemester
$result = $this->StudiensemesterModel->getByDate($datum->format('Y-m-d'));
if (hasData($result)) {
$dataSem = current(getData($result));
}
$studiensemester = $dataSem->studiensemester_kurzbz;
$studsemShort = substr($studiensemester, 0, 2);
if($studsemShort == "SS")
{
$data['studSemShort_Eng'] = "summer semester";
$data['meldenBis'] = "15.1.";
$data['meldenBis_Eng'] = "January 15";
}
elseif ($studsemShort == "WS") {
$data['studSemShort_Eng'] = "winter semester";
$data['meldenBis'] = "1.8.";
$data['meldenBis_Eng'] = "August 1";
}
else
{
$studsemShort = "SS/WS";
$data['studSemShort_Eng'] = "summer/winter semester";
$data['meldenBis'] = "15.1. (bei Einstieg ins SS) / 1.8. (bei Einstieg ins WS)";
$data['meldenBis_Eng'] = "January 15 (for sommer semester enrollment) / August 1 (for winter semester enrollment)";
}
$data['studSemShort'] = $studsemShort;
// NOTE(chris): Sancho mail Assistant
$sancho_assistant_sent = sendSanchoMail('Sancho_Mail_Antrag_U_Reminder', $data, $antrag->email, 'Reminder: Unterbrechung Wiedereinstieg');
if($sancho_assistant_sent)
{
$count++;
}
else
{
$this->logError('Error: failed to send Assistant Reminder studierendenantrag_id: ' . $antrag->studierendenantrag_id);
}
//Mail to Student
$sancho_student_sent = sendSanchoMail(
'Sancho_Mail_Antrag_U_Remind_Stud',
$data,
$email_student_FH,
'Reminder: Unterbrechung Wiedereinstieg',
'',
'',
'',
$email_student_privat);
if($sancho_student_sent)
{
$countReminderStudent++;
}
else
{
$this->logError('Error: failed to send Student Reminder studierendenantrag_id: ' . $antrag->studierendenantrag_id);
}
if($sancho_assistant_sent && $sancho_student_sent)
{
$this->StudierendenantragstatusModel->insert([
'studierendenantrag_id' => $antrag->studierendenantrag_id,
'studierendenantrag_statustyp_kurzbz' => Studierendenantragstatus_model::STATUS_REMINDERSENT,
@@ -268,7 +352,7 @@ class AntragJob extends JOB_Controller
]);
}
}
$this->logInfo($count . ' Reminder gesendet - Ende Job sendReminderWiedereinstieg');
$this->logInfo($count . ' Reminder an Assistenz und ' . $countReminderStudent . ' Reminder an Student gesendet - Ende Job sendReminderWiedereinstieg');
}
/**
+5 -6
View File
@@ -68,7 +68,8 @@ class PrestudentLib
$this->_ci->PrestudentModel->addOrder('zgv_code', 'DESC');
$this->_ci->PrestudentModel->addLimit(1);
$result = $this->_ci->PrestudentModel->loadWhere([
'person_id' => $person_id
'person_id' => $person_id,
'zgv_code IS NOT NULL' => null
]);
if (isError($result)) return $result;
@@ -686,9 +687,6 @@ class PrestudentLib
$now = date('c');
$today = date('Y-m-d');
$jahr = mb_substr($studiensemester_kurzbz, 4, 2);
// Genererate Personenkennzeichen
$personenkennzeichen = $this->_ci->StudentModel->generateMatrikelnummer2(
$student_data->studiengang_kz,
@@ -698,8 +696,9 @@ class PrestudentLib
if (isError($personenkennzeichen))
return $personenkennzeichen;
$personenkennzeichen = getData($personenkennzeichen);
$jahr = mb_substr($personenkennzeichen, 0, 2);
// Generate UID
$uid = $this->_ci->StudentModel->generateUID(
$student_data->kurzbz,
+1 -1
View File
@@ -169,7 +169,7 @@ class Student_model extends DB_Model
$max = 0;
if ($matrikelnrres && hasData($matrikelnrres)) {
$max = mb_substr(getData($matrikelnrres)[0]->matrikelnr, 7);
$max = mb_substr(trim(getData($matrikelnrres)[0]->matrikelnr), -3);
if (!is_numeric($max)) {
$max = (int)$max;
}
@@ -135,7 +135,8 @@ class Profil_update_model extends DB_Model
attachment_id,
UPPER(public.tbl_studiengang.typ || public.tbl_studiengang.kurzbz) AS studiengang,
COALESCE(of.orgform_kurzbz, public.tbl_studiengang.orgform_kurzbz) AS orgform,
NULL as oezuordnung
NULL as oezuordnung,
tbl_student.semester
FROM public.tbl_profil_update
JOIN public.tbl_profil_update_status ON public.tbl_profil_update_status.status_kurzbz = public.tbl_profil_update.status
JOIN public.tbl_student ON public.tbl_student.student_uid=public.tbl_profil_update.uid
-8
View File
@@ -447,14 +447,6 @@ if (isset($_POST['save']) && isset($_SESSION['prestudent_id']))
{
e.preventDefault();
});
// If Browser is any other than Mozilla Firefox and the test includes any MathML,
// show message to use Mozilla Firefox
var ua = navigator.userAgent;
if ((ua.indexOf("Firefox") > -1) == false)
{
$("#alertmsgdiv").html("<div class='alert alert-danger'>BITTE VERWENDEN SIE DEN MOZILLA FIREFOX BROWSER!<br>(Manche Prüfungsfragen werden sonst nicht korrekt dargestellt.<br><br>PLEASE USE MOZILLA FIREFOX BROWSER!<br>(Otherwise some exam items will not be displayed correctly</div>");
//alert('BITTE VERWENDEN SIE DEN MOZILLA FIREFOX BROWSER!\n(Manche Prüfungsfragen werden sonst nicht korrekt dargestellt.\n\nPLEASE USE MOZILLA FIREFOX BROWSER!\n(Ohterwise some exam items will not be displayed correctly.)');
}
});
</script>
<?php
-22
View File
@@ -425,28 +425,6 @@ else
e.preventDefault();
});
});
// Get users Browser
var ua = navigator.userAgent;
// If Browser is any other than Mozilla Firefox and the test includes any MathML,
// show message to use Mozilla Firefox
if ((ua.indexOf("Firefox") > -1) == false)
{
let hasMathML = "<?php echo (isset($gebiet_hasMathML)?$gebiet_hasMathML:''); ?>";
let userLang = "<?php echo $sprache_user; ?>";
if (hasMathML == true)
{
if (userLang == 'German')
{
alert('BITTE VERWENDEN SIE DEN MOZILLA FIREFOX BROWSER!\n(Manche Prüfungsfragen werden sonst nicht korrekt dargestellt.)');
}
else if(userLang == 'English')
{
alert('PLEASE USE MOZILLA FIREFOX BROWSER!\n(Ohterwise some exam items will not be displayed correctly.)');
}
}
}
// Error massage if check_gebiet function returns false
$(function() {
var invalid_gebiete = "<?php echo (isset($invalid_gebiete)?$invalid_gebiete:''); ?>";
@@ -46,7 +46,6 @@ export default {
loading: false,
filter: "Pending",
profil_update_id: Number(this.id),
};
},
computed: {
@@ -60,6 +59,10 @@ export default {
},
profilUpdateOptions: function () {
return {
persistence: {
columns: ["width", "visible", "frozen"],
},
persistenceID: 'cis-profilupdate-2025121702',
ajaxURL: 'dummy',
ajaxRequestFunc: (url, config, params) => {
return this.$api.call(ApiProfilUpdate.getProfilUpdateWithPermission(params.filter));
@@ -205,7 +208,7 @@ export default {
//responsive:0,
},
{
title: this.$p.t("lehre", "studiengang") + ' (' + this.$p.t("profil", "studentIn") + ')',
title: this.$p.t("profil", "stg_short") + ' (' + this.$p.t("profil", "studentIn") + ')',
field: "studiengang",
minWidth: 50,
resizable: true,
@@ -213,8 +216,14 @@ export default {
headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"},
//responsive:0,
},
{
title: this.$p.t("lehre", "organisationsform") + ' (' + this.$p.t("profil", "studentIn") + ')',
{
title: this.$p.t("profil", "sem_short") + ' (' + this.$p.t("profil", "studentIn") + ')',
field: "semester",
headerFilter: "list",
headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"}
},
{
title: this.$p.t("profil", "orgform_short") + ' (' + this.$p.t("profil", "studentIn") + ')',
field: "orgform",
minWidth: 50,
resizable: true,
@@ -222,8 +231,8 @@ export default {
headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"},
//responsive:0,
},
{
title: this.$p.t("lehre", "organisationseinheit") + ' (' + this.$p.t("profil", "mitarbeiterIn") + ')',
{
title: this.$p.t("profil", "orgeinheit_short") + ' (' + this.$p.t("profil", "mitarbeiterIn") + ')',
field: "oezuordnung",
minWidth: 200,
resizable: true,
@@ -231,7 +240,7 @@ export default {
headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"},
//responsive:0,
},
{
{
title: this.$p.t("profilUpdate", "Topic"),
field: "topic",
resizable: true,
@@ -240,7 +249,7 @@ export default {
headerFilterParams: {valuesLookup:true, listOnEmpty:true, autocomplete:true, sort:"asc"},
//responsive:0,
},
{
{
title: this.$p.t("profilUpdate", "insertamum"),
field: "insertamum_iso",
resizable: true,
@@ -251,7 +260,7 @@ export default {
formatterParams: this.datetimeFormatterParams(),
//responsive:0,
},
{
{
title: this.$p.t("profilUpdate", "Status"),
field: "status_translated",
hozAlign: "center",
@@ -273,7 +282,6 @@ export default {
}
return `<div class='row justify-content-center'><div class='col-2'><i class='${iconClasses}'></i></div> <div class='col-4'><span>${cell.getValue()}</span></div></div>`;
},
resizable: true,
minWidth: 200,
//responsive:0,
@@ -309,7 +317,6 @@ export default {
],
};
}
},
methods: {
denyProfilUpdate: function (data) {
@@ -351,7 +358,6 @@ export default {
this.showModal = false;
this.modalData = null;
},
showAcceptDenyModal(value) {
this.modalData = value;
if (!this.modalData) {
@@ -364,7 +370,6 @@ export default {
this.$refs.AcceptDenyModal.show();
});
},
updateData: function (event) {
this.$refs.UpdatesTable.tabulator.setData();
//? store the selected view in the session storage of the browser
@@ -415,22 +420,30 @@ export default {
},
template: /*html*/ `
<div>
<accept-deny-update :title="$p.t('profilUpdate','profilUpdateRequest')" v-if="showModal" ref="AcceptDenyModal" @hideBsModal="hideAcceptDenyModal" :value="JSON.parse(JSON.stringify(modalData))" :setLoading="setLoading" ></accept-deny-update>
<div class="form-underline flex-fill ">
<div class="form-underline-titel">{{$p.t('ui','anzeigen')}} </div>
<select class="mb-4 form-select" v-model="filter" @change="updateData" aria-label="Profil updates display selection">
<option :selected="true" :value="profilUpdateStates['Pending']" >{{$p.t('profilUpdate','pendingRequests')}}</option>
<option :value="profilUpdateStates['Accepted']">{{$p.t('profilUpdate','acceptedRequests')}}</option>
<option :value="profilUpdateStates['Rejected']">{{$p.t('profilUpdate','rejectedRequests')}}</option>
<option :value="'Alle'">{{$p.t('profilUpdate','allRequests')}}</option>
</select>
</div>
<loading ref="loadingModalRef" :timeout="0"></loading>
<core-filter-cmpt v-if="profilUpdateStates && categoryLoaded" :title="$p.t('profilUpdate','profilUpdateRequests')" ref="UpdatesTable" :tabulatorEvents="profilUpdateEvents" :tabulator-options="profilUpdateOptions" tableOnly :sideMenu="false" />
<accept-deny-update :title="$p.t('profilUpdate','profilUpdateRequest')" v-if="showModal" ref="AcceptDenyModal" @hideBsModal="hideAcceptDenyModal" :value="JSON.parse(JSON.stringify(modalData))" :setLoading="setLoading" ></accept-deny-update>
<h3>{{$p.t('profilUpdate', 'profilUpdateRequests')}}</h3>
<loading ref="loadingModalRef" :timeout="0"></loading>
</div>`,
<core-filter-cmpt
v-if="profilUpdateStates && categoryLoaded"
ref="UpdatesTable"
:tabulatorEvents="profilUpdateEvents"
:tabulator-options="profilUpdateOptions"
table-only
:sideMenu="false">
<template #actions>
<div style="width: 94vw;" class="d-flex justify-content-end">
<div>
<select class="mb-4 form-select" v-model="filter" @change="updateData" aria-label="Profil updates display selection">
<option :selected="true" :value="profilUpdateStates['Pending']" >{{$p.t('profilUpdate','pendingRequests')}}</option>
<option :value="profilUpdateStates['Accepted']">{{$p.t('profilUpdate','acceptedRequests')}}</option>
<option :value="profilUpdateStates['Rejected']">{{$p.t('profilUpdate','rejectedRequests')}}</option>
<option :value="'Alle'">{{$p.t('profilUpdate','allRequests')}}</option>
</select>
</div>
</div>
</template>
</core-filter-cmpt>
</div>`,
};
+14 -2
View File
@@ -42,7 +42,11 @@ export default {
showErweitert: Boolean,
showDocument: Boolean,
showTinyMce: Boolean,
visibleColumns: Array
visibleColumns: Array,
tabulatorPersistenceId: {
type: String,
default: 'core-notiz'
}
},
data() {
return {
@@ -179,7 +183,15 @@ export default {
//responsiveLayout: "collapse",
maxHeight: '200px',
index: 'notiz_id',
persistenceID: 'core-notiz'
persistenceID: this.tabulatorPersistenceId,
persistence: {
sort: false,
columns: ["width", "visible", "frozen"],
filter: false,
headerFilter: false,
group: false,
page: false,
}
},
tabulatorEvents: [
{
@@ -31,6 +31,7 @@ export default {
show-tiny-mce
:visibleColumns="['titel','text','verfasser','bearbeiter','dokumente']"
@reload="$emit('update:suffix')"
tabulator-persistence-id="stv-notiz-2026011301"
>
</core-notiz>
-1
View File
@@ -1581,7 +1581,6 @@ $filters = array(
}',
'oe_kurzbz' => null,
),
);
// Loop through the filters array
+79
View File
@@ -29216,6 +29216,85 @@ array(
)
)
),
array(
'app' => 'core',
'category' => 'profil',
'phrase' => 'stg_short',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'StG',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'degree Progr',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'profil',
'phrase' => 'orgform_short',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'OrgForm',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'org Form',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'profil',
'phrase' => 'orgeinheit_short',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'OrgEH',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'org Unit',
'description' => '',
'insertvon' => 'system'
)
)
), array(
'app' => 'core',
'category' => 'profil',
'phrase' => 'sem_short',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Sem',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'sem',
'description' => '',
'insertvon' => 'system'
)
)
),
//Profil Phrasen ende
// LvPlan Phrasen start
array(