Merge remote-tracking branch 'origin/main' into feature/member-overview-groups
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/promote/production Build is passing

This commit is contained in:
Simon 2026-02-16 15:57:57 +01:00
commit 6831ba046f
Signed by: simon
GPG key ID: 40E7A58C4AA1EDB2
48 changed files with 3516 additions and 182 deletions

5
priv/fonts/.gitkeep Normal file
View file

@ -0,0 +1,5 @@
# This file ensures the fonts directory is tracked by git
# Place TTF font files here

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -150,9 +150,11 @@ msgstr "Hausnummer"
msgid "Notes"
msgstr "Notizen"
#: lib/mv/membership/members_pdf.ex
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/statistics_live.ex
#: lib/mv_web/member_live/index/membership_fee_status.ex
#, elixir-autogen, elixir-format
msgid "Paid"
@ -318,6 +320,7 @@ msgstr "Benutzer*innen auflisten"
#: lib/mv_web/live/member_live/index.ex
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Members"
msgstr "Mitglieder"
@ -762,6 +765,7 @@ msgstr "Dieses Feld darf nicht leer bleiben"
#: lib/mv_web/components/core_components.ex
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "All"
msgstr "Alle"
@ -929,16 +933,20 @@ msgstr "Vierteljährlich"
msgid "Status"
msgstr "Status"
#: lib/mv/membership/members_pdf.ex
#: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/statistics_live.ex
#: lib/mv_web/member_live/index/membership_fee_status.ex
#, elixir-autogen, elixir-format
msgid "Suspended"
msgstr "Pausiert"
#: lib/mv/membership/members_pdf.ex
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/statistics_live.ex
#: lib/mv_web/member_live/index/membership_fee_status.ex
#, elixir-autogen, elixir-format
msgid "Unpaid"
@ -2388,17 +2396,12 @@ msgstr "Mitgliederdaten verwalten"
msgid "Use the data field name as the CSV column header in your file. Data fields must exist in Mila before importing, so they must be listed in the list of member data (like e-mail or first name). Unknown data field columns will be ignored with a warning."
msgstr "Verwende die Namen der Datenfelder als Spaltennamen in der CSV Datei. Datenfelder müssen in Mila bereits angelegt sein, damit sie importiert werden können. sie müssen in der Liste der Mitgliederdaten als Datenfeld enthalten sein (z.B. E-Mail). Spalten mit unbekannten Spaltenüberschriften werden mit einer Warnung ignoriert."
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Export members to CSV"
msgstr "Mitglieder importieren (CSV)"
#: lib/mv_web/live/member_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Export to CSV"
msgstr "Nach CSV exportieren"
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "all"
msgstr "alle"
@ -2474,3 +2477,148 @@ msgstr "Unbezahlt"
#, elixir-autogen, elixir-format
msgid "Member of group %{name}"
msgstr "Mitglied der Gruppe %{name}"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Active members"
msgstr "Aktive Mitglieder"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Exits"
msgstr "Austritte"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Inactive members"
msgstr "Inaktive Mitglieder"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Joins"
msgstr "Eintritte"
#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Statistics"
msgstr "Statistik"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Total"
msgstr "Gesamt"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Year"
msgstr "Jahr"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Contributions pie: paid %{paid}%%, unpaid %{unpaid}%%, suspended %{suspended}%%"
msgstr "Beiträge Kreis: bezahlt %{paid}%, unbezahlt %{unpaid}%, pausiert %{suspended}%"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "All years combined (pie)"
msgstr "Alle Jahre zusammengefasst (Kreis)"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Contributions by year"
msgstr "Beiträge nach Jahr"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Overview from first membership to today"
msgstr "Übersicht vom ersten Eintritt bis heute"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Contributions by year as table with stacked bars"
msgstr "Beiträge nach Jahr als Tabelle mit gestapelten Balken"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Contributions"
msgstr "Beiträge"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Fee type"
msgstr "Beitragsart"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Member numbers by year"
msgstr "Mitgliederzahlen nach Jahr"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "From %{first} to %{last} (relevant years with membership data)"
msgstr "Von %{first} bis %{last} (Jahre mit Mitgliederdaten)"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Member numbers by year as table with bars"
msgstr "Mitgliederzahlen nach Jahr als Tabelle mit Balken"
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Fee types could not be loaded."
msgstr "Beitragsarten konnten nicht geladen werden."
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "CSV"
msgstr "CSV"
#: lib/mv/membership/members_pdf.ex
#, elixir-autogen, elixir-format
msgid "Created at:"
msgstr "Erstellt am:"
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Export"
msgstr "Nach CSV exportieren"
#: lib/mv_web/controllers/member_pdf_export_controller.ex
#, elixir-autogen, elixir-format
msgid "Export contains %{count} rows, maximum is %{max}"
msgstr "Export enthält %{count} Zeilen, Maximum ist %{max}"
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Export members to PDF"
msgstr "Mitglieder als PDF exportieren"
#: lib/mv_web/controllers/member_pdf_export_controller.ex
#, elixir-autogen, elixir-format
msgid "Failed to generate PDF export"
msgstr "Erstellen des PDF Exports ist gescheitert"
#: lib/mv/membership/members_pdf.ex
#, elixir-autogen, elixir-format
msgid "Member %{club_name}"
msgstr "Mitglieder %{club_name}"
#: lib/mv/membership/members_pdf.ex
#, elixir-autogen, elixir-format
msgid "Member count:"
msgstr "Anzahl Mitglieder:"
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "PDF"
msgstr "PDF"
#~ #: lib/mv_web/live/global_settings_live.ex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Custom Fields in CSV Import"
#~ msgstr "Benutzerdefinierte Felder"
#~ #, elixir-autogen, elixir-format
#~ msgid "Failed to prepare CSV import: %{error}"
#~ msgstr "Das Vorbereiten des CSV Imports ist gescheitert: %{error}"

View file

@ -151,9 +151,11 @@ msgstr ""
msgid "Notes"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/statistics_live.ex
#: lib/mv_web/member_live/index/membership_fee_status.ex
#, elixir-autogen, elixir-format
msgid "Paid"
@ -319,6 +321,7 @@ msgstr ""
#: lib/mv_web/live/member_live/index.ex
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Members"
msgstr ""
@ -763,6 +766,7 @@ msgstr ""
#: lib/mv_web/components/core_components.ex
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "All"
msgstr ""
@ -930,16 +934,20 @@ msgstr ""
msgid "Status"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/statistics_live.ex
#: lib/mv_web/member_live/index/membership_fee_status.ex
#, elixir-autogen, elixir-format
msgid "Suspended"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/statistics_live.ex
#: lib/mv_web/member_live/index/membership_fee_status.ex
#, elixir-autogen, elixir-format
msgid "Unpaid"
@ -2389,17 +2397,12 @@ msgstr ""
msgid "Use the data field name as the CSV column header in your file. Data fields must exist in Mila before importing, so they must be listed in the list of member data (like e-mail or first name). Unknown data field columns will be ignored with a warning."
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "Export members to CSV"
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Export to CSV"
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "all"
msgstr ""
@ -2475,3 +2478,139 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Member of group %{name}"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Active members"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Exits"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Inactive members"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Joins"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Statistics"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Total"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Year"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Contributions pie: paid %{paid}%%, unpaid %{unpaid}%%, suspended %{suspended}%%"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "All years combined (pie)"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Contributions by year"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Overview from first membership to today"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Contributions by year as table with stacked bars"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Contributions"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Fee type"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Member numbers by year"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "From %{first} to %{last} (relevant years with membership data)"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Member numbers by year as table with bars"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Fee types could not be loaded."
msgstr ""
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "CSV"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#, elixir-autogen, elixir-format
msgid "Created at:"
msgstr ""
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "Export"
msgstr ""
#: lib/mv_web/controllers/member_pdf_export_controller.ex
#, elixir-autogen, elixir-format
msgid "Export contains %{count} rows, maximum is %{max}"
msgstr ""
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "Export members to PDF"
msgstr ""
#: lib/mv_web/controllers/member_pdf_export_controller.ex
#, elixir-autogen, elixir-format
msgid "Failed to generate PDF export"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#, elixir-autogen, elixir-format
msgid "Member %{club_name}"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#, elixir-autogen, elixir-format
msgid "Member count:"
msgstr ""
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "PDF"
msgstr ""

View file

@ -151,9 +151,11 @@ msgstr ""
msgid "Notes"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/statistics_live.ex
#: lib/mv_web/member_live/index/membership_fee_status.ex
#, elixir-autogen, elixir-format
msgid "Paid"
@ -319,6 +321,7 @@ msgstr ""
#: lib/mv_web/live/member_live/index.ex
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/live/membership_fee_type_live/index.ex
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Members"
msgstr ""
@ -763,6 +766,7 @@ msgstr ""
#: lib/mv_web/components/core_components.ex
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "All"
msgstr ""
@ -930,16 +934,20 @@ msgstr ""
msgid "Status"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/statistics_live.ex
#: lib/mv_web/member_live/index/membership_fee_status.ex
#, elixir-autogen, elixir-format
msgid "Suspended"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#: lib/mv_web/live/components/member_filter_component.ex
#: lib/mv_web/live/member_live/show.ex
#: lib/mv_web/live/member_live/show/membership_fees_component.ex
#: lib/mv_web/live/statistics_live.ex
#: lib/mv_web/member_live/index/membership_fee_status.ex
#, elixir-autogen, elixir-format
msgid "Unpaid"
@ -2389,17 +2397,12 @@ msgstr ""
msgid "Use the data field name as the CSV column header in your file. Data fields must exist in Mila before importing, so they must be listed in the list of member data (like e-mail or first name). Unknown data field columns will be ignored with a warning."
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Export members to CSV"
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex
#, elixir-autogen, elixir-format
msgid "Export to CSV"
msgstr ""
#: lib/mv_web/live/member_live/index.html.heex
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "all"
msgstr ""
@ -2475,3 +2478,144 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Member of group %{name}"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Active members"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Exits"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Inactive members"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Joins"
msgstr ""
#: lib/mv_web/components/layouts/sidebar.ex
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Statistics"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Total"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Year"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Contributions pie: paid %{paid}%%, unpaid %{unpaid}%%, suspended %{suspended}%%"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "All years combined (pie)"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Contributions by year"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Overview from first membership to today"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Contributions by year as table with stacked bars"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Contributions"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Fee type"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Member numbers by year"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "From %{first} to %{last} (relevant years with membership data)"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Member numbers by year as table with bars"
msgstr ""
#: lib/mv_web/live/statistics_live.ex
#, elixir-autogen, elixir-format
msgid "Fee types could not be loaded."
msgstr ""
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "CSV"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#, elixir-autogen, elixir-format
msgid "Created at:"
msgstr "Created at:"
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Export"
msgstr ""
#: lib/mv_web/controllers/member_pdf_export_controller.ex
#, elixir-autogen, elixir-format
msgid "Export contains %{count} rows, maximum is %{max}"
msgstr ""
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format, fuzzy
msgid "Export members to PDF"
msgstr ""
#: lib/mv_web/controllers/member_pdf_export_controller.ex
#, elixir-autogen, elixir-format
msgid "Failed to generate PDF export"
msgstr ""
#: lib/mv/membership/members_pdf.ex
#, elixir-autogen, elixir-format
msgid "Member %{club_name}"
msgstr "Member %{club_name}"
#: lib/mv/membership/members_pdf.ex
#, elixir-autogen, elixir-format
msgid "Member count:"
msgstr "Member count:"
#: lib/mv_web/components/export_dropdown.ex
#, elixir-autogen, elixir-format
msgid "PDF"
msgstr ""
#~ #: lib/mv_web/live/global_settings_live.ex
#~ #, elixir-autogen, elixir-format, fuzzy
#~ msgid "Custom Fields in CSV Import"
#~ msgstr ""

View file

@ -0,0 +1,95 @@
// Typst template for member export (PDF)
// Expected sys.inputs.elixir_data:
// {
// "columns": [{"key": "...", "kind": "...", "label": "..."}, ...],
// "rows": [["cell1", "cell2", ...], ...],
// "meta": {"generated_at": "...", "member_count": 123}
// }
#set page(
paper: "a4",
flipped: true,
margin: (top: 1.2cm, bottom: 1.2cm, left: 1.0cm, right: 1.0cm)
)
#set text(size: 9pt, hyphenate: true)
#set heading(numbering: none)
// Enable text wrapping in table cells
#show table.cell: it => box(width: 100%)[#it]
#let data = sys.inputs.elixir_data
#let columns = data.at("columns", default: ())
#let rows = data.at("rows", default: ())
#let meta = data.at("meta", default: (generated_at: "", member_count: rows.len()))
#let title = data.at("title", default: "Member Export")
#let created_at_label = data.at("created_at_label", default: "Created at:")
#let member_count_label = data.at("member_count_label", default: "Member count:")
// Title
#align(center)[
#text(size: 14pt, weight: "bold")[#title]
]
#v(0.4cm)
// Export metadata
#set text(size: 8pt, fill: black)
#grid(
columns: (1fr, 1fr),
gutter: 1cm,
[*#created_at_label* #meta.at("generated_at", default: "")],
[*#member_count_label* #meta.at("member_count", default: rows.len())],
)
#v(0.6cm)
// ---- Horizontal paging config ----
#let fixed_count = calc.min(2, columns.len())
#let max_dynamic_cols = 5
#let fixed_col_widths = (32mm, 32mm)
#let fixed_cols = columns.slice(0, fixed_count)
#let dynamic_cols = columns.slice(fixed_count, columns.len())
#let dynamic_chunks = dynamic_cols.chunks(max_dynamic_cols)
#let render_chunk(chunk_index, dyn_cols_chunk) = [
#let dyn_count = dyn_cols_chunk.len()
#let start = fixed_count + chunk_index * max_dynamic_cols
#let page_cols = fixed_cols + dyn_cols_chunk
#let headers = page_cols.map(c => c.at("label", default: ""))
// widths: first two columns fixed (32mm, 42mm), rest distributed as 1fr
#let widths = (
if fixed_count >= 1 { fixed_col_widths.at(0) } else { 1fr },
if fixed_count >= 2 { fixed_col_widths.at(1) } else { 1fr },
..((1fr,) * dyn_count)
)
#let header_cells = headers.map(h => text(weight: "bold", size: 9pt)[#h])
// Body cells (row-major), nur die Spalten dieses Chunks
#let body_cells = (
rows
.map(row => row.slice(0, fixed_count) + row.slice(start, start + dyn_count))
.map(cells => cells.map(cell => text(size: 8.5pt)[#cell]))
.flatten()
)
#table(
columns: widths,
table.header(..header_cells),
..body_cells,
)
]
// ---- Output ----
#if dynamic_cols.len() == 0 {
render_chunk(0, ())
} else {
for (i, chunk) in dynamic_chunks.enumerate() {
render_chunk(i, chunk)
if i < dynamic_chunks.len() - 1 { pagebreak() }
}
}

View file

@ -379,10 +379,9 @@ Enum.each(member_attrs_list, fn member_attrs ->
# Generate cycles if member has a fee type
if final_member.membership_fee_type_id do
# Load member with cycles to check if they already exist
# Load member with cycles to check if they already exist (actor required for auth)
member_with_cycles =
final_member
|> Ash.load!(:membership_fee_cycles)
Ash.load!(final_member, :membership_fee_cycles, actor: admin_user_with_role)
# Only generate if no cycles exist yet (to avoid duplicates on re-run)
cycles =
@ -427,7 +426,7 @@ Enum.each(member_attrs_list, fn member_attrs ->
if cycle.status != status do
cycle
|> Ash.Changeset.for_update(:update, %{status: status})
|> Ash.update!(actor: admin_user_with_role)
|> Ash.update!(actor: admin_user_with_role, domain: Mv.MembershipFees)
end
end)
end
@ -542,10 +541,9 @@ Enum.with_index(linked_members)
# Generate cycles for linked members
if final_member.membership_fee_type_id do
# Load member with cycles to check if they already exist
# Load member with cycles to check if they already exist (actor required for auth)
member_with_cycles =
final_member
|> Ash.load!(:membership_fee_cycles)
Ash.load!(final_member, :membership_fee_cycles, actor: admin_user_with_role)
# Only generate if no cycles exist yet (to avoid duplicates on re-run)
cycles =
@ -575,7 +573,7 @@ Enum.with_index(linked_members)
if cycle.status != status do
cycle
|> Ash.Changeset.for_update(:update, %{status: status})
|> Ash.update!()
|> Ash.update!(actor: admin_user_with_role, domain: Mv.MembershipFees)
end
end)
end