feat(overview): add period-scoped payment filter and field-picker descriptor

This commit is contained in:
Simon 2026-07-10 16:27:15 +02:00
parent 95ef3177ac
commit 7d1a71b1fd
12 changed files with 654 additions and 0 deletions

View file

@ -52,6 +52,7 @@ defmodule MvWeb.MemberLive.Index.OverviewQuery do
opts[:show_current_cycle],
today(opts)
)
|> apply_payment_filter(opts[:payment_filter], payment_period(opts))
|> apply_sort(opts[:sort_field], opts[:sort_order], opts[:custom_fields] || [])
end
@ -232,6 +233,40 @@ defmodule MvWeb.MemberLive.Index.OverviewQuery do
)
end
# ---------------------------------------------------------------------------
# Payment aging filter (period-scoped unpaid-cycle count)
#
# `fully_paid` keeps members with zero unpaid cycles whose cycle_end lies in
# the active period; `{:has_unpaid, n}` keeps members with at least n such
# cycles. Both push to SQL via the `unpaid_cycle_count` calculation (a
# correlated aggregate over `membership_fee_cycles`), so no member set is
# loaded into memory. Suspended/paid cycles are excluded by the calculation.
# ---------------------------------------------------------------------------
defp payment_period(opts) do
case opts[:payment_period] do
%{from: _, to: _} = period -> period
_ -> %{from: nil, to: nil}
end
end
defp apply_payment_filter(query, :fully_paid, %{from: from, to: to}) do
Ash.Query.filter(
query,
expr(unpaid_cycle_count(period_from: ^from, period_to: ^to) == 0)
)
end
defp apply_payment_filter(query, {:has_unpaid, n}, %{from: from, to: to})
when is_integer(n) and n > 0 do
Ash.Query.filter(
query,
expr(unpaid_cycle_count(period_from: ^from, period_to: ^to) >= ^n)
)
end
defp apply_payment_filter(query, _filter, _period), do: query
# ---------------------------------------------------------------------------
# Built-in date filters (join/exit)
# ---------------------------------------------------------------------------