fix existing flakiness + cut runtime closes #533 #544
19 changed files with 279 additions and 513 deletions
|
|
@ -4,30 +4,15 @@ defmodule Mv.Membership.MemberCycleCalculationsTest do
|
||||||
"""
|
"""
|
||||||
use Mv.DataCase, async: true
|
use Mv.DataCase, async: true
|
||||||
|
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2, create_cycle: 4]
|
||||||
|
|
||||||
alias Mv.MembershipFees.CalendarCycles
|
alias Mv.MembershipFees.CalendarCycles
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
%{actor: system_actor}
|
%{actor: system_actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member
|
# Helper to create a member
|
||||||
defp create_member(attrs, actor) do
|
defp create_member(attrs, actor) do
|
||||||
default_attrs = %{
|
default_attrs = %{
|
||||||
|
|
@ -41,23 +26,6 @@ defmodule Mv.Membership.MemberCycleCalculationsTest do
|
||||||
member
|
member
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a cycle
|
|
||||||
defp create_cycle(member, fee_type, attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
cycle_start: ~D[2024-01-01],
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
member_id: member.id,
|
|
||||||
membership_fee_type_id: fee_type.id,
|
|
||||||
status: :unpaid
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeCycle
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "current_cycle_status" do
|
describe "current_cycle_status" do
|
||||||
test "returns status of current cycle for member with active cycle", %{actor: actor} do
|
test "returns status of current cycle for member with active cycle", %{actor: actor} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ defmodule Mv.Membership.MemberTypeChangeIntegrationTest do
|
||||||
"""
|
"""
|
||||||
use Mv.DataCase, async: true
|
use Mv.DataCase, async: true
|
||||||
|
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2, create_cycle: 4]
|
||||||
|
|
||||||
alias Mv.MembershipFees.CalendarCycles
|
alias Mv.MembershipFees.CalendarCycles
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
alias Mv.MembershipFees.MembershipFeeCycle
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
|
|
@ -15,21 +16,6 @@ defmodule Mv.Membership.MemberTypeChangeIntegrationTest do
|
||||||
%{actor: system_actor}
|
%{actor: system_actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member
|
# Helper to create a member
|
||||||
defp create_member(attrs, actor) do
|
defp create_member(attrs, actor) do
|
||||||
default_attrs = %{
|
default_attrs = %{
|
||||||
|
|
@ -44,23 +30,6 @@ defmodule Mv.Membership.MemberTypeChangeIntegrationTest do
|
||||||
member
|
member
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a cycle
|
|
||||||
defp create_cycle(member, fee_type, attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
cycle_start: ~D[2024-01-01],
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
member_id: member.id,
|
|
||||||
membership_fee_type_id: fee_type.id,
|
|
||||||
status: :unpaid
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeCycle
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "type change cycle regeneration" do
|
describe "type change cycle regeneration" do
|
||||||
test "future unpaid cycles are regenerated with new amount", %{actor: actor} do
|
test "future unpaid cycles are regenerated with new amount", %{actor: actor} do
|
||||||
today = Date.utc_today()
|
today = Date.utc_today()
|
||||||
|
|
|
||||||
|
|
@ -4,29 +4,15 @@ defmodule Mv.MembershipFees.Changes.ValidateSameIntervalTest do
|
||||||
"""
|
"""
|
||||||
use Mv.DataCase, async: true
|
use Mv.DataCase, async: true
|
||||||
|
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2]
|
||||||
|
|
||||||
alias Mv.MembershipFees.Changes.ValidateSameInterval
|
alias Mv.MembershipFees.Changes.ValidateSameInterval
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
%{actor: system_actor}
|
%{actor: system_actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member
|
# Helper to create a member
|
||||||
defp create_member(attrs, actor) do
|
defp create_member(attrs, actor) do
|
||||||
default_attrs = %{
|
default_attrs = %{
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,9 @@ defmodule Mv.MembershipFees.MemberCycleIntegrationTest do
|
||||||
"""
|
"""
|
||||||
use Mv.DataCase, async: false
|
use Mv.DataCase, async: false
|
||||||
|
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2]
|
||||||
|
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
alias Mv.MembershipFees.MembershipFeeCycle
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
|
|
@ -14,21 +15,6 @@ defmodule Mv.MembershipFees.MemberCycleIntegrationTest do
|
||||||
%{actor: system_actor}
|
%{actor: system_actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to set up settings
|
# Helper to set up settings
|
||||||
defp setup_settings(include_joining_cycle, actor) do
|
defp setup_settings(include_joining_cycle, actor) do
|
||||||
{:ok, settings} = Mv.Membership.get_settings()
|
{:ok, settings} = Mv.Membership.get_settings()
|
||||||
|
|
|
||||||
|
|
@ -4,29 +4,15 @@ defmodule Mv.MembershipFees.MembershipFeeCycleTest do
|
||||||
"""
|
"""
|
||||||
use Mv.DataCase, async: true
|
use Mv.DataCase, async: true
|
||||||
|
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2, create_cycle: 4]
|
||||||
|
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
alias Mv.MembershipFees.MembershipFeeCycle
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
%{actor: system_actor}
|
%{actor: system_actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member
|
# Helper to create a member
|
||||||
defp create_member(attrs, actor) do
|
defp create_member(attrs, actor) do
|
||||||
default_attrs = %{
|
default_attrs = %{
|
||||||
|
|
@ -40,22 +26,6 @@ defmodule Mv.MembershipFees.MembershipFeeCycleTest do
|
||||||
member
|
member
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a cycle
|
|
||||||
defp create_cycle(member, fee_type, attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
cycle_start: ~D[2024-01-01],
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
member_id: member.id,
|
|
||||||
membership_fee_type_id: fee_type.id
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeCycle
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "status defaults" do
|
describe "status defaults" do
|
||||||
test "status defaults to :unpaid when creating a cycle", %{actor: actor} do
|
test "status defaults to :unpaid when creating a cycle", %{actor: actor} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
fee_type = create_fee_type(%{interval: :yearly}, actor)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ defmodule Mv.MembershipFees.MembershipFeeTypeIntegrationTest do
|
||||||
"""
|
"""
|
||||||
use Mv.DataCase, async: false
|
use Mv.DataCase, async: false
|
||||||
|
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2]
|
||||||
|
|
||||||
alias Mv.Membership.Member
|
alias Mv.Membership.Member
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
alias Mv.MembershipFees.MembershipFeeCycle
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
alias Mv.MembershipFees.MembershipFeeType
|
||||||
|
|
@ -15,21 +17,6 @@ defmodule Mv.MembershipFees.MembershipFeeTypeIntegrationTest do
|
||||||
%{actor: system_actor}
|
%{actor: system_actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "admin can create membership fee type" do
|
describe "admin can create membership fee type" do
|
||||||
test "creates type with all fields", %{actor: actor} do
|
test "creates type with all fields", %{actor: actor} do
|
||||||
attrs = %{
|
attrs = %{
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,10 @@ defmodule Mv.MembershipFees.CycleGeneratorEdgeCasesTest do
|
||||||
"""
|
"""
|
||||||
use Mv.DataCase, async: false
|
use Mv.DataCase, async: false
|
||||||
|
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2]
|
||||||
|
|
||||||
alias Mv.MembershipFees.CycleGenerator
|
alias Mv.MembershipFees.CycleGenerator
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
alias Mv.MembershipFees.MembershipFeeCycle
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
|
|
@ -23,21 +24,6 @@ defmodule Mv.MembershipFees.CycleGeneratorEdgeCasesTest do
|
||||||
%{actor: system_actor}
|
%{actor: system_actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member. Note: If membership_fee_type_id is provided,
|
# Helper to create a member. Note: If membership_fee_type_id is provided,
|
||||||
# cycles will be auto-generated during creation in test environment.
|
# cycles will be auto-generated during creation in test environment.
|
||||||
defp create_member(attrs, actor) do
|
defp create_member(attrs, actor) do
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
"""
|
"""
|
||||||
use Mv.DataCase, async: false
|
use Mv.DataCase, async: false
|
||||||
|
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2]
|
||||||
|
|
||||||
alias Mv.MembershipFees.CycleGenerator
|
alias Mv.MembershipFees.CycleGenerator
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
alias Mv.MembershipFees.MembershipFeeCycle
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
|
|
@ -15,21 +16,6 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
|
||||||
%{actor: system_actor}
|
%{actor: system_actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member without triggering cycle generation
|
# Helper to create a member without triggering cycle generation
|
||||||
defp create_member_without_cycles(attrs, actor) do
|
defp create_member_without_cycles(attrs, actor) do
|
||||||
default_attrs = %{
|
default_attrs = %{
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@ defmodule Mv.MembershipFees.MembershipFeeCyclePoliciesTest do
|
||||||
"""
|
"""
|
||||||
use Mv.DataCase, async: false
|
use Mv.DataCase, async: false
|
||||||
|
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 1, create_cycle: 3]
|
||||||
|
|
||||||
alias Mv.Membership
|
alias Mv.Membership
|
||||||
alias Mv.MembershipFees
|
alias Mv.MembershipFees
|
||||||
|
|
||||||
|
|
@ -32,41 +34,15 @@ defmodule Mv.MembershipFees.MembershipFeeCyclePoliciesTest do
|
||||||
member
|
member
|
||||||
end
|
end
|
||||||
|
|
||||||
defp create_fee_type_fixture do
|
defp fee_type_fixture do
|
||||||
admin = Mv.Fixtures.user_with_role_fixture("admin")
|
create_fee_type(%{amount: Decimal.new("10.00"), description: "Test"})
|
||||||
|
|
||||||
{:ok, fee_type} =
|
|
||||||
MembershipFees.create_membership_fee_type(
|
|
||||||
%{
|
|
||||||
name: "Test Fee #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("10.00"),
|
|
||||||
interval: :yearly,
|
|
||||||
description: "Test"
|
|
||||||
},
|
|
||||||
actor: admin
|
|
||||||
)
|
|
||||||
|
|
||||||
fee_type
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp create_cycle_fixture do
|
defp cycle_fixture do
|
||||||
admin = Mv.Fixtures.user_with_role_fixture("admin")
|
create_cycle(create_member_fixture(), fee_type_fixture(), %{
|
||||||
member = create_member_fixture()
|
cycle_start: Date.utc_today(),
|
||||||
fee_type = create_fee_type_fixture()
|
amount: Decimal.new("10.00")
|
||||||
|
})
|
||||||
{:ok, cycle} =
|
|
||||||
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: admin
|
|
||||||
)
|
|
||||||
|
|
||||||
cycle
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "own_data permission set" do
|
describe "own_data permission set" do
|
||||||
|
|
@ -74,7 +50,7 @@ defmodule Mv.MembershipFees.MembershipFeeCyclePoliciesTest do
|
||||||
user = Mv.Fixtures.user_with_role_fixture("own_data")
|
user = Mv.Fixtures.user_with_role_fixture("own_data")
|
||||||
linked_member = create_member_fixture()
|
linked_member = create_member_fixture()
|
||||||
other_member = create_member_fixture()
|
other_member = create_member_fixture()
|
||||||
fee_type = create_fee_type_fixture()
|
fee_type = fee_type_fixture()
|
||||||
admin = Mv.Fixtures.user_with_role_fixture("admin")
|
admin = Mv.Fixtures.user_with_role_fixture("admin")
|
||||||
|
|
||||||
user =
|
user =
|
||||||
|
|
@ -130,7 +106,7 @@ defmodule Mv.MembershipFees.MembershipFeeCyclePoliciesTest do
|
||||||
describe "read_only permission set" do
|
describe "read_only permission set" do
|
||||||
setup %{actor: actor} do
|
setup %{actor: actor} do
|
||||||
user = Mv.Fixtures.user_with_role_fixture("read_only")
|
user = Mv.Fixtures.user_with_role_fixture("read_only")
|
||||||
cycle = create_cycle_fixture()
|
cycle = cycle_fixture()
|
||||||
%{actor: actor, user: user, cycle: cycle}
|
%{actor: actor, user: user, cycle: cycle}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -156,7 +132,7 @@ defmodule Mv.MembershipFees.MembershipFeeCyclePoliciesTest do
|
||||||
|
|
||||||
test "cannot create cycle (returns forbidden)", %{user: user, actor: _actor} do
|
test "cannot create cycle (returns forbidden)", %{user: user, actor: _actor} do
|
||||||
member = create_member_fixture()
|
member = create_member_fixture()
|
||||||
fee_type = create_fee_type_fixture()
|
fee_type = fee_type_fixture()
|
||||||
|
|
||||||
assert {:error, %Ash.Error.Forbidden{}} =
|
assert {:error, %Ash.Error.Forbidden{}} =
|
||||||
MembershipFees.create_membership_fee_cycle(
|
MembershipFees.create_membership_fee_cycle(
|
||||||
|
|
@ -180,7 +156,7 @@ defmodule Mv.MembershipFees.MembershipFeeCyclePoliciesTest do
|
||||||
describe "normal_user permission set" do
|
describe "normal_user permission set" do
|
||||||
setup %{actor: actor} do
|
setup %{actor: actor} do
|
||||||
user = Mv.Fixtures.user_with_role_fixture("normal_user")
|
user = Mv.Fixtures.user_with_role_fixture("normal_user")
|
||||||
cycle = create_cycle_fixture()
|
cycle = cycle_fixture()
|
||||||
%{actor: actor, user: user, cycle: cycle}
|
%{actor: actor, user: user, cycle: cycle}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -210,7 +186,7 @@ defmodule Mv.MembershipFees.MembershipFeeCyclePoliciesTest do
|
||||||
|
|
||||||
test "can create cycle", %{user: user, actor: _actor} do
|
test "can create cycle", %{user: user, actor: _actor} do
|
||||||
member = create_member_fixture()
|
member = create_member_fixture()
|
||||||
fee_type = create_fee_type_fixture()
|
fee_type = fee_type_fixture()
|
||||||
|
|
||||||
assert {:ok, created} =
|
assert {:ok, created} =
|
||||||
MembershipFees.create_membership_fee_cycle(
|
MembershipFees.create_membership_fee_cycle(
|
||||||
|
|
@ -235,7 +211,7 @@ defmodule Mv.MembershipFees.MembershipFeeCyclePoliciesTest do
|
||||||
describe "admin permission set" do
|
describe "admin permission set" do
|
||||||
setup %{actor: actor} do
|
setup %{actor: actor} do
|
||||||
user = Mv.Fixtures.user_with_role_fixture("admin")
|
user = Mv.Fixtures.user_with_role_fixture("admin")
|
||||||
cycle = create_cycle_fixture()
|
cycle = cycle_fixture()
|
||||||
%{actor: actor, user: user, cycle: cycle}
|
%{actor: actor, user: user, cycle: cycle}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -270,7 +246,7 @@ defmodule Mv.MembershipFees.MembershipFeeCyclePoliciesTest do
|
||||||
|
|
||||||
test "can create cycle", %{user: user, actor: _actor} do
|
test "can create cycle", %{user: user, actor: _actor} do
|
||||||
member = create_member_fixture()
|
member = create_member_fixture()
|
||||||
fee_type = create_fee_type_fixture()
|
fee_type = fee_type_fixture()
|
||||||
|
|
||||||
assert {:ok, created} =
|
assert {:ok, created} =
|
||||||
MembershipFees.create_membership_fee_cycle(
|
MembershipFees.create_membership_fee_cycle(
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ defmodule Mv.StatisticsTest do
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
import Ash.Expr
|
import Ash.Expr
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2]
|
||||||
|
|
||||||
alias Mv.Membership.Member
|
alias Mv.Membership.Member
|
||||||
alias Mv.MembershipFees
|
alias Mv.MembershipFees
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
alias Mv.MembershipFees.MembershipFeeCycle
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
alias Mv.Statistics
|
alias Mv.Statistics
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
|
|
@ -18,22 +18,6 @@ defmodule Mv.StatisticsTest do
|
||||||
%{actor: actor}
|
%{actor: actor}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp create_fee_type(actor, attrs) do
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(
|
|
||||||
:create,
|
|
||||||
Map.merge(
|
|
||||||
%{
|
|
||||||
name: "Test Fee #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
},
|
|
||||||
attrs
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "first_join_year/1" do
|
describe "first_join_year/1" do
|
||||||
test "returns the year of the earliest join_date", %{actor: actor} do
|
test "returns the year of the earliest join_date", %{actor: actor} do
|
||||||
Mv.Fixtures.member_fixture(%{join_date: ~D[2019-03-15]})
|
Mv.Fixtures.member_fixture(%{join_date: ~D[2019-03-15]})
|
||||||
|
|
@ -131,7 +115,7 @@ defmodule Mv.StatisticsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns totals by status for cycles in that year", %{actor: actor} do
|
test "returns totals by status for cycles in that year", %{actor: actor} do
|
||||||
fee_type = create_fee_type(actor, %{amount: Decimal.new("50.00")})
|
fee_type = create_fee_type(%{amount: Decimal.new("50.00")}, actor)
|
||||||
|
|
||||||
# Creating members with fee type triggers cycle generation (2020..today). We use 2024 cycles.
|
# Creating members with fee type triggers cycle generation (2020..today). We use 2024 cycles.
|
||||||
_member1 =
|
_member1 =
|
||||||
|
|
@ -171,8 +155,8 @@ defmodule Mv.StatisticsTest do
|
||||||
test "when fee_type_id is passed in opts, returns only cycles of that fee type", %{
|
test "when fee_type_id is passed in opts, returns only cycles of that fee type", %{
|
||||||
actor: actor
|
actor: actor
|
||||||
} do
|
} do
|
||||||
fee_type_a = create_fee_type(actor, %{amount: Decimal.new("30.00")})
|
fee_type_a = create_fee_type(%{amount: Decimal.new("30.00")}, actor)
|
||||||
fee_type_b = create_fee_type(actor, %{amount: Decimal.new("70.00")})
|
fee_type_b = create_fee_type(%{amount: Decimal.new("70.00")}, actor)
|
||||||
|
|
||||||
_m1 =
|
_m1 =
|
||||||
Mv.Fixtures.member_fixture(%{
|
Mv.Fixtures.member_fixture(%{
|
||||||
|
|
@ -207,7 +191,7 @@ defmodule Mv.StatisticsTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "returns sum of amount for all unpaid cycles", %{actor: actor} do
|
test "returns sum of amount for all unpaid cycles", %{actor: actor} do
|
||||||
fee_type = create_fee_type(actor, %{amount: Decimal.new("50.00")})
|
fee_type = create_fee_type(%{amount: Decimal.new("50.00")}, actor)
|
||||||
|
|
||||||
_member =
|
_member =
|
||||||
Mv.Fixtures.member_fixture(%{
|
Mv.Fixtures.member_fixture(%{
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ defmodule MvWeb.MembershipFeeTypeLive.FormTest do
|
||||||
use MvWeb.ConnCase, async: false
|
use MvWeb.ConnCase, async: false
|
||||||
|
|
||||||
import Phoenix.LiveViewTest
|
import Phoenix.LiveViewTest
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 1]
|
||||||
|
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
alias Mv.MembershipFees.MembershipFeeType
|
||||||
|
|
||||||
|
|
@ -17,23 +18,6 @@ defmodule MvWeb.MembershipFeeTypeLive.FormTest do
|
||||||
%{conn: authenticated_conn, user: user}
|
%{conn: authenticated_conn, user: user}
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs) do
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
||||||
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: system_actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member
|
# Helper to create a member
|
||||||
defp create_member(attrs) do
|
defp create_member(attrs) do
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ defmodule MvWeb.MembershipFeeTypeLive.IndexTest do
|
||||||
use MvWeb.ConnCase, async: false
|
use MvWeb.ConnCase, async: false
|
||||||
|
|
||||||
import Phoenix.LiveViewTest
|
import Phoenix.LiveViewTest
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2]
|
||||||
|
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
alias Mv.MembershipFees.MembershipFeeType
|
||||||
|
|
||||||
|
|
@ -13,22 +14,6 @@ defmodule MvWeb.MembershipFeeTypeLive.IndexTest do
|
||||||
# Use global setup from ConnCase which provides admin user with role
|
# Use global setup from ConnCase which provides admin user with role
|
||||||
# No custom setup needed
|
# No custom setup needed
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
# Uses admin_user to test permissions (UI-/Permissions-nah)
|
|
||||||
defp create_fee_type(attrs, admin_user) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: admin_user)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member. Requires actor (e.g. admin_user from setup); no fallback so
|
# Helper to create a member. Requires actor (e.g. admin_user from setup); no fallback so
|
||||||
# missing-actor bugs are not masked in tests.
|
# missing-actor bugs are not masked in tests.
|
||||||
defp create_member(attrs, actor) do
|
defp create_member(attrs, actor) do
|
||||||
|
|
|
||||||
|
|
@ -5,27 +5,10 @@ defmodule MvWeb.MemberLive.FormMembershipFeeTypeTest do
|
||||||
use MvWeb.ConnCase, async: false
|
use MvWeb.ConnCase, async: false
|
||||||
|
|
||||||
import Phoenix.LiveViewTest
|
import Phoenix.LiveViewTest
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 2]
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
# Uses admin_user to test permissions (UI-/Permissions-nah)
|
|
||||||
defp create_fee_type(attrs, admin_user) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: admin_user)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member
|
# Helper to create a member
|
||||||
# Uses admin_user to test permissions (UI-/Permissions-nah)
|
# Uses admin_user to test permissions (UI-/Permissions-nah)
|
||||||
defp create_member(attrs, admin_user) do
|
defp create_member(attrs, admin_user) do
|
||||||
|
|
|
||||||
|
|
@ -4,30 +4,13 @@ defmodule MvWeb.MemberLive.Index.MembershipFeeStatusTest do
|
||||||
"""
|
"""
|
||||||
use Mv.DataCase, async: false
|
use Mv.DataCase, async: false
|
||||||
|
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 1, create_cycle: 3]
|
||||||
|
|
||||||
alias Mv.Membership.Member
|
alias Mv.Membership.Member
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
alias MvWeb.MemberLive.Index.MembershipFeeStatus
|
alias MvWeb.MemberLive.Index.MembershipFeeStatus
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs) do
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
||||||
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: system_actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member
|
# Helper to create a member
|
||||||
defp create_member(attrs) do
|
defp create_member(attrs) do
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
@ -43,27 +26,6 @@ defmodule MvWeb.MemberLive.Index.MembershipFeeStatusTest do
|
||||||
member
|
member
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a cycle
|
|
||||||
# Note: Does not delete existing cycles - tests should manage their own test data
|
|
||||||
# If cleanup is needed, it should be done in setup or explicitly in the test
|
|
||||||
defp create_cycle(member, fee_type, attrs) do
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
||||||
|
|
||||||
default_attrs = %{
|
|
||||||
cycle_start: ~D[2023-01-01],
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
member_id: member.id,
|
|
||||||
membership_fee_type_id: fee_type.id,
|
|
||||||
status: :unpaid
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeCycle
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: system_actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "load_cycles_for_members/2" do
|
describe "load_cycles_for_members/2" do
|
||||||
test "efficiently loads cycles for members" do
|
test "efficiently loads cycles for members" do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
|
|
|
||||||
|
|
@ -5,29 +5,12 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
||||||
use MvWeb.ConnCase, async: false
|
use MvWeb.ConnCase, async: false
|
||||||
|
|
||||||
import Phoenix.LiveViewTest
|
import Phoenix.LiveViewTest
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 1, create_cycle: 3]
|
||||||
|
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
alias Mv.MembershipFees.MembershipFeeCycle
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs) do
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
||||||
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: system_actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member
|
# Helper to create a member
|
||||||
defp create_member(attrs) do
|
defp create_member(attrs) do
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
@ -43,38 +26,16 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
||||||
member
|
member
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper to create a cycle
|
|
||||||
defp create_cycle(member, fee_type, attrs) do
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
||||||
|
|
||||||
# Delete any auto-generated cycles first to avoid conflicts
|
|
||||||
existing_cycles =
|
|
||||||
MembershipFeeCycle
|
|
||||||
|> Ash.Query.filter(member_id == ^member.id)
|
|
||||||
|> Ash.read!(actor: system_actor)
|
|
||||||
|
|
||||||
Enum.each(existing_cycles, fn cycle -> Ash.destroy!(cycle, actor: system_actor) end)
|
|
||||||
|
|
||||||
default_attrs = %{
|
|
||||||
cycle_start: ~D[2023-01-01],
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
member_id: member.id,
|
|
||||||
membership_fee_type_id: fee_type.id,
|
|
||||||
status: :unpaid
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeCycle
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: system_actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "status column display" do
|
describe "status column display" do
|
||||||
test "shows status column in member list", %{conn: conn} do
|
test "shows status column in member list", %{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 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||||
create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :paid})
|
|
||||||
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :paid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, _view, html} = live(conn, "/members")
|
{:ok, _view, html} = live(conn, "/members")
|
||||||
|
|
||||||
|
|
@ -85,8 +46,18 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
||||||
test "shows last completed cycle status by default", %{conn: conn} do
|
test "shows last completed cycle status by default", %{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 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||||
create_cycle(member, fee_type, %{cycle_start: ~D[2022-01-01], status: :paid})
|
|
||||||
create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2022-01-01],
|
||||||
|
status: :paid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :unpaid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members")
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
|
@ -102,8 +73,17 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
||||||
today = Date.utc_today()
|
today = Date.utc_today()
|
||||||
current_year_start = %{today | month: 1, day: 1}
|
current_year_start = %{today | month: 1, day: 1}
|
||||||
|
|
||||||
create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :paid})
|
create_cycle(member, fee_type, %{
|
||||||
create_cycle(member, fee_type, %{cycle_start: current_year_start, status: :suspended})
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :paid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: current_year_start,
|
||||||
|
status: :suspended,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members")
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
|
@ -120,7 +100,12 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
||||||
test "shows correct color coding for paid status", %{conn: conn} do
|
test "shows correct color coding for paid status", %{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 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||||
create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :paid})
|
|
||||||
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :paid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members")
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
|
@ -131,7 +116,12 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
||||||
test "shows correct color coding for unpaid status", %{conn: conn} do
|
test "shows correct color coding for unpaid status", %{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 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||||
create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
|
||||||
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :unpaid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members")
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
|
@ -142,7 +132,12 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
||||||
test "shows correct color coding for suspended status", %{conn: conn} do
|
test "shows correct color coding for suspended status", %{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 = create_member(%{membership_fee_type_id: fee_type.id})
|
||||||
create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :suspended})
|
|
||||||
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :suspended,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members")
|
{:ok, view, _html} = live(conn, "/members")
|
||||||
|
|
||||||
|
|
@ -169,11 +164,21 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
||||||
|
|
||||||
# Member with unpaid last cycle
|
# Member with unpaid last cycle
|
||||||
member1 = create_member(%{first_name: "UnpaidMember", membership_fee_type_id: fee_type.id})
|
member1 = create_member(%{first_name: "UnpaidMember", membership_fee_type_id: fee_type.id})
|
||||||
create_cycle(member1, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
|
||||||
|
create_cycle(member1, fee_type, %{
|
||||||
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :unpaid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
# Member with paid last cycle
|
# Member with paid last cycle
|
||||||
member2 = create_member(%{first_name: "PaidMember", membership_fee_type_id: fee_type.id})
|
member2 = create_member(%{first_name: "PaidMember", membership_fee_type_id: fee_type.id})
|
||||||
create_cycle(member2, fee_type, %{cycle_start: ~D[2023-01-01], status: :paid})
|
|
||||||
|
create_cycle(member2, fee_type, %{
|
||||||
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :paid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
||||||
|
|
@ -205,11 +210,21 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
||||||
|
|
||||||
# Member with unpaid current cycle
|
# Member with unpaid current cycle
|
||||||
member1 = create_member(%{first_name: "UnpaidCurrent", membership_fee_type_id: fee_type.id})
|
member1 = create_member(%{first_name: "UnpaidCurrent", membership_fee_type_id: fee_type.id})
|
||||||
create_cycle(member1, fee_type, %{cycle_start: current_year_start, status: :unpaid})
|
|
||||||
|
create_cycle(member1, fee_type, %{
|
||||||
|
cycle_start: current_year_start,
|
||||||
|
status: :unpaid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
# Member with paid current cycle
|
# Member with paid current cycle
|
||||||
member2 = create_member(%{first_name: "PaidCurrent", membership_fee_type_id: fee_type.id})
|
member2 = create_member(%{first_name: "PaidCurrent", membership_fee_type_id: fee_type.id})
|
||||||
create_cycle(member2, fee_type, %{cycle_start: current_year_start, status: :paid})
|
|
||||||
|
create_cycle(member2, fee_type, %{
|
||||||
|
cycle_start: current_year_start,
|
||||||
|
status: :paid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
||||||
|
|
@ -243,7 +258,12 @@ defmodule MvWeb.MemberLive.IndexMembershipFeeStatusTest do
|
||||||
# Create multiple members with cycles
|
# Create multiple members with cycles
|
||||||
Enum.each(1..5, fn _ ->
|
Enum.each(1..5, fn _ ->
|
||||||
member = create_member(%{membership_fee_type_id: fee_type.id})
|
member = create_member(%{membership_fee_type_id: fee_type.id})
|
||||||
create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :paid})
|
|
||||||
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :paid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
end)
|
end)
|
||||||
|
|
||||||
{:ok, _view, html} = live(conn, "/members")
|
{:ok, _view, html} = live(conn, "/members")
|
||||||
|
|
|
||||||
|
|
@ -7,49 +7,9 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
alias Mv.Membership
|
alias Mv.Membership
|
||||||
alias Mv.Membership.CustomField
|
alias Mv.Membership.CustomField
|
||||||
alias Mv.Membership.CustomFieldValue
|
alias Mv.Membership.CustomFieldValue
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
alias MvWeb.MemberLive.Index, as: MemberIndex
|
alias MvWeb.MemberLive.Index, as: MemberIndex
|
||||||
|
|
||||||
# Helper to create a membership fee type (shared across all tests)
|
import Mv.Fixtures, only: [create_fee_type: 2, create_cycle: 4]
|
||||||
defp create_fee_type(attrs, actor) do
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a cycle (shared across all tests)
|
|
||||||
defp create_cycle(member, fee_type, attrs, actor) do
|
|
||||||
# Delete any auto-generated cycles first to avoid conflicts
|
|
||||||
existing_cycles =
|
|
||||||
MembershipFeeCycle
|
|
||||||
|> Ash.Query.filter(member_id == ^member.id)
|
|
||||||
|> Ash.read!(actor: actor)
|
|
||||||
|
|
||||||
Enum.each(existing_cycles, fn cycle -> Ash.destroy!(cycle, actor: actor) end)
|
|
||||||
|
|
||||||
default_attrs = %{
|
|
||||||
cycle_start: ~D[2023-01-01],
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
member_id: member.id,
|
|
||||||
membership_fee_type_id: fee_type.id,
|
|
||||||
status: :unpaid
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeCycle
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "desktop layout: scroll container and sticky table header" do
|
describe "desktop layout: scroll container and sticky table header" do
|
||||||
@describetag :ui
|
@describetag :ui
|
||||||
|
|
@ -1110,7 +1070,7 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
create_cycle(
|
create_cycle(
|
||||||
paid_member,
|
paid_member,
|
||||||
fee_type,
|
fee_type,
|
||||||
%{cycle_start: last_year_start, status: :paid},
|
%{cycle_start: last_year_start, status: :paid, replace_existing: true},
|
||||||
system_actor
|
system_actor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1127,7 +1087,7 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
create_cycle(
|
create_cycle(
|
||||||
unpaid_member,
|
unpaid_member,
|
||||||
fee_type,
|
fee_type,
|
||||||
%{cycle_start: last_year_start, status: :unpaid},
|
%{cycle_start: last_year_start, status: :unpaid, replace_existing: true},
|
||||||
system_actor
|
system_actor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1157,7 +1117,7 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
create_cycle(
|
create_cycle(
|
||||||
paid_member,
|
paid_member,
|
||||||
fee_type,
|
fee_type,
|
||||||
%{cycle_start: last_year_start, status: :paid},
|
%{cycle_start: last_year_start, status: :paid, replace_existing: true},
|
||||||
system_actor
|
system_actor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1174,7 +1134,7 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
create_cycle(
|
create_cycle(
|
||||||
unpaid_member,
|
unpaid_member,
|
||||||
fee_type,
|
fee_type,
|
||||||
%{cycle_start: last_year_start, status: :unpaid},
|
%{cycle_start: last_year_start, status: :unpaid, replace_existing: true},
|
||||||
system_actor
|
system_actor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1204,7 +1164,7 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
create_cycle(
|
create_cycle(
|
||||||
paid_member,
|
paid_member,
|
||||||
fee_type,
|
fee_type,
|
||||||
%{cycle_start: current_year_start, status: :paid},
|
%{cycle_start: current_year_start, status: :paid, replace_existing: true},
|
||||||
system_actor
|
system_actor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1221,7 +1181,7 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
create_cycle(
|
create_cycle(
|
||||||
unpaid_member,
|
unpaid_member,
|
||||||
fee_type,
|
fee_type,
|
||||||
%{cycle_start: current_year_start, status: :unpaid},
|
%{cycle_start: current_year_start, status: :unpaid, replace_existing: true},
|
||||||
system_actor
|
system_actor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1251,7 +1211,7 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
create_cycle(
|
create_cycle(
|
||||||
paid_member,
|
paid_member,
|
||||||
fee_type,
|
fee_type,
|
||||||
%{cycle_start: current_year_start, status: :paid},
|
%{cycle_start: current_year_start, status: :paid, replace_existing: true},
|
||||||
system_actor
|
system_actor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1268,7 +1228,7 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
create_cycle(
|
create_cycle(
|
||||||
unpaid_member,
|
unpaid_member,
|
||||||
fee_type,
|
fee_type,
|
||||||
%{cycle_start: current_year_start, status: :unpaid},
|
%{cycle_start: current_year_start, status: :unpaid, replace_existing: true},
|
||||||
system_actor
|
system_actor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -2196,7 +2156,7 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
create_cycle(
|
create_cycle(
|
||||||
member_paid_true,
|
member_paid_true,
|
||||||
fee_type,
|
fee_type,
|
||||||
%{cycle_start: last_year_start, status: :paid},
|
%{cycle_start: last_year_start, status: :paid, replace_existing: true},
|
||||||
system_actor
|
system_actor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -2224,7 +2184,7 @@ defmodule MvWeb.MemberLive.IndexTest do
|
||||||
create_cycle(
|
create_cycle(
|
||||||
member_unpaid_true,
|
member_unpaid_true,
|
||||||
fee_type,
|
fee_type,
|
||||||
%{cycle_start: last_year_start, status: :unpaid},
|
%{cycle_start: last_year_start, status: :unpaid, replace_existing: true},
|
||||||
system_actor
|
system_actor
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,29 +5,12 @@ defmodule MvWeb.MemberLive.MembershipFeeIntegrationTest do
|
||||||
use MvWeb.ConnCase, async: false
|
use MvWeb.ConnCase, async: false
|
||||||
|
|
||||||
import Phoenix.LiveViewTest
|
import Phoenix.LiveViewTest
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 1]
|
||||||
|
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
alias Mv.MembershipFees.MembershipFeeCycle
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs) do
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
||||||
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: system_actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a member
|
# Helper to create a member
|
||||||
defp create_member(attrs) do
|
defp create_member(attrs) do
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
||||||
|
|
|
||||||
|
|
@ -5,56 +5,12 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
use MvWeb.ConnCase, async: false
|
use MvWeb.ConnCase, async: false
|
||||||
|
|
||||||
import Phoenix.LiveViewTest
|
import Phoenix.LiveViewTest
|
||||||
|
import Mv.Fixtures, only: [create_fee_type: 1, create_cycle: 3]
|
||||||
|
|
||||||
alias Mv.MembershipFees.MembershipFeeCycle
|
alias Mv.MembershipFees.MembershipFeeCycle
|
||||||
alias Mv.MembershipFees.MembershipFeeType
|
|
||||||
|
|
||||||
require Ash.Query
|
require Ash.Query
|
||||||
|
|
||||||
# Helper to create a membership fee type
|
|
||||||
defp create_fee_type(attrs) do
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
||||||
|
|
||||||
default_attrs = %{
|
|
||||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
interval: :yearly
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeType
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: system_actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Helper to create a cycle
|
|
||||||
defp create_cycle(member, fee_type, attrs) do
|
|
||||||
system_actor = Mv.Helpers.SystemActor.get_system_actor()
|
|
||||||
|
|
||||||
# Delete any auto-generated cycles first to avoid conflicts
|
|
||||||
existing_cycles =
|
|
||||||
MembershipFeeCycle
|
|
||||||
|> Ash.Query.filter(member_id == ^member.id)
|
|
||||||
|> Ash.read!(actor: system_actor)
|
|
||||||
|
|
||||||
Enum.each(existing_cycles, fn cycle -> Ash.destroy!(cycle, actor: system_actor) end)
|
|
||||||
|
|
||||||
default_attrs = %{
|
|
||||||
cycle_start: ~D[2023-01-01],
|
|
||||||
amount: Decimal.new("50.00"),
|
|
||||||
member_id: member.id,
|
|
||||||
membership_fee_type_id: fee_type.id,
|
|
||||||
status: :unpaid
|
|
||||||
}
|
|
||||||
|
|
||||||
attrs = Map.merge(default_attrs, attrs)
|
|
||||||
|
|
||||||
MembershipFeeCycle
|
|
||||||
|> Ash.Changeset.for_create(:create, attrs)
|
|
||||||
|> Ash.create!(actor: system_actor)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "cycle-regeneration control tooltip (§3.5 icon/tooltip audit)" do
|
describe "cycle-regeneration control tooltip (§3.5 icon/tooltip audit)" do
|
||||||
test "the regenerate_cycles control carries a tooltip and accessible label", %{conn: conn} do
|
test "the regenerate_cycles control carries a tooltip and accessible label", %{conn: conn} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
|
|
@ -76,8 +32,19 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = Mv.Fixtures.member_fixture(%{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 =
|
||||||
_cycle2 = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2022-01-01],
|
||||||
|
status: :paid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
|
_cycle2 =
|
||||||
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :unpaid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
@ -101,7 +68,8 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
create_cycle(member, fee_type, %{
|
create_cycle(member, fee_type, %{
|
||||||
cycle_start: ~D[2023-01-01],
|
cycle_start: ~D[2023-01-01],
|
||||||
amount: Decimal.new("60.00"),
|
amount: Decimal.new("60.00"),
|
||||||
status: :paid
|
status: :paid,
|
||||||
|
replace_existing: true
|
||||||
})
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
@ -158,7 +126,12 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = Mv.Fixtures.member_fixture(%{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,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
@ -189,7 +162,12 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = Mv.Fixtures.member_fixture(%{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,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
@ -220,7 +198,12 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = Mv.Fixtures.member_fixture(%{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,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
@ -316,7 +299,13 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
} do
|
} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = Mv.Fixtures.member_fixture(%{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,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
@ -335,7 +324,13 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
} do
|
} do
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = Mv.Fixtures.member_fixture(%{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,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
@ -361,7 +356,13 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
# 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 = Mv.Fixtures.member_fixture(%{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,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
assert {:error, %Ash.Error.Forbidden{}} =
|
assert {:error, %Ash.Error.Forbidden{}} =
|
||||||
Ash.destroy(cycle, domain: Mv.MembershipFees, actor: read_only_user)
|
Ash.destroy(cycle, domain: Mv.MembershipFees, actor: read_only_user)
|
||||||
|
|
@ -389,8 +390,20 @@ defmodule MvWeb.MemberLive.ShowMembershipFeesTest do
|
||||||
|
|
||||||
fee_type = create_fee_type(%{interval: :yearly})
|
fee_type = create_fee_type(%{interval: :yearly})
|
||||||
member = Mv.Fixtures.member_fixture(%{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})
|
|
||||||
_c2 = create_cycle(member, fee_type, %{cycle_start: ~D[2023-01-01], status: :unpaid})
|
_c1 =
|
||||||
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2022-01-01],
|
||||||
|
status: :paid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
|
_c2 =
|
||||||
|
create_cycle(member, fee_type, %{
|
||||||
|
cycle_start: ~D[2023-01-01],
|
||||||
|
status: :unpaid,
|
||||||
|
replace_existing: true
|
||||||
|
})
|
||||||
|
|
||||||
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
{:ok, view, _html} = live(conn, "/members/#{member.id}")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -335,4 +335,82 @@ defmodule Mv.Fixtures do
|
||||||
{:ok, request} = Membership.confirm_join_request(token, actor: nil)
|
{:ok, request} = Membership.confirm_join_request(token, actor: nil)
|
||||||
request
|
request
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Creates a membership fee type with default or custom attributes.
|
||||||
|
|
||||||
|
Defaults: a unique `name`, `amount` 50.00, `interval` :yearly.
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
- `attrs` - Map of attributes to override defaults (e.g. `%{interval: :monthly}`).
|
||||||
|
- `actor` - the authorization actor; defaults to the system actor when omitted/nil.
|
||||||
|
|
||||||
|
## Returns
|
||||||
|
- MembershipFeeType struct.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> create_fee_type(%{interval: :monthly})
|
||||||
|
%Mv.MembershipFees.MembershipFeeType{interval: :monthly, ...}
|
||||||
|
|
||||||
|
iex> create_fee_type(%{amount: Decimal.new("10.00")}, admin)
|
||||||
|
%Mv.MembershipFees.MembershipFeeType{...}
|
||||||
|
"""
|
||||||
|
def create_fee_type(attrs \\ %{}, actor \\ nil) do
|
||||||
|
actor = actor || SystemActor.get_system_actor()
|
||||||
|
|
||||||
|
default_attrs = %{
|
||||||
|
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
||||||
|
amount: Decimal.new("50.00"),
|
||||||
|
interval: :yearly
|
||||||
|
}
|
||||||
|
|
||||||
|
Mv.MembershipFees.MembershipFeeType
|
||||||
|
|> Ash.Changeset.for_create(:create, Map.merge(default_attrs, attrs))
|
||||||
|
|> Ash.create!(actor: actor)
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Creates a membership fee cycle for the given member and fee type.
|
||||||
|
|
||||||
|
Defaults: `cycle_start` ~D[2024-01-01], `amount` 50.00, `status` :unpaid,
|
||||||
|
with `member_id`/`membership_fee_type_id` derived from the passed structs.
|
||||||
|
|
||||||
|
## Parameters
|
||||||
|
- `member` - the Member struct the cycle belongs to.
|
||||||
|
- `fee_type` - the MembershipFeeType struct the cycle references.
|
||||||
|
- `attrs` - Map overriding the cycle defaults (e.g. `%{cycle_start: ~D[2023-01-01], status: :paid}`).
|
||||||
|
A reserved `:replace_existing` key (truthy) deletes any pre-existing cycles for the member
|
||||||
|
before creating the new one (used where auto-generated cycles would otherwise conflict);
|
||||||
|
it is stripped from the attrs and never passed to the create action. Defaults to absent/false.
|
||||||
|
- `actor` - the authorization actor; defaults to the system actor when omitted/nil.
|
||||||
|
|
||||||
|
## Returns
|
||||||
|
- MembershipFeeCycle struct.
|
||||||
|
"""
|
||||||
|
def create_cycle(member, fee_type, attrs \\ %{}, actor \\ nil) do
|
||||||
|
actor = actor || SystemActor.get_system_actor()
|
||||||
|
{replace_existing, attrs} = Map.pop(attrs, :replace_existing, false)
|
||||||
|
|
||||||
|
if replace_existing do
|
||||||
|
require Ash.Query
|
||||||
|
|
||||||
|
Mv.MembershipFees.MembershipFeeCycle
|
||||||
|
|> Ash.Query.filter(member_id == ^member.id)
|
||||||
|
|> Ash.read!(actor: actor)
|
||||||
|
|> Enum.each(&Ash.destroy!(&1, actor: actor))
|
||||||
|
end
|
||||||
|
|
||||||
|
default_attrs = %{
|
||||||
|
cycle_start: ~D[2024-01-01],
|
||||||
|
amount: Decimal.new("50.00"),
|
||||||
|
member_id: member.id,
|
||||||
|
membership_fee_type_id: fee_type.id,
|
||||||
|
status: :unpaid
|
||||||
|
}
|
||||||
|
|
||||||
|
Mv.MembershipFees.MembershipFeeCycle
|
||||||
|
|> Ash.Changeset.for_create(:create, Map.merge(default_attrs, attrs))
|
||||||
|
|> Ash.create!(actor: actor)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue