Membership Fee 6 - UI Components & LiveViews closes #280 #304

Open
moritz wants to merge 65 commits from feature/280_membership_fee_ui into main
2 changed files with 43 additions and 9 deletions
Showing only changes of commit 3241dd7d96 - Show all commits

View file

@ -299,11 +299,15 @@ defmodule Mv.MembershipFees.CalendarCycles do
end end
defp quarterly_cycle_end(cycle_start) do defp quarterly_cycle_end(cycle_start) do
case cycle_start.month do # Ensure cycle_start is aligned to quarter boundary
1 -> Date.new!(cycle_start.year, 3, 31) # This handles cases where cycle_start might not be at the correct quarter start (e.g., month 12)
4 -> Date.new!(cycle_start.year, 6, 30) aligned_start = quarterly_cycle_start(cycle_start)
7 -> Date.new!(cycle_start.year, 9, 30)
10 -> Date.new!(cycle_start.year, 12, 31) case aligned_start.month do
1 -> Date.new!(aligned_start.year, 3, 31)
4 -> Date.new!(aligned_start.year, 6, 30)
7 -> Date.new!(aligned_start.year, 9, 30)
10 -> Date.new!(aligned_start.year, 12, 31)
end end
end end
@ -313,9 +317,13 @@ defmodule Mv.MembershipFees.CalendarCycles do
end end
defp half_yearly_cycle_end(cycle_start) do defp half_yearly_cycle_end(cycle_start) do
case cycle_start.month do # Ensure cycle_start is aligned to half-year boundary
1 -> Date.new!(cycle_start.year, 6, 30) # This handles cases where cycle_start might not be at the correct half-year start (e.g., month 10)
7 -> Date.new!(cycle_start.year, 12, 31) aligned_start = half_yearly_cycle_start(cycle_start)
case aligned_start.month do
1 -> Date.new!(aligned_start.year, 6, 30)
7 -> Date.new!(aligned_start.year, 12, 31)
end end
end end

View file

@ -386,18 +386,44 @@ defmodule Mv.MembershipFees.CycleGenerator do
{:ok, cycle} -> {:ok, cycle} ->
{: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, reason} ->
{:error, {cycle_start, reason}} {:error, {cycle_start, reason}}
end end
end) end)
{successes, errors} = Enum.split_with(results, &match?({:ok, _, _}, &1)) {successes, skips, errors} =
Enum.reduce(results, {[], [], []}, fn
{:ok, cycle, notifications}, {successes, skips, errors} ->
{[{:ok, cycle, notifications} | successes], skips, errors}
{:skip, cycle_start}, {successes, skips, errors} ->
{successes, [cycle_start | skips], errors}
{:error, error}, {successes, skips, errors} ->
{successes, skips, [error | errors]}
end)
all_notifications = all_notifications =
Enum.flat_map(successes, fn {:ok, _cycle, notifications} -> notifications end) Enum.flat_map(successes, fn {:ok, _cycle, notifications} -> notifications end)
if Enum.empty?(errors) do if Enum.empty?(errors) do
successful_cycles = Enum.map(successes, fn {:ok, cycle, _notifications} -> cycle end) 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}"
)
end
{:ok, successful_cycles, all_notifications} {:ok, successful_cycles, all_notifications}
else else
Logger.warning("Some cycles failed to create: #{inspect(errors)}") Logger.warning("Some cycles failed to create: #{inspect(errors)}")