Membership Fee Type Resource & Settings closes #278 #291
1 changed files with 42 additions and 42 deletions
|
|
@ -50,31 +50,43 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
|> Ash.update!()
|
|> Ash.update!()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Helper to get cycles for a member
|
||||||
|
defp get_member_cycles(member_id) do
|
||||||
|
MembershipFeeCycle
|
||||||
|
|> Ash.Query.filter(member_id == ^member_id)
|
||||||
|
|> Ash.Query.sort(cycle_start: :asc)
|
||||||
|
|> Ash.read!()
|
||||||
|
end
|
||||||
|
|
||||||
describe "generate_cycles_for_member/2" do
|
describe "generate_cycles_for_member/2" do
|
||||||
test "generates cycles from start date to today" do
|
test "generates cycles from start date to today" do
|
||||||
setup_settings(true)
|
setup_settings(true)
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
|
|
||||||
|
# Create member WITHOUT fee type first, then assign it
|
||||||
|
# This avoids the auto-generation on create and gives us control
|
||||||
member =
|
member =
|
||||||
create_member_without_cycles(%{
|
create_member_without_cycles(%{
|
||||||
join_date: ~D[2022-03-15],
|
join_date: ~D[2022-03-15],
|
||||||
membership_fee_type_id: fee_type.id
|
membership_fee_start_date: ~D[2022-01-01]
|
||||||
})
|
})
|
||||||
|
|
||||||
# Wait a moment for async task to complete or skip it
|
# Assign fee type, which will trigger auto-generation in test env
|
||||||
Process.sleep(100)
|
member =
|
||||||
|
member
|
||||||
|
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||||
|
|> Ash.update!()
|
||||||
|
|
||||||
# Generate cycles with specific "today" date
|
# Verify cycles were generated
|
||||||
today = ~D[2024-06-15]
|
all_cycles = get_member_cycles(member.id)
|
||||||
{:ok, cycles} = CycleGenerator.generate_cycles_for_member(member.id, today: today)
|
cycle_years = Enum.map(all_cycles, & &1.cycle_start.year) |> Enum.sort() |> Enum.uniq()
|
||||||
|
|
||||||
# With include_joining_cycle=true and join_date=2022-03-15,
|
# With include_joining_cycle=true and join_date=2022-03-15,
|
||||||
# start_date should be 2022-01-01
|
# start_date should be 2022-01-01
|
||||||
# Should generate cycles for 2022, 2023, 2024
|
# Should have cycles for 2022, 2023, 2024
|
||||||
_cycle_years = Enum.map(cycles, & &1.cycle_start.year) |> Enum.sort()
|
assert 2022 in cycle_years
|
||||||
|
assert 2023 in cycle_years
|
||||||
# May already have some cycles from the async trigger, so check we have at least 3
|
assert 2024 in cycle_years
|
||||||
assert length(cycles) >= 0
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "generates cycles from last existing cycle" do
|
test "generates cycles from last existing cycle" do
|
||||||
|
|
@ -127,8 +139,6 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
membership_fee_start_date: ~D[2022-01-01]
|
membership_fee_start_date: ~D[2022-01-01]
|
||||||
})
|
})
|
||||||
|
|
||||||
Process.sleep(100)
|
|
||||||
|
|
||||||
# Generate cycles with specific "today" date far in the future
|
# Generate cycles with specific "today" date far in the future
|
||||||
today = ~D[2025-06-15]
|
today = ~D[2025-06-15]
|
||||||
{:ok, cycles} = CycleGenerator.generate_cycles_for_member(member.id, today: today)
|
{:ok, cycles} = CycleGenerator.generate_cycles_for_member(member.id, today: today)
|
||||||
|
|
@ -152,8 +162,6 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
membership_fee_start_date: ~D[2023-01-01]
|
membership_fee_start_date: ~D[2023-01-01]
|
||||||
})
|
})
|
||||||
|
|
||||||
Process.sleep(100)
|
|
||||||
|
|
||||||
today = ~D[2024-06-15]
|
today = ~D[2024-06-15]
|
||||||
|
|
||||||
# First generation
|
# First generation
|
||||||
|
|
@ -178,13 +186,12 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
membership_fee_start_date: ~D[2024-01-01]
|
membership_fee_start_date: ~D[2024-01-01]
|
||||||
})
|
})
|
||||||
|
|
||||||
Process.sleep(100)
|
# Verify cycles were generated with correct amount
|
||||||
|
all_cycles = get_member_cycles(member.id)
|
||||||
today = ~D[2024-06-15]
|
refute Enum.empty?(all_cycles), "Expected cycles to be generated"
|
||||||
{:ok, cycles} = CycleGenerator.generate_cycles_for_member(member.id, today: today)
|
|
||||||
|
|
||||||
# All cycles should have the correct amount
|
# All cycles should have the correct amount
|
||||||
Enum.each(cycles, fn cycle ->
|
Enum.each(all_cycles, fn cycle ->
|
||||||
assert Decimal.equal?(cycle.amount, amount)
|
assert Decimal.equal?(cycle.amount, amount)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
@ -193,7 +200,8 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
setup_settings(true)
|
setup_settings(true)
|
||||||
fee_type = create_fee_type(%{interval: :quarterly})
|
fee_type = create_fee_type(%{interval: :quarterly})
|
||||||
|
|
||||||
# Create member without membership_fee_start_date
|
# Create member without membership_fee_start_date - it will be auto-calculated
|
||||||
|
# and cycles will be auto-generated
|
||||||
member =
|
member =
|
||||||
create_member_without_cycles(%{
|
create_member_without_cycles(%{
|
||||||
join_date: ~D[2024-02-15],
|
join_date: ~D[2024-02-15],
|
||||||
|
|
@ -201,33 +209,29 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
# No membership_fee_start_date - should be calculated
|
# No membership_fee_start_date - should be calculated
|
||||||
})
|
})
|
||||||
|
|
||||||
Process.sleep(100)
|
# Verify cycles were auto-generated
|
||||||
|
all_cycles = get_member_cycles(member.id)
|
||||||
today = ~D[2024-06-15]
|
|
||||||
{:ok, cycles} = CycleGenerator.generate_cycles_for_member(member.id, today: today)
|
|
||||||
|
|
||||||
# With include_joining_cycle=true and join_date=2024-02-15 (quarterly),
|
# With include_joining_cycle=true and join_date=2024-02-15 (quarterly),
|
||||||
# start_date should be 2024-01-01
|
# start_date should be 2024-01-01 (Q1 start)
|
||||||
# Should have Q1 and Q2 2024 cycles
|
# Should have Q1, Q2, Q3, Q4 2024 cycles (based on current date)
|
||||||
unless Enum.empty?(cycles) do
|
refute Enum.empty?(all_cycles), "Expected cycles to be generated"
|
||||||
cycle_starts = Enum.map(cycles, & &1.cycle_start) |> Enum.sort(Date)
|
|
||||||
first_cycle_start = List.first(cycle_starts)
|
|
||||||
|
|
||||||
# First cycle should start in Q1 2024
|
cycle_starts = Enum.map(all_cycles, & &1.cycle_start) |> Enum.sort(Date)
|
||||||
assert first_cycle_start.year == 2024
|
first_cycle_start = List.first(cycle_starts)
|
||||||
assert first_cycle_start.month in [1, 4]
|
|
||||||
end
|
# First cycle should start in Q1 2024 (2024-01-01)
|
||||||
|
assert first_cycle_start == ~D[2024-01-01]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns error when member has no membership_fee_type" do
|
test "returns error when member has no membership_fee_type" do
|
||||||
|
# Create member without fee type - no auto-generation will occur
|
||||||
member =
|
member =
|
||||||
create_member_without_cycles(%{
|
create_member_without_cycles(%{
|
||||||
join_date: ~D[2024-03-15]
|
join_date: ~D[2024-03-15]
|
||||||
# No membership_fee_type_id
|
# No membership_fee_type_id
|
||||||
})
|
})
|
||||||
|
|
||||||
Process.sleep(100)
|
|
||||||
|
|
||||||
{:error, reason} = CycleGenerator.generate_cycles_for_member(member.id)
|
{:error, reason} = CycleGenerator.generate_cycles_for_member(member.id)
|
||||||
assert reason == :no_membership_fee_type
|
assert reason == :no_membership_fee_type
|
||||||
end
|
end
|
||||||
|
|
@ -235,14 +239,14 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
test "returns error when member has no join_date" do
|
test "returns error when member has no join_date" do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
|
|
||||||
|
# Create member without join_date - no auto-generation will occur
|
||||||
|
# (after_action hook checks for join_date)
|
||||||
member =
|
member =
|
||||||
create_member_without_cycles(%{
|
create_member_without_cycles(%{
|
||||||
membership_fee_type_id: fee_type.id
|
membership_fee_type_id: fee_type.id
|
||||||
# No join_date
|
# No join_date
|
||||||
})
|
})
|
||||||
|
|
||||||
Process.sleep(100)
|
|
||||||
|
|
||||||
{:error, reason} = CycleGenerator.generate_cycles_for_member(member.id)
|
{:error, reason} = CycleGenerator.generate_cycles_for_member(member.id)
|
||||||
assert reason == :no_join_date
|
assert reason == :no_join_date
|
||||||
end
|
end
|
||||||
|
|
@ -312,8 +316,6 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
membership_fee_start_date: ~D[2024-01-01]
|
membership_fee_start_date: ~D[2024-01-01]
|
||||||
})
|
})
|
||||||
|
|
||||||
Process.sleep(200)
|
|
||||||
|
|
||||||
today = ~D[2024-06-15]
|
today = ~D[2024-06-15]
|
||||||
{:ok, results} = CycleGenerator.generate_cycles_for_all_members(today: today)
|
{:ok, results} = CycleGenerator.generate_cycles_for_all_members(today: today)
|
||||||
|
|
||||||
|
|
@ -336,8 +338,6 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
membership_fee_start_date: ~D[2022-01-01]
|
membership_fee_start_date: ~D[2022-01-01]
|
||||||
})
|
})
|
||||||
|
|
||||||
Process.sleep(100)
|
|
||||||
|
|
||||||
today = ~D[2024-06-15]
|
today = ~D[2024-06-15]
|
||||||
|
|
||||||
# Run two concurrent generations
|
# Run two concurrent generations
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue