From a8ea121800809887239e6f05367c1612d45ef879 Mon Sep 17 00:00:00 2001 From: Moritz Date: Fri, 26 Dec 2025 21:00:52 +0100 Subject: [PATCH] Refactor cycle generator and update translations Extract error handling into separate functions to reduce nesting depth. --- lib/mv/membership_fees/cycle_generator.ex | 68 +++++++++++++++-------- priv/gettext/de/LC_MESSAGES/default.po | 19 ++++--- priv/gettext/default.pot | 17 ++++-- priv/gettext/en/LC_MESSAGES/default.po | 17 ++++-- priv/repo/seeds.exs | 3 +- 5 files changed, 82 insertions(+), 42 deletions(-) diff --git a/lib/mv/membership_fees/cycle_generator.ex b/lib/mv/membership_fees/cycle_generator.ex index 23889fb..7d6c798 100644 --- a/lib/mv/membership_fees/cycle_generator.ex +++ b/lib/mv/membership_fees/cycle_generator.ex @@ -379,25 +379,10 @@ defmodule Mv.MembershipFees.CycleGenerator do status: :unpaid } - case Ash.create(MembershipFeeCycle, attrs, return_notifications?: true) do - {:ok, cycle, notifications} when is_list(notifications) -> - {:ok, cycle, notifications} - - {:ok, cycle} -> - {:ok, cycle, []} - - {:error, %Ash.Error.Invalid{errors: [%Ash.Error.Changes.InvalidAttribute{private_vars: %{constraint: constraint, constraint_type: :unique}}]}} = error -> - # Cycle already exists (unique constraint violation) - skip it silently - # This makes the function idempotent and prevents errors on server restart - if constraint == "membership_fee_cycles_unique_cycle_per_member_index" do - {:skip, cycle_start} - else - {:error, {cycle_start, error}} - end - - {:error, reason} -> - {:error, {cycle_start, reason}} - end + handle_cycle_creation_result( + Ash.create(MembershipFeeCycle, attrs, return_notifications?: true), + cycle_start + ) end) {successes, skips, errors} = @@ -419,9 +404,7 @@ defmodule Mv.MembershipFees.CycleGenerator do successful_cycles = Enum.map(successes, fn {:ok, cycle, _notifications} -> cycle end) if Enum.any?(skips) do - Logger.debug( - "Skipped #{length(skips)} cycles that already exist for member #{member_id}" - ) + Logger.debug("Skipped #{length(skips)} cycles that already exist for member #{member_id}") end {:ok, successful_cycles, all_notifications} @@ -433,4 +416,45 @@ defmodule Mv.MembershipFees.CycleGenerator do {:error, {:partial_failure, errors}} end end + + defp handle_cycle_creation_result({:ok, cycle, notifications}, _cycle_start) + when is_list(notifications) do + {:ok, cycle, notifications} + end + + defp handle_cycle_creation_result({:ok, cycle}, _cycle_start) do + {:ok, cycle, []} + end + + defp handle_cycle_creation_result( + {:error, + %Ash.Error.Invalid{ + errors: [ + %Ash.Error.Changes.InvalidAttribute{ + private_vars: %{constraint: constraint, constraint_type: :unique} + } + ] + }} = error, + cycle_start + ) do + # Cycle already exists (unique constraint violation) - skip it silently + # This makes the function idempotent and prevents errors on server restart + handle_unique_constraint_violation(constraint, cycle_start, error) + end + + defp handle_cycle_creation_result({:error, reason}, cycle_start) do + {:error, {cycle_start, reason}} + end + + defp handle_unique_constraint_violation( + "membership_fee_cycles_unique_cycle_per_member_index", + cycle_start, + _error + ) do + {:skip, cycle_start} + end + + defp handle_unique_constraint_violation(_constraint, cycle_start, error) do + {:error, {cycle_start, error}} + end end diff --git a/priv/gettext/de/LC_MESSAGES/default.po b/priv/gettext/de/LC_MESSAGES/default.po index 0bebadd..4d87ac7 100644 --- a/priv/gettext/de/LC_MESSAGES/default.po +++ b/priv/gettext/de/LC_MESSAGES/default.po @@ -39,7 +39,6 @@ msgstr "Stadt" #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/show/membership_fees_component.ex -#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/user_live/index.html.heex #, elixir-autogen, elixir-format msgid "Delete" @@ -779,6 +778,7 @@ msgid "Tip: Paste email addresses into the BCC field for privacy compliance" msgstr "Tipp: E-Mail-Adressen ins BCC-Feld einfügen für Datenschutzkonformität" #: lib/mv_web/components/core_components.ex +#: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format, fuzzy msgid "This field cannot be empty" msgstr "Dieses Feld darf nicht leer bleiben" @@ -1322,11 +1322,6 @@ msgstr "Textfeld" msgid "Yes/No-Selection" msgstr "Ja/Nein-Auswahl" -#: lib/mv_web/live/components/payment_filter_component.ex -#, elixir-autogen, elixir-format -msgid "All payment statuses" -msgstr "Jeder Zahlungs-Zustand" - #: lib/mv_web/live/member_live/index.html.heex #, elixir-autogen, elixir-format, fuzzy msgid "Copy email addresses" @@ -1754,7 +1749,7 @@ msgstr "Löschen" #: lib/mv_web/live/member_live/show/membership_fees_component.ex #, elixir-autogen, elixir-format, fuzzy msgid "Delete All Cycles" -msgstr "Zyklus löschen" +msgstr "Alle Zyklen löschen" #: lib/mv_web/live/member_live/show/membership_fees_component.ex #, elixir-autogen, elixir-format, fuzzy @@ -1816,6 +1811,16 @@ msgstr "Aktueller Zyklus Zahlungsstatus" msgid "Last Cycle Payment Status" msgstr "Letzter Zyklus Zahlungsstatus" +#: lib/mv_web/live/membership_fee_type_live/index.ex +#, elixir-autogen, elixir-format +msgid "Delete membership fee type" +msgstr "" + +#: lib/mv_web/live/membership_fee_type_live/index.ex +#, elixir-autogen, elixir-format, fuzzy +msgid "Edit membership fee type" +msgstr "Mitgliedsbeitragsart bearbeiten" + #~ #: lib/mv_web/live/components/payment_filter_component.ex #~ #, elixir-autogen, elixir-format #~ msgid "All payment statuses" diff --git a/priv/gettext/default.pot b/priv/gettext/default.pot index 550dcc5..bdbc93e 100644 --- a/priv/gettext/default.pot +++ b/priv/gettext/default.pot @@ -40,7 +40,6 @@ msgstr "" #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/show/membership_fees_component.ex -#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/user_live/index.html.heex #, elixir-autogen, elixir-format msgid "Delete" @@ -780,6 +779,7 @@ msgid "Tip: Paste email addresses into the BCC field for privacy compliance" msgstr "" #: lib/mv_web/components/core_components.ex +#: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format msgid "This field cannot be empty" msgstr "" @@ -1323,11 +1323,6 @@ msgstr "" msgid "Yes/No-Selection" msgstr "" -#: lib/mv_web/live/components/payment_filter_component.ex -#, elixir-autogen, elixir-format -msgid "All payment statuses" -msgstr "" - #: lib/mv_web/live/member_live/index.html.heex #, elixir-autogen, elixir-format msgid "Copy email addresses" @@ -1816,3 +1811,13 @@ msgstr "" #, elixir-autogen, elixir-format msgid "Last Cycle Payment Status" msgstr "" + +#: lib/mv_web/live/membership_fee_type_live/index.ex +#, elixir-autogen, elixir-format +msgid "Delete membership fee type" +msgstr "" + +#: lib/mv_web/live/membership_fee_type_live/index.ex +#, elixir-autogen, elixir-format +msgid "Edit membership fee type" +msgstr "" diff --git a/priv/gettext/en/LC_MESSAGES/default.po b/priv/gettext/en/LC_MESSAGES/default.po index 87f9019..7ced824 100644 --- a/priv/gettext/en/LC_MESSAGES/default.po +++ b/priv/gettext/en/LC_MESSAGES/default.po @@ -40,7 +40,6 @@ msgstr "" #: lib/mv_web/live/custom_field_live/index_component.ex #: lib/mv_web/live/member_live/index.html.heex #: lib/mv_web/live/member_live/show/membership_fees_component.ex -#: lib/mv_web/live/membership_fee_type_live/index.ex #: lib/mv_web/live/user_live/index.html.heex #, elixir-autogen, elixir-format msgid "Delete" @@ -780,6 +779,7 @@ msgid "Tip: Paste email addresses into the BCC field for privacy compliance" msgstr "" #: lib/mv_web/components/core_components.ex +#: lib/mv_web/live/membership_fee_type_live/form.ex #, elixir-autogen, elixir-format, fuzzy msgid "This field cannot be empty" msgstr "" @@ -1323,11 +1323,6 @@ msgstr "" msgid "Yes/No-Selection" msgstr "" -#: lib/mv_web/live/components/payment_filter_component.ex -#, elixir-autogen, elixir-format -msgid "All payment statuses" -msgstr "" - #: lib/mv_web/live/member_live/index.html.heex #, elixir-autogen, elixir-format, fuzzy msgid "Copy email addresses" @@ -1817,6 +1812,16 @@ msgstr "Current Cycle Payment Status" msgid "Last Cycle Payment Status" msgstr "Last Cycle Payment Status" +#: lib/mv_web/live/membership_fee_type_live/index.ex +#, elixir-autogen, elixir-format +msgid "Delete membership fee type" +msgstr "" + +#: lib/mv_web/live/membership_fee_type_live/index.ex +#, elixir-autogen, elixir-format, fuzzy +msgid "Edit membership fee type" +msgstr "" + #~ #: lib/mv_web/live/components/payment_filter_component.ex #~ #, elixir-autogen, elixir-format #~ msgid "All payment statuses" diff --git a/priv/repo/seeds.exs b/priv/repo/seeds.exs index 2fc27c4..fb102f4 100644 --- a/priv/repo/seeds.exs +++ b/priv/repo/seeds.exs @@ -211,7 +211,8 @@ Enum.each(member_attrs_list, fn member_attrs -> # Only set membership_fee_type_id if member doesn't have one yet (idempotent) final_member = - if is_nil(member.membership_fee_type_id) and Map.has_key?(member_attrs_without_status, :membership_fee_type_id) do + if is_nil(member.membership_fee_type_id) and + Map.has_key?(member_attrs_without_status, :membership_fee_type_id) do member |> Ash.Changeset.for_update(:update_member, %{ membership_fee_type_id: member_attrs_without_status.membership_fee_type_id