Merge branch 'feature-60874/FHC4_Studierendenverwaltung_Dokumente' into merge_FHC4_55354_55991_55992_60874_60875_61229_61230_61231

This commit is contained in:
Harald Bamberger
2025-05-21 13:49:58 +02:00
15 changed files with 2547 additions and 1 deletions
@@ -83,6 +83,10 @@ class Config extends FHCAPI_Controller
'title' => 'Status',
'component' => './Stv/Studentenverwaltung/Details/MultiStatus.js'
];
$result['documents'] = [
'title' => $this->p->t('stv', 'tab_dokumente'),
'component' => './Stv/Studentenverwaltung/Details/Dokumente.js'
];
$result['banking'] = [
'title' => $this->p->t('stv', 'tab_banking'),
'component' => './Stv/Studentenverwaltung/Details/Konto.js',
@@ -0,0 +1,553 @@
<?php
if (! defined('BASEPATH')) exit('No direct script access allowed');
use \DateTime as DateTime;
class Dokumente extends FHCAPI_Controller
{
public function __construct()
{
parent::__construct([
'getDocumentsUnaccepted' => ['admin:r', 'assistenz:r'],
'getDocumentsAccepted' => ['admin:r', 'assistenz:r'],
'deleteZuordnung' => ['admin:rw', 'assistenz:rw'],
'createZuordnung' => ['admin:rw', 'assistenz:rw'],
'loadAkte' => ['admin:rw', 'assistenz:rw'],
'deleteAkte' => ['admin:rw', 'assistenz:rw'],
'updateAkte' => ['admin:rw', 'assistenz:rw'],
'getDoktypen' => ['admin:r', 'assistenz:r'],
'uploadDokument' => ['admin:rw', 'assistenz:rw'],
'download' => ['admin:rw', 'assistenz:rw'],
]);
// Load Libraries
$this->load->library('VariableLib', ['uid' => getAuthUID()]);
$this->load->library('form_validation');
// Load language phrases
$this->loadPhrases([
'ui',
'dokumente'
]);
// Load models
$this->load->model('crm/Akte_model', 'AkteModel');
$this->load->model('crm/Dokument_model', 'DokumentModel');
$this->load->model('crm/Dokumentprestudent_model', 'DokumentprestudentModel');
//TODO(Manu) check additional Berechtigungen
//TODO(Manu) check if using dokument lib instead of dokument model?
}
public function getDocumentsUnaccepted($prestudent_id, $studiengang_kz)
{
if(!$prestudent_id)
$this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL);
if (!is_numeric($prestudent_id))
$this->terminateWithError($this->p->t('ui', 'error_valueNotNumeric', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL);
if(!$studiengang_kz)
$this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Studiengang_kz']), self::ERROR_TYPE_GENERAL);
$person_id = $this->_getPersonId($prestudent_id);
$result = $this->DokumentModel->getUnacceptedDocuments($prestudent_id, $person_id);
$dataAkteUnaccepted = $this->getDataOrTerminateWithError($result);
$resultMd = $this->_getMissingDocuments($studiengang_kz, $prestudent_id);
$data = $this->_mergeDocuments($dataAkteUnaccepted, $resultMd);
$this->terminateWithSuccess($data);
}
public function getDocumentsAccepted($prestudent_id, $studiengang_kz)
{
if(!$prestudent_id)
$this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL);
if (!is_numeric($prestudent_id))
$this->terminateWithError($this->p->t('ui', 'error_valueNotNumeric', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL);
if(!$studiengang_kz)
$this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Studiengang_kz']), self::ERROR_TYPE_GENERAL);
$resultPreDoc = $this->_getPrestudentDokumente($prestudent_id);
$arrayAccepted = [];
$person_id = $this->_getPersonId($prestudent_id);
$docNames = array_map(function ($item) {
return $item->dokument_kurzbz;
}, $resultPreDoc);
foreach($docNames as $doc)
{
$result = $this->AkteModel->getAktenFAS($person_id, $doc, $studiengang_kz, $prestudent_id, true);
if (isError($result))
{
return $this->terminateWithError($result, self::ERROR_TYPE_GENERAL);
}
if (hasData($result))
{
$data = getData($result);
array_push($arrayAccepted, current($data));
}
}
//Merge with Data of Akte
$newDataMap = [];
//helper, lookupArray
foreach ($arrayAccepted as $item) {
$newDataMap[$item->dokument_kurzbz] = $item;
}
//add Data of Akte to PrestudentData
foreach ($resultPreDoc as $obj) {
if (isset($newDataMap[$obj->dokument_kurzbz])) {
$obj->akte_id = $newDataMap[$obj->dokument_kurzbz]->akte_id;
$obj->hochgeladenamum = $newDataMap[$obj->dokument_kurzbz]->hochgeladenamum;
$obj->titel_intern = $newDataMap[$obj->dokument_kurzbz]->titel_intern;
$obj->nachgereicht = $newDataMap[$obj->dokument_kurzbz]->nachgereicht;
$obj->akzeptiertamum = $newDataMap[$obj->dokument_kurzbz]->akzeptiertamum;
$obj->dms_id = $newDataMap[$obj->dokument_kurzbz]->dms_id;
$obj->infotext = $newDataMap[$obj->dokument_kurzbz]->infotext;
$obj->anmerkung_intern = $newDataMap[$obj->dokument_kurzbz]->anmerkung_intern;
$obj->nachgereicht_am = $newDataMap[$obj->dokument_kurzbz]->nachgereicht_am;
$obj->vorhanden = $newDataMap[$obj->dokument_kurzbz]->vorhanden;
}
}
$this->terminateWithSuccess($resultPreDoc);
}
public function deleteZuordnung($prestudent_id, $dokument_kurzbz)
{
if(!$prestudent_id)
$this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL);
if (!is_numeric($prestudent_id))
$this->terminateWithError($this->p->t('ui', 'error_valueNotNumeric', ['value' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL);
if(!$dokument_kurzbz)
$this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Dokument_kurzbz']), self::ERROR_TYPE_GENERAL);
$result = $this->DokumentprestudentModel->delete(
[
'prestudent_id' => $prestudent_id,
'dokument_kurzbz' => $dokument_kurzbz
]
);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function loadAkte($akte_id)
{
if (!$akte_id)
$this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Akte ID']), self::ERROR_TYPE_GENERAL);
$this->AkteModel->addSelect('public.tbl_akte.*');
$this->AkteModel->addSelect("CONCAT(public.tbl_person.vorname, ' ' , public.tbl_person.nachname) AS namePerson");
$this->AkteModel->addJoin('public.tbl_person', 'person_id');
$result = $this->AkteModel->loadWhere(
[
'akte_id' => $akte_id,
]
);
$data = $this->getDataOrTerminateWithError($result);
$data = current($data);
$this->terminateWithSuccess($data);
}
public function updateAkte()
{
$this->form_validation->set_rules('akte_id', 'Akte ID', 'required', [
'required' => $this->p->t('dokumente', 'err_updateNotAllowed')
]);
$this->form_validation->set_rules('dokument_kurzbz', 'Dokumenttyp', 'required', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Dokumenttyp'])
]);
$this->form_validation->set_rules('nachreichung_am', 'Nachreichung am', 'is_valid_date', [
'is_valid_date' => $this->p->t('ui', 'error_notValidDate', ['field' => 'Nachreichung am'])
]);
if ($this->form_validation->run() == false)
{
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
$uid = getAuthUID();
$result = $this->AkteModel->update(
[
'akte_id' => $this->input->post('akte_id'),
],
[
'dokument_kurzbz' => $this->input->post('dokument_kurzbz'),
'anmerkung_intern' => $this->input->post('anmerkung_intern'),
'titel_intern' => $this->input->post('titel_intern'),
'nachgereicht_am' => $this->input->post('nachgereicht_am'),
'updateamum' => date('c'),
'updatevon' => $uid,
]
);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess(current($data));
}
public function createZuordnung($prestudent_id, $dokument_kurzbz)
{
if (!$prestudent_id)
$this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Prestudent ID']), self::ERROR_TYPE_GENERAL);
if(!$dokument_kurzbz)
$this->terminateWithError($this->p->t('ui', 'errorMissingValue', ['value' => 'Dokument_kurzbz']), self::ERROR_TYPE_GENERAL);
$uid = getAuthUid();
$result = $this->DokumentprestudentModel->insert(
[
'prestudent_id' => $prestudent_id,
'dokument_kurzbz' => $dokument_kurzbz,
'mitarbeiter_uid' => $uid,
'datum' => date('c'),
'insertamum' => date('c'),
'insertvon' => $uid,
]
);
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function deleteAkte($akte_id)
{
if (!$akte_id)
$this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Akte ID']), self::ERROR_TYPE_GENERAL);
$result = $this->AkteModel->load($akte_id);
$dataAkte = $this->getDataOrTerminateWithError($result);
$logdata_akte = var_export($dataAkte, true);
$dms_id = current($dataAkte)->dms_id;
$nachgereicht = current($dataAkte)->nachgereicht;
$inhalt = current($dataAkte)->inhalt;
$inhaltVorhanden = $inhalt != '';
$uid = getAuthUid();
$this->db->trans_start();
if($dms_id)
{
$this->load->model('content/Dms_model', 'DmsModel');
$result = $this->DmsModel->load($dms_id);
$data = $this->getDataOrTerminateWithError($result);
$logdata_dms = (array)$data;
$logdata_dms = "Logdata: " . var_export($logdata_dms, true);
//delete from dmsLib
$this->load->library('DmsLib');
$person_id = current($dataAkte)->person_id;
$result = $this->dmslib->delete($person_id, $dms_id);
$this->getDataOrTerminateWithError($result);
//LOGGING Dms ID
$this->load->model('system/Log_model', 'LogModel');
$result = $this->LogModel->insert([
'executetime' => date('c'),
'mitarbeiter_uid' => $uid,
'beschreibung' => "Löschen der DMS_ID ". $dms_id,
'sql' => $logdata_dms
]);
$this->getDataOrTerminateWithError($result);
//delete akte
$result = $this->AkteModel->delete(
[
'akte_id' => $akte_id
]
);
$data = $this->getDataOrTerminateWithError($result);
//Logging Deletion Akte
$result = $this->LogModel->insert([
'executetime' => date('c'),
'mitarbeiter_uid' => $uid,
'beschreibung' => "Löschen der Akte ". $akte_id,
'sql' => "DELETE FROM public.tbl_akte WHERE akte_id=" .$akte_id. " LogData: ". $logdata_akte
]);
$this->getDataOrTerminateWithError($result);
$this->db->trans_complete();
$this->terminateWithSuccess($data);
}
elseif (!!$dms_id || ($nachgereicht && !$inhaltVorhanden))
{
$result = $this->AkteModel->delete(
[
'akte_id' => $akte_id
]
);
$data = $this->getDataOrTerminateWithError($result);
$result = $this->LogModel->insert([
'executetime' => date('c'),
'mitarbeiter_uid' => $uid,
'beschreibung' => "Löschen der Akte ". $akte_id,
'sql' => "DELETE FROM public.tbl_akte WHERE akte_id=" .$akte_id. " LogData: ". $logdata_akte
]);
$this->getDataOrTerminateWithError($result);
$this->db->trans_complete();
$this->terminateWithSuccess($data);
}
else
$this->terminateWithError($this->p->t('dokumente', 'err_deleteDokHere'), self::ERROR_TYPE_GENERAL);
}
public function uploadDokument()
{
$this->load->library('DmsLib');
$prestudent_id = $this->input->post('prestudent_id');
$anmerkung_intern = $this->input->post('anmerkung_intern');
$titel_intern = $this->input->post('titel_intern');
$dokument_kurzbz = $this->input->post('dokument_kurzbz');
$this->form_validation->set_rules('prestudent_id', 'Prestudent_id', 'required', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Prestudent ID'])
]);
$this->form_validation->set_rules('dokument_kurzbz', 'Dokumenttyp', 'required', [
'required' => $this->p->t('ui', 'error_fieldRequired', ['field' => 'Dokumenttyp'])
]);
//validation if attachment was added
$this->form_validation->set_rules('anhang', 'Attachment', 'callback_file_check');
if ($this->form_validation->run() == false)
{
$this->terminateWithValidationErrors($this->form_validation->error_array());
}
$this->db->trans_start();
$uid = getAuthUID();
$dms = array(
'kategorie_kurzbz' => 'Akte',
'version' => 0,
'name' => $_FILES['anhang']['name'],
'mimetype' => $_FILES['anhang']['type'],
'insertamum' => date('c'),
'insertvon' => $uid
);
$result = $this->dmslib->upload($dms, 'anhang', array("jpg", "png", "pdf"));
if (isError($result))
{
return $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL);
}
$dms_id = $result->retval['dms_id'];
$person_id = $this->_getPersonId($prestudent_id);
$result = $this->DokumentModel->load($dokument_kurzbz);
$data = $this->getDataOrTerminateWithError($result);
$bezeichnung = current($data)->bezeichnung;
//save entry in akte
if($dms_id)
{
$result = $this->AkteModel->insert([
'person_id' => $person_id,
'dms_id' => $dms_id,
'dokument_kurzbz' => $dokument_kurzbz,
'mimetype' => $_FILES['anhang']['type'],
'insertamum' => date('c'),
'erstelltam' => date('c'),
'insertvon' => $uid,
'anmerkung_intern' => $anmerkung_intern,
'titel_intern' => $titel_intern,
'bezeichnung' => $bezeichnung,
'titel' => $_FILES['anhang']['name']
]);
$data = $this->getDataOrTerminateWithError($result);
$this->db->trans_complete();
$this->terminateWithSuccess($data);
}
$this->db->trans_complete();
$this->terminateWithSuccess($data);
}
public function getDoktypen()
{
$this->DokumentModel->addSelect('dokument_kurzbz');
$this->DokumentModel->addSelect('bezeichnung');
$this->DokumentModel->addOrder('dokument_kurzbz', 'ASC');
$result = $this->DokumentModel->load();
$data = $this->getDataOrTerminateWithError($result);
$this->terminateWithSuccess($data);
}
public function download()
{
//TODO(Manu) check filetype, Decoding
$akte_id = $this->input->get('akte_id');
if(!$akte_id)
$this->terminateWithError($this->p->t('ui', 'error_missingId', ['id' => 'Akte ID']), self::ERROR_TYPE_GENERAL);
if (!is_numeric($akte_id))
$this->terminateWithError($this->p->t('ui', 'error_valueNotNumeric', ['value' => 'Akte ID']), self::ERROR_TYPE_GENERAL);
$result = $this->AkteModel->load($akte_id);
if (!hasData($result)) $this->terminateWithError('Akte not found');
$data = getData($result)[0];
header('Content-Description: File Transfer');
header('Content-Type: '. $data->mimetype);
header('Content-Disposition: attachment; filename="'.$data->titel.'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
if (isset($data->inhalt) && !empty($data->inhalt)) {
$decodedContent = base64_decode($data->inhalt, true);
if ($decodedContent === false) {
die('Error: Base64-Dekodierung failed.');
}
echo $decodedContent;
}
die();
}
private function _getMissingDocuments($studiengang_kz, $prestudent_id)
{
$result = $this->DokumentModel->getMissingDocuments($studiengang_kz, $prestudent_id);
$data = $this->getDataOrTerminateWithError($result);
return $data;
}
private function _getUnacceptedDocuments($prestudent_id)
{
$person_id = $this->_getPersonId($prestudent_id);
$result = $this->DokumentModel->getUnacceptedDocuments($prestudent_id, $person_id);
$data = $this->getDataOrTerminateWithError($result);
return $data;
}
/**
* helper function for merging objects
* sorts object after merging according to dokument_kurzbz
* @param $original object of documents of akte
* @param object $toMerge documents to merge (of dokumentprestudent, dokumentstudiengang)
* @return Array mergedObject
*/
private function _mergeDocuments($original, $toMerge)
{
$existingKurzbez = [];
foreach ($original as $doc) {
$existingKurzbez[$doc->dokument_kurzbz] = true;
}
foreach ($toMerge as $doc) {
if (!isset($existingKurzbez[$doc->dokument_kurzbz])) {
$original[] = $doc;
$existingKurzbez[$doc->dokument_kurzbz] = true;
}
else
{
foreach($original as $docOriginal)
{
if ($docOriginal->dokument_kurzbz == $doc->dokument_kurzbz)
{
$docOriginal->pflicht = $doc->pflicht;
$docOriginal->onlinebewerbung = $doc->onlinebewerbung;
}
}
}
}
usort($original, function ($a, $b) {
return strcmp($a->dokument_kurzbz, $b->dokument_kurzbz);
});
return $original;
}
private function _getDocumentsOfAkte($person_id)
{
$result = $this->AkteModel->getAktenFAS($person_id);
$data = $this->getDataOrTerminateWithError($result);
return $data;
}
private function _getPrestudentDokumente($prestudent_id)
{
$result = $this->DokumentprestudentModel->getPrestudentDokumente($prestudent_id);
$data = $this->getDataOrTerminateWithError($result);
return $data;
}
private function _getPersonId($prestudent_id)
{
$this->load->model('crm/Prestudent_model', 'PrestudentModel');
$result = $this->PrestudentModel->loadWhere(
['prestudent_id' => $prestudent_id]
);
$data = $this->getDataOrTerminateWithError($result);
$person = current($data);
return $person->person_id;
}
public function file_check($str)
{
if (isset($_FILES['anhang']) && $_FILES['anhang']['size'] > 0)
{
$allowed_mime_types = ['image/jpeg', 'image/png', 'application/pdf'];
$mime = mime_content_type($_FILES['anhang']['tmp_name']);
if (in_array($mime, $allowed_mime_types))
{
return true;
} else
{
$this->form_validation->set_message('file_check', $this->p->t('dokumente', 'error_fileType'));
return false;
}
}
else
{
$this->form_validation->set_message('file_check', $this->p->t('dokumente', 'error_fileMissing'));
return false;
}
}
}
+56 -1
View File
@@ -92,7 +92,7 @@ class Akte_model extends DB_Model
a.anmerkung,
a.nachgereicht,
a.nachgereicht_am,
CASE WHEN MAX(dp.dokument_kurzbz) IS NOT NULL THEN TRUE ELSE FALSE END AS accepted
CASE WHEN MAX(dp.dokument_kurzbz) IS NOT NULL THEN TRUE ELSE FALSE END AS accepted,
FROM public.tbl_akte a
INNER JOIN public.tbl_prestudent p USING(person_id)
LEFT JOIN public.tbl_dokumentprestudent dp USING(prestudent_id, dokument_kurzbz)
@@ -111,6 +111,61 @@ class Akte_model extends DB_Model
return $this->execQuery($query, $parametersArray);
}
/**
* getAktenAccepted FAS
*/
public function getAktenFAS($person_id, $dokument_kurzbz = null, $stg_kz = null, $prestudent_id = null, $returnInhalt = false)
{
$query = 'SELECT
a.akte_id,
a.bezeichnung,
a.dokument_kurzbz,
a.titel_intern,
a.anmerkung_intern,
a.insertamum as hochgeladenamum,
a.updatevon, a.insertvon, a.uid,
a.dms_id, a.anmerkung as infotext,
a.nachgereicht,
CASE
WHEN inhalt IS NOT NULL OR a.dms_id IS NOT NULL
THEN true
ELSE false
END AS vorhanden,
a.nachgereicht_am,
ausstellungsnation, formal_geprueft_amum, archiv,
signiert, stud_selfservice, akzeptiertamum, inhalt
FROM public.tbl_akte a
WHERE a.person_id = ?';
$parametersArray = array($person_id);
if (!isEmptyString($dokument_kurzbz))
{
$query .= " AND dokument_kurzbz = ?
AND dokument_kurzbz NOT IN ('Zeugnis','DiplSupp','Bescheid')";
array_push($parametersArray, $dokument_kurzbz);
}
if($stg_kz != null && $prestudent_id != null)
{
$query.= " AND dokument_kurzbz not in (
SELECT dokument_kurzbz
FROM public.tbl_dokument
JOIN public.tbl_dokumentstudiengang USING(dokument_kurzbz)
WHERE studiengang_kz= ?
AND dokument_kurzbz NOT IN(
SELECT dokument_kurzbz FROM public.tbl_dokumentprestudent
JOIN public.tbl_dokument USING(dokument_kurzbz)
WHERE prestudent_id=?))";
array_push($parametersArray, $stg_kz);
array_push($parametersArray, $prestudent_id);
}
$query .= ' ORDER BY erstelltam';
return $this->execQuery($query, $parametersArray);
}
/**
* getAktenAcceptedDms
*/
+87
View File
@@ -11,4 +11,91 @@ class Dokument_model extends DB_Model
$this->dbTable = 'public.tbl_dokument';
$this->pk = 'dokument_kurzbz';
}
/**
* Loads all missing Documents of a Studiengang
* a Prestudent has not submitted
* @param integer studiengang_kz
* @param integer prestudent_id
* @param boolean archivdokumente
* Default: true.
* If false, documents that are archivable (tbl_vorlage.archivierbar e.g. certificate, notice, ...) not retrieved
* @return Array of Documents || error
*/
public function getMissingDocuments($studiengang_kz, $prestudent_id = null, $archivdokumente = false, $person_id = null)
{
$parametersArray = array($studiengang_kz);
$qry = "SELECT
tbl_dokument.* ,
tbl_dokumentstudiengang.*
FROM public.tbl_dokument
JOIN public.tbl_dokumentstudiengang USING(dokument_kurzbz)
LEFT JOIN public.tbl_vorlage ON (tbl_dokument.dokument_kurzbz = tbl_vorlage.vorlage_kurzbz)
WHERE studiengang_kz = ? ";
if($prestudent_id)
{
array_push($parametersArray, $prestudent_id);
$qry.=" AND tbl_dokument.dokument_kurzbz NOT IN (
SELECT dokument_kurzbz FROM public.tbl_dokumentprestudent WHERE prestudent_id= ?)";
}
if(!$archivdokumente)
{
$qry.=" AND (tbl_vorlage.archivierbar = FALSE OR tbl_vorlage.archivierbar IS NULL)";
}
$qry.=" ORDER BY tbl_dokument.dokument_kurzbz;";
return $this->execQuery($qry, $parametersArray);
}
public function getUnacceptedDocuments($prestudent_id, $person_id)
{
$parametersArray = array($person_id, $prestudent_id);
$qry = " SELECT
a.akte_id,
a.bezeichnung,
a.dokument_kurzbz,
a.titel_intern,
a.anmerkung_intern,
a.insertamum as hochgeladenamum,
a.updatevon,
a.insertvon,
a.uid,
a.dms_id,
a.anmerkung as infotext,
a.nachgereicht,
CASE
WHEN inhalt IS NOT NULL
OR a.dms_id IS NOT NULL THEN true
ELSE false
END AS vorhanden,
a.nachgereicht_am,
ausstellungsnation,
formal_geprueft_amum,
archiv,
signiert,
stud_selfservice,
akzeptiertamum,
inhalt
FROM
public.tbl_akte a
WHERE
a.person_id = ?
AND a.dokument_kurzbz NOT IN (
SELECT
dokument_kurzbz
FROM
public.tbl_dokumentprestudent
WHERE
prestudent_id = ?
)
AND a.dokument_kurzbz NOT IN ('Zeugnis','DiplSupp','Bescheid')
ORDER BY a.dokument_kurzbz;";
return $this->execQuery($qry, $parametersArray);
}
}
@@ -69,4 +69,39 @@ class Dokumentprestudent_model extends DB_Model
return $result;
}
/**
* Loads all Documents of Prestudent, already submitted
* @param integer prestudent_id
* @param boolean archivdokumente Default true. if false, archivable Documents (tbl_vorlage.archivierbar zB Zeugnis, Bescheid, ...) not retrieved
* @return Array of Documents || error
*/
public function getPrestudentDokumente($prestudent_id, $archivdokumente = true)
{
$parametersArray = array($prestudent_id);
$qry = "SELECT
d.bezeichnung,
d.dokument_kurzbz,
dp.datum as Docdatum,
dp.mitarbeiter_uid as DocMitarbeiter_uid,
dp.insertamum as Docinsertamum,
dp.prestudent_id,
CONCAT(p.vorname, ' ', p.nachname) as insertvonma
FROM
public.tbl_dokumentprestudent dp
JOIN public.tbl_dokument d USING(dokument_kurzbz)
LEFT JOIN public.tbl_vorlage v ON (d.dokument_kurzbz = v.vorlage_kurzbz)
LEFT JOIN public.tbl_benutzer bn ON (bn.uid = dp.mitarbeiter_uid)
LEFT JOIN public.tbl_person p ON (p.person_id = bn.person_id)
WHERE
prestudent_id = ?";
if(!$archivdokumente)
{
$qry.=" AND (v.archivierbar = FALSE OR v.archivierbar IS NULL)";
}
return $this->execQuery($qry, $parametersArray);
}
}
+76
View File
@@ -0,0 +1,76 @@
/**
* Copyright (C) 2025 fhcomplete.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
export default {
getDocumentsUnaccepted(params) {
return {
method: 'get',
url: 'api/frontend/v1/stv/dokumente/getDocumentsUnaccepted/' + params.id + '/' + params.studiengang_kz
};
},
getDocumentsAccepted(params) {
return {
method: 'get',
url: 'api/frontend/v1/stv/dokumente/getDocumentsAccepted/' + params.id + '/' + params.studiengang_kz
};
},
deleteZuordnung(params){
return {
method: 'post',
url: 'api/frontend/v1/stv/dokumente/deleteZuordnung/' + params.prestudent_id + '/' + params.dokument_kurzbz
};
},
createZuordnung(params){
return {
method: 'post',
url: 'api/frontend/v1/stv/dokumente/createZuordnung/' + params.prestudent_id + '/' + params.dokument_kurzbz
};
},
loadAkte(akte_id){
return {
method: 'get',
url: 'api/frontend/v1/stv/dokumente/loadAkte/' + akte_id
};
},
getDoktypen(){
return {
method: 'get',
url: 'api/frontend/v1/stv/dokumente/getDoktypen/'
};
},
updateFile(akte_id, params){
return {
method: 'post',
url: 'api/frontend/v1/stv/dokumente/updateAkte/' + akte_id,
params
};
},
deleteFile(akte_id){
console.log("in deleteFile " + akte_id);
return {
method: 'post',
url: 'api/frontend/v1/stv/dokumente/deleteAkte/' + akte_id,
};
},
uploadFile(prestudent_id, params){
return {
method: 'post',
url: 'api/frontend/v1/stv/dokumente/uploadDokument/' + prestudent_id,
params
};
},
}
+2
View File
@@ -12,6 +12,7 @@ import abschlusspruefung from './stv/abschlusspruefung.js';
import grades from './stv/grades.js';
import mobility from './stv/mobility.js';
import archiv from './stv/archiv.js';
import documents from './stv/documents.js';
export default {
verband,
@@ -28,6 +29,7 @@ export default {
grades,
mobility,
archiv,
documents,
configStudent() {
return this.$fhcApi.get('api/frontend/v1/stv/config/student');
},
+33
View File
@@ -0,0 +1,33 @@
export default {
getDocumentsUnaccepted(url, config, params) {
return this.$fhcApi.get('api/frontend/v1/stv/dokumente/getDocumentsUnaccepted/' + params.id + '/' + params.studiengang_kz);
},
getDocumentsAccepted(url, config, params) {
return this.$fhcApi.get('api/frontend/v1/stv/dokumente/getDocumentsAccepted/' + params.id + '/' + params.studiengang_kz);
},
deleteZuordnung(params){
return this.$fhcApi.post('api/frontend/v1/stv/dokumente/deleteZuordnung/' + params.prestudent_id + '/' + params.dokument_kurzbz);
},
createZuordnung(params){
return this.$fhcApi.post('api/frontend/v1/stv/dokumente/createZuordnung/'
+ params.prestudent_id + '/'
+ params.dokument_kurzbz);
},
loadAkte(akte_id){
return this.$fhcApi.get('api/frontend/v1/stv/dokumente/loadAkte/' + akte_id);
},
getDoktypen(){
return this.$fhcApi.get('api/frontend/v1/stv/dokumente/getDoktypen/');
},
updateFile(akte_id, data){
return this.$fhcApi.post('api/frontend/v1/stv/dokumente/updateAkte/' + akte_id,
data);
},
deleteFile(akte_id){
return this.$fhcApi.post('api/frontend/v1/stv/dokumente/deleteAkte/' + akte_id);
},
uploadFile(prestudent_id, data){
return this.$fhcApi.post('api/frontend/v1/stv/dokumente/uploadDokument/' + prestudent_id,
data);
},
}
@@ -0,0 +1,18 @@
import ViewDocuments from "./Dokumente/Dokumente.js";
export default {
name:"TabDocuments",
components: {
ViewDocuments
},
props: {
modelValue: Object,
},
data(){
return {}
},
template: `
<div class="stv-details-documents h-100 d-flex flex-column">
<view-documents ref="vw_documents" :student="modelValue"></view-documents>
</div>`
};
@@ -0,0 +1,51 @@
import DocumentsUnaccepted from './List/Unaccepted.js';
import DocumentsAccepted from './List/Accepted.js';
export default {
components: {
DocumentsUnaccepted,
DocumentsAccepted
},
props: {
student: Object
},
data(){
return {
listMissingDocuments: []
}
},
methods: {
reloadUnaccepted(){
this.$refs.tableUnaccepted.reload();
},
reloadAccepted(){
this.$refs.tableAccepted.reload();
},
},
template: `
<div class="stv-details-documents h-100 pb-3">
<div class="row mb-3">
<div class="col-6">
<documents-unaccepted
ref="tableUnaccepted"
:prestudent_id="student.prestudent_id"
:studiengang_kz="student.studiengang_kz"
@reloadAccepted="reloadAccepted"
></documents-unaccepted>
</div>
<div class="col-6">
<documents-accepted
ref="tableAccepted"
:prestudent_id="student.prestudent_id"
:studiengang_kz="student.studiengang_kz"
@reloadUnaccepted="reloadUnaccepted"
></documents-accepted>
</div>
</div>
</div>
`
}
@@ -0,0 +1,335 @@
import {CoreFilterCmpt} from "../../../../../filter/Filter.js";
import ModalEdit from "../Modal/Edit.js";
import ModalUpload from "../Modal/Upload.js";
import ApiStvDocuments from "../../../../../../api/factory/stv/documents.js";
export default {
components: {
name: "AcceptedDocuments",
CoreFilterCmpt,
ModalEdit,
ModalUpload
},
props: {
prestudent_id: Number,
studiengang_kz: Number
},
data(){
return {
tabulatorOptions: {
ajaxURL: 'dummy',
ajaxRequestFunc: () => this.$api.call(
ApiStvDocuments.getDocumentsAccepted({
id: this.prestudent_id,
studiengang_kz: this.studiengang_kz})
),
ajaxResponse: (url, params, response) => {
return response.data;
},
columns: [
{title: "Dokument", field: "bezeichnung"},
{title: "Akzeptiertdatum", field: "docdatum",
formatter: function (cell) {
const dateStr = cell.getValue();
if (!dateStr) return "";
const date = new Date(dateStr);
return date.toLocaleString("de-DE", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour12: false
});
}},
{title: "Akzeptiertvon", field: "insertvonma"},
{
title: "UploadDatum", field: "hochgeladenamum",
formatter: function (cell) {
const dateStr = cell.getValue();
if (!dateStr) return "";
const date = new Date(dateStr);
return date.toLocaleString("de-DE", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour12: false
});
}},
{title: "Kurzbz", field: "dokument_kurzbz", visible: false},
{title: "Prestudent ID", field: "prestudent_id", visible: false},
{title: "nachgereicht", field: "nachgereicht", visible: false,
formatter:"tickCross",
hozAlign:"center",
formatterParams: {
tickElement: '<i class="fa fa-check text-secondary"></i>',
crossElement: '<i class="fa fa-xmark text-secondary"></i>'
}},
{title: "infotext", field: "infotext"},
{title: "akte_id", field: "akte_id"},
{title: "dms_id", field: "dms_id", visible: false},
{title: "titel", field: "titel_intern"},
{title: "vorhanden", field: "vorhanden",
formatter:"tickCross",
hozAlign:"center",
formatterParams: {
tickElement: '<i class="fa fa-check text-success"></i>',
crossElement: '<i class="fa fa-xmark text-danger"></i>'
}},
{title: "Anmerkung_intern", field: "anmerkung_intern", visible: false},
{title: "Nachreichung am", field: "nachgereicht_am",
formatter: function (cell) {
const dateStr = cell.getValue();
if (!dateStr) return "";
const date = new Date(dateStr);
return date.toLocaleString("de-DE", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour12: false
});
}},
{
title: 'Aktionen', field: 'actions',
minWidth: 50,
maxWidth: 100,
formatter: (cell, formatterParams, onRendered) => {
let container = document.createElement('div');
container.className = "d-flex gap-2";
if(cell.getData().vorhanden){
let button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-download"></i>';
button.title = this.$p.t('ui', 'downloadDok');
button.addEventListener('click', (event) =>
this.actionDownloadFile(cell.getData().akte_id)
);
container.append(button);
button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-edit"></i>';
button.title = this.$p.t('ui', 'editDokument');
button.addEventListener('click', (event) =>
this.actionEditDocument(cell.getData().akte_id)
);
container.append(button);
button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-xmark"></i>';
button.title = this.$p.t('ui', 'deleteDokument');
button.addEventListener('click', () =>
this.actionDeleteFile(cell.getData().akte_id)
);
container.append(button);
}
else
{
let button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-upload"></i>';
button.title = this.$p.t('ui', 'uploadDokument');
button.addEventListener('click', () =>
this.actionUploadFile(cell.getData().dokument_kurzbz)
);
container.append(button);
}
return container;
},
frozen: true
},
],
layout: 'fitColumns',
layoutColumnsOnNewData: false,
height: 300,
selectable: true,
selectableRangeMode: 'click',
persistenceID: 'core-details-documents-accepted',
listDocuments: [],
},
tabulatorEvents: [
{
event: 'tableBuilt',
handler: async () => {
await this.$p.loadCategory(['global', 'dokumente', 'ui', 'mobility', 'ampeln']);
let cm = this.$refs.table.tabulator.columnManager;
cm.getColumnByField('bezeichnung').component.updateDefinition({
title: this.$p.t('global', 'dokument')
});
cm.getColumnByField('docdatum').component.updateDefinition({
title: this.$p.t('dokumente', 'datumAkzeptiert')
});
cm.getColumnByField('dokument_kurzbz').component.updateDefinition({
title: this.$p.t('mobility', 'kurzbz')
});
cm.getColumnByField('insertvonma').component.updateDefinition({
title: this.$p.t('global', 'uploaddatum')
});
cm.getColumnByField('hochgeladenamum').component.updateDefinition({
title: this.$p.t('global', 'uploaddatum')
});
cm.getColumnByField('nachgereicht').component.updateDefinition({
title: this.$p.t('dokumente', 'nachgereicht')
});
cm.getColumnByField('vorhanden').component.updateDefinition({
title: this.$p.t('dokumente', 'vorhanden')
});
cm.getColumnByField('dms_id').component.updateDefinition({
title: this.$p.t('global', 'dms_id')
});
cm.getColumnByField('titel_intern').component.updateDefinition({
title: this.$p.t('global', 'titel')
});
cm.getColumnByField('anmerkung_intern').component.updateDefinition({
title: this.$p.t('global', 'anmerkung')
});
cm.getColumnByField('akte_id').component.updateDefinition({
title: this.$p.t('global', 'akte_id')
});
cm.getColumnByField('nachgereicht_am').component.updateDefinition({
title: this.$p.t('global', 'dokument')
});
}
}
]
}
},
computed: {
tabulatorEvents() {
const events = [
{
event: "rowDblClick",
handler: (e, row) => {
this.actionDownloadFile(row.getData().akte_id);
}
}
];
return events;
}
},
methods: {
actionDownloadFile(akte_id){
window.open(
FHC_JS_DATA_STORAGE_OBJECT.app_root
+ FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/api/frontend/v1/stv/dokumente/download?akte_id=' + encodeURIComponent(akte_id),
'_blank'
);
},
actionUploadFile(dokument_kurzbz){
this.$refs.modalUpload.open(this.prestudent_id, dokument_kurzbz);
},
actionEditDocument(akte_id){
this.$refs.modalEdit.open(akte_id);
},
actionDeleteFile(akte_id){
this.$fhcAlert
.confirmDelete()
.then(result => result
? akte_id
: Promise.reject({handled: true}))
.then(this.deleteFile)
.catch(this.$fhcAlert.handleSystemError);
},
deleteFile(akte_id){
return this.$api
.call(ApiStvDocuments.deleteFile(akte_id))
.then(response => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'));
})
.catch(this.$fhcAlert.handleSystemError)
.finally(()=> {
this.reload();
});
},
deleteZuordnung(selected) {
Promise.allSettled(
selected.map(e =>
this.$api
.call(ApiStvDocuments.deleteZuordnung({
prestudent_id: this.prestudent_id,
dokument_kurzbz: e.dokument_kurzbz
}))
.then(() => ({
success: true,
dokument_bz: e.bezeichnung
}))
.catch(() => ({
success: false,
dokument_bz: e.bezeichnung
}))
)
).then(results => {
const failed = results.filter(res => !res.value.success);
const suceeded = results.filter(res => res.value.success);
if (failed.length > 0) {
failed.forEach(res => {
this.$fhcAlert.alertError(this.$p.t('dokumente', 'errorUnaccepted',
{'dokument_kurzbz': res.value.dokument_bz}
));
});
let countSuceeded = suceeded.length;
if(countSuceeded > 0)
this.$fhcAlert.alertSuccess(this.$p.t('dokumente', 'successCountUnaccepted',
{'count': countSuceeded}));
} else {
this.$fhcAlert.alertSuccess(this.$p.t('dokumente', 'successUnaccepted'));
}
this.reloadAll();
});
},
reload(){
this.$refs.table.reloadTable();
},
reloadAll(){
this.reload();
this.$emit('reloadUnaccepted');
}
},
template: `
<div class="stv-details-documents h-100 pb-3">
<h5>{{$p.t('dokumente', 'accepted')}}</h5>
<modal-edit
ref="modalEdit"
@reload="reloadAll"
>
</modal-edit>
<modal-upload
ref="modalUpload"
@reload="reloadAll"
>
</modal-upload>
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
table-only
:side-menu="false"
reload
>
<template #actions="{selected}">
<button
class="btn btn-primary"
@click="deleteZuordnung(selected)"
:disabled="!selected.length"
>
{{$p.t('dokumente', 'dokumentUnaccept')}}
</button>
</template>
</core-filter-cmpt>
</div>
`
}
@@ -0,0 +1,347 @@
import {CoreFilterCmpt} from "../../../../../filter/Filter.js";
import ModalEdit from "../Modal/Edit.js";
import ModalUpload from "../Modal/Upload.js";
import ApiStvDocuments from "../../../../../../api/factory/stv/documents.js";
export default {
name: "UnacceptedDocuments",
components: {
CoreFilterCmpt,
ModalEdit,
ModalUpload
},
props: {
prestudent_id: Number,
studiengang_kz: Number
},
data(){
return {
tabulatorOptions: {
ajaxURL: 'dummy',
ajaxRequestFunc: () => this.$api.call(
ApiStvDocuments.getDocumentsUnaccepted({
id: this.prestudent_id,
studiengang_kz: this.studiengang_kz})
),
ajaxResponse: (url, params, response) => response.data,
columns: [
{title: "Dokument", field: "bezeichnung"},
{title: "Kurzbz", field: "dokument_kurzbz", visible: false},
{
title: "UploadDatum", field: "hochgeladenamum",
formatter: function (cell) {
const dateStr = cell.getValue();
if (!dateStr) return "";
const date = new Date(dateStr);
return date.toLocaleString("de-DE", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour12: false
});
}
},
{title: "nachgereicht", field: "nachgereicht", visible: false,
formatter:"tickCross",
hozAlign:"center",
formatterParams: {
tickElement: '<i class="fa fa-check text-secondary"></i>',
crossElement: '<i class="fa fa-xmark text-secondary"></i>'
}},
{title: "vorhanden",
field: "vorhanden",
formatter: function(cell, formatterParams, onRendered) {
let value = cell.getValue();
let rowData = cell.getRow().getData(); // Zugriff auf gesamte Zeile
let dueDate = rowData["nachgereicht_am"];
const date = new Date(dueDate);
let dateFormatted = date.toLocaleString("de-DE", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour12: false
});
let tickCrossIcon = value
? '<i class="fa fa-check text-success"></i>'
: '<i class="fa fa-xmark text-danger"></i>';
// if nachgereicht_am show datum
let pill = dueDate
? `<span>${dateFormatted}</span>`
: '';
return `${tickCrossIcon} ${pill}`;
},
hozAlign: "center"
},
{title: "infotext", field: "infotext"},
{title: "akte_id", field: "akte_id"},
{title: "titel_intern", field: "titel_intern"},
{title: "Anmerkung_intern", field: "anmerkung_intern", visible: false},
{title: "Online", field: "onlinebewerbung",
formatter:"tickCross",
hozAlign:"center",
formatterParams: {
tickElement: '<i class="fa fa-check text-secondary"></i>',
crossElement: '<i class="fa fa-xmark text-secondary"></i>'
}},
{title: "Pflicht", field: "pflicht",
formatter:"tickCross",
hozAlign:"center",
formatterParams: {
tickElement: '<i class="fa fa-check text-secondary"></i>',
crossElement: '<i class="fa fa-xmark text-secondary"></i>'
}},
{title: "Nachreichung am", field: "nachgereicht_am",
formatter: function (cell) {
const dateStr = cell.getValue();
if (!dateStr) return "";
const date = new Date(dateStr);
return date.toLocaleString("de-DE", {
day: "2-digit",
month: "2-digit",
year: "numeric",
hour12: false
});
}},
{
title: 'Aktionen', field: 'actions',
minWidth: 50,
maxWidth: 100,
formatter: (cell, formatterParams, onRendered) => {
let container = document.createElement('div');
container.className = "d-flex gap-2";
if(cell.getData().akte_id){
let button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-download"></i>';
button.title = this.$p.t('ui', 'downloadDok');
button.addEventListener('click', (event) =>
this.actionDownloadFile(cell.getData().akte_id)
);
container.append(button);
button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-edit"></i>';
button.title = this.$p.t('ui', 'editDokument');
button.addEventListener('click', (event) =>
this.actionEditFile(cell.getData().akte_id)
);
container.append(button);
button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-xmark"></i>';
button.title = this.$p.t('ui', 'deleteDokument');
button.addEventListener('click', () =>
this.actionDeleteFile(cell.getData().akte_id)
);
container.append(button);
}
else
{
let button = document.createElement('button');
button.className = 'btn btn-outline-secondary btn-action';
button.innerHTML = '<i class="fa fa-upload"></i>';
button.title = this.$p.t('ui', 'uploadDokument');
button.addEventListener('click', () =>
this.actionUploadFile(cell.getData().dokument_kurzbz)
);
container.append(button);
}
return container;
},
frozen: true
},
],
layout: 'fitColumns',
layoutColumnsOnNewData: false,
height: 300,
selectable: true,
selectableRangeMode: 'click',
persistenceID: 'core-details-documents-unaccepted',
listDocuments: [],
prestudentDocumentData: [],
},
tabulatorEvents: [
{
event: 'tableBuilt',
handler: async () => {
await this.$p.loadCategory(['global', 'dokumente', 'ui', 'mobility', 'ampeln']);
let cm = this.$refs.table.tabulator.columnManager;
cm.getColumnByField('bezeichnung').component.updateDefinition({
title: this.$p.t('global', 'dokument')
});
cm.getColumnByField('dokument_kurzbz').component.updateDefinition({
title: this.$p.t('mobility', 'kurzbz')
});
cm.getColumnByField('hochgeladenamum').component.updateDefinition({
title: this.$p.t('global', 'uploaddatum')
});
cm.getColumnByField('nachgereicht').component.updateDefinition({
title: this.$p.t('dokumente', 'nachgereicht')
});
cm.getColumnByField('vorhanden').component.updateDefinition({
title: this.$p.t('dokumente', 'vorhanden')
});
cm.getColumnByField('anmerkung_intern').component.updateDefinition({
title: this.$p.t('global', 'anmerkung')
});
cm.getColumnByField('akte_id').component.updateDefinition({
title: this.$p.t('global', 'akte_id')
});
cm.getColumnByField('pflicht').component.updateDefinition({
title: this.$p.t('ampeln', 'mandatory')
});
cm.getColumnByField('nachgereicht_am').component.updateDefinition({
title: this.$p.t('global', 'dokument')
});
}
}
]
}
},
computed: {
tabulatorEvents() {
const events = [
{
event: "rowDblClick",
handler: (e, row) => {
this.actionDownloadFile(row.getData().akte_id);
}
}
];
return events;
}
},
methods: {
actionDownloadFile(akte_id){
window.open(
FHC_JS_DATA_STORAGE_OBJECT.app_root
+ FHC_JS_DATA_STORAGE_OBJECT.ci_router + '/api/frontend/v1/stv/dokumente/download?akte_id=' + encodeURIComponent(akte_id),
'_blank'
);
},
actionUploadFile(dokument_kurzbz){
this.$refs.modalUpload.open(this.prestudent_id, dokument_kurzbz);
},
actionDeleteFile(akte_id){
this.$fhcAlert
.confirmDelete()
.then(result => result
? akte_id
: Promise.reject({handled: true}))
.then(this.deleteFile)
.catch(this.$fhcAlert.handleSystemError);
},
actionEditFile(akte_id){
this.$refs.modalEdit.open(akte_id);
},
acceptDocuments(selected){
Promise
.allSettled(
selected.map(e =>
this.$api
.call(ApiStvDocuments.createZuordnung({
prestudent_id: this.prestudent_id,
dokument_kurzbz: e.dokument_kurzbz
}))
.then(() => ({
success: true,
dokument_bz: e.bezeichnung
}))
.catch(() => ({
success: false,
dokument_bz: e.bezeichnung
}))
)
)
.then(results => {
const failed = results.filter(res => !res.value.success);
const suceeded = results.filter(res => res.value.success);
if (failed.length > 0) {
failed.forEach(res => {
this.$fhcAlert.alertError(this.$p.t('dokumente', 'errorAccepted',
{'dokument_kurzbz': res.value.dokument_bz}
));
});
let countSuceeded = suceeded.length;
if(countSuceeded > 0)
this.$fhcAlert.alertSuccess(this.$p.t('dokumente', 'successCountAccepted',
{'count': countSuceeded}));
} else {
this.$fhcAlert.alertSuccess(this.$p.t('dokumente', 'successAccepted'));
}
this.reloadAll();
});
},
deleteFile(akte_id){
return this.$fhcApi.factory.stv.documents.deleteFile(akte_id)
.then(response => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete'));
})
.catch(this.$fhcAlert.handleSystemError)
.finally(()=> {
this.reload();
});
},
reload(){
this.$refs.table.reloadTable();
},
reloadAll() {
this.reload();
this.$emit('reloadAccepted');
}
},
template: `
<div class="stv-details-documents h-100 pb-3">
<h5>{{$p.t('dokumente', 'unaccepted')}}</h5>
<modal-edit
ref="modalEdit"
@reload="reloadAll"
>
</modal-edit>
<modal-upload
ref="modalUpload"
@reload="reloadAll"
>
</modal-upload>
<core-filter-cmpt
ref="table"
:tabulator-options="tabulatorOptions"
:tabulator-events="tabulatorEvents"
table-only
:side-menu="false"
reload
new-btn-show
:new-btn-label="this.$p.t('global', 'dokument')"
@click:new="actionUploadFile"
>
<template #actions="{selected}">
<button
class="btn btn-primary"
@click="acceptDocuments(selected)"
:disabled="!selected.length"
>
{{$p.t('dokumente', 'dokumentAccept')}}
</button>
</template>
</core-filter-cmpt>
</div>
`
}
@@ -0,0 +1,141 @@
import BsModal from "../../../../../Bootstrap/Modal.js";
import FormForm from "../../../../../Form/Form.js";
import FormInput from "../../../../../Form/Input.js";
import ApiStvDocuments from "../../../../../../api/factory/stv/documents.js";
export default {
name: "modalEditDocuments",
components: {
BsModal,
FormForm,
FormInput
},
data(){
return {
formData: [],
listDokTypen: []
}
},
methods: {
updateFile(akte_id){
this.$api
.call(ApiStvDocuments.updateFile(akte_id, this.formData))
.then(response => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successSave'));
this.$refs.modalEditDocument.hide();
this.$emit('reload');
})
.catch(this.$fhcAlert.handleSystemError);
},
open(akte_id){
this.loadFormData(akte_id);
this.$refs.modalEditDocument.show();
},
loadFormData(akte_id){
return this.$api
.call(ApiStvDocuments.loadAkte(akte_id))
.then(result => {
this.formData = result.data;
return result;
})
.catch(this.$fhcAlert.handleSystemError);
}
},
created(){
this.$api
.call(ApiStvDocuments.getDoktypen())
.then(result => {
this.listDokTypen = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
},
template: `
<bs-modal
ref="modalEditDocument"
dialog-class="modal-dialog-scrollable"
>
<template #title>
{{ $p.t('dokumente', 'dokDetails') }} {{formData.nameperson}}
</template>
<form-form
ref="formEditDocument"
>
<div>
<div class="row mb-3">
<form-input
type="select"
name="dokument_kurzbz"
:label="$p.t('dokumente/dokTyp')"
v-model="formData.dokument_kurzbz"
>
<option
v-for="typ in listDokTypen"
:key="typ.dokument_kurzbz"
:value="typ.dokument_kurzbz" >{{typ.bezeichnung}}
</option>
</form-input>
</div>
<div class="row mb-3">
<form-input
type="text"
name="titel_intern"
:label="$p.t('dokumente/title')"
v-model="formData.titel_intern"
>
</form-input>
</div>
<div class="row mb-3">
<form-input
type="textarea"
name="anmerkung"
:label="$p.t('global/anmerkung')"
v-model="formData.anmerkung_intern"
rows="5"
>
</form-input>
</div>
<div class="row mb-3">
<form-input
type="DatePicker"
v-model="formData.nachgereicht_am"
name="nachgereicht_am"
:label="$p.t('dokumente/nachreichungAm')"
auto-apply
:enable-time-picker="false"
format="dd.MM.yyyy"
preview-format="dd.MM.yyyy"
:teleport="true"
>
</form-input>
</div>
<div class="row mb-3">
<form-input
type="textarea"
name="anmerkung"
:label="$p.t('dokumente/anmerkung_person')"
v-model="formData.anmerkung"
rows="5"
disabled
>
</form-input>
</div>
</div>
</form-form>
<template #footer>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button type="button" class="btn btn-primary" @click="updateFile(formData.akte_id)">{{$p.t('global', 'speichern')}}</button>
</div>
</template>
</bs-modal>
`,
}
@@ -0,0 +1,127 @@
import BsModal from "../../../../../Bootstrap/Modal.js";
import FormForm from "../../../../../Form/Form.js";
import FormInput from "../../../../../Form/Input.js";
import FormUploadDms from "../../../../../Form/Upload/Dms.js";
import ApiStvDocuments from "../../../../../../api/factory/stv/documents.js";
export default {
name: "modalUploadDocuments",
components: {
BsModal,
FormForm,
FormInput,
FormUploadDms
},
data(){
return{
formData: {
dokument_kurzbz: null,
anhang: [],
anmerkung_intern: null
},
listDokTypen: []
}
},
methods:{
open(prestudent_id, dokument_kurzbz){
this.formData.dokument_kurzbz = dokument_kurzbz;
this.formData.prestudent_id = prestudent_id;
this.$refs.modalUploadFile.show();
},
uploadFile(){
// console.log(this.formData.anhang[0]);
return this.$api
.call(ApiStvDocuments.uploadFile(this.formData.prestudent_id, this.formData))
.then(result => {
this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successUpload'));
this.resetModal();
this.$refs.modalUploadFile.hide();
this.$emit('reload');
})
.catch(this.$fhcAlert.handleSystemError);
},
resetModal(){
this.formData.dokument_kurzbz = null;
this.formData.anhang = [];
this.formData.anmerkung_intern = null;
this.formData.titel_intern = null;
}
},
created(){
this.$api
.call(ApiStvDocuments.getDoktypen())
.then(result => {
this.listDokTypen = result.data;
})
.catch(this.$fhcAlert.handleSystemError);
},
template: `
<bs-modal
ref="modalUploadFile"
dialog-class="modal-dialog-scrollable"
>
<template #title>
Upload {{ $p.t('stv', 'tab_documents') }}
</template>
<form-form
ref="formUploadFile"
>
<div>
<div class="row mb-3">
<label for="text" class="form-label col-sm-2">{{$p.t('global','dokument')}}</label>
<FormUploadDms ref="upload" id="file" v-model="formData.anhang"></FormUploadDms>
</div>
<div class="row mb-3">
<form-input
type="select"
name="dokument_kurzbz"
:label="$p.t('dokumente/dokTyp')"
v-model="formData.dokument_kurzbz"
>
<option value=null> -- {{ $p.t('fehlermonitoring', 'keineAuswahl') }} --</option>
<option
v-for="typ in listDokTypen"
:key="typ.dokument_kurzbz"
:value="typ.dokument_kurzbz" >{{typ.bezeichnung}}
</option>
</form-input>
</div>
<div class="row mb-3">
<form-input
type="text"
name="titel_intern"
:label="$p.t('dokumente/title')"
v-model="formData.titel_intern"
>
</form-input>
</div>
<div class="row mb-3">
<form-input
type="textarea"
name="anmerkung"
:label="$p.t('global/anmerkung')"
v-model="formData.anmerkung_intern"
rows="5"
>
</form-input>
</div>
</div>
</form-form>
<template #footer>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button type="button" class="btn btn-primary" @click="uploadFile">{{$p.t('ui', 'hochladen')}}</button>
</div>
</template>
</bs-modal>
`,
}
+682
View File
@@ -42123,6 +42123,688 @@ and represent the current state of research on the topic. The prescribed citatio
),
/////////// FHC4 Phrases Messages END ///////////
// FHC4 Studierendenverwaltung Dokumente START
array(
'app' => 'core',
'category' => 'stv',
'phrase' => 'tab_documents',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dokumente',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Documents',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'uploadDokument',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dokument hochladen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Upload document',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'deleteDokument',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dokument löschen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Delete document',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'editDokument',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dokument bearbeiten',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Edit document',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'title',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Titel',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'title',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'dokTyp',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dokumententyp',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Document type',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'nachreichungAm',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nachreichung am',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Submission on',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'dokDetails',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dokumentendetails',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Document Details',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'anmerkung_person',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Anmerkung der Person',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Notes of the Person',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'successUpload',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dokument erfolgreich hochgeladen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Dokumentupload successful',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'dokumentAccept',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Akzeptieren',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Accept',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'dokumentUnaccept',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Entakzeptieren',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Unaccept',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'accepted',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Akzeptiert',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Accepted',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'unaccepted',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nicht Akzeptiert',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Not Accepted',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'err_deleteDokHere',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dieses Dokument darf hier nicht gelöscht werden',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'This document may not be deleted here',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'err_updateNotAllowed',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Es können nur Eintraege geändert werden zu denen Dokumente hochgeladen wurden',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Only entries to which documents have been uploaded can be changed',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'downloadDok',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dokument herunterladen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Download Document',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'successAccepted',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Akzeptieren erfolgreich',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Successfully set to accepted',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'successUnaccepted',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Entakzeptieren erfolgreich',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Successfully set to unaccepted',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'successCountUnaccepted',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Entakzeptieren von {count} Dokument(en) erfolgreich',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => '{count} Document(s) successfully set to unaccepted',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'successCountAccepted',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Akzeptieren von {count} Dokument(en) erfolgreich',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => '{count} Document(s) successfully set to accepted',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'errorUnaccepted',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Fehler beim Entakzeptieren von Dokument {dokument_kurzbz}',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Error unaccepting document {dokument_kurzbz}',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'errorAccepted',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Fehler beim Akzeptieren von Dokument {dokument_kurzbz}',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Error Accepting document {dokument_kurzbz}',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'errorMissingValue',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => '{value} fehlt',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => '{value} missing',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'ui',
'phrase' => 'error_valueNotNumeric',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => '{value} darf nur Ziffern enthalten.',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => '{value} must contain only numbers.',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'nachgereicht',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nachgereicht',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Submitted later',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'vorhanden',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Vorhanden',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Available',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'global',
'phrase' => 'akte_id',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Akte ID',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'File ID',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'global',
'phrase' => 'nachgereicht_am',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nachgereicht am',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Submitted on',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'datumAkzeptiert',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Akzeptiertdatum',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Accepted on',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'akzeptiertVon',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Akzeptiert von',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Accepted by',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'global',
'phrase' => 'dms_id',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Dms ID',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Dms ID',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'error_fileMissing',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Bitte eine Datei anhängen',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Please attach a file',
'description' => '',
'insertvon' => 'system'
)
)
),
array(
'app' => 'core',
'category' => 'dokumente',
'phrase' => 'error_fileType',
'insertvon' => 'system',
'phrases' => array(
array(
'sprache' => 'German',
'text' => 'Nur Dateitypen JPEG, PNG oder PDF sind erlaubt',
'description' => '',
'insertvon' => 'system'
),
array(
'sprache' => 'English',
'text' => 'Only JPEG, PNG, or PDF files are allowed.',
'description' => '',
'insertvon' => 'system'
)
)
),
// FHC4 Studierendenverwaltung Dokumente END
);