From c5c29df6ccd6415607e813fc1d1df7152f793420 Mon Sep 17 00:00:00 2001 From: Alexei Karpenko Date: Tue, 14 Jul 2026 20:51:41 +0200 Subject: [PATCH 01/23] Gehaltsbestandteil, Gehaltsbestandteil_model: added gehaltstyp_bezeichnung --- .../vertragsbestandteil/Gehaltsbestandteil.php | 11 ++++++++++- .../vertragsbestandteil/Gehaltsbestandteil_model.php | 9 ++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php b/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php index 95bbdd908..70c362ed7 100644 --- a/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php +++ b/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php @@ -21,6 +21,7 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl protected $valorisierungssperre; protected $valorisierung; protected $auszahlungen; + protected $gehaltstyp_bezeichnung; protected $insertamum; protected $insertvon; @@ -47,7 +48,8 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl isset($data->valorisierungssperre) && $this->setValorisierungssperre($data->valorisierungssperre); isset($data->valorisierung) && $this->setValorisierung($data->valorisierung); isset($data->auszahlungen) && $this->setAuszahlungen($data->auszahlungen); - + isset($data->gehaltstyp_bezeichnung) && $this->setGehaltstyp_bezeichnung($data->gehaltstyp_bezeichnung); + isset($data->insertamum) && $this->setInsertamum($data->insertamum); isset($data->insertvon) && $this->setInsertvon($data->insertvon); isset($data->updateamum) && $this->setUpdateamum($data->updateamum); @@ -242,6 +244,13 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl return $this; } + public function setGehaltstyp_bezeichnung($gehaltstyp_bezeichnung) + { + $this->markDirty('gehaltstyp_bezeichnung', $this->gehaltstyp_bezeichnung, $gehaltstyp_bezeichnung); + $this->gehaltstyp_bezeichnung = $gehaltstyp_bezeichnung; + return $this; + } + public function setInsertamum($insertamum) { $this->markDirty('insertamum', $this->insertamum, $insertamum); diff --git a/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php b/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php index 2669105a1..57031ac08 100644 --- a/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php +++ b/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php @@ -177,7 +177,8 @@ LEFT JOIN $stichtagclause .= ')'; } - $this->addSelect('*'); + $this->addSelect('tbl_gehaltsbestandteil.*, tbl_gehaltstyp.bezeichnung AS gehaltstyp_bezeichnung'); + $this->addJoin('hr.tbl_gehaltstyp', 'gehaltstyp_kurzbz'); $where = <<escape($dienstverhaeltnis_id)} {$stichtagclause} @@ -213,9 +214,11 @@ SELECT g.updateamum, g.updatevon, g.valorisierung, - g.auszahlungen + g.auszahlungen, + gt.bezeichnung AS gehaltstyp_bezeichnung FROM - hr.tbl_gehaltsbestandteil g + hr.tbl_gehaltsbestandteil g + JOIN hr.tbl_gehaltstyp gt USING (gehaltstyp_kurzbz) LEFT JOIN hr.tbl_valorisierung_historie vh ON vh.gehaltsbestandteil_id = g.gehaltsbestandteil_id AND vh.valorisierungsdatum = ( SELECT From 13515b25227ab2a4c6c8857ee7a6b490881f8bca Mon Sep 17 00:00:00 2001 From: chfhtw Date: Tue, 4 Aug 2026 09:40:47 +0200 Subject: [PATCH 02/23] Bugfix: after a drag and drop operation, when resizing the page, the moved item stays in the drop position even if it has had a position in the resized layout --- public/js/components/Drop/Grid.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/public/js/components/Drop/Grid.js b/public/js/components/Drop/Grid.js index 6d9777c28..d4d8c90d9 100644 --- a/public/js/components/Drop/Grid.js +++ b/public/js/components/Drop/Grid.js @@ -233,6 +233,14 @@ export default { if (value == oldValue) return; + /** NOTE(chris): tempPositionUpdates depends on the cols not to be + * updated. So if they do we reset to get a clean value. In case the + * drag and drop operation is still motion on the next tick this + * will be correct again and if there is no such operation we clean + * up. + */ + this.tempPositionUpdates = null; + this.reinitGrid(); }, rows: { @@ -246,6 +254,11 @@ export default { }, indexedItems: { handler(value) { + /** NOTE(chris): there was an update of the items, so in case + * it came from a drag and drop operation we need to clean up + */ + this.tempPositionUpdates = null; + this.reinitGrid(); }, immediate: true, From d824334538bd7f12df511413c601a18c6906196c Mon Sep 17 00:00:00 2001 From: chfhtw Date: Tue, 4 Aug 2026 09:42:18 +0200 Subject: [PATCH 03/23] Hiding widgets should look like deleting and recovering is moved to the "add widget" popup --- public/js/components/Dashboard/Dashboard.js | 43 +++++++++++---- public/js/components/Dashboard/Item.js | 28 +--------- public/js/components/Dashboard/Section.js | 19 +------ .../js/components/Dashboard/Widget/Picker.js | 55 +++++++++++++++---- 4 files changed, 81 insertions(+), 64 deletions(-) diff --git a/public/js/components/Dashboard/Dashboard.js b/public/js/components/Dashboard/Dashboard.js index bf45ad227..b88765856 100644 --- a/public/js/components/Dashboard/Dashboard.js +++ b/public/js/components/Dashboard/Dashboard.js @@ -62,6 +62,9 @@ export default { return [type, result]; })); + }, + hiddenWidgets() { + return this.widgets.filter(widget => widget.hidden); } }, methods: { @@ -69,6 +72,9 @@ export default { this.$refs.widgetpicker .getWidget() .then(widget_id => { + if (widget_id.hidden) + this.widgetUnhide(widget_id, widget.place); + widget.widget = widget_id; // NOTE(chris): min size widget.place = Object.fromEntries(Object.entries(widget.place).map(([key, value]) => { @@ -131,17 +137,6 @@ export default { this.widgets.forEach((widget, i) => { if (failed.includes(widget.id)) { this.widgets[i] = structuredClone(ObjectUtils.deepToRaw(this.originalWidgets[widget.id])); - /** NOTE(chris): if you wanna hide or unhide a - * preset and it fails: switch around the hidden - * value to revert it properly (checkboxes can't - * really handle it otherwise) - */ - if (payload[widget.id].hidden !== undefined) { - this.widgets[i].hidden = payload[widget.id].hidden; - this.$nextTick(() => { - this.widgets[i] = structuredClone(ObjectUtils.deepToRaw(this.originalWidgets[widget.id])); - }); - } } else if (payload[widget.id]) { payload[widget.id].id = widget.id; payload[widget.id].index = widget.index; @@ -160,6 +155,31 @@ export default { }) .catch(this.$fhcAlert.handleSystemError); }, + widgetUnhide(orig, place) { + place = Object.fromEntries(Object.entries(place).map(([key, value]) => { + value.w = this.sizeLimits[orig.widget].width.min; + value.h = this.sizeLimits[orig.widget].height.min; + // NOTE(chris): unpin pinned widgets because they got a new placement + value.pinned = false; + return [key, value]; + })); + // NOTE(chris): clear placement in other screensizes + Object.keys(orig.place).forEach(key => { + if (!place[key]) { + place[key] = { + x: undefined, + y: undefined, + pinned: false + }; + } + }); + let payload = {}; + payload[orig.id] = { + hidden: false, + place + }; + return this.widgetUpdate(payload); + }, async fetchViewData() { let viewDataResult = await this.$api.call(ApiDashboard.getViewData()); const viewData = viewDataResult.data; @@ -223,6 +243,7 @@ export default { ` } diff --git a/public/js/components/Dashboard/Item.js b/public/js/components/Dashboard/Item.js index 20c195178..160b34e91 100644 --- a/public/js/components/Dashboard/Item.js +++ b/public/js/components/Dashboard/Item.js @@ -36,7 +36,6 @@ export default { "width", "height", "custom", - "hidden", "editMode", "loading", // widget got added and is waiting for backend to save in db "item_data", @@ -115,14 +114,6 @@ export default { }, ready() { return this.component && this.arguments !== null; - }, - visible: { - get() { - return !this.hidden; - }, - set(value) { - this.$emit('remove', this.hidden); - } } }, methods: { @@ -202,10 +193,8 @@ export default { }, template: /*html*/ `
@@ -299,9 +288,9 @@ export default { > - + - - -
- -
-
diff --git a/public/js/components/Dashboard/Section.js b/public/js/components/Dashboard/Section.js index e8c56fd4e..b55eefb7a 100644 --- a/public/js/components/Dashboard/Section.js +++ b/public/js/components/Dashboard/Section.js @@ -124,8 +124,6 @@ export default { return { ...item, ...placement, weight }; }); - if (this.editModeIsActive) - return placedItems; return placedItems.filter(item => !item.hidden); } }, @@ -141,22 +139,12 @@ export default { handleConfigClosed() { this.configOpened = false }, - removeWidget(item, revert) { + removeWidget(item) { if (item.custom) { BsConfirm.popup(this.$p.t('dashboard', 'alert_deleteWidget')).then(() => this.$emit('widgetRemove', item.id, this.name)); } else { let update = {}; - update[item.id] = { hidden: !revert }; - - if (!revert) { - // NOTE(chris): move to last line - update[item.id].place = []; - let y = this.gridHeight; - if (this.additionalRow) - y--; - update[item.id].place[this.gridWidth] = { x: 0, y }; - } - + update[item.id] = { hidden: true }; this.updatePreset(update); } }, @@ -251,13 +239,12 @@ export default { :loading="item.loading" :config="item.config" :custom="item.custom" - :hidden="item.hidden" :editMode="editModeIsActive" :place="item.place[gridWidth]" :widget-template="indexedWidgetsTemplates[item.widget]" :source="adminMode ? null : item.source || 'custom'" @change="saveConfig($event, item)" - @remove="removeWidget(item, $event)" + @remove="removeWidget(item)" @config-opened="handleConfigOpened" @config-closed="handleConfigClosed" @pin-item="updatePositions" diff --git a/public/js/components/Dashboard/Widget/Picker.js b/public/js/components/Dashboard/Widget/Picker.js index 260b95874..284eb551c 100644 --- a/public/js/components/Dashboard/Widget/Picker.js +++ b/public/js/components/Dashboard/Widget/Picker.js @@ -7,11 +7,21 @@ export default { WidgetIcon, }, props: [ - "widgets" + "widgets", + "hiddenWidgets" ], data: () => ({ callbacks: {} }), + computed: { + hasAnyWidgets() { + if (!this.widgets) + return false; + if (!this.widgets.length && !this.hiddenWidgets?.length) + return false; + return true; + } + }, methods: { getWidget() { return new Promise((resolve,reject) => { @@ -37,23 +47,46 @@ export default {
From 2f86a1b0171738b58baef4a114d82115e1967cb3 Mon Sep 17 00:00:00 2001 From: chfhtw Date: Tue, 4 Aug 2026 10:46:08 +0200 Subject: [PATCH 05/23] Changing the edit button into a toggle --- public/js/components/Dashboard/Dashboard.js | 26 ++++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/public/js/components/Dashboard/Dashboard.js b/public/js/components/Dashboard/Dashboard.js index b88765856..e390f16d4 100644 --- a/public/js/components/Dashboard/Dashboard.js +++ b/public/js/components/Dashboard/Dashboard.js @@ -224,15 +224,23 @@ export default { }, template: /* html */`
-

- {{ userFirstName ? $p.t('global/personalGreeting', [ userFirstName ]) : '' }} - -

+
+

+ {{ userFirstName ? $p.t('global/personalGreeting', [ userFirstName ]) : '' }} +

+
+ + +
+
Date: Thu, 6 Aug 2026 13:26:33 +0200 Subject: [PATCH 06/23] add Tile PrestudentID to FHC Header --- .../js/components/DetailHeader/DetailHeader.js | 17 +++++++++++++++++ .../Stv/Studentenverwaltung/Details.js | 6 ++++++ 2 files changed, 23 insertions(+) diff --git a/public/js/components/DetailHeader/DetailHeader.js b/public/js/components/DetailHeader/DetailHeader.js index 2a5987a9b..595586a39 100644 --- a/public/js/components/DetailHeader/DetailHeader.js +++ b/public/js/components/DetailHeader/DetailHeader.js @@ -82,6 +82,9 @@ export default { hasTileGammaSlot() { return !!this.$slots.titleGammaTile }, + hasTileDeltaSlot() { + return !!this.$slots.titleDeltaTile + }, hasTileUIDSlot() { return !!this.$slots.uid }, @@ -490,6 +493,13 @@ export default {
+
+

+
+ + +
+

@@ -610,6 +620,13 @@ export default {
+
+

+
+ + +
+

diff --git a/public/js/components/Stv/Studentenverwaltung/Details.js b/public/js/components/Stv/Studentenverwaltung/Details.js index 799030730..119461b88 100644 --- a/public/js/components/Stv/Studentenverwaltung/Details.js +++ b/public/js/components/Stv/Studentenverwaltung/Details.js @@ -63,6 +63,10 @@ export default { let tile = this.students[0].matrikelnr != null ? this.students[0].matrikelnr : '-'; return tile; }, + tile_PrestdId(){ + let tile = this.students[0].prestudent_id != null ? this.students[0].prestudent_id : '-'; + return tile; + }, }, watch: { '$p.user_language.value'(n, o) { @@ -150,6 +154,8 @@ export default { + + Date: Mon, 10 Aug 2026 12:20:30 +0200 Subject: [PATCH 07/23] add db schema for gehaltsanpassungtyp --- system/dbupdate_3.4/28260_vertraege.php | 40 +++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/system/dbupdate_3.4/28260_vertraege.php b/system/dbupdate_3.4/28260_vertraege.php index 1e0e4e048..5615dc1f4 100644 --- a/system/dbupdate_3.4/28260_vertraege.php +++ b/system/dbupdate_3.4/28260_vertraege.php @@ -49,6 +49,7 @@ if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table dienstverhaeltnis_id integer NOT NULL, vertragsbestandteil_id integer, gehaltstyp_kurzbz character varying(32) NOT NULL, + gehaltsanpassungtyp_kurzbz character varying(32), von date, bis date, anmerkung text, @@ -69,6 +70,7 @@ if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table COMMENT ON COLUMN hr.tbl_gehaltsbestandteil.auszahlungen IS E'Wie oft im Jahr wird das Gehalt bezahlt. zb 14x oder nur 12x'; COMMENT ON COLUMN hr.tbl_gehaltsbestandteil.valorisierung IS E'Wird dieser Bestandteil mitvalorisiert'; COMMENT ON COLUMN hr.tbl_gehaltsbestandteil.valorisierungssperre IS E'Bis zu welchem Datum ist dieser Bestandteil von der Valorisierung ausgenommen'; + COMMENT ON COLUMN hr.tbl_gehaltsbestandteil.gehaltsanpassungtyp_kurzbz IS E'Ersteinstufung, indiv. Erhöhung, etc.'; ALTER TABLE hr.tbl_gehaltsbestandteil ADD CONSTRAINT tbl_dienstverhaeltnis_fk FOREIGN KEY (dienstverhaeltnis_id) REFERENCES hr.tbl_dienstverhaeltnis (dienstverhaeltnis_id) MATCH FULL @@ -120,6 +122,21 @@ if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table REFERENCES hr.tbl_gehaltstyp (gehaltstyp_kurzbz) MATCH FULL ON DELETE RESTRICT ON UPDATE CASCADE; + CREATE TABLE hr.tbl_gehaltsanpassungtyp + ( + gehaltsanpassungtyp_kurzbz character varying(32) NOT NULL, + bezeichnung varchar(256), + sort smallint, + aktiv boolean NOT NULL DEFAULT true, + CONSTRAINT tbl_gehaltsanpassungtyp_pk PRIMARY KEY (gehaltsanpassungtyp_kurzbz) + ); + + COMMENT ON TABLE hr.tbl_gehaltsanpassungtyp IS E'Key-Table of Salary Adaption Types'; + + ALTER TABLE hr.tbl_gehaltsbestandteil ADD CONSTRAINT tbl_gehaltsanpassungtyp_fk FOREIGN KEY (gehaltsanpassungtyp_kurzbz) + REFERENCES hr.tbl_gehaltsanpassungtyp (gehaltsanpassungtyp_kurzbz) MATCH FULL + ON DELETE RESTRICT ON UPDATE CASCADE; + CREATE TABLE hr.tbl_vertragsart ( vertragsart_kurzbz varchar(32) NOT NULL, @@ -368,6 +385,7 @@ if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table GRANT SELECT, UPDATE, INSERT, DELETE ON hr.tbl_gehaltsbestandteil TO vilesci; GRANT SELECT, UPDATE, INSERT, DELETE ON hr.tbl_gehaltshistorie TO vilesci; GRANT SELECT, UPDATE, INSERT, DELETE ON hr.tbl_gehaltstyp TO vilesci; + GRANT SELECT, UPDATE, INSERT, DELETE ON hr.tbl_gehaltsanpassungtyp TO vilesci; GRANT USAGE ON SCHEMA hr TO vilesci; GRANT USAGE ON SCHEMA hr TO web; @@ -398,6 +416,10 @@ if ($result = $db->db_query("SELECT * FROM information_schema.tables WHERE table INSERT INTO hr.tbl_gehaltstyp(gehaltstyp_kurzbz, bezeichnung, valorisierung, sort, aktiv) VALUES('lohnausgleichatz','Lohnausgleich ATZ', false, 5, true); INSERT INTO hr.tbl_gehaltstyp(gehaltstyp_kurzbz, bezeichnung, valorisierung, sort, aktiv) VALUES('zusatzvereinbarung','Zusatzvereinbarung',false, 6, true); + INSERT INTO hr.tbl_gehaltsanpassungtyp(gehaltsanpassungtyp_kurzbz, bezeichnung, sort, aktiv) VALUES('ersteinstufung','Ersteinstufung', 1, true); + INSERT INTO hr.tbl_gehaltsanpassungtyp(gehaltsanpassungtyp_kurzbz, bezeichnung, sort, aktiv) VALUES('individuelle_anpassung','Indiv. Anpassung', 2, true); + INSERT INTO hr.tbl_gehaltsanpassungtyp(gehaltsanpassungtyp_kurzbz, bezeichnung, sort, aktiv) VALUES('strukturelle_anpassung','Strukturelle Anpassung', 3, true); + INSERT INTO hr.tbl_vertragsbestandteil_freitexttyp(freitexttyp_kurzbz, bezeichnung, ueberlappend, kuendigungsrelevant) VALUES('allin','All-In', false, false); INSERT INTO hr.tbl_vertragsbestandteil_freitexttyp(freitexttyp_kurzbz, bezeichnung, ueberlappend, kuendigungsrelevant) VALUES('ersatzarbeitskraft','Ersatzarbeitskraft', false, true); INSERT INTO hr.tbl_vertragsbestandteil_freitexttyp(freitexttyp_kurzbz, bezeichnung, ueberlappend, kuendigungsrelevant) VALUES('zusatzvereinbarung','Zusatzvereinbarung', true, false); @@ -607,6 +629,24 @@ if ($result = $db->db_query("SELECT * FROM information_schema.columns WHERE colu } } + +if ($result = $db->db_query("SELECT * FROM information_schema.columns WHERE column_name='gehaltsanpassungtyp_kurzbz' AND table_name='tbl_gehaltsbestandteil' AND table_schema='hr'")) +{ + if ($db->db_num_rows($result) == 0) + { + $qry = " + ALTER TABLE + hr.tbl_gehaltsbestandteil + ADD COLUMN + gehaltsanpassungtyp_kurzbz character varying(32) + "; + if (! $db->db_query($qry)) + echo 'Vertraege: ' . $db->db_last_error() . '
'; + else + echo 'Spalte gehaltsanpassungtyp_kurzbz wurde in hr.tbl_gehaltsbestandteil neu erstellt
'; + } +} + if ($result = $db->db_query("SELECT * FROM information_schema.columns WHERE column_name='betrag' AND table_name='tbl_sachaufwand' AND table_schema='hr'")) { if ($db->db_num_rows($result) == 0) From dc5a846c10a776ab5c91fc320dd4d10dc541c729 Mon Sep 17 00:00:00 2001 From: adisposkofh Date: Mon, 10 Aug 2026 16:24:58 +0200 Subject: [PATCH 08/23] defaulting searchbar isMobile injectable to false when not provided --- public/js/components/searchbar/searchbar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/js/components/searchbar/searchbar.js b/public/js/components/searchbar/searchbar.js index 3b73c44f2..8fb4a5cd4 100644 --- a/public/js/components/searchbar/searchbar.js +++ b/public/js/components/searchbar/searchbar.js @@ -40,7 +40,7 @@ export default { query: Vue.computed(() => this.lastQuery), }; }, - inject: ["isMobile"], + inject: { isMobile: { default: false } }, data: function () { return { searchtimer: null, From 108f91ea1a5237124237e23d84e8bee7861f6049 Mon Sep 17 00:00:00 2001 From: adisposkofh Date: Mon, 10 Aug 2026 17:09:31 +0200 Subject: [PATCH 09/23] quick copy option on full name and title in profile and other lv plan --- .../api/frontend/v1/OtherLvPlan.php | 3 + .../js/components/Cis/LvPlan/OtherLvPlan.js | 35 ++++++++--- .../ProfilComponents/ProfilInformation.js | 25 ++++++++ system/phrasesupdate.php | 60 +++++++++++++++++++ 4 files changed, 115 insertions(+), 8 deletions(-) diff --git a/application/controllers/api/frontend/v1/OtherLvPlan.php b/application/controllers/api/frontend/v1/OtherLvPlan.php index af075fbc3..5b930b002 100644 --- a/application/controllers/api/frontend/v1/OtherLvPlan.php +++ b/application/controllers/api/frontend/v1/OtherLvPlan.php @@ -54,6 +54,7 @@ class OtherLvPlan extends FHCAPI_Controller $resProfileData = $this->profillib->getView($uid); $profileData = hasData($resProfileData) ? getData($resProfileData) : null; + $this->addMeta("data", $profileData->data); $viewData = [ "user_data" => [ "username" => $uid, @@ -62,6 +63,8 @@ class OtherLvPlan extends FHCAPI_Controller "foto" => $profileData->data->foto, "vorname" => $profileData->data->vorname, "nachname" => $profileData->data->nachname, + "titel" => $profileData->data->titel, + "postnomen" => $profileData->data->postnomen, ], ]; diff --git a/public/js/components/Cis/LvPlan/OtherLvPlan.js b/public/js/components/Cis/LvPlan/OtherLvPlan.js index d1caebc90..6c70e1c93 100644 --- a/public/js/components/Cis/LvPlan/OtherLvPlan.js +++ b/public/js/components/Cis/LvPlan/OtherLvPlan.js @@ -32,7 +32,7 @@ export default { listGroup: [], rangeIntervalFirst: null, otherPersonData: { - fullName: "", + fullNameWithTitle: "", photo: "", }, timezone: FHC_JS_DATA_STORAGE_OBJECT.timezone, @@ -210,10 +210,17 @@ export default { this.isOtherPersonMitarbeiter = !!viewData?.user_data?.is_mitarbeiter; this.isOtherPersonStudent = !!viewData?.user_data?.is_student; - this.otherPersonData.fullName = - viewData?.user_data?.vorname + - " " + - viewData?.user_data?.nachname; + let fullNameWithTitleFragments = [ + viewData?.user_data?.titel, + viewData?.user_data?.vorname, + viewData?.user_data?.nachname, + viewData?.user_data?.postnomen, + ]; + fullNameWithTitleFragments = fullNameWithTitleFragments.filter( + (fragment) => !!fragment, + ); + this.otherPersonData.fullNameWithTitle = + fullNameWithTitleFragments.join(" "); this.otherPersonData.photo = viewData?.user_data?.foto; }, async redirectToMyLvPlanIfAuthUid() { @@ -225,12 +232,21 @@ export default { this.$router.push({ name: "MyLvPlan" }); } }, + copyFullNameWithTitleToClipboard() { + navigator.clipboard.writeText( + this.otherPersonData.fullNameWithTitle, + ); + this.$fhcAlert.alertSuccess( + this.$p.t("profil/name_title_clipboard_copy_confirmation"), + ); + }, }, async created() { await this.redirectToMyLvPlanIfAuthUid(); await this.fetchViewData(); + await this.$p.loadCategory(["profil"]); }, - template: ` + template: /*html*/ `

@@ -238,8 +254,11 @@ export default { {{ $p.t('lehre/stundenplan') + (studiensemester_kurzbz ? " " + studiensemester_kurzbz : "") }}
- - {{ otherPersonData.fullName }} + + {{ otherPersonData.fullNameWithTitle }} + + + profile picture
diff --git a/public/js/components/Cis/Profil/ProfilComponents/ProfilInformation.js b/public/js/components/Cis/Profil/ProfilComponents/ProfilInformation.js index d714c9faa..2df4024ca 100644 --- a/public/js/components/Cis/Profil/ProfilComponents/ProfilInformation.js +++ b/public/js/components/Cis/Profil/ProfilComponents/ProfilInformation.js @@ -67,6 +67,21 @@ export default { return res; }, }, + methods: { + copyFullNameWithTitleToClipboard() { + let fragments = [ + this.$props.data.Titel, + this.$props.data.Vorname, + this.$props.data.Nachname, + this.$props.data.Postnomen, + ]; + fragments = fragments.filter((fragment) => !!fragment); + navigator.clipboard.writeText(fragments.join(" ")); + this.$fhcAlert.alertSuccess( + this.$p.t("profil/name_title_clipboard_copy_confirmation"), + ); + }, + }, template: /*html*/ `
@@ -124,6 +139,16 @@ export default { {{wert?wert:'-'}}
+ + + + + {{ $p.t("profil/name_title_copy") }} +

diff --git a/system/phrasesupdate.php b/system/phrasesupdate.php index 8630fe31a..1cda99fc5 100644 --- a/system/phrasesupdate.php +++ b/system/phrasesupdate.php @@ -29742,6 +29742,46 @@ array( ) ) ), + array( + 'app' => 'core', + 'category' => 'profil', + 'phrase' => 'name_title_clipboard_copy_confirmation', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Name mit Titel in die Zwischenablage kopiert.', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Full name with title copied to clipboard.', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), + array( + 'app' => 'core', + 'category' => 'profil', + 'phrase' => 'name_title_copy', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Name mit Titel kopieren', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Copy full name with title', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), array( 'app' => 'core', 'category' => 'profil', @@ -60832,6 +60872,26 @@ I have been informed that I am under no obligation to consent to the transmissio ) ) ), + array( + 'app' => 'core', + 'category' => 'LvPlan', + 'phrase' => 'copy', + 'insertvon' => 'system', + 'phrases' => array( + array( + 'sprache' => 'German', + 'text' => 'Kopieren', + 'description' => '', + 'insertvon' => 'system' + ), + array( + 'sprache' => 'English', + 'text' => 'Copy', + 'description' => '', + 'insertvon' => 'system' + ) + ) + ), // ### LvPlanStgOrg END ### // DMS-Link Phrasen Start array( From 59ac56374e078b10021694d737d04204a730cd38 Mon Sep 17 00:00:00 2001 From: adisposkofh Date: Tue, 11 Aug 2026 09:44:41 +0200 Subject: [PATCH 10/23] removed redundant response meta used for dev --- application/controllers/api/frontend/v1/OtherLvPlan.php | 1 - 1 file changed, 1 deletion(-) diff --git a/application/controllers/api/frontend/v1/OtherLvPlan.php b/application/controllers/api/frontend/v1/OtherLvPlan.php index 5b930b002..1807f0a4a 100644 --- a/application/controllers/api/frontend/v1/OtherLvPlan.php +++ b/application/controllers/api/frontend/v1/OtherLvPlan.php @@ -54,7 +54,6 @@ class OtherLvPlan extends FHCAPI_Controller $resProfileData = $this->profillib->getView($uid); $profileData = hasData($resProfileData) ? getData($resProfileData) : null; - $this->addMeta("data", $profileData->data); $viewData = [ "user_data" => [ "username" => $uid, From d66fe72cc9ddcd06ab34fd2f94b020392cef7331 Mon Sep 17 00:00:00 2001 From: Werner Masik Date: Tue, 11 Aug 2026 11:18:36 +0200 Subject: [PATCH 11/23] =?UTF-8?q?add=20field=20for=20salary=20adaption=20t?= =?UTF-8?q?ype=20(Ersteinstufung,=20indiv.=20Erh=C3=B6hung,=20..)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Gehaltsbestandteil.php | 19 +++++++++++++++++++ .../Gehaltsbestandteil_model.php | 8 +++++++- public/vendor | 1 + 3 files changed, 27 insertions(+), 1 deletion(-) create mode 120000 public/vendor diff --git a/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php b/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php index 95bbdd908..aeaa52c8e 100644 --- a/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php +++ b/application/libraries/vertragsbestandteil/Gehaltsbestandteil.php @@ -13,6 +13,7 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl protected $dienstverhaeltnis_id; protected $vertragsbestandteil_id; protected $gehaltstyp_kurzbz; + protected $gehaltsanpassungtyp_kurzbz = ''; protected $von; protected $bis; protected $anmerkung; @@ -39,6 +40,10 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl isset($data->dienstverhaeltnis_id) && $this->setDienstverhaeltnis_id($data->dienstverhaeltnis_id); isset($data->vertragsbestandteil_id) && $this->setVertragsbestandteil_id($data->vertragsbestandteil_id); isset($data->gehaltstyp_kurzbz) && $this->setGehaltstyp_kurzbz($data->gehaltstyp_kurzbz); + //isset($data->gehaltsanpassungtyp_kurzbz) && $this->setGehaltsanpassungtyp_kurzbz($data->gehaltsanpassungtyp_kurzbz); + if (!empty($data->gehaltsanpassungtyp_kurzbz)) { + $this->setGehaltsanpassungtyp_kurzbz($data->gehaltsanpassungtyp_kurzbz); + } isset($data->von) && $this->setVon($data->von); isset($data->bis) && $this->setBis($data->bis); isset($data->anmerkung) && $this->setAnmerkung($data->anmerkung); @@ -75,6 +80,11 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl return $this->gehaltstyp_kurzbz; } + public function getGehaltsanpassungtyp_kurzbz() + { + return $this->gehaltsanpassungtyp_kurzbz; + } + public function getVon() { return $this->von; @@ -178,6 +188,13 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl return $this; } + public function setGehaltsanpassungtyp_kurzbz($gehaltsanpassungtyp_kurzbz) + { + $this->markDirty('gehaltsanpassungtyp_kurzbz', $this->gehaltsanpassungtyp_kurzbz, $gehaltsanpassungtyp_kurzbz); + $this->gehaltsanpassungtyp_kurzbz = $gehaltsanpassungtyp_kurzbz; + return $this; + } + public function setVon($von) { $this->markDirty('von', $this->von, $von); @@ -284,6 +301,7 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl 'dienstverhaeltnis_id' => $this->getDienstverhaeltnis_id(), 'vertragsbestandteil_id' => $this->getVertragsbestandteil_id(), 'gehaltstyp_kurzbz' => $this->getGehaltstyp_kurzbz(), + 'gehaltsanpassungtyp_kurzbz' => $this->getGehaltsanpassungtyp_kurzbz(), 'von' => $this->getVon(), 'bis' => $this->getBis(), 'anmerkung' => $this->getAnmerkung(), @@ -312,6 +330,7 @@ class Gehaltsbestandteil extends AbstractBestandteil implements \JsonSerializabl dienstverhaeltnis_id: {$this->getDienstverhaeltnis_id()} vertragsbestandteil_id: {$this->getVertragsbestandteil_id()} gehaltstyp_kurzbz: {$this->getGehaltstyp_kurzbz()} + gehaltsanpassungtyp_kurzbz: {$this->getGehaltsanpassungtyp_kurzbz()} von: {$this->getVon()} bis: {$this->getBis()} anmerkung: {$this->getAnmerkung()} diff --git a/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php b/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php index 2669105a1..21939fda0 100644 --- a/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php +++ b/application/models/vertragsbestandteil/Gehaltsbestandteil_model.php @@ -41,6 +41,7 @@ with gbt as ( gb.anmerkung, gb.dienstverhaeltnis_id, gb.gehaltstyp_kurzbz, + gb.gehaltsanpassungtyp_kurzbz, gb.valorisierungssperre, gb.valorisierung, gb.grundbetrag as grund_betrag_decrypted, @@ -76,11 +77,13 @@ select gbt.anmerkung, gbt.dienstverhaeltnis_id, gbt.gehaltstyp_kurzbz, + gbt.gehaltsanpassungtyp_kurzbz, gbt.valorisierungssperre, gbt.valorisierung, gbt.grund_betrag_decrypted, gbt.betrag_val_decrypted, gt.bezeichnung as gehaltstyp_bezeichnung, + ga.bezeichnung as gehaltsanpassungtyp_bezeichnung, vb.vertragsbestandteiltyp_kurzbz, bf.funktion_kurzbz, bf.oe_kurzbz, @@ -93,6 +96,8 @@ from gbt LEFT JOIN hr.tbl_gehaltstyp gt using(gehaltstyp_kurzbz) +LEFT JOIN + hr.tbl_gehaltsanpassungtyp ga using(gehaltsanpassungtyp_kurzbz) LEFT JOIN hr.tbl_vertragsbestandteil vb using(vertragsbestandteil_id) LEFT JOIN @@ -202,6 +207,7 @@ SELECT g.dienstverhaeltnis_id, g.vertragsbestandteil_id, g.gehaltstyp_kurzbz, + g.gehaltsanpassungtyp_kurzbz, g.von, g.bis, g.anmerkung, @@ -263,7 +269,7 @@ EOSQL; // Note: replaced gb.betrag_valorisiert with vh.betrag_valorisiert! $qry = " SELECT - gb.gehaltsbestandteil_id,gb.dienstverhaeltnis_id,gb.vertragsbestandteil_id,gb.gehaltstyp_kurzbz, + gb.gehaltsbestandteil_id,gb.dienstverhaeltnis_id,gb.vertragsbestandteil_id,gb.gehaltstyp_kurzbz,gb.gehaltsanpassungtyp_kurzbz, gb.von,gb.bis,gb.anmerkung,gb.grundbetrag as grundbetrag,gb.valorisierungssperre,gb.insertamum, gb.insertvon,gb.updateamum,gb.updatevon,gb.valorisierung,gb.auszahlungen, vh.valorisierungsdatum, vh.betrag_valorisiert as betrag_valorisiert diff --git a/public/vendor b/public/vendor new file mode 120000 index 000000000..9c39cc9f8 --- /dev/null +++ b/public/vendor @@ -0,0 +1 @@ +../vendor \ No newline at end of file From 772b8c603caf06921a953b4c63a57276fcce483f Mon Sep 17 00:00:00 2001 From: adisposkofh Date: Tue, 11 Aug 2026 15:50:24 +0200 Subject: [PATCH 12/23] fixed issue with ineffective localization of courses in 'degree programs' page --- public/js/components/Cis/Studium/Studium.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/js/components/Cis/Studium/Studium.js b/public/js/components/Cis/Studium/Studium.js index c70646608..721fec8ad 100644 --- a/public/js/components/Cis/Studium/Studium.js +++ b/public/js/components/Cis/Studium/Studium.js @@ -381,13 +381,13 @@ export default {