Replace the create_fee_type/create_cycle helpers duplicated across 18/8 membership-fee test files with a single shared definition in Mv.Fixtures, reconciling the divergent local signatures (including the reversed argument order) into one superset so behavior is unchanged.
184 lines
6.8 KiB
Elixir
184 lines
6.8 KiB
Elixir
defmodule Mv.MembershipFees.MembershipFeeCycleTest do
|
|
@moduledoc """
|
|
Tests for MembershipFeeCycle resource, focusing on status management actions.
|
|
"""
|
|
use Mv.DataCase, async: true
|
|
|
|
import Mv.Fixtures, only: [create_fee_type: 2, create_cycle: 4]
|
|
|
|
alias Mv.MembershipFees.MembershipFeeCycle
|
|
|
|
setup do
|
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
%{actor: system_actor}
|
|
end
|
|
|
|
# Helper to create a member
|
|
defp create_member(attrs, actor) do
|
|
default_attrs = %{
|
|
first_name: "Test",
|
|
last_name: "Member",
|
|
email: "test.member.#{System.unique_integer([:positive])}@example.com"
|
|
}
|
|
|
|
attrs = Map.merge(default_attrs, attrs)
|
|
{:ok, member} = Mv.Membership.create_member(attrs, actor: actor)
|
|
member
|
|
end
|
|
|
|
describe "status defaults" do
|
|
test "status defaults to :unpaid when creating a cycle", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
|
|
cycle =
|
|
MembershipFeeCycle
|
|
|> Ash.Changeset.for_create(:create, %{
|
|
cycle_start: ~D[2024-01-01],
|
|
amount: Decimal.new("50.00"),
|
|
member_id: member.id,
|
|
membership_fee_type_id: fee_type.id
|
|
})
|
|
|> Ash.create!(actor: actor)
|
|
|
|
assert cycle.status == :unpaid
|
|
end
|
|
end
|
|
|
|
describe "mark_as_paid" do
|
|
test "sets status to :paid", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
cycle = create_cycle(member, fee_type, %{status: :unpaid}, actor)
|
|
|
|
assert {:ok, updated} = Ash.update(cycle, %{}, actor: actor, action: :mark_as_paid)
|
|
assert updated.status == :paid
|
|
end
|
|
|
|
test "can set notes when marking as paid", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
cycle = create_cycle(member, fee_type, %{status: :unpaid}, actor)
|
|
|
|
assert {:ok, updated} =
|
|
Ash.update(cycle, %{notes: "Payment received via bank transfer"},
|
|
actor: actor,
|
|
action: :mark_as_paid
|
|
)
|
|
|
|
assert updated.status == :paid
|
|
assert updated.notes == "Payment received via bank transfer"
|
|
end
|
|
|
|
test "can change from suspended to paid", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
cycle = create_cycle(member, fee_type, %{status: :suspended}, actor)
|
|
|
|
assert {:ok, updated} = Ash.update(cycle, %{}, actor: actor, action: :mark_as_paid)
|
|
assert updated.status == :paid
|
|
end
|
|
end
|
|
|
|
describe "mark_as_suspended" do
|
|
test "sets status to :suspended", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
cycle = create_cycle(member, fee_type, %{status: :unpaid}, actor)
|
|
|
|
assert {:ok, updated} = Ash.update(cycle, %{}, actor: actor, action: :mark_as_suspended)
|
|
assert updated.status == :suspended
|
|
end
|
|
|
|
test "can set notes when marking as suspended", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
cycle = create_cycle(member, fee_type, %{status: :unpaid}, actor)
|
|
|
|
assert {:ok, updated} =
|
|
Ash.update(cycle, %{notes: "Waived due to special circumstances"},
|
|
actor: actor,
|
|
action: :mark_as_suspended
|
|
)
|
|
|
|
assert updated.status == :suspended
|
|
assert updated.notes == "Waived due to special circumstances"
|
|
end
|
|
|
|
test "can change from paid to suspended", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
cycle = create_cycle(member, fee_type, %{status: :paid}, actor)
|
|
|
|
assert {:ok, updated} = Ash.update(cycle, %{}, actor: actor, action: :mark_as_suspended)
|
|
assert updated.status == :suspended
|
|
end
|
|
end
|
|
|
|
describe "mark_as_unpaid" do
|
|
test "sets status to :unpaid", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
cycle = create_cycle(member, fee_type, %{status: :paid}, actor)
|
|
|
|
assert {:ok, updated} = Ash.update(cycle, %{}, actor: actor, action: :mark_as_unpaid)
|
|
assert updated.status == :unpaid
|
|
end
|
|
|
|
test "can set notes when marking as unpaid", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
cycle = create_cycle(member, fee_type, %{status: :paid}, actor)
|
|
|
|
assert {:ok, updated} =
|
|
Ash.update(cycle, %{notes: "Payment was reversed"},
|
|
actor: actor,
|
|
action: :mark_as_unpaid
|
|
)
|
|
|
|
assert updated.status == :unpaid
|
|
assert updated.notes == "Payment was reversed"
|
|
end
|
|
|
|
test "can change from suspended to unpaid", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
cycle = create_cycle(member, fee_type, %{status: :suspended}, actor)
|
|
|
|
assert {:ok, updated} = Ash.update(cycle, %{}, actor: actor, action: :mark_as_unpaid)
|
|
assert updated.status == :unpaid
|
|
end
|
|
end
|
|
|
|
describe "status transitions" do
|
|
test "all status transitions are allowed", %{actor: actor} do
|
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
|
member = create_member(%{membership_fee_type_id: fee_type.id}, actor)
|
|
|
|
# unpaid -> paid
|
|
cycle1 = create_cycle(member, fee_type, %{status: :unpaid}, actor)
|
|
assert {:ok, c1} = Ash.update(cycle1, %{}, actor: actor, action: :mark_as_paid)
|
|
assert c1.status == :paid
|
|
|
|
# paid -> suspended
|
|
assert {:ok, c2} = Ash.update(c1, %{}, actor: actor, action: :mark_as_suspended)
|
|
assert c2.status == :suspended
|
|
|
|
# suspended -> unpaid
|
|
assert {:ok, c3} = Ash.update(c2, %{}, actor: actor, action: :mark_as_unpaid)
|
|
assert c3.status == :unpaid
|
|
|
|
# unpaid -> suspended
|
|
assert {:ok, c4} = Ash.update(c3, %{}, actor: actor, action: :mark_as_suspended)
|
|
assert c4.status == :suspended
|
|
|
|
# suspended -> paid
|
|
assert {:ok, c5} = Ash.update(c4, %{}, actor: actor, action: :mark_as_paid)
|
|
assert c5.status == :paid
|
|
|
|
# paid -> unpaid
|
|
assert {:ok, c6} = Ash.update(c5, %{}, actor: actor, action: :mark_as_unpaid)
|
|
assert c6.status == :unpaid
|
|
end
|
|
end
|
|
end
|