Add actor parameter to all tests requiring authorization
This commit adds actor: system_actor to all Ash operations in tests that require authorization.
This commit is contained in:
parent
686f69c9e9
commit
0f48a9b15a
75 changed files with 4686 additions and 2859 deletions
|
|
@ -11,8 +11,13 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
|
||||
require Ash.Query
|
||||
|
||||
setup do
|
||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||
%{actor: system_actor}
|
||||
end
|
||||
|
||||
# Helper to create a membership fee type
|
||||
defp create_fee_type(attrs) do
|
||||
defp create_fee_type(attrs, actor) do
|
||||
default_attrs = %{
|
||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
||||
amount: Decimal.new("50.00"),
|
||||
|
|
@ -23,11 +28,11 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
|
||||
MembershipFeeType
|
||||
|> Ash.Changeset.for_create(:create, attrs)
|
||||
|> Ash.create!()
|
||||
|> Ash.create!(actor: actor)
|
||||
end
|
||||
|
||||
# Helper to create a member without triggering cycle generation
|
||||
defp create_member_without_cycles(attrs) do
|
||||
defp create_member_without_cycles(attrs, actor) do
|
||||
default_attrs = %{
|
||||
first_name: "Test",
|
||||
last_name: "User",
|
||||
|
|
@ -38,50 +43,53 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
|
||||
Member
|
||||
|> Ash.Changeset.for_create(:create_member, attrs)
|
||||
|> Ash.create!()
|
||||
|> Ash.create!(actor: actor)
|
||||
end
|
||||
|
||||
# Helper to set up settings with specific include_joining_cycle value
|
||||
defp setup_settings(include_joining_cycle) do
|
||||
defp setup_settings(include_joining_cycle, actor) do
|
||||
{:ok, settings} = Mv.Membership.get_settings()
|
||||
|
||||
settings
|
||||
|> Ash.Changeset.for_update(:update, %{include_joining_cycle: include_joining_cycle})
|
||||
|> Ash.update!()
|
||||
|> Ash.update!(actor: actor)
|
||||
end
|
||||
|
||||
# Helper to get cycles for a member
|
||||
defp get_member_cycles(member_id) do
|
||||
defp get_member_cycles(member_id, actor) do
|
||||
MembershipFeeCycle
|
||||
|> Ash.Query.filter(member_id == ^member_id)
|
||||
|> Ash.Query.sort(cycle_start: :asc)
|
||||
|> Ash.read!()
|
||||
|> Ash.read!(actor: actor)
|
||||
end
|
||||
|
||||
describe "generate_cycles_for_member/2" do
|
||||
test "generates cycles from start date to today" do
|
||||
setup_settings(true)
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
test "generates cycles from start date to today", %{actor: actor} do
|
||||
setup_settings(true, actor)
|
||||
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
||||
|
||||
# Create member WITHOUT fee type first to avoid auto-generation
|
||||
member =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2022-03-15],
|
||||
membership_fee_start_date: ~D[2022-01-01]
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2022-03-15],
|
||||
membership_fee_start_date: ~D[2022-01-01]
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
# Assign fee type
|
||||
member =
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||
|> Ash.update!()
|
||||
|> Ash.update!(actor: actor)
|
||||
|
||||
# Explicitly generate cycles with fixed "today" date to avoid date dependency
|
||||
today = ~D[2024-06-15]
|
||||
{:ok, _, _} = CycleGenerator.generate_cycles_for_member(member.id, today: today)
|
||||
|
||||
# Verify cycles were generated
|
||||
all_cycles = get_member_cycles(member.id)
|
||||
all_cycles = get_member_cycles(member.id, actor)
|
||||
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,
|
||||
|
|
@ -92,16 +100,19 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
assert 2024 in cycle_years
|
||||
end
|
||||
|
||||
test "generates cycles from last existing cycle" do
|
||||
setup_settings(true)
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
test "generates cycles from last existing cycle", %{actor: actor} do
|
||||
setup_settings(true, actor)
|
||||
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
||||
|
||||
# Create member without fee type first to avoid auto-generation
|
||||
member =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2022-03-15],
|
||||
membership_fee_start_date: ~D[2022-01-01]
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2022-03-15],
|
||||
membership_fee_start_date: ~D[2022-01-01]
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
# Manually create a cycle for 2022
|
||||
MembershipFeeCycle
|
||||
|
|
@ -112,13 +123,13 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
amount: fee_type.amount,
|
||||
status: :paid
|
||||
})
|
||||
|> Ash.create!()
|
||||
|> Ash.create!(actor: actor)
|
||||
|
||||
# Now assign fee type to member
|
||||
member =
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||
|> Ash.update!()
|
||||
|> Ash.update!(actor: actor)
|
||||
|
||||
# Generate cycles with specific "today" date
|
||||
today = ~D[2024-06-15]
|
||||
|
|
@ -130,17 +141,20 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
assert 2022 not in new_cycle_years
|
||||
end
|
||||
|
||||
test "respects left_at boundary (stops generation)" do
|
||||
setup_settings(true)
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
test "respects left_at boundary (stops generation)", %{actor: actor} do
|
||||
setup_settings(true, actor)
|
||||
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
||||
|
||||
member =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2022-03-15],
|
||||
exit_date: ~D[2023-06-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2022-01-01]
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2022-03-15],
|
||||
exit_date: ~D[2023-06-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2022-01-01]
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
# Generate cycles with specific "today" date far in the future
|
||||
today = ~D[2025-06-15]
|
||||
|
|
@ -154,16 +168,19 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
assert 2025 not in cycle_years
|
||||
end
|
||||
|
||||
test "skips existing cycles (idempotent)" do
|
||||
setup_settings(true)
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
test "skips existing cycles (idempotent)", %{actor: actor} do
|
||||
setup_settings(true, actor)
|
||||
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
||||
|
||||
member =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2023-03-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2023-01-01]
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2023-03-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2023-01-01]
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
today = ~D[2024-06-15]
|
||||
|
||||
|
|
@ -177,37 +194,43 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
assert second_cycles == []
|
||||
end
|
||||
|
||||
test "does not fill gaps when cycles were deleted" do
|
||||
setup_settings(true)
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
test "does not fill gaps when cycles were deleted", %{actor: actor} do
|
||||
setup_settings(true, actor)
|
||||
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
||||
|
||||
# Create member without fee type first to control which cycles exist
|
||||
member =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2020-03-15],
|
||||
membership_fee_start_date: ~D[2020-01-01]
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2020-03-15],
|
||||
membership_fee_start_date: ~D[2020-01-01]
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
# Manually create cycles for 2020, 2021, 2022, 2023
|
||||
for year <- [2020, 2021, 2022, 2023] do
|
||||
MembershipFeeCycle
|
||||
|> Ash.Changeset.for_create(:create, %{
|
||||
cycle_start: Date.new!(year, 1, 1),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id,
|
||||
amount: fee_type.amount,
|
||||
status: :unpaid
|
||||
})
|
||||
|> Ash.create!()
|
||||
|> Ash.Changeset.for_create(
|
||||
:create,
|
||||
%{
|
||||
cycle_start: Date.new!(year, 1, 1),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id,
|
||||
amount: fee_type.amount,
|
||||
status: :unpaid
|
||||
}
|
||||
)
|
||||
|> Ash.create!(actor: actor)
|
||||
end
|
||||
|
||||
# Delete the 2021 cycle (create a gap)
|
||||
cycle_2021 =
|
||||
MembershipFeeCycle
|
||||
|> Ash.Query.filter(member_id == ^member.id and cycle_start == ^~D[2021-01-01])
|
||||
|> Ash.read_one!()
|
||||
|> Ash.read_one!(actor: actor)
|
||||
|
||||
Ash.destroy!(cycle_2021)
|
||||
Ash.destroy!(cycle_2021, actor: actor)
|
||||
|
||||
# Now assign fee type to member (this triggers generation)
|
||||
# Since cycles already exist (2020, 2022, 2023), the generator will
|
||||
|
|
@ -215,10 +238,10 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
member =
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||
|> Ash.update!()
|
||||
|> Ash.update!(actor: actor)
|
||||
|
||||
# Verify gap was NOT filled and new cycles were generated from last existing
|
||||
all_cycles = get_member_cycles(member.id)
|
||||
all_cycles = get_member_cycles(member.id, actor)
|
||||
all_cycle_years = Enum.map(all_cycles, & &1.cycle_start.year) |> Enum.sort()
|
||||
|
||||
# 2021 should NOT exist (gap was not filled)
|
||||
|
|
@ -234,20 +257,23 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
assert 2025 in all_cycle_years
|
||||
end
|
||||
|
||||
test "sets correct amount from membership fee type" do
|
||||
setup_settings(true)
|
||||
test "sets correct amount from membership fee type", %{actor: actor} do
|
||||
setup_settings(true, actor)
|
||||
amount = Decimal.new("75.50")
|
||||
fee_type = create_fee_type(%{interval: :yearly, amount: amount})
|
||||
fee_type = create_fee_type(%{interval: :yearly, amount: amount}, actor)
|
||||
|
||||
member =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2024-03-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2024-01-01]
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2024-03-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2024-01-01]
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
# Verify cycles were generated with correct amount
|
||||
all_cycles = get_member_cycles(member.id)
|
||||
all_cycles = get_member_cycles(member.id, actor)
|
||||
refute Enum.empty?(all_cycles), "Expected cycles to be generated"
|
||||
|
||||
# All cycles should have the correct amount
|
||||
|
|
@ -256,21 +282,24 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
end)
|
||||
end
|
||||
|
||||
test "handles NULL membership_fee_start_date by calculating from join_date" do
|
||||
setup_settings(true)
|
||||
fee_type = create_fee_type(%{interval: :quarterly})
|
||||
test "handles NULL membership_fee_start_date by calculating from join_date", %{actor: actor} do
|
||||
setup_settings(true, actor)
|
||||
fee_type = create_fee_type(%{interval: :quarterly}, actor)
|
||||
|
||||
# Create member without membership_fee_start_date - it will be auto-calculated
|
||||
# and cycles will be auto-generated
|
||||
member =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2024-02-15],
|
||||
membership_fee_type_id: fee_type.id
|
||||
# No membership_fee_start_date - should be calculated
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2024-02-15],
|
||||
membership_fee_type_id: fee_type.id
|
||||
# No membership_fee_start_date - should be calculated
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
# Verify cycles were auto-generated
|
||||
all_cycles = get_member_cycles(member.id)
|
||||
all_cycles = get_member_cycles(member.id, actor)
|
||||
|
||||
# With include_joining_cycle=true and join_date=2024-02-15 (quarterly),
|
||||
# start_date should be 2024-01-01 (Q1 start)
|
||||
|
|
@ -284,28 +313,34 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
assert first_cycle_start == ~D[2024-01-01]
|
||||
end
|
||||
|
||||
test "returns error when member has no membership_fee_type" do
|
||||
test "returns error when member has no membership_fee_type", %{actor: actor} do
|
||||
# Create member without fee type - no auto-generation will occur
|
||||
member =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2024-03-15]
|
||||
# No membership_fee_type_id
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2024-03-15]
|
||||
# No membership_fee_type_id
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
{:error, reason} = CycleGenerator.generate_cycles_for_member(member.id)
|
||||
assert reason == :no_membership_fee_type
|
||||
end
|
||||
|
||||
test "returns error when member has no join_date" do
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
test "returns error when member has no join_date", %{actor: actor} do
|
||||
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
||||
|
||||
# Create member without join_date - no auto-generation will occur
|
||||
# (after_action hook checks for join_date)
|
||||
member =
|
||||
create_member_without_cycles(%{
|
||||
membership_fee_type_id: fee_type.id
|
||||
# No join_date
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
membership_fee_type_id: fee_type.id
|
||||
# No join_date
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
{:error, reason} = CycleGenerator.generate_cycles_for_member(member.id)
|
||||
assert reason == :no_join_date
|
||||
|
|
@ -357,24 +392,30 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
end
|
||||
|
||||
describe "generate_cycles_for_all_members/1" do
|
||||
test "generates cycles for multiple members" do
|
||||
setup_settings(true)
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
test "generates cycles for multiple members", %{actor: actor} do
|
||||
setup_settings(true, actor)
|
||||
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
||||
|
||||
# Create multiple members
|
||||
_member1 =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2024-01-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2024-01-01]
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2024-01-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2024-01-01]
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
_member2 =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2024-02-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2024-01-01]
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2024-02-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2024-01-01]
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
today = ~D[2024-06-15]
|
||||
{:ok, results} = CycleGenerator.generate_cycles_for_all_members(today: today)
|
||||
|
|
@ -387,16 +428,19 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
|||
end
|
||||
|
||||
describe "lock mechanism" do
|
||||
test "prevents concurrent generation for same member" do
|
||||
setup_settings(true)
|
||||
fee_type = create_fee_type(%{interval: :yearly})
|
||||
test "prevents concurrent generation for same member", %{actor: actor} do
|
||||
setup_settings(true, actor)
|
||||
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
||||
|
||||
member =
|
||||
create_member_without_cycles(%{
|
||||
join_date: ~D[2022-03-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2022-01-01]
|
||||
})
|
||||
create_member_without_cycles(
|
||||
%{
|
||||
join_date: ~D[2022-03-15],
|
||||
membership_fee_type_id: fee_type.id,
|
||||
membership_fee_start_date: ~D[2022-01-01]
|
||||
},
|
||||
actor
|
||||
)
|
||||
|
||||
today = ~D[2024-06-15]
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue