From bf1bc8d1a97dbb52c2d1bd30a295a3909058da22 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Sun, 13 Oct 2024 13:32:15 +0200 Subject: [PATCH 001/112] added new contact type email unverifiziert and adresse type meldeadresse (mainly for electronic onboarding) --- system/dbupdate_3.4.php | 1 + ...14_electronic_onboarding_anbindung_ida.php | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 system/dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php diff --git a/system/dbupdate_3.4.php b/system/dbupdate_3.4.php index 11880fd55..d3b7b454d 100644 --- a/system/dbupdate_3.4.php +++ b/system/dbupdate_3.4.php @@ -58,6 +58,7 @@ require_once('dbupdate_3.4/17513_Entwicklungsteam.php'); require_once('dbupdate_3.4/28575_softwarebereitstellung.php'); require_once('dbupdate_3.4/41150_oe-pfad_db_view.php'); require_once('dbupdate_3.4/44031_stv_favorites.php'); +require_once('dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php'); // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

Pruefe Tabellen und Attribute!

'; diff --git a/system/dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php b/system/dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php new file mode 100644 index 000000000..ccc0a5827 --- /dev/null +++ b/system/dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php @@ -0,0 +1,30 @@ +db_query("SELECT 1 FROM public.tbl_kontakttyp WHERE kontakttyp='email_unverifiziert'")) +{ + if($db->db_num_rows($result)==0) + { + $qry = "INSERT INTO public.tbl_kontakttyp(kontakttyp, beschreibung, bezeichnung_mehrsprachig) VALUES('email_unverifiziert', 'Unverifizierte E-Mail', '{\"Unverifizierte E-Mail\", \"Unverified email\"}');"; + + if(!$db->db_query($qry)) + echo 'Kontakttyp: '.$db->db_last_error().'
'; + else + echo '
Neuen Kontakttyp E-Mail unverifiziert in public.tbl_kontakttyp hinzugefügt'; + } +} + +// public.tbl_adressentyp: add type Meldeadresse +if($result = $db->db_query("SELECT 1 FROM public.tbl_adressentyp WHERE adressentyp_kurzbz='m'")) +{ + if($db->db_num_rows($result)==0) + { + $qry = "INSERT INTO public.tbl_adressentyp(adressentyp_kurzbz, bezeichnung, bezeichnung_mehrsprachig, sort) VALUES('m', 'Meldeadresse', '{\"Meldeadresse\", \"Registered adress\"}', 6);"; + + if(!$db->db_query($qry)) + echo 'Adressentyp: '.$db->db_last_error().'
'; + else + echo '
Neue Adressentyp Meldeadresse in public.tbl_adressentyp hinzugefügt'; + } +} From b8ff37eb8edfd28c897119d032c517533663574f Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Sat, 19 Oct 2024 17:25:09 +0200 Subject: [PATCH 002/112] added kontakt verifikation table for saving of kontakt verifikation data, added model for the table --- .../person/Kontaktverifikation_model.php | 42 ++++++++++++++++ ...14_electronic_onboarding_anbindung_ida.php | 48 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 application/models/person/Kontaktverifikation_model.php diff --git a/application/models/person/Kontaktverifikation_model.php b/application/models/person/Kontaktverifikation_model.php new file mode 100644 index 000000000..b15439edb --- /dev/null +++ b/application/models/person/Kontaktverifikation_model.php @@ -0,0 +1,42 @@ +dbTable = 'public.tbl_kontakt_verifikation'; + $this->pk = 'kontakt_verifikation_id'; + } + + /** + * Gets contact verification for a person and a verification code + * @param person_id + * @param kontakttyp + * @param verifikation_code + * @param expiration_days number of days after which verifikation code expires + * @return object success or error + */ + public function getKontaktVerifikation($person_id, $kontakttyp, $verifikation_code, $expiration_days = 1) + { + $qry = " + SELECT + kt.kontakt_id, + kv.verifikation_code + FROM + public.tbl_kontakt_verifikation kv + JOIN public.tbl_kontakt kt USING(kontakt_id) + WHERE kt.person_id = ? + AND kt.kontakttyp = ? + AND kv.verifikation_code = ? + AND kv.erstelldatum >= NOW() - INTERVAL '".$this->escape($expiration_days)." days' + ORDER BY + kt.kontakt_id DESC + LIMIT 1"; + + return $this->execQuery($qry, array($person_id, $kontakttyp, $verifikation_code)); + } +} diff --git a/system/dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php b/system/dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php index ccc0a5827..b204d45aa 100644 --- a/system/dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php +++ b/system/dbupdate_3.4/40314_electronic_onboarding_anbindung_ida.php @@ -28,3 +28,51 @@ if($result = $db->db_query("SELECT 1 FROM public.tbl_adressentyp WHERE adressent echo '
Neue Adressentyp Meldeadresse in public.tbl_adressentyp hinzugefügt'; } } + +if (!$result = @$db->db_query('SELECT 1 FROM public.tbl_kontakt_verifikation LIMIT 1')) +{ + $qry = "CREATE SEQUENCE public.tbl_kontakt_verifikation_kontakt_verifikation_id_seq + INCREMENT BY 1 + NO MAXVALUE + NO MINVALUE + START WITH 1 + CACHE 1 + NO CYCLE; + + CREATE TABLE public.tbl_kontakt_verifikation + ( + kontakt_verifikation_id integer DEFAULT nextval('public.tbl_kontakt_verifikation_kontakt_verifikation_id_seq'::regclass), + kontakt_id integer UNIQUE NOT NULL, + verifikation_code varchar(32) UNIQUE NOT NULL, + erstelldatum timestamp without time zone, + verifikation_datum timestamp without time zone, + app varchar(32), + CONSTRAINT pk_tbl_kontakt_verifikation_id PRIMARY KEY (kontakt_verifikation_id) + ); + + ALTER TABLE public.tbl_kontakt_verifikation ADD CONSTRAINT fk_tbl_kontakt_verifikation_kontakt_id FOREIGN KEY (kontakt_id) + REFERENCES public.tbl_kontakt (kontakt_id) + ON DELETE CASCADE ON UPDATE CASCADE; + + ALTER TABLE public.tbl_kontakt_verifikation ADD CONSTRAINT fk_tbl_kontakt_verifikation_app FOREIGN KEY (app) + REFERENCES system.tbl_app (app) + ON DELETE RESTRICT ON UPDATE CASCADE; + + COMMENT ON TABLE public.tbl_kontakt_verifikation IS 'Contact verification'; + COMMENT ON COLUMN public.tbl_kontakt_verifikation.kontakt_id IS 'Contact to verify'; + COMMENT ON COLUMN public.tbl_kontakt_verifikation.verifikation_code IS 'Code generated for verification'; + COMMENT ON COLUMN public.tbl_kontakt_verifikation.erstelldatum IS 'Time when verification code was generated'; + COMMENT ON COLUMN public.tbl_kontakt_verifikation.verifikation_datum IS 'Time when contact was verified'; + COMMENT ON COLUMN public.tbl_kontakt_verifikation.app IS 'App where contact was verified'; + + GRANT SELECT, UPDATE, INSERT, DELETE ON public.tbl_kontakt_verifikation TO web; + GRANT SELECT, UPDATE, INSERT, DELETE ON public.tbl_kontakt_verifikation TO vilesci; + GRANT SELECT, UPDATE ON public.tbl_kontakt_verifikation_kontakt_verifikation_id_seq TO vilesci; + GRANT SELECT, UPDATE ON public.tbl_kontakt_verifikation_kontakt_verifikation_id_seq TO web; + "; + + if(!$db->db_query($qry)) + echo 'public.tbl_kontakt_verifikation: '.$db->db_last_error().'
'; + else + echo ' public.tbl_kontakt_verifikation: Tabelle hinzugefuegt
'; +} From add9263d35ff2a1883c5336a5329144714118882 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Mon, 11 Nov 2024 17:17:33 +0100 Subject: [PATCH 003/112] added Electronic Onboarding phrases --- system/phrasesupdate.php | 366 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 364 insertions(+), 2 deletions(-) diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 7ef0269c9..29d5d6132 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -31025,8 +31025,370 @@ array( 'insertvon' => 'system' ) ) - ) - + ), + //**************************** FHC-Core-ElectronicOnboarding + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'emailFehlt', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Email fehlt', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Email is missing', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'emailUngueltig', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Email ist ungültig', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'The email is not valid', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'emailRegistriert', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Diese Email ist bereits registriert. Bitte verwenden sie eine andere Email oder loggen sie sich mit einer anderen Methode ein.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'The email is already registered. Please choose a different email or use a different login method.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bewerbungZugangEmailBetreff', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Zugang zu Ihrer Bewerbung', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Access to your application', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bewerbungZugangEmailAnredeWeiblich', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Sehr geehrte Frau', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Dear Ms', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bewerbungZugangEmailAnredeMaennlich', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Sehr geehrter Herr', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Dear Mr', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bewerbungZugangEmailAnredeNeutral', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Sehr geehrte/r', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Dear', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'registrierungVerifzierenFuer', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Registrierung verifizieren für', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Verify registration for', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'registrierungVerifzieren', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Registrierung verifizieren', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Verify registration', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'vorname', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Vorname', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'First name', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'nachname', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nachname', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Last name', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'geburtsdatum', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Geburtsdatum', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Birth date', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'emailAdresse', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'E-Mail Adresse', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'E-mail address', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'emailGesendet', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Die E-Mail mit dem Link zu Ihrer Bewerbung wurde erfolgreich an {0} verschickt.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'The email with the link to your application has been successfully sent to {0}.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'emailGesendetHinweis', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'In der Regel erhalten Sie das Mail in wenigen Minuten. Wenn Sie nach 24 Stunden noch kein Mail erhalten haben, + kontaktieren Sie bitte unsere {0}Studienberatung{1}', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'You should receive an e-mail within a few minutes. If you receive no e-mail within 24 hours please contact + our {0}student counselling team{1}.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'fehlerBeiRegistrierung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Fehler bei der Registrierung', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Error when registering', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'fehlerBeiRegistrierungText', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Da ist etwas schief gelaufen. Wir bitten um Entschuldigung.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Sorry, something went wrong.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'fehlerBeiRegistrierungNochmalVersuchen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Nochmals versuchen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Try again', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), ); From b63146a8d89cdc4f08213350170346b1956cd560 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Wed, 20 Nov 2024 15:03:59 +0100 Subject: [PATCH 004/112] added MeldezettelJob for accepting Meldezettel of students with Meldeadresse --- .../controllers/jobs/MeldezettelJob.php | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 application/controllers/jobs/MeldezettelJob.php diff --git a/application/controllers/jobs/MeldezettelJob.php b/application/controllers/jobs/MeldezettelJob.php new file mode 100644 index 000000000..329597985 --- /dev/null +++ b/application/controllers/jobs/MeldezettelJob.php @@ -0,0 +1,86 @@ +_ci =& get_instance(); + + $this->_ci->load->model('crm/Dokumentprestudent_model', 'DokumentprestudentModel'); + } + + /** + * Sets Meldezettel to "accepted" for all students with Meldeadresse. + */ + public function acceptMeldezettel() + { + $this->logInfo('Start Meldezettel Job'); + + $params = array(self::DOKUMENT_KURZBZ); + + $qry = " + -- get all prestudents with meldeadresse, but no accepted Meldezettel + SELECT + DISTINCT prestudent_id + FROM + public.tbl_adresse + JOIN public.tbl_person USING (person_id) + JOIN public.tbl_prestudent ps USING (person_id) + WHERE + typ = 'm' + AND NOT EXISTS ( + SELECT + 1 + FROM + public.tbl_dokumentprestudent + WHERE + prestudent_id = ps.prestudent_id + AND dokument_kurzbz = ? + )"; + + // get all prestudents with Meldeadresse and no accpeted Meldezettel + $result = $this->_ci->DokumentprestudentModel->execReadOnlyQuery($qry, $params); + + if (isError($result)) + { + $this->logError(getError($result)); + } + + $count = 0; + + if (hasData($result)) + { + $prestudents = getData($result); + + foreach ($prestudents as $prestudent) + { + // set Meldezettel to accepted + $result = $this->_ci->DokumentprestudentModel->insert( + array( + 'prestudent_id' => $prestudent->prestudent_id, + 'dokument_kurzbz' => self::DOKUMENT_KURZBZ, + 'datum' => date('Y-m-d'), + 'insertamum' => strftime('%Y-%m-%d %H:%M'), + 'insertvon' => self::INSERT_VON + ) + ); + + if (isError($result)) + $this->logError(getError($result)); + else + $count++; + } + } + + $this->logInfo('End Meldezettel Job', array('Number of changes ' => $count)); + } +} From 0a97b39efbb877ff3f7a07ca0d531434b54cb3ca Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Tue, 24 Dec 2024 19:14:04 +0100 Subject: [PATCH 005/112] added phrases for electronic onboarding verification page --- .../person/Kontaktverifikation_model.php | 2 +- system/phrasesupdate.php | 137 +++++++++++++++++- 2 files changed, 132 insertions(+), 7 deletions(-) diff --git a/application/models/person/Kontaktverifikation_model.php b/application/models/person/Kontaktverifikation_model.php index b15439edb..17bcb1c35 100644 --- a/application/models/person/Kontaktverifikation_model.php +++ b/application/models/person/Kontaktverifikation_model.php @@ -29,7 +29,7 @@ class Kontaktverifikation_model extends DB_Model FROM public.tbl_kontakt_verifikation kv JOIN public.tbl_kontakt kt USING(kontakt_id) - WHERE kt.person_id = ? + WHERE kt.person_id = ? AND kt.kontakttyp = ? AND kv.verifikation_code = ? AND kv.erstelldatum >= NOW() - INTERVAL '".$this->escape($expiration_days)." days' diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 8d7bdd939..843a055a1 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -31310,18 +31310,18 @@ array( array( 'app' => 'core', 'category' => 'onboarding', - 'phrase' => 'registrierungVerifzierenFuer', + 'phrase' => 'bewerbungVerifizierung', 'insertvon' => 'system', 'phrases' => array( array( 'sprache' => 'German', - 'text' => 'Registrierung verifizieren für', + 'text' => 'Verifizierung Ihrer Bewerbung', 'description' => '', 'insertvon' => 'system' ), array( 'sprache' => 'English', - 'text' => 'Verify registration for', + 'text' => 'Application verification', 'description' => '', 'insertvon' => 'system' ) @@ -31330,18 +31330,143 @@ array( array( 'app' => 'core', 'category' => 'onboarding', - 'phrase' => 'registrierungVerifzieren', + 'phrase' => 'bewerbungVerifzieren', 'insertvon' => 'system', 'phrases' => array( array( 'sprache' => 'German', - 'text' => 'Registrierung verifizieren', + 'text' => 'Bewerbung verifizieren', 'description' => '', 'insertvon' => 'system' ), array( 'sprache' => 'English', - 'text' => 'Verify registration', + 'text' => 'Verify application', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bewerbungVerifizierungEinleitung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Wenn Ihre Daten stimmen, geben Sie bitte Ihre E-Mail Adresse ein und drücken Sie auf "Bewerbung verfifizieren". +Danach erhalten Sie eine E-Mail mit dem Link zu Ihrer Bewerbung an die angegebene Adresse. +Dort können Sie Studienrichtungen hinzufügen, Ihre Daten vervollständigen, und sich unverbindlich bewerben.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'If your data is correct, please enter your email and click "Verify application". +We will then send you a link via e-mail to the address specified. There, you can add personal information or degree programs and submit non-binding applications.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bewerbungVerifizierungKontakthinweis', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Wenn Sie mehr Informationen benötigen, steht Ihnen unsere Studienberatung gerne persönlich, telefonisch, per E-Mail oder WhatsApp zur Verfügung.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Should you require any additional information, please do not hesitate to contact our student counselling team in person, by phone, or via e-mail or WhatsApp.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bewerbungVerifizierungDatenschutzhinweis', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Datenschutz-Hinweis', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Privacy information', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bewerbungVerifizierungDatenschutzhinweisText', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Die uns von Ihnen zum Zwecke der Bewerbung bekanntgegebenen Daten werden von uns ausschließlich zur Abwicklung der Bewerbung auf der Grundlage von vor- bzw vertraglichen Zwecken verarbeitet und mit der unten beschriebenen Ausnahme bei Unklarheiten betreffend die Zugangsvoraussetzungen nicht an Dritte weitergegeben. +Kommt es zu keinem weiteren Kontakt bzw zu keiner Aufnahme, löschen wir Ihre Daten nach drei Jahren.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'The data communicated to us by you for the purpose of the application will be used by us exclusively for the processing of the application on the basis of pre-contractual or contractual purposes and will not be passed on to third parties with the exception described below in case of uncertainties regarding the entry requirements. +If there is no further contact or enrolment, your data will be deleted after three years.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bewerbungVerifizierungInformationenDatenschutzGrundverordnung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Informationen zu Ihren Betroffenenrechten finden Sie hier:', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Information on your data subject rights can be found here:', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bewerbungVerifizierungDatenschutzFragen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Bei Fragen stehen wir Ihnen jederzeit unter folgender Mail zur Verfügung: ', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'If you have any questions, please contact us at ', 'description' => '', 'insertvon' => 'system' ) From 115b35ad7b40f3b27a161c5a8859ca019f1924e5 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Wed, 8 Jan 2025 14:52:32 +0100 Subject: [PATCH 006/112] electronic onboarding: changed phrase for error display --- system/phrasesupdate.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 843a055a1..4de9cbb03 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -31622,13 +31622,13 @@ If there is no further contact or enrolment, your data will be deleted after thr 'phrases' => array( array( 'sprache' => 'German', - 'text' => 'Da ist etwas schief gelaufen. Wir bitten um Entschuldigung.', + 'text' => 'Es ist ein Fehler bei der Registrierung aufgetreten.', 'description' => '', 'insertvon' => 'system' ), array( 'sprache' => 'English', - 'text' => 'Sorry, something went wrong.', + 'text' => 'An error occured during registration.', 'description' => '', 'insertvon' => 'system' ) From 08cb3d3809b34b43eb87558a02a5ae702e4c8681 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Thu, 16 Jan 2025 21:02:01 +0100 Subject: [PATCH 007/112] electronic onboarding phrase typo fix --- system/phrasesupdate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 4de9cbb03..7f030e62b 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -31355,7 +31355,7 @@ array( 'phrases' => array( array( 'sprache' => 'German', - 'text' => 'Wenn Ihre Daten stimmen, geben Sie bitte Ihre E-Mail Adresse ein und drücken Sie auf "Bewerbung verfifizieren". + 'text' => 'Wenn Ihre Daten stimmen, geben Sie bitte Ihre E-Mail Adresse ein und drücken Sie auf "Bewerbung verifizieren". Danach erhalten Sie eine E-Mail mit dem Link zu Ihrer Bewerbung an die angegebene Adresse. Dort können Sie Studienrichtungen hinzufügen, Ihre Daten vervollständigen, und sich unverbindlich bewerben.', 'description' => '', From 39ada202774fbb77811a2cd54bd96f2a046917aa Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Wed, 22 Jan 2025 15:26:25 +0100 Subject: [PATCH 008/112] Electronic Onboarding: added phrases --- system/phrasesupdate.php | 102 +++++++++++++++++++++++++++++++-------- 1 file changed, 82 insertions(+), 20 deletions(-) diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 7f030e62b..e177274ec 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -31307,26 +31307,6 @@ array( ) ) ), - array( - 'app' => 'core', - 'category' => 'onboarding', - 'phrase' => 'bewerbungVerifizierung', - 'insertvon' => 'system', - 'phrases' => array( - array( - 'sprache' => 'German', - 'text' => 'Verifizierung Ihrer Bewerbung', - 'description' => '', - 'insertvon' => 'system' - ), - array( - 'sprache' => 'English', - 'text' => 'Application verification', - 'description' => '', - 'insertvon' => 'system' - ) - ) - ), array( 'app' => 'core', 'category' => 'onboarding', @@ -31654,6 +31634,88 @@ If there is no further contact or enrolment, your data will be deleted after thr ) ) ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'zustimmungDatenuebermittlung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Können in Ausnahmefällen die Zugangsvoraussetzungen von der FH Technikum Wien nicht abschließend abgeklärt werden, erteile ich die Zustimmung, dass die FH Technikum Wien die Dokumente zur Überprüfung an die zuständigen Behörden weiterleiten kann.
+Ich wurde darüber informiert, dass ich nicht verpflichtet bin, der Übermittlung meiner Daten zuzustimmen. Diese Zustimmung ist allerdings notwendig, um die Bewerbung berücksichtigen zu können.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'If in exceptional cases the admission requirements can not be finally clarified by the UAS Technikum Wien, I give my consent that the UAS Technikum Wien can forward the documents to the competent authorities for verification.
+I have been informed that I am under no obligation to consent to the transmission of my data. However, this consent is necessary in order for the application to be considered.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'zustimmungDatenschutzerklaerung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Ich habe die Datenschutzerklärung zu Kenntnis genommen.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'I have taken note of the privacy policy.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bitteDatenuebermittlungZustimmen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Sie müssen der Datenübermittlung zustimmen, um Ihre Bewerbung abschicken zu können.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'You have to consent the transmission of your data to send the application.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'onboarding', + 'phrase' => 'bitteDatenschutzerklaerungZustimmen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Sie müssen der Datenschutzerklärung zustimmen, um Ihre Bewerbung abschicken zu können.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'You have to consent to the privacy statement to send the application.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ) ); From ea2be8026b463c8cf9c7132197aea82831aa9886 Mon Sep 17 00:00:00 2001 From: ma0068 Date: Wed, 12 Mar 2025 08:06:23 +0100 Subject: [PATCH 009/112] filter hidden from kontakttyp, show typ.beschreibung in dropdown --- .../controllers/api/frontend/v1/stv/Kontakt.php | 15 ++++++++------- .../Details/Kontakt/Contact.js | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Kontakt.php b/application/controllers/api/frontend/v1/stv/Kontakt.php index fd16fff06..1c3c0c95d 100644 --- a/application/controllers/api/frontend/v1/stv/Kontakt.php +++ b/application/controllers/api/frontend/v1/stv/Kontakt.php @@ -439,6 +439,7 @@ class Kontakt extends FHCAPI_Controller $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); } $this->terminateWithSuccess((getData($result) ?: [])); + } public function getKontakttypen() @@ -446,13 +447,13 @@ class Kontakt extends FHCAPI_Controller $this->load->model('person/Kontakttyp_model', 'KontakttypModel'); $result = $this->KontakttypModel->load(); - if (isError($result)) { - $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); - } - else - { - $this->terminateWithSuccess(getData($result) ?: []); - } + + $data = $this->getDataOrTerminateWithError($result); + + $filteredData = array_filter($data, function ($item) { + return $item->kontakttyp !== "hidden"; + }); + $this->terminateWithSuccess($filteredData); } public function loadContact() diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Contact.js b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Contact.js index 87dc70eb1..0bda648a9 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Contact.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Kontakt/Contact.js @@ -322,7 +322,7 @@ export default{ v-model="contactData.kontakttyp"> > - + From f96bfbe0004a41312fb64d940bf9686329939a20 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Wed, 28 May 2025 07:51:10 +0200 Subject: [PATCH 010/112] =?UTF-8?q?lehrf=C3=A4cherverteilung=20v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/controllers/LVVerwaltung.php | 42 + .../api/frontend/v1/Lehrveranstaltung.php | 243 ++++++ .../api/frontend/v1/lv/DirektGruppe.php | 108 +++ .../api/frontend/v1/lv/Favorites.php | 47 ++ .../controllers/api/frontend/v1/lv/Gruppe.php | 189 +++++ .../api/frontend/v1/lv/Lehreinheit.php | 438 +++++++++++ .../controllers/api/frontend/v1/lv/Lektor.php | 380 +++++++++ .../controllers/api/frontend/v1/lv/Setup.php | 116 +++ .../api/frontend/v1/lv/StgTree.php | 91 +++ .../controllers/api/frontend/v1/lv/Tags.php | 24 + .../frontend/v1/notiz/NotizLehreinheit.php | 21 + application/libraries/LektorLib.php | 342 +++++++++ .../models/accounting/Vertrag_model.php | 70 ++ .../models/education/Lehreinheit_model.php | 438 +++++++++++ .../education/Lehreinheitgruppe_model.php | 208 +++++ .../Lehreinheitmitarbeiter_model.php | 71 ++ .../education/Lehrveranstaltung_model.php | 225 ++++++ .../Organisationseinheit_model.php | 30 + .../models/organisation/Studienplan_model.php | 21 + application/models/person/Notiz_model.php | 54 +- .../models/ressource/Mitarbeiter_model.php | 14 + .../models/ressource/Stundenplandev_model.php | 83 ++ .../models/ressource/Stundensatz_model.php | 16 + .../Dienstverhaeltnis_model.php | 21 + application/views/LVVerwaltung.php | 39 + public/css/Lvverwaltung.css | 27 + public/js/api/factory/notiz.js | 5 +- public/js/api/factory/notiz/lehreinheit.js | 29 + public/js/api/lehrveranstaltung.js | 28 + public/js/api/lehrveranstaltung/details.js | 30 + .../js/api/lehrveranstaltung/direktgruppe.js | 26 + public/js/api/lehrveranstaltung/gruppe.js | 56 ++ .../js/api/lehrveranstaltung/lehreinheit.js | 41 + public/js/api/lehrveranstaltung/lektor.js | 78 ++ public/js/api/lehrveranstaltung/setup.js | 9 + .../api/lehrveranstaltung/studiengangtree.js | 43 ++ public/js/api/lehrveranstaltung/tag.js | 54 ++ public/js/api/lehrveranstaltung/vertrag.js | 22 + public/js/apps/LVVerwaltung.js | 46 ++ .../LVVerwaltung/Details/Direktinskription.js | 155 ++++ .../components/LVVerwaltung/Details/Form.js | 209 +++++ .../LVVerwaltung/Details/Gruppen.js | 195 +++++ .../components/LVVerwaltung/LVVerwaltung.js | 282 +++++++ .../components/LVVerwaltung/Lektor/Daten.js | 270 +++++++ .../components/LVVerwaltung/Lektor/Table.js | 223 ++++++ .../components/LVVerwaltung/Lektor/Vertrag.js | 161 ++++ .../js/components/LVVerwaltung/Setup/Table.js | 683 +++++++++++++++++ .../js/components/LVVerwaltung/Setup/Tabs.js | 62 ++ .../components/LVVerwaltung/Tabs/Details.js | 133 ++++ .../js/components/LVVerwaltung/Tabs/Lektor.js | 70 ++ .../js/components/LVVerwaltung/Tabs/Notiz.js | 33 + .../js/components/Stv/Studentenverwaltung.js | 4 +- .../Stv/Studentenverwaltung/Verband.js | 69 +- public/js/components/Tag/Tag.js | 12 +- .../tabulator/filters/extendedHeaderFilter.js | 110 ++- system/dbupdate_3.4.php | 1 + .../60882_lehrfaecherverteilung_favorites.php | 16 + system/phrasesupdate.php | 723 +++++++++++++++++- 58 files changed, 7146 insertions(+), 90 deletions(-) create mode 100644 application/controllers/LVVerwaltung.php create mode 100644 application/controllers/api/frontend/v1/Lehrveranstaltung.php create mode 100644 application/controllers/api/frontend/v1/lv/DirektGruppe.php create mode 100644 application/controllers/api/frontend/v1/lv/Favorites.php create mode 100644 application/controllers/api/frontend/v1/lv/Gruppe.php create mode 100644 application/controllers/api/frontend/v1/lv/Lehreinheit.php create mode 100644 application/controllers/api/frontend/v1/lv/Lektor.php create mode 100644 application/controllers/api/frontend/v1/lv/Setup.php create mode 100644 application/controllers/api/frontend/v1/lv/StgTree.php create mode 100644 application/controllers/api/frontend/v1/lv/Tags.php create mode 100644 application/controllers/api/frontend/v1/notiz/NotizLehreinheit.php create mode 100644 application/libraries/LektorLib.php create mode 100644 application/views/LVVerwaltung.php create mode 100644 public/css/Lvverwaltung.css create mode 100644 public/js/api/factory/notiz/lehreinheit.js create mode 100644 public/js/api/lehrveranstaltung.js create mode 100644 public/js/api/lehrveranstaltung/details.js create mode 100644 public/js/api/lehrveranstaltung/direktgruppe.js create mode 100644 public/js/api/lehrveranstaltung/gruppe.js create mode 100644 public/js/api/lehrveranstaltung/lehreinheit.js create mode 100644 public/js/api/lehrveranstaltung/lektor.js create mode 100644 public/js/api/lehrveranstaltung/setup.js create mode 100644 public/js/api/lehrveranstaltung/studiengangtree.js create mode 100644 public/js/api/lehrveranstaltung/tag.js create mode 100644 public/js/api/lehrveranstaltung/vertrag.js create mode 100644 public/js/apps/LVVerwaltung.js create mode 100644 public/js/components/LVVerwaltung/Details/Direktinskription.js create mode 100644 public/js/components/LVVerwaltung/Details/Form.js create mode 100644 public/js/components/LVVerwaltung/Details/Gruppen.js create mode 100644 public/js/components/LVVerwaltung/LVVerwaltung.js create mode 100644 public/js/components/LVVerwaltung/Lektor/Daten.js create mode 100644 public/js/components/LVVerwaltung/Lektor/Table.js create mode 100644 public/js/components/LVVerwaltung/Lektor/Vertrag.js create mode 100644 public/js/components/LVVerwaltung/Setup/Table.js create mode 100644 public/js/components/LVVerwaltung/Setup/Tabs.js create mode 100644 public/js/components/LVVerwaltung/Tabs/Details.js create mode 100644 public/js/components/LVVerwaltung/Tabs/Lektor.js create mode 100644 public/js/components/LVVerwaltung/Tabs/Notiz.js create mode 100644 system/dbupdate_3.4/60882_lehrfaecherverteilung_favorites.php diff --git a/application/controllers/LVVerwaltung.php b/application/controllers/LVVerwaltung.php new file mode 100644 index 000000000..2a79d6375 --- /dev/null +++ b/application/controllers/LVVerwaltung.php @@ -0,0 +1,42 @@ +method] = ['admin:r', 'assistenz:r']; + parent::__construct($permissions); + + $this->load->library('VariableLib', ['uid' => getAuthUID()]); + } + + /** + * @return void + */ + public function _remap() + { + $this->load->view('LVVerwaltung', [ + 'permissions' => [ + 'lehre/lehrveranstaltung' => $this->permissionlib->isBerechtigt('lehre/lehrveranstaltung'), + 'lv-plan/gruppenentfernen' => $this->permissionlib->isBerechtigt('lv-plan/gruppenentfernen'), + 'lv-plan/lektorentfernen' => $this->permissionlib->isBerechtigt('lv-plan/lektorentfernen'), + ], + 'variables' => [ + 'semester_aktuell' => $this->variablelib->getVar('semester_aktuell') + ], + 'configs' => [ + 'showVertragsdetails' => defined('FAS_LV_LEKTORINNENZUTEILUNG_VERTRAGSDETAILS_ANZEIGEN') && FAS_LV_LEKTORINNENZUTEILUNG_VERTRAGSDETAILS_ANZEIGEN, + 'showGewichtung' => defined('CIS_GESAMTNOTE_GEWICHTUNG') && CIS_GESAMTNOTE_GEWICHTUNG, + 'lehreinheitAnmerkungDefault' => defined('LEHREINHEIT_ANMERKUNG_DEFAULT') ? LEHREINHEIT_ANMERKUNG_DEFAULT : '', + 'lehreinheitRaumtypDefault' => defined('DEFAULT_LEHREINHEIT_RAUMTYP') ? DEFAULT_LEHREINHEIT_RAUMTYP : '', + 'lehreinheitRaumtypAlternativeDefault' => defined('DEFAULT_LEHREINHEIT_RAUMTYP_ALTERNATIV') ? DEFAULT_LEHREINHEIT_RAUMTYP_ALTERNATIV : '' + ] + ]); + + } +} diff --git a/application/controllers/api/frontend/v1/Lehrveranstaltung.php b/application/controllers/api/frontend/v1/Lehrveranstaltung.php new file mode 100644 index 000000000..1b2e2bc35 --- /dev/null +++ b/application/controllers/api/frontend/v1/Lehrveranstaltung.php @@ -0,0 +1,243 @@ +. + */ + +if (!defined('BASEPATH')) + exit('No direct script access allowed'); + +class Lehrveranstaltung extends FHCAPI_Controller +{ + private $_ci; + private $_uid; + + public function __construct() + { + parent::__construct([ + 'loadByEmployee' => ['admin:r', 'assistenz:r'], + 'loadByStudiengang' => ['admin:r', 'assistenz:r'], + 'loadByLV' => ['admin:r', 'assistenz:r'], + ]); + + $this->_ci = &get_instance(); + $this->_setAuthUID(); + + $this->_ci->load->model('education/Lehreinheit_model', 'LehreinheitModel'); + $this->_ci->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); + + $this->_ci->load->library('VariableLib', ['uid' => $this->_uid]); + } + public function loadByEmployee($mitarbeiter_uid = null, $stg_kz = null) + { + if (is_null($mitarbeiter_uid)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $studiensemester_kurzbz = $this->_ci->variablelib->getVar('semester_aktuell'); + + $lehrveranstaltungen = $this->_ci->LehreinheitModel->getLvsByEmployee($mitarbeiter_uid, $studiensemester_kurzbz, $stg_kz); + $lehrveranstaltungen_data = $this->getDataOrTerminateWithError($lehrveranstaltungen); + + $tree = []; + + foreach ($lehrveranstaltungen_data as $lehrveranstaltung) + { + $lehreinheiten = $this->_ci->LehreinheitModel->getLEByLV($lehrveranstaltung->lehrveranstaltung_id, $studiensemester_kurzbz, $mitarbeiter_uid); + $lehreinheiten_data = $this->getDataOrTerminateWithError($lehreinheiten); + + if (!isset($lehrveranstaltung->_children)) + { + $lehrveranstaltung->_children = $lehreinheiten_data; + } + $tree[] = $lehrveranstaltung; + } + + $this->terminateWithSuccess($tree); + } + + public function loadByStudiengang($studiengang_kz = null, $semester = null) + { + if (is_null($studiengang_kz) || !ctype_digit((string)$studiengang_kz)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $verband = null; + if (!is_null($semester) && !is_numeric($semester)) + { + $verband = $semester; + $semester = null; + } + + $this->_ci->load->model('organisation/Studienplan_model', 'StudienplanModel'); + + $studiensemester_kurzbz = $this->_ci->variablelib->getVar('semester_aktuell'); + $studienplan_data = $this->_ci->StudienplanModel->getStudienplaeneBySemester($studiengang_kz, $studiensemester_kurzbz, $semester, $verband); + + $studienplan_ids = array(); + $only_ids = array(); + $placeholders = array(); + + if (hasData($studienplan_data)) + { + foreach (getData($studienplan_data) as $studienplan) { + $placeholders[] = "(?, ?)"; + $studienplan_ids[] = $studienplan->studienplan_id; + $studienplan_ids[] = $studienplan->semester; + $only_ids[] = $studienplan->studienplan_id; + } + } + + $lehrveranstaltungen_data = $this->_ci->LehrveranstaltungModel->getLvsByStudiengang($studienplan_ids, $placeholders, $only_ids, $studiengang_kz, $studiensemester_kurzbz, $semester, $verband); + $lehrveranstaltungen_data = hasData($lehrveranstaltungen_data) ? getData($lehrveranstaltungen_data) : array(); + + + $tree = []; + foreach ($lehrveranstaltungen_data as $row) + { + $rowData = $row; + + $lehreinheiten_data = $this->_ci->LehreinheitModel->getByLvidStudiensemester($row->lehrveranstaltung_id, $studiensemester_kurzbz); + + if (hasData($lehreinheiten_data)) + { + $lehreinheiten = getData($lehreinheiten_data); + $rowData->_children = $lehreinheiten; + } + + if (!isEmptyString($row->studienplan_lehrveranstaltung_id_parent)) + { + $child = $this->_ci->StudienplanModel->loadStudienplanLehrveranstaltung($row->studienplan_lehrveranstaltung_id_parent); + + if (hasData($child)) + { + $child = getData($child)[0]; + $searchId = $child->lehrveranstaltung_id; + + foreach ($lehrveranstaltungen_data as &$searchParent) + { + if ($searchParent->lehrveranstaltung_id === $searchId) + { + if (!isset($searchParent->_children)) + { + $searchParent->_children = []; + } + + if (is_array($searchParent->_children)) + { + $searchParent->_children[] = $row; + } + else + { + $searchParent->_children = [$searchParent->_children, $row]; + } + break; + } + } + + } + } + else + { + $tree[] = $rowData; + } + } + + $counter = 0; + $this->assignUniqueIndex($tree, $counter); + $this->terminateWithSuccess($tree); + } + + + public function loadByLV($lehrveranstaltung_id = null) + { + if (is_null($lehrveranstaltung_id) || !ctype_digit((string)$lehrveranstaltung_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $this->_ci->LehrveranstaltungModel->addSelect('lehrveranstaltung_id, lehrform_kurzbz, lehre, bezeichnung as lvbezeichnung'); + $lehrveranstaltung_result = $this->_ci->LehrveranstaltungModel->loadWhere(array('lehrveranstaltung_id' => $lehrveranstaltung_id)); + $lehrveranstaltung_result = $this->getDataOrTerminateWithError($lehrveranstaltung_result); + $lehrveranstaltung = $lehrveranstaltung_result[0]; + + $this->_ci->LehreinheitModel->addSelect('lehrveranstaltung_id_kompatibel'); + $this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrveranstaltung_kompatibel', 'lehrveranstaltung_id'); + $lehrfaecher = $this->_ci->LehreinheitModel->loadWhere(array('lehrveranstaltung_id' => $lehrveranstaltung->lehrveranstaltung_id)); + + $lehrfaecher_array = []; + if (hasData($lehrfaecher)) + $lehrfaecher_array = array_merge($lehrfaecher_array, array_column(getData($lehrfaecher), 'lehrveranstaltung_id_kompatibel')); + + $lehrfaecher_array[] = $lehrveranstaltung->lehrveranstaltung_id; + + $this->_ci->LehrveranstaltungModel->addDistinct('lehrfach_id'); + $this->_ci->LehrveranstaltungModel->addSelect("tbl_lehrveranstaltung.lehrveranstaltung_id, CONCAT(tbl_lehrveranstaltung.bezeichnung || '(' || tbl_lehrveranstaltung.oe_kurzbz || ')') as lehrfach"); + $this->_ci->LehrveranstaltungModel->db->where_in('tbl_lehrveranstaltung.lehrveranstaltung_id', $lehrfaecher_array); + $lehrfaecher_result = $this->_ci->LehrveranstaltungModel->load(); + + $lehrfaecher_array = hasData($lehrfaecher_result) ? getData($lehrfaecher_result) : array(); + + $lehrveranstaltung->lehrfaecher = $lehrfaecher_array; + $this->terminateWithSuccess($lehrveranstaltung); + } + + /* + * (david) ggf. im naechsten release + * public function loadByOrganization($oe_kurzbz) + { + $studiensemester_kurzbz = $this->variablelib->getVar('semester_aktuell'); + + $lehrveranstaltungen = $this->LehrveranstaltungModel->getLvsByOrganization($oe_kurzbz); + $lehrveranstaltungen_data = $this->getDataOrTerminateWithError($lehrveranstaltungen); + $tree = []; + + foreach ($lehrveranstaltungen_data as $lehrveranstaltung) + { + $lehreinheiten = $this->LehreinheitModel->getLEByLV($lehrveranstaltung->lehrveranstaltung_id, $studiensemester_kurzbz); + $lehreinheiten_data = $this->getDataOrTerminateWithError($lehreinheiten); + + if (!isset($lehrveranstaltung->_children)) + { + + $lehrveranstaltung->_children = $lehreinheiten_data; + } + $tree[] = $lehrveranstaltung; + } + $this->terminateWithSuccess($tree); + }*/ + + /*public function loadByFachbereich($fachbereich, $mitarbeiter_uid = null) + { + $studiensemester_kurzbz = $this->variablelib->getVar('semester_aktuell'); + + $this->LehreinheitModel->getLvsByFachbereich($fachbereich, $studiensemester_kurzbz, $mitarbeiter_uid); + }*/ + private function _setAuthUID() + { + $this->_uid = getAuthUID(); + + if (!$this->_uid) + show_error('User authentification failed'); + } + + private function assignUniqueIndex(&$nodes, &$counter) + { + foreach ($nodes as &$node) + { + $node->uniqueindex = $counter++; + if (!empty($node->_children) && is_array($node->_children)) + { + $this->assignUniqueIndex($node->_children, $counter); + } + } + } +} diff --git a/application/controllers/api/frontend/v1/lv/DirektGruppe.php b/application/controllers/api/frontend/v1/lv/DirektGruppe.php new file mode 100644 index 000000000..fe1737f6a --- /dev/null +++ b/application/controllers/api/frontend/v1/lv/DirektGruppe.php @@ -0,0 +1,108 @@ +. + */ + +if (!defined('BASEPATH')) + exit('No direct script access allowed'); + +class DirektGruppe extends FHCAPI_Controller +{ + private $_ci; + public function __construct() + { + parent::__construct([ + 'add' => ['admin:rw', 'assistenz:rw'], + 'delete' => ['admin:rw', 'assistenz:rw'], + 'getByLehreinheit' => ['admin:r', 'assistenz:r'], + ]); + + $this->_ci = &get_instance(); + + $this->loadPhrases([ + 'ui' + ]); + $this->_ci->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel'); + $this->_ci->load->model('education/lehreinheit_model', 'LehreinheitModel'); + $this->_ci->load->model('person/Benutzer_model', 'BenutzerModel'); + } + + public function add() + { + $uid = $this->input->post('uid'); + $lehreinheit_id = $this->input->post('lehreinheit_id'); + + $this->checkPermission($lehreinheit_id, $uid); + + $result = $this->_ci->LehreinheitgruppeModel->direktUserAdd($uid, $lehreinheit_id); + + if (isError($result)) + $this->terminateWithError(getError($result)); + + $this->terminateWithSuccess($result); + } + + public function delete() + { + $uid = $this->input->post('uid'); + $lehreinheit_id = $this->input->post('lehreinheit_id'); + + $this->checkPermission($lehreinheit_id, $uid); + + $result = $this->_ci->LehreinheitgruppeModel->direktUserDelete($uid, $lehreinheit_id); + + if (isError($result)) + $this->terminateWithError(getError($result)); + + $this->terminateWithSuccess($result); + } + + public function getByLehreinheit($lehreinheit_id = null) + { + $this->checkPermission($lehreinheit_id); + $gruppen = $this->_ci->LehreinheitgruppeModel->getDirectGroup($lehreinheit_id); + $this->terminateWithSuccess(hasData($gruppen) ? getData($gruppen) : array()); + } + + private function checkPermission($lehreinheit_id, $uid = false) + { + if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $lehreinheit_result = $this->_ci->LehreinheitModel->load($lehreinheit_id); + + if (!hasData($lehreinheit_result) || isError($lehreinheit_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + if ($uid) + { + $benuzuer_result = $this->_ci->BenutzerModel->load(array($uid)); + if (!hasData($benuzuer_result) || isError($benuzuer_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + } + + $result = $this->_ci->LehreinheitModel->getOes($lehreinheit_id); + + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + $oe_array = $result; + + if (!$this->_ci->permissionlib->isBerechtigtMultipleOe('admin', $oe_array, 'suid') && + !$this->_ci->permissionlib->isBerechtigtMultipleOe('assistenz', $oe_array, 'suid')) + $this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess')); + } +} diff --git a/application/controllers/api/frontend/v1/lv/Favorites.php b/application/controllers/api/frontend/v1/lv/Favorites.php new file mode 100644 index 000000000..080a4ec6e --- /dev/null +++ b/application/controllers/api/frontend/v1/lv/Favorites.php @@ -0,0 +1,47 @@ + self::PERM_LOGGED, + 'set' => self::PERM_LOGGED + ]); + + // Load models + $this->load->model('system/Variable_model', 'VariableModel'); + } + + public function index() + { + $result = $this->VariableModel->getVariables(getAuthUID(), ['lv_favorites']); + + $data = $this->getDataOrTerminateWithError($result); + + if (!$data) + $this->terminateWithSuccess(null); + else + $this->terminateWithSuccess(isset($data['lv_favorites']) ? $data['lv_favorites'] : null); + } + + public function set() + { + $this->load->library('form_validation'); + + $this->form_validation->set_rules('favorites', 'Favorites', 'required'); + + if (!$this->form_validation->run()) + $this->terminateWithValidationErrors($this->form_validation->error_array()); + + $favorites = $this->input->post('favorites'); + + $result = $this->VariableModel->setVariable(getAuthUID(), 'lv_favorites', $favorites); + + $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess(true); + } +} diff --git a/application/controllers/api/frontend/v1/lv/Gruppe.php b/application/controllers/api/frontend/v1/lv/Gruppe.php new file mode 100644 index 000000000..01c11f98f --- /dev/null +++ b/application/controllers/api/frontend/v1/lv/Gruppe.php @@ -0,0 +1,189 @@ + ['admin:rw', 'assistenz:rw'], + 'delete' => ['admin:rw', 'assistenz:rw'], + 'deleteFromLVPlan' => ['admin:rw', 'assistenz:rw'], + 'getBenutzer' => ['admin:r', 'assistenz:r'], + 'getAll' => ['admin:r', 'assistenz:r'], + 'getByLehreinheit' => ['admin:r', 'assistenz:r'], + ]); + + $this->_ci = &get_instance(); + $this->_setAuthUID(); + $this->_ci->load->model('organisation/Gruppe_model', 'GruppeModel'); + $this->_ci->load->model('organisation/Lehrverband_model', 'LehrverbandModel'); + $this->_ci->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel'); + $this->_ci->load->model('person/Person_model', 'PersonModel'); + $this->_ci->load->model('ressource/stundenplandev_model', 'StundenplandevModel'); + } + + public function delete() + { + $lehreinheitgruppe_id = $this->input->post('lehreinheitgruppe_id'); + $lehreinheit_id = $this->input->post('lehreinheit_id'); + + if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id) || is_null($lehreinheitgruppe_id) || !ctype_digit((string)$lehreinheitgruppe_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $lehreinheitgruppe_result = $this->_ci->LehreinheitgruppeModel->loadWhere(array('lehreinheitgruppe_id' => $lehreinheitgruppe_id)); + if (!hasData($lehreinheitgruppe_result) || isError($lehreinheitgruppe_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $this->checkPermission($lehreinheit_id); + + $result = $this->_ci->LehreinheitgruppeModel->deleteGroup($lehreinheit_id, $lehreinheitgruppe_id); + + if (isError($result)) + $this->terminateWithError(getError($result)); + + $this->terminateWithSuccess($result); + } + + public function add() + { + $lehreinheit_id = $this->input->post('lehreinheit_id'); + $gid = $this->input->post('gid'); + $lehrverband = $this->input->post('lehrverband'); + + if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id) || is_null($gid) || !ctype_digit((string)$gid) || is_null($lehrverband)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $gruppe_result = $this->_ci->GruppeModel->loadWhere(array('gid' => $gid)); + if (!hasData($gruppe_result) || isError($gruppe_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $this->checkPermission($lehreinheit_id); + + $result = $this->_ci->LehreinheitgruppeModel->addGroup($lehreinheit_id, $gid, !($lehrverband === 'false')); + + if (isError($result)) + $this->terminateWithError(getError($result)); + + $this->terminateWithSuccess($result); + } + + public function getByLehreinheit($lehreinheit_id = null) + { + if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $this->checkPermission($lehreinheit_id); + + $gruppen = $this->_ci->LehreinheitgruppeModel->getByLehreinheit($lehreinheit_id); + $this->terminateWithSuccess(hasData($gruppen) ? getData($gruppen) : array()); + } + + public function deleteFromLVPlan() + { + $lehreinheit_id = $this->input->post('lehreinheit_id'); + $lehreinheitgruppe_id = $this->input->post('lehreinheitgruppe_id'); + + if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id) || is_null($lehreinheitgruppe_id) || !ctype_digit((string)$lehreinheitgruppe_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $lehreinheitgruppe_result = $this->_ci->LehreinheitgruppeModel->loadWhere(array('lehreinheitgruppe_id' => $lehreinheitgruppe_id)); + if (!hasData($lehreinheitgruppe_result) || isError($lehreinheitgruppe_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $this->checkPermission($lehreinheit_id); + + $result = $this->_ci->StundenplandevModel->deleteGroupPlanning($lehreinheit_id, $lehreinheitgruppe_id); + + if (isError($result)) + $this->terminateWithError(getError($result)); + + $this->terminateWithSuccess($result); + } + + + public function getAll() + { + $this->_ci->GruppeModel->addSelect('gruppe_kurzbz, + studiengang_kz, + semester, + bezeichnung, + gid, + \'false\' as lehrverband'); + $gruppen_result = $this->_ci->GruppeModel->loadWhere(array('sichtbar' => true, 'aktiv' => true, 'lehre' => true, 'direktinskription' => false)); + + $gruppen_array = array(); + + if (isError($gruppen_result)) + $this->terminateWithError(getError($gruppen_result), self::ERROR_TYPE_GENERAL); + + if (hasData($gruppen_result)) + $gruppen_array = getData($gruppen_result); + + $this->_ci->LehrverbandModel->addSelect('CONCAT(UPPER(CONCAT(typ, kurzbz)), \'\', semester, verband, COALESCE(gruppe,\'\')) as gruppe_kurzbz, + studiengang_kz, + semester, + tbl_lehrverband.bezeichnung, + gid, + \'true\' as lehrverband'); + $this->_ci->LehrverbandModel->addJoin('public.tbl_studiengang', 'studiengang_kz'); + $this->_ci->LehrverbandModel->addOrder('verband'); + $this->_ci->LehrverbandModel->addOrder('gruppe'); + $lehrverband_result = $this->_ci->LehrverbandModel->loadWhere(array('tbl_lehrverband.aktiv' => true)); + + $lehrverband_array = array(); + + if (isError($lehrverband_result)) + $this->terminateWithError(getError($lehrverband_result), self::ERROR_TYPE_GENERAL); + + if (hasData($lehrverband_result)) + $lehrverband_array = getData($lehrverband_result); + + $all_gruppen = array_merge($gruppen_array, $lehrverband_array); + + $this->terminateWithSuccess($all_gruppen); + } + + public function getBenutzer() + { + $this->_ci->PersonModel->addSelect('vorname, nachname, uid, semester, UPPER(CONCAT(tbl_studiengang.typ, tbl_studiengang.kurzbz)) as studiengang'); + $this->_ci->PersonModel->addJoin('public.tbl_benutzer', 'person_id'); + $this->_ci->PersonModel->addJoin('public.tbl_mitarbeiter', 'uid = mitarbeiter_uid', 'LEFT'); + $this->_ci->PersonModel->addJoin('public.tbl_student', 'uid = student_uid', 'LEFT'); + $this->_ci->PersonModel->addJoin('public.tbl_studiengang', 'studiengang_kz', 'LEFT'); + + $personen = $this->_ci->PersonModel->loadWhere(array('tbl_benutzer.aktiv' => true)); + $this->terminateWithSuccess(hasData($personen) ? getData($personen) : array()); + } + + private function _setAuthUID() + { + $this->_uid = getAuthUID(); + + if (!$this->_uid) + show_error('User authentification failed'); + } + + private function checkPermission($lehreinheit_id) + { + $lehreinheit_result = $this->_ci->LehreinheitModel->load($lehreinheit_id); + + if (!hasData($lehreinheit_result) || isError($lehreinheit_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $result = $this->_ci->LehreinheitModel->getOes($lehreinheit_id); + + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $oe_array = $result; + + if (!$this->_ci->permissionlib->isBerechtigtMultipleOe('admin', $oe_array, 'suid') && + !$this->_ci->permissionlib->isBerechtigtMultipleOe('assistenz', $oe_array, 'suid') && + !$this->_ci->permissionlib->isBerechtigtMultipleOe('lv-plan', $oe_array, 'suid')) + $this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess')); + } + +} diff --git a/application/controllers/api/frontend/v1/lv/Lehreinheit.php b/application/controllers/api/frontend/v1/lv/Lehreinheit.php new file mode 100644 index 000000000..84ee66d5d --- /dev/null +++ b/application/controllers/api/frontend/v1/lv/Lehreinheit.php @@ -0,0 +1,438 @@ + ['admin:rw', 'assistenz:rw'], + 'copy' => ['admin:rw', 'assistenz:rw'], + 'delete' => ['admin:rw', 'assistenz:rw'], + 'update' => ['admin:rw', 'assistenz:rw'], + + 'get' => ['admin:r', 'assistenz:r'], + 'getStudiensemester' => ['admin:r', 'assistenz:r'], + 'getLehrfach' => ['admin:r', 'assistenz:r'], + 'getSprache' => ['admin:r', 'assistenz:r'], + 'getRaumtyp' => ['admin:r', 'assistenz:r'], + 'getLehrform' => ['admin:r', 'assistenz:r'] + ]); + + $this->_ci = &get_instance(); + $this->_setAuthUID(); + $this->_ci->load->library('VariableLib', ['uid' => $this->_uid]); + $this->_ci->load->library('PhrasesLib'); + $this->loadPhrases( + array( + 'global', + 'ui' + ) + ); + + $this->_ci->load->model('education/Lehreinheit_model', 'LehreinheitModel'); + $this->_ci->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel'); + $this->_ci->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel'); + } + + public function get($lehreinheit_id) + { + $lehreinheit = $this->checkLehreinheit($lehreinheit_id); + $lehreinheit->lehrfaecher = $this->getLehrfaecher($lehreinheit); + $this->terminateWithSuccess($lehreinheit); + } + + private function getLehrfaecher($lehreinheit) + { + $lehrfacher_array = array($lehreinheit->lehrfach_id); + $this->_ci->LehreinheitModel->addSelect('lehrveranstaltung_id_kompatibel'); + $this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrveranstaltung_kompatibel', 'lehrveranstaltung_id'); + $lehrfaecher = $this->_ci->LehreinheitModel->loadWhere(array('lehrveranstaltung_id' => $lehreinheit->lehrveranstaltung_id)); + + + if (hasData($lehrfaecher)) + $lehrfaecher_array = array_merge($lehrfacher_array, array_column(getData($lehrfaecher), 'lehrveranstaltung_id_kompatibel')); + + $lehrfaecher_array[] = $lehreinheit->lehrveranstaltung_id; + + $this->_ci->LehrveranstaltungModel->addDistinct('lehrfach_id'); + $this->_ci->LehrveranstaltungModel->addSelect("tbl_lehrveranstaltung.lehrveranstaltung_id, CONCAT(tbl_lehrveranstaltung.bezeichnung || '(' || tbl_lehrveranstaltung.oe_kurzbz || ')') as lehrfach"); + $this->_ci->LehrveranstaltungModel->db->where_in('tbl_lehrveranstaltung.lehrveranstaltung_id', $lehrfaecher_array); + $lehrfaecher_result = $this->_ci->LehrveranstaltungModel->load(); + + return hasData($lehrfaecher_result) ? getData($lehrfaecher_result) : array(); + } + + public function add() + { + $lehrveranstaltung_id = $this->input->post('lehrveranstaltung_id'); + + if (is_null($lehrveranstaltung_id) || !ctype_digit((string)$lehrveranstaltung_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $lehrveranstaltung_result = $this->_ci->LehrveranstaltungModel->loadWhere(array('lehrveranstaltung_id' => $lehrveranstaltung_id)); + + if (!hasData($lehrveranstaltung_result) || isError($lehrveranstaltung_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $lehrveranstaltung = getData($lehrveranstaltung_result)[0]; + + $oe_result = $this->_ci->LehrveranstaltungModel->getAllOe($lehrveranstaltung->lehrveranstaltung_id, $lehrveranstaltung->studiengang_kz); + $oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array(); + + if (!$this->_ci->permissionlib->isBerechtigtMultipleOe('admin', $oe_array, 'suid') && + !$this->_ci->permissionlib->isBerechtigtMultipleOe('assistenz', $oe_array, 'suid') && + !$this->_ci->permissionlib->isBerechtigtMultipleOe('lv-plan', $oe_array, 'suid')) + $this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess')); + + $this->_ci->load->library('form_validation'); + + $updatableFields = array( + 'lehrveranstaltung_id', + 'studiensemester_kurzbz', + 'lehrfach_id', + 'lehrform_kurzbz', + 'stundenblockung', + 'wochenrythmus', + 'gewicht', + 'start_kw', + 'raumtyp', + 'raumtypalternativ', + 'sprache', + 'lehre', + 'anmerkung', + 'lvnr', + 'unr', + ); + + foreach ($updatableFields as $field) + { + switch ($field) { + case 'lehrveranstaltung_id': + $this->form_validation->set_rules($field, 'Lehrveranstaltung ID', 'required|integer'); + break; + case 'studiensemester_kurzbz': + $this->form_validation->set_rules($field, 'Studiensemester', 'required|max_length[16]'); + break; + case 'lehrfach_id': + $this->form_validation->set_rules($field, 'Lehrfach ID', 'required|integer'); + break; + case 'lehrform_kurzbz': + $this->form_validation->set_rules($field, 'Lehrform', 'required|max_length[8]'); + break; + case 'stundenblockung': + $this->form_validation->set_rules($field, 'Stundenblockung', 'required|integer|greater_than_equal_to[0]'); + break; + case 'wochenrythmus': + $this->form_validation->set_rules($field, 'Wochenrhytmus', 'required|integer|greater_than_equal_to[0]'); + break; + case 'start_kw': + $this->form_validation->set_rules($field, 'Start KW', 'integer|greater_than[0]|less_than_equal_to[53]'); + break; + case 'gewicht': + $this->form_validation->set_rules($field, 'Gewicht', 'numeric'); + break; + case 'raumtyp': + $this->form_validation->set_rules($field, 'Raumtyp', 'required|max_length[16]'); + break; + case 'raumtypalternativ': + $this->form_validation->set_rules($field, 'Raumtyp Alternativ', 'required|max_length[16]'); + break; + case 'sprache': + $this->form_validation->set_rules($field, 'Sprache', 'required|max_length[16]'); + break; + case 'lvnr': + $this->form_validation->set_rules($field, 'LVNR', 'integer'); + break; + case 'unr': + $this->form_validation->set_rules($field, 'UNR', 'integer'); + break; + case 'lehre': + $this->form_validation->set_rules($field, 'Lehre', 'trim'); + break; + case 'anmerkung': + $this->form_validation->set_rules($field, 'Anmerkung', 'trim'); + break; + } + } + + if ($this->form_validation->run() === false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + + $updateData = array(); + foreach ($updatableFields as $field) + { + $value = $this->input->post($field); + + if ($value !== null) + { + $updateData[$field] = $value; + } + } + + $updateData['insertvon'] = $this->_uid; + $updateData['insertamum'] = date('Y-m-d H:i:s'); + + $result = $this->_ci->LehreinheitModel->insert( + $updateData + ); + + $this->terminateWithSuccess($result); + } + + public function copy() + { + $lehreinheit_id = $this->input->post('lehreinheit_id'); + $art = $this->input->post('art'); + + $lehreinheit_old = $this->checkLehreinheit($lehreinheit_id); + $this->checkPermission($lehreinheit_old->lehreinheit_id); + + $lehreinheit_new = $lehreinheit_old; + + $lehreinheit_new->unr = null; + unset($lehreinheit_new->lehreinheit_id); + $lehreinheit_new->updateamum = date('Y-m-d H:i:s'); + $lehreinheit_new->updatevon = $this->_uid; + $lehreinheit_new->insertamum = date('Y-m-d H:i:s'); + $lehreinheit_new->insertvon = $this->_uid; + + $insert_result = $this->_ci->LehreinheitModel->insert($lehreinheit_new); + + if (isError($insert_result)) + $this->terminateWithError(getError($insert_result), self::ERROR_TYPE_GENERAL); + + $lehreinheit_id_new = getData($insert_result); + + if (in_array($art, array('gruppen', 'alle'))) + { + $gruppen_result = $this->_ci->LehreinheitgruppeModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + + if (isError($gruppen_result)) + $this->terminateWithError(getError($gruppen_result), self::ERROR_TYPE_GENERAL); + + if (hasData($gruppen_result)) + { + $gruppen = getData($gruppen_result); + + foreach ($gruppen as $gruppe) + { + $gruppe_new = $gruppe; + unset($gruppe_new->lehreinheitgruppe_id); + $gruppe_new->lehreinheit_id = $lehreinheit_id_new; + $gruppe_new->insertamum = date('Y-m-d H:i:s'); + $gruppe_new->insertvon = $this->_uid; + $gruppe_new->updateamum = date('Y-m-d H:i:s'); + $gruppe_new->updatevon = $this->_uid; + + $gruppe_new_result = $this->_ci->LehreinheitgruppeModel->insert($gruppe_new); + + if (isError($gruppe_new_result)) + $this->terminateWithError(getError($gruppe_new_result), self::ERROR_TYPE_GENERAL); + } + } + } + + if (in_array($art, array('lektoren', 'alle'))) + { + $lektoren_result = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + + if (isError($lektoren_result)) + $this->terminateWithError(getError($lektoren_result), self::ERROR_TYPE_GENERAL); + + if (hasData($lektoren_result)) + { + $lektoren = getData($lektoren_result); + + foreach ($lektoren as $lektor) + { + + $lektor_new = $lektor; + $lektor_new->lehreinheit_id = $lehreinheit_id_new; + $lektor_new->insertamum = date('Y-m-d H:i:s'); + $lektor_new->insertvon = $this->_uid; + $lektor_new->updateamum = date('Y-m-d H:i:s'); + $lektor_new->updatevon = $this->_uid; + unset($lektor_new->vertrag_id); + + $lektor_new_result = $this->_ci->LehreinheitmitarbeiterModel->insert((array)$lektor_new); + + if (isError($lektor_new_result)) + $this->terminateWithError(getError($lektor_new_result), self::ERROR_TYPE_GENERAL); + } + } + } + + $this->terminateWithSuccess("Erfolgeich gespeichert"); + } + + public function delete() + { + $lehreinheit_id = $this->input->post('lehreinheit_id'); + $lehreinheit = $this->checkLehreinheit($lehreinheit_id); + $this->checkPermission($lehreinheit->lehreinheit_id); + + $result = $this->_ci->LehreinheitModel->deleteLehreinheit($lehreinheit->lehreinheit_id); + + if (isError($result)) + $this->terminateWithValidationErrors(getError($result)); + + $this->terminateWithSuccess('Erfolgreich geloescht'); + } + + public function update() + { + $lehreinheit = $this->checkLehreinheit($this->input->post('lehreinheit_id')); + + $this->checkPermission($lehreinheit->lehreinheit_id); + + $this->_ci->load->library('form_validation'); + + $formData = $this->input->post('formData'); + + $updatableFields = array( + 'lehrveranstaltung_id', + 'studiensemester_kurzbz', + 'lehrfach_id', + 'lehrform_kurzbz', + 'stundenblockung', + 'wochenrythmus', + 'gewicht', + 'start_kw', + 'raumtyp', + 'raumtypalternativ', + 'sprache', + 'lehre', + 'anmerkung', + 'lvnr', + 'unr', + ); + + $this->form_validation->set_data($formData); + + foreach ($updatableFields as $field) + { + if (array_key_exists($field, $formData)) + { + switch ($field) + { + case 'lehrveranstaltung_id': + $this->form_validation->set_rules($field, 'Lehrveranstaltung ID', 'required|integer'); + break; + case 'studiensemester_kurzbz': + $this->form_validation->set_rules($field, 'Studiensemester', 'required|max_length[16]'); + break; + case 'lehrfach_id': + $this->form_validation->set_rules($field, 'Lehrfach ID', 'required|integer'); + break; + case 'lehrform_kurzbz': + $this->form_validation->set_rules($field, 'Lehrform', 'required|max_length[8]'); + break; + case 'stundenblockung': + $this->form_validation->set_rules($field, 'Stundenblockung', 'required|integer|greater_than_equal_to[0]'); + break; + case 'wochenrythmus': + $this->form_validation->set_rules($field, 'Wochenrhytmus', 'required|integer|greater_than_equal_to[0]'); + break; + case 'start_kw': + $this->form_validation->set_rules($field, 'Start KW', 'integer|greater_than[0]|less_than_equal_to[53]'); + break; + case 'gewicht': + $this->form_validation->set_rules($field, 'Gewicht', 'numeric'); + break; + case 'raumtyp': + $this->form_validation->set_rules($field, 'Raumtyp', 'required|max_length[16]'); + break; + case 'raumtypalternativ': + $this->form_validation->set_rules($field, 'Raumtyp Alternativ', 'required|max_length[16]'); + break; + case 'sprache': + $this->form_validation->set_rules($field, 'Sprache', 'required|max_length[16]'); + break; + case 'lvnr': + $this->form_validation->set_rules($field, 'LVNR', 'integer'); + break; + case 'unr': + $this->form_validation->set_rules($field, 'UNR', 'integer'); + break; + case 'lehre': + $this->form_validation->set_rules($field, 'Lehre', 'trim'); + break; + case 'anmerkung': + $this->form_validation->set_rules($field, 'Anmerkung', 'trim'); + break; + } + } + } + + if ($this->form_validation->run() === false) + { + $this->terminateWithValidationErrors($this->form_validation->error_array()); + } + + $updateData = []; + foreach ($updatableFields as $field) + { + if (array_key_exists($field, $formData)) + { + $updateData[$field] = $formData[$field]; + } + } + + + $updateData['updatevon'] = $this->_uid; + $updateData['updateamum'] = date('Y-m-d H:i:s'); + $result = $this->_ci->LehreinheitModel->update( + [ + 'lehreinheit_id' => $this->input->post('lehreinheit_id'), + ], + $updateData + ); + + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $this->terminateWithSuccess($this->p->t('global', 'gespeichert')); + } + + + private function checkPermission($lehreinheit_id) + { + $result = $this->_ci->LehreinheitModel->getOes($lehreinheit_id); + + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + $oe_array = $result; + + if (!$this->_ci->permissionlib->isBerechtigtMultipleOe('admin', $oe_array, 'suid') && + !$this->_ci->permissionlib->isBerechtigtMultipleOe('assistenz', $oe_array, 'suid') && + !$this->_ci->permissionlib->isBerechtigtMultipleOe('lv-plan', $oe_array, 'suid')) + $this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess')); + } + private function checkLehreinheit($lehreinheit_id) + { + if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $lehreinheit_result = $this->_ci->LehreinheitModel->load($lehreinheit_id); + + if (!hasData($lehreinheit_result) || isError($lehreinheit_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + return getData($lehreinheit_result)[0]; + } + + private function _setAuthUID() + { + $this->_uid = getAuthUID(); + + if (!$this->_uid) + show_error('User authentification failed'); + } +} diff --git a/application/controllers/api/frontend/v1/lv/Lektor.php b/application/controllers/api/frontend/v1/lv/Lektor.php new file mode 100644 index 000000000..332bc47b6 --- /dev/null +++ b/application/controllers/api/frontend/v1/lv/Lektor.php @@ -0,0 +1,380 @@ + ['admin:rw', 'assistenz:rw'], + 'update' => ['admin:rw', 'assistenz:rw'], + 'cancelVertrag' => ['admin:rw', 'assistenz:rw'], + 'deleteLVPlan' => ['admin:rw', 'assistenz:rw'], + 'deletePerson' => ['admin:rw', 'assistenz:rw'], + 'getLehrfunktionen' => ['admin:r', 'assistenz:r'], + 'getLektoren' => ['admin:r', 'assistenz:r'], + 'getLektorenByLE' => ['admin:r', 'assistenz:r'], + 'getLektorDaten' => ['admin:r', 'assistenz:r'], + 'getLektorVertrag' => ['admin:r', 'assistenz:r'], + + ]); + + $this->_ci = &get_instance(); + $this->_setAuthUID(); + $this->_ci->load->library('VariableLib', ['uid' => $this->_uid]); + $this->_ci->load->library('PermissionLib'); + $this->_ci->load->library('LektorLib'); + $this->_ci->load->library('form_validation'); + $this->loadPhrases([ + 'ui' + ]); + + $this->_ci->load->model('accounting/Vertrag_model', 'VertragModel'); + $this->_ci->load->model('ressource/Mitarbeiter_model', 'MitarbeiterModel'); + $this->_ci->load->model('education/lehreinheit_model', 'LehreinheitModel'); + $this->_ci->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel'); + $this->_ci->load->model('ressource/stundenplandev_model', 'StundenplandevModel'); + $this->_ci->load->model('ressource/Stundensatz_model', 'StundensatzModel'); + + } + + private function checkMitarbeiter($mitarbeiter_uid) + { + if (is_null($mitarbeiter_uid)) + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $mitarbeiter_result = $this->_ci->MitarbeiterModel->load($mitarbeiter_uid); + + if (!hasData($mitarbeiter_result) || isError($mitarbeiter_result)) + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + } + + public function add() + { + $lehreinheit_id = $this->input->post('lehreinheit_id'); + $mitarbeiter_uid = $this->input->post('mitarbeiter_uid'); + + $this->checkLehreinheit($lehreinheit_id); + $this->checkMitarbeiter($mitarbeiter_uid); + $lehrfach_permission = $this->checkLehrfachPermission($lehreinheit_id, array('assistenz', 'admin')); + $lehreinheit_permission = $this->checkPermission($lehreinheit_id, array('admin', 'assistenz', 'lv-plan')); + + if (!$lehrfach_permission && !$lehreinheit_permission) + $this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess')); + + $result = $this->_ci->lektorlib->addLektorToLehreinheit($lehreinheit_id, $mitarbeiter_uid); + + if (isError($result)) $this->terminateWithError(getError($result)); + + $this->terminateWithSuccess("Erfolgreich gespeichert"); + } + + public function update() + { + $formData = $this->input->post('formData'); + $lehreinheit_id = $this->input->post('lehreinheit_id'); + $mitarbeiter_uid = $this->input->post('mitarbeiter_uid'); + + $this->checkLehreinheit($lehreinheit_id); + $this->checkMitarbeiter($mitarbeiter_uid); + + $updatableFields = array( + 'lehrfunktion_kurzbz', + 'planstunden', + 'stundensatz', + 'faktor', + 'anmerkung', + 'bismelden', + 'semesterstunden', + 'mitarbeiter_uid' + ); + + $this->form_validation->set_data($formData); + + foreach ($updatableFields as $field) + { + if (array_key_exists($field, $formData)) + { + switch ($field) + { + case 'lehrfunktion_kurzbz': + $this->form_validation->set_rules($field, 'Lehrfunktion', 'required|max_length[16]'); + break; + case 'planstunden': + $this->form_validation->set_rules($field, 'Planstunden', 'integer|greater_than_equal_to[0]'); + break; + case 'stundensatz': + $this->form_validation->set_rules($field, 'Stundensatz', 'numeric|greater_than_equal_to[0]'); + break; + case 'faktor': + $this->form_validation->set_rules($field, 'Faktor', 'numeric|greater_than_equal_to[0]'); + break; + case 'anmerkung': + $this->form_validation->set_rules($field, 'Anmerkung', 'max_length[256]'); + break; + case 'bismelden': + $this->form_validation->set_rules($field, 'Bis Melden', 'trim'); + break; + case 'semesterstunden': + $this->form_validation->set_rules($field, 'Semesterstunden', 'callback__check_semesterstunden'); + break; + case 'mitarbeiter_uid': + $this->form_validation->set_rules($field, 'Semesterstunden', 'required|max_length[32]'); + break; + } + } + } + if (!$this->form_validation->run()) + { + $this->terminateWithError($this->form_validation->error_array()); + } + + if (isset($formData['semesterstunden']) && (!is_numeric($formData['semesterstunden']) || $formData['semesterstunden'] === '')) + { + $formData['semesterstunden'] = null; + } + + $lehreinheit_permission = $this->checkPermission($lehreinheit_id, array('admin', 'assistenz', 'lv-plan')); + + if (!$lehreinheit_permission) + $this->terminateWithError($this->p->t('ui', 'error_fieldWriteAccess')); + + $result = $this->_ci->lektorlib->updateLektorFromLehreinheit($lehreinheit_id, $mitarbeiter_uid, $formData); + + if (isError($result)) $this->terminateWithError(getError($result)); + $this->terminateWithSuccess("Erfolgreich geupdated"); + } + + public function _check_semesterstunden($value) + { + if ($value === null || $value === '') { + return true; + } + + if (!is_numeric($value)) + { + $this->form_validation->set_message( + '_check_semesterstunden', + 'Das Feld {field} muss eine Zahl sein.' + ); + return false; + } + + if ($value < 0) + { + $this->form_validation->set_message( + '_check_semesterstunden', + 'Das Feld {field} muss eine Zahl größer oder gleich 0 sein.' + ); + return false; + } + + return true; + } + public function getLehrfunktionen() + { + $this->_ci->load->model('education/Lehrfunktion_model', 'LehrfunktionModel'); + $this->_ci->LehrfunktionModel->addOrder('lehrfunktion_kurzbz'); + $this->terminateWithSuccess(getData($this->_ci->LehrfunktionModel->load())); + } + + public function getLektoren() + { + $this->_ci->MitarbeiterModel->addSelect('uid, person_id, vorname, nachname'); + $this->_ci->MitarbeiterModel->addJoin('public.tbl_benutzer', 'uid = mitarbeiter_uid'); + $this->_ci->MitarbeiterModel->addJoin('public.tbl_person', 'person_id'); + $this->terminateWithSuccess(getData($this->_ci->MitarbeiterModel->loadWhere(array('public.tbl_benutzer.aktiv' => true)))); + } + + private function checkLehreinheit($lehreinheit_id) + { + if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $lehreinheit_result = $this->_ci->LehreinheitModel->load($lehreinheit_id); + + if (!hasData($lehreinheit_result) || isError($lehreinheit_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + return getData($lehreinheit_result)[0]; + + } + public function getLektorenByLE($lehreinheit_id = null) + { + $this->checkLehreinheit($lehreinheit_id); + $le_mitarbeiter_data = $this->_ci->LehreinheitmitarbeiterModel->getLektorenByLe($lehreinheit_id); + $this->terminateWithSuccess(hasData($le_mitarbeiter_data) ? getData($le_mitarbeiter_data) : array()); + } + + public function getLektorDaten($lehreinheit_id = null, $mitarbeiter_uid = null) + { + $lehreinheit = $this->checkLehreinheit($lehreinheit_id); + + if (is_null($mitarbeiter_uid)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $mitarbeiter_result = $this->_ci->MitarbeiterModel->load($mitarbeiter_uid); + + if (!hasData($mitarbeiter_result) || isError($mitarbeiter_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $this->load->model('organisation/Studiensemester_model','StudiensemesterModel'); + $studiensemester_result = $this->_ci->StudiensemesterModel->loadWhere(array('studiensemester_kurzbz' => $lehreinheit->studiensemester_kurzbz)); + $studiensemester = getData($studiensemester_result)[0]; + + $defaultStundensatz = $this->_ci->StundensatzModel->getDefaultStundensatz($mitarbeiter_uid, $studiensemester->start, $studiensemester->ende, 'lehre'); + + $le_mitarbeiter_result = $this->_ci->LehreinheitmitarbeiterModel->getByLeLektor($lehreinheit_id, $mitarbeiter_uid); + + $le_mitarbeiter_data = array(); + if (hasData($le_mitarbeiter_result)) + { + $le_mitarbeiter_data = getData($le_mitarbeiter_result)[0]; + $le_mitarbeiter_data->default_stundensatz = $defaultStundensatz; + } + $vertrag = $this->getLektorVertrag($lehreinheit_id, $mitarbeiter_uid); + $le_mitarbeiter_data->vertrag = $vertrag; + $this->terminateWithSuccess($le_mitarbeiter_data); + } + + private function getLektorVertrag($lehreinheit_id = null, $mitarbeiter_uid = null) + { + $this->_ci->load->model('accounting/Vertrag_model', 'VertragModel'); + $vertrag = $this->_ci->VertragModel->getVertrag($mitarbeiter_uid, $lehreinheit_id); + return hasData($vertrag) ? getData($vertrag)[0] : null; + } + + private function checkLehrfachPermission($lehreinheit_id, $permissions) + { + $lehrfach_oe_kurzbz = $this->_ci->LehreinheitModel->getLehrfachOe($lehreinheit_id); + + if (isError($lehrfach_oe_kurzbz)) + $this->terminateWithError(getError($lehrfach_oe_kurzbz), self::ERROR_TYPE_GENERAL); + + $lehrfach_oe_kurzbz = array(''); + if (hasData($lehrfach_oe_kurzbz)) + $lehrfach_oe_kurzbz = array_column(getData($lehrfach_oe_kurzbz), 'oe_kurzbz'); + + + return $this->checkPermissionGenerel($permissions, $lehrfach_oe_kurzbz); + } + + private function checkPermissionGenerel($permissions, $oe_array) + { + $hasPermission = false; + foreach ($permissions as $permission) + { + if ($this->_ci->permissionlib->isBerechtigtMultipleOe($permission, $oe_array, 'suid')) + { + $hasPermission = true; + break; + } + } + + return $hasPermission; + } + + private function checkPermission($lehreinheit_id, $permissions) + { + $result = $this->_ci->LehreinheitModel->getOes($lehreinheit_id); + + if (isError($result)) + $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + + $oe_array = $result; + + return $this->checkPermissionGenerel($permissions, $oe_array); + } + public function cancelVertrag() + { + $vertrag_id = $this->input->post('vertrag_id'); + $lehreinheit_id = $this->input->post('lehreinheit_id'); + $mitarbeiter_uid = $this->input->post('mitarbeiter_uid'); + + $this->checkLehreinheit($lehreinheit_id); + $this->checkPermission($lehreinheit_id, array('admin', 'lehre/lehrauftrag_bestellen')); + + if (is_null($vertrag_id) || !ctype_digit((string)$vertrag_id)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $vertrag_result = $this->_ci->VertragModel->load($vertrag_id); + + if (!hasData($vertrag_result) || isError($vertrag_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + if (is_null($mitarbeiter_uid)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $mitarbeiter_result = $this->_ci->MitarbeiterModel->load($mitarbeiter_uid); + + if (!hasData($mitarbeiter_result) || isError($mitarbeiter_result)) + $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $result = $this->_ci->VertragModel->cancelVertrag($vertrag_id, $mitarbeiter_uid); + + if (isError($result)) + $this->terminateWithError(getError($result)); + + $this->terminateWithSuccess($result); + } + + public function deletePerson() + { + $lehreinheit_id = $this->input->post('lehreinheit_id'); + $mitarbeiter_uid = $this->input->post('mitarbeiter_uid'); + + $this->checkLehreinheit($lehreinheit_id); + $this->checkPermission($lehreinheit_id, array('admin', 'assistenz', 'lv-plan')); + + if (is_null($mitarbeiter_uid)) + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $mitarbeiter_result = $this->_ci->MitarbeiterModel->load($mitarbeiter_uid); + + if (!hasData($mitarbeiter_result) || isError($mitarbeiter_result)) + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $delete_result =$this->_ci->LehreinheitmitarbeiterModel->deleteLektorFromLe($lehreinheit_id, $mitarbeiter_uid); + + if (isError($delete_result)) + $this->terminateWithError(getError($delete_result)); + + $this->terminateWithSuccess($delete_result); + } + + public function deleteLVPlan() + { + $lehreinheit_id = $this->input->post('lehreinheit_id'); + $mitarbeiter_uid = $this->input->post('mitarbeiter_uid'); + + $this->checkLehreinheit($lehreinheit_id); + $this->checkPermission($lehreinheit_id, array('lv-plan/lektorentfernen')); + + if (is_null($mitarbeiter_uid)) + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + $mitarbeiter_result = $this->_ci->MitarbeiterModel->load($mitarbeiter_uid); + + if (!hasData($mitarbeiter_result) || isError($mitarbeiter_result)) + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + + + $delete_result = $this->_ci->StundenplandevModel->deleteLektorPlanning($lehreinheit_id, $mitarbeiter_uid); + + if (isError($delete_result)) + $this->terminateWithError(getError($delete_result)); + + $this->terminateWithSuccess($delete_result); + } + + private function _setAuthUID() + { + $this->_uid = getAuthUID(); + + if (!$this->_uid) + show_error('User authentification failed'); + } +} diff --git a/application/controllers/api/frontend/v1/lv/Setup.php b/application/controllers/api/frontend/v1/lv/Setup.php new file mode 100644 index 000000000..cf73697a7 --- /dev/null +++ b/application/controllers/api/frontend/v1/lv/Setup.php @@ -0,0 +1,116 @@ +. + */ + +if (!defined('BASEPATH')) + exit('No direct script access allowed'); + +class Setup extends FHCAPI_Controller +{ + private $_ci; + private $_uid; + + public function __construct() + { + parent::__construct([ + 'getTabs' => ['admin:r', 'assistenz:r'], + 'getStudiensemester' => ['admin:r', 'assistenz:r'], + 'getSprache' => ['admin:r', 'assistenz:r'], + 'getRaumtyp' => ['admin:r', 'assistenz:r'], + 'getLehrform' => ['admin:r', 'assistenz:r'], + ]); + + $this->_ci = &get_instance(); + $this->_setAuthUID(); + + $this->_ci->load->model('education/Lehreinheit_model', 'LehreinheitModel'); + $this->_ci->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); + + $this->_ci->load->library('VariableLib', ['uid' => $this->_uid]); + } + + public function getTabs() + { + $tabs['details'] = array ( + 'title' => 'Details', + 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Details.js', + 'config' => [] + ); + $tabs['lektor'] = array ( + 'title' => 'LektorInnenzuteilung', + 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Lektor.js', + 'config' => [] + ); + $tabs['notiz'] = array ( + 'title' => 'Notizen', + 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Notiz.js', + 'config' => [] + ); + $this->terminateWithSuccess($tabs); + } + + public function getStudiensemester() + { + $this->_ci->load->model('organisation/Studiensemester_model', 'StudiensemesterModel'); + $this->_ci->StudiensemesterModel->addOrder('start', 'DESC'); + $this->terminateWithSuccess(getData($this->_ci->StudiensemesterModel->load())); + } + public function getSprache() + { + $this->_ci->load->model('system/Sprache_model', 'SpracheModel'); + $this->terminateWithSuccess(getData($this->_ci->SpracheModel->load())); + } + + public function getRaumtyp() + { + $this->_ci->load->model('ressource/Raumtyp_model', 'RaumtypModel'); + $this->_ci->RaumtypModel->addOrder('raumtyp_kurzbz'); + $this->terminateWithSuccess(getData($this->_ci->RaumtypModel->loadWhere(array('aktiv' => true)))); + } + + public function getLehrform() + { + $language = $this->_getLanguageIndex(); + + $this->_ci->load->model('codex/lehrform_model', 'LehrformModel'); + + $this->_ci->LehrformModel->addSelect( + '*, + bezeichnung_kurz[('.$language.')] as bez_kurz, + bezeichnung_lang[('.$language.')] as bez + ' + ); + $this->terminateWithSuccess(getData($this->_ci->LehrformModel->load())); + } + + private function _getLanguageIndex() + { + $this->_ci->load->model('system/Sprache_model', 'SpracheModel'); + $this->_ci->SpracheModel->addSelect('index'); + $result = $this->_ci->SpracheModel->loadWhere(array('sprache' => getUserLanguage())); + + return hasData($result) ? getData($result)[0]->index : 1; + } + + private function _setAuthUID() + { + $this->_uid = getAuthUID(); + + if (!$this->_uid) + show_error('User authentification failed'); + } +} diff --git a/application/controllers/api/frontend/v1/lv/StgTree.php b/application/controllers/api/frontend/v1/lv/StgTree.php new file mode 100644 index 000000000..fe3047902 --- /dev/null +++ b/application/controllers/api/frontend/v1/lv/StgTree.php @@ -0,0 +1,91 @@ +method] = ['admin:r', 'assistenz:r']; + parent::__construct($permissions); + + $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); + } + + public function _remap($method, $params = []) + { + if ($method == '' || $method == 'index') + return $this->getBase(); + + if (!$this->permissionlib->isBerechtigt('assistenz', 's', $method) + && !$this->permissionlib->isBerechtigt('admin', 's', $method) + ) { + return $this->_outputAuthError([$method => ['admin:r', 'assistenz:r']]); + } + + return $this->getStudiengang($method); + show_404(); + } + + protected function getBase() + { + $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); + + $this->StudiengangModel->addDistinct(); + $this->StudiengangModel->addSelect("v.studiengang_kz AS link"); + $this->StudiengangModel->addSelect( + "CONCAT(kurzbzlang, ' (', UPPER(CONCAT(typ, kurzbz)), ') - ', tbl_studiengang.bezeichnung) AS name", + false + ); + $this->StudiengangModel->addSelect('erhalter_kz'); + $this->StudiengangModel->addSelect('typ'); + $this->StudiengangModel->addSelect('kurzbz'); + $this->StudiengangModel->addSelect('studiengang_kz'); + $this->StudiengangModel->addSelect('studiengang_kz AS stg_kz'); + + $this->StudiengangModel->addOrder('erhalter_kz'); + $this->StudiengangModel->addOrder('typ'); + $this->StudiengangModel->addOrder('kurzbz'); + + $stgs = $this->permissionlib->getSTG_isEntitledFor('admin') ?: []; + $stgs = array_merge($stgs, $this->permissionlib->getSTG_isEntitledFor('assistenz') ?: []); + + if (!$stgs) + $this->terminateWithSuccess([]); + + $this->StudiengangModel->db->where_in('studiengang_kz', $stgs); + + $result = $this->StudiengangModel->loadWhere(['v.aktiv' => true]); + + $list = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($list); + } + + protected function getStudiengang($studiengang_kz) + { + $link = $studiengang_kz . '/'; + + $this->StudiengangModel->addJoin('public.tbl_lehrverband v', 'studiengang_kz'); + + $this->StudiengangModel->addDistinct(); + $this->StudiengangModel->addSelect("CONCAT(" . $this->StudiengangModel->escape($link) . ", semester) AS link", false); + $this->StudiengangModel->addSelect("CONCAT(UPPER(CONCAT(typ, kurzbz)), '-', semester, (SELECT CASE WHEN bezeichnung IS NULL OR bezeichnung='' THEN ''::TEXT ELSE CONCAT(' (', bezeichnung, ')') END FROM public.tbl_lehrverband WHERE studiengang_kz=v.studiengang_kz AND semester=v.semester ORDER BY verband, gruppe LIMIT 1)) AS name", false); + $this->StudiengangModel->addSelect("TRUE AS leaf", false); + + $this->StudiengangModel->addSelect('semester'); + $this->StudiengangModel->addSelect($this->StudiengangModel->escape($studiengang_kz) . '::integer AS stg_kz', false); + + $this->StudiengangModel->addOrder('semester'); + + $result = $this->StudiengangModel->loadWhere([ + 'v.studiengang_kz' => $studiengang_kz, + 'v.aktiv' => true + ]); + $list = $this->getDataOrTerminateWithError($result); + + $this->terminateWithSuccess($list); + } +} diff --git a/application/controllers/api/frontend/v1/lv/Tags.php b/application/controllers/api/frontend/v1/lv/Tags.php new file mode 100644 index 000000000..234ab3cba --- /dev/null +++ b/application/controllers/api/frontend/v1/lv/Tags.php @@ -0,0 +1,24 @@ + self::BERECHTIGUNG_KURZBZ, + 'getTags' => self::BERECHTIGUNG_KURZBZ, + 'addTag' => self::BERECHTIGUNG_KURZBZ, + 'updateTag' => self::BERECHTIGUNG_KURZBZ, + 'doneTag' => self::BERECHTIGUNG_KURZBZ, + 'deleteTag' => self::BERECHTIGUNG_KURZBZ, + 'updateLehre' => self::BERECHTIGUNG_KURZBZ, + 'doneLehre' => self::BERECHTIGUNG_KURZBZ, + 'deleteLehre' => self::BERECHTIGUNG_KURZBZ, + ]); + } +} \ No newline at end of file diff --git a/application/controllers/api/frontend/v1/notiz/NotizLehreinheit.php b/application/controllers/api/frontend/v1/notiz/NotizLehreinheit.php new file mode 100644 index 000000000..f8e1f816b --- /dev/null +++ b/application/controllers/api/frontend/v1/notiz/NotizLehreinheit.php @@ -0,0 +1,21 @@ + ['admin:r', 'assistenz:r'], + 'getNotizen' => ['admin:r', 'assistenz:r'], + 'loadNotiz' => ['admin:r', 'assistenz:r'], + 'addNewNotiz' => ['admin:rw', 'assistenz:rw'], + 'updateNotiz' => ['admin:rw', 'assistenz:rw'], + 'deleteNotiz' => ['admin:rw', 'assistenz:rw'], + 'loadDokumente' => ['admin:r', 'assistenz:r'], + 'getMitarbeiter' => ['admin:r', 'assistenz:r'], + 'isBerechtigt' => ['admin:r', 'assistenz:r'], + ]); + } +} \ No newline at end of file diff --git a/application/libraries/LektorLib.php b/application/libraries/LektorLib.php new file mode 100644 index 000000000..44c71cdaa --- /dev/null +++ b/application/libraries/LektorLib.php @@ -0,0 +1,342 @@ +_ci =& get_instance(); + $this->_ci->load->model('education/lehreinheit_model', 'LehreinheitModel'); + $this->_ci->load->model('education/Lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel'); + $this->_ci->load->model('organisation/Studiensemester_model','StudiensemesterModel'); + $this->_ci->load->model('ressource/Stundensatz_model', 'StundensatzModel'); + $this->_ci->load->model('vertragsbestandteil/Dienstverhaeltnis_model','DienstverhaeltnisModel'); + $this->_ci->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel'); + $this->_ci->load->model('ressource/mitarbeiter_model', 'MitarbeiterModel'); + $this->_ci->load->model('person/Benutzer_model', 'BenutzerModel'); + } + + public function addLektorToLehreinheit($lehreinheit_id, $mitarbeiter_uid) + { + $this->_ci->LehreinheitModel->addSelect('tbl_lehreinheit.*, tbl_lehrveranstaltung.studiengang_kz, semesterstunden'); + $this->_ci->LehreinheitModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id'); + $lehreinheit_result = $this->_ci->LehreinheitModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + + if (isError($lehreinheit_result)) return $lehreinheit_result; + + if (!hasData($lehreinheit_result)) return error("Lehreinheit not found"); + + $lehreinheit = getData($lehreinheit_result)[0]; + + $already_assigned = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit->lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); + + if (isError($already_assigned)) return $already_assigned; + + if (hasData($already_assigned)) return error('Lektor already assigned'); + + $studiensemester_result = $this->_ci->StudiensemesterModel->loadWhere(array('studiensemester_kurzbz' => $lehreinheit->studiensemester_kurzbz)); + if (isError($studiensemester_result)) return $studiensemester_result; + $studiensemester = getData($studiensemester_result)[0]; + + $stundensatz = $this->_ci->StundensatzModel->getDefaultStundensatz($mitarbeiter_uid, $studiensemester->start, $studiensemester->ende, 'lehre'); + $echter_dv_result = $this->_ci->DienstverhaeltnisModel->existsDienstverhaeltnis($mitarbeiter_uid, $studiensemester->start, $studiensemester->ende, 'echterdv'); + + $echter_dv = false; + + if (hasData($echter_dv_result)) + { + $echter_dv = true; + } + + $maxstunden = $this->getMaxStunden($mitarbeiter_uid, $studiensemester->studiensemester_kurzbz, $lehreinheit->studiengang_kz, $echter_dv); + + $newData['semesterstunden'] = 0; + $newData['planstunden'] = 0; + if (!is_null($lehreinheit->semesterstunden)) + { + $newData['semesterstunden'] = min($lehreinheit->semesterstunden, $maxstunden); + $newData['planstunden'] = min($lehreinheit->semesterstunden, $maxstunden); + } + + $newData['lehreinheit_id'] = $lehreinheit->lehreinheit_id; + $newData['mitarbeiter_uid'] = $mitarbeiter_uid; + $newData['lehrfunktion_kurzbz'] = 'Lektor'; + $newData['bismelden'] = true; + $newData['insertvon'] = getAuthUID(); + $newData['insertamum'] = date('Y-m-d H:i:s'); + $newData['stundensatz'] = $stundensatz; + $result = $this->_ci->LehreinheitmitarbeiterModel->insert($newData); + + if (isError($result)) return $result; + + return success("Lektor added successfully"); + } + + public function updateLektorFromLehreinheit($lehreinheit_id, $mitarbeiter_uid, $new_data) + { + $this->_ci->LehreinheitmitarbeiterModel->addSelect('lehre.tbl_lehreinheitmitarbeiter.*, lehre.tbl_lehreinheit.studiensemester_kurzbz, tbl_lehrveranstaltung.studiengang_kz'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id'); + $lehreinheit_result = $this->_ci->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); + + if (isError($lehreinheit_result)) return $lehreinheit_result; + + if (!hasData($lehreinheit_result)) return error("Lehreinheit not found"); + + $lehreinheit = getData($lehreinheit_result)[0]; + + //TODO kollision check, wird vorerst nicht implementiert -> nur über das FAS möglich + if (isset($new_data['mitarbeiter_uid']) && $new_data['mitarbeiter_uid'] !== $mitarbeiter_uid) + { + $this->_ci->load->model('ressource/stundenplandev_model', 'StundenplandevModel'); + $this->_ci->StundenplandevModel->addGroupBy('stundenplandev_id'); + $this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid'); + $this->_ci->StundenplandevModel->addGroupBy('mitarbeiter_uid'); + $verplant = $this->_ci->StundenplandevModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); + + if (hasData($verplant)) + return error('Wechsel vom Mitarbeiter nicht möglich da er bereits verplant ist!'); + } + $warning = ''; + if (isset($new_data['semesterstunden'])) + { + $studiengang_result = $this->_ci->StudiengangModel->loadWhere(array('studiengang_kz' => $lehreinheit->studiengang_kz)); + if (isError($studiengang_result)) return $studiengang_result; + if (!hasData($studiengang_result)) return error('Studiengang not found'); + $studiengang = getData($studiengang_result)[0]; + + $studiensemester_result = $this->_ci->StudiensemesterModel->loadWhere(array('studiensemester_kurzbz' => $lehreinheit->studiensemester_kurzbz)); + if (isError($studiensemester_result)) return $studiensemester_result; + $studiensemester = getData($studiensemester_result)[0]; + + $echter_dv_result = $this->_ci->DienstverhaeltnisModel->existsDienstverhaeltnis($mitarbeiter_uid, $studiensemester->start, $studiensemester->ende, 'echterdv'); + + $echter_dv = false; + + if (hasData($echter_dv_result)) + { + $echter_dv = true; + } + + $neue_stunden_eingerechnet = isset($new_data['bismelden']) ? $new_data['bismelden'] : $lehreinheit->bismelden; + $alte_stunden_eingerechnet = $lehreinheit->bismelden; + + if (($new_data['semesterstunden'] > $lehreinheit->semesterstunden) || $neue_stunden_eingerechnet) + { + $stundengrenze_result = $this->_ci->OrganisationseinheitModel->getStundengrenze($studiengang->oe_kurzbz, $echter_dv); + if (isError($stundengrenze_result)) return $stundengrenze_result; + + $stundengrenze = getData($stundengrenze_result)[0]; + + $oe_result = $this->_ci->OrganisationseinheitModel->getChilds($stundengrenze->oe_kurzbz); + $oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array(''); + + if ($alte_stunden_eingerechnet && $neue_stunden_eingerechnet) + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($lehreinheit->semesterstunden) + {$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])}) as summe"); + else if ($alte_stunden_eingerechnet && !$neue_stunden_eingerechnet) + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) - ($lehreinheit->semesterstunden)) as summe"); + else if (!$alte_stunden_eingerechnet && $neue_stunden_eingerechnet) + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden) + ({$this->_ci->LehreinheitmitarbeiterModel->db->escape($new_data['semesterstunden'])})) as summe"); + else if (!$alte_stunden_eingerechnet && !$neue_stunden_eingerechnet) + $this->_ci->LehreinheitmitarbeiterModel->addSelect("(SUM(tbl_lehreinheitmitarbeiter.semesterstunden)) as summe"); + + $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('public.tbl_studiengang', 'studiengang_kz'); + + $this->_ci->LehreinheitmitarbeiterModel->db->where('mitarbeiter_uid', (isset($new_data['mitarbeiter_uid']) ? $new_data['mitarbeiter_uid'] : $mitarbeiter_uid)); + $this->_ci->LehreinheitmitarbeiterModel->db->where('studiensemester_kurzbz', $lehreinheit->studiensemester_kurzbz); + $this->_ci->LehreinheitmitarbeiterModel->db->where('bismelden', true); + $this->_ci->LehreinheitmitarbeiterModel->db->where('lower(mitarbeiter_uid) NOT LIKE', '_dummy%'); + + $this->_ci->LehreinheitmitarbeiterModel->db->where_in('tbl_studiengang.oe_kurzbz', $oe_array); + + + if(defined('FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE') + && is_array(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) + && count(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) > 0) + { + $this->_ci->LehreinheitmitarbeiterModel->db->where_not_in('tbl_studiengang.oe_kurzbz', FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE); + } + + $summe_result = $this->_ci->LehreinheitmitarbeiterModel->load(); + + if (isError($summe_result)) return $summe_result; + + if (!hasData($summe_result)) return error('Fehler beim Ermitteln der Gesamtstunden'); + + $summe = getData($summe_result)[0]->summe; + + if ($summe > $stundengrenze->stunden) + { + + if (!$echter_dv && (!$this->_ci->permissionlib->isBerechtigt('admin'))) + { + if (!$this->LehrauftragAufFirma(isset($formData['mitarbeiter_uid']) ? $formData['mitarbeiter_uid'] : $mitarbeiter_uid)) + return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\n Daten wurden NICHT gespeichert!\n\n"); + } + else + { + $warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\n Daten wurden gespeichert!\n\n"; + } + + $stunden_limit_result = $this->getStundenInstitut($mitarbeiter_uid, $lehreinheit->studiensemester_kurzbz, $oe_array); + + if (hasData($stunden_limit_result)) + { + $stunden_limit_array = getData($stunden_limit_result); + foreach ($stunden_limit_array as $stunden_limit) + { + $warning .= $stunden_limit->summe . ' Stunden' . $stunden_limit->bezeichnung; + } + } + } + } + } + + $benutzer_result = $this->_ci->BenutzerModel->load(array(isset($formData['mitarbeiter_uid']) ? $formData['mitarbeiter_uid'] : $mitarbeiter_uid)); + + if (isError($benutzer_result)) return $benutzer_result; + + if (!hasData($benutzer_result)) return error('Benutzer not found'); + + $benutzer_aktiv = getData($benutzer_result)[0]->aktiv; + + if (!$benutzer_aktiv) + $warning .= "Achtung: Der/Die Benutzer*in ist inaktiv!\nBitte informieren Sie die Personalbteilung.\n\nDaten wurden gespeichert.\n\n"; + + $updatableFields = array( + 'semesterstunden', + 'planstunden', + 'stundensatz', + 'faktor', + 'anmerkung', + 'lehrfunktion_kurzbz', + 'mitarbeiter_uid', + 'bismelden' + ); + + $updateData = array(); + foreach ($updatableFields as $field) + { + $value = isset($new_data[$field]) ? $new_data[$field] : null; + + if ($value !== null) + { + $updateData[$field] = $value; + } + } + $updateData['updatevon'] = getAuthUID(); + $updateData['updateamum'] = date('Y-m-d H:i:s'); + + $result = $this->_ci->LehreinheitmitarbeiterModel->update(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid), $updateData); + + if (isError($result)) return $result; + + if ($warning !== '') return error($warning); + + return success('Successfully updated Lehreinheit'); + } + + private function getMaxStunden($mitarbeiter_uid, $studiensemester_kurzbz, $studiengang_kz, $echter_dv) + { + $maxstunden = 9999; + + $studiengang_result = $this->_ci->StudiengangModel->loadWhere(array('studiengang_kz' => $studiengang_kz)); + if (isError($studiengang_result)) return $studiengang_result; + + $studiengang = getData($studiengang_result)[0]; + + $stundengrenze_result = $this->_ci->OrganisationseinheitModel->getStundengrenze($studiengang->oe_kurzbz, $echter_dv); + if (isError($stundengrenze_result)) return $stundengrenze_result; + + $stundengrenze = getData($stundengrenze_result)[0]; + $maxstunden = $stundengrenze->stunden; + + $lehrauftrag_firma = $this->LehrauftragAufFirma($mitarbeiter_uid); + + if (!$echter_dv && !$lehrauftrag_firma) + { + $oe_result = $this->_ci->OrganisationseinheitModel->getChilds($stundengrenze->oe_kurzbz); + $oe_array = hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array(''); + + $stunden_summe_result = $this->getSumSemesterstunden($mitarbeiter_uid, $studiensemester_kurzbz, $oe_array); + + $stunden_summe = hasData($stunden_summe_result) ? getData($stunden_summe_result)[0]->summe : 0; + + if ($stunden_summe >= $maxstunden && (!$this->_ci->permissionlib->isBerechtigt('admin'))) + { + $stunden_limit_result = $this->getStundenInstitut($mitarbeiter_uid, $studiensemester_kurzbz, $oe_array); + + $error = "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $maxstunden Stunden ($stundengrenze->oe_kurzbz) wurde ueberschritten!\n + Daten wurden NICHT gespeichert!\n\n"; + + if (hasData($stunden_limit_result)) + { + $stunden_limit_array = getData($stunden_limit_result); + + foreach ($stunden_limit_array as $stunden_limit) + { + $error .= $stunden_limit->summe . ' Stunden' . $stunden_limit->bezeichnung; + } + } + return error($error); + } + else + $maxstunden =- $stunden_summe; + } + return $maxstunden; + } + + private function LehrauftragAufFirma($mitarbeiter_uid) + { + $this->_ci->MitarbeiterModel->addJoin('tbl_benutzer', 'tbl_mitarbeiter.mitarbeiter_uid = tbl_benutzer.uid'); + $this->_ci->MitarbeiterModel->addJoin('tbl_person', 'person_id'); + $this->_ci->MitarbeiterModel->addJoin('tbl_adresse', 'person_id', 'LEFT'); + $this->_ci->MitarbeiterModel->addOrder('zustelladresse', 'DESC'); + $this->_ci->MitarbeiterModel->addOrder('firma_id'); + $this->_ci->MitarbeiterModel->addLimit(1); + $firma_result = $this->_ci->MitarbeiterModel->loadWhere(array('mitarbeiter_uid' => $mitarbeiter_uid)); + $firma = getData($firma_result)[0]->firma_id; + return !is_null($firma); + } + + private function getSumSemesterstunden($mitarbeiter_uid, $studiensemester_kurzbz, $oe_array = array()) + { + $this->_ci->LehreinheitmitarbeiterModel->addSelect('SUM(tbl_lehreinheitmitarbeiter.semesterstunden) as summe'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('public.tbl_studiengang', 'studiengang_kz'); + $this->_ci->LehreinheitmitarbeiterModel->db->where('mitarbeiter_uid', $mitarbeiter_uid); + $this->_ci->LehreinheitmitarbeiterModel->db->where('studiensemester_kurzbz', $studiensemester_kurzbz); + $this->_ci->LehreinheitmitarbeiterModel->db->where('bismelden', true); + $this->_ci->LehreinheitmitarbeiterModel->db->where('lower(mitarbeiter_uid) NOT LIKE', '_dummy%'); + $this->_ci->LehreinheitmitarbeiterModel->db->where_in('tbl_studiengang.oe_kurzbz', $oe_array); + return $this->_ci->LehreinheitmitarbeiterModel->load(); + } + + private function getStundenInstitut($mitarbeiter_uid, $studiensemester_kurzbz, $oe_array = array()) + { + $this->_ci->LehreinheitmitarbeiterModel->addSelect('SUM(tbl_lehreinheitmitarbeiter.semesterstunden) as summe, tbl_studiengang.bezeichnung'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehreinheit', 'lehreinheit_id'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('lehre.tbl_lehrveranstaltung', 'lehrveranstaltung_id'); + $this->_ci->LehreinheitmitarbeiterModel->addJoin('public.tbl_studiengang', 'studiengang_kz'); + $this->_ci->LehreinheitmitarbeiterModel->db->where('mitarbeiter_uid', $mitarbeiter_uid); + $this->_ci->LehreinheitmitarbeiterModel->db->where('studiensemester_kurzbz', $studiensemester_kurzbz); + $this->_ci->LehreinheitmitarbeiterModel->db->where('bismelden', true); + $this->_ci->LehreinheitmitarbeiterModel->db->where_in('tbl_studiengang.oe_kurzbz', $oe_array); + + if(defined('FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE') + && is_array(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) + && count(FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE) > 0) + { + $this->_ci->LehreinheitmitarbeiterModel->db->where_not_in('tbl_studiengang.oe_kurzbz', FAS_LV_LEKTORINNENZUTEILUNG_STUNDEN_IGNORE_OE); + } + + $this->_ci->LehreinheitmitarbeiterModel->addGroupBy('tbl_studiengang.bezeichnung'); + return $this->_ci->LehreinheitmitarbeiterModel->load(); + } +} diff --git a/application/models/accounting/Vertrag_model.php b/application/models/accounting/Vertrag_model.php index abc2114a6..c17c676c7 100644 --- a/application/models/accounting/Vertrag_model.php +++ b/application/models/accounting/Vertrag_model.php @@ -384,6 +384,60 @@ class Vertrag_model extends DB_Model } } + public function getVertrag($mitarbeiter_uid, $lehreinheit_id) + { + $this->addSelect('tbl_lehreinheitmitarbeiter.*, tbl_vertrag.*, status.bezeichnung as vertragsstatus, status.vertragsstatus_kurzbz'); + $this->addJoin('lehre.tbl_lehreinheitmitarbeiter', 'vertrag_id'); + $this->addJoin('lehre.tbl_vertragstyp', 'vertragstyp_kurzbz', 'LEFT'); + $this->addJoin(' + ( + SELECT DISTINCT ON(vertrag_id) vertrag_id, + bezeichnung, + tbl_vertragsstatus.vertragsstatus_kurzbz + FROM lehre.tbl_vertrag_vertragsstatus + JOIN lehre.tbl_vertragsstatus USING(vertragsstatus_kurzbz) + ORDER BY vertrag_id, datum DESC + ) as status', 'status.vertrag_id = lehre.tbl_vertrag.vertrag_id', 'LEFT'); + + return $this->loadWhere(array('mitarbeiter_uid' => $mitarbeiter_uid, 'lehreinheit_id' => $lehreinheit_id)); + } + + public function cancelVertrag($vertrag_id, $mitarbeiter_uid) + { + $vertrag = $this->load($vertrag_id); + + if (!hasData($vertrag)) + return error("Contract not found"); + + $vertrag = getData($vertrag)[0]; + + $this->_updateVertragRelevant($vertrag->vertrag_id); + + return $this->VertragvertragsstatusModel->insert(array( + 'vertrag_id' => $vertrag->vertrag_id, + 'vertragsstatus_kurzbz' => 'storno', + 'uid' => $mitarbeiter_uid, + 'datum' => 'NOW()', + 'insertamum' => 'NOW()', + 'insertvon' => getAuthUID() + )); + } + + public function deleteVertrag($vertrag_id) + { + $vertrag = $this->load($vertrag_id); + + if (!hasData($vertrag)) + return error("Contract not found"); + + $vertrag = getData($vertrag)[0]; + + $this->_updateVertragRelevant($vertrag->vertrag_id); + + $this->VertragvertragsstatusModel->delete(array('vertrag_id' => $vertrag->vertrag_id)); + return $this->delete(array('vertrag_id' => $vertrag->vertrag_id)); + } + // ----------------------------------------------------------------------------------------------------------------- // Private methods @@ -415,4 +469,20 @@ class Vertrag_model extends DB_Model return $bezeichnung; } + + private function _updateVertragRelevant($vertrag_id) + { + $this->LehreinheitmitarbeiterModel->update( + array("vertrag_id" => $vertrag_id), + array( + 'vertrag_id' => null + ) + ); + $this->ProjektbetreuerModel->update( + array("vertrag_id" => $vertrag_id), + array( + 'vertrag_id' => null + ) + ); + } } diff --git a/application/models/education/Lehreinheit_model.php b/application/models/education/Lehreinheit_model.php index d4bc7a22f..ba9e82c64 100644 --- a/application/models/education/Lehreinheit_model.php +++ b/application/models/education/Lehreinheit_model.php @@ -1,4 +1,6 @@ load->model('education/lehreinheitgruppe_model', 'LehreinheitgruppeModel'); $this->load->model('education/lehreinheitmitarbeiter_model', 'LehreinheitmitarbeiterModel'); $this->load->model('organisation/studiengang_model', 'StudiengangModel'); + $this->load->model('ressource/stundenplandev_model', 'StundenplandevModel'); + $this->load->model('ressource/stundenplan_model', 'StundenplanModel'); + $this->load->model('system/Log_model', 'LogModel'); } /** @@ -303,4 +308,437 @@ EOSQL; return $this->execQuery($query, $params); } + + + public function getOes($lehreinheit_id) + { + $this->addSelect('tbl_lehrveranstaltung.studiengang_kz, + tbl_lehrveranstaltung.lehrveranstaltung_id'); + $this->addJoin('lehre.tbl_lehrveranstaltung', 'tbl_lehrveranstaltung.lehrveranstaltung_id = tbl_lehreinheit.lehrveranstaltung_id'); + $result = $this->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + + if (isError($result)) return $result; + + if (hasData($result)) + { + $lehrveranstaltung = getData($result)[0]; + $oe_result = $this->LehrveranstaltungModel->getAllOe($lehrveranstaltung->lehrveranstaltung_id, $lehrveranstaltung->studiengang_kz); + return success(hasData($oe_result) ? array_column(getData($oe_result), 'oe_kurzbz') : array('')); + } + } + + public function getLehrfachOe($lehreinheit_id) + { + $this->addSelect('lehrfach.oe_kurzbz'); + $this->addJoin('lehre.tbl_lehrveranstaltung lehrfach', 'lehrfach.lehrveranstaltung_id = tbl_lehreinheit.lehrfach_id', 'LEFT'); + return $this->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + } + + + public function getByLvidStudiensemester($lv_id, $studiensemester_kurzbz) + { + $qry = "WITH lehreinheiten AS ( + SELECT * + FROM lehre.tbl_lehreinheit + WHERE lehrveranstaltung_id = ? + AND studiensemester_kurzbz = ? + ), + gruppen AS ( + SELECT + COALESCE( + string_agg( + tbl_lehreinheitgruppe.gruppe_kurzbz, ' ' + ) FILTER (WHERE NOT direktinskription), + string_agg( + COALESCE( + upper(tbl_studiengang.typ::varchar(1) ||tbl_studiengang.kurzbz) || + '-'|| + COALESCE(tbl_lehreinheitgruppe.semester::varchar, '') || + COALESCE(tbl_lehreinheitgruppe.verband::varchar, '')|| + COALESCE(tbl_lehreinheitgruppe.gruppe, '')), ', ' + ) + ) AS gruppe, + lehreinheit_id + FROM + lehre.tbl_lehreinheitgruppe + LEFT JOIN public.tbl_studiengang USING(studiengang_kz) + LEFT JOIN public.tbl_gruppe USING(gruppe_kurzbz) + GROUP BY lehreinheit_id + ), + mitarbeiter AS ( + SELECT kurzbz, semesterstunden, planstunden, lehreinheit_id + FROM lehre.tbl_lehreinheitmitarbeiter + JOIN public.tbl_mitarbeiter USING(mitarbeiter_uid) + ), + fachbereich AS ( + SELECT + tbl_organisationseinheit.bezeichnung, + tbl_organisationseinheit.organisationseinheittyp_kurzbz, + lehreinheit_id + FROM + public.tbl_organisationseinheit, + lehre.tbl_lehrveranstaltung as lehrfach, + lehre.tbl_lehreinheit + WHERE tbl_organisationseinheit.oe_kurzbz = lehrfach.oe_kurzbz + AND lehrfach.lehrveranstaltung_id = tbl_lehreinheit.lehrfach_id + ), + tag_data_agg AS ( + SELECT + lehreinheit_id, + COALESCE(json_agg(tag ORDER BY id), '[]'::json) AS tags + FROM ( + SELECT DISTINCT ON (public.tbl_notiz.notiz_id) + tbl_notiz.notiz_id AS id, + typ_kurzbz, + array_to_json(tbl_notiz_typ.bezeichnung_mehrsprachig)->>0 AS beschreibung, + text AS notiz, + style, + erledigt AS done, + lehreinheit_id + FROM public.tbl_notizzuordnung + JOIN public.tbl_notiz ON tbl_notizzuordnung.notiz_id = tbl_notiz.notiz_id + JOIN public.tbl_notiz_typ ON tbl_notiz.typ = tbl_notiz_typ.typ_kurzbz + WHERE lehreinheit_id IN (SELECT lehreinheit_id FROM lehreinheiten) + ) AS tag + GROUP BY lehreinheit_id + ) + SELECT lehreinheiten.*, + lehreinheiten.lehrform_kurzbz as lv_lehrform_kurzbz, + tbl_lehrveranstaltung.kurzbz as lv_kurzbz, + tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, + COALESCE(tag_data_agg.tags, '[]'::json) AS tags, + ( + SELECT string_agg(gr.gruppe, ' ') + FROM gruppen gr + WHERE gr.lehreinheit_id = lehreinheiten.lehreinheit_id + ) AS gruppen, + ( + SELECT string_agg(ma.kurzbz, ' ') + FROM mitarbeiter ma + WHERE ma.lehreinheit_id = lehreinheiten.lehreinheit_id + ) AS lektoren, + ( + SELECT string_agg(fachbereich.bezeichnung, ' ') + FROM fachbereich + WHERE fachbereich.lehreinheit_id = lehreinheiten.lehreinheit_id + ) AS fachbereich + FROM lehreinheiten + LEFT JOIN lehre.tbl_lehrveranstaltung ON tbl_lehrveranstaltung.lehrveranstaltung_id = lehreinheiten.lehrfach_id + LEFT JOIN tag_data_agg ON tag_data_agg.lehreinheit_id = lehreinheiten.lehreinheit_id"; + + return $this->execReadOnlyQuery($qry, array($lv_id, $studiensemester_kurzbz)); + } + + private function getLVTmp($stg_kz = null) + { + $qry = "SELECT DISTINCT ON(lehrveranstaltung_id) *, + '' as studienplan_id, '' as studienplan_beeichnung, + CONCAT(vw_lehreinheit.stg_typ, vw_lehreinheit.stg_kurzbz) as studiengang + FROM campus.vw_lehreinheit + WHERE mitarbeiter_uid = ? + AND studiensemester_kurzbz = ?"; + + if (!is_null($stg_kz)) { + $qry .= " AND lv_studiengang_kz = ?"; + } + + return $qry; + } + + public function getLvsByEmployee($mitarbeiter_uid, $studiensemester_kurzbz, $stg_kz = null) + { + $qry = "WITH lvs AS (" . $this->getLVTmp($stg_kz) . ") + SELECT lvs.* + FROM lvs + "; + + $params = array($mitarbeiter_uid, $studiensemester_kurzbz); + if (!is_null($stg_kz)) + { + $params[] = $stg_kz; + } + return $this->execReadOnlyQuery($qry, $params); + } + + + + public function getLEByLV($lv_id, $studiensemester_kurzbz, $mitarbeiter_uid = null, $fachbereich_kurzbz = null) + { + $qry = " + WITH gruppen AS ( + SELECT + COALESCE( + string_agg( + tbl_lehreinheitgruppe.gruppe_kurzbz, ', ' + ) FILTER (WHERE NOT direktinskription), + string_agg( + COALESCE( + upper(tbl_studiengang.typ::varchar(1) ||tbl_studiengang.kurzbz) || + '-'|| + COALESCE(tbl_lehreinheitgruppe.semester::varchar, '') || + COALESCE(tbl_lehreinheitgruppe.verband::varchar, '')|| + COALESCE(tbl_lehreinheitgruppe.gruppe, '')), ', ' + ) + ) AS gruppen, + lehreinheit_id + FROM + lehre.tbl_lehreinheitgruppe + LEFT JOIN public.tbl_studiengang USING(studiengang_kz) + LEFT JOIN public.tbl_gruppe USING(gruppe_kurzbz) + GROUP BY lehreinheit_id + ), + lektoren AS ( + SELECT string_agg(kurzbz, ' ') as lektoren, + string_agg(semesterstunden::text, ' ') as semesterstunden, + string_agg(planstunden::text, ' ') as planstunden, + lehreinheit_id + FROM lehre.tbl_lehreinheitmitarbeiter + JOIN public.tbl_mitarbeiter USING(mitarbeiter_uid) + GROUP BY lehreinheit_id + ), + fachbereich AS ( + SELECT + string_agg(CONCAT(tbl_organisationseinheit.bezeichnung, ' (', tbl_organisationseinheit.organisationseinheittyp_kurzbz, ')'),' ') as fachbereich, + lehreinheit_id + FROM + public.tbl_organisationseinheit, + lehre.tbl_lehrveranstaltung as lehrfach, + lehre.tbl_lehreinheit + WHERE + tbl_organisationseinheit.oe_kurzbz = lehrfach.oe_kurzbz + AND lehrfach.lehrveranstaltung_id = tbl_lehreinheit.lehrfach_id + GROUP BY lehreinheit_id + ) + SELECT tbl_lehreinheit.*, + tbl_lehrveranstaltung.*, + tbl_lehrveranstaltung.kurzbz as lv_kurzbz, + tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, + lektoren.lektoren, + lektoren.semesterstunden, + lektoren.planstunden, + fachbereich.fachbereich + FROM lehre.tbl_lehreinheit + LEFT JOIN lehre.tbl_lehrveranstaltung ON tbl_lehrveranstaltung.lehrveranstaltung_id = tbl_lehreinheit.lehrfach_id + LEFT JOIN gruppen ON tbl_lehreinheit.lehreinheit_id = gruppen.lehreinheit_id + LEFT JOIN lektoren ON tbl_lehreinheit.lehreinheit_id = lektoren.lehreinheit_id + LEFT JOIN fachbereich ON tbl_lehreinheit.lehreinheit_id = fachbereich.lehreinheit_id + WHERE tbl_lehreinheit.lehrveranstaltung_id = ? + AND studiensemester_kurzbz = ? + "; + + $params = array($lv_id, $studiensemester_kurzbz); + if ($mitarbeiter_uid !== null) + { + $qry .= " AND tbl_lehreinheit.lehreinheit_id IN ( SELECT lehreinheit_id FROM lehre.tbl_lehreinheitmitarbeiter WHERE mitarbeiter_uid = ?) "; + $params[] = $mitarbeiter_uid; + } + + if($fachbereich_kurzbz !== null) + { + $qry .= " AND EXISTS ( SELECT 1 FROM lehre.tbl_lehrveranstaltung JOIN public.tbl_fachbereich USING(oe_kurzbz) WHERE fachbereich_kurzbz= ? AND lehrveranstaltung_id=tbl_lehreinheit.lehrfach_id)"; + $params[] = $fachbereich_kurzbz; + } + $qry .= " ORDER BY lehreinheit_id;"; + + return $this->execReadOnlyQuery($qry, $params); + } + + public function deleteLehreinheit($lehreinheit_id) + { + $lehreinheit = $this->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + + if (isError($lehreinheit)) return $lehreinheit; + + if (!hasData($lehreinheit)) + return error("Lehreinheit not found!"); + + $errorReasons = []; + $addError = function ($reason = null) use (&$errorReasons) + { + if ($reason !== null) + { + $errorReasons[] = $reason; + } + }; + + $stundenplandev_result = $this->StundenplandevModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + $stundenplan_result = $this->StundenplanModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + + if (hasData($stundenplan_result) || hasData($stundenplandev_result)) + $addError('Dieser LV-Teil ist bereits im LV-Plan verplant und kann daher nicht geloescht werden!'); + + Events::trigger( + 'lehreinheit_delete_check', + $addError, + $lehreinheit_id + ); + + if (!empty($errorReasons)) return error($errorReasons); + + $this->db->trans_begin(); + + Events::trigger( + 'lehreinheit_delete', + $addError, + $lehreinheit_id + ); + + $undosql = ''; + + $lehreinheit_gruppe_result = $this->LehreinheitgruppeModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + if (hasData($lehreinheit_gruppe_result)) + { + foreach (getData($lehreinheit_gruppe_result) as $row) + { + $values = [ + $this->db->escape($row->lehreinheitgruppe_id), + $this->db->escape($row->lehreinheit_id), + $this->db->escape($row->studiengang_kz), + $this->db->escape($row->semester), + $this->db->escape($row->verband), + $this->db->escape($row->gruppe), + $this->db->escape($row->gruppe_kurzbz), + $this->db->escape($row->updateamum), + $this->db->escape($row->updatevon), + $this->db->escape($row->insertamum), + $this->db->escape($row->insertvon) + ]; + + $undosql .= "INSERT INTO lehre.tbl_lehreinheitgruppe ( + lehreinheitgruppe_id, + lehreinheit_id, + studiengang_kz, + semester, + verband, + gruppe, + gruppe_kurzbz, + updateamum, + updatevon, + insertamum, + insertvon + ) VALUES (" . implode(', ', $values) . ");\n"; + } + + $lehreinheit_gruppe_delete_result = $this->LehreinheitgruppeModel->delete(array('lehreinheit_id' => $lehreinheit_id)); + + if (isError($lehreinheit_gruppe_delete_result)) + $addError(getError($lehreinheit_gruppe_delete_result)); + } + + $lehreinheit_mitarbeiter_result = $this->LehreinheitmitarbeiterModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + if (hasData($lehreinheit_mitarbeiter_result)) + { + foreach (getData($lehreinheit_mitarbeiter_result) as $row) + { + $values = [ + $this->db->escape($row->lehreinheit_id), + $this->db->escape($row->mitarbeiter_uid), + $this->db->escape($row->lehrfunktion_kurzbz), + $this->db->escape($row->planstunden), + $this->db->escape($row->stundensatz), + $this->db->escape($row->faktor), + $this->db->escape($row->anmerkung), + $this->db->escape($row->bismelden), + $this->db->escape($row->updateamum), + $this->db->escape($row->updatevon), + $this->db->escape($row->insertamum), + $this->db->escape($row->insertvon), + $this->db->escape($row->semesterstunden) + ]; + + $undosql .= "INSERT INTO lehre.tbl_lehreinheitmitarbeiter ( + lehreinheit_id, + mitarbeiter_uid, + lehrfunktion_kurzbz, + planstunden, + stundensatz, + faktor, + anmerkung, + bismelden, + updateamum, + updatevon, + insertamum, + insertvon, + semesterstunden + ) VALUES (" . implode(', ', $values) . ");\n"; + } + + $lehreinheit_mitarbeiter_delete_result = $this->LehreinheitmitarbeiterModel->delete(array('lehreinheit_id' => $lehreinheit_id)); + if (isError($lehreinheit_mitarbeiter_delete_result)) + $addError(getError($lehreinheit_mitarbeiter_delete_result)); + } + + foreach (getData($lehreinheit) as $row) + { + $values = [ + $this->db->escape($row->lehreinheit_id), + $this->db->escape($row->lehrveranstaltung_id), + $this->db->escape($row->studiensemester_kurzbz), + $this->db->escape($row->lehrfach_id), + $this->db->escape($row->lehrform_kurzbz), + $this->db->escape($row->stundenblockung), + $this->db->escape($row->wochenrythmus), + $this->db->escape($row->start_kw), + $this->db->escape($row->raumtyp), + $this->db->escape($row->raumtypalternativ), + $this->db->escape($row->sprache), + $this->db->escape($row->lehre), + $this->db->escape($row->anmerkung), + $this->db->escape($row->unr), + $this->db->escape($row->lvnr), + $this->db->escape($row->updateamum), + $this->db->escape($row->updatevon), + $this->db->escape($row->insertamum), + $this->db->escape($row->insertvon), + ]; + + $undosql .= "INSERT INTO lehre.tbl_lehreinheit ( + lehreinheit_id, + lehrveranstaltung_id, + studiensemester_kurzbz, + lehrfach_id, + lehrform_kurzbz, + stundenblockung, + wochenrythmus, + start_kw, + raumtyp, + raumtypalternativ, + sprache, + lehre, + anmerkung, + unr, + lvnr, + updateamum, + updatevon, + insertamum, + insertvon + ) VALUES (" . implode(', ', $values) . ");\n"; + } + $lehreinheit_result = $this->delete($lehreinheit_id); + + $deleteSql = "DELETE FROM lehre.tbl_lehreinheitmitarbeiter WHERE lehreinheit_id = " . $this->db->escape($lehreinheit_id) ."; \n + DELETE FROM lehre.tbl_lehreinheitgruppe WHERE lehreinheit_id = " . $this->db->escape($lehreinheit_id) ."; \n + DELETE FROM lehre.tbl_lehreinheit WHERE lehreinheit_id = " . $this->db->escape($lehreinheit_id) .";"; + if (isError($lehreinheit_result)) + $addError($lehreinheit_result); + + $log_result = $this->LogModel->insert([ + 'sql' => $deleteSql, + 'sqlundo' => $undosql, + 'beschreibung' => 'Lehreinheit loeschen - ' . $lehreinheit_id, + 'mitarbeiter_uid' => getAuthUID(), + ]); + + if (isError($log_result)) + $addError($log_result); + + if (!empty($errorReasons)) + { + $this->db->trans_rollback(); + return error($errorReasons); + } + + $this->db->trans_commit(); + return success('Contract successfully updated.'); + } } diff --git a/application/models/education/Lehreinheitgruppe_model.php b/application/models/education/Lehreinheitgruppe_model.php index 2a6f9571a..5dd2fa66c 100644 --- a/application/models/education/Lehreinheitgruppe_model.php +++ b/application/models/education/Lehreinheitgruppe_model.php @@ -14,6 +14,7 @@ class Lehreinheitgruppe_model extends DB_Model $this->load->model('organisation/studiengang_model', 'StudiengangModel'); $this->load->model('organisation/gruppe_model', 'GruppeModel'); $this->load->model('person/benutzergruppe_model', 'BenutzergruppeModel'); + $this->load->model('ressource/stundenplandev_model', 'StundenplandevModel'); } /** @@ -23,7 +24,15 @@ class Lehreinheitgruppe_model extends DB_Model */ public function getDirectGroup($lehreinheit_id) { + $this->addSelect('tbl_lehreinheitgruppe.*'); + $this->addSelect('tbl_gruppe.*'); + $this->addSelect('uid'); + $this->addSelect('vorname'); + $this->addSelect('nachname'); $this->addJoin('public.tbl_gruppe', 'gruppe_kurzbz'); + $this->addJoin('public.tbl_benutzergruppe', 'gruppe_kurzbz', 'LEFT'); + $this->addJoin('public.tbl_benutzer', 'uid', 'LEFT'); + $this->addJoin('public.tbl_person', 'person_id', 'LEFT'); return $this->loadWhere( array( 'tbl_gruppe.direktinskription' => true, @@ -264,4 +273,203 @@ class Lehreinheitgruppe_model extends DB_Model } return $result; } + + public function addGroup($lehreinheit_id, $gid, $verband) + { + $lehreinheit = $this->LehreinheitModel->load($lehreinheit_id); + + if (!hasData($lehreinheit)) + return error ('No Lehreinheit found!'); + + if ($verband === false) + { + $gruppen_result = $this->GruppeModel->loadWhere(array('gid' => $gid)); + + if (!hasData($gruppen_result)) + return error('No group found for gid ' . $gid); + + $gruppen_array = getData($gruppen_result)[0]; + + if (!isEmptyString($gruppen_array->gruppe_kurzbz)) + { + $this->db->where('trim(gruppe_kurzbz)', $gruppen_array->gruppe_kurzbz); + } + else + { + $this->db->group_start(); + $this->db->where("trim(gruppe_kurzbz) = ''"); + $this->db->or_where("gruppe_kurzbz IS NULL"); + $this->db->group_end(); + } + } + else if ($verband === true) + { + $gruppen_result = $this->_ci->LehrverbandModel->loadWhere(array('gid' => $gid)); + + if (!hasData($gruppen_result)) + return error('No group found for gid ' . $gid); + + $gruppen_array = getData($gruppen_result)[0]; + + if (!isEmptyString($gruppen_array->verband)) + { + $this->db->where('verband', $gruppen_array->verband); + } + else + { + $this->db->group_start(); + $this->db->where("trim(verband) = ''"); + $this->db->or_where("verband IS NULL"); + $this->db->group_end(); + } + + if (!isEmptyString($gruppen_array->gruppe)) + { + $this->db->where('gruppe', $gruppen_array->gruppe); + } + else + { + $this->db->group_start(); + $this->db->where("trim(gruppe) = ''"); + $this->db->or_where("gruppe IS NULL"); + $this->db->group_end(); + } + } + else + return error('Wrong type of verband'); + + $this->db->where('lehreinheit_id', $lehreinheit_id); + $this->db->where('studiengang_kz', $gruppen_array->studiengang_kz); + + if (!isEmptyString($gruppen_array->semester)) + { + $this->db->where('semester', $gruppen_array->semester); + } + else + { + $this->db->group_start(); + $this->db->where("semester = ''"); + $this->db->or_where("semester IS NULL"); + $this->db->group_end(); + } + + $exist_result = $this->load(); + + if (!hasData($exist_result)) + { + $new_group_result = $this->insert(array( + 'lehreinheit_id' => $lehreinheit_id, + 'studiengang_kz' => $gruppen_array->studiengang_kz, + 'gruppe_kurzbz' => isset($gruppen_array->gruppe_kurzbz) ? $gruppen_array->gruppe_kurzbz : null, + 'semester' => $gruppen_array->semester, + 'verband' => isset($gruppen_array->verband) && !isEmptyString($gruppen_array->verband) ? $gruppen_array->verband : null, + 'gruppe' => isset($gruppen_array->gruppe) && !isEmptyString($gruppen_array->gruppe) ? $gruppen_array->gruppe : null, + 'insertamum' => date('Y-m-d H:i:s'), + 'insertvon' => getAuthUID() + )); + + if (isError($new_group_result)) + return error('Error when adding Group'); + + return success('Group assigned successfully to Lehreinheit'); + } + else + return error('Group already assigned'); + } + + public function deleteGroup($lehreinheit_id, $lehreinheitgruppe_id) + { + $lehreinheit = $this->LehreinheitModel->load($lehreinheit_id); + + if (!hasData($lehreinheit)) + return error ('No Lehreinheit found!'); + + $lehreinheitgruppe = $this->load($lehreinheitgruppe_id); + + if (!hasData($lehreinheitgruppe)) + return error ('No Lehreinheitgruppe found!'); + + $this->addSelect('stundenplandev_id'); + $this->addJoin('lehre.tbl_stundenplandev', + "tbl_stundenplandev.lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id + AND tbl_stundenplandev.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz + AND tbl_stundenplandev.semester = tbl_lehreinheitgruppe.semester + AND trim(COALESCE(tbl_stundenplandev.verband, '')) = trim(COALESCE(tbl_lehreinheitgruppe.verband, '')) + AND trim(COALESCE(tbl_stundenplandev.gruppe, '')) = trim(COALESCE(tbl_lehreinheitgruppe.gruppe, '')) + AND trim(COALESCE(tbl_stundenplandev.gruppe_kurzbz, '')) = trim(COALESCE(tbl_lehreinheitgruppe.gruppe_kurzbz, ''))" + ); + $stundenplan_result = $this->loadWhere(array('tbl_lehreinheitgruppe.lehreinheitgruppe_id' => $lehreinheitgruppe_id)); + + if (hasData($stundenplan_result)) + return error('Gruppe already verplant'); + + $delete_result = $this->delete($lehreinheitgruppe_id); + + if (isError($delete_result)) + return error('Error deleting Group'); + + return success('Group deleted'); + } + + public function getByLehreinheit($lehreinheit_id) + { + $lehreinheit = $this->LehreinheitModel->load($lehreinheit_id); + + if (!hasData($lehreinheit)) + return error ('No Lehreinheit found!'); + + $this->addSelect('tbl_lehreinheitgruppe.*'); + $this->addSelect('tbl_gruppe.direktinskription'); + $this->addSelect('tbl_gruppe.gruppe_kurzbz'); + $this->addSelect("CASE + WHEN tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL THEN + COALESCE ( + UPPER(tbl_studiengang.typ || tbl_studiengang.kurzbz) || + COALESCE(tbl_lehreinheitgruppe.semester::varchar, '') || + COALESCE(tbl_lehreinheitgruppe.verband::varchar, '') || + COALESCE(tbl_lehreinheitgruppe.gruppe, ''), + '') + ELSE tbl_lehreinheitgruppe.gruppe_kurzbz + END AS bezeichnung"); + $this->addSelect("CASE + WHEN tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL THEN + ( + SELECT bezeichnung + FROM public.tbl_lehrverband + WHERE studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz + AND semester = tbl_lehreinheitgruppe.semester + AND verband = tbl_lehreinheitgruppe.verband + AND gruppe = tbl_lehreinheitgruppe.gruppe + LIMIT 1 + ) + ELSE tbl_gruppe.beschreibung + END AS beschreibung"); + $this->addSelect("CASE + WHEN tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL THEN + ( + SELECT EXISTS ( + SELECT 1 + FROM lehre.tbl_stundenplandev + WHERE lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id + AND studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz + AND semester = tbl_lehreinheitgruppe.semester + AND TRIM(COALESCE(verband, '')) = TRIM(tbl_lehreinheitgruppe.verband) + AND TRIM(COALESCE(gruppe, '')) = TRIM(tbl_lehreinheitgruppe.gruppe) + AND (gruppe_kurzbz IS NULL OR gruppe_kurzbz = '') + ) + ) + ELSE + ( + SELECT EXISTS ( + SELECT 1 + FROM lehre.tbl_stundenplandev + WHERE lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id + AND gruppe_kurzbz = tbl_lehreinheitgruppe.gruppe_kurzbz + ) + ) + END AS verplant"); + $this->addJoin('tbl_studiengang', 'studiengang_kz', 'LEFT'); + $this->addJoin('public.tbl_gruppe', 'gruppe_kurzbz', 'LEFT'); + return $this->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'tbl_gruppe.direktinskription' => false)); + } } diff --git a/application/models/education/Lehreinheitmitarbeiter_model.php b/application/models/education/Lehreinheitmitarbeiter_model.php index ae1ac55d2..efdb2e74d 100644 --- a/application/models/education/Lehreinheitmitarbeiter_model.php +++ b/application/models/education/Lehreinheitmitarbeiter_model.php @@ -10,6 +10,14 @@ class Lehreinheitmitarbeiter_model extends DB_Model parent::__construct(); $this->dbTable = 'lehre.tbl_lehreinheitmitarbeiter'; $this->pk = array('mitarbeiter_uid', 'lehreinheit_id'); + $this->hasSequence = false; + + $this->load->model('accounting/Vertrag_model', 'VertragModel'); + $this->load->model('ressource/stundenplandev_model', 'StundenplandevModel'); + $this->load->model('ressource/stundenplan_model', 'StundenplanModel'); + $this->load->model('organisation/Studiengang_model', 'StudiengangModel'); + $this->load->model('organisation/Organisationseinheit_model', 'OrganisationseinheitModel'); + $this->load->model('ressource/mitarbeiter_model', 'MitarbeiterModel'); } /** @@ -75,4 +83,67 @@ class Lehreinheitmitarbeiter_model extends DB_Model ]); } + public function getLektorenByLe($lehreinheit_id) + { + $this->addSelect('vorname, nachname, tbl_lehreinheitmitarbeiter.*, stundenplan.verplant'); + $this->addJoin('tbl_benutzer', 'uid = mitarbeiter_uid'); + $this->addJoin('tbl_person', 'person_id'); + + $this->addJoin('( + SELECT 1 as verplant, lehreinheit_id, mitarbeiter_uid + FROM lehre.tbl_stundenplandev + GROUP BY lehreinheit_id, mitarbeiter_uid + + ) stundenplan', 'stundenplan.mitarbeiter_uid = tbl_lehreinheitmitarbeiter.mitarbeiter_uid AND stundenplan.lehreinheit_id = tbl_lehreinheitmitarbeiter.lehreinheit_id', 'LEFT'); + + return $this->loadWhere(array('tbl_lehreinheitmitarbeiter.lehreinheit_id' => $lehreinheit_id)); + } + + public function getByLeLektor($lehreinheit_id, $mitarbeiter_uid) + { + $this->addSelect('vorname, nachname, tbl_lehreinheitmitarbeiter.*'); + $this->addJoin('tbl_benutzer', 'uid = mitarbeiter_uid'); + $this->addJoin('tbl_person', 'person_id'); + return $this->loadWhere(array('tbl_lehreinheitmitarbeiter.lehreinheit_id' => $lehreinheit_id, 'tbl_lehreinheitmitarbeiter.mitarbeiter_uid' => $mitarbeiter_uid)); + } + + public function deleteLektorFromLe($lehreinheit_id, $mitarbeiter_uid) + { + if (defined('FAS_LV_LEKTORINNENZUTEILUNG_VERTRAGSDETAILS_ANZEIGEN') && FAS_LV_LEKTORINNENZUTEILUNG_VERTRAGSDETAILS_ANZEIGEN) + { + $vertrag_result = $this->VertragModel->getVertrag($mitarbeiter_uid, $lehreinheit_id); + + if (hasData($vertrag_result)) + return error("Loeschen nur nach Stornierung des Vertrags möglich"); + } + + $stundenplandev_result = $this->StundenplandevModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); + $stundenplan_result = $this->StundenplanModel->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); + + if (hasData($stundenplandev_result) || hasData($stundenplan_result)) + return error("Diese/r LektorIn kann nicht gelöscht werden da er schon verplant ist"); + + $result = $this->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); + + if (hasData($result)) + { + $le_mitarbeiter_array = getData($result)[0]; + + if ($le_mitarbeiter_array->vertrag_id !== null) + { + $vertrag_result = $this->VertragModel->deleteVertrag($le_mitarbeiter_array->vertrag_id); + if (isError($vertrag_result)) + return $vertrag_result; + } + + $delete_result = $this->delete(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); + + if (isError($delete_result)) + return $delete_result; + + return success($delete_result); + } + } + + } diff --git a/application/models/education/Lehrveranstaltung_model.php b/application/models/education/Lehrveranstaltung_model.php index 056fb45d7..955177273 100644 --- a/application/models/education/Lehrveranstaltung_model.php +++ b/application/models/education/Lehrveranstaltung_model.php @@ -988,4 +988,229 @@ class Lehrveranstaltung_model extends DB_Model return $this->execQuery($qry, $params); } + + public function getLvsByOrganization($oe_kurzbz) + { + $qry=" + SELECT + distinct on (lehrveranstaltung_id) + tbl_lehrveranstaltung.studiengang_kz as lv_studiengang_kz, tbl_lehrveranstaltung.semester as lv_semester, + tbl_lehrveranstaltung.kurzbz as lv_kurzbz, tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, tbl_lehrveranstaltung.ects as lv_ects, + tbl_lehrveranstaltung.lehreverzeichnis as lv_lehreverzeichnis, tbl_lehrveranstaltung.planfaktor as lv_planfaktor, + tbl_lehrveranstaltung.planlektoren as lv_planlektoren, tbl_lehrveranstaltung.planpersonalkosten as lv_planpersonalkosten, + tbl_lehrveranstaltung.plankostenprolektor as lv_plankostenprolektor, tbl_lehrveranstaltung.orgform_kurzbz as lv_orgform_kurzbz, + tbl_lehrveranstaltung.lehrveranstaltung_id, + tbl_lehrveranstaltung.lehrform_kurzbz as lehrform_kurzbz, + tbl_lehrveranstaltung.lehrform_kurzbz as lv_lehrform_kurzbz, + tbl_lehrveranstaltung.bezeichnung_english as lv_bezeichnung_english, + tbl_lehrveranstaltung.studiengang_kz, tbl_lehrveranstaltung.semester, tbl_lehrveranstaltung.anmerkung, tbl_lehrveranstaltung.sprache, tbl_lehrveranstaltung.semesterstunden, + tbl_lehrveranstaltung.lehre, tbl_lehrveranstaltung.aktiv, + '' as studienplan_id, '' as studienplan_bezeichnung, tbl_lehrveranstaltung.lehrtyp_kurzbz + FROM + lehre.tbl_lehrveranstaltung + WHERE + tbl_lehrveranstaltung.oe_kurzbz= ? + AND tbl_lehrveranstaltung.aktiv + "; + + return $this->execReadOnlyQuery($qry, array($oe_kurzbz)); + } + + public function getLvsByFachbereich($fachbereich, $studiensemester_kurbz, $mitarbeiter_uid = null) + { + $qry = ""; + if (!is_null($mitarbeiter_uid)) + { + $qry = $this->getLvsFromStudienplanByEmp(); + $params = array($fachbereich, $studiensemester_kurbz); + } + + $qry .= "SELECT + distinct on(lehrveranstaltung_id) + lv_studiengang_kz, lv_semester, lv_kurzbz, lv_bezeichnung, lv_ects, + lv_lehreverzeichnis, lv_planfaktor, lv_planlektoren, lv_planpersonalkosten, + lv_plankostenprolektor, lv_orgform_kurzbz, lehrveranstaltung_id, + lehrform_kurzbz, lv_lehrform_kurzbz, lv_bezeichnung_english, studiengang_kz, semester, anmerkung, sprache, semesterstunden, + lehre, aktiv, + '' as studienplan_id, '' as studienplan_bezeichnung, + (SELECT lehrtyp_kurzbz FROM lehre.tbl_lehrveranstaltung WHERE lehrveranstaltung_id=vw_lehreinheit.lehrveranstaltung_id) as lehrtyp_kurzbz + FROM + campus.vw_lehreinheit + WHERE studiensemester_kurzbz = ? + AND fachbereich_kurzbz = ?"; + + $params[] = array($studiensemester_kurbz, $fachbereich); + + if (!is_null($mitarbeiter_uid)) + { + $qry .= " AND mitarbeiter_uid = ?"; + $params[] = $mitarbeiter_uid; + } + else + { + $qry.=" AND lehrveranstaltung_id NOT IN (SELECT lehrveranstaltung_id + FROM + lehre.tbl_lehrveranstaltung + JOIN lehre.tbl_studienplan_lehrveranstaltung USING(lehrveranstaltung_id) + JOIN lehre.tbl_studienplan USING(studienplan_id) + JOIN lehre.tbl_studienordnung USING(studienordnung_id) + JOIN lehre.tbl_studienplan_semester USING(studienplan_id) + WHERE + tbl_lehrveranstaltung.oe_kurzbz=(Select oe_kurzbz from public.tbl_fachbereich where fachbereich_kurzbz= ?) + AND tbl_studienplan_semester.studiensemester_kurzbz= ?"; + + $params[] = array($fachbereich, $studiensemester_kurbz); + } + + return $this->execReadOnlyQuery($qry, $params); + } + + private function getLvsFromStudienplanByEmp() + { + return " + SELECT + distinct on (lehrveranstaltung_id) + tbl_lehrveranstaltung.studiengang_kz as lv_studiengang_kz, + tbl_lehrveranstaltung.semester as lv_semester, + tbl_lehrveranstaltung.kurzbz as lv_kurzbz, + tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, + tbl_lehrveranstaltung.ects as lv_ects, + tbl_lehrveranstaltung.lehreverzeichnis as lv_lehreverzeichnis, + tbl_lehrveranstaltung.planfaktor as lv_planfaktor, + tbl_lehrveranstaltung.planlektoren as lv_planlektoren, + tbl_lehrveranstaltung.planpersonalkosten as lv_planpersonalkosten, + tbl_lehrveranstaltung.plankostenprolektor as lv_plankostenprolektor, + tbl_lehrveranstaltung.orgform_kurzbz as lv_orgform_kurzbz, + tbl_lehrveranstaltung.lehrveranstaltung_id, + tbl_lehrveranstaltung.lehrform_kurzbz as lehrform_kurzbz, + tbl_lehrveranstaltung.lehrform_kurzbz as lv_lehrform_kurzbz, + tbl_lehrveranstaltung.bezeichnung_english as lv_bezeichnung_english, + tbl_lehrveranstaltung.studiengang_kz, + tbl_studienplan_lehrveranstaltung.semester, + tbl_lehrveranstaltung.anmerkung, + tbl_lehrveranstaltung.sprache, + tbl_lehrveranstaltung.semesterstunden, + tbl_lehrveranstaltung.lehre, + tbl_lehrveranstaltung.aktiv, + tbl_studienplan.studienplan_id::text, + tbl_studienplan.bezeichnung as studienplan_bezeichnung, + tbl_lehrveranstaltung.lehrtyp_kurzbz + FROM + lehre.tbl_lehrveranstaltung + JOIN lehre.tbl_studienplan_lehrveranstaltung USING(lehrveranstaltung_id) + JOIN lehre.tbl_studienplan USING(studienplan_id) + JOIN lehre.tbl_studienordnung USING(studienordnung_id) + JOIN lehre.tbl_studienplan_semester USING(studienplan_id) + WHERE + tbl_lehrveranstaltung.oe_kurzbz=(Select oe_kurzbz from public.tbl_fachbereich where fachbereich_kurzbz= ?) + AND tbl_studienplan_semester.studiensemester_kurzbz = ? + AND tbl_lehrveranstaltung.aktiv + UNION + "; + } + + public function getLvsByStudiengang($studienplan_ids, $placeholders, $only_ids, $studiengang_kz, $studiensemester_kurzbz, $semester = null, $verband = null) + { + $qry = ""; + $params = array(); + + if (!empty($studienplan_ids)) + { + $qry = $this->getLvsFromStudienplanByStudienplanID($placeholders); + $params = $studienplan_ids; + } + + $qry .= " + SELECT DISTINCT on(lehrveranstaltung_id) lehrveranstaltung_id, + kurzbz as lv_kurzbz, + bezeichnung as lv_bezeichnung, + bezeichnung_english as lv_bezeichnung_english, + studiengang_kz, + semester, + tbl_lehrveranstaltung.sprache, + ects as lv_ects, + semesterstunden, + tbl_lehrveranstaltung.anmerkung, + tbl_lehrveranstaltung.lehre, + lehreverzeichnis as lv_lehreverzeichnis, + aktiv, + planfaktor as lv_planfaktor, + planlektoren as lv_planlektoren, + planpersonalkosten as lv_planpersonalkosten, + plankostenprolektor as lv_plankostenprolektor, + tbl_lehrveranstaltung.lehrform_kurzbz as lv_lehrform_kurzbz, + tbl_lehrveranstaltung.orgform_kurzbz, + ''::text as studienplan_id, + '' as studienplan_bezeichnung, + '' as studienplan_lehrveranstaltung_id_parent, + tbl_lehrveranstaltung.lehrtyp_kurzbz + FROM lehre.tbl_lehrveranstaltung + JOIN lehre.tbl_lehreinheit USING (lehrveranstaltung_id) + WHERE studiengang_kz = ? + AND studiensemester_kurzbz = ? + "; + + $params[] = $studiengang_kz; + $params[] = $studiensemester_kurzbz; + if (!is_null($semester)) + { + $qry .= ' AND semester = ?'; + $params[] = $semester; + } + if (!is_null($verband)) + { + $qry .= ' AND (orgform_kurzbz = ? OR orgform_kurzbz IS NULL)'; + $params[] = $verband; + } + + if (!empty($only_ids)) + { + + $qry .= ' AND NOT EXISTS (SELECT 1 FROM lehre.tbl_studienplan_lehrveranstaltung where studienplan_id IN ? + AND lehrveranstaltung_id = tbl_lehrveranstaltung.lehrveranstaltung_id AND tbl_lehrveranstaltung.aktiv)'; + + $params[] = $only_ids; + } + + return $this->execReadOnlyQuery($qry, $params); + } + private function getLvsFromStudienplanByStudienplanID($placeholders) + { + return " + SELECT + lehrveranstaltung_id, kurzbz as lv_kurzbz, tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, bezeichnung_english as lv_bezeichnung_english, studiengang_kz, + tbl_studienplan_lehrveranstaltung.semester, tbl_lehrveranstaltung.sprache, + ects as lv_ects, semesterstunden, anmerkung, lehre, lehreverzeichnis as lv_lehreverzeichnis, tbl_lehrveranstaltung.aktiv, + planfaktor as lv_planfaktor, planlektoren as lv_planlektoren, planpersonalkosten as lv_planpersonalkosten, + plankostenprolektor as lv_plankostenprolektor, lehrform_kurzbz as lv_lehrform_kurzbz, tbl_lehrveranstaltung.orgform_kurzbz, + tbl_studienplan_lehrveranstaltung.studienplan_id::text as studienplan_id, tbl_studienplan.bezeichnung as studienplan_bezeichnung, tbl_studienplan_lehrveranstaltung.studienplan_lehrveranstaltung_id_parent::text, + tbl_lehrveranstaltung.lehrtyp_kurzbz + FROM + lehre.tbl_lehrveranstaltung + JOIN lehre.tbl_studienplan_lehrveranstaltung USING(lehrveranstaltung_id) + JOIN lehre.tbl_studienplan USING(studienplan_id) + WHERE + tbl_lehrveranstaltung.aktiv AND ((studienplan_id, tbl_studienplan_lehrveranstaltung.semester) IN ( " . implode(',', $placeholders) . ")) + UNION + "; + } + + public function getAllOe($lv_id, $stg_kz = null) + { + $qry = "SELECT DISTINCT oe_kurzbz + FROM lehre.tbl_studienplan_lehrveranstaltung + JOIN lehre.tbl_studienplan USING(studienplan_id) + JOIN lehre.tbl_studienordnung USING(studienordnung_id) + JOIN public.tbl_studiengang USING(studiengang_kz) + WHERE lehrveranstaltung_id = ? "; + + $params = array($lv_id); + if (!is_null($stg_kz)) + { + $qry .= ' OR studiengang_kz = ?'; + $params[] = $stg_kz; + } + + return $this->execReadOnlyQuery($qry, $params); + } } diff --git a/application/models/organisation/Organisationseinheit_model.php b/application/models/organisation/Organisationseinheit_model.php index 1b1a826aa..b07a90c87 100644 --- a/application/models/organisation/Organisationseinheit_model.php +++ b/application/models/organisation/Organisationseinheit_model.php @@ -217,4 +217,34 @@ class Organisationseinheit_model extends DB_Model oe_kurzbz ILIKE '%". $this->escapeLike($eventQuery). "%' "); } + + /** + * Ermittelt die Stundenobergrenze fuer Lektoren + * Dabei wird im OE Baum nach oben nach Stundengrenzen gesucht und die niedrigste Stundengrenze ermittelt + * @param $oe_kurzbz Organisationseinheit + * @param $fixangestellt boolean legt fest ob die Grenze + * fuer Freie oder Fixangestellte Lektoren ermittelt werden soll + + */ + public function getStundengrenze($oe_kurzbz, $fixangestellt = true) + { + $fixfrei = $fixangestellt ? 'fix' : 'frei'; + + $qry = " + WITH RECURSIVE oes(oe_kurzbz, oe_parent_kurzbz) as + ( + SELECT oe_kurzbz, oe_parent_kurzbz FROM public.tbl_organisationseinheit + WHERE oe_kurzbz= ? + UNION ALL + SELECT o.oe_kurzbz, o.oe_parent_kurzbz FROM public.tbl_organisationseinheit o, oes + WHERE o.oe_kurzbz=oes.oe_parent_kurzbz + ) + SELECT oe_kurzbz, warn_semesterstunden_{$fixfrei} AS stunden + FROM oes + JOIN public.tbl_organisationseinheit USING (oe_kurzbz) + ORDER BY warn_semesterstunden_{$fixfrei} ASC + LIMIT 1"; + + return $this->execReadOnlyQuery($qry, array($oe_kurzbz)); + } } diff --git a/application/models/organisation/Studienplan_model.php b/application/models/organisation/Studienplan_model.php index e35ba52fb..5a9097d9a 100644 --- a/application/models/organisation/Studienplan_model.php +++ b/application/models/organisation/Studienplan_model.php @@ -134,4 +134,25 @@ class Studienplan_model extends DB_Model 'prestudent_id' => $prestudent_id ]); } + + public function loadStudienplanLehrveranstaltung($lv_id) + { + $qry = "SELECT studienplan_lehrveranstaltung_id, + semester, + pflicht, + studienplan_id, + koordinator, + studienplan_lehrveranstaltung_id_parent, + lehrveranstaltung_id, + insertamum, + insertvon, + updateamum, + updatevon, + sort, + curriculum, + export + FROM lehre.tbl_studienplan_lehrveranstaltung WHERE studienplan_lehrveranstaltung_id = ? "; + return $this->execReadOnlyQuery($qry, array($lv_id)); + } + } diff --git a/application/models/person/Notiz_model.php b/application/models/person/Notiz_model.php index 2e99d1cdd..e13c6ccb9 100644 --- a/application/models/person/Notiz_model.php +++ b/application/models/person/Notiz_model.php @@ -151,36 +151,36 @@ class Notiz_model extends DB_Model * bestellung_id, lehreinheit_id, anrechnung_id, uid) * @param $id the corresponding id, part of public.tbl_notizzuordnung */ - public function getNotizWithDocEntries($id, $type) + public function getNotizWithDocEntries($id, $type, $withoutTags = true) { - $qry = " - SELECT - n.*, count(dms_id) as countDoc, z.notizzuordnung_id, - (CASE - WHEN n.updateamum >= n.insertamum THEN n.updateamum - ELSE n.insertamum - END) AS lastUpdate, - regexp_replace(n.text, '<[^>]*>', '', 'g') as text_stripped, - TO_CHAR(n.start::timestamp, 'DD.MM.YYYY') AS start_format, - TO_CHAR(n.ende::timestamp, 'DD.MM.YYYY') AS ende_format, - z.notiz_id, z.person_id as id, ? as type_id - - FROM - public.tbl_notiz n - JOIN - public.tbl_notizzuordnung z USING (notiz_id) - LEFT JOIN - public.tbl_notiz_dokument dok USING (notiz_id) - LEFT JOIN - campus.tbl_dms_version USING (dms_id) - WHERE - z.$type = ? - GROUP BY - notiz_id, z.notizzuordnung_id - "; + $this->addSelect("tbl_notiz.*, + count(dms_id) as countDoc, + z.notizzuordnung_id, + (CASE + WHEN tbl_notiz.updateamum >= tbl_notiz.insertamum THEN tbl_notiz.updateamum + ELSE tbl_notiz.insertamum + END) AS lastUpdate, + regexp_replace(tbl_notiz.text, '<[^>]*>', '', 'g') as text_stripped, + TO_CHAR(tbl_notiz.start::timestamp, 'DD.MM.YYYY') AS start_format, + TO_CHAR(tbl_notiz.ende::timestamp, 'DD.MM.YYYY') AS ende_format, + z.notiz_id, + z.person_id as id, + {$type} as type_id + "); - return $this->execQuery($qry, array($type, $id)); + $this->addJoin('public.tbl_notizzuordnung z', 'notiz_id'); + $this->addJoin('public.tbl_notiz_dokument dok', 'notiz_id', 'LEFT'); + $this->addJoin('campus.tbl_dms_version', 'dms_id', 'LEFT'); + $this->db->where("z.{$type}", $id); + + if ($withoutTags) + $this->db->where('tbl_notiz.typ IS NULL'); + + $this->addGroupBy('notiz_id'); + $this->addGroupBy('z.notizzuordnung_id'); + + return $this->load(); } diff --git a/application/models/ressource/Mitarbeiter_model.php b/application/models/ressource/Mitarbeiter_model.php index 836f5d65a..337997b8e 100644 --- a/application/models/ressource/Mitarbeiter_model.php +++ b/application/models/ressource/Mitarbeiter_model.php @@ -278,4 +278,18 @@ class Mitarbeiter_model extends DB_Model return $this->execQuery($qry, $parametersArray); } + + public function isLehrauftragFirma($mitarbeiter_uid) + { + $this->addSelect('firma_id'); + $this->addJoin('public.tbl_benutzer', 'uid = mitarbeiter_uid'); + $this->addJoin('public.tbl_person', 'person_id'); + $this->addJoin('public.tbl_adresse', 'person_id', 'LEFT'); + $this->addOrder('zustelladresse', 'DESC'); + $this->addOrder('firma_id'); + $this->addLimit(1); + $firma_result = $this->loadWhere(array('mitarbeiter_uid' => $mitarbeiter_uid)); + $firma = getData($firma_result)[0]->firma_id; + return !is_null($firma); + } } diff --git a/application/models/ressource/Stundenplandev_model.php b/application/models/ressource/Stundenplandev_model.php index 800540d60..82b3779ab 100644 --- a/application/models/ressource/Stundenplandev_model.php +++ b/application/models/ressource/Stundenplandev_model.php @@ -10,6 +10,9 @@ class Stundenplandev_model extends DB_Model parent::__construct(); $this->dbTable = 'lehre.tbl_stundenplandev'; $this->pk = 'stundenplandev_id'; + + $this->load->model('education/lehreinheit_model', 'LehreinheitModel'); + $this->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel'); } @@ -157,4 +160,84 @@ class Stundenplandev_model extends DB_Model return $this->execQuery($qry, $params); } + public function deleteGroupPlanning($lehreinheit_id, $lehreinheitgruppe_id) + { + $lehreinheit = $this->LehreinheitModel->load($lehreinheit_id); + + if (!hasData($lehreinheit)) + return error ('No Lehreinheit found!'); + + $lehreinheitgruppe = $this->LehreinheitgruppeModel->load($lehreinheitgruppe_id); + + if (!hasData($lehreinheitgruppe)) + return error ('No Lehreinheitgruppe found!'); + + $this->addJoin('lehre.tbl_stundenplan_betriebsmittel', 'stundenplandev_id'); + $this->addJoin('lehre.tbl_lehreinheitgruppe', 'lehreinheit_id'); + $this->db->where('tbl_lehreinheitgruppe.lehreinheitgruppe_id', $lehreinheitgruppe_id); + + $this->db->group_start(); + $this->db->group_start(); + $this->db->where('tbl_lehreinheitgruppe.gruppe_kurzbz IS NOT NULL', null, false); + $this->db->where('tbl_lehreinheitgruppe.gruppe_kurzbz = tbl_stundenplandev.gruppe_kurzbz', null, false); + $this->db->group_end(); + $this->db->or_group_start(); + $this->db->where('tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL', null, false); + $this->db->where('tbl_lehreinheitgruppe.studiengang_kz = tbl_stundenplandev.studiengang_kz', null, false); + $this->db->where('tbl_lehreinheitgruppe.semester = tbl_stundenplandev.semester', null, false); + $this->db->where('tbl_lehreinheitgruppe.verband = tbl_stundenplandev.verband', null, false); + $this->db->where('tbl_lehreinheitgruppe.gruppe = tbl_stundenplandev.gruppe', null, false); + $this->db->group_end(); + $this->db->group_end(); + + $betriebsmittel_result = $this->load(); + $betriebsmittel_array = hasData($betriebsmittel_result) ? getData($betriebsmittel_result) : array(); + if (sizeof($betriebsmittel_array) > 0) + { + return error ('Gruppe kann nicht entfernt werden da bereits Ressourcen zugeordnet wurden'); + } + + $this->addSelect('stundenplandev_id'); + $this->addJoin('lehre.tbl_lehreinheitgruppe', + "tbl_stundenplandev.lehreinheit_id = tbl_lehreinheitgruppe.lehreinheit_id + AND tbl_stundenplandev.studiengang_kz = tbl_lehreinheitgruppe.studiengang_kz + AND tbl_stundenplandev.semester = tbl_lehreinheitgruppe.semester + AND trim(COALESCE(tbl_stundenplandev.verband, '')) = trim(COALESCE(tbl_lehreinheitgruppe.verband, '')) + AND trim(COALESCE(tbl_stundenplandev.gruppe, '')) = trim(COALESCE(tbl_lehreinheitgruppe.gruppe, '')) + AND trim(COALESCE(tbl_stundenplandev.gruppe_kurzbz, '')) = trim(COALESCE(tbl_lehreinheitgruppe.gruppe_kurzbz, ''))" + ); + $stundenplan_result = $this->loadWhere(array('tbl_lehreinheitgruppe.lehreinheitgruppe_id' => $lehreinheitgruppe_id)); + + if (hasData($stundenplan_result)) + { + $stundenplan_ids = array_column(getData($stundenplan_result), 'stundenplandev_id'); + $this->db->where_in('stundenplandev_id', $stundenplan_ids); + $delete_result = $this->db->delete('lehre.tbl_stundenplandev'); + + if ($delete_result) + return success('Group deleted successfully from Stundenplandev'); + else + return error('Error deleting Group from Stundenplandev'); + } + } + + public function deleteLektorPlanning($lehreinheit_id, $mitarbeiter_uid) + { + $this->addDistinct('mitarbeiter_uid'); + $this->addSelect('mitarbeiter_uid'); + $stundenplan_result = $this->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); + $stundenplan_array = hasData($stundenplan_result) ? (getData($stundenplan_result)) : array(); + + if (sizeof($stundenplan_array) <= 1) + return error('Diese/r LektorIn kann nicht aus dem LVPlan entfernt werden da dies der/die letzte verplante LektorIn ist'); + + $this->addJoin('lehre.tbl_stundenplan_betriebsmittel', 'stundenplandev_id'); + $betriebsmittel_result = $this->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'tbl_stundenplandev.mitarbeiter_uid' => $mitarbeiter_uid)); + $betriebsmittel_array = hasData($betriebsmittel_result) ? getData($betriebsmittel_result) : array(); + + if (sizeof($betriebsmittel_array) > 0) + return error('Gruppe kann nicht entfernt werden da bereits Ressourcen zugeordnet wurden'); + + return $this->delete(array('lehreinheit_id' => $lehreinheit_id, 'mitarbeiter_uid' => $mitarbeiter_uid)); + } } diff --git a/application/models/ressource/Stundensatz_model.php b/application/models/ressource/Stundensatz_model.php index 10f5a6aa1..f34ad07ed 100644 --- a/application/models/ressource/Stundensatz_model.php +++ b/application/models/ressource/Stundensatz_model.php @@ -42,4 +42,20 @@ class Stundensatz_model extends DB_Model return $this->execQuery($qry, $params); } + + public function getDefaultStundensatz($mitarbeiter_uid, $beginn, $ende = null, $typ = null) + { + $stundensatz_result = $this->getStundensatzByDatum($mitarbeiter_uid, $beginn, $ende, $typ); + $default_stundensatz = hasData($stundensatz_result) ? getData($stundensatz_result)[0]->stundensatz : null; + if (defined('FAS_LV_LEKTORINNENZUTEILUNG_FIXANGESTELLT_STUNDENSATZ') && !FAS_LV_LEKTORINNENZUTEILUNG_FIXANGESTELLT_STUNDENSATZ) + { + $this->load->model('vertragsbestandteil/Dienstverhaeltnis_model','DienstverhaeltnisModel'); + $echterdv_result = $this->DienstverhaeltnisModel->existsDienstverhaeltnis($mitarbeiter_uid, $beginn, $ende, 'echterdv'); + if (hasData($echterdv_result)) + { + $default_stundensatz = null; + } + } + return $default_stundensatz; + } } \ No newline at end of file diff --git a/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php b/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php index f81a2d518..b055ee954 100644 --- a/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php +++ b/application/models/vertragsbestandteil/Dienstverhaeltnis_model.php @@ -253,4 +253,25 @@ EOSQL; } return $dvs; } + + public function existsDienstverhaeltnis($mitarbeiter_uid, $start, $ende = null, $vertragsart_kurzbz = null) + { + $this->addOrder('von', 'DESC'); + $this->db->where('mitarbeiter_uid', $mitarbeiter_uid); + if (!is_null($vertragsart_kurzbz)) + $this->db->where('vertragsart_kurzbz', $this->escape($vertragsart_kurzbz)); + + $this->db->where('von <=', $ende); + + if (!is_null($ende)) + { + $this->db->group_start(); + $this->db->where('bis >=', $start); + $this->db->or_where('bis IS NULL', null, false); + $this->db->group_end(); + } + + $this->addLimit(1); + return $this->load(); + } } diff --git a/application/views/LVVerwaltung.php b/application/views/LVVerwaltung.php new file mode 100644 index 000000000..4cebae839 --- /dev/null +++ b/application/views/LVVerwaltung.php @@ -0,0 +1,39 @@ + 'LVVerwaltung', + 'axios027' => true, + 'bootstrap5' => true, + 'fontawesome6' => true, + 'vue3' => true, + 'primevue3' => true, + 'tabulator6' => true, + 'tinymce5' => true, + 'tags' => true, + + 'customCSSs' => [ + 'public/css/components/vue-datepicker.css', + 'public/css/components/primevue.css', + 'public/css/Studentenverwaltung.css', + 'public/css/Lvverwaltung.css' + + ], + 'customJSModules' => [ + 'public/js/apps/LVVerwaltung.js' + ] + ); + + $this->load->view('templates/FHC-Header', $includesArray); + +?> +
+ + + +
+load->view('templates/FHC-Footer', $includesArray); ?> + diff --git a/public/css/Lvverwaltung.css b/public/css/Lvverwaltung.css new file mode 100644 index 000000000..1ca3f0be1 --- /dev/null +++ b/public/css/Lvverwaltung.css @@ -0,0 +1,27 @@ +textarea[name="anmerkung"] { + position: absolute; + max-height: 300px; +} + +.lv_table_icon::before +{ + font-family: 'Font Awesome 6 Free'; + font-weight: 900; + margin-left: 5px; + display: inline-block; +} + +.lv_table_icon.icon-modul::before +{ + content: '\f468'; +} + +.lv_table_icon.icon-lv::before +{ + content: '\f466'; +} + +.lv_table_icon.icon-::before +{ + content: '\f073'; +} \ No newline at end of file diff --git a/public/js/api/factory/notiz.js b/public/js/api/factory/notiz.js index 074d4b6a5..ce14269d6 100644 --- a/public/js/api/factory/notiz.js +++ b/public/js/api/factory/notiz.js @@ -16,7 +16,10 @@ */ import person from "./notiz/person.js"; +import lehreinheit from "./notiz/lehreinheit.js"; + export default { - person + person, + lehreinheit }; diff --git a/public/js/api/factory/notiz/lehreinheit.js b/public/js/api/factory/notiz/lehreinheit.js new file mode 100644 index 000000000..d93bb50f9 --- /dev/null +++ b/public/js/api/factory/notiz/lehreinheit.js @@ -0,0 +1,29 @@ +/** + * 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 . + */ + +import Person from './person.js'; + +export default { + + ...Person, + getNotizen(id, type) { + return { + method: 'get', + url: 'api/frontend/v1/notiz/notizLehreinheit/getNotizen/' + encodeURIComponent(id) + '/' + encodeURIComponent(type) + }; + }, +}; diff --git a/public/js/api/lehrveranstaltung.js b/public/js/api/lehrveranstaltung.js new file mode 100644 index 000000000..0499572ba --- /dev/null +++ b/public/js/api/lehrveranstaltung.js @@ -0,0 +1,28 @@ +export default { + + getByLV(lehrveranstaltung_id) + { + return { + method: 'get', + url: '/api/frontend/v1/Lehrveranstaltung/loadByLV/' + encodeURIComponent(lehrveranstaltung_id) + }; + }, + getByStg(studiengang_kz, semester) + { + return ("/api/frontend/v1/Lehrveranstaltung/loadByStudiengang/" + encodeURIComponent(studiengang_kz) + "/" + encodeURIComponent(semester)); + }, + + getByEmpStg(mitarbeiter_uid, stg) + { + return ("/api/frontend/v1/Lehrveranstaltung/loadByEmployee/" + encodeURIComponent(mitarbeiter_uid) + "/" + encodeURIComponent(stg)); + }, + + getTable(url) + { + return { + method: 'get', + url: url + }; + }, + +} \ No newline at end of file diff --git a/public/js/api/lehrveranstaltung/details.js b/public/js/api/lehrveranstaltung/details.js new file mode 100644 index 000000000..db251330a --- /dev/null +++ b/public/js/api/lehrveranstaltung/details.js @@ -0,0 +1,30 @@ +export default { + getStudiensemester() + { + return { + method: 'get', + url: '/api/frontend/v1/lv/setup/getStudiensemester/' + }; + }, + getSprache() + { + return { + method: 'get', + url: '/api/frontend/v1/lv/setup/getSprache/' + }; + }, + getLehrform() + { + return { + method: 'get', + url: '/api/frontend/v1/lv/setup/getLehrform/' + }; + }, + getRaumtyp() + { + return { + method: 'get', + url: '/api/frontend/v1/lv/setup/getRaumtyp/' + }; + }, +} diff --git a/public/js/api/lehrveranstaltung/direktgruppe.js b/public/js/api/lehrveranstaltung/direktgruppe.js new file mode 100644 index 000000000..9cd72fcc7 --- /dev/null +++ b/public/js/api/lehrveranstaltung/direktgruppe.js @@ -0,0 +1,26 @@ +export default { + add(newData) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/DirektGruppe/add/', + params: newData + }; + }, + delete(deleteData) + { + + return { + method: 'post', + url: '/api/frontend/v1/lv/DirektGruppe/delete/', + params: deleteData + }; + }, + getByLehreinheit(lehreinheit_id) + { + return { + method: 'get', + url: '/api/frontend/v1/lv/DirektGruppe/getByLehreinheit/' + encodeURIComponent(lehreinheit_id) + }; + }, +} diff --git a/public/js/api/lehrveranstaltung/gruppe.js b/public/js/api/lehrveranstaltung/gruppe.js new file mode 100644 index 000000000..12c55509c --- /dev/null +++ b/public/js/api/lehrveranstaltung/gruppe.js @@ -0,0 +1,56 @@ +export default { + + delete(deleteData) + { + + return { + method: 'post', + url: '/api/frontend/v1/lv/gruppe/delete/', + params: deleteData + }; + }, + + add(newData) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/gruppe/add/', + params: newData + }; + }, + getByLehreinheit(lehreinheit_id) + { + return { + method: 'get', + url: '/api/frontend/v1/lv/gruppe/getByLehreinheit/' + encodeURIComponent(lehreinheit_id) + }; + }, + + deleteFromLVPlan(deleteData) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/gruppe/deleteLVPlan/', + params: deleteData + }; + }, + + +/*------------- details -------- */ + getAll() + { + return { + method: 'get', + url: '/api/frontend/v1/lv/gruppe/getAll/' + }; + }, + + getBenutzer() + { + return { + method: 'get', + url: '/api/frontend/v1/lv/gruppe/getBenutzer/' + }; + } + +} diff --git a/public/js/api/lehrveranstaltung/lehreinheit.js b/public/js/api/lehrveranstaltung/lehreinheit.js new file mode 100644 index 000000000..d8f12e27a --- /dev/null +++ b/public/js/api/lehrveranstaltung/lehreinheit.js @@ -0,0 +1,41 @@ +export default { + copy(data) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/lehreinheit/copy/', + params: data + }; + }, + delete(data) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/lehreinheit/delete/', + params: data + }; + }, + add(newData) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/lehreinheit/add/', + params: newData + }; + }, + get(lehreinheit) + { + return { + method: 'get', + url: '/api/frontend/v1/lv/lehreinheit/get/' + encodeURIComponent(lehreinheit) + }; + }, + update(updatedData) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/lehreinheit/update/', + params: updatedData + }; + }, +} diff --git a/public/js/api/lehrveranstaltung/lektor.js b/public/js/api/lehrveranstaltung/lektor.js new file mode 100644 index 000000000..e8c2fb673 --- /dev/null +++ b/public/js/api/lehrveranstaltung/lektor.js @@ -0,0 +1,78 @@ +export default { + + getLehrfunktionen() + { + return { + method: 'get', + url: '/api/frontend/v1/lv/lektor/getLehrfunktionen/' + }; + }, + + + getLektoren() + { + return { + method: 'get', + url: '/api/frontend/v1/lv/lektor/getLektoren/' + }; + }, + + + getByLehreinheit(lehreinheit_id) + { + return { + method: 'get', + url: '/api/frontend/v1/lv/lektor/getLektorenByLE/' + encodeURIComponent(lehreinheit_id) + }; + }, + + + add(newData) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/lektor/add/', + params: newData + }; + }, + + update(updatedData) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/lektor/update/', + params: updatedData + }; + }, + + + deletePerson(deleteData) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/lektor/deletePerson/', + params: deleteData + }; + }, + deleteFromLVPlan(deleteData) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/lektor/deleteLVPlan/', + params: deleteData + }; + }, + getLektorDaten(lehreinheit_id, mitarbeiter_uid) + { + return { + method: 'get', + url: '/api/frontend/v1/lv/lektor/getLektorDaten/' + encodeURIComponent(lehreinheit_id) + '/' + encodeURIComponent(mitarbeiter_uid) + }; + }, + + + + + + +} diff --git a/public/js/api/lehrveranstaltung/setup.js b/public/js/api/lehrveranstaltung/setup.js new file mode 100644 index 000000000..78f78b05b --- /dev/null +++ b/public/js/api/lehrveranstaltung/setup.js @@ -0,0 +1,9 @@ +export default { + getTabs() + { + return { + method: 'get', + url: '/api/frontend/v1/lv/setup/getTabs/' + }; + }, +} diff --git a/public/js/api/lehrveranstaltung/studiengangtree.js b/public/js/api/lehrveranstaltung/studiengangtree.js new file mode 100644 index 000000000..fb63db729 --- /dev/null +++ b/public/js/api/lehrveranstaltung/studiengangtree.js @@ -0,0 +1,43 @@ +/** + * 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 . + */ + +export default { + get(path) { + let url = 'api/frontend/v1/lv/StgTree'; + if (path) + url += '/' + path; + return { + method: 'get', + url + }; + }, + favorites: { + get() { + return { + method: 'get', + url: 'api/frontend/v1/lv/favorites' + }; + }, + set(favorites) { + return { + method: 'post', + url: 'api/frontend/v1/lv/favorites/set', + params: { favorites } + }; + } + } +}; \ No newline at end of file diff --git a/public/js/api/lehrveranstaltung/tag.js b/public/js/api/lehrveranstaltung/tag.js new file mode 100644 index 000000000..3d5a5f2ea --- /dev/null +++ b/public/js/api/lehrveranstaltung/tag.js @@ -0,0 +1,54 @@ +export default { + + getTag(data) + { + return { + method: 'get', + url: 'api/frontend/v1/lv/Tags/getTag', + params: data + }; + }, + + getTags(data) + { + return { + method: 'get', + url: 'api/frontend/v1/lv/Tags/getTags' + }; + }, + + addTag(data) + { + return { + method: 'post', + url: 'api/frontend/v1/lv/Tags/addTag', + params: data + }; + }, + + updateTag(data) + { + return { + method: 'post', + url: 'api/frontend/v1/lv/Tags/updateTag', + params: data + }; + }, + doneTag(data) + { + return { + method: 'post', + url: 'api/frontend/v1/lv/Tags/doneTag', + params: data + }; + }, + + deleteTag(data) + { + return { + method: 'post', + url: 'api/frontend/v1/lv/Tags/deleteTag', + params: data + }; + }, +}; \ No newline at end of file diff --git a/public/js/api/lehrveranstaltung/vertrag.js b/public/js/api/lehrveranstaltung/vertrag.js new file mode 100644 index 000000000..601f4b7e3 --- /dev/null +++ b/public/js/api/lehrveranstaltung/vertrag.js @@ -0,0 +1,22 @@ +export default { + + getByLeEmp(lehreinheit_id, mitarbeiter_uid) + { + return { + method: 'get', + url: '/api/frontend/v1/lv/lektor/getLektorDaten/' + encodeURIComponent(lehreinheit_id) + '/' + encodeURIComponent(mitarbeiter_uid), + }; + }, + + cancelByLeEmp(needUpdate) + { + return { + method: 'post', + url: '/api/frontend/v1/lv/lektor/cancelVertrag/', + params: needUpdate + }; + }, + + + +} diff --git a/public/js/apps/LVVerwaltung.js b/public/js/apps/LVVerwaltung.js new file mode 100644 index 000000000..c582f817e --- /dev/null +++ b/public/js/apps/LVVerwaltung.js @@ -0,0 +1,46 @@ +import LVVerwaltung from "../components/LVVerwaltung/LVVerwaltung.js"; +import Phrasen from "../plugins/Phrasen.js"; + +const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router; + +const router = VueRouter.createRouter({ + history: VueRouter.createWebHistory(`/${ciPath}/LVVerwaltung`), + routes: [ + { + name: 'index', + path: `/`, + component: LVVerwaltung + }, + { + name: `byEmp`, + path: `/emp/:emp/:stg?`, + component: LVVerwaltung + }, + /*{ + name: `byFachbereich`, + path: `/fachbereich/:fachbereich/:emp?`, + component: LVVerwaltung + },*/ + { + name: `byStg`, + path: `/stg/:stg/:semester?`, + component: LVVerwaltung + }, + { + path: '/:pathMatch(.*)*', + redirect: '/' + } + ] +}); + +const app = Vue.createApp(); + +app + .use(router) + .use(primevue.config.default, { + zIndex: { + overlay: 1100 + } + }) + .use(Phrasen) + .mount('#main'); diff --git a/public/js/components/LVVerwaltung/Details/Direktinskription.js b/public/js/components/LVVerwaltung/Details/Direktinskription.js new file mode 100644 index 000000000..c7b8e5894 --- /dev/null +++ b/public/js/components/LVVerwaltung/Details/Direktinskription.js @@ -0,0 +1,155 @@ +import {CoreFilterCmpt} from "../../filter/Filter.js"; +import FormForm from '../../Form/Form.js'; +import FormInput from '../../Form/Input.js'; +import ApiDirektGruppe from "../../../api/lehrveranstaltung/direktgruppe.js"; +export default{ + name: "LVDirektGruppen", + components: { + CoreFilterCmpt, + FormForm, + FormInput + }, + props: { + lehreinheit_id: Number + }, + inject: { + dropdowns: { + from: 'dropdowns' + }, + }, + computed: { + tabulatorOptions() { + return { + ajaxURL: 'dummy', + ajaxRequestFunc: () => this.$api.call(ApiDirektGruppe.getByLehreinheit(this.lehreinheit_id)), + ajaxResponse: (url, params, response) => { return response.data || [] }, + columns:[ + {title: this.$p.t('person', 'uid'), field:"uid"}, + {title: this.$p.t('person', 'vorname'), field:"vorname"}, + {title: this.$p.t('person', 'nachname'), field:"nachname"}, + {title: this.$p.t('lehre', 'gruppe'), field:"gruppe_kurzbz"}, + { + title: this.$p.t('global', 'actions'), field: 'actions', + minWidth: 150, + formatter: (cell, formatterParams, onRendered) => { + let container = document.createElement('div'); + let button = document.createElement('button'); + container.className = "d-flex gap-1"; + + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'loeschen'); + button.addEventListener('click', (event) => { + event.stopPropagation(); + this.deleteDirektGroup(cell.getData().gruppe_kurzbz, cell.getData().uid) + }); + container.append(button); + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + selectable: true, + persistenceID: 'lvverwaltung_direkt_gruppen_2025_05_27_v1', + height: 'auto', + } + } + }, + data() { + return{ + lastSelected: null, + gruppen: [], + tabulatorEvents: [], + showAutocomplete: false, + selectedUser: null, + filteredUsers: [], + abortController: null, + searchTimeout: null, + } + }, + watch: { + lehreinheit_id(n) { + this.$refs.table.reloadTable(); + } + }, + methods:{ + reload() { + this.$refs.table.reloadTable(); + }, + + deleteDirektGroup(gruppe_kurzbz, uid) + { + let deleteData = { + 'gruppe_kurzbz': gruppe_kurzbz, + 'uid': uid, + 'lehreinheit_id': this.lehreinheit_id + } + + this.$api.call(ApiDirektGruppe.delete(deleteData)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + this.reload(); + }) + }, + searchUser(event) + { + const query = event.query.toLowerCase().trim(); + this.filteredUsers = this.dropdowns.benutzer_array.filter(user => { + + const fullName = `${user.vorname.toLowerCase()} ${user.nachname.toLowerCase()}`; + const reverseFullName = `${user.nachname.toLowerCase()} ${user.vorname.toLowerCase()}`; + return fullName.includes(query) || reverseFullName.includes(query) || user.uid.toLowerCase().includes(query) || user.studiengang.toLowerCase().includes(query); + }).map(user => ({ + label: user.studiengang + ? `${user.nachname} ${user.vorname} ${user.uid} ${user.studiengang} ${user.semester}` + : `${user.nachname} ${user.vorname} ${user.uid}`, + uid: user.uid + })); + }, + addUser() + { + let newData = { + 'uid': this.selectedUser.uid, + 'lehreinheit_id': this.lehreinheit_id + } + return this.$api.call(ApiDirektGruppe.add(newData)) + .then(result => { + this.reload() + this.selectedUser = '' + }) + .catch(this.$fhcAlert.handleSystemError); + }, + }, + template: ` + + + + + ` +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Details/Form.js b/public/js/components/LVVerwaltung/Details/Form.js new file mode 100644 index 000000000..eed65f7ad --- /dev/null +++ b/public/js/components/LVVerwaltung/Details/Form.js @@ -0,0 +1,209 @@ +import CoreForm from '../../Form/Form.js'; +import FormInput from '../../Form/Input.js'; + +export default { + name: "LVDetailsForm", + components: { + FormInput, + CoreForm + }, + props: { + data: { + type: Object, + required: true + } + }, + inject: { + dropdowns: { + from: 'dropdowns' + }, + showLVID: { + from: 'permissionLehrveranstaltung', + default: false + }, + showGewichtung: { + from: 'configShowGewichtung', + default: true + } + }, + computed: { + formattedAnmerkung: { + get() { + return (this.data.anmerkung || '').replace(/\\n/g, '\n'); + }, + set(value) { + this.data.anmerkung = (value || '').replace(/\n/g, '\\n'); + } + } + }, + template: ` +
+
+ + + +
+
+ + + + + + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + + + + + +
+ +
+ + + +
+
+` +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Details/Gruppen.js b/public/js/components/LVVerwaltung/Details/Gruppen.js new file mode 100644 index 000000000..62dae172f --- /dev/null +++ b/public/js/components/LVVerwaltung/Details/Gruppen.js @@ -0,0 +1,195 @@ +import {CoreFilterCmpt} from "../../filter/Filter.js"; +import FormForm from '../../Form/Form.js'; +import FormInput from '../../Form/Input.js'; +import ApiGruppe from "../../../api/lehrveranstaltung/gruppe.js"; +export default{ + name: "LVGruppen", + components: { + CoreFilterCmpt, + FormForm, + FormInput + }, + props: { + lehreinheit_id: Number + }, + inject: { + dropdowns: { + from: 'dropdowns' + }, + showLVPlanGruppenDel: { + from: 'permissionGruppenEntfernen', + default: false + }, + }, + computed: { + tabulatorOptions() { + return { + ajaxURL: 'dummy', + ajaxRequestFunc: () => this.$api.call(ApiGruppe.getByLehreinheit(this.lehreinheit_id)), + ajaxResponse: (url, params, response) => response.data, + columns:[ + {title: this.$p.t('global', 'bezeichnung'), field:"bezeichnung"}, + {title: this.$p.t('global', 'beschreibung'), field:"beschreibung"}, + {title: this.$p.t('lehre', 'studiengang'), field:"studiengang"}, + {title: "ID", field:"id", visible:false}, + { + title: this.$p.t('lehre', 'verplant'), + field:"verplant", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + } + }, + { + title: this.$p.t('global', 'actions'), field: 'actions', + minWidth: 150, + formatter: (cell, formatterParams, onRendered) => { + let container = document.createElement('div'); + let button = document.createElement('button'); + container.className = "d-flex gap-1"; + + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'loeschen'); + button.addEventListener('click', (event) => { + event.stopPropagation(); + this.deleteGroup(cell.getData().lehreinheitgruppe_id) + }); + container.append(button); + + if (this.showLVPlanGruppenDel) + { + button = document.createElement('button'); + container.className = "d-flex gap-2"; + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('lehre', 'auslvplanentfernen'); + button.disabled = !cell.getData().verplant; + button.addEventListener('click', (event) => { + event.stopPropagation(); + this.deleteLVPlan(cell.getData().lehreinheitgruppe_id) + }); + container.append(button); + } + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + selectable: true, + persistenceID: 'lvverwaltung_gruppen_2025_05_27_v1', + height: 'auto', + } + } + }, + data() { + return{ + tabulatorEvents: [], + showAutocomplete: false, + filteredGroups: [], + selectedGroup: null + } + }, + watch: { + lehreinheit_id() { + this.$refs.table.reloadTable(); + } + }, + methods:{ + searchGroup(event) + { + const query = event.query.toLowerCase().trim(); + this.filteredGroups = this.dropdowns.gruppen_array.filter(gruppe => { + return gruppe.gruppe_kurzbz.toLowerCase().includes(query); + }).map(gruppe => ({ + label: gruppe.bezeichnung + ? `${gruppe.gruppe_kurzbz.trim()} (${gruppe.bezeichnung})` + : gruppe.gruppe_kurzbz.trim(), + gid: gruppe.gid, + gruppe_kurzbz: gruppe.gruppe_kurzbz.trim(), + lehrverband: gruppe.lehrverband, + })); + }, + reload() { + this.$refs.table.reloadTable(); + }, + addGroup() + { + let newData = { + 'gid': this.selectedGroup.gid, + 'lehreinheit_id': this.lehreinheit_id, + 'lehrverband': this.selectedGroup.lehrverband, + 'gruppe_kurzbz' : this.selectedGroup.gruppe_kurzbz + } + + return this.$api.call(ApiGruppe.add(newData)) + .then(result => { + this.reload() + this.selectedGroup = '' + }) + .catch(this.$fhcAlert.handleSystemError); + }, + deleteLVPlan(lehreinheitgruppe_id) + { + let deleteData = { + 'lehreinheitgruppe_id': lehreinheitgruppe_id, + 'lehreinheit_id': this.lehreinheit_id + } + + this.$api.call(ApiGruppe.deleteFromLVPlan(deleteData)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + this.reload(); + }) + }, + deleteGroup(lehreinheitgruppe_id) + { + let deleteData = { + 'lehreinheitgruppe_id': lehreinheitgruppe_id, + 'lehreinheit_id': this.lehreinheit_id + } + + this.$api.call(ApiGruppe.delete(deleteData)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + this.reload(); + }) + }, + }, + template: ` + + + + + ` +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js new file mode 100644 index 000000000..772af5a47 --- /dev/null +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -0,0 +1,282 @@ +import CoreSearchbar from "../searchbar/searchbar.js"; +import VerticalSplit from "../verticalsplit/verticalsplit.js"; +import StvVerband from "../Stv/Studentenverwaltung/Verband.js"; +import StvStudiensemester from "../Stv/Studentenverwaltung/Studiensemester.js"; +import LvTable from "./Setup/Table.js"; +import LvTabs from "./Setup/Tabs.js"; + +import ApiDetails from "../../api/lehrveranstaltung/details.js"; +import ApiLektor from "../../api/lehrveranstaltung/lektor.js"; +import ApiGruppe from "../../api/lehrveranstaltung/gruppe.js"; +import ApiStudiengangTree from "../../api/lehrveranstaltung/studiengangtree.js"; +import ApiSearchbar from "../../api/factory/searchbar.js"; + + +export default { + name: "LVVerwaltung", + components: { + CoreSearchbar, + VerticalSplit, + StvVerband, + StvStudiensemester, + LvTable, + LvTabs, + }, + props: { + defaultSemester: String, + lvRoot: String, + permissions: Object, + config: Object + }, + computed: { + type(){ + return this.$route.params.type + } + }, + provide() { + return { + currentSemester: Vue.computed(() => this.studiensemesterKurzbz), + dropdowns: this.dropdowns, + configShowVertragsdetails: this.config.showVertragsdetails, + configShowGewichtung: this.config.showGewichtung, + lehreinheitAnmerkungDefault: this.config.lehreinheitAnmerkungDefault, + lehreinheitRaumtypDefault: this.config.lehreinheitRaumtypDefault, + lehreinheitRaumtypAlternativeDefault: this.config.lehreinheitRaumtypAlternativeDefault, + + permissionLehrveranstaltung: this.permissions['lehre/lehrveranstaltung'], + permissionGruppenEntfernen: this.permissions['lv-plan/gruppenentfernen'], + permissionLektorEntfernen: this.permissions['lv-plan/lektorentfernen'], + } + }, + mounted() { + this.updateFilter(this.$route); + }, + watch: { + '$route'(to) { + this.updateFilter(to); + }, + }, + data() { + return { + selected: [], + studiensemesterKurzbz: this.defaultSemester, + stg: "", + filter: {}, + endpoint: ApiStudiengangTree, + dropdowns: { + studiensemester_array: [], + sprachen_array: [], + lehrform_array: [], + raumtyp_array: [], + lektor_array: [], + gruppen_array: [], + benutzer_array: [], + }, + selectedStudiengang: '', + searchbaroptions: { + cssclass: "position-relative", + calcheightonly: true, + types: [ + "mitarbeiter" + ], + actions: { + employee: { + defaultaction: { + type: "function", + action: (data) => { + this.onSelectEmployee(data.uid); + } + }, + childactions: [ + ] + }, + } + }, + } + }, + methods: { + updateFilter(route) + { + let filter = { ...route.params, ...route.query }; + if (!filter.activeFilter) + { + if (filter.emp) + { + filter.activeFilter = 'employee'; + } + else if (filter.stg) + { + filter.activeFilter = 'verband'; + } + } + this.filter = filter; + }, + handleRowClicked(data) + { + this.selected = data + }, + onSelectEmployee(emp) + { + let stg = this.stg === '' ? null : this.stg; + + this.$router.push({ + name: 'byEmp', + params: { emp, stg, activeFilter: 'employee'}, + }); + }, + + onSelectVerband({link}) + { + let stg = null; + let semester = null; + + if (typeof link === 'number') + stg = link; + else if (typeof link === 'string') + { + [stg, semester] = link.split('/'); + } + + this.stg = stg; + + if (this.filter && this.filter.emp) + { + this.$router.push({ + name: 'byEmp', + params: { emp: this.filter.emp, stg, activeFilter: 'employee' }, + }); + } + else + { + this.$router.push({ + name: 'byStg', + params: { stg, semester, activeFilter: 'verband' }, + }); + } + + this.selected = []; + }, + resetEmployeeFilter() + { + const newParams = { ...this.$route.params, activeFilter: 'verband' }; + if (newParams.stg === '') + this.$router.replace({ name: 'index' }); + else + { + delete newParams.emp; + newParams.semester = null; + this.$router.replace({ name: 'byStg', params: newParams }); + + } + }, + searchfunction(params) { + return this.$api.call(ApiSearchbar.search(params)); + }, + studiensemesterChanged(newValue) { + this.studiensemesterKurzbz = newValue; + this.$refs.lvTable.reload(); + this.selected = []; + }, + }, + created() { + if (this.$route.params.stg !== undefined) + { + this.selectedStudiengang = this.$route.params?.semester !== '' && this.$route.params?.semester + ? `${this.$route.params.stg}/${this.$route.params.semester}` + : this.$route.params.stg; + } + + this.$p.loadCategory(['lehre', 'person']) + + this.$api.call(ApiDetails.getStudiensemester()) + .then(result => { + this.dropdowns.studiensemester_array = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api.call(ApiDetails.getSprache()) + .then(result => { + this.dropdowns.sprachen_array = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api.call(ApiDetails.getLehrform()) + .then(result => { + this.dropdowns.lehrform_array = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api.call(ApiDetails.getRaumtyp()) + .then(result => { + this.dropdowns.raumtyp_array = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api.call(ApiLektor.getLehrfunktionen()) + .then(result => { + this.dropdowns.lehrfunktion_array = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api.call(ApiLektor.getLektoren()) + .then(result => { + this.dropdowns.lektor_array = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api.call(ApiGruppe.getAll()) + .then(result => { + this.dropdowns.gruppen_array = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + this.$api.call(ApiGruppe.getBenutzer()) + .then(result => { + this.dropdowns.benutzer_array = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + + template: ` +
+ +
+
+ + +
+ + + + +
+
+
+
` +}; diff --git a/public/js/components/LVVerwaltung/Lektor/Daten.js b/public/js/components/LVVerwaltung/Lektor/Daten.js new file mode 100644 index 000000000..bb40f56fe --- /dev/null +++ b/public/js/components/LVVerwaltung/Lektor/Daten.js @@ -0,0 +1,270 @@ +import {CoreFilterCmpt} from "../../filter/Filter.js"; +import CoreForm from '../../Form/Form.js'; +import FormInput from '../../Form/Input.js'; +import ApiLektor from "../../../api/lehrveranstaltung/lektor.js"; + +export default{ + name: "LVLektorDaten", + components: { + CoreFilterCmpt, + CoreForm, + FormInput + }, + props: { + lehreinheit_id: Number, + mitarbeiter_uid: String + }, + emits: [ + 'changedLektor', + 'changedCosts', + ], + inject: { + dropdowns: { + from: 'dropdowns' + } + }, + + data() { + return{ + original: null, + data: null, + changed: {}, + internal_mitarbeiter_uid: null, + filteredLektor: [], + } + }, + computed: { + changedLength() { + return Object.keys(this.changed).length; + }, + berechneteGesamtkosten() { + if (!this.data) return 0; + + const stunden = Number(this.data.semesterstunden) || 0; + const stundensatz = Number(this.data.stundensatz) || 0; + + return (stunden * stundensatz).toFixed(2); + } + }, + watch: { + lehreinheit_id: + { + deep: true, + handler(newVal, oldVal) { + this.data = null; + this.original = null; + this.internal_mitarbeiter_uid = null; + } + }, + mitarbeiter_uid: + { + deep: true, + handler(newVal, oldVal) { + this.internal_mitarbeiter_uid = newVal; + + if (newVal === null) + this.data = null; + else if (newVal !== undefined && this.lehreinheit_id !== undefined) + this.getLektorData(); + } + + }, + data: { + handler(newValue) { + if (newValue === null) + { + this.changed = {} + return + } + let changed = {}; + + let keys = Object.keys(this.original); + + for (let key of keys) + { + if (this.original[key] !== newValue[key]) + changed[key] = newValue[key]; + } + this.changed = changed; + }, + deep: true + }, + }, + methods: { + getLektorData() + { + if (!this.lehreinheit_id || !this.internal_mitarbeiter_uid) + return; + + return this.$api.call(ApiLektor.getLektorDaten(this.lehreinheit_id, this.internal_mitarbeiter_uid)) + .then(result => { + this.data = result.data; + this.original = { ...this.data }; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + updateDaten() + { + if (!this.changedLength) + return; + + if (this.changed.mitarbeiter_uid && this.changed.mitarbeiter_uid.uid) + { + this.changed.mitarbeiter_uid = this.changed.mitarbeiter_uid.uid; + } + this.$refs.form.clearValidation(); + + let updatedData = { + lehreinheit_id: this.lehreinheit_id, + mitarbeiter_uid: this.mitarbeiter_uid, + formData: this.changed + } + this.$refs.form.call(ApiLektor.update(updatedData)) + .then(result => { + let error = result.data?.error; + if (error) + this.$fhcAlert.alertWarning(error) + this.original = {...this.data}; + + if (this.changed.mitarbeiter_uid) + { + this.$emit('changedLektor', this.changed.mitarbeiter_uid); + } + if (this.changed.semesterstunden || this.changed.stundensatz) + { + this.$emit('changedCosts'); + } + this.changed = {}; + + }) + .catch(this.$fhcAlert.handleSystemError); + }, + searchLektor(event) + { + const query = event.query.toLowerCase().trim(); + this.filteredLektor = this.dropdowns.lektor_array.filter(lektor => { + const fullName = `${lektor.vorname.toLowerCase()} ${lektor.nachname.toLowerCase()}`; + const reverseFullName = `${lektor.nachname.toLowerCase()} ${lektor.vorname.toLowerCase()}`; + return fullName.includes(query) || reverseFullName.includes(query) || lektor.uid.toLowerCase().includes(query); + }).map(lektor => ({ + label: `${lektor.nachname} ${lektor.vorname} (${lektor.uid})`, + uid: lektor.uid + })); + }, + + }, + created() { + this.getLektorData() + }, + template: ` + +
+ +
+
+ {{$p.t('lehre', 'daten')}} + + +
+
+ ` +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Lektor/Table.js b/public/js/components/LVVerwaltung/Lektor/Table.js new file mode 100644 index 000000000..373a8955c --- /dev/null +++ b/public/js/components/LVVerwaltung/Lektor/Table.js @@ -0,0 +1,223 @@ +import {CoreFilterCmpt} from "../../filter/Filter.js"; +import FormForm from '../../Form/Form.js'; +import FormInput from '../../Form/Input.js'; +import ApiLektor from "../../../api/lehrveranstaltung/lektor.js"; + + +export default{ + name: "LVLektorTable", + components: { + CoreFilterCmpt, + FormForm, + FormInput + }, + props: { + lehreinheit_id: Number, + selected: String + }, + inject: { + dropdowns: { + from: 'dropdowns' + }, + showLVPlanLektorDel: { + from: 'permissionLektorEntfernen', + default: false + }, + }, + emits: ['update:selected'], + + data() { + return { + tabulatorEvents: [ + { + event: 'rowSelectionChanged', + handler: this.lektorSelected + } + ], + showAutocomplete: false, + filteredLektor: [], + selectedLektor: '' + } + }, + computed: { + tabulatorOptions() { + return { + + ajaxURL: 'dummy', + ajaxRequestFunc: () => this.$api.call(ApiLektor.getByLehreinheit(this.lehreinheit_id)), + ajaxResponse: (url, params, response) => { return response.data || [] }, + columns:[ + {title: this.$p.t('person', 'nachname'), field:"nachname"}, + {title: this.$p.t('person', 'vorname'), field:"vorname"}, + {title: this.$p.t('person', 'uid'), field:"mitarbeiter_uid"}, + {title: this.$p.t('lehre', 'lehreinheit_id'), field:"lehreinheit_id"}, + { + title: this.$p.t('lehre', 'verplant'), + field:"verplant", + formatter:"tickCross", + hozAlign:"center", + formatterParams: { + tickElement: '', + crossElement: '' + } + }, + { + title: this.$p.t('global', 'actions'), field: 'actions', + minWidth: 150, + formatter: (cell, formatterParams, onRendered) => { + let container = document.createElement('div'); + let button = document.createElement('button'); + + container.className = "d-flex gap-2"; + + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.title = this.$p.t('ui', 'loeschen'); + button.addEventListener('click', (event) => { + event.stopPropagation(); + this.deletePerson(cell.getData().mitarbeiter_uid, cell.getData().lehreinheit_id); + }); + + container.append(button); + if (this.showLVPlanLektorDel) + { + button = document.createElement('button'); + button.className = 'btn btn-outline-secondary btn-action'; + button.innerHTML = ''; + button.disabled = !cell.getData().verplant; + button.title = this.$p.t('ui', 'auslvplanentfernen'); + button.addEventListener('click', (event) => { + event.stopPropagation(); + this.deleteLVPlan(cell.getData().mitarbeiter_uid, cell.getData().lehreinheit_id) + }); + container.append(button); + } + + return container; + }, + frozen: true + }, + ], + layout: 'fitDataFill', + height: 'auto', + selectable: true, + selectableRangeMode: 'click', + selectableRows:1, + persistenceID: 'lehrveranstaltungen_lektor_table_2025_05_27_v1', + }}, + }, + mounted(){ + }, + watch: { + lehreinheit_id() { + this.$refs.table.tabulator.setData('api/frontend/v1/lv/lektor/getLektorenByLE/' + encodeURIComponent(this.lehreinheit_id)); + }, + }, + methods:{ + lektorSelected(data) + { + if (data.length > 0) + { + let mitarbeiter_uid = data[0].mitarbeiter_uid; + this.$emit('update:selected', mitarbeiter_uid); + } + else + { + this.$emit('update:selected', null); + } + }, + reload() { + this.$refs.table.reloadTable(); + }, + + deleteLVPlan(uid, lehreinheit_id) + { + let deleteData = { + 'mitarbeiter_uid': uid, + 'lehreinheit_id': lehreinheit_id, + } + + this.$api.call(ApiLektor.deleteFromLVPlan(deleteData)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + this.reload(); + }) + }, + deletePerson(uid, lehreinheit_id) + { + let deleteData = { + 'mitarbeiter_uid': uid, + 'lehreinheit_id': lehreinheit_id, + } + + this.$api.call(ApiLektor.deletePerson(deleteData)) + .then(response => { + this.$fhcAlert.alertSuccess(this.$p.t('ui', 'successDelete')); + this.reload(); + }) + .catch(this.$fhcAlert.handleSystemError) + .finally(()=> { + + }) + }, + searchLektor(event) + { + const query = event.query.toLowerCase().trim(); + this.filteredLektor = this.dropdowns.lektor_array.filter(lektor => { + const fullName = `${lektor.vorname.toLowerCase()} ${lektor.nachname.toLowerCase()}`; + const reverseFullName = `${lektor.nachname.toLowerCase()} ${lektor.vorname.toLowerCase()}`; + return fullName.includes(query) || reverseFullName.includes(query) || lektor.uid.toLowerCase().includes(query); + }).map(lektor => ({ + label: `${lektor.nachname} ${lektor.vorname} (${lektor.uid})`, + uid: lektor.uid + })); + }, + addLektor() + { + let newData = { + 'mitarbeiter_uid': this.selectedLektor.uid, + 'lehreinheit_id': this.lehreinheit_id + } + + this.$api.call(ApiLektor.add(newData)) + .then(result => { + this.reload() + this.selectedLektor = '' + }) + .catch(this.$fhcAlert.handleSystemError); + }, + + }, + template: ` + + + + +` +}; + + diff --git a/public/js/components/LVVerwaltung/Lektor/Vertrag.js b/public/js/components/LVVerwaltung/Lektor/Vertrag.js new file mode 100644 index 000000000..f36fad8e0 --- /dev/null +++ b/public/js/components/LVVerwaltung/Lektor/Vertrag.js @@ -0,0 +1,161 @@ +import {CoreFilterCmpt} from "../../filter/Filter.js"; +import CoreForm from '../../Form/Form.js'; +import FormInput from '../../Form/Input.js'; +import ApiVertrag from "../../../api/lehrveranstaltung/vertrag.js"; + +export default{ + name: "LVLektorVertrag", + components: { + CoreFilterCmpt, + CoreForm, + FormInput + }, + emits: [ + 'canceledVertrag' + ], + props: { + lehreinheit_id: Number, + mitarbeiter_uid: String + }, + + inject: { + dropdowns: { + from: 'dropdowns' + }, + showVertragsdetails: { + from: 'configShowVertragsdetails', + default: false + } + }, + + data() { + return{ + data: null, + internal_mitarbeiter_uid: null, + } + }, + watch: { + lehreinheit_id: + { + deep: true, + handler(newVal, oldVal) { + this.data = null; + this.internal_mitarbeiter_uid = null; + } + + }, + mitarbeiter_uid: + { + deep: true, + handler(newVal, oldVal) { + this.internal_mitarbeiter_uid = newVal; + + if (newVal === null) + this.data = null; + else if (newVal !== undefined && this.lehreinheit_id !== undefined) + this.getLektorVertrag(); + } + }, + }, + computed: { + vertragsstatus() { + if (!this.data || !this.data.vertrag) return; + + const betragVertrag = Number(this.data.vertrag.betrag) || 0; + const stundenVertrag = Number(this.data.vertrag.vertragsstunden) || 0; + + const semStunden = Number(this.data.semesterstunden) || 0; + const stundensatz = Number(this.data.stundensatz) || 0; + + const kostenAktuell = semStunden * stundensatz; + + return (stundenVertrag !== semStunden || betragVertrag !== kostenAktuell) ? 'Geändert' : (this.data.vertrag.vertragsstatus || ''); + }, + }, + methods: { + getLektorVertrag () + { + if (this.showVertragsdetails === false) + return; + + if (!this.lehreinheit_id || !this.internal_mitarbeiter_uid) + return; + + this.$api.call(ApiVertrag.getByLeEmp(this.lehreinheit_id, this.internal_mitarbeiter_uid)) + .then(result => { + this.data = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + + cancelVertrag() + { + let needUpdate = { + vertrag_id: this.data.vertrag.vertrag_id, + mitarbeiter_uid: this.mitarbeiter_uid, + lehreinheit_id: this.lehreinheit_id + } + this.$api.call(ApiVertrag.cancelByLeEmp(needUpdate)) + .then(result => { + this.data.vertrag = null; + this.$emit('canceledVertrag'); + }) + .catch(this.$fhcAlert.handleSystemError); + }, + }, + // language=HTML + template: ` + +
+ {{$p.t('lehre', 'vertragsdetails')}} + {{ data === null ? ' – Noch kein Vertrag' : '' }} + + +
+
+ ` +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js new file mode 100644 index 000000000..9b0ae71f3 --- /dev/null +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -0,0 +1,683 @@ +import {CoreFilterCmpt} from "../../filter/Filter.js"; +import BsModal from "../../Bootstrap/Modal.js"; +import DetailsForm from "../Details/Form.js"; +import CoreTag from '../../Tag/Tag.js'; +import { tagHeaderFilter } from '../../../../js/tabulator/filters/extendedHeaderFilter.js'; +import { extendedHeaderFilter } from "../../../../js/tabulator/filters/extendedHeaderFilter.js"; + +import ApiLv from "../../../api/lehrveranstaltung.js"; +import ApiTag from "../../../api/lehrveranstaltung/tag.js"; +import ApiLehreinheit from "../../../api/lehrveranstaltung/lehreinheit.js"; + +export default { + name: "LVVerwaltungTable", + components: { + CoreFilterCmpt, + BsModal, + DetailsForm, + CoreTag + + }, + props: { + selected: Object, + filter: { + type: Object, + default: () => ({}) + } + }, + inject: { + currentSemester: { + from: 'currentSemester' + }, + lehreinheitAnmerkungDefault: { + from: 'lehreinheitAnmerkungDefault', + default: '' + }, + lehreinheitRaumtypDefault: { + from: 'lehreinheitRaumtypDefault', + default: '' + }, + lehreinheitRaumtypAlternativeDefault: { + from: 'lehreinheitRaumtypAlternativeDefault', + default: '' + } + }, + emits: [ + 'update:selected', + 'row-clicked' + ], + watch: { + filter: { + handler() { + if (this.$refs.table && this.$refs.table.tabulator) + { + this.expanded = []; + this.reload(); + } + }, + deep: true, + + } + }, + data() { + return { + fieldTitleMap: { + lv_kurzbz: ['lehre', 'kurzbz'], + tags: ['ui', 'tags'], + lehrveranstaltung_id: ['lehre', 'lehrveranstaltung_id'], + lv_bezeichnung: ['ui', 'bezeichnung'], + lv_bezeichnung_english: ['lehre', 'bezeichnungeng'], + lv_studiengang_kz: ['lehre', 'studiengangskennzahlLehre'], + studiengang: ['lehre', 'studiengang'], + semester: ['lehre', 'semester'], + sprache: ['global', 'sprache'], + lv_ects: ['lehre', 'ects'], + semesterstunden: ['lehre', 'semesterstunden'], + anmerkung: ['global', 'anmerkung'], + lehre: ['lehre', 'lehre'], + lehreverzeichnis: ['ui', 'lehreverzeichnis'], + aktiv: ['person', 'aktiv'], + planfaktor: ['ui', 'planfaktor'], + planlektoren: ['ui', 'planlektoren'], + planpersonalkosten: ['ui', 'planpersonalkosten'], + plankostenprolektor: ['ui', 'plankostenprolektor'], + orgform_kurzbz: ['lehre', 'organisationsform'], + studienplan_id: ['ui', 'studienplan_id'], + studienplan_bezeichnung: ['ui', 'studienplan_bezeichnung'], + lehrtyp_kurzbz: ['ui', 'lehrtyp_kurzbz'], + lehrform_kurzbz: ['lehre', 'lehrform'], + le_planstunden: ['lehre', 'leplanstunden'], + lehreinheit_id: ['lehre', 'lehreinheit_id'], + stundenblockung: ['lehre', 'stundenblockung'], + wochenrythmus: ['lehre', 'wochenrhytmus'], + startkw: ['lehre', 'startkw'], + raumtyp: ['lehre', 'raumtyp'], + raumtypalternativ: ['lehre', 'raumtypalternativ'], + gruppen: ['lehre', 'gruppen'], + lektoren: ['lehre', 'lehrende'], + }, + + expanded: [], + selectedColumnValues: [], + tagEndpoint: ApiTag, + iconPath: FHC_JS_DATA_STORAGE_OBJECT.app_root + '/skin/images/lehrtyp_', + tabulatorEvents: [ + { + event: 'rowSelectionChanged', + handler: this.rowSelectionChanged + }, + + { + event: 'dataProcessed', + handler: (data) => { + this.reexpandRows() + this.$emit('update:selected', {}) + } + }, + { + event: 'dataTreeRowExpanded', + handler: (data) => { + this.getExpandedRows() + } + },{ + event: 'dataTreeRowCollapsed', + handler: (data) => { + this.getExpandedRows() + } + } + + ], + formData: {}, + lv_info: false, + lv_info_default: { + stundenblockung: 2, + wochenrythmus: 1, + studiensemester_kurzbz: this.currentSemester, + lehrform_kurzbz: 'UE', + anmerkung: this.lehreinheitAnmerkungDefault.replace("'","\'"), + raumtyp: this.lehreinheitRaumtypDefault, + raumtypalternativ: this.lehreinheitRaumtypAlternativeDefault, + lehrfach_id: '' + + } + } + }, + computed: { + tabulatorOptions() { + return { + index: 'uniqueindex', + ajaxURL: 'dummy', + ajaxRequestFunc: async (url, config, params) => { + let realUrl = this.buildApiUrl(); + if (realUrl) + return this.$api.call(ApiLv.getTable(this.buildApiUrl())); + }, + ajaxResponse: (url, params, response) => { return response?.data || [] }, + dataTree: true, + initialSort:[ + {column: 'lv_bezeichnung', dir: 'desc'}, + ], + dataTreeElementColumn: "lv_kurzbz", + dataTreeFilter: true, + dataTreeStartExpanded: false, + dataTreeCollapseElement: '', + dataTreeExpandElement: '', + columnDefaults: { + tooltip: true, + headerFilter: "input", + headerFilterFunc: extendedHeaderFilter + }, + layout: 'fitDataStretch', + layoutColumnsOnNewData: false, + height: '100%', + selectableRowsRangeMode: 'click', + selectableRows: true, + rowContextMenu: (component, e) => { + + return [ + { + label: "LV-Teil kopieren", + menu: [ + { + label: "Alles", + action: (e, row) => + { + this.copyLehreinheit(row, "alle"); + }, + }, + { + label: "Nur LV-Teil", + action: (e, row) => + { + this.copyLehreinheit(row, "lvteil"); + }, + }, + { + label: "Nur mit Gruppen", + action: (e, row) => + { + this.copyLehreinheit(row, "halb"); + }, + }, + { + label: "Nur mit Lehrenden", + action: (e, row) => + { + this.copyLehreinheit(row, "lektoren"); + }, + }, + ], + }, + { + label: "Entfernen", + action: (e, row) => { + this.deleteLehreinheit(row) + }, + }, + ]; + }, + + persistenceID: 'lehrveranstaltungen_2025_05_27_v1', + columns: [ + { + title: this.$p.t('lehre', 'kurzbz'), + field: "lv_kurzbz", + headerFilterFuncParams: {field: 'lv_kurzbz'}, + headerFilter: true, + formatter: (cell, formatterParams) => { + const rowData = cell.getRow().getData(); + const iconKey = (rowData.lehrtyp_kurzbz || '').toLowerCase(); + + const span = document.createElement('span'); + span.classList.add('lv_table_icon', `icon-${iconKey}`); + span.title = iconKey || 'LV-Teil'; + return span; + }, + + cellClick: (e, cell) => { + cell.getRow().treeToggle(); + } + }, + { + title: 'Tags', + field: 'tags', + tooltip: false, + headerFilter: "input", + headerFilterFunc: tagHeaderFilter, + headerFilterFuncParams: {field: 'tags'}, + formatter: (cell) => { + let tags = cell.getValue(); + if (!tags) return; + + let container = document.createElement('div'); + container.className = "d-flex gap-1"; + + let parsedTags = JSON.parse(tags); + let maxVisibleTags = 2; + + const rowData = cell.getRow().getData(); + if (rowData._tagExpanded === undefined) { + rowData._tagExpanded = false; + } + + const renderTags = () => { + container.innerHTML = ''; + parsedTags = parsedTags.filter(item => item !== null); + const tagsToShow = rowData._tagExpanded ? parsedTags : parsedTags.slice(0, maxVisibleTags); + + tagsToShow.forEach(tag => { + if (!tag) return; + let tagElement = document.createElement('span'); + tagElement.innerText = tag.beschreibung; + tagElement.title = tag.notiz; + tagElement.className = "tag " + tag.style; + if (tag.done) tagElement.className += " tag_done"; + + tagElement.addEventListener('click', (event) => { + event.stopPropagation(); + event.preventDefault(); + this.$refs.tagComponent.editTag(tag.id); + }); + + container.appendChild(tagElement); + }); + + if (parsedTags.length > maxVisibleTags) { + let toggle = document.createElement('button'); + toggle.innerText = (rowData._tagExpanded ? '- ' : '+ ') + (parsedTags.length - maxVisibleTags); + toggle.className = "display_all"; + toggle.title = rowData._tagExpanded ? "Tags ausblenden" : "Tags einblenden"; + + toggle.addEventListener('click', () => { + rowData._tagExpanded = !rowData._tagExpanded; + renderTags(); + }); + + container.appendChild(toggle); + } + }; + + renderTags(); + return container; + }, + width: 150, + }, + { + title: this.$p.t('lehre', 'lehrveranstaltung_id'), + field: "lehrveranstaltung_id", + headerFilterFuncParams: {field: 'lehrveranstaltung_id'}, + headerFilter: true + }, + {title: this.$p.t('ui', 'bezeichnung'), field: "lv_bezeichnung", headerFilter: true, headerFilterFuncParams: {field: 'lv_bezeichnung'}}, + {title: this.$p.t('lehre', 'bezeichnungeng'), field: "lv_bezeichnung_english", headerFilter: true, headerFilterFuncParams: {field: 'lv_bezeichnung_english'}}, + { + title: this.$p.t('lehre', 'studiengangskennzahlLehre'), + field: "lv_studiengang_kz", + headerFilter: true, + headerFilterFuncParams: {field: 'lv_studiengang_kz'} + }, + {title: this.$p.t('lehre', 'studiengang'), field: "studiengang", headerFilter: true, headerFilterFuncParams: {field: 'studiengang'}}, + {title: this.$p.t('lehre', 'semester'), field: "semester", headerFilter: true, headerFilterFuncParams: {field: 'semester'}}, + {title: this.$p.t('global', 'sprache'), field: "sprache", headerFilter: true, headerFilterFuncParams: {field: 'sprache'}}, + {title: this.$p.t('lehre', 'ects'), field: "lv_ects", headerFilter: true, headerFilterFuncParams: {field: 'lv_ects'}}, + {title: this.$p.t('lehre', 'semesterstunden'), field: "semesterstunden", headerFilter: true, headerFilterFuncParams: {field: 'semesterstunden'}}, + {title: this.$p.t('global', 'anmerkung'), field: "anmerkung", headerFilter: true, headerFilterFuncParams: {field: 'anmerkung'}}, + {title: this.$p.t('lehre', 'lehre'), field: "lehre", headerFilter: true, headerFilterFuncParams: {field: 'lehre'}}, + {title: "Lehreverzeichnis", field: "lehreverzeichnis", headerFilter: true, headerFilterFuncParams: {field: 'lehreverzeichnis'}}, + {title: this.$p.t('person', 'aktiv'), field: "aktiv", headerFilter: true, headerFilterFuncParams: {field: 'aktiv'}}, + {title: "Planfaktor", field: "planfaktor", headerFilter: true, headerFilterFuncParams: {field: 'planfaktor'}}, + {title: "Planlektoren", field: "planlektoren", headerFilter: true, headerFilterFuncParams: {field: 'planlektoren'}}, + {title: "planpersonalkosten", field: "planpersonalkosten", headerFilter: true, headerFilterFuncParams: {field: 'planpersonalkosten'}}, + {title: "plankostenprolektor", field: "plankostenprolektor", headerFilter: true, headerFilterFuncParams: {field: 'plankostenprolektor'}}, + {title: this.$p.t('ui', 'organisationsform'), field: "orgform_kurzbz", headerFilter: true, headerFilterFuncParams: {field: 'orgform_kurzbz'}}, + {title: this.$p.t('ui', 'studienplan_id'), field: "studienplan_id", headerFilter: true, headerFilterFuncParams: {field: 'studienplan_id'}}, + {title: "studienplan_bezeichnung", field: "studienplan_bezeichnung", headerFilter: true, headerFilterFuncParams: {field: 'studienplan_bezeichnung'}}, + {title: "lehrtyp_kurzbz", field: "lehrtyp_kurzbz", headerFilter: true, headerFilterFuncParams: {field: 'lehrtyp_kurzbz'}}, + {title: this.$p.t('lehre', 'lehrform'), field: "lehrform_kurzbz", headerFilter: true, headerFilterFuncParams: {field: 'lehrform_kurzbz'}}, + {title: this.$p.t('lehre', 'leplanstunden'), field: "le_planstunden", headerFilter: true, headerFilterFuncParams: {field: 'le_planstunden'}}, + {title: this.$p.t('lehre', 'lehreinheit_id'), field: "lehreinheit_id", headerFilter: true, headerFilterFuncParams: {field: 'lehreinheit_id'}}, + {title: this.$p.t('lehre', 'stundenblockung'), field: "stundenblockung", headerFilter: true, headerFilterFuncParams: {field: 'stundenblockung'}}, + {title: this.$p.t('lehre', 'wochenrhytmus'), field: "wochenrythmus", headerFilter: true, headerFilterFuncParams: {field: 'wochenrythmus'}}, + {title: this.$p.t('lehre', 'startkw'), field: "startkw", headerFilter: true, headerFilterFuncParams: {field: 'startkw'}}, + {title: this.$p.t('lehre', 'raumtyp'), field: "raumtyp", headerFilter: true, headerFilterFuncParams: {field: 'raumtyp'}}, + {title: this.$p.t('lehre', 'raumtypalternativ'), field: "raumtypalternativ", headerFilter: true, headerFilterFuncParams: {field: 'raumtypalternativ'}}, + {title: this.$p.t('lehre', 'gruppen'), field: "gruppen", headerFilter: true, headerFilterFuncParams: {field: 'gruppen'}}, + {title: this.$p.t('lehre', 'lehrende'), field: "lektoren", headerFilter: true, headerFilterFuncParams: {field: 'lektoren'}}, + ], + } + + } + }, + + mounted() { + if (this.shouldAutoLoad()) + { + this.reload(); + } + }, + methods: { + shouldAutoLoad() { + return this.filter && this.filter.activeFilter; + }, + async reload() + { + + if (this.shouldAutoLoad) + { + this.$refs.table.reloadTable(); + } + }, + rowSelectionChanged(data) { + this.selectedRows = this.$refs.table.tabulator.getSelectedRows(); + this.selectedColumnValues = this.selectedRows.filter(row => row.getData().lehreinheit_id !== undefined).map(row => row.getData().lehreinheit_id); + + if (data[0]?.lehreinheit_id !== undefined && this.selectedColumnValues.length === 1) + { + this.$emit('update:selected', [data[0]]); + this.lv_info = false + } + else if (data[0]?.lehrveranstaltung_id) + { + this.$emit('update:selected', {}); + this.getLVInfos(data[0]); + } + }, + getLVInfos(data) + { + this.$api.call(ApiLv.getByLV(data.lehrveranstaltung_id)) + .then(result => { + + if (result.data?.lehrfach_id === undefined + && Array.isArray(result.data?.lehrfaecher)) + { + const match = result.data.lehrfaecher?.find( + lf => lf.lehrfach?.startsWith(result.data.lvbezeichnung) + ); + if (match) + { + result.data.lehrfach_id = match.lehrveranstaltung_id; + } + } + this.lv_info = {...this.lv_info_default, ...result.data}; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + buildApiUrl() + { + if (this.filter.activeFilter === 'employee' && this.filter.emp) + { + return this.$api.getUri(ApiLv.getByEmpStg( + this.filter.emp, + this.filter.stg + )); + } + + if (this.filter.activeFilter === 'verband' && this.filter.stg) + { + return this.$api.getUri(ApiLv.getByStg( + this.filter.stg, + this.filter.semester + )); + } + }, + resetEmployeeFilter() + { + const newFilter = { ...this.filter }; + delete newFilter.emp; + newFilter.activeFilter = 'verband'; + }, + buildParams() + { + const params = {}; + for (const [key, value] of Object.entries(this.filter)) { + if (value !== undefined && value !== null) { + params[key] = value; + } + } + return params; + }, + showLehreinheitModal() { + this.resetModal(); + this.$refs.lehreinheitModal.show(); + }, + addNewLehreinheit() + { + return this.$api.call(ApiLehreinheit.add(this.lv_info)) + .then(result => { + this.$refs.lehreinheitModal.hide() + this.reload() + }) + .catch(this.$fhcAlert.handleSystemError); + }, + resetModal() + { + this.lv_info_default = { + stundenblockung: 2, + wochenrythmus: 1, + studiensemester_kurzbz: this.currentSemester, + lehrform_kurzbz: 'UE', + anmerkung: this.lehreinheitAnmerkungDefault.replace("'","\'"), + raumtyp: this.lehreinheitRaumtypDefault, + raumtypalternativ: this.lehreinheitRaumtypAlternativeDefault, + lehrfach_id: '' + } + }, + addedTag(addedTag) + { + const table = this.$refs.table.tabulator; + + this.selectedRows.forEach(row => + { + if (Array.isArray(addedTag.response)) + { + addedTag.response.forEach(tag => { + + const all = this.getAllRows(table.getRows()); + const targetRow = all.find(row => row.getData().lehreinheit_id === tag.lehreinheit_id); + if (targetRow) + { + const rowData = targetRow.getData(); + let tags = []; + try { + tags = JSON.parse(rowData.tags || '[]'); + } catch (e) {} + + const tagExists = tags.some((t) => t.id === tag.id); + if (!tagExists) + { + addedTag.id = tag.id; + tags.push({ ...addedTag }); + targetRow.update({ tags: JSON.stringify(tags) }); + targetRow.reformat(); + } + } + }); + } + }); + }, + deletedTag(deletedTag) { + const table = this.$refs.table.tabulator; + const all = this.getAllRows(table.getRows()); + + const targetRow = all.find(row => { + const rowData = row.getData(); + + let tags = []; + try { + tags = JSON.parse(rowData.tags || '[]'); + } catch (e) {} + + return tags.some(tag => tag.id === deletedTag); + }); + + if (targetRow) { + const rowData = targetRow.getData(); + let tags = []; + + try { + tags = JSON.parse(rowData.tags || '[]'); + } catch (e) {} + + const filteredTags = tags.filter(t => t.id !== deletedTag); + const updatedTags = JSON.stringify(filteredTags); + + if (updatedTags !== rowData.tags) { + targetRow.update({ + tags: updatedTags + }); + + targetRow.reformat(); + } + } + }, + + updatedTag(updatedTag) { + const table = this.$refs.table.tabulator; + const all = this.getAllRows(table.getRows()); + + const targetRow = all.find(row => { + const rowData = row.getData(); + let tags = []; + + try { + tags = JSON.parse(rowData.tags || '[]'); + } catch (e) {} + + return tags.some(t => t?.id === updatedTag.id); + }); + + if (targetRow) + { + const rowData = targetRow.getData(); + let tags = []; + try { + tags = JSON.parse(rowData.tags || '[]'); + } catch (e) {} + + let changed = false; + + const tagIndex = tags.findIndex(tag => tag?.id === updatedTag.id); + if (tagIndex !== -1) { + tags[tagIndex] = { ...updatedTag }; + changed = true; + } + + if (changed) + { + targetRow.update({ + tags: JSON.stringify(tags), + }); + targetRow.reformat(); + } + } + }, + async copyLehreinheit(row, art) + { + let data = { + lehreinheit_id: row.getData().lehreinheit_id, + art: art + } + + return this.$api.call(ApiLehreinheit.copy(data)) + .then(result => { + this.reload() + }) + .catch(this.$fhcAlert.handleSystemError) + }, + + async getExpandedRows() { + this.expanded = []; + let rows = this.$refs.table.tabulator.getRows(); + let allRows = this.getAllRows(rows); + allRows.forEach(row => { + if (row.getTreeChildren().length > 0 && row.isTreeExpanded()) + { + this.expanded.push(row.getData().uniqueindex); + } + }); + }, + reexpandRows() { + const all = this.getAllRows(this.$refs.table.tabulator.getRows()); + + const matchingRows = all.filter(row => + this.expanded.includes(row.getData().uniqueindex) + ); + + matchingRows.forEach((row, index) => { + row._row.modules.dataTree.open = true; + + if (index === matchingRows.length - 1) + { + row.treeExpand(); + } + }); + }, + deleteLehreinheit(row) + { + let deleteData = { + lehreinheit_id: row.getData().lehreinheit_id, + } + return this.$api.call(ApiLehreinheit.delete(deleteData)) + .then(result => { + this.reload() + }) + .catch(this.$fhcAlert.handleSystemError); + }, + getAllRows(rows) + { + let result = []; + rows.forEach(row => + { + result.push(row); + let children = row.getTreeChildren(); + if(children && children.length > 0) + { + result = result.concat(this.getAllRows(children)); + } + }); + return result; + }, + }, + template: ` + + + + + + + + + + + + + +` +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Setup/Tabs.js b/public/js/components/LVVerwaltung/Setup/Tabs.js new file mode 100644 index 000000000..af14fbf32 --- /dev/null +++ b/public/js/components/LVVerwaltung/Setup/Tabs.js @@ -0,0 +1,62 @@ +import FhcTabs from "../../Tabs.js"; +import Setup from "../../../api/lehrveranstaltung/setup.js"; + +export default { + name: "LVVerwaltungTabs", + components: { + FhcTabs + }, + data() { + return { + configLVTabs: {}, + }; + }, + props: { + lv: Object + }, + computed: { + config() { + if (!this.lv || !this.lv.length) + return {}; + + return this.configLVTabs; + } + }, + methods: { + reload() { + if (this.$refs.tabs?.$refs?.current?.reload) + { + this.$refs.tabs.$refs.current.reload(); + } + } + }, + created() { + this.$api.call(Setup.getTabs()) + .then(result => { + this.configLVTabs = result.data; + }) + .catch(this.$fhcAlert.handleSystemError); + + }, + template: ` +
+
+ Bitte eine Lehreinheit auswählen! +
+
+ +
+
+ Loading... +
+
+ ` +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Tabs/Details.js b/public/js/components/LVVerwaltung/Tabs/Details.js new file mode 100644 index 000000000..ce0102177 --- /dev/null +++ b/public/js/components/LVVerwaltung/Tabs/Details.js @@ -0,0 +1,133 @@ +import CoreForm from '../../Form/Form.js'; +import FormInput from '../../Form/Input.js'; +import GruppenTable from '../Details/Gruppen.js'; +import GruppenDirektTable from '../Details/Direktinskription.js'; +import DetailsForm from '../Details/Form.js' +import ApiLehreinheit from "../../../api/lehrveranstaltung/lehreinheit.js"; + +export default { + name: "LVTabDetails", + components: { + CoreForm, + FormInput, + GruppenTable, + GruppenDirektTable, + DetailsForm + }, + props: { + modelValue: Object, + config: { + type: Object, + default: {} + }, + }, + inject: { + dropdowns: { + from: 'dropdowns' + } + }, + watch: { + modelValue(newValue) + { + this.updateLE(newValue) + }, + data: { + handler(newValue) { + if (newValue === null) + { + this.changed = {} + return + } + let changed = {}; + + let keys = Object.keys(this.original); + + for (let key of keys) { + if (this.original[key] !== newValue[key]) + { + changed[key] = newValue[key]; + } + } + this.changed = changed; + }, + deep: true + } + }, + data() { + return { + original: null, + data: null, + changed: {} + } + }, + computed: { + changedLength() { + return Object.keys(this.changed).length; + } + }, + + methods: { + updateLE(le) { + if (le?.lehreinheit_id === undefined) + { + this.data = null; + return; + } + return this.$api.call(ApiLehreinheit.get(le.lehreinheit_id)) + .then(result => { + this.data = result.data; + this.original = {...(this.original || {}), ...this.data}; + }) + .catch(this.$fhcAlert.handleSystemError); + }, + save() { + if (!this.changedLength) + return; + this.$refs.form.clearValidation(); + + let updatedData = { + lehreinheit_id: this.modelValue.lehreinheit_id, + formData: this.changed + } + return this.$refs.form.call(ApiLehreinheit.update(updatedData)) + .then(result => { + this.original = {...this.data}; + this.changed = {}; + this.$refs.form.setFeedback(true, result.data); + }) + .catch(this.$fhcAlert.handleSystemError); + + }, + reload(){ + this.updateLE(this.modelValue); + } + }, + created() { + this.updateLE(this.modelValue); + }, + template: ` + +
+ +
+
+ {{this.$p.t('lehre', 'lehreinheit')}} + +
+
+
+
+
+ {{this.$p.t('lehre', 'gruppen')}} + +
+
+ {{this.$p.t('lehre', 'assignedPersons')}} + +
+
+ +
` +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Tabs/Lektor.js b/public/js/components/LVVerwaltung/Tabs/Lektor.js new file mode 100644 index 000000000..99e1edb9e --- /dev/null +++ b/public/js/components/LVVerwaltung/Tabs/Lektor.js @@ -0,0 +1,70 @@ +import CoreForm from '../../Form/Form.js'; +import FormInput from '../../Form/Input.js'; +import LektorTable from '../Lektor/Table.js' +import LektorDaten from '../Lektor/Daten.js' +import LektorVertrag from '../Lektor/Vertrag.js' +export default { + name: "LVTabLektor", + components: { + CoreForm, + FormInput, + LektorTable, + LektorDaten, + LektorVertrag + }, + props: { + modelValue: Object, + config: { + type: Object, + default: {} + }, + }, + data() { + return { + mitarbeiter_uid: null + } + }, + methods: { + changedLektor(uid) { + const lektorTable = this.$refs.lektor_table; + const tabulator = lektorTable.$refs.table.tabulator; + + const selectUID = () => { + let row = tabulator.getRows().find(r => r.getData().mitarbeiter_uid === uid); + if (row) + { + row.select(); + } + tabulator.off('dataProcessed', selectUID); + }; + tabulator.on('dataProcessed', selectUID); + lektorTable.reload(); + }, + changedCosts() { + this.$refs.lektor_vertrag?.getLektorVertrag(); + }, + canceledVertrag() { + this.$refs.lektor_daten?.getLektorData(); + } + }, + template: ` +
+
+
+ {{ $p.t('lehre', 'lektorInnen')}} + +
+
+ +
+
+
+
+
+
+ +
+
+
+ ` +}; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Tabs/Notiz.js b/public/js/components/LVVerwaltung/Tabs/Notiz.js new file mode 100644 index 000000000..6bccf5c52 --- /dev/null +++ b/public/js/components/LVVerwaltung/Tabs/Notiz.js @@ -0,0 +1,33 @@ +import CoreNotiz from "../../Notiz/Notiz.js"; +import ApiNotizLehreinheit from '../../../api/factory/notiz/lehreinheit.js'; +export default { + name: "LVTabNotiz", + components: { + CoreNotiz + }, + props: { + modelValue: Object + }, + data() { + return { + endpoint: ApiNotizLehreinheit + }; + }, + template: ` +
+ + +
+ ` +}; \ No newline at end of file diff --git a/public/js/components/Stv/Studentenverwaltung.js b/public/js/components/Stv/Studentenverwaltung.js index 248cfd55c..cc224480f 100644 --- a/public/js/components/Stv/Studentenverwaltung.js +++ b/public/js/components/Stv/Studentenverwaltung.js @@ -24,6 +24,7 @@ import StvStudiensemester from "./Studentenverwaltung/Studiensemester.js"; import ApiSearchbar from "../../api/factory/searchbar.js"; import ApiStv from "../../api/factory/stv.js"; +import ApiStvVerband from '../../api/factory/stv/verband.js'; export default { @@ -70,6 +71,7 @@ export default { }, data() { return { + endpoint: ApiStvVerband, selected: [], searchbaroptions: { cssclass: "position-relative", @@ -220,7 +222,7 @@ export default {
- +
diff --git a/public/js/components/Stv/Studentenverwaltung/Verband.js b/public/js/components/Stv/Studentenverwaltung/Verband.js index 8ae2b6b40..c60242511 100644 --- a/public/js/components/Stv/Studentenverwaltung/Verband.js +++ b/public/js/components/Stv/Studentenverwaltung/Verband.js @@ -5,8 +5,6 @@ import PvTree from "../../../../../index.ci.php/public/js/components/primevue/tr import PvTreetable from "../../../../../index.ci.php/public/js/components/primevue/treetable/treetable.esm.min.js"; import PvColumn from "../../../../../index.ci.php/public/js/components/primevue/column/column.esm.min.js"; -import ApiStvVerband from '../../../api/factory/stv/verband.js'; - export default { components: { PvTree, @@ -16,11 +14,22 @@ export default { emits: [ 'selectVerband' ], + props: { + endpoint: { + type: Object, + required: true, + }, + preselectedKey: { + type: String, + default: null + } + }, data() { return { loading: true, nodes: [], selectedKey: [], + expandedKeys: {}, filters: {}, // TODO(chris): filter only 1st level? favnodes: [], favorites: {on: false, list: []} @@ -44,7 +53,7 @@ export default { return res.pop(); return null; }, - onExpandTreeNode(node) { + async onExpandTreeNode(node) { if (!node.children) { if (node.data.link) { let activeEl = null; @@ -55,8 +64,8 @@ export default { }); this.loading = true; - this.$api - .call(ApiStvVerband.get(node.data.link)) + return this.$api + .call(this.endpoint.get(node.data.link)) .then(result => result.data) .then(result => { const subNodes = result.map(this.mapResultToTreeData); @@ -68,7 +77,7 @@ export default { let treeitem = this.$refs.tree.$el.querySelector('[data-tree-item-key="' + node.key + '"]'); treeitem = treeitem.closest('[role="row"]'); - + this.$nextTick(() => { if (activeEl == document.activeElement) treeitem.dispatchEvent(new KeyboardEvent('keydown', { @@ -108,7 +117,7 @@ export default { } this.favorites.on = !this.favorites.on; this.$api - .call(ApiStvVerband.favorites.set( + .call(this.endpoint.favorites.set( JSON.stringify(this.favorites) )); this.loading = false; @@ -135,7 +144,7 @@ export default { for (let parent in sortedInParents) promises.push( this.$api - .call(ApiStvVerband.get(parent == '_' ? '' : parent)) + .call(this.endpoint.get(parent == '_' ? '' : parent)) .then(res => res.data) .then(res => res.filter(node => sortedInParents[parent].includes(node.link + ''))) ); @@ -160,9 +169,9 @@ export default { this.favnodes.push((await this.loadNodes([key.data.link])).pop()); this.favorites.list.push(key.data.link + ''); } - + this.$api - .call(ApiStvVerband.favorites.set( + .call(this.endpoint.favorites.set( JSON.stringify(this.favorites) )); }, @@ -181,19 +190,54 @@ export default { let items = e.target.querySelectorAll('[data-link-fav-add][tabindex="-1"]'); items.forEach(el => el.tabIndex = 0); } + }, + async setPreselection() + { + if (!this.preselectedKey) + return; + + let rawKey = this.preselectedKey + + if (!rawKey || typeof rawKey !== 'string') + return; + + const parts = this.preselectedKey.split('/'); + let currentKey = parts[0]; + let currentNode = this.findNodeByKey(currentKey); + + if (!currentNode) + return; + + for (let i = 1; i < parts.length; i++) + { + this.expandedKeys[currentNode.key] = true; + + await this.onExpandTreeNode(currentNode); + + currentKey += '-' + parts[i]; + currentNode = this.findNodeByKey(currentKey); + + if (!currentNode) + { + return; + } + } + + this.selectedKey = { [currentNode.key]: true }; } }, mounted() { this.$api - .call(ApiStvVerband.get()) + .call(this.endpoint.get()) .then(result => { this.nodes = result.data.map(this.mapResultToTreeData); + this.setPreselection(); this.loading = false; }) .catch(this.$fhcAlert.handleSystemError); this.$api - .call(ApiStvVerband.favorites.get()) + .call(this.endpoint.favorites.get()) .then(result => { if (result.data) { let f = JSON.parse(result.data); @@ -218,6 +262,7 @@ export default { :value="filteredNodes" @node-expand="onExpandTreeNode" selection-mode="single" + v-model:expanded-keys="expandedKeys" v-model:selection-keys="selectedKey" @node-select="onSelectTreeNode" scrollable diff --git a/public/js/components/Tag/Tag.js b/public/js/components/Tag/Tag.js index c7552a5a9..a3243ed47 100644 --- a/public/js/components/Tag/Tag.js +++ b/public/js/components/Tag/Tag.js @@ -57,7 +57,7 @@ export default { init() { if (!this.endpoint) return; - this.endpoint.getTags() + this.$api.call(this.endpoint.getTags()) .then(response => response.data) .then(response => { this.tags = response @@ -71,7 +71,7 @@ export default { 'id': tag_id }; - this.endpoint.getTag(getData) + this.$api.call(this.endpoint.getTag(getData)) .then(result => result.data) .then(result => this.openModal(result)) }, @@ -118,7 +118,7 @@ export default { { postData.id = this.selectedTagId; this.tagData.id = this.selectedTagId; - this.endpoint.updateTag(postData); + this.$api.call(this.endpoint.updateTag(postData)); this.$emit("updated", this.tagData); this.$refs.tagModal.hide(); } @@ -130,7 +130,7 @@ export default { return; } - this.endpoint.addTag(postData) + this.$api.call(this.endpoint.addTag(postData)) .then(response => response.data) .then(response => { if (typeof response === 'number') { @@ -156,7 +156,7 @@ export default { id: this.selectedTagId, done: !this.tagData.done } - this.endpoint.doneTag(postData) + this.$api.call(this.endpoint.doneTag(postData)) this.$emit("updated", this.tagData); this.$refs.tagModal.hide(); }, @@ -165,7 +165,7 @@ export default { let postData = { id: this.selectedTagId } - this.endpoint.deleteTag(postData) + this.$api.call(this.endpoint.deleteTag(postData)) this.$emit("deleted", this.selectedTagId) this.$refs.tagModal.hide(); }, diff --git a/public/js/tabulator/filters/extendedHeaderFilter.js b/public/js/tabulator/filters/extendedHeaderFilter.js index e15f8d9ac..5dfcce205 100644 --- a/public/js/tabulator/filters/extendedHeaderFilter.js +++ b/public/js/tabulator/filters/extendedHeaderFilter.js @@ -39,7 +39,7 @@ function parseFilterExpression(expression) return collections; } -export function extendedHeaderFilter(headerValue, rowValue) +export function extendedHeaderFilter(headerValue, rowValue, rowData, filterParams) { if (typeof headerValue === 'boolean') { @@ -48,52 +48,79 @@ export function extendedHeaderFilter(headerValue, rowValue) const collections = parseFilterExpression(headerValue); - try { + function matchValue(value) + { + try { + return collections.some(collection => { - return collections.some(collection => { + let positives = collection.positives.length === 0 || collection.positives.every(condition => { - let positives = collection.positives.length === 0 || collection.positives.every(condition => { + if (condition.type === 'comparison') + { + let value = parseFloat(rowValue); + if (isNaN(value)) return false; - if (condition.type === 'comparison') - { - let value = parseFloat(rowValue); - if (isNaN(value)) return false; - - switch (condition.operator) { - case '<': - return value < condition.number; - case '>': - return value > condition.number; - case '<=': - return value <= condition.number; - case '>=': - return value >= condition.number; - case '=': - return value === condition.number; - case '!=': - return value !== condition.number; - default: - return false; + switch (condition.operator) { + case '<': + return value < condition.number; + case '>': + return value > condition.number; + case '<=': + return value <= condition.number; + case '>=': + return value >= condition.number; + case '=': + return value === condition.number; + case '!=': + return value !== condition.number; + default: + return false; + } } - } - else if (condition.type === 'regex') - { - return condition.regex.test(rowValue); - } - return false; + else if (condition.type === 'regex') + { + return condition.regex.test(rowValue); + } + return false; + }); + + let negatives = collection.negatives.every(condition => { + return !condition.regex.test(rowValue); + }); + + return positives && negatives; }); + } catch (e) { - let negatives = collection.negatives.every(condition => { - return !condition.regex.test(rowValue); - }); - - return positives && negatives; - }); - } catch (e) { - + } } + + if (matchValue(rowValue)) + return true; + + if (rowData && filterParams) + { + const childrenField = filterParams?.children || '_children'; + const field = filterParams?.field; + + const children = rowData[childrenField]; + if (Array.isArray(children)) + { + for (let child of children) + { + let childValue = child[field]; + if (extendedHeaderFilter(headerValue, childValue, child, filterParams)) + { + return true; + } + } + } + } + + return false; } -export function tagHeaderFilter(headerValue, rowValue) { +export function tagHeaderFilter(headerValue, rowValue, rowData, filterParams) +{ let data; @@ -120,6 +147,5 @@ export function tagHeaderFilter(headerValue, rowValue) { combinedText = String(data); } - return extendedHeaderFilter(headerValue, combinedText) -} - + return extendedHeaderFilter(headerValue, combinedText, rowData, filterParams) +} \ No newline at end of file diff --git a/system/dbupdate_3.4.php b/system/dbupdate_3.4.php index 0e2b4e7c6..fbdc1f4ae 100644 --- a/system/dbupdate_3.4.php +++ b/system/dbupdate_3.4.php @@ -74,6 +74,7 @@ require_once('dbupdate_3.4/55968_index_anrechnung.php'); require_once('dbupdate_3.4/25999_locale_update.php'); require_once('dbupdate_3.4/55289_pep_fine_tuning.php'); require_once('dbupdate_3.4/55614_perm_verwaltetoe.php'); +require_once('dbupdate_3.4/60882_lehrfaecherverteilung_favorites.php'); // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

Pruefe Tabellen und Attribute!

'; diff --git a/system/dbupdate_3.4/60882_lehrfaecherverteilung_favorites.php b/system/dbupdate_3.4/60882_lehrfaecherverteilung_favorites.php new file mode 100644 index 000000000..55fb55b80 --- /dev/null +++ b/system/dbupdate_3.4/60882_lehrfaecherverteilung_favorites.php @@ -0,0 +1,16 @@ +db_query("SELECT 1 FROM public.tbl_variablenname WHERE name = 'lv_favorites';")) +{ + if ($db->db_num_rows($result) == 0) + { + $qry = "INSERT INTO public.tbl_variablenname(name, defaultwert) VALUES('lv_favorites', null);"; + + if (!$db->db_query($qry)) + echo 'public.tbl_variablenname '.$db->db_last_error().'
'; + else + echo 'public.tbl_variablenname: Added name "lv_favorites"
'; + } +} diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 0203b3c2f..c158e3971 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -41873,8 +41873,729 @@ and represent the current state of research on the topic. The prescribed citatio 'insertvon' => 'system' ) ) - ) + ), // PROJEKTARBEITSBEURTEILUNG SS2025 ENDE --------------------------------------------------------------------------- + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'gewicht', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gewicht', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Weight', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'newlehreinheit', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Neuer LV-Teil', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'New teaching unit', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'bezeichnungeng', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Bezeichnung Englisch', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'title english', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'detailanmerkung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Info an LV-Planung', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Info to LV Planning', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'unr', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'UNR', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'UNR', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'las', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehrauftragsstunden (LAS)', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Teaching hours (LAS)', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'lehre', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehre', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Teaching', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'raumtyp', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Raumtyp', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Room', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'lehrende', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehrende', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'lecturers', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'raumtypalternativ', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Raumtyp Alternativ', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Room Alternative', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'startkw', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Start KW', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Start CW', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'stundenblockung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Stunden Block', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Hours Block', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'wochenrhythmus', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Wochenrhythmus', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Weekly rhythm', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'lehrfunktion', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehrfunktion', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Teaching function', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'anmerkung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Info an DepL/KFL', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Info to DepL/KFL', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'planstunden', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'LV-Plan Stunden', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Course-Plan Hours', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'leplanstunden', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Planstunden', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Plan Hours', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'default', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Default', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Default', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'stundensatz', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Stundensatz', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Hourly Rate', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'bismelden', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'BIS-Melden', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Report BIS', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'gesamtkosten', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gesamtkosten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Total costs', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'daten', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Daten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Data', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'lehreinheit_id', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehreinheit ID', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Teaching Unit ID', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'verplant', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Verplant', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Planned', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'addLektor', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'LektorIn hinzufügen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Add lector', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'gruppen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gruppen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Groups', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'addGroup', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Gruppe hinzufügen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Add group', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'assignPerson', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Person zuordnen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Assign person', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'assignedPersons', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Direkt zugeordnete Personen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Directly assigned persons', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'geaendert', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Geändert', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Changed', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'vertragurfassung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Vertragsdetails lt. Urfassung', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Contract details as per original version', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'vertragsdetails', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Vertragsdetails', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Contract details', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'semesterstunden', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Semesterstunden', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Semester hours', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'vertragsstatus', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Vertragsstatus', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Contract status', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'auslvplanentfernen', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Stunden aus LV-Plan entfernen', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Remove hours from course plan', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'lehrfach', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehrfach', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Course', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + ); From 239eace246349288b1146c1c684243e59e5721af Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Fri, 27 Jun 2025 23:14:56 +0200 Subject: [PATCH 011/112] registration links to Bewerbungstool: changed in infocenter and fas, studentenverwaltung so that user email is not verified --- application/views/system/infocenter/stammdaten.php | 2 +- .../js/components/Stv/Studentenverwaltung/Details/Details.js | 4 ++-- rdf/student.rdf.php | 2 +- vilesci/personen/personendetails.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/application/views/system/infocenter/stammdaten.php b/application/views/system/infocenter/stammdaten.php index f143c9c03..4806d979a 100644 --- a/application/views/system/infocenter/stammdaten.php +++ b/application/views/system/infocenter/stammdaten.php @@ -188,7 +188,7 @@ zugangscode)): ?> diff --git a/public/js/components/Stv/Studentenverwaltung/Details/Details.js b/public/js/components/Stv/Studentenverwaltung/Details/Details.js index ae4f92b20..3ca656697 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details/Details.js +++ b/public/js/components/Stv/Studentenverwaltung/Details/Details.js @@ -153,7 +153,7 @@ export default { @@ -459,4 +459,4 @@ export default { ` -}; \ No newline at end of file +}; diff --git a/rdf/student.rdf.php b/rdf/student.rdf.php index 40cf28e01..f16f8a7b0 100644 --- a/rdf/student.rdf.php +++ b/rdf/student.rdf.php @@ -349,7 +349,7 @@ function draw_content($row) uid)?$row->uid.'@'.DOMAIN:'').']]> zugangscode.']]> - zugangscode.'&emailAdresse='.$mail_privat.']]> + zugangscode.'&emailAdresse='.$mail_privat.'&keepEmailUnverified=true]]> bpk.']]> diff --git a/vilesci/personen/personendetails.php b/vilesci/personen/personendetails.php index a20e34c5d..684b21712 100644 --- a/vilesci/personen/personendetails.php +++ b/vilesci/personen/personendetails.php @@ -153,7 +153,7 @@ echo "Name: $person->titelpre $person->nachname $ echo "Geburtsdatum: ".$datum_obj->formatDatum($person->gebdatum,'d.m.Y').""; echo "Geschlecht: ".$person->geschlecht.""; echo "Anmerkung: ".$db->convert_html_chars($person->anmerkungen).""; -echo "Zugangscode:".(in_array('bewerbung', (explode(';', ACTIVE_ADDONS)))?"".$db->convert_html_chars($person->zugangscode)."":$db->convert_html_chars($person->zugangscode)).""; +echo "Zugangscode:".(in_array('bewerbung', (explode(';', ACTIVE_ADDONS)))?"".$db->convert_html_chars($person->zugangscode)."":$db->convert_html_chars($person->zugangscode)).""; echo ''; echo '
Statusinformation - FH Ausweis
'; From 31f0be35c876a39eb7d2bcfaae57039e9932dfa7 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Wed, 2 Jul 2025 12:53:54 +0200 Subject: [PATCH 012/112] selbe person auch wenn nicht abbrecher --- application/models/person/Person_model.php | 116 +++++++++------------ 1 file changed, 52 insertions(+), 64 deletions(-) diff --git a/application/models/person/Person_model.php b/application/models/person/Person_model.php index 997048972..3947378cf 100644 --- a/application/models/person/Person_model.php +++ b/application/models/person/Person_model.php @@ -307,72 +307,60 @@ class Person_model extends DB_Model public function checkDuplicate($person_id) { - $qry = "SELECT person_id - FROM public.tbl_prestudent p - JOIN - ( - SELECT DISTINCT ON(prestudent_id) * - FROM public.tbl_prestudentstatus - WHERE prestudent_id IN - ( - SELECT prestudent_id - FROM public.tbl_prestudent - WHERE person_id IN - ( - SELECT p2.person_id - FROM public.tbl_person p - JOIN public.tbl_person p2 - ON lower(p.vorname) = lower(p2.vorname) - AND lower(p.nachname) = lower(p2.nachname) - AND p.gebdatum = p2.gebdatum - AND p.person_id = ? - ) - ) - ORDER BY prestudent_id, datum DESC, insertamum DESC - ) ps USING(prestudent_id) - JOIN public.tbl_status USING(status_kurzbz) + $qry = " + WITH person AS ( + SELECT * + FROM public.tbl_person + WHERE person_id = ? + ), + allePersonen AS ( + SELECT p.person_id + FROM public.tbl_person p + JOIN person + ON lower(p.vorname) = lower(person.vorname) + AND lower(p.nachname) = lower(person.nachname) + AND p.gebdatum = person.gebdatum + ), + lastStatus AS ( + SELECT DISTINCT ON (tbl_prestudentstatus.prestudent_id) + tbl_prestudentstatus.prestudent_id, + tbl_prestudentstatus.status_kurzbz, + tbl_prestudent.studiengang_kz, + tbl_prestudent.person_id + FROM public.tbl_prestudentstatus + JOIN public.tbl_prestudent USING (prestudent_id) + WHERE tbl_prestudent.person_id IN (SELECT person_id FROM allePersonen) + ORDER BY tbl_prestudentstatus.prestudent_id, tbl_prestudentstatus.datum DESC, tbl_prestudentstatus.insertamum DESC + ), + interessenten AS ( + SELECT * + FROM lastStatus WHERE status_kurzbz = 'Interessent' - AND studiengang_kz IN - ( - SELECT studiengang_kz - FROM public.tbl_prestudent p - JOIN - ( - SELECT DISTINCT ON(prestudent_id) * - FROM public.tbl_prestudentstatus - WHERE prestudent_id IN - ( - SELECT prestudent_id - FROM public.tbl_prestudent - WHERE person_id IN - ( - SELECT p2.person_id - FROM public.tbl_person p - JOIN public.tbl_person p2 - ON lower(p.vorname) = lower(p2.vorname) - AND lower(p.nachname) = lower(p2.nachname) - AND p.gebdatum = p2.gebdatum - AND p.person_id = ? - ) - ) - ORDER BY prestudent_id, datum DESC, insertamum DESC - ) ps USING(prestudent_id) - JOIN public.tbl_status USING(status_kurzbz) - WHERE status_kurzbz = 'Abbrecher' - ) - - UNION - + ), + keineInteressenten AS ( + SELECT * + FROM lastStatus + WHERE status_kurzbz != 'Interessent' + ), + doppeltePerson AS ( SELECT p2.person_id - FROM tbl_person p1 - JOIN tbl_prestudent ps ON p1.person_id = ps.person_id - INNER JOIN ( - SELECT vorname, nachname, gebdatum, person.person_id - FROM tbl_person person - JOIN tbl_prestudent sps ON person.person_id = sps.person_id - ) p2 - ON (lower(p1.vorname) = lower(p2.vorname) AND lower(p1.nachname) = lower(p2.nachname) AND p1.gebdatum = p2.gebdatum) - WHERE p1.person_id != p2.person_id AND (p1.person_id = ?)"; + FROM public.tbl_person p1 + JOIN public.tbl_prestudent ps1 ON ps1.person_id = p1.person_id + JOIN public.tbl_person p2 + ON lower(p1.vorname) = lower(p2.vorname) + AND lower(p1.nachname) = lower(p2.nachname) + AND p1.gebdatum = p2.gebdatum + WHERE p1.person_id = ? + AND p1.person_id <> p2.person_id + ) + SELECT DISTINCT(interessenten.person_id) + FROM interessenten + JOIN keineInteressenten + ON interessenten.studiengang_kz = keineInteressenten.studiengang_kz + WHERE interessenten.person_id = ? + UNION + SELECT DISTINCT person_id + FROM doppeltePerson"; return $this->execQuery($qry, array($person_id, $person_id, $person_id)); } From 5b2b715a169f83e0e29a186577e39bcae984da20 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Mon, 7 Jul 2025 08:59:36 +0200 Subject: [PATCH 013/112] userstory 61241: bugs behoben --- .../api/frontend/v1/Lehrveranstaltung.php | 16 +- .../controllers/api/frontend/v1/lv/Gruppe.php | 11 +- .../api/frontend/v1/lv/Lehreinheit.php | 7 +- .../models/education/Lehreinheit_model.php | 290 ++++++++---------- .../education/Lehreinheitgruppe_model.php | 4 +- .../education/Lehrveranstaltung_model.php | 17 +- public/css/Lvverwaltung.css | 5 +- .../components/LVVerwaltung/LVVerwaltung.js | 2 +- .../js/components/LVVerwaltung/Setup/Table.js | 139 ++++++--- .../js/components/LVVerwaltung/Tabs/Notiz.js | 2 +- system/phrasesupdate.php | 42 +++ 11 files changed, 300 insertions(+), 235 deletions(-) diff --git a/application/controllers/api/frontend/v1/Lehrveranstaltung.php b/application/controllers/api/frontend/v1/Lehrveranstaltung.php index 1b2e2bc35..098d44712 100644 --- a/application/controllers/api/frontend/v1/Lehrveranstaltung.php +++ b/application/controllers/api/frontend/v1/Lehrveranstaltung.php @@ -39,6 +39,12 @@ class Lehrveranstaltung extends FHCAPI_Controller $this->_ci->load->model('education/Lehrveranstaltung_model', 'LehrveranstaltungModel'); $this->_ci->load->library('VariableLib', ['uid' => $this->_uid]); + + $this->loadPhrases( + array( + 'ui' + ) + ); } public function loadByEmployee($mitarbeiter_uid = null, $stg_kz = null) { @@ -54,7 +60,7 @@ class Lehrveranstaltung extends FHCAPI_Controller foreach ($lehrveranstaltungen_data as $lehrveranstaltung) { - $lehreinheiten = $this->_ci->LehreinheitModel->getLEByLV($lehrveranstaltung->lehrveranstaltung_id, $studiensemester_kurzbz, $mitarbeiter_uid); + $lehreinheiten = $this->_ci->LehreinheitModel->getByLvidStudiensemester($lehrveranstaltung->lehrveranstaltung_id, $studiensemester_kurzbz, $mitarbeiter_uid); $lehreinheiten_data = $this->getDataOrTerminateWithError($lehreinheiten); if (!isset($lehrveranstaltung->_children)) @@ -69,8 +75,8 @@ class Lehrveranstaltung extends FHCAPI_Controller public function loadByStudiengang($studiengang_kz = null, $semester = null) { - if (is_null($studiengang_kz) || !ctype_digit((string)$studiengang_kz)) - $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); + if (is_null($studiengang_kz) || !preg_match("/^-?[1-9][0-9]*$/", (string)$studiengang_kz)) + $this->terminateWithError($this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); $verband = null; if (!is_null($semester) && !is_numeric($semester)) @@ -164,7 +170,7 @@ class Lehrveranstaltung extends FHCAPI_Controller if (is_null($lehrveranstaltung_id) || !ctype_digit((string)$lehrveranstaltung_id)) $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); - $this->_ci->LehrveranstaltungModel->addSelect('lehrveranstaltung_id, lehrform_kurzbz, lehre, bezeichnung as lvbezeichnung'); + $this->_ci->LehrveranstaltungModel->addSelect('lehrveranstaltung_id, lehrform_kurzbz, lehre, bezeichnung as lvbezeichnung, sprache'); $lehrveranstaltung_result = $this->_ci->LehrveranstaltungModel->loadWhere(array('lehrveranstaltung_id' => $lehrveranstaltung_id)); $lehrveranstaltung_result = $this->getDataOrTerminateWithError($lehrveranstaltung_result); $lehrveranstaltung = $lehrveranstaltung_result[0]; @@ -202,7 +208,7 @@ class Lehrveranstaltung extends FHCAPI_Controller foreach ($lehrveranstaltungen_data as $lehrveranstaltung) { - $lehreinheiten = $this->LehreinheitModel->getLEByLV($lehrveranstaltung->lehrveranstaltung_id, $studiensemester_kurzbz); + $lehreinheiten = $this->LehreinheitModel->getByLvidStudiensemester($lehrveranstaltung->lehrveranstaltung_id, $studiensemester_kurzbz); $lehreinheiten_data = $this->getDataOrTerminateWithError($lehreinheiten); if (!isset($lehrveranstaltung->_children)) diff --git a/application/controllers/api/frontend/v1/lv/Gruppe.php b/application/controllers/api/frontend/v1/lv/Gruppe.php index 01c11f98f..09f253a59 100644 --- a/application/controllers/api/frontend/v1/lv/Gruppe.php +++ b/application/controllers/api/frontend/v1/lv/Gruppe.php @@ -19,6 +19,13 @@ class Gruppe extends FHCAPI_Controller $this->_ci = &get_instance(); $this->_setAuthUID(); + $this->_ci->load->library('PhrasesLib'); + $this->loadPhrases( + array( + 'ui' + ) + ); + $this->_ci->load->model('organisation/Gruppe_model', 'GruppeModel'); $this->_ci->load->model('organisation/Lehrverband_model', 'LehrverbandModel'); $this->_ci->load->model('education/Lehreinheitgruppe_model', 'LehreinheitgruppeModel'); @@ -57,10 +64,6 @@ class Gruppe extends FHCAPI_Controller if (is_null($lehreinheit_id) || !ctype_digit((string)$lehreinheit_id) || is_null($gid) || !ctype_digit((string)$gid) || is_null($lehrverband)) $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); - $gruppe_result = $this->_ci->GruppeModel->loadWhere(array('gid' => $gid)); - if (!hasData($gruppe_result) || isError($gruppe_result)) - $this->terminateWithError( $this->p->t('ui', 'ungueltigeParameter'), self::ERROR_TYPE_GENERAL); - $this->checkPermission($lehreinheit_id); $result = $this->_ci->LehreinheitgruppeModel->addGroup($lehreinheit_id, $gid, !($lehrverband === 'false')); diff --git a/application/controllers/api/frontend/v1/lv/Lehreinheit.php b/application/controllers/api/frontend/v1/lv/Lehreinheit.php index 84ee66d5d..0c42c0082 100644 --- a/application/controllers/api/frontend/v1/lv/Lehreinheit.php +++ b/application/controllers/api/frontend/v1/lv/Lehreinheit.php @@ -164,7 +164,6 @@ class Lehreinheit extends FHCAPI_Controller $this->terminateWithValidationErrors($this->form_validation->error_array()); } - $updateData = array(); foreach ($updatableFields as $field) { @@ -183,6 +182,12 @@ class Lehreinheit extends FHCAPI_Controller $updateData ); + if (!isset($updateData['unr'])) + { + $unr = getData($result); + $this->_ci->LehreinheitModel->update($unr, array('unr' => $unr)); + } + $this->terminateWithSuccess($result); } diff --git a/application/models/education/Lehreinheit_model.php b/application/models/education/Lehreinheit_model.php index ba9e82c64..ce414bad2 100644 --- a/application/models/education/Lehreinheit_model.php +++ b/application/models/education/Lehreinheit_model.php @@ -335,7 +335,7 @@ EOSQL; } - public function getByLvidStudiensemester($lv_id, $studiensemester_kurzbz) + public function getByLvidStudiensemester($lv_id, $studiensemester_kurzbz, $mitarbeiter_uid = null, $fachbereich_kurzbz = null) { $qry = "WITH lehreinheiten AS ( SELECT * @@ -343,98 +343,64 @@ EOSQL; WHERE lehrveranstaltung_id = ? AND studiensemester_kurzbz = ? ), - gruppen AS ( - SELECT - COALESCE( - string_agg( - tbl_lehreinheitgruppe.gruppe_kurzbz, ' ' - ) FILTER (WHERE NOT direktinskription), - string_agg( - COALESCE( - upper(tbl_studiengang.typ::varchar(1) ||tbl_studiengang.kurzbz) || - '-'|| - COALESCE(tbl_lehreinheitgruppe.semester::varchar, '') || - COALESCE(tbl_lehreinheitgruppe.verband::varchar, '')|| - COALESCE(tbl_lehreinheitgruppe.gruppe, '')), ', ' - ) - ) AS gruppe, - lehreinheit_id - FROM - lehre.tbl_lehreinheitgruppe - LEFT JOIN public.tbl_studiengang USING(studiengang_kz) - LEFT JOIN public.tbl_gruppe USING(gruppe_kurzbz) - GROUP BY lehreinheit_id - ), - mitarbeiter AS ( - SELECT kurzbz, semesterstunden, planstunden, lehreinheit_id - FROM lehre.tbl_lehreinheitmitarbeiter - JOIN public.tbl_mitarbeiter USING(mitarbeiter_uid) - ), - fachbereich AS ( - SELECT - tbl_organisationseinheit.bezeichnung, - tbl_organisationseinheit.organisationseinheittyp_kurzbz, - lehreinheit_id - FROM - public.tbl_organisationseinheit, - lehre.tbl_lehrveranstaltung as lehrfach, - lehre.tbl_lehreinheit - WHERE tbl_organisationseinheit.oe_kurzbz = lehrfach.oe_kurzbz - AND lehrfach.lehrveranstaltung_id = tbl_lehreinheit.lehrfach_id - ), - tag_data_agg AS ( - SELECT - lehreinheit_id, - COALESCE(json_agg(tag ORDER BY id), '[]'::json) AS tags - FROM ( - SELECT DISTINCT ON (public.tbl_notiz.notiz_id) - tbl_notiz.notiz_id AS id, - typ_kurzbz, - array_to_json(tbl_notiz_typ.bezeichnung_mehrsprachig)->>0 AS beschreibung, - text AS notiz, - style, - erledigt AS done, - lehreinheit_id - FROM public.tbl_notizzuordnung - JOIN public.tbl_notiz ON tbl_notizzuordnung.notiz_id = tbl_notiz.notiz_id - JOIN public.tbl_notiz_typ ON tbl_notiz.typ = tbl_notiz_typ.typ_kurzbz - WHERE lehreinheit_id IN (SELECT lehreinheit_id FROM lehreinheiten) - ) AS tag - GROUP BY lehreinheit_id - ) + ". $this->_getGruppenCTE() . ", + ". $this->_getLektorenCTE() . ", + ". $this->_getFachbereichCTE() . ", + ". $this->_getTagsCTE() . " + SELECT lehreinheiten.*, lehreinheiten.lehrform_kurzbz as lv_lehrform_kurzbz, tbl_lehrveranstaltung.kurzbz as lv_kurzbz, tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, COALESCE(tag_data_agg.tags, '[]'::json) AS tags, - ( - SELECT string_agg(gr.gruppe, ' ') - FROM gruppen gr - WHERE gr.lehreinheit_id = lehreinheiten.lehreinheit_id - ) AS gruppen, - ( - SELECT string_agg(ma.kurzbz, ' ') - FROM mitarbeiter ma - WHERE ma.lehreinheit_id = lehreinheiten.lehreinheit_id - ) AS lektoren, - ( - SELECT string_agg(fachbereich.bezeichnung, ' ') - FROM fachbereich - WHERE fachbereich.lehreinheit_id = lehreinheiten.lehreinheit_id - ) AS fachbereich + gruppen.gruppen, + mitarbeiter.lektoren, + mitarbeiter.le_planstunden, + mitarbeiter.semesterstunden, + fachbereich.bezeichnung as fachbereich, + UPPER(CONCAT(tbl_studiengang.typ,tbl_studiengang.kurzbz)) as studiengang, + semester FROM lehreinheiten LEFT JOIN lehre.tbl_lehrveranstaltung ON tbl_lehrveranstaltung.lehrveranstaltung_id = lehreinheiten.lehrfach_id - LEFT JOIN tag_data_agg ON tag_data_agg.lehreinheit_id = lehreinheiten.lehreinheit_id"; + LEFT JOIN public.tbl_studiengang USING(studiengang_kz) + LEFT JOIN tag_data_agg ON tag_data_agg.lehreinheit_id = lehreinheiten.lehreinheit_id + LEFT JOIN mitarbeiter ON lehreinheiten.lehreinheit_id = mitarbeiter.lehreinheit_id + LEFT JOIN fachbereich ON lehreinheiten.lehreinheit_id = fachbereich.lehreinheit_id + LEFT JOIN gruppen ON lehreinheiten.lehreinheit_id = gruppen.lehreinheit_id + WHERE true + "; - return $this->execReadOnlyQuery($qry, array($lv_id, $studiensemester_kurzbz)); + $params = array($lv_id, $studiensemester_kurzbz); + + if ($mitarbeiter_uid !== null) + { + $qry .= " AND lehreinheiten.lehreinheit_id IN ( SELECT lehreinheit_id FROM lehre.tbl_lehreinheitmitarbeiter WHERE mitarbeiter_uid = ?) "; + $params[] = $mitarbeiter_uid; + } + + if($fachbereich_kurzbz !== null) + { + $qry .= " AND EXISTS ( SELECT 1 FROM lehre.tbl_lehrveranstaltung JOIN public.tbl_fachbereich USING(oe_kurzbz) WHERE fachbereich_kurzbz= ? AND lehrveranstaltung_id=lehreinheiten.lehrfach_id)"; + $params[] = $fachbereich_kurzbz; + } + $qry .= " ORDER BY lehrveranstaltung_id;"; + + return $this->execReadOnlyQuery($qry, $params); } private function getLVTmp($stg_kz = null) { $qry = "SELECT DISTINCT ON(lehrveranstaltung_id) *, - '' as studienplan_id, '' as studienplan_beeichnung, - CONCAT(vw_lehreinheit.stg_typ, vw_lehreinheit.stg_kurzbz) as studiengang - FROM campus.vw_lehreinheit + '' as stundenblockung, + '' as lehreinheit_id, + '' as wochenrythmus, + '' as raumtyp, + '' as raumtypalternativ, + '' as gruppen, + '' as studienplan_id, + '' as studienplan_beeichnung, + UPPER(CONCAT(vw_lehreinheit.stg_typ, vw_lehreinheit.stg_kurzbz)) as studiengang + FROM campus.vw_lehreinheit WHERE mitarbeiter_uid = ? AND studiensemester_kurzbz = ?"; @@ -460,89 +426,6 @@ EOSQL; return $this->execReadOnlyQuery($qry, $params); } - - - public function getLEByLV($lv_id, $studiensemester_kurzbz, $mitarbeiter_uid = null, $fachbereich_kurzbz = null) - { - $qry = " - WITH gruppen AS ( - SELECT - COALESCE( - string_agg( - tbl_lehreinheitgruppe.gruppe_kurzbz, ', ' - ) FILTER (WHERE NOT direktinskription), - string_agg( - COALESCE( - upper(tbl_studiengang.typ::varchar(1) ||tbl_studiengang.kurzbz) || - '-'|| - COALESCE(tbl_lehreinheitgruppe.semester::varchar, '') || - COALESCE(tbl_lehreinheitgruppe.verband::varchar, '')|| - COALESCE(tbl_lehreinheitgruppe.gruppe, '')), ', ' - ) - ) AS gruppen, - lehreinheit_id - FROM - lehre.tbl_lehreinheitgruppe - LEFT JOIN public.tbl_studiengang USING(studiengang_kz) - LEFT JOIN public.tbl_gruppe USING(gruppe_kurzbz) - GROUP BY lehreinheit_id - ), - lektoren AS ( - SELECT string_agg(kurzbz, ' ') as lektoren, - string_agg(semesterstunden::text, ' ') as semesterstunden, - string_agg(planstunden::text, ' ') as planstunden, - lehreinheit_id - FROM lehre.tbl_lehreinheitmitarbeiter - JOIN public.tbl_mitarbeiter USING(mitarbeiter_uid) - GROUP BY lehreinheit_id - ), - fachbereich AS ( - SELECT - string_agg(CONCAT(tbl_organisationseinheit.bezeichnung, ' (', tbl_organisationseinheit.organisationseinheittyp_kurzbz, ')'),' ') as fachbereich, - lehreinheit_id - FROM - public.tbl_organisationseinheit, - lehre.tbl_lehrveranstaltung as lehrfach, - lehre.tbl_lehreinheit - WHERE - tbl_organisationseinheit.oe_kurzbz = lehrfach.oe_kurzbz - AND lehrfach.lehrveranstaltung_id = tbl_lehreinheit.lehrfach_id - GROUP BY lehreinheit_id - ) - SELECT tbl_lehreinheit.*, - tbl_lehrveranstaltung.*, - tbl_lehrveranstaltung.kurzbz as lv_kurzbz, - tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, - lektoren.lektoren, - lektoren.semesterstunden, - lektoren.planstunden, - fachbereich.fachbereich - FROM lehre.tbl_lehreinheit - LEFT JOIN lehre.tbl_lehrveranstaltung ON tbl_lehrveranstaltung.lehrveranstaltung_id = tbl_lehreinheit.lehrfach_id - LEFT JOIN gruppen ON tbl_lehreinheit.lehreinheit_id = gruppen.lehreinheit_id - LEFT JOIN lektoren ON tbl_lehreinheit.lehreinheit_id = lektoren.lehreinheit_id - LEFT JOIN fachbereich ON tbl_lehreinheit.lehreinheit_id = fachbereich.lehreinheit_id - WHERE tbl_lehreinheit.lehrveranstaltung_id = ? - AND studiensemester_kurzbz = ? - "; - - $params = array($lv_id, $studiensemester_kurzbz); - if ($mitarbeiter_uid !== null) - { - $qry .= " AND tbl_lehreinheit.lehreinheit_id IN ( SELECT lehreinheit_id FROM lehre.tbl_lehreinheitmitarbeiter WHERE mitarbeiter_uid = ?) "; - $params[] = $mitarbeiter_uid; - } - - if($fachbereich_kurzbz !== null) - { - $qry .= " AND EXISTS ( SELECT 1 FROM lehre.tbl_lehrveranstaltung JOIN public.tbl_fachbereich USING(oe_kurzbz) WHERE fachbereich_kurzbz= ? AND lehrveranstaltung_id=tbl_lehreinheit.lehrfach_id)"; - $params[] = $fachbereich_kurzbz; - } - $qry .= " ORDER BY lehreinheit_id;"; - - return $this->execReadOnlyQuery($qry, $params); - } - public function deleteLehreinheit($lehreinheit_id) { $lehreinheit = $this->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); @@ -741,4 +624,85 @@ EOSQL; $this->db->trans_commit(); return success('Contract successfully updated.'); } + + private function _getGruppenCTE() + { + return "gruppen AS ( + SELECT + lehreinheit_id, + STRING_AGG( + CASE + WHEN (tbl_lehreinheitgruppe.gruppe_kurzbz IS NULL OR tbl_lehreinheitgruppe.gruppe_kurzbz = '') + THEN + UPPER(tbl_studiengang.typ::varchar(1) || tbl_studiengang.kurzbz) || + COALESCE(TRIM(tbl_lehreinheitgruppe.semester::text), '') || + COALESCE(TRIM(tbl_lehreinheitgruppe.verband), '') || + COALESCE(TRIM(tbl_lehreinheitgruppe.gruppe), '') + ELSE + CASE + WHEN NOT tbl_gruppe.direktinskription THEN tbl_lehreinheitgruppe.gruppe_kurzbz + ELSE NULL + END + END, + ' ' + ) AS gruppen + FROM lehre.tbl_lehreinheitgruppe + LEFT JOIN public.tbl_studiengang USING (studiengang_kz) + LEFT JOIN public.tbl_gruppe USING (gruppe_kurzbz) + JOIN lehreinheiten USING(lehreinheit_id) + GROUP BY lehreinheit_id + )"; + } + private function _getLektorenCTE() + { + return "mitarbeiter AS ( + SELECT + tbl_lehreinheitmitarbeiter.lehreinheit_id, + STRING_AGG(m.kurzbz, ' ') AS lektoren, + STRING_AGG(tbl_lehreinheitmitarbeiter.semesterstunden::text, ' ') AS semesterstunden, + STRING_AGG(tbl_lehreinheitmitarbeiter.planstunden::text, ' ') AS le_planstunden + FROM lehre.tbl_lehreinheitmitarbeiter + JOIN public.tbl_mitarbeiter m USING (mitarbeiter_uid) + JOIN lehreinheiten USING(lehreinheit_id) + GROUP BY tbl_lehreinheitmitarbeiter.lehreinheit_id + )"; + } + + private function _getFachbereichCTE() + { + return "fachbereich AS ( + SELECT + CONCAT(tbl_organisationseinheit.bezeichnung, ' (', tbl_organisationseinheit.organisationseinheittyp_kurzbz, ')') as bezeichnung, + lehreinheiten.lehreinheit_id + FROM public.tbl_organisationseinheit + JOIN lehre.tbl_lehrveranstaltung AS lehrfach ON tbl_organisationseinheit.oe_kurzbz = lehrfach.oe_kurzbz + JOIN lehre.tbl_lehreinheit ON lehrfach.lehrveranstaltung_id = tbl_lehreinheit.lehrfach_id + JOIN lehreinheiten ON tbl_lehreinheit.lehreinheit_id = lehreinheiten.lehreinheit_id + )"; + } + + private function _getTagsCTE() + { + return "tag_data_agg AS ( + SELECT + lehreinheit_id, + COALESCE(json_agg(tag ORDER BY id), '[]'::json) AS tags + FROM ( + SELECT DISTINCT ON (public.tbl_notiz.notiz_id) + tbl_notiz.notiz_id AS id, + typ_kurzbz, + array_to_json(tbl_notiz_typ.bezeichnung_mehrsprachig)->>0 AS beschreibung, + text AS notiz, + style, + erledigt AS done, + lehreinheit_id + FROM public.tbl_notizzuordnung + JOIN public.tbl_notiz ON tbl_notizzuordnung.notiz_id = tbl_notiz.notiz_id + JOIN public.tbl_notiz_typ ON tbl_notiz.typ = tbl_notiz_typ.typ_kurzbz + WHERE lehreinheit_id IN (SELECT lehreinheit_id FROM lehreinheiten) + ) AS tag + GROUP BY lehreinheit_id + )"; + } + } diff --git a/application/models/education/Lehreinheitgruppe_model.php b/application/models/education/Lehreinheitgruppe_model.php index 5dd2fa66c..8fc8e09f3 100644 --- a/application/models/education/Lehreinheitgruppe_model.php +++ b/application/models/education/Lehreinheitgruppe_model.php @@ -304,7 +304,7 @@ class Lehreinheitgruppe_model extends DB_Model } else if ($verband === true) { - $gruppen_result = $this->_ci->LehrverbandModel->loadWhere(array('gid' => $gid)); + $gruppen_result = $this->LehrverbandModel->loadWhere(array('gid' => $gid)); if (!hasData($gruppen_result)) return error('No group found for gid ' . $gid); @@ -470,6 +470,6 @@ class Lehreinheitgruppe_model extends DB_Model END AS verplant"); $this->addJoin('tbl_studiengang', 'studiengang_kz', 'LEFT'); $this->addJoin('public.tbl_gruppe', 'gruppe_kurzbz', 'LEFT'); - return $this->loadWhere(array('lehreinheit_id' => $lehreinheit_id, 'tbl_gruppe.direktinskription' => false)); + return $this->loadWhere(array('lehreinheit_id' => $lehreinheit_id)); } } diff --git a/application/models/education/Lehrveranstaltung_model.php b/application/models/education/Lehrveranstaltung_model.php index 955177273..121de9233 100644 --- a/application/models/education/Lehrveranstaltung_model.php +++ b/application/models/education/Lehrveranstaltung_model.php @@ -1122,9 +1122,9 @@ class Lehrveranstaltung_model extends DB_Model $qry .= " SELECT DISTINCT on(lehrveranstaltung_id) lehrveranstaltung_id, - kurzbz as lv_kurzbz, - bezeichnung as lv_bezeichnung, - bezeichnung_english as lv_bezeichnung_english, + tbl_lehrveranstaltung.kurzbz as lv_kurzbz, + tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, + tbl_lehrveranstaltung.bezeichnung_english as lv_bezeichnung_english, studiengang_kz, semester, tbl_lehrveranstaltung.sprache, @@ -1133,7 +1133,7 @@ class Lehrveranstaltung_model extends DB_Model tbl_lehrveranstaltung.anmerkung, tbl_lehrveranstaltung.lehre, lehreverzeichnis as lv_lehreverzeichnis, - aktiv, + tbl_lehrveranstaltung.aktiv, planfaktor as lv_planfaktor, planlektoren as lv_planlektoren, planpersonalkosten as lv_planpersonalkosten, @@ -1143,9 +1143,11 @@ class Lehrveranstaltung_model extends DB_Model ''::text as studienplan_id, '' as studienplan_bezeichnung, '' as studienplan_lehrveranstaltung_id_parent, - tbl_lehrveranstaltung.lehrtyp_kurzbz + tbl_lehrveranstaltung.lehrtyp_kurzbz, + UPPER(CONCAT(tbl_studiengang.typ,tbl_studiengang.kurzbz)) as studiengang FROM lehre.tbl_lehrveranstaltung JOIN lehre.tbl_lehreinheit USING (lehrveranstaltung_id) + JOIN public.tbl_studiengang USING(studiengang_kz) WHERE studiengang_kz = ? AND studiensemester_kurzbz = ? "; @@ -1178,17 +1180,18 @@ class Lehrveranstaltung_model extends DB_Model { return " SELECT - lehrveranstaltung_id, kurzbz as lv_kurzbz, tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, bezeichnung_english as lv_bezeichnung_english, studiengang_kz, + lehrveranstaltung_id, tbl_lehrveranstaltung.kurzbz as lv_kurzbz, tbl_lehrveranstaltung.bezeichnung as lv_bezeichnung, bezeichnung_english as lv_bezeichnung_english, studiengang_kz, tbl_studienplan_lehrveranstaltung.semester, tbl_lehrveranstaltung.sprache, ects as lv_ects, semesterstunden, anmerkung, lehre, lehreverzeichnis as lv_lehreverzeichnis, tbl_lehrveranstaltung.aktiv, planfaktor as lv_planfaktor, planlektoren as lv_planlektoren, planpersonalkosten as lv_planpersonalkosten, plankostenprolektor as lv_plankostenprolektor, lehrform_kurzbz as lv_lehrform_kurzbz, tbl_lehrveranstaltung.orgform_kurzbz, tbl_studienplan_lehrveranstaltung.studienplan_id::text as studienplan_id, tbl_studienplan.bezeichnung as studienplan_bezeichnung, tbl_studienplan_lehrveranstaltung.studienplan_lehrveranstaltung_id_parent::text, - tbl_lehrveranstaltung.lehrtyp_kurzbz + tbl_lehrveranstaltung.lehrtyp_kurzbz, UPPER(CONCAT(tbl_studiengang.typ,tbl_studiengang.kurzbz)) as studiengang FROM lehre.tbl_lehrveranstaltung JOIN lehre.tbl_studienplan_lehrveranstaltung USING(lehrveranstaltung_id) JOIN lehre.tbl_studienplan USING(studienplan_id) + JOIN tbl_studiengang USING(studiengang_kz) WHERE tbl_lehrveranstaltung.aktiv AND ((studienplan_id, tbl_studienplan_lehrveranstaltung.semester) IN ( " . implode(',', $placeholders) . ")) UNION diff --git a/public/css/Lvverwaltung.css b/public/css/Lvverwaltung.css index 1ca3f0be1..38d74def4 100644 --- a/public/css/Lvverwaltung.css +++ b/public/css/Lvverwaltung.css @@ -14,14 +14,17 @@ textarea[name="anmerkung"] { .lv_table_icon.icon-modul::before { content: '\f468'; + color: #4e4ed2; } .lv_table_icon.icon-lv::before { content: '\f466'; + color: black; } .lv_table_icon.icon-::before { content: '\f073'; -} \ No newline at end of file + color: #f3c541; +} diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index 772af5a47..c7c34802d 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -186,7 +186,7 @@ export default { : this.$route.params.stg; } - this.$p.loadCategory(['lehre', 'person']) + this.$p.loadCategory(['lehre', 'person', 'global']) this.$api.call(ApiDetails.getStudiensemester()) .then(result => { diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js index 9b0ae71f3..b4674ccff 100644 --- a/public/js/components/LVVerwaltung/Setup/Table.js +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -100,7 +100,6 @@ export default { expanded: [], selectedColumnValues: [], tagEndpoint: ApiTag, - iconPath: FHC_JS_DATA_STORAGE_OBJECT.app_root + '/skin/images/lehrtyp_', tabulatorEvents: [ { event: 'rowSelectionChanged', @@ -119,7 +118,8 @@ export default { handler: (data) => { this.getExpandedRows() } - },{ + }, + { event: 'dataTreeRowCollapsed', handler: (data) => { this.getExpandedRows() @@ -157,19 +157,18 @@ export default { initialSort:[ {column: 'lv_bezeichnung', dir: 'desc'}, ], + dataTreeChildIndent: 20, dataTreeElementColumn: "lv_kurzbz", - dataTreeFilter: true, dataTreeStartExpanded: false, dataTreeCollapseElement: '', dataTreeExpandElement: '', columnDefaults: { tooltip: true, headerFilter: "input", - headerFilterFunc: extendedHeaderFilter + headerFilterFunc: extendedHeaderFilter, }, layout: 'fitDataStretch', - layoutColumnsOnNewData: false, - height: '100%', + persistenceID: 'lehrveranstaltungen_2025_07_07_v1', selectableRowsRangeMode: 'click', selectableRows: true, rowContextMenu: (component, e) => { @@ -217,7 +216,6 @@ export default { ]; }, - persistenceID: 'lehrveranstaltungen_2025_05_27_v1', columns: [ { title: this.$p.t('lehre', 'kurzbz'), @@ -302,45 +300,55 @@ export default { }, width: 150, }, + { + title: this.$p.t('lehre', 'kurzbz'), + field: "lv_kurzbz_anzeige", + headerFilterFuncParams: {field: 'lv_kurzbz_anzeige'}, + formatter: (cell, formatterParams) => { + let rowData = cell.getRow().getData(); + return rowData?.lv_kurzbz?.toUpperCase(); + }, + headerFilter: true + }, { title: this.$p.t('lehre', 'lehrveranstaltung_id'), field: "lehrveranstaltung_id", headerFilterFuncParams: {field: 'lehrveranstaltung_id'}, - headerFilter: true + headerFilter: true, + visible: false }, {title: this.$p.t('ui', 'bezeichnung'), field: "lv_bezeichnung", headerFilter: true, headerFilterFuncParams: {field: 'lv_bezeichnung'}}, - {title: this.$p.t('lehre', 'bezeichnungeng'), field: "lv_bezeichnung_english", headerFilter: true, headerFilterFuncParams: {field: 'lv_bezeichnung_english'}}, + {title: this.$p.t('lehre', 'bezeichnungeng'), field: "lv_bezeichnung_english", headerFilter: true, headerFilterFuncParams: {field: 'lv_bezeichnung_english'}, visible: false}, { title: this.$p.t('lehre', 'studiengangskennzahlLehre'), field: "lv_studiengang_kz", headerFilter: true, - headerFilterFuncParams: {field: 'lv_studiengang_kz'} + headerFilterFuncParams: {field: 'lv_studiengang_kz'}, + visible: false }, - {title: this.$p.t('lehre', 'studiengang'), field: "studiengang", headerFilter: true, headerFilterFuncParams: {field: 'studiengang'}}, + {title: this.$p.t('lehre', 'studiengang'), field: "studiengang", headerFilter: true, headerFilterFuncParams: {field: 'studiengang'}, visible: false}, {title: this.$p.t('lehre', 'semester'), field: "semester", headerFilter: true, headerFilterFuncParams: {field: 'semester'}}, - {title: this.$p.t('global', 'sprache'), field: "sprache", headerFilter: true, headerFilterFuncParams: {field: 'sprache'}}, - {title: this.$p.t('lehre', 'ects'), field: "lv_ects", headerFilter: true, headerFilterFuncParams: {field: 'lv_ects'}}, - {title: this.$p.t('lehre', 'semesterstunden'), field: "semesterstunden", headerFilter: true, headerFilterFuncParams: {field: 'semesterstunden'}}, - {title: this.$p.t('global', 'anmerkung'), field: "anmerkung", headerFilter: true, headerFilterFuncParams: {field: 'anmerkung'}}, - {title: this.$p.t('lehre', 'lehre'), field: "lehre", headerFilter: true, headerFilterFuncParams: {field: 'lehre'}}, - {title: "Lehreverzeichnis", field: "lehreverzeichnis", headerFilter: true, headerFilterFuncParams: {field: 'lehreverzeichnis'}}, - {title: this.$p.t('person', 'aktiv'), field: "aktiv", headerFilter: true, headerFilterFuncParams: {field: 'aktiv'}}, - {title: "Planfaktor", field: "planfaktor", headerFilter: true, headerFilterFuncParams: {field: 'planfaktor'}}, - {title: "Planlektoren", field: "planlektoren", headerFilter: true, headerFilterFuncParams: {field: 'planlektoren'}}, - {title: "planpersonalkosten", field: "planpersonalkosten", headerFilter: true, headerFilterFuncParams: {field: 'planpersonalkosten'}}, - {title: "plankostenprolektor", field: "plankostenprolektor", headerFilter: true, headerFilterFuncParams: {field: 'plankostenprolektor'}}, - {title: this.$p.t('ui', 'organisationsform'), field: "orgform_kurzbz", headerFilter: true, headerFilterFuncParams: {field: 'orgform_kurzbz'}}, - {title: this.$p.t('ui', 'studienplan_id'), field: "studienplan_id", headerFilter: true, headerFilterFuncParams: {field: 'studienplan_id'}}, - {title: "studienplan_bezeichnung", field: "studienplan_bezeichnung", headerFilter: true, headerFilterFuncParams: {field: 'studienplan_bezeichnung'}}, - {title: "lehrtyp_kurzbz", field: "lehrtyp_kurzbz", headerFilter: true, headerFilterFuncParams: {field: 'lehrtyp_kurzbz'}}, + {title: this.$p.t('global', 'sprache'), field: "sprache", headerFilter: true, headerFilterFuncParams: {field: 'sprache'}, visible: false}, + {title: this.$p.t('lehre', 'ects'), field: "lv_ects", headerFilter: true, headerFilterFuncParams: {field: 'lv_ects'}, visible: false}, + {title: this.$p.t('lehre', 'semesterstunden'), field: "semesterstunden", headerFilter: true, headerFilterFuncParams: {field: 'semesterstunden'}, visible: false}, + {title: this.$p.t('global', 'anmerkung'), field: "anmerkung", headerFilter: true, headerFilterFuncParams: {field: 'anmerkung'}, visible: false}, + {title: this.$p.t('lehre', 'lehre'), field: "lehre", headerFilter: true, headerFilterFuncParams: {field: 'lehre'}, formatter: (cell) => cell.getValue() ? this.toUpperCase(this.$p.t('ui', 'ja')) : this.toUpperCase(this.$p.t('ui', 'nein')), visible: false}, + {title: this.$p.t('person', 'aktiv'), field: "aktiv", headerFilter: true, headerFilterFuncParams: {field: 'aktiv'}, formatter: (cell) => cell.getValue() ? this.toUpperCase(this.$p.t('ui', 'ja')) : this.toUpperCase(this.$p.t('ui', 'nein')), visible: false}, + {title: this.$p.t('lehre', 'organisationsform'), field: "orgform_kurzbz", headerFilter: true, headerFilterFuncParams: {field: 'orgform_kurzbz'}}, + {title: this.$p.t('ui', 'studienplan_id'), field: "studienplan_id", headerFilter: true, headerFilterFuncParams: {field: 'studienplan_id'}, visible: false}, + {title: this.$p.t('lehre', 'studienplan'), field: "studienplan_bezeichnung", headerFilter: true, headerFilterFuncParams: {field: 'studienplan_bezeichnung'}, visible: false}, + {title: this.$p.t('lehre', 'lehrtyp'), field: "lehrtyp_kurzbz", headerFilter: true, headerFilterFuncParams: {field: 'lehrtyp_kurzbz'}, visible: false}, {title: this.$p.t('lehre', 'lehrform'), field: "lehrform_kurzbz", headerFilter: true, headerFilterFuncParams: {field: 'lehrform_kurzbz'}}, - {title: this.$p.t('lehre', 'leplanstunden'), field: "le_planstunden", headerFilter: true, headerFilterFuncParams: {field: 'le_planstunden'}}, - {title: this.$p.t('lehre', 'lehreinheit_id'), field: "lehreinheit_id", headerFilter: true, headerFilterFuncParams: {field: 'lehreinheit_id'}}, - {title: this.$p.t('lehre', 'stundenblockung'), field: "stundenblockung", headerFilter: true, headerFilterFuncParams: {field: 'stundenblockung'}}, - {title: this.$p.t('lehre', 'wochenrhytmus'), field: "wochenrythmus", headerFilter: true, headerFilterFuncParams: {field: 'wochenrythmus'}}, - {title: this.$p.t('lehre', 'startkw'), field: "startkw", headerFilter: true, headerFilterFuncParams: {field: 'startkw'}}, - {title: this.$p.t('lehre', 'raumtyp'), field: "raumtyp", headerFilter: true, headerFilterFuncParams: {field: 'raumtyp'}}, - {title: this.$p.t('lehre', 'raumtypalternativ'), field: "raumtypalternativ", headerFilter: true, headerFilterFuncParams: {field: 'raumtypalternativ'}}, + {title: this.$p.t('lehre', 'leplanstunden'), field: "le_planstunden", headerFilter: true, headerFilterFuncParams: {field: 'le_planstunden'}, visible: false}, + {title: this.$p.t('lehre', 'lehreinheit_id'), field: "lehreinheit_id", headerFilter: true, headerFilterFuncParams: {field: 'lehreinheit_id'}, visible: false}, + {title: this.$p.t('lehre', 'studiensemester'), field: "studiensemester_kurzbz", headerFilter: true, headerFilterFuncParams: {field: 'studiensemester_kurzbz'}, visible: false}, + {title: this.$p.t('lehre', 'unr'), field: "unr", headerFilter: true, headerFilterFuncParams: {field: 'unr'}, visible: false}, + {title: this.$p.t('lehre', 'fachbereich'), field: "fachbereich", headerFilter: true, headerFilterFuncParams: {field: 'fachbereich'}, visible: false}, + {title: this.$p.t('lehre', 'stundenblockung'), field: "stundenblockung", headerFilter: true, headerFilterFuncParams: {field: 'stundenblockung'}, visible: false}, + {title: this.$p.t('lehre', 'wochenrhythmus'), field: "wochenrythmus", headerFilter: true, headerFilterFuncParams: {field: 'wochenrythmus'}, visible: false}, + {title: this.$p.t('lehre', 'startkw'), field: "start_kw", headerFilter: true, headerFilterFuncParams: {field: 'startkw'}, visible: false}, + {title: this.$p.t('lehre', 'raumtyp'), field: "raumtyp", headerFilter: true, headerFilterFuncParams: {field: 'raumtyp'}, visible: false}, + {title: this.$p.t('lehre', 'raumtypalternativ'), field: "raumtypalternativ", headerFilter: true, headerFilterFuncParams: {field: 'raumtypalternativ'}, visible: false}, {title: this.$p.t('lehre', 'gruppen'), field: "gruppen", headerFilter: true, headerFilterFuncParams: {field: 'gruppen'}}, {title: this.$p.t('lehre', 'lehrende'), field: "lektoren", headerFilter: true, headerFilterFuncParams: {field: 'lektoren'}}, ], @@ -359,6 +367,11 @@ export default { shouldAutoLoad() { return this.filter && this.filter.activeFilter; }, + toUpperCase(str) { + if (!str) + return ''; + return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase() + }, async reload() { @@ -369,7 +382,7 @@ export default { }, rowSelectionChanged(data) { this.selectedRows = this.$refs.table.tabulator.getSelectedRows(); - this.selectedColumnValues = this.selectedRows.filter(row => row.getData().lehreinheit_id !== undefined).map(row => row.getData().lehreinheit_id); + this.selectedColumnValues = this.selectedRows.filter(row => row.getData().lehreinheit_id !== undefined && row.getData().lehreinheit_id).map(row => row.getData().lehreinheit_id); if (data[0]?.lehreinheit_id !== undefined && this.selectedColumnValues.length === 1) { @@ -471,9 +484,7 @@ export default { if (Array.isArray(addedTag.response)) { addedTag.response.forEach(tag => { - - const all = this.getAllRows(table.getRows()); - const targetRow = all.find(row => row.getData().lehreinheit_id === tag.lehreinheit_id); + const targetRow = this.allRows.find(row => row.getData().lehreinheit_id === tag.lehreinheit_id); if (targetRow) { const rowData = targetRow.getData(); @@ -496,10 +507,7 @@ export default { }); }, deletedTag(deletedTag) { - const table = this.$refs.table.tabulator; - const all = this.getAllRows(table.getRows()); - - const targetRow = all.find(row => { + const targetRow = this.allRows.find(row => { const rowData = row.getData(); let tags = []; @@ -532,10 +540,7 @@ export default { }, updatedTag(updatedTag) { - const table = this.$refs.table.tabulator; - const all = this.getAllRows(table.getRows()); - - const targetRow = all.find(row => { + const targetRow = this.allRows.find(row => { const rowData = row.getData(); let tags = []; @@ -587,9 +592,8 @@ export default { async getExpandedRows() { this.expanded = []; - let rows = this.$refs.table.tabulator.getRows(); - let allRows = this.getAllRows(rows); - allRows.forEach(row => { + + this.allRows.forEach(row => { if (row.getTreeChildren().length > 0 && row.isTreeExpanded()) { this.expanded.push(row.getData().uniqueindex); @@ -597,9 +601,9 @@ export default { }); }, reexpandRows() { - const all = this.getAllRows(this.$refs.table.tabulator.getRows()); + this.allRows = this.getAllRows(this.$refs.table.tabulator.getRows()); - const matchingRows = all.filter(row => + const matchingRows = this.allRows.filter(row => this.expanded.includes(row.getData().uniqueindex) ); @@ -637,6 +641,39 @@ export default { }); return result; }, + resetTree() { + this.allRows.forEach(row => { + row._row.modules.dataTree.open = false; + }); + + let rootRows = this.$refs.table.tabulator.getRows(true); + var lastRow = rootRows[rootRows.length - 1]; + lastRow.treeCollapse(true) + + this.currentTreeLevel = 0; + }, + expandTree() + { + this.currentTreeLevel = (this.currentTreeLevel || 0) + 1; + + let lastMatchingRow = null; + + this.allRows.forEach(row => { + const level = row._row.modules.dataTree?.index ?? 0; + + if (level === this.currentTreeLevel - 1 ) + { + row._row.modules.dataTree.open = true; + lastMatchingRow = row; + } + }); + + if (lastMatchingRow) + { + lastMatchingRow.treeExpand(); + } + this.$refs.table.tabulator.redraw(); + }, }, template: ` + + - + +
+
{{$p.t('profilUpdate','nachweisdokumente')}}
+ +
`, }; From 7e40e34212f30191121dec324eff8f1e83ca9655 Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Tue, 16 Sep 2025 17:40:27 +0200 Subject: [PATCH 061/112] remove DMS_PATH from original user filename --- application/libraries/DmsLib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/libraries/DmsLib.php b/application/libraries/DmsLib.php index 774ebdc79..c6c16a866 100644 --- a/application/libraries/DmsLib.php +++ b/application/libraries/DmsLib.php @@ -670,7 +670,7 @@ class DmsLib $fileObj = new stdClass(); $fileObj->filename = getData($result)[0]->filename; $fileObj->file = DMS_PATH.getData($result)[0]->filename; - $fileObj->name = DMS_PATH.getData($result)[0]->name; // original user filename + $fileObj->name = getData($result)[0]->name; // original user filename $fileObj->mimetype = getData($result)[0]->mimetype; return success($fileObj); From dff8223d3e8c593c03c0e7daf31804b93f4eaf71 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Wed, 17 Sep 2025 11:04:10 +0200 Subject: [PATCH 062/112] sortierung der tags --- public/js/components/LVVerwaltung/Setup/Table.js | 11 +++++++++++ public/js/components/filter/Filter.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js index 5360c3525..fa288f8d7 100644 --- a/public/js/components/LVVerwaltung/Setup/Table.js +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -233,6 +233,17 @@ export default { const renderTags = () => { container.innerHTML = ''; parsedTags = parsedTags.filter(item => item !== null); + + parsedTags.sort((a, b) => { + let adone = a.done ? 1 : 0; + let bbone = b.done ? 1 : 0; + + if (adone !== bbone) + { + return adone - bbone; + } + return b.id - a.id; + }); const tagsToShow = rowData._tagExpanded ? parsedTags : parsedTags.slice(0, maxVisibleTags); tagsToShow.forEach(tag => { diff --git a/public/js/components/filter/Filter.js b/public/js/components/filter/Filter.js index cefa99404..9a294d2d4 100644 --- a/public/js/components/filter/Filter.js +++ b/public/js/components/filter/Filter.js @@ -666,7 +666,7 @@ export const CoreFilterCmpt = { {{ selectedData.length }} ausgewählt - Mit {{ selectedData.length }} ausgewählten: + Mit {{ selectedData.length }} ausgewählten: From bbfaf447f569afa7ca8c9d54648cbcf8e09b0b50 Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Wed, 17 Sep 2025 12:13:15 +0200 Subject: [PATCH 063/112] remove dependency to library from pv extension and do not delete salary history when gb is deleted since foreign key is configured on delete set null --- .../libraries/vertragsbestandteil/GehaltsbestandteilLib.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/application/libraries/vertragsbestandteil/GehaltsbestandteilLib.php b/application/libraries/vertragsbestandteil/GehaltsbestandteilLib.php index 1aaafa471..c1238c13d 100644 --- a/application/libraries/vertragsbestandteil/GehaltsbestandteilLib.php +++ b/application/libraries/vertragsbestandteil/GehaltsbestandteilLib.php @@ -24,7 +24,6 @@ class GehaltsbestandteilLib $this->CI = get_instance(); $this->CI->load->model('vertragsbestandteil/Gehaltsbestandteil_model', 'GehaltsbestandteilModel'); - $this->CI->load->library('extensions/FHC-Core-Personalverwaltung/abrechnung/GehaltsLib'); $this->GehaltsbestandteilModel = $this->CI->GehaltsbestandteilModel; } @@ -121,10 +120,6 @@ class GehaltsbestandteilLib { $this->setUIDtoPGSQL(); - // delete Gehaltsabrechnung - $ret = $this->CI->gehaltslib->deleteAbrechnung($gehaltsbestandteil); - - // $ret = $this->GehaltsbestandteilModel->delete($gehaltsbestandteil->getGehaltsbestandteil_id()); if (isError($ret)) From 57531d956d1a0ef18e98ec4a50a4d5c1c3ed55a6 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Thu, 18 Sep 2025 13:18:44 +0200 Subject: [PATCH 064/112] gruppen in eigenen tab verschoben styling phrases --- .../api/frontend/v1/lv/Lehreinheit.php | 4 +- .../controllers/api/frontend/v1/lv/Lektor.php | 33 +++- .../controllers/api/frontend/v1/lv/Setup.php | 5 + application/libraries/LektorLib.php | 14 +- public/css/Lvverwaltung.css | 10 ++ public/css/Tabulator6.css | 154 +++++++++++++++- .../components/LVVerwaltung/Details/Form.js | 166 ++++++++++-------- .../LVVerwaltung/Details/Gruppen.js | 4 +- .../components/LVVerwaltung/LVVerwaltung.js | 4 +- .../components/LVVerwaltung/Lektor/Daten.js | 19 +- .../components/LVVerwaltung/Lektor/Table.js | 2 +- .../components/LVVerwaltung/Lektor/Vertrag.js | 9 +- .../js/components/LVVerwaltung/Setup/Table.js | 22 +-- .../js/components/LVVerwaltung/Setup/Tabs.js | 1 - .../components/LVVerwaltung/Tabs/Details.js | 19 +- .../components/LVVerwaltung/Tabs/Gruppen.js | 39 ++++ system/phrasesupdate.php | 40 +++++ 17 files changed, 418 insertions(+), 127 deletions(-) create mode 100644 public/js/components/LVVerwaltung/Tabs/Gruppen.js diff --git a/application/controllers/api/frontend/v1/lv/Lehreinheit.php b/application/controllers/api/frontend/v1/lv/Lehreinheit.php index b851f8c22..958007901 100644 --- a/application/controllers/api/frontend/v1/lv/Lehreinheit.php +++ b/application/controllers/api/frontend/v1/lv/Lehreinheit.php @@ -350,7 +350,7 @@ class Lehreinheit extends FHCAPI_Controller $this->form_validation->set_rules($field, 'Start KW', 'integer|greater_than[0]|less_than_equal_to[53]'); break; case 'gewicht': - $this->form_validation->set_rules($field, 'Gewicht', 'numeric'); + $this->form_validation->set_rules($field, 'Gewicht', 'numeric|greater_than_equal_to[0]'); break; case 'raumtyp': $this->form_validation->set_rules($field, 'Raumtyp', 'required|max_length[16]'); @@ -365,7 +365,7 @@ class Lehreinheit extends FHCAPI_Controller $this->form_validation->set_rules($field, 'LVNR', 'integer'); break; case 'unr': - $this->form_validation->set_rules($field, 'UNR', 'integer'); + $this->form_validation->set_rules($field, 'UNR', 'integer|greater_than_equal_to[0]'); break; case 'lehre': $this->form_validation->set_rules($field, 'Lehre', 'trim'); diff --git a/application/controllers/api/frontend/v1/lv/Lektor.php b/application/controllers/api/frontend/v1/lv/Lektor.php index 4a244c1a1..68bec1bc4 100644 --- a/application/controllers/api/frontend/v1/lv/Lektor.php +++ b/application/controllers/api/frontend/v1/lv/Lektor.php @@ -107,7 +107,8 @@ class Lektor extends FHCAPI_Controller $this->form_validation->set_rules($field, 'Planstunden', 'integer|greater_than_equal_to[0]'); break; case 'stundensatz': - $this->form_validation->set_rules($field, 'Stundensatz', 'numeric|greater_than_equal_to[0]'); + $formData['stundensatz'] = str_replace(',', '.', $formData['stundensatz']); + $this->form_validation->set_rules($field, 'Stundensatz', 'callback__check_stundensatz'); break; case 'faktor': $this->form_validation->set_rules($field, 'Faktor', 'numeric|greater_than_equal_to[0]'); @@ -119,6 +120,7 @@ class Lektor extends FHCAPI_Controller $this->form_validation->set_rules($field, 'Bis Melden', 'trim'); break; case 'semesterstunden': + $formData['semesterstunden'] = str_replace(',', '.', $formData['semesterstunden']); $this->form_validation->set_rules($field, 'Semesterstunden', 'callback__check_semesterstunden'); break; case 'mitarbeiter_uid': @@ -129,7 +131,7 @@ class Lektor extends FHCAPI_Controller } if (!$this->form_validation->run()) { - $this->terminateWithError($this->form_validation->error_array()); + $this->terminateWithValidationErrors($this->form_validation->error_array()); } if (isset($formData['semesterstunden']) && (!is_numeric($formData['semesterstunden']) || $formData['semesterstunden'] === '')) @@ -145,9 +147,26 @@ class Lektor extends FHCAPI_Controller $result = $this->_ci->lektorlib->updateLektorFromLehreinheit($lehreinheit_id, $mitarbeiter_uid, $formData); if (isError($result)) $this->terminateWithError(getError($result)); - $this->terminateWithSuccess("Erfolgreich geupdated"); + $this->terminateWithSuccess($result); } + public function _check_stundensatz($value) + { + $value = str_replace(',', '.', $value); + + if (!is_numeric($value)) + { + $this->form_validation->set_message('_check_decimal', 'Das Feld {field} muss eine Zahl sein.'); + return false; + } + + if ($value < 0 || $value >= 10000) { + $this->form_validation->set_message('_check_decimal', 'Das Feld {field} muss zwischen 0 und 10000 liegen.'); + return false; + } + + return true; + } public function _check_semesterstunden($value) { if ($value === null || $value === '') { @@ -171,6 +190,14 @@ class Lektor extends FHCAPI_Controller ); return false; } + if ($value > 999.99) + { + $this->form_validation->set_message( + '_check_semesterstunden', + 'Das Feld {field} darf maximal 999,99 betragen.' + ); + return false; + } return true; } diff --git a/application/controllers/api/frontend/v1/lv/Setup.php b/application/controllers/api/frontend/v1/lv/Setup.php index cf73697a7..a2c167dd6 100644 --- a/application/controllers/api/frontend/v1/lv/Setup.php +++ b/application/controllers/api/frontend/v1/lv/Setup.php @@ -50,6 +50,11 @@ class Setup extends FHCAPI_Controller 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Details.js', 'config' => [] ); + $tabs['gruppen'] = array ( + 'title' => 'Gruppen', + 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Gruppen.js', + 'config' => [] + ); $tabs['lektor'] = array ( 'title' => 'LektorInnenzuteilung', 'component' => APP_ROOT . 'public/js/components/LVVerwaltung/Tabs/Lektor.js', diff --git a/application/libraries/LektorLib.php b/application/libraries/LektorLib.php index 44c71cdaa..e06e2b728 100644 --- a/application/libraries/LektorLib.php +++ b/application/libraries/LektorLib.php @@ -176,11 +176,11 @@ class LektorLib if (!$echter_dv && (!$this->_ci->permissionlib->isBerechtigt('admin'))) { if (!$this->LehrauftragAufFirma(isset($formData['mitarbeiter_uid']) ? $formData['mitarbeiter_uid'] : $mitarbeiter_uid)) - return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\n Daten wurden NICHT gespeichert!\n\n"); + return error("ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden NICHT gespeichert!\n\n"); } else { - $warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\n Daten wurden gespeichert!\n\n"; + $warning .= "ACHTUNG: Die maximal erlaubte Semesterstundenanzahl des Lektors von $summe Stunden ($stundengrenze->stunden) wurde ueberschritten!\nDaten wurden gespeichert!\n\n"; } $stunden_limit_result = $this->getStundenInstitut($mitarbeiter_uid, $lehreinheit->studiensemester_kurzbz, $oe_array); @@ -190,7 +190,7 @@ class LektorLib $stunden_limit_array = getData($stunden_limit_result); foreach ($stunden_limit_array as $stunden_limit) { - $warning .= $stunden_limit->summe . ' Stunden' . $stunden_limit->bezeichnung; + $warning .= $stunden_limit->summe . ' Stunden ' . $stunden_limit->bezeichnung . "\n"; } } } @@ -206,7 +206,7 @@ class LektorLib $benutzer_aktiv = getData($benutzer_result)[0]->aktiv; if (!$benutzer_aktiv) - $warning .= "Achtung: Der/Die Benutzer*in ist inaktiv!\nBitte informieren Sie die Personalbteilung.\n\nDaten wurden gespeichert.\n\n"; + $warning .= "Achtung: Der/Die Benutzer*in ist inaktiv!\nBitte informieren Sie die Personalbteilung.\nDaten wurden gespeichert.\n\n"; $updatableFields = array( 'semesterstunden', @@ -236,9 +236,9 @@ class LektorLib if (isError($result)) return $result; - if ($warning !== '') return error($warning); + if ($warning !== '') return success(['warning' => $warning]); - return success('Successfully updated Lehreinheit'); + return success('Erfolgreich geupdated'); } private function getMaxStunden($mitarbeiter_uid, $studiensemester_kurzbz, $studiengang_kz, $echter_dv) @@ -280,7 +280,7 @@ class LektorLib foreach ($stunden_limit_array as $stunden_limit) { - $error .= $stunden_limit->summe . ' Stunden' . $stunden_limit->bezeichnung; + $error .= $stunden_limit->summe . ' Stunden ' . $stunden_limit->bezeichnung . "\n"; } } return error($error); diff --git a/public/css/Lvverwaltung.css b/public/css/Lvverwaltung.css index 38d74def4..6e0f4c760 100644 --- a/public/css/Lvverwaltung.css +++ b/public/css/Lvverwaltung.css @@ -28,3 +28,13 @@ textarea[name="anmerkung"] { content: '\f073'; color: #f3c541; } + + +.modal-dialog.modal-xxl { + max-width: 95% !important; +} + +.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu:after +{ + border-color: black; +} diff --git a/public/css/Tabulator6.css b/public/css/Tabulator6.css index 8be726544..7a66dd2f6 100644 --- a/public/css/Tabulator6.css +++ b/public/css/Tabulator6.css @@ -1 +1,153 @@ -@import '../../vendor/olifolkerd/tabulator6/dist/css/tabulator_simple.min.css'; \ No newline at end of file +@import '../../vendor/olifolkerd/tabulator6/dist/css/tabulator_simple.min.css'; +.tabulator-row { + border-bottom: none; +} +.tabulator-row .tabulator-frozen, +.tabulator-row .tabulator-cell { + border-bottom: 1px solid #dee2e6; +} +.tabulator-row.tabulator-row-even { + background-color: transparent; +} +.tabulator-headers .tabulator-frozen, +.tabulator-row.tabulator-row-odd .tabulator-frozen, +.tabulator-row.tabulator-row-odd .tabulator-cell { + background-color: #fff; +} +.tabulator-row.tabulator-row-even .tabulator-frozen, +.tabulator-row.tabulator-row-even .tabulator-cell { + background-color: #f2f2f2; +} +.tabulator-row.tabulator-selectable:hover .tabulator-frozen, +.tabulator-row.tabulator-selectable:hover .tabulator-cell { + background-color: #ececec; +} +.tabulator-row.tabulator-selected .tabulator-frozen, +.tabulator-row.tabulator-selected .tabulator-cell { + background-color: #9abcea; +} +.tabulator-row.tabulator-selected:hover .tabulator-frozen, +.tabulator-row.tabulator-selected:hover .tabulator-cell { + background-color: #769bcc; +} +.tabulator .tabulator-col-resize-handle:last-of-type { + z-index: 999999; +} + +/* classes for rows that are not selectable in the tabulator, except for rows that are used for calculation */ +.tabulator-row.tabulator-unselectable:not(.tabulator-calcs) { + color: #adb5bd !important; + pointer-events: none !important; +} + +.tabulator-row.tabulator-unselectable a { + pointer-events: auto !important; +} + +/* using bootstrap background classes to style the background color of tabulator rows */ +/* bg-warning */ +/* odd-rows */ +.tabulator-headers .tabulator-frozen.bg-warning, +.tabulator-row.tabulator-row-odd .tabulator-frozen.bg-warning, +.tabulator-row.tabulator-row-odd .tabulator-cell.bg-warning { + background-color: #fcf8e3; + +} +/* even-rows */ +.tabulator-headers .tabulator-frozen.bg-warning, +.tabulator-row.tabulator-row-even .tabulator-frozen.bg-warning, +.tabulator-row.tabulator-row-even .tabulator-cell.bg-warning { + background-color: #fcf8e3; + +} + +/* bg-success */ +/* odd-rows */ +.tabulator-headers .tabulator-frozen.bg-success, +.tabulator-row.tabulator-row-odd .tabulator-frozen.bg-success, +.tabulator-row.tabulator-row-odd .tabulator-cell.bg-success { + background-color: #dff0d8; + +} +/* even-rows */ +.tabulator-headers .tabulator-frozen.bg-success, +.tabulator-row.tabulator-row-even .tabulator-frozen.bg-success, +.tabulator-row.tabulator-row-even .tabulator-cell.bg-success { + background-color: #dff0d8; + +} + +/* bg-info */ +/* odd-rows */ +.tabulator-headers .tabulator-frozen.bg-info, +.tabulator-row.tabulator-row-odd .tabulator-frozen.bg-info, +.tabulator-row.tabulator-row-odd .tabulator-cell.bg-info { + background-color: #d9edf7; + +} +/* even-rows */ +.tabulator-headers .tabulator-frozen.bg-info, +.tabulator-row.tabulator-row-even .tabulator-frozen.bg-info, +.tabulator-row.tabulator-row-even .tabulator-cell.bg-info { + background-color: #d9edf7; + +} + +/* special bootstrap5 styling for tableWidget and their accordion-item ::after content */ +.accordion-button::after{ + content:none !important; +} + + +.tabulator { + font-size: 1rem; +} + +.tabulator-initialfontsize .tabulator { + font-size: 14px; +} + +.tabulator-row.tabulator-unselectable .tabulator-cell { + pointer-events: all; +} + +.tabulator-tooltip { + color: #fff; + background-color: #000; +} + +.tabulator-row.tabulator-unselectable:not(.tabulator-calcs) { + color: #777 !important; +} + +.tabulator-cell .btn { + padding: 0 .375rem; + font-size: calc(1rem - 2px / 1.5); /* substract border (2 x 1px) modified by the line-height (1.5) */ + border-radius: .2rem; + vertical-align: baseline; +} + +.tabulator-row.tabulator-selectable:focus { + box-shadow: 0 0 0 .24rem rgba(13,110,253,.25); + z-index: 1; + outline: 0; +} + +.btn-select-col-selected +{ + background-color: #e6e6e6; +} + +.accordion-item-dark, .accordion-item-dark:focus{ + background-color:#CED4DA !important; + border-color:#ADB5BD !important; + box-shadow: none !important; +} + +/** + * Make keyboard-focused list items look like the mouse-hovered list items + */ +.tabulator-edit-list .tabulator-edit-list-item.focused { + color: #fff; + background: #1d68cd; +} diff --git a/public/js/components/LVVerwaltung/Details/Form.js b/public/js/components/LVVerwaltung/Details/Form.js index eed65f7ad..5908512d7 100644 --- a/public/js/components/LVVerwaltung/Details/Form.js +++ b/public/js/components/LVVerwaltung/Details/Form.js @@ -38,33 +38,6 @@ export default { }, template: `
-
- - - -
-
- -
+ - - - -
- -
- - - -
@@ -179,30 +112,109 @@ export default { {{ raumtyp.raumtyp_kurzbz }} {{ raumtyp.beschreibung }} + + +
+ + +
+ + + + + + + + + +
+ +
+ +
+ +
+ +
+ + +
` diff --git a/public/js/components/LVVerwaltung/Details/Gruppen.js b/public/js/components/LVVerwaltung/Details/Gruppen.js index 219b956d8..a6f9df005 100644 --- a/public/js/components/LVVerwaltung/Details/Gruppen.js +++ b/public/js/components/LVVerwaltung/Details/Gruppen.js @@ -50,7 +50,7 @@ export default{ let button = document.createElement('button'); container.className = "d-flex gap-1"; - button.className = 'btn btn-outline-secondary btn-action'; + button.className = 'btn btn-outline-secondary'; button.innerHTML = ''; button.title = this.$p.t('ui', 'loeschen'); button.addEventListener('click', (event) => { @@ -63,7 +63,7 @@ export default{ { button = document.createElement('button'); container.className = "d-flex gap-2"; - button.className = 'btn btn-outline-secondary btn-action'; + button.className = 'btn btn-outline-secondary'; button.innerHTML = ''; button.title = this.$p.t('lehre', 'auslvplanentfernen'); button.disabled = !cell.getData().verplant; diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index e9d132848..a1ff28a2e 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -88,10 +88,12 @@ export default { }, selectedStudiengang: '', searchbaroptions: { + origin: 'lvverwaltung', cssclass: "position-relative", calcheightonly: true, types: [ - "mitarbeiter" + "mitarbeiter", + "mitarbeiter_ohne_zuordnung" ], actions: { employee: { diff --git a/public/js/components/LVVerwaltung/Lektor/Daten.js b/public/js/components/LVVerwaltung/Lektor/Daten.js index 0f6b9e0f7..d4c6aa5e3 100644 --- a/public/js/components/LVVerwaltung/Lektor/Daten.js +++ b/public/js/components/LVVerwaltung/Lektor/Daten.js @@ -121,9 +121,9 @@ export default{ } this.$refs.form.call(ApiLektor.update(updatedData)) .then(result => { - let error = result.data?.error; - if (error) - this.$fhcAlert.alertWarning(error) + let warning = result.data?.retval?.warning; + if (warning) + this.$fhcAlert.alertWarning(warning) this.original = {...this.data}; if (this.changed.mitarbeiter_uid) @@ -192,6 +192,7 @@ export default{ container-class="col-3" dropdown @complete="searchLektor" + name="lektorautocomplete" > { event.stopPropagation(); this.deleteLVPlan(cell.getData().mitarbeiter_uid, cell.getData().lehreinheit_id) diff --git a/public/js/components/LVVerwaltung/Lektor/Vertrag.js b/public/js/components/LVVerwaltung/Lektor/Vertrag.js index f36fad8e0..bdb156546 100644 --- a/public/js/components/LVVerwaltung/Lektor/Vertrag.js +++ b/public/js/components/LVVerwaltung/Lektor/Vertrag.js @@ -88,8 +88,14 @@ export default{ .catch(this.$fhcAlert.handleSystemError); }, - cancelVertrag() + async cancelVertrag() { + + if (await this.$fhcAlert.confirm({ + message: this.$p.t('lehre', 'vertragConfirm'), + acceptLabel: this.$p.t('ui', 'ja').charAt(0).toUpperCase() + this.$p.t('ui', 'ja').slice(1), + acceptClass: 'btn btn-danger'}) === false) + return; let needUpdate = { vertrag_id: this.data.vertrag.vertrag_id, mitarbeiter_uid: this.mitarbeiter_uid, @@ -126,6 +132,7 @@ export default{ type="button" class="btn btn-outline-secondary w-100" @click="cancelVertrag" + :title="$p.t('lehre', 'cancelvertrag')" > diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js index fa288f8d7..2f37e4207 100644 --- a/public/js/components/LVVerwaltung/Setup/Table.js +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -670,19 +670,19 @@ export default {
- - + + - + - - + + ` }; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Setup/Tabs.js b/public/js/components/LVVerwaltung/Setup/Tabs.js index af14fbf32..62c5bbc31 100644 --- a/public/js/components/LVVerwaltung/Setup/Tabs.js +++ b/public/js/components/LVVerwaltung/Setup/Tabs.js @@ -50,7 +50,6 @@ export default { :modelValue="lv[0]" :config="configLVTabs" :default="$route.params.tab" - style="flex: 1 1 0%; height: 0%" @changed="reload" /> diff --git a/public/js/components/LVVerwaltung/Tabs/Details.js b/public/js/components/LVVerwaltung/Tabs/Details.js index ce0102177..cb3275d23 100644 --- a/public/js/components/LVVerwaltung/Tabs/Details.js +++ b/public/js/components/LVVerwaltung/Tabs/Details.js @@ -111,23 +111,14 @@ export default {
- {{this.$p.t('lehre', 'lehreinheit')}} +
+ {{ this.$p.t('lehre', 'lehreinheit') }} + +
-
-
-
- {{this.$p.t('lehre', 'gruppen')}} - -
-
- {{this.$p.t('lehre', 'assignedPersons')}} - -
-
- -
` + ` }; \ No newline at end of file diff --git a/public/js/components/LVVerwaltung/Tabs/Gruppen.js b/public/js/components/LVVerwaltung/Tabs/Gruppen.js new file mode 100644 index 000000000..2879c1959 --- /dev/null +++ b/public/js/components/LVVerwaltung/Tabs/Gruppen.js @@ -0,0 +1,39 @@ +import GruppenTable from '../Details/Gruppen.js'; +import GruppenDirektTable from '../Details/Direktinskription.js'; + +export default { + name: "LVTabGruppen", + components: { + GruppenTable, + GruppenDirektTable, + }, + props: { + modelValue: Object, + config: { + type: Object, + default: {} + }, + }, + inject: { + dropdowns: { + from: 'dropdowns' + } + }, + + template: ` + +
+
+
+ {{this.$p.t('lehre', 'gruppen')}} + +
+
+ {{this.$p.t('lehre', 'assignedPersons')}} + +
+
+ +
+ ` +}; \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 0927ea309..6a4c98fd9 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -2984,6 +2984,46 @@ $phrases = array( ) ) ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'cancelvertrag', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Vertrag stornieren', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Cancel Contract', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'lehre', + 'phrase' => 'vertragConfirm', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Möchten Sie den Vertrag wirklich stornieren?', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Do you really want to cancel the contract?', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'core', 'category' => 'lehre', From 41dbd83bdb39cc1035e9a5bcd7d88b7910ffab19 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Thu, 18 Sep 2025 15:27:04 +0200 Subject: [PATCH 065/112] phrases tags als default entfernt master gemerged --- application/config/lvverwaltung.php | 14 ++--- system/phrasesupdate.php | 80 +++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+), 7 deletions(-) diff --git a/application/config/lvverwaltung.php b/application/config/lvverwaltung.php index 466f5c7ab..4fe09bff3 100644 --- a/application/config/lvverwaltung.php +++ b/application/config/lvverwaltung.php @@ -1,11 +1,11 @@ ['readonly' => false], - 'hinweis' => ['readonly' => false], - 'hinweis_assistenz' => ['readonly' => false], - 'finished_stg' => ['readonly' => false], +/*It defines which tags are available in LVVerwaltung and whether they are editable - 'finished_kf' => ['readonly' => true], - 'inwork_kf' => ['readonly' => true], +$config['lvverwaltung_tags'] = [ + 'tag_1' => ['readonly' => false], + 'tag_1' => ['readonly' => true] ]; +*/ + +$config['lvverwaltung_tags'] = []; \ No newline at end of file diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 437e76c1e..008ad8a8d 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -43278,6 +43278,86 @@ array( ) ) ), + array( + 'app' => 'pep', + 'category' => 'ui', + 'phrase' => 'lehrauftrag', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Lehrauftrag', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Teaching lectureship', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'pep', + 'category' => 'ui', + 'phrase' => 'kategorie', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Kategorie', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Category', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'pep', + 'category' => 'ui', + 'phrase' => 'project', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Kategorie', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Category', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'pep', + 'category' => 'ui', + 'phrase' => 'lventwicklung', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'LV-Weiterentwicklung', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Course Development', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'pep', 'category' => 'ui', From 0577f3f8b96a31fbd7f087c1586a2de717d64b30 Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Thu, 18 Sep 2025 18:46:11 +0200 Subject: [PATCH 066/112] Cis4 Profile only show current userfunctions with description from tbl_funktion --- application/libraries/ProfilLib.php | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/application/libraries/ProfilLib.php b/application/libraries/ProfilLib.php index 2a130d263..e86a343e7 100644 --- a/application/libraries/ProfilLib.php +++ b/application/libraries/ProfilLib.php @@ -303,10 +303,22 @@ class ProfilLib{ private function getBenutzerFunktion($uid) { $this->ci->load->model("person/Benutzerfunktion_model","BenutzerfunktionModel"); - $this->ci->BenutzerfunktionModel->addSelect(["tbl_benutzerfunktion.bezeichnung as Bezeichnung", "tbl_organisationseinheit.bezeichnung as Organisationseinheit", "datum_von as Gültig_von", "datum_bis as Gültig_bis", "wochenstunden as Wochenstunden"]); + $this->ci->BenutzerfunktionModel->addSelect([ + "tbl_funktion.beschreibung as Bezeichnung", + "tbl_organisationseinheit.bezeichnung as Organisationseinheit", + "datum_von as Gültig_von", + "datum_bis as Gültig_bis", + "COALESCE(wochenstunden, '0'::numeric(5,2)) AS \"Wochenstunden\"" + ]); + $this->ci->BenutzerfunktionModel->addJoin("tbl_funktion", "funktion_kurzbz"); $this->ci->BenutzerfunktionModel->addJoin("tbl_organisationseinheit", "oe_kurzbz"); - $benutzer_funktion_res = $this->ci->BenutzerfunktionModel->loadWhere(array('uid' => $uid)); + $benutzer_funktion_res = $this->ci->BenutzerfunktionModel->loadWhere( + array( + 'uid' => $uid, + 'NOW()::date BETWEEN COALESCE(datum_von, \'1970-01-01\'::date) AND COALESCE(datum_bis, \'2170-12-01\'::date)' => null + ) + ); if(isError($benutzer_funktion_res)){ return error(getData($benutzer_funktion_res)); } From 41143a6dfc66bf34bb6b454ae2c6e059de015fc8 Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Fri, 19 Sep 2025 10:58:53 +0200 Subject: [PATCH 067/112] profile functions use tbl_benutzerfunktion.beschreibung in column description, format date columns in profile tabulators, fix vuejs dev version warnings --- application/libraries/ProfilLib.php | 2 +- .../Cis/Profil/MitarbeiterProfil.js | 35 ++++++++++++++----- .../Cis/Profil/MitarbeiterViewProfil.js | 27 +++++++++++--- .../ProfilComponents/RoleInformation.js | 19 ++++++++-- .../EditProfilComponents/ImageUpload.js | 4 +-- .../js/components/Cis/Profil/StudentProfil.js | 21 ++++++++--- 6 files changed, 85 insertions(+), 23 deletions(-) diff --git a/application/libraries/ProfilLib.php b/application/libraries/ProfilLib.php index e86a343e7..50b8bc264 100644 --- a/application/libraries/ProfilLib.php +++ b/application/libraries/ProfilLib.php @@ -304,7 +304,7 @@ class ProfilLib{ { $this->ci->load->model("person/Benutzerfunktion_model","BenutzerfunktionModel"); $this->ci->BenutzerfunktionModel->addSelect([ - "tbl_funktion.beschreibung as Bezeichnung", + "CASE WHEN (tbl_benutzerfunktion.bezeichnung IS NOT NULL AND tbl_benutzerfunktion.bezeichnung <> '' AND tbl_benutzerfunktion.bezeichnung <> tbl_funktion.beschreibung) THEN tbl_funktion.beschreibung || ' - ' || tbl_benutzerfunktion.bezeichnung ELSE tbl_funktion.beschreibung END as \"Bezeichnung\"", "tbl_organisationseinheit.bezeichnung as Organisationseinheit", "datum_von as Gültig_von", "datum_bis as Gültig_bis", diff --git a/public/js/components/Cis/Profil/MitarbeiterProfil.js b/public/js/components/Cis/Profil/MitarbeiterProfil.js index 223b5c2b6..bf3c4cf49 100644 --- a/public/js/components/Cis/Profil/MitarbeiterProfil.js +++ b/public/js/components/Cis/Profil/MitarbeiterProfil.js @@ -11,6 +11,7 @@ import RoleInformation from "./ProfilComponents/RoleInformation.js"; import ProfilInformation from "./ProfilComponents/ProfilInformation.js"; import ApiProfilUpdate from '../../../api/factory/profilUpdate.js'; +import { dateFilter } from '../../../tabulator/filters/Dates.js'; export default { components: { @@ -40,7 +41,7 @@ export default { persistence: { columns: false }, - height: 300, + minHeight: 300, layout: "fitColumns", responsiveLayout: "collapse", responsiveLayoutCollapseUseFormatters: false, @@ -74,18 +75,24 @@ export default { { title: Vue.computed(() => this.preloadedPhrasen.gueltigVonPhrase), field: "Gültig_von", - headerFilter: true, + headerFilterFunc: 'dates', + headerFilter: dateFilter, resizable: true, minWidth: 200, - visible: true + visible: true, + formatter:"datetime", + formatterParams: this.datetimeFormatterParams() }, { title: Vue.computed(() => this.preloadedPhrasen.gueltigBisPhrase), field: "Gültig_bis", - headerFilter: true, + headerFilterFunc: 'dates', + headerFilter: dateFilter, resizable: true, minWidth: 200, - visible: true + visible: true, + formatter:"datetime", + formatterParams: this.datetimeFormatterParams() }, { title: Vue.computed(() => this.preloadedPhrasen.wochenstundenPhrase), @@ -102,7 +109,7 @@ export default { persistence: { columns: false }, - height: 300, + minHeight: 300, layout: "fitColumns", responsiveLayout: "collapse", responsiveLayoutCollapseUseFormatters: false, @@ -138,9 +145,12 @@ export default { { title: Vue.computed(() => this.preloadedPhrasen.ausgabedatumPhrase), field: "Ausgegeben_am", - headerFilter: true, + headerFilterFunc: 'dates', + headerFilter: dateFilter, minWidth: 200, - visible: true + visible: true, + formatter:"datetime", + formatterParams: this.datetimeFormatterParams() }, ], } @@ -211,6 +221,15 @@ export default { setTableColumnTitles() { // reevaluates computed phrasen if(this.$refs.betriebsmittelTable) this.$refs.betriebsmittelTable.tabulator.setColumns(this.betriebsmittel_table_options.columns) if(this.$refs.funktionenTable) this.$refs.funktionenTable.tabulator.setColumns(this.funktionen_table_options.columns) + }, + datetimeFormatterParams: function() { + const params = { + inputFormat:"yyyy-MM-dd", + outputFormat:"dd.MM.yyyy", + invalidPlaceholder:"(invalid date)", + timezone:FHC_JS_DATA_STORAGE_OBJECT.timezone + }; + return params; } }, diff --git a/public/js/components/Cis/Profil/MitarbeiterViewProfil.js b/public/js/components/Cis/Profil/MitarbeiterViewProfil.js index c1ce4ead6..481714590 100644 --- a/public/js/components/Cis/Profil/MitarbeiterViewProfil.js +++ b/public/js/components/Cis/Profil/MitarbeiterViewProfil.js @@ -5,6 +5,8 @@ import RoleInformation from "./ProfilComponents/RoleInformation.js"; import ProfilEmails from "./ProfilComponents/ProfilEmails.js"; import ProfilInformation from "./ProfilComponents/ProfilInformation.js"; +import { dateFilter } from '../../../tabulator/filters/Dates.js'; + export default { components: { CoreFilterCmpt, @@ -24,7 +26,7 @@ export default { persistence: { columns: false }, - height: 300, + minHeight: 300, layout: "fitColumns", responsiveLayout: "collapse", responsiveLayoutCollapseUseFormatters: false, @@ -60,18 +62,24 @@ export default { { title: Vue.computed(() => this.$p.t('global/gueltigVon')), field: "Gültig_von", - headerFilter: true, + headerFilterFunc: 'dates', + headerFilter: dateFilter, resizable: true, minWidth: 200, - visible: true + visible: true, + formatter:"datetime", + formatterParams: this.datetimeFormatterParams() }, { title: Vue.computed(() => this.$p.t('global/gueltigBis')), field: "Gültig_bis", - headerFilter: true, + headerFilterFunc: 'dates', + headerFilter: dateFilter, resizable: true, minWidth: 200, - visible: true + visible: true, + formatter:"datetime", + formatterParams: this.datetimeFormatterParams() }, { title: Vue.computed(() => this.$p.t('profil/wochenstunden')), @@ -91,6 +99,15 @@ export default { funktionenTableBuilt: function () { this.$refs.funktionenTable.tabulator.setData(this.data.funktionen); }, + datetimeFormatterParams: function() { + const params = { + inputFormat:"yyyy-MM-dd", + outputFormat:"dd.MM.yyyy", + invalidPlaceholder:"(invalid date)", + timezone:FHC_JS_DATA_STORAGE_OBJECT.timezone + }; + return params; + } }, watch: { 'data.funktionen'(newVal) { diff --git a/public/js/components/Cis/Profil/ProfilComponents/RoleInformation.js b/public/js/components/Cis/Profil/ProfilComponents/RoleInformation.js index ae1a4f2b9..968fb2f83 100644 --- a/public/js/components/Cis/Profil/ProfilComponents/RoleInformation.js +++ b/public/js/components/Cis/Profil/ProfilComponents/RoleInformation.js @@ -10,21 +10,34 @@ export default { type: String, } }, - inject: [ - 'studiengang_kz', // inject info that should not be displayed - ], + inject: { + // inject info that should not be displayed + 'studiengang_kz': { + from: 'studiengang_kz', + default: false + }, + }, computed: { getLinkGruppeListe() { + if(this.studiengang_kz === false) { + return ''; + } return this.data.gruppe?.value && this.data.verband?.value && this.data.semester?.value ? FHC_JS_DATA_STORAGE_OBJECT.app_root + 'cis/private/stud_in_grp.php?kz='+this.studiengang_kz+'&sem=' + this.data.semester.value + '&verband=' + this.data.verband.value + '&grp=' + this.data.gruppe.value : '' }, getLinkVerbandListe() { + if(this.studiengang_kz === false) { + return ''; + } return this.data.verband?.value && this.data.semester?.value ? FHC_JS_DATA_STORAGE_OBJECT.app_root + 'cis/private/stud_in_grp.php?kz='+this.studiengang_kz+'&sem=' + this.data.semester.value + '&verband=' + this.data.verband.value : '' }, getLinkSemesterListe() { + if(this.studiengang_kz === false) { + return ''; + } return this.data.semester?.value ? FHC_JS_DATA_STORAGE_OBJECT.app_root + 'cis/private/stud_in_grp.php?kz='+this.studiengang_kz+'&sem=' + this.data.semester.value : '' } diff --git a/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/ImageUpload.js b/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/ImageUpload.js index 672b4ce4a..2d2efb0fe 100644 --- a/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/ImageUpload.js +++ b/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/ImageUpload.js @@ -16,7 +16,7 @@ export default { mixins: [BsModal], props: { titel: { - type: Object, + type: String, }, files: { type: Array, @@ -57,7 +57,7 @@ export default { }, template: /*html*/` - + diff --git a/public/js/components/Cis/Profil/StudentProfil.js b/public/js/components/Cis/Profil/StudentProfil.js index 8d46377d5..3f8e8380d 100644 --- a/public/js/components/Cis/Profil/StudentProfil.js +++ b/public/js/components/Cis/Profil/StudentProfil.js @@ -11,6 +11,7 @@ import FetchProfilUpdates from "./ProfilComponents/FetchProfilUpdates.js"; import EditProfil from "./ProfilModal/EditProfil.js"; import ApiProfilUpdate from '../../../api/factory/profilUpdate.js'; +import { dateFilter } from '../../../tabulator/filters/Dates.js'; export default { components: { @@ -39,7 +40,7 @@ export default { persistence: { columns: false }, - height: 200, + minHeight: 200, layout: "fitColumns", columns: [{ title: Vue.computed(() => this.preloadedPhrasen.zutrittsGruppenPhrase), @@ -51,7 +52,7 @@ export default { persistence: { columns: false }, - height: 300, + minHeight: 300, layout: "fitColumns", responsiveLayout: "collapse", responsiveLayoutCollapseUseFormatters: false, @@ -85,9 +86,12 @@ export default { { title: Vue.computed(() =>this.preloadedPhrasen.ausgabedatum) , field: "Ausgegeben_am", - headerFilter: true, + headerFilterFunc: 'dates', + headerFilter: dateFilter, minWidth: 200, - visible: true + visible: true, + formatter:"datetime", + formatterParams: this.datetimeFormatterParams() }, ], }, @@ -160,6 +164,15 @@ export default { this.$refs.editModal.show(); }); }, + datetimeFormatterParams: function() { + const params = { + inputFormat:"yyyy-MM-dd", + outputFormat:"dd.MM.yyyy", + invalidPlaceholder:"(invalid date)", + timezone:FHC_JS_DATA_STORAGE_OBJECT.timezone + }; + return params; + } }, computed: { From 3f5801f6ed92f8861d8f39ff89a213fdbccb26b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20=C3=96sterreicher?= Date: Mon, 22 Sep 2025 09:26:13 +0200 Subject: [PATCH 068/112] =?UTF-8?q?Men=C3=BCpunkt=20f=C3=BCr=20LV-Verwaltu?= =?UTF-8?q?ng=20im=20Vilesci=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/config/navigation.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/application/config/navigation.php b/application/config/navigation.php index 5cbb6512c..11fd1a3a6 100644 --- a/application/config/navigation.php +++ b/application/config/navigation.php @@ -64,7 +64,7 @@ $config['navigation_header'] = array( 'lehrveranstaltungen' => array( 'link' => site_url('lehre/lvplanung/LvTemplateUebersicht'), 'icon' => '', - 'description' => 'Lehrveranstaltungen', + 'description' => 'Lehrveranstaltungen Templates', 'sort' => 15 ), 'reihungstest' => array( @@ -81,6 +81,16 @@ $config['navigation_header'] = array( 'sort' => 30, 'requiredPermissions' => 'infocenter:r' ), + 'lvverwaltung' => array( + 'link' => site_url('LVVerwaltung'), + 'icon' => '', + 'description' => 'LV Verwaltung', + 'requiredPermissions' => array( + 'admin:r', + 'assistenz:r' + ), + 'sort' => 35 + ), 'lehrauftrag' => array( 'link' => site_url('lehre/lehrauftrag/Lehrauftrag/Dashboard'), 'description' => 'Lehrauftrag', From ef56af633790177d4010a78e82e5abed9bcb61ff Mon Sep 17 00:00:00 2001 From: ma0048 Date: Mon, 22 Sep 2025 09:40:37 +0200 Subject: [PATCH 069/112] lv teil hinzufuegen beim semesterwechsel das richtige semester preselecten lv teil kopieren nur bei lv teilen anzeigen --- public/js/components/LVVerwaltung/LVVerwaltung.js | 12 +++++------- public/js/components/LVVerwaltung/Lektor/Daten.js | 4 ++-- public/js/components/LVVerwaltung/Lektor/Vertrag.js | 1 - public/js/components/LVVerwaltung/Setup/Table.js | 12 ++++++++++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/public/js/components/LVVerwaltung/LVVerwaltung.js b/public/js/components/LVVerwaltung/LVVerwaltung.js index a1ff28a2e..c03e7c84c 100644 --- a/public/js/components/LVVerwaltung/LVVerwaltung.js +++ b/public/js/components/LVVerwaltung/LVVerwaltung.js @@ -32,13 +32,7 @@ export default { studiensemester_kurzbz: { type: String, required: false, default: null }, emp: { type: String, required: false, default: null } }, - computed: { - selectedStudiensemester() { - return this.studiensemester_kurzbz != null - ? this.studiensemester_kurzbz - : this.defaultSemester; - } - }, + provide() { return { currentSemester: Vue.computed(() => this.selectedStudiensemester), @@ -70,12 +64,16 @@ export default { emp() { this.updateFilter(); }, + studiensemester_kurzbz(newVal) { + this.selectedStudiensemester = newVal ?? this.defaultSemester; + } }, data() { return { selected: [], studiengang: "", filter: {}, + selectedStudiensemester: this.studiensemester_kurzbz ?? this.defaultSemester, endpoint: ApiStudiengangTree, dropdowns: { studiensemester_array: [], diff --git a/public/js/components/LVVerwaltung/Lektor/Daten.js b/public/js/components/LVVerwaltung/Lektor/Daten.js index d4c6aa5e3..a9c7e53be 100644 --- a/public/js/components/LVVerwaltung/Lektor/Daten.js +++ b/public/js/components/LVVerwaltung/Lektor/Daten.js @@ -198,7 +198,7 @@ export default{ @@ -230,7 +230,7 @@ export default{ -
+
diff --git a/public/js/components/LVVerwaltung/Setup/Table.js b/public/js/components/LVVerwaltung/Setup/Table.js index 2f37e4207..309960f54 100644 --- a/public/js/components/LVVerwaltung/Setup/Table.js +++ b/public/js/components/LVVerwaltung/Setup/Table.js @@ -56,7 +56,13 @@ export default { } }, deep: true, - + }, + currentSemester: { + handler(newVal) + { + this.lv_info_default.studiensemester_kurzbz = newVal + this.lv_info = false; + } } }, data() { @@ -137,6 +143,8 @@ export default { selectableRows: true, rowContextMenu: (component, e) => { + if (e.getData()?.lehreinheit_id === undefined) + return; return [ { label: "LV-Teil kopieren", @@ -159,7 +167,7 @@ export default { label: "Nur mit Gruppen", action: (e, row) => { - this.copyLehreinheit(row, "halb"); + this.copyLehreinheit(row, "gruppen"); }, }, { From c69877ed85eaf7efc840348b889377e6ec9de91f Mon Sep 17 00:00:00 2001 From: ma0048 Date: Mon, 22 Sep 2025 13:41:58 +0200 Subject: [PATCH 070/112] bug beim loeschen von einer notiz mit doc --- application/core/Notiz_Controller.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/core/Notiz_Controller.php b/application/core/Notiz_Controller.php index c2bb03267..cfc54d5f5 100644 --- a/application/core/Notiz_Controller.php +++ b/application/core/Notiz_Controller.php @@ -393,10 +393,10 @@ abstract class Notiz_Controller extends FHCAPI_Controller foreach ($result as $doc) { $res = $this->dmslib->removeAll($doc->dms_id); - if (isError($result)) + if (isError($res)) { $this->db->trans_rollback(); - $this->terminateWithError(getError($result), self::ERROR_TYPE_GENERAL); + $this->terminateWithError(getError($res), self::ERROR_TYPE_GENERAL); } } From 5efad50b62e4c27d18dd608f66f0c0a17efbee8f Mon Sep 17 00:00:00 2001 From: ma0048 Date: Tue, 23 Sep 2025 08:31:00 +0200 Subject: [PATCH 071/112] added missing iframe component --- .../Cis/Cms/Content_types/Iframe_content.js | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 public/js/components/Cis/Cms/Content_types/Iframe_content.js diff --git a/public/js/components/Cis/Cms/Content_types/Iframe_content.js b/public/js/components/Cis/Cms/Content_types/Iframe_content.js new file mode 100644 index 000000000..568cfaf03 --- /dev/null +++ b/public/js/components/Cis/Cms/Content_types/Iframe_content.js @@ -0,0 +1,31 @@ +import { replaceRelativeLegacyLink } from "../../../../helpers/LegacyLinkReplaceHelper.js"; + +export default { + name: "iframe_content", + props: { + content: { type: String, required: true } + }, + computed: { + srcUrl() { + const parser = new DOMParser() + const doc = parser.parseFromString(`
${this.content}
`, "text/html"); + const iframe = doc.querySelector("iframe[src]"); + + if (!iframe) + return ""; + + let url = iframe.getAttribute("src") || ""; + return replaceRelativeLegacyLink(url); + } + }, + template: ` +
+ +
Keine URL gefunden.
+
+ ` +}; From 6abdb25c0a40d83498c690c4133cf9a305b3fc39 Mon Sep 17 00:00:00 2001 From: ma0048 Date: Wed, 24 Sep 2025 09:33:41 +0200 Subject: [PATCH 072/112] abort controller fixed und index auf campus.tbl_studierendenantrag_status.studierendenantrag_id hinzugefuegt --- public/js/api/factory/studstatus/leitung.js | 2 +- .../Studierendenantrag/Leitung/Actions/New.js | 28 +++++++------------ system/dbupdate_3.4.php | 1 + ...udstatus_suche_abort_controller_haengt.php | 16 +++++++++++ 4 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 system/dbupdate_3.4/67490_studstatus_suche_abort_controller_haengt.php diff --git a/public/js/api/factory/studstatus/leitung.js b/public/js/api/factory/studstatus/leitung.js index cc6b87d25..7f6bc9f54 100644 --- a/public/js/api/factory/studstatus/leitung.js +++ b/public/js/api/factory/studstatus/leitung.js @@ -34,7 +34,7 @@ export default { url: '/api/frontend/v1/studstatus/leitung/getHistory/' + antrag_id }; }, - getPrestudents(query, signal) { + getPrestudents(query) { return { method: 'post', url: '/api/frontend/v1/studstatus/leitung/getPrestudents', diff --git a/public/js/components/Studierendenantrag/Leitung/Actions/New.js b/public/js/components/Studierendenantrag/Leitung/Actions/New.js index a6cd69219..f78455baa 100644 --- a/public/js/components/Studierendenantrag/Leitung/Actions/New.js +++ b/public/js/components/Studierendenantrag/Leitung/Actions/New.js @@ -37,16 +37,16 @@ export default { }); }, loadData(evt) { - if( evt.query.length < 2 ) - { - return false; - } + if (evt.query.length < 2) + { + return false; + } + + if (this.abortController) + { + this.abortController.abort(); + } - if (this.abortController instanceof AbortController - && this.abortController.signal.aborted === false) - { - this.abortController.abort(); - } this.abortController = new AbortController(); this.$api @@ -56,16 +56,8 @@ export default { }) .then(result => { this.data = result.data; - this.abortController = null; }) - .catch(error => { - if (this.abortController instanceof AbortController - && this.abortController.signal.aborted === false) - { - this.abortController.abort(); - } - this.$fhcAlert.handleSystemError(error); - }); + .catch(this.$fhcAlert.handleSystemError); } }, template: ` diff --git a/system/dbupdate_3.4.php b/system/dbupdate_3.4.php index 4b52b04c4..7b298df36 100644 --- a/system/dbupdate_3.4.php +++ b/system/dbupdate_3.4.php @@ -79,6 +79,7 @@ require_once('dbupdate_3.4/61730_Dashboard_Anpassungen.php'); require_once('dbupdate_3.4/40128_search.php'); require_once('dbupdate_3.4/60882_lehrfaecherverteilung_favorites.php'); require_once('dbupdate_3.4/66982_berufsschule.php'); +require_once('dbupdate_3.4/67490_studstatus_suche_abort_controller_haengt.php'); // *** Pruefung und hinzufuegen der neuen Attribute und Tabellen echo '

Pruefe Tabellen und Attribute!

'; diff --git a/system/dbupdate_3.4/67490_studstatus_suche_abort_controller_haengt.php b/system/dbupdate_3.4/67490_studstatus_suche_abort_controller_haengt.php new file mode 100644 index 000000000..4c348a7ab --- /dev/null +++ b/system/dbupdate_3.4/67490_studstatus_suche_abort_controller_haengt.php @@ -0,0 +1,16 @@ +db_query("SELECT * FROM pg_class WHERE relname='idx_tbl_studierendenantrag_status_studierendenantrag_id'")) +{ + if ($db->db_num_rows($result) == 0) + { + $qry = "CREATE INDEX idx_tbl_studierendenantrag_status_studierendenantrag_id ON campus.tbl_studierendenantrag_status USING btree (studierendenantrag_id)"; + + if (!$db->db_query($qry)) + echo 'Indizes: ' . $db->db_last_error() . '
'; + else + echo 'Index fuer campus.tbl_studierendenantrag_status.studierendenantrag_id hinzugefuegt'; + } +} From 2ef2948a6e4bf2cbe32d547d18a5f7dacbf77397 Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Thu, 25 Sep 2025 16:02:43 +0200 Subject: [PATCH 073/112] prevent strange effects when switching between content_types --- public/js/components/Cis/Cms/Content.js | 32 ++++--------------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/public/js/components/Cis/Cms/Content.js b/public/js/components/Cis/Cms/Content.js index ec1bc8a76..355add08a 100644 --- a/public/js/components/Cis/Cms/Content.js +++ b/public/js/components/Cis/Cms/Content.js @@ -30,39 +30,19 @@ export default { }, data() { return { + content_type: null, content: null, content_id_internal: this.content_id }; }, methods: { fetchContent(){ - return this.$api + this.$api .call(ApiCms.content(this.content_id_internal, this.version, this.sprache, this.sichtbar)) .then(res => { - this.content = res.data.content; - this.content_type = res.data.type; - - document.querySelectorAll("#cms [data-confirm]").forEach((el) => { - el.addEventListener("click", (evt) => { - evt.preventDefault(); - BsConfirm.popup(el.dataset.confirm) - .then(() => { - Axios.get(el.href) - .then((res) => { - // TODO(chris): check for success then show message and/or reload - location = location; - }) - .catch((err) => console.error("ERROR:", err)); - }) - .catch(() => { - }); - }); - }); - document.querySelectorAll("#cms [data-href]").forEach((el) => { - el.href = el.dataset.href.replace( - /^ROOT\//, - FHC_JS_DATA_STORAGE_OBJECT.app_root - ); + this.$nextTick(function() { + this.content = res.data.content; + this.content_type = res.data.type; }); }); } @@ -96,8 +76,6 @@ export default { created() { this.fetchContent(); }, - mounted() { - }, template: /*html*/ `
From 58b942f0441aae268b784e7b3020b4e3f364f5eb Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Thu, 25 Sep 2025 16:14:09 +0200 Subject: [PATCH 074/112] fix typo in template_kurzbz --- system/dbupdate_3.4/63436_cis4_iframe_component.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/dbupdate_3.4/63436_cis4_iframe_component.php b/system/dbupdate_3.4/63436_cis4_iframe_component.php index abff4b7e1..a5b3bbf7c 100644 --- a/system/dbupdate_3.4/63436_cis4_iframe_component.php +++ b/system/dbupdate_3.4/63436_cis4_iframe_component.php @@ -57,7 +57,7 @@ $xslt_xhtml_c4= <<db_query("SELECT * FROM campus.tbl_template WHERE template_kurzbz='iframe2'")) +if ($result = @$db->db_query("SELECT * FROM campus.tbl_template WHERE template_kurzbz='iframe'")) { if ($db->db_num_rows($result) == 0) { @@ -78,4 +78,4 @@ EOD; } } -} \ No newline at end of file +} From 6047b19f4710cb941cdca0f9d31f5e6169fe7637 Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Thu, 25 Sep 2025 17:19:19 +0200 Subject: [PATCH 075/112] do not show contacts with type hidden in cis4 profile --- application/libraries/ProfilLib.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/application/libraries/ProfilLib.php b/application/libraries/ProfilLib.php index 50b8bc264..6e93a0943 100644 --- a/application/libraries/ProfilLib.php +++ b/application/libraries/ProfilLib.php @@ -214,7 +214,7 @@ class ProfilLib{ * @param integer $uid the userID used to get the kontakt information * @return array all the kontakt information corresponding to a userID */ - private function getKontaktInfo($pid) + private function getKontaktInfo($pid, $includehidden=false) { $this->ci->load->model("person/Kontakt_model","KontaktModel"); $this->ci->KontaktModel->addSelect(['kontakttyp', 'kontakt_id', 'kontakt', 'tbl_kontakt.anmerkung', 'tbl_kontakt.zustellung']); @@ -222,7 +222,13 @@ class ProfilLib{ $this->ci->KontaktModel->addJoin('public.tbl_firma', 'firma_id', 'LEFT'); $this->ci->KontaktModel->addOrder('kontakttyp, kontakt, tbl_kontakt.updateamum, tbl_kontakt.insertamum'); - $kontakte_res = $this->ci->KontaktModel->loadWhere(['person_id' => $pid]); + $params = array('person_id' => $pid); + if(!$includehidden) + { + $params['kontakttyp <>'] = 'hidden'; + } + + $kontakte_res = $this->ci->KontaktModel->loadWhere($params); if(isError($kontakte_res)){ return error(getData($kontakte_res)); } From a021c8592022d6f86ccc29f1c56902c41c8b9927 Mon Sep 17 00:00:00 2001 From: Johann Hoffmann Date: Thu, 25 Sep 2025 17:23:03 +0200 Subject: [PATCH 076/112] =?UTF-8?q?sch=C3=B6nere=20phrasen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- system/phrasesupdate.php | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 008ad8a8d..ceb265b14 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -30686,6 +30686,26 @@ array( ) ) ), + array( + 'app' => 'anwesenheiten', + 'category' => 'global', + 'phrase' => 'jetztStarten', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Jetzt Starten', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Start Now', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'anwesenheiten', 'category' => 'global', @@ -42556,6 +42576,26 @@ array( ) ) ), + array( + 'app' => 'core', + 'category' => 'abgabetool', + 'phrase' => 'c4abgabeStgSpezifischeRichtlinienBeachten', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => "Bitte beachten Sie gegebenenfalls existierende studiengangsspezifische Richtlinien und informieren Sie sich diesbezüglich. Vielen Dank.", + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Please note any existing program-specific guidelines and inform yourself about them. Thank you.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'core', 'category' => 'abgabetool', From e908215b050aa9152803e849995e377c21d8f829 Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Thu, 25 Sep 2025 17:40:39 +0200 Subject: [PATCH 077/112] use person_id from profilupdate request instead of logged in user to handle duplicates --- .../api/frontend/v1/ProfilUpdate.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/application/controllers/api/frontend/v1/ProfilUpdate.php b/application/controllers/api/frontend/v1/ProfilUpdate.php index bbfed651c..6752c805a 100644 --- a/application/controllers/api/frontend/v1/ProfilUpdate.php +++ b/application/controllers/api/frontend/v1/ProfilUpdate.php @@ -813,7 +813,7 @@ class ProfilUpdate extends FHCAPI_Controller $insert_adresse_id = $insertID; $insert_adresse_id = $this->getDataOrTerminateWithError($insert_adresse_id, $this->p->t('profilUpdate', 'profilUpdate_insertAdresse_error')); if ($insert_adresse_id) { - $this->handleDupplicateZustellAdressen($requested_change['zustelladresse'], $insert_adresse_id); + $this->handleDupplicateZustellAdressen($requested_change['zustelladresse'], $insert_adresse_id, $personID); } } //! DELETE @@ -829,7 +829,7 @@ class ProfilUpdate extends FHCAPI_Controller $requested_change['updatevon'] = getAuthUID(); $update_adresse_id = $this->AdresseModel->update($adresse_id, $requested_change); $update_adresse_id = $this->getDataOrTerminateWithError($update_adresse_id, $this->p->t('profilUpdate', 'profilUpdate_updateAdresse_error')); - $this->handleDupplicateZustellAdressen($requested_change['zustelladresse'], $update_adresse_id); + $this->handleDupplicateZustellAdressen($requested_change['zustelladresse'], $update_adresse_id, $personID); } return $insertID ?? null; @@ -852,7 +852,7 @@ class ProfilUpdate extends FHCAPI_Controller $insert_kontakt_id = $insertID; $insert_kontakt_id = $this->getDataOrTerminateWithError($insert_kontakt_id, $this->p->t('profilUpdate', 'profilUpdate_insertKontakt_error')); if ($insert_kontakt_id) { - $this->handleDupplicateZustellKontakte($requested_change['zustellung'], $insert_kontakt_id); + $this->handleDupplicateZustellKontakte($requested_change['zustellung'], $insert_kontakt_id, $personID); } } //! DELETE @@ -869,18 +869,18 @@ class ProfilUpdate extends FHCAPI_Controller $update_kontakt_id = $this->KontaktModel->update($kontakt_id, $requested_change); $update_kontakt_id = $this->getDataOrTerminateWithError($update_kontakt_id, $this->p->t('profilUpdate', 'profilUpdate_updateKontakt_error')); if ($update_kontakt_id) { - $this->handleDupplicateZustellKontakte($requested_change['zustellung'], $update_kontakt_id); + $this->handleDupplicateZustellKontakte($requested_change['zustellung'], $update_kontakt_id, $personID); } } return isset($insertID) ? $insertID : null; } - private function handleDupplicateZustellAdressen($zustellung, $adresse_id) + private function handleDupplicateZustellAdressen($zustellung, $adresse_id, $person_id) { if ($zustellung) { $this->PersonModel->addSelect("public.tbl_adresse.adresse_id"); $this->PersonModel->addJoin("public.tbl_adresse", "public.tbl_adresse.person_id = public.tbl_person.person_id"); - $zustellAdressenArray = $this->PersonModel->loadWhere(["public.tbl_person.person_id" => $this->pid, "zustelladresse" => TRUE]); + $zustellAdressenArray = $this->PersonModel->loadWhere(["public.tbl_person.person_id" => $person_id, "zustelladresse" => TRUE]); if (isError($zustellAdressenArray)) { $this->terminateWithError($this->p->t('profilUpdate', 'profilUpdate_loadingZustellAdressen_error')); } @@ -893,6 +893,8 @@ class ProfilUpdate extends FHCAPI_Controller return $adresse->adresse_id != $adresse_id; }); + $this->addMeta('bhzustelladressen', $zustellAdressenArray); + // remove the zustelladresse from all other zustelladressen foreach ($zustellAdressenArray as $adresse) { $this->AdresseModel->update($adresse->adresse_id, ["zustelladresse" => FALSE]); @@ -902,12 +904,12 @@ class ProfilUpdate extends FHCAPI_Controller } } - private function handleDupplicateZustellKontakte($zustellung, $kontakt_id) + private function handleDupplicateZustellKontakte($zustellung, $kontakt_id, $person_id) { if ($zustellung) { $this->PersonModel->addSelect("public.tbl_kontakt.kontakt_id"); $this->PersonModel->addJoin("public.tbl_kontakt", "public.tbl_kontakt.person_id = public.tbl_person.person_id"); - $zustellKontakteArray = $this->PersonModel->loadWhere(["public.tbl_person.person_id" => $this->pid, "zustellung" => TRUE]); + $zustellKontakteArray = $this->PersonModel->loadWhere(["public.tbl_person.person_id" => $person_id, "zustellung" => TRUE]); if (!isSuccess($zustellKontakteArray)) { return error($this->p->t('profilUpdate', 'profilUpdate_loadingZustellkontakte_error')); } From 0df9cf769fd7a27528fe7b2534fce82dcb9f05e6 Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Fri, 26 Sep 2025 14:33:20 +0200 Subject: [PATCH 078/112] strip data image base64 prefix before storing foto, show dummy profile img when foto is null in DetailsHeader --- .../controllers/api/frontend/v1/stv/Student.php | 15 ++++++++++----- public/js/components/DetailHeader/DetailHeader.js | 9 ++++++++- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/application/controllers/api/frontend/v1/stv/Student.php b/application/controllers/api/frontend/v1/stv/Student.php index 90c12fe41..f2845572f 100644 --- a/application/controllers/api/frontend/v1/stv/Student.php +++ b/application/controllers/api/frontend/v1/stv/Student.php @@ -276,14 +276,19 @@ class Student extends FHCAPI_Controller $update_person = array(); foreach ($array_allowed_props_person as $prop) { $val = $this->input->post($prop); - if ($val !== null) + if ($val === null) + { + continue; + } + if($prop == 'foto') + { + $fotoval = ($val == '') ? null : str_replace('data:image/jpeg;base64,', '', $val); + $update_person[$prop] = $fotoval; + } + else { $update_person[$prop] = $val; } - if($prop == 'foto' && $val == '') - { - $update_person[$prop] = null; - } } $array_allowed_props_student = ['matrikelnr']; diff --git a/public/js/components/DetailHeader/DetailHeader.js b/public/js/components/DetailHeader/DetailHeader.js index 5c1573753..1088e3f63 100644 --- a/public/js/components/DetailHeader/DetailHeader.js +++ b/public/js/components/DetailHeader/DetailHeader.js @@ -102,6 +102,13 @@ export default { redirectToLeitung(){ this.$emit('redirectToLeitung', { person_id: this.leitungData.person_id}); + }, + getFotoSrc(foto) { + if(foto === null) { + return FHC_JS_DATA_STORAGE_OBJECT.app_root + 'skin/images/profilbild_dummy.jpg'; + } else { + return 'data:image/jpeg;base64,' + foto; + } } }, template: ` @@ -116,7 +123,7 @@ export default { Profilbild
From 8a1ca9a598e60b9599d53eb5bc8e62e8372d9bbe Mon Sep 17 00:00:00 2001 From: Paolo Date: Tue, 7 Oct 2025 13:33:49 +0200 Subject: [PATCH 090/112] Checked that the session is not an error in the FilterComponent --- application/libraries/FilterCmptLib.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/application/libraries/FilterCmptLib.php b/application/libraries/FilterCmptLib.php index f742b4ce1..b1de89245 100644 --- a/application/libraries/FilterCmptLib.php +++ b/application/libraries/FilterCmptLib.php @@ -902,7 +902,7 @@ class FilterCmptLib $filterCmptsSession = getSession(self::SESSION_NAME); // If something is present in session - if ($filterCmptsSession != null) + if (!isError($filterCmptsSession) && $filterCmptsSession != null) { // Loops in the session for all the filter components foreach ($filterCmptsSession as $filterCmpt => $filterCmptData) @@ -965,7 +965,7 @@ class FilterCmptLib $filterCmptsSession = getSession(self::SESSION_NAME); // If something is present in session - if ($filterCmptsSession != null) + if (!isError($filterCmptsSession) && $filterCmptsSession != null) { // Loops in the session for all the filter components foreach ($filterCmptsSession as $filterCmpt => $filterCmptData) @@ -1174,3 +1174,4 @@ class FilterCmptLib return $filterName; } } + From 5f57c53ed0cdb40233afcba80423d3eb58947841 Mon Sep 17 00:00:00 2001 From: Paolo Date: Tue, 7 Oct 2025 14:47:34 +0200 Subject: [PATCH 091/112] Api.js: better error handling --- public/js/plugins/Api.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/public/js/plugins/Api.js b/public/js/plugins/Api.js index 0b8e2fd17..895ecf70d 100644 --- a/public/js/plugins/Api.js +++ b/public/js/plugins/Api.js @@ -328,6 +328,7 @@ export default { url: error.request.responseURL }]; } else { + if (error.response.data.errors == undefined) return []; return error.response.data.errors; } } else if (error.request) { @@ -346,6 +347,9 @@ export default { function popHandleableErrors(errorHandling, errors) { const result = {}; const copy = []; + + if (errors == undefined) return {}; + while (errors.length) copy.push(errors.pop()); for (var error of copy) { @@ -551,4 +555,4 @@ export default { app.provide('$api', app.config.globalProperties.$api); } -}; \ No newline at end of file +}; From b681ca29c17929bd7bfd85dbde11444d99234261 Mon Sep 17 00:00:00 2001 From: Harald Bamberger Date: Tue, 7 Oct 2025 15:13:07 +0200 Subject: [PATCH 092/112] add info alert for heimatadresse, tune duplicate zustellkontakt handling --- .../api/frontend/v1/ProfilUpdate.php | 12 +++-- .../models/person/Profil_update_model.php | 1 + public/js/components/Cis/Profil/Profil.js | 20 +++++--- .../Cis/Profil/ProfilComponents/Adresse.js | 2 +- .../EditProfilComponents/EditAdresse.js | 6 +-- .../EditProfilComponents/EditKontakt.js | 29 +++++------ .../Profil/ProfilModal/EditProfilSelect.js | 22 +++++++-- system/phrasesupdate.php | 48 +++++++++++++++++-- 8 files changed, 103 insertions(+), 37 deletions(-) diff --git a/application/controllers/api/frontend/v1/ProfilUpdate.php b/application/controllers/api/frontend/v1/ProfilUpdate.php index d0eb26858..e5129b678 100644 --- a/application/controllers/api/frontend/v1/ProfilUpdate.php +++ b/application/controllers/api/frontend/v1/ProfilUpdate.php @@ -873,7 +873,7 @@ class ProfilUpdate extends FHCAPI_Controller $insert_kontakt_id = $insertID; $insert_kontakt_id = $this->getDataOrTerminateWithError($insert_kontakt_id, $this->p->t('profilUpdate', 'profilUpdate_insertKontakt_error')); if ($insert_kontakt_id) { - $this->handleDupplicateZustellKontakte($requested_change['zustellung'], $insert_kontakt_id, $personID); + $this->handleDupplicateZustellKontakte($requested_change['zustellung'], $insert_kontakt_id, $requested_change['kontakttyp'], $personID); } } //! DELETE @@ -890,7 +890,7 @@ class ProfilUpdate extends FHCAPI_Controller $update_kontakt_id = $this->KontaktModel->update($kontakt_id, $requested_change); $update_kontakt_id = $this->getDataOrTerminateWithError($update_kontakt_id, $this->p->t('profilUpdate', 'profilUpdate_updateKontakt_error')); if ($update_kontakt_id) { - $this->handleDupplicateZustellKontakte($requested_change['zustellung'], $update_kontakt_id, $personID); + $this->handleDupplicateZustellKontakte($requested_change['zustellung'], $update_kontakt_id, $requested_change['kontakttyp'], $personID); } } return isset($insertID) ? $insertID : null; @@ -925,12 +925,16 @@ class ProfilUpdate extends FHCAPI_Controller } } - private function handleDupplicateZustellKontakte($zustellung, $kontakt_id, $person_id) + private function handleDupplicateZustellKontakte($zustellung, $kontakt_id, $kontakttyp, $person_id) { if ($zustellung) { $this->PersonModel->addSelect("public.tbl_kontakt.kontakt_id"); $this->PersonModel->addJoin("public.tbl_kontakt", "public.tbl_kontakt.person_id = public.tbl_person.person_id"); - $zustellKontakteArray = $this->PersonModel->loadWhere(["public.tbl_person.person_id" => $person_id, "zustellung" => TRUE]); + $zustellKontakteArray = $this->PersonModel->loadWhere([ + "public.tbl_person.person_id" => $person_id, + "zustellung" => TRUE, + "kontakttyp" => $kontakttyp + ]); if (!isSuccess($zustellKontakteArray)) { return error($this->p->t('profilUpdate', 'profilUpdate_loadingZustellkontakte_error')); } diff --git a/application/models/person/Profil_update_model.php b/application/models/person/Profil_update_model.php index 141044a2c..36f53ff75 100644 --- a/application/models/person/Profil_update_model.php +++ b/application/models/person/Profil_update_model.php @@ -63,6 +63,7 @@ class Profil_update_model extends DB_Model $this->addSelect(["public.tbl_profil_update.*", "public.tbl_person.vorname"]); $this->addJoin("public.tbl_benutzer", "public.tbl_benutzer.uid = public.tbl_profil_update.uid"); $this->addJoin("public.tbl_person", "public.tbl_person.person_id = public.tbl_benutzer.person_id"); + $this->db->order_by('COALESCE(public.tbl_profil_update.updateamum, public.tbl_profil_update.insertamum)', 'DESC', false); $res = $this->loadWhere($whereClause); if (isError($res)) { return $res; diff --git a/public/js/components/Cis/Profil/Profil.js b/public/js/components/Cis/Profil/Profil.js index 8ca2cfe8e..da205816d 100644 --- a/public/js/components/Cis/Profil/Profil.js +++ b/public/js/components/Cis/Profil/Profil.js @@ -120,10 +120,10 @@ export const Profil = { }, sortProfilUpdates: (ele1, ele2) => { let result = 0; - if (ele1.status === "pending") { + if (ele1.status.toLowerCase() === "pending") { result = -1; - } else if (ele1.status === "accepted") { - result = ele2.status === "rejected" ? -1 : 1; + } else if (ele1.status.toLowerCase() === "accepted") { + result = ele2.status.toLowerCase() === "rejected" ? -1 : 1; } else { result = 1; } @@ -226,10 +226,13 @@ export const Profil = { kontakteArray = kontakteArray.concat( this.data.profilUpdates .filter((update) => { - return update.requested_change.zustellung; + return update.status === 'Pending' && update.requested_change.zustellung; }) .map((kontant) => { - return kontant.requested_change.kontakt_id; + return { + kontakt_id: kontant.requested_change.kontakt_id, + kontakttyp: kontant.requested_change.kontakttyp + }; }) ); } @@ -241,7 +244,7 @@ export const Profil = { .every((kontakt) => this.data.profilUpdates.some( (update) => - update.requested_change.kontakt_id == kontakt.kontakt_id + update.status === 'Pending' && update.requested_change.kontakt_id == kontakt.kontakt_id ) ) ) { @@ -251,7 +254,10 @@ export const Profil = { return kontakt.zustellung; }) .map((kon) => { - return kon.kontakt_id; + return { + kontakt_id: kon.kontakt_id, + kontakttyp: kon.kontakttyp + }; }) ); } diff --git a/public/js/components/Cis/Profil/ProfilComponents/Adresse.js b/public/js/components/Cis/Profil/ProfilComponents/Adresse.js index 5ba2f1fe7..7ec1213e2 100644 --- a/public/js/components/Cis/Profil/ProfilComponents/Adresse.js +++ b/public/js/components/Cis/Profil/ProfilComponents/Adresse.js @@ -4,7 +4,7 @@ export default { view:String, withZustelladresse:{ type:Boolean, - default:false, + default:true, }, }, data(){ diff --git a/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/EditAdresse.js b/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/EditAdresse.js index 76e08b974..8f0724f9c 100644 --- a/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/EditAdresse.js +++ b/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/EditAdresse.js @@ -160,10 +160,8 @@ export default {
-
-
+
{{$p.t('profilUpdate','zustell_adressen_warning')}} -
@@ -173,7 +171,7 @@ export default {
diff --git a/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/EditKontakt.js b/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/EditKontakt.js index 4f978f636..b484c9dd5 100644 --- a/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/EditKontakt.js +++ b/public/js/components/Cis/Profil/ProfilModal/EditProfilComponents/EditKontakt.js @@ -30,12 +30,15 @@ export default { // if the kontakt is already a zustellungskontakt when the user is editing the kontakt, then no warning is shown and the zustellung will be overwritten if (JSON.parse(this.originalValue).zustellung) { return false; - } + } + const kontakteOfSelectedType = this.zustellKontakteCount.filter((element) => { + return element.kontakttyp === this.data?.kontakttyp + }); // if zustellKontakteCount is not 0 and the own kontakt has the flag zustellung set to true - if (!this.zustellKontakteCount.includes(this.data.kontakt_id)) { - return this.data.zustellung && this.zustellKontakteCount.length; + if (!this.zustellKontakteCount.some((element) => element.kontakt_id === this.data.kontakt_id)) { + return this.data.zustellung && kontakteOfSelectedType.length; } - return this.zustellKontakteCount.length >= 2 && this.data.zustellung; + return this.kontakteOfSelectedType.length >= 2 && this.data.zustellung; }, isChanged: function () { //? returns true if the original passed data object was changed @@ -57,16 +60,6 @@ export default {
- -
-
-
- {{$p.t('profilUpdate','zustell_kontakte_warning')}} -
-
-
- -
@@ -108,6 +101,14 @@ export default {
+ +
+
+ {{$p.t('profilUpdate','zustell_kontakte_warning')}} +
+
+ +
{{$p.t('profilUpdate','zustellungsKontakt')}} diff --git a/public/js/components/Cis/Profil/ProfilModal/EditProfilSelect.js b/public/js/components/Cis/Profil/ProfilModal/EditProfilSelect.js index 60dd759b3..921758ae0 100644 --- a/public/js/components/Cis/Profil/ProfilModal/EditProfilSelect.js +++ b/public/js/components/Cis/Profil/ProfilModal/EditProfilSelect.js @@ -148,16 +148,32 @@ export default {