feat: add cycle status calculations to Member resource
This commit is contained in:
parent
48d98b97b2
commit
6763d4f2eb
2 changed files with 411 additions and 0 deletions
|
|
@ -501,6 +501,50 @@ defmodule Mv.Membership.Member do
|
|||
has_many :membership_fee_cycles, Mv.MembershipFees.MembershipFeeCycle
|
||||
end
|
||||
|
||||
calculations do
|
||||
calculate :current_cycle_status, :atom do
|
||||
description "Status of the current cycle (the one that is active today)"
|
||||
# Automatically load cycles with all attributes and membership_fee_type
|
||||
load membership_fee_cycles: [:cycle_start, :status, membership_fee_type: [:interval]]
|
||||
|
||||
calculation fn [member], _context ->
|
||||
case get_current_cycle(member) do
|
||||
nil -> [nil]
|
||||
cycle -> [cycle.status]
|
||||
end
|
||||
end
|
||||
|
||||
constraints one_of: [:unpaid, :paid, :suspended]
|
||||
end
|
||||
|
||||
calculate :last_cycle_status, :atom do
|
||||
description "Status of the last completed cycle (the most recent cycle that has ended)"
|
||||
# Automatically load cycles with all attributes and membership_fee_type
|
||||
load membership_fee_cycles: [:cycle_start, :status, membership_fee_type: [:interval]]
|
||||
|
||||
calculation fn [member], _context ->
|
||||
case get_last_completed_cycle(member) do
|
||||
nil -> [nil]
|
||||
cycle -> [cycle.status]
|
||||
end
|
||||
end
|
||||
|
||||
constraints one_of: [:unpaid, :paid, :suspended]
|
||||
end
|
||||
|
||||
calculate :overdue_count, :integer do
|
||||
description "Count of unpaid cycles that have already ended (cycle_end < today)"
|
||||
# Automatically load cycles with all attributes and membership_fee_type
|
||||
load membership_fee_cycles: [:cycle_start, :status, membership_fee_type: [:interval]]
|
||||
|
||||
calculation fn [member], _context ->
|
||||
overdue = get_overdue_cycles(member)
|
||||
count = if is_list(overdue), do: length(overdue), else: 0
|
||||
[count]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Define identities for upsert operations
|
||||
identities do
|
||||
identity :unique_email, [:email]
|
||||
|
|
@ -547,6 +591,91 @@ defmodule Mv.Membership.Member do
|
|||
|
||||
def show_in_overview?(_), do: true
|
||||
|
||||
# Helper functions for cycle status calculations
|
||||
|
||||
@doc false
|
||||
def get_current_cycle(member) do
|
||||
today = Date.utc_today()
|
||||
|
||||
# Check if cycles are already loaded
|
||||
cycles = Map.get(member, :membership_fee_cycles)
|
||||
|
||||
if is_list(cycles) and cycles != [] do
|
||||
Enum.find(cycles, fn cycle ->
|
||||
case Map.get(cycle, :membership_fee_type) do
|
||||
%{interval: interval} ->
|
||||
cycle_end =
|
||||
Mv.MembershipFees.CalendarCycles.calculate_cycle_end(cycle.cycle_start, interval)
|
||||
|
||||
Date.compare(cycle.cycle_start, today) in [:lt, :eq] and
|
||||
Date.compare(today, cycle_end) in [:lt, :eq]
|
||||
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@doc false
|
||||
def get_last_completed_cycle(member) do
|
||||
today = Date.utc_today()
|
||||
|
||||
# Check if cycles are already loaded
|
||||
cycles = Map.get(member, :membership_fee_cycles)
|
||||
|
||||
if is_list(cycles) and cycles != [] do
|
||||
cycles
|
||||
|> Enum.filter(fn cycle ->
|
||||
case Map.get(cycle, :membership_fee_type) do
|
||||
%{interval: interval} ->
|
||||
cycle_end =
|
||||
Mv.MembershipFees.CalendarCycles.calculate_cycle_end(cycle.cycle_start, interval)
|
||||
|
||||
# Cycle must have ended (cycle_end < today)
|
||||
Date.compare(today, cycle_end) == :gt
|
||||
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end)
|
||||
|> Enum.sort_by(fn cycle ->
|
||||
interval = Map.get(cycle, :membership_fee_type).interval
|
||||
Mv.MembershipFees.CalendarCycles.calculate_cycle_end(cycle.cycle_start, interval)
|
||||
end, {:desc, Date})
|
||||
|> List.first()
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@doc false
|
||||
def get_overdue_cycles(member) do
|
||||
today = Date.utc_today()
|
||||
|
||||
# Check if cycles are already loaded
|
||||
cycles = Map.get(member, :membership_fee_cycles)
|
||||
|
||||
if is_list(cycles) and cycles != [] do
|
||||
Enum.filter(cycles, fn cycle ->
|
||||
case Map.get(cycle, :membership_fee_type) do
|
||||
%{interval: interval} ->
|
||||
cycle_end =
|
||||
Mv.MembershipFees.CalendarCycles.calculate_cycle_end(cycle.cycle_start, interval)
|
||||
|
||||
cycle.status == :unpaid and Date.compare(today, cycle_end) == :gt
|
||||
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end)
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
# Normalizes visibility config map keys from strings to atoms.
|
||||
# JSONB in PostgreSQL converts atom keys to string keys when storing.
|
||||
defp normalize_visibility_config(config) when is_map(config) do
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue