diff --git a/src-modules/module/rpta/conf/rpta.xml b/src-modules/module/rpta/conf/rpta.xml
index b54b850..8dd83b3 100644
--- a/src-modules/module/rpta/conf/rpta.xml
+++ b/src-modules/module/rpta/conf/rpta.xml
@@ -329,6 +329,12 @@ parent="Berichtsassistent">Abfragen zur Administration von Berichtsassistent $RPTA_PFAD/masken
+
+ Leistungen und Studiengänge
+
+ $RPTA_PFAD/masken
+
+
@@ -429,6 +435,14 @@ parent="Berichtsassistent">Abfragen zur Administration von Berichtsassistent
+
+
+
+
+
+
+
+
@@ -477,6 +491,7 @@ scriptfile="" database=""/>
+
@@ -518,6 +533,7 @@ scriptfile="" database=""/>
+
diff --git a/src-modules/module/rpta/masken/48140_felderinfo.unl b/src-modules/module/rpta/masken/48140_felderinfo.unl
new file mode 100644
index 0000000..4528e77
--- /dev/null
+++ b/src-modules/module/rpta/masken/48140_felderinfo.unl
@@ -0,0 +1,28 @@
+48140^Spaltenlayout^3000^350^-1^140^180^1^char^30^1^1^<>SELECT uniquename,\
+ caption\
+FROM rpta_column_layout \
+where resultset_id in (select R.tid from rpta_resultset R where R.uniquename='rpta_exam_unit_dim_studiengang'\
+)\
+order by sortnr, caption\
+ ;^ ^<>SELECT uniquename,\
+ caption\
+FROM rpta_column_layout \
+where resultset_id in (select R.tid from rpta_resultset R where R.uniquename='rpta_exam_unit_dim_studiengang'\
+) and uniquename='rpta_exam_unit_dim_studiengang_note';^
+48141^Seit Semester^10^0^0^140^80^1^integer^30^0^1^<> select tid, eintrag from semester order by tid DESC;^ ^<> select tid,eintrag from semester where today() between sem_beginn and sem_ende;^
+48142^Fächer^30^0^0^130^200^6^char^1000^0^999^<> select tid,name,sortnr from sichten where art='Fächer-Sicht' order by 3,2;^ ^ ^
+48143^Abschluss^40^0^0^100^200^3^char^1500^0^999^<> select apnr, druck from cifx where key=35 order by 2;^ ^ ^
+48144^bis Fachsemester^1000^300^-1^200^100^1^integer^30^0^0^^ ^ ^
+48145^Semestertyp^22^350^-1^140^80^1^integer^255^0^1^<> select 1,'nur Sommersemester' from xdummy union select 2,'nur Wintersemester' from xdummy^Eintrag^<> select 2,'nur Wintersemester' from xdummy^
+48146^Hochschulzugangsberechtigung^120^300^-1^200^200^1^sql^30^0^999^hs_zugangsber^apnr, eintrag^ ^
+48147^Bis Semester^20^350^-1^140^80^1^integer^30^0^1^<> select tid, eintrag from semester order by tid DESC;^ ^<> select tid,eintrag from semester where today() between sem_beginn and sem_ende;^
+48148^Staatsangehörigkeit^150^0^0^140^150^10^char^30^0^999^<> select tid,name,sortnr from sichten where art='SOS-Staaten-Sicht' order by 3,2;^ ^ ^
+48149^Studiengang^25^0^0^140^150^50^char^1000^0^999^<> select tid,name,sortnr from sichten where art in ('SOS-Kostenstellen-Sicht', 'SOS-Studiengang-Sicht') order by 3,2;^ ^ ^
+48151^Stichtag^23^330^-1^130^100^1^sql^30^1^999^<> select tid, name from sos_stichtag where stichtagsart='Studierende';^ ^<> select tid, name from sos_stichtag where stichtagsart='Studierende' and appl_key='0';^
+48152^Hörerstatus^200^330^-1^140^150^1^sql^30^0^999^<> select apnr, eintrag from hoererstatus order by 2^apnr, eintrag^<> select apnr, eintrag from hoererstatus where eintrag='alle';^
+48158^Köpfe oder Fälle ?^0^0^0^140^150^1^sql^70^0^999^<> select apnr, eintrag from koepfe_oder_faelle order by 2^apnr, eintrag^<> select apnr, eintrag from koepfe_oder_faelle where eintrag = 'Fälle';^
+48162^Geschlecht^110^0^0^140^80^1^integer^30^0^999^<> SELECT apnr,druck FROM cif where key = 9003 and apnr between 1 and 4 order by 1;^ ^ ^
+48163^Spalten^3001^0^0^150^190^10^char^30^0^1^<>\
+select C.uniquename, C.caption ,L.layout_id from rpta_column C, rpta_column2layout L where C.tid=L.column_id and layout_id in\
+(select tid from rpta_column_layout where uniquename=<>) order by 2;^ ^ ^
+48164^Fächer^30^0^0^130^200^6^char^1000^1^1^<> select stg,dtxt from k_stg order by 2;^ ^ ^
diff --git a/src-modules/module/rpta/masken/48140_maske_system_bez.unl b/src-modules/module/rpta/masken/48140_maske_system_bez.unl
new file mode 100644
index 0000000..2aa999c
--- /dev/null
+++ b/src-modules/module/rpta/masken/48140_maske_system_bez.unl
@@ -0,0 +1 @@
+48140^7^
diff --git a/src-modules/module/rpta/masken/48140_masken_felder_bez.unl b/src-modules/module/rpta/masken/48140_masken_felder_bez.unl
new file mode 100644
index 0000000..3a20f93
--- /dev/null
+++ b/src-modules/module/rpta/masken/48140_masken_felder_bez.unl
@@ -0,0 +1,16 @@
+48140^48140^
+48140^48141^
+48140^48142^
+48140^48143^
+48140^48144^
+48140^48145^
+48140^48146^
+48140^48147^
+48140^48148^
+48140^48149^
+48140^48151^
+48140^48152^
+48140^48158^
+48140^48162^
+48140^48163^
+48140^48164^
diff --git a/src-modules/module/rpta/masken/48140_maskeninfo.unl b/src-modules/module/rpta/masken/48140_maskeninfo.unl
new file mode 100644
index 0000000..339b2e6
--- /dev/null
+++ b/src-modules/module/rpta/masken/48140_maskeninfo.unl
@@ -0,0 +1,216 @@
+48140^Leistungen und Studiengänge (Makro)^--Freemarker Template\
+<#include "SQL_lingua_franca"/>\
+<#include "SuperX_general"/>\
+--\
+--Autor D. Quathamer 2024\
+\
+\
+SELECT distinct name,\
+0::smallint as is_virtual,\
+name as runtime_tablename\
+ from sx_tables\
+ where name in ('${my_base_rs}')\
+ and 0=(select count(*) from rpta_resultset R where R.uniquename='${my_base_rs}')\
+ union\
+ select R.uniquename,\
+ 1::smallint as is_virtual,\
+ 'tmp_' || R.uniquename as runtime_tablename\
+ from rpta_resultset R where R.uniquename='${my_base_rs}'\
+ ;\
+ ]]>\
+\
+\
+>;\
+\
+]]>\
+>\
+/* and C.uniquename in (<>) */\
+order by CL.sortnr\
+ ;\
+]]>\
+\
+\
+<#assign filter="1=1\
+/* and sem_der_pruefung >= <> */\
+/* and sem_der_pruefung <= <> */\
+/* and sem_der_pruefung = <> */\
+/* and substring('' || sem_der_pruefung from 5 for 1)='<>' */\
+/* and fach_sem_zahl <= <> */\
+" />\
+\
+<#assign filter = filter + " and 's_' || tid_stg in "+Studiengang.allNeededKeysList /> \
+<#assign filter = filter + " and tid_stg in (select tid from lehr_stg_ab where stg in "+Fächer.allNeededKeysList +")"/> \
+\
+<#if columns?has_content>\
+\
+<#if basetable.is_virtual==1>\
+\
+create temp table ${basetable.runtime_tablename} as\
+select ${rpta_resultset.fieldclause} \
+from ${rpta_resultset.joinclause} \
+where 1=1\
+<#if rpta_resultset.whereclause != ""> \
+${rpta_resultset.whereclause} #if>\
+and ${filter}\
+;\
+#if>\
+\
+\
+\
+select \
+--zuerst die Basisdaten:\
+<#foreach column in columns>\
+<#if column.coltype="physicalColumn">\
+${column.srcfieldname} as ${column.srcfieldname},\
+<#elseif column.coltype="logicalColumn">\
+${column.colfunction} as ${column.targetfieldname},\
+<#elseif column.coltype="lookupColumn">\
+(${column.colfunction}) as ${column.targetfieldname},\
+<#elseif column.coltype="computedColumn" || column.coltype=="processingColumn">\
+null::decimal(19,6) as ${column.targetfieldname},\
+#if>\
+#foreach>\
+null::char(1) as dummycol\
+into temp tmp_stud\
+from ${basetable.runtime_tablename}\
+<#if rpta_column_layout.whereclause !="">\
+where ${rpta_column_layout.whereclause}\
+#if>\
+;\
+\
+--ergebnistabelle:\
+select \
+--zuerst die nicht-Aggregate:\
+<#assign groupby=0 />\
+<#foreach column in columns>\
+-- logicalColumns ausgeschlossen, da sie von processingColumns aggregiert werden\
+-- computedColumns immer mitnehmen, da später verarbeitet\
+<#if column.is_aggregate==0 && column.coltype!="logicalColumn" && column.coltype!="processingColumn" || column.coltype="computedColumn"> \
+<#assign groupby=groupby+1 />\
+${column.targetfieldname},\
+<#elseif column.is_aggregate==0 && column.coltype="processingColumn"> \
+<#assign groupby=groupby+1 />\
+${column.srcfieldname} as ${column.targetfieldname},\
+#if>\
+#foreach>\
+--dann die Aggregate:\
+<#foreach column in columns>\
+-- logicalColumns ausgeschlossen, da sie von processingColumns aggregiert werden\
+-- computedColumns ausgeschlossen, da später im finalen select verarbeitet\
+<#if column.is_aggregate==1 && column.coltype!="computedColumn" && column.coltype!="logicalColumn"> \
+${column.colfunction}(${column.srcfieldname}) as ${column.targetfieldname},\
+#if>\
+#foreach>\
+null::char(1) as dummycol\
+into temp tmp_stud2\
+from tmp_stud\
+where 1=1\
+/* ${<>} */\
+group by\
+<#list 1..groupby as i>${i}\
+<#if i != groupby>\
+,\
+#if>\
+#list>\
+;\
+--für Prozentwerte alle Aggregate summieren:\
+select <#foreach column in columns>\
+<#if column.is_aggregate==1 && column.coltype!="computedColumn" && column.coltype!="processingColumn">\
+sum(${column.targetfieldname})::float as ${column.targetfieldname},\
+#if>\
+#foreach>\
+null::char(1) as dummycol\
+into temp tmp_gesamt\
+from tmp_stud2\
+where 1=1\
+;\
+\
+<#assign number_of_visible_colums=0 />\
+<#foreach column in columns>\
+<#if column.is_visible!=0>\
+<#assign number_of_visible_colums=number_of_visible_colums+1 />\
+#if>\
+#foreach>\
+<#assign colnr=0 />\
+select \
+<#foreach column in columns>\
+<#if column.is_visible!=0>\
+<#assign colnr=colnr+1 />\
+<#assign format_sql="" />\
+<#if column.format_sql?string != "">\
+<#assign format_sql=column.format_sql />\
+#if>\
+\
+<#if column.coltype=="computedColumn">\
+(${column.colfunction})${format_sql} as ${column.targetfieldname}\
+<#else>\
+${column.targetfieldname}${format_sql} as ${column.targetfieldname}\
+#if>\
+\
+<#if colnr < number_of_visible_colums>,#if>\
+#if> --wenn sichtbar\
+#foreach>\
+from tmp_stud2\
+order by <#list 1..number_of_visible_colums as i>${i}\
+<#if i != number_of_visible_colums>\
+,\
+#if>\
+#list>\
+;\
+<#if basetable.is_virtual==1>\
+drop table if exists ${basetable.runtime_tablename};\
+#if>\
+\
+\
+drop table if exists tmp_stud;\
+drop table if exists tmp_stud2;\
+drop table if exists tmp_gesamt;\
+\
+\
+#if> --wenn columns?has_content^--Freemarker Template\
+ XIL List\
+ sizable_columns horizontal_scrolling\
+ drop_and_delete movable_columns \
+ white_space_color=COLOR_WHITE fixed_columns=1\
+ min_heading_height=55\
+<#foreach column in columns>\
+<#if column.is_visible!=0>\
+Column CID=0 heading_text="${column.caption}" center_heading explanation="${column.description}"\
+ row_selectable heading_platform readonly\
+ width=${column.visible_width} text_size=60\
+#if>\
+#foreach>\
+@@@^Studienfach^Anzahl bzw. Anteil^Makrobericht zur Ausgabe nach Fächern^drop table if exists tmp_stud2; drop table if exists tmp_stud3;^^2^850^540^^1^<>SELECT description FROM rpta_column_layout where tid=<>;^
diff --git a/src-modules/module/rpta/masken/48140_sachgeb_maske_bez.unl b/src-modules/module/rpta/masken/48140_sachgeb_maske_bez.unl
new file mode 100644
index 0000000..9adc3c1
--- /dev/null
+++ b/src-modules/module/rpta/masken/48140_sachgeb_maske_bez.unl
@@ -0,0 +1 @@
+16^48140^
diff --git a/src-modules/module/rpta/schluesseltabellen/macro_masken_bez_fuellen.sql b/src-modules/module/rpta/schluesseltabellen/macro_masken_bez_fuellen.sql
new file mode 100644
index 0000000..5a25845
--- /dev/null
+++ b/src-modules/module/rpta/schluesseltabellen/macro_masken_bez_fuellen.sql
@@ -0,0 +1,133 @@
+--freemarker template
+<#assign makros = [
+{"tid":"48140"}
+] />
+<#assign masken = [
+{"makro":"48140", "tid":"48110", "sortnr":"10", "schleifenrelation":"<>select ''s_'' || tid,text from lehr_stg_ab where stg in (<>) order by 2",
+ "schleifenfeldname":"Studiengang","schleifenfstand":"12.03.2025", "schleifenfsicht":"<>"}
+] />
+<#assign felder = [
+] />
+
+-- ab hier nicht mehr ändern:
+CREATE TEMP TABLE tmp_macro_masken_bez (
+ maskeninfo_id1 integer NOT NULL,
+ maskeninfo_id2 integer NOT NULL,
+ active integer DEFAULT 1 NOT NULL,
+ sortnr smallint NOT NULL,
+ schleifenrelation character(255),
+ schleifenfeldname character(255),
+ alias character(255),
+ schleifenfstand character(255),
+ schleifenfsicht character(255),
+ aktion character(255)
+);
+CREATE TEMP TABLE tmp_macro_feld_wert (
+ macro integer NOT NULL,
+ sortnr integer NOT NULL,
+ feldname character(255) NOT NULL,
+ alias character(255) NOT NULL,
+ value character(255),
+ value_caption character(255),
+ feldstand character(255),
+ feldsicht character(255),
+ active integer DEFAULT 1 NOT NULL
+);
+<#foreach makro in makros>
+<#foreach maske in masken>
+<#if maske.makro==makro.tid>
+insert into tmp_macro_masken_bez(maskeninfo_id1,
+ maskeninfo_id2,
+ active,
+ sortnr,
+ schleifenrelation,
+ schleifenfeldname,
+ schleifenfstand,
+ schleifenfsicht)
+select ${makro.tid},--maskeninfo_id1,
+ ${maske.tid},--maskeninfo_id2,
+ 1,--active,
+ ${maske.sortnr}, --sortnr,
+ '${maske.schleifenrelation}', --schleifenrelation,
+ '${maske.schleifenfeldname}', --schleifenfeldname,
+ '${maske.schleifenfstand}', --schleifenfstand,
+ '${maske.schleifenfsicht}' --schleifenfsicht
+ from xdummy;
+
+<#foreach feld in felder>
+<#if feld.makro==makro.tid && feld.sortnr==maske.sortnr>
+--Tab.12: alle ohne Exmatr
+insert into tmp_macro_feld_wert
+( macro,
+ sortnr,
+ feldname,
+ alias,
+ value,
+ value_caption,
+ feldstand,
+ feldsicht,
+ active)
+ SELECT ${makro.tid}, --macro
+ ${maske.sortnr},--sortnr
+ '${feld.feldname}',--feldname,
+ '',--alias,
+ '${feld.value}', --value,
+ '',--value_caption,
+ '', --feldstand,
+ '',--feldsicht,
+ 1 --active
+FROM xdummy;
+#if>
+#foreach>
+#if>
+#foreach>
+#foreach>
+
+delete from macro_masken_bez where maskeninfo_id1 in (select maskeninfo_id1 from tmp_macro_masken_bez)
+;
+insert into macro_masken_bez
+(maskeninfo_id1,
+ maskeninfo_id2,
+ active,
+ sortnr,
+ schleifenrelation,
+ schleifenfeldname,
+ alias,
+ schleifenfstand,
+ schleifenfsicht,
+ aktion)
+select maskeninfo_id1,
+ maskeninfo_id2,
+ active,
+ sortnr,
+ schleifenrelation,
+ schleifenfeldname,
+ alias,
+ schleifenfstand,
+ schleifenfsicht,
+ aktion
+FROM tmp_macro_masken_bez
+;
+delete from macro_feld_wert where macro in (select macro from tmp_macro_feld_wert);
+insert into macro_feld_wert
+( macro,
+ sortnr,
+ feldname,
+ alias,
+ value,
+ value_caption,
+ feldstand,
+ feldsicht,
+ active)
+ SELECT macro,
+ sortnr,
+ feldname,
+ alias,
+ value,
+ value_caption,
+ feldstand,
+ feldsicht,
+ active
+FROM tmp_macro_feld_wert;
+drop table tmp_macro_masken_bez;
+drop table tmp_macro_feld_wert;
\ No newline at end of file