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.
270 lines
8.4 KiB
Elixir
270 lines
8.4 KiB
Elixir
defmodule Mv.MembershipFees.MembershipFeeCyclePoliciesTest do
|
|
@moduledoc """
|
|
Tests for MembershipFeeCycle resource authorization policies.
|
|
|
|
Verifies own_data can only read :linked (linked member's cycles);
|
|
read_only can only read (no create/update/destroy);
|
|
normal_user and admin can read, create, update, destroy (including mark_as_paid).
|
|
"""
|
|
use Mv.DataCase, async: false
|
|
|
|
import Mv.Fixtures, only: [create_fee_type: 1, create_cycle: 3]
|
|
|
|
alias Mv.Membership
|
|
alias Mv.MembershipFees
|
|
|
|
setup do
|
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
%{actor: system_actor}
|
|
end
|
|
|
|
defp create_member_fixture do
|
|
admin = Mv.Fixtures.user_with_role_fixture("admin")
|
|
|
|
{:ok, member} =
|
|
Membership.create_member(
|
|
%{
|
|
first_name: "Test",
|
|
last_name: "Member",
|
|
email: "test#{System.unique_integer([:positive])}@example.com"
|
|
},
|
|
actor: admin
|
|
)
|
|
|
|
member
|
|
end
|
|
|
|
defp fee_type_fixture do
|
|
create_fee_type(%{amount: Decimal.new("10.00"), description: "Test"})
|
|
end
|
|
|
|
defp cycle_fixture do
|
|
create_cycle(create_member_fixture(), fee_type_fixture(), %{
|
|
cycle_start: Date.utc_today(),
|
|
amount: Decimal.new("10.00")
|
|
})
|
|
end
|
|
|
|
describe "own_data permission set" do
|
|
setup %{actor: actor} do
|
|
user = Mv.Fixtures.user_with_role_fixture("own_data")
|
|
linked_member = create_member_fixture()
|
|
other_member = create_member_fixture()
|
|
fee_type = fee_type_fixture()
|
|
admin = Mv.Fixtures.user_with_role_fixture("admin")
|
|
|
|
user =
|
|
user
|
|
|> Ash.Changeset.for_update(:update, %{}, domain: Mv.Accounts)
|
|
|> Ash.Changeset.force_change_attribute(:member_id, linked_member.id)
|
|
|> Ash.update(actor: admin, domain: Mv.Accounts)
|
|
|
|
{:ok, user} = Ash.load(user, :role, domain: Mv.Accounts, actor: actor)
|
|
|
|
{:ok, cycle_linked} =
|
|
MembershipFees.create_membership_fee_cycle(
|
|
%{
|
|
member_id: linked_member.id,
|
|
membership_fee_type_id: fee_type.id,
|
|
cycle_start: Date.utc_today(),
|
|
amount: Decimal.new("10.00"),
|
|
status: :unpaid
|
|
},
|
|
actor: admin
|
|
)
|
|
|
|
{:ok, cycle_other} =
|
|
MembershipFees.create_membership_fee_cycle(
|
|
%{
|
|
member_id: other_member.id,
|
|
membership_fee_type_id: fee_type.id,
|
|
cycle_start: Date.add(Date.utc_today(), -365),
|
|
amount: Decimal.new("10.00"),
|
|
status: :unpaid
|
|
},
|
|
actor: admin
|
|
)
|
|
|
|
%{user: user, cycle_linked: cycle_linked, cycle_other: cycle_other}
|
|
end
|
|
|
|
test "can read only linked member's cycles", %{
|
|
user: user,
|
|
cycle_linked: cycle_linked,
|
|
cycle_other: cycle_other
|
|
} do
|
|
{:ok, list} =
|
|
Mv.MembershipFees.MembershipFeeCycle
|
|
|> Ash.read(actor: user, domain: Mv.MembershipFees)
|
|
|
|
ids = Enum.map(list, & &1.id)
|
|
assert cycle_linked.id in ids
|
|
refute cycle_other.id in ids
|
|
end
|
|
end
|
|
|
|
describe "read_only permission set" do
|
|
setup %{actor: actor} do
|
|
user = Mv.Fixtures.user_with_role_fixture("read_only")
|
|
cycle = cycle_fixture()
|
|
%{actor: actor, user: user, cycle: cycle}
|
|
end
|
|
|
|
test "can read membership_fee_cycles (list)", %{user: user} do
|
|
{:ok, list} =
|
|
Mv.MembershipFees.MembershipFeeCycle
|
|
|> Ash.read(actor: user, domain: Mv.MembershipFees)
|
|
|
|
assert is_list(list)
|
|
end
|
|
|
|
test "cannot update cycle (returns forbidden)", %{user: user, cycle: cycle} do
|
|
assert {:error, %Ash.Error.Forbidden{}} =
|
|
MembershipFees.update_membership_fee_cycle(cycle, %{status: :paid}, actor: user)
|
|
end
|
|
|
|
test "cannot mark_as_paid (returns forbidden)", %{user: user, cycle: cycle} do
|
|
assert {:error, %Ash.Error.Forbidden{}} =
|
|
cycle
|
|
|> Ash.Changeset.for_update(:mark_as_paid, %{}, domain: Mv.MembershipFees)
|
|
|> Ash.update(actor: user, domain: Mv.MembershipFees)
|
|
end
|
|
|
|
test "cannot create cycle (returns forbidden)", %{user: user, actor: _actor} do
|
|
member = create_member_fixture()
|
|
fee_type = fee_type_fixture()
|
|
|
|
assert {:error, %Ash.Error.Forbidden{}} =
|
|
MembershipFees.create_membership_fee_cycle(
|
|
%{
|
|
member_id: member.id,
|
|
membership_fee_type_id: fee_type.id,
|
|
cycle_start: Date.utc_today(),
|
|
amount: Decimal.new("10.00"),
|
|
status: :unpaid
|
|
},
|
|
actor: user
|
|
)
|
|
end
|
|
|
|
test "cannot destroy cycle (returns forbidden)", %{user: user, cycle: cycle} do
|
|
assert {:error, %Ash.Error.Forbidden{}} =
|
|
MembershipFees.destroy_membership_fee_cycle(cycle, actor: user)
|
|
end
|
|
end
|
|
|
|
describe "normal_user permission set" do
|
|
setup %{actor: actor} do
|
|
user = Mv.Fixtures.user_with_role_fixture("normal_user")
|
|
cycle = cycle_fixture()
|
|
%{actor: actor, user: user, cycle: cycle}
|
|
end
|
|
|
|
test "can read membership_fee_cycles (list)", %{user: user} do
|
|
{:ok, list} =
|
|
Mv.MembershipFees.MembershipFeeCycle
|
|
|> Ash.read(actor: user, domain: Mv.MembershipFees)
|
|
|
|
assert is_list(list)
|
|
end
|
|
|
|
test "can update cycle status", %{user: user, cycle: cycle} do
|
|
assert {:ok, updated} =
|
|
MembershipFees.update_membership_fee_cycle(cycle, %{status: :paid}, actor: user)
|
|
|
|
assert updated.status == :paid
|
|
end
|
|
|
|
test "can mark_as_paid", %{user: user, cycle: cycle} do
|
|
assert {:ok, updated} =
|
|
cycle
|
|
|> Ash.Changeset.for_update(:mark_as_paid, %{}, domain: Mv.MembershipFees)
|
|
|> Ash.update(actor: user, domain: Mv.MembershipFees)
|
|
|
|
assert updated.status == :paid
|
|
end
|
|
|
|
test "can create cycle", %{user: user, actor: _actor} do
|
|
member = create_member_fixture()
|
|
fee_type = fee_type_fixture()
|
|
|
|
assert {:ok, created} =
|
|
MembershipFees.create_membership_fee_cycle(
|
|
%{
|
|
member_id: member.id,
|
|
membership_fee_type_id: fee_type.id,
|
|
cycle_start: Date.utc_today(),
|
|
amount: Decimal.new("10.00"),
|
|
status: :unpaid
|
|
},
|
|
actor: user
|
|
)
|
|
|
|
assert created.member_id == member.id
|
|
end
|
|
|
|
test "can destroy cycle", %{user: user, cycle: cycle} do
|
|
assert :ok = MembershipFees.destroy_membership_fee_cycle(cycle, actor: user)
|
|
end
|
|
end
|
|
|
|
describe "admin permission set" do
|
|
setup %{actor: actor} do
|
|
user = Mv.Fixtures.user_with_role_fixture("admin")
|
|
cycle = cycle_fixture()
|
|
%{actor: actor, user: user, cycle: cycle}
|
|
end
|
|
|
|
test "can read membership_fee_cycles (list)", %{user: user} do
|
|
{:ok, list} =
|
|
Mv.MembershipFees.MembershipFeeCycle
|
|
|> Ash.read(actor: user, domain: Mv.MembershipFees)
|
|
|
|
assert is_list(list)
|
|
end
|
|
|
|
test "can update cycle", %{user: user, cycle: cycle} do
|
|
assert {:ok, updated} =
|
|
MembershipFees.update_membership_fee_cycle(cycle, %{status: :paid}, actor: user)
|
|
|
|
assert updated.status == :paid
|
|
end
|
|
|
|
test "can mark_as_paid", %{user: user, cycle: cycle} do
|
|
cycle_unpaid =
|
|
cycle
|
|
|> Ash.Changeset.for_update(:mark_as_unpaid, %{}, domain: Mv.MembershipFees)
|
|
|> Ash.update!(actor: user, domain: Mv.MembershipFees)
|
|
|
|
assert {:ok, updated} =
|
|
cycle_unpaid
|
|
|> Ash.Changeset.for_update(:mark_as_paid, %{}, domain: Mv.MembershipFees)
|
|
|> Ash.update(actor: user, domain: Mv.MembershipFees)
|
|
|
|
assert updated.status == :paid
|
|
end
|
|
|
|
test "can create cycle", %{user: user, actor: _actor} do
|
|
member = create_member_fixture()
|
|
fee_type = fee_type_fixture()
|
|
|
|
assert {:ok, created} =
|
|
MembershipFees.create_membership_fee_cycle(
|
|
%{
|
|
member_id: member.id,
|
|
membership_fee_type_id: fee_type.id,
|
|
cycle_start: Date.utc_today(),
|
|
amount: Decimal.new("10.00"),
|
|
status: :unpaid
|
|
},
|
|
actor: user
|
|
)
|
|
|
|
assert created.member_id == member.id
|
|
end
|
|
|
|
test "can destroy cycle", %{user: user, cycle: cycle} do
|
|
assert :ok = MembershipFees.destroy_membership_fee_cycle(cycle, actor: user)
|
|
end
|
|
end
|
|
end
|