Complete Permissions for Groups, Membership Fees, and User Role Assignment closes #404 #405
2 changed files with 18 additions and 31 deletions
|
|
@ -81,8 +81,8 @@ lib/
|
||||||
├── membership/ # Membership domain
|
├── membership/ # Membership domain
|
||||||
│ ├── membership.ex # Domain definition
|
│ ├── membership.ex # Domain definition
|
||||||
│ ├── member.ex # Member resource
|
│ ├── member.ex # Member resource
|
||||||
|
│ ├── custom_field.ex # Custom field (definition) resource
|
||||||
│ ├── custom_field_value.ex # Custom field value resource
|
│ ├── custom_field_value.ex # Custom field value resource
|
||||||
│ ├── custom_field.ex # CustomFieldValue type resource
|
|
||||||
│ ├── setting.ex # Global settings (singleton resource)
|
│ ├── setting.ex # Global settings (singleton resource)
|
||||||
│ └── email.ex # Email custom type
|
│ └── email.ex # Email custom type
|
||||||
├── membership_fees/ # MembershipFees domain
|
├── membership_fees/ # MembershipFees domain
|
||||||
|
|
@ -194,7 +194,8 @@ test/
|
||||||
├── seeds_test.exs # Database seed tests
|
├── seeds_test.exs # Database seed tests
|
||||||
└── support/ # Test helpers
|
└── support/ # Test helpers
|
||||||
├── conn_case.ex # Controller test helpers
|
├── conn_case.ex # Controller test helpers
|
||||||
└── data_case.ex # Data layer test helpers
|
├── data_case.ex # Data layer test helpers
|
||||||
|
└── fixtures.ex # Shared test fixtures (Mv.Fixtures)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 1.2 Module Organization
|
### 1.2 Module Organization
|
||||||
|
|
@ -1247,7 +1248,8 @@ test/
|
||||||
│ └── components/
|
│ └── components/
|
||||||
└── support/ # Test helpers
|
└── support/ # Test helpers
|
||||||
├── conn_case.ex # Controller test setup
|
├── conn_case.ex # Controller test setup
|
||||||
└── data_case.ex # Database test setup
|
├── data_case.ex # Database test setup
|
||||||
|
└── fixtures.ex # Shared test fixtures (Mv.Fixtures)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Test File Naming:**
|
**Test File Naming:**
|
||||||
|
|
|
||||||
|
|
@ -28,21 +28,6 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
|> Ash.create!(actor: system_actor)
|
|> Ash.create!(actor: system_actor)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a member
|
|
||||||
defp create_member(attrs) do
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
||||||
|
|
||||||
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: system_actor)
|
|
||||||
member
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a cycle
|
# Helper to create a cycle
|
||||||
defp create_cycle(member, fee_type, attrs) do
|
defp create_cycle(member, fee_type, attrs) do
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
@ -73,7 +58,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
describe "cycles table display" do
|
describe "cycles table display" do
|
||||||
test "displays all cycles for member", %{conn: conn} do
|
test "displays all cycles for member", %{conn: conn} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
|
||||||
|
|
||||||
_cycle1 = create_cycle(member, fee_type, %{cycle_start: ~D[2022-01-01], status: :paid})
|
_cycle1 = create_cycle(member, fee_type, %{cycle_start: ~D[2022-01-01], status: :paid})
|
||||||
_cycle2 = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
_cycle2 = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
||||||
|
|
@ -95,7 +80,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
|
|
||||||
test "table columns show correct data", %{conn: conn} do
|
test "table columns show correct data", %{conn: conn} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly, amount: Decimal.new("60.00")})
|
fee_type = create_fee_type(%{interval: :yearly, amount: Decimal.new("60.00")})
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
|
||||||
|
|
||||||
create_cycle(member, fee_type, %{
|
create_cycle(member, fee_type, %{
|
||||||
cycle_start: ~D[2023-01-01],
|
cycle_start: ~D[2023-01-01],
|
||||||
|
|
@ -124,7 +109,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
yearly_type = create_fee_type(%{interval: :yearly, name: "Yearly Type"})
|
yearly_type = create_fee_type(%{interval: :yearly, name: "Yearly Type"})
|
||||||
_monthly_type = create_fee_type(%{interval: :monthly, name: "Monthly Type"})
|
_monthly_type = create_fee_type(%{interval: :monthly, name: "Monthly Type"})
|
||||||
|
|
||||||
member = create_member(%{membership_fee_type_id: yearly_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: yearly_type.id})
|
||||||
|
|
||||||
{:ok, _view, html} = live(conn, "/members/#{member.id}")
|
{:ok, _view, html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
@ -133,7 +118,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "shows no type message when no type assigned", %{conn: conn} do
|
test "shows no type message when no type assigned", %{conn: conn} do
|
||||||
member = create_member(%{})
|
member = Mv.Fixtures.member_fixture(%{})
|
||||||
|
|
||||||
{:ok, _view, html} = live(conn, "/members/#{member.id}")
|
{:ok, _view, html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
@ -145,7 +130,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
describe "status change actions" do
|
describe "status change actions" do
|
||||||
test "mark as paid works", %{conn: conn} do
|
test "mark as paid works", %{conn: conn} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
|
||||||
|
|
||||||
cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
||||||
|
|
||||||
|
|
@ -176,7 +161,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
|
|
||||||
test "mark as suspended works", %{conn: conn} do
|
test "mark as suspended works", %{conn: conn} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
|
||||||
|
|
||||||
cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
||||||
|
|
||||||
|
|
@ -207,7 +192,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
|
|
||||||
test "mark as unpaid works", %{conn: conn} do
|
test "mark as unpaid works", %{conn: conn} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
|
||||||
|
|
||||||
cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :paid})
|
cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :paid})
|
||||||
|
|
||||||
|
|
@ -240,7 +225,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
describe "cycle regeneration" do
|
describe "cycle regeneration" do
|
||||||
test "manual regeneration button exists and can be clicked", %{conn: conn} do
|
test "manual regeneration button exists and can be clicked", %{conn: conn} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
@ -266,7 +251,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
describe "edge cases" do
|
describe "edge cases" do
|
||||||
test "handles members without membership fee type gracefully", %{conn: conn} do
|
test "handles members without membership fee type gracefully", %{conn: conn} do
|
||||||
# No fee type
|
# No fee type
|
||||||
member = create_member(%{})
|
member = Mv.Fixtures.member_fixture(%{})
|
||||||
|
|
||||||
{:ok, _view, html} = live(conn, "/members/#{member.id}")
|
{:ok, _view, html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
@ -282,7 +267,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
conn: conn
|
conn: conn
|
||||||
} do
|
} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
|
||||||
_cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
_cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
@ -301,7 +286,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
conn: conn
|
conn: conn
|
||||||
} do
|
} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
|
||||||
cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
@ -327,7 +312,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
# (e.g. via dev tools), the server would enforce policy and show an error.
|
# (e.g. via dev tools), the server would enforce policy and show an error.
|
||||||
# This test verifies that Ash.destroy(cycle, actor: read_only_user) returns Forbidden.
|
# This test verifies that Ash.destroy(cycle, actor: read_only_user) returns Forbidden.
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
|
||||||
cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
cycle = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
||||||
|
|
||||||
assert {:error, %Ash.Error.Forbidden{}} =
|
assert {:error, %Ash.Error.Forbidden{}} =
|
||||||
|
|
@ -342,7 +327,7 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
conn = put_session(conn, :locale, "en")
|
conn = put_session(conn, :locale, "en")
|
||||||
|
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = Mv.Fixtures.member_fixture(%{membership_fee_type_id: fee_type.id})
|
||||||
_c1 = create_cycle(member, fee_type, %{cycle_start: ~D[2022-01-01], status: :paid})
|
_c1 = create_cycle(member, fee_type, %{cycle_start: ~D[2022-01-01], status: :paid})
|
||||||
_c2 = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
_c2 = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue