mitgliederverwaltung/test/mv_web/helpers/membership_fee_helpers_test.exs
Moritz 0f48a9b15a
Add actor parameter to all tests requiring authorization
This commit adds actor: system_actor to all Ash operations in tests that
require authorization.
2026-01-24 02:21:02 +01:00

265 lines
8.6 KiB
Elixir

defmodule MvWeb.Helpers.MembershipFeeHelpersTest do
@moduledoc """
Tests for MembershipFeeHelpers module.
"""
use Mv.DataCase, async: true
require Ash.Query
alias MvWeb.Helpers.MembershipFeeHelpers
alias Mv.MembershipFees.CalendarCycles
setup do
system_actor = Mv.Helpers.SystemActor.get_system_actor()
%{actor: system_actor}
end
describe "format_currency/1" do
test "formats decimal amount correctly" do
assert MembershipFeeHelpers.format_currency(Decimal.new("60.00")) == "60,00 €"
assert MembershipFeeHelpers.format_currency(Decimal.new("5.5")) == "5,50 €"
assert MembershipFeeHelpers.format_currency(Decimal.new("100")) == "100,00 €"
assert MembershipFeeHelpers.format_currency(Decimal.new("0.99")) == "0,99 €"
end
end
describe "format_interval/1" do
test "formats all interval types correctly" do
assert MembershipFeeHelpers.format_interval(:monthly) == "Monthly"
assert MembershipFeeHelpers.format_interval(:quarterly) == "Quarterly"
assert MembershipFeeHelpers.format_interval(:half_yearly) == "Half-yearly"
assert MembershipFeeHelpers.format_interval(:yearly) == "Yearly"
end
end
describe "format_cycle_range/2" do
test "formats yearly cycle range correctly" do
cycle_start = ~D[2024-01-01]
interval = :yearly
_cycle_end = CalendarCycles.calculate_cycle_end(cycle_start, interval)
result = MembershipFeeHelpers.format_cycle_range(cycle_start, interval)
assert result =~ "2024"
assert result =~ "01.01"
assert result =~ "31.12"
end
test "formats quarterly cycle range correctly" do
cycle_start = ~D[2024-01-01]
interval = :quarterly
_cycle_end = CalendarCycles.calculate_cycle_end(cycle_start, interval)
result = MembershipFeeHelpers.format_cycle_range(cycle_start, interval)
assert result =~ "2024"
assert result =~ "01.01"
assert result =~ "31.03"
end
test "formats monthly cycle range correctly" do
cycle_start = ~D[2024-03-01]
interval = :monthly
_cycle_end = CalendarCycles.calculate_cycle_end(cycle_start, interval)
result = MembershipFeeHelpers.format_cycle_range(cycle_start, interval)
assert result =~ "2024"
assert result =~ "01.03"
assert result =~ "31.03"
end
end
describe "get_last_completed_cycle/2" do
test "returns last completed cycle for member", %{actor: actor} do
# Create test data
fee_type =
Mv.MembershipFees.MembershipFeeType
|> Ash.Changeset.for_create(:create, %{
name: "Test Type",
amount: Decimal.new("50.00"),
interval: :yearly
})
|> Ash.create!(actor: actor)
# Create member without fee type first to avoid auto-generation
member =
Mv.Membership.Member
|> Ash.Changeset.for_create(:create_member, %{
first_name: "Test",
last_name: "Member",
email: "test#{System.unique_integer([:positive])}@example.com",
join_date: ~D[2022-01-01]
})
|> Ash.create!(actor: actor)
# Assign fee type after member creation (this may generate cycles, but we'll create our own)
member =
member
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|> Ash.update!(actor: actor)
# Delete any auto-generated cycles first
cycles =
Mv.MembershipFees.MembershipFeeCycle
|> Ash.Query.filter(member_id == ^member.id)
|> Ash.read!(actor: actor)
Enum.each(cycles, fn cycle -> Ash.destroy!(cycle, actor: actor) end)
# Create cycles manually
_cycle_2022 =
Mv.MembershipFees.MembershipFeeCycle
|> Ash.Changeset.for_create(:create, %{
cycle_start: ~D[2022-01-01],
amount: Decimal.new("50.00"),
member_id: member.id,
membership_fee_type_id: fee_type.id,
status: :paid
})
|> Ash.create!(actor: actor)
cycle_2023 =
Mv.MembershipFees.MembershipFeeCycle
|> Ash.Changeset.for_create(:create, %{
cycle_start: ~D[2023-01-01],
amount: Decimal.new("50.00"),
member_id: member.id,
membership_fee_type_id: fee_type.id,
status: :paid
})
|> Ash.create!(actor: actor)
# Load cycles with membership_fee_type relationship
member =
member
|> Ash.load!(membership_fee_cycles: [:membership_fee_type])
|> Ash.load!(:membership_fee_type)
# Use a fixed date in 2024 to ensure 2023 is last completed
today = ~D[2024-06-15]
last_cycle = MembershipFeeHelpers.get_last_completed_cycle(member, today)
assert last_cycle.id == cycle_2023.id
end
test "returns nil if no cycles exist", %{actor: actor} do
fee_type =
Mv.MembershipFees.MembershipFeeType
|> Ash.Changeset.for_create(:create, %{
name: "Test Type",
amount: Decimal.new("50.00"),
interval: :yearly
})
|> Ash.create!(actor: actor)
# Create member without fee type first
member =
Mv.Membership.Member
|> Ash.Changeset.for_create(:create_member, %{
first_name: "Test",
last_name: "Member",
email: "test#{System.unique_integer([:positive])}@example.com"
})
|> Ash.create!(actor: actor)
# Assign fee type
member =
member
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|> Ash.update!(actor: actor)
# Delete any auto-generated cycles
cycles =
Mv.MembershipFees.MembershipFeeCycle
|> Ash.Query.filter(member_id == ^member.id)
|> Ash.read!(actor: actor)
Enum.each(cycles, fn cycle -> Ash.destroy!(cycle, actor: actor) end)
# Load cycles and fee type (will be empty)
member =
member
|> Ash.load!(membership_fee_cycles: [:membership_fee_type])
|> Ash.load!(:membership_fee_type)
last_cycle = MembershipFeeHelpers.get_last_completed_cycle(member, Date.utc_today())
assert last_cycle == nil
end
end
describe "get_current_cycle/2" do
test "returns current cycle for member", %{actor: actor} do
fee_type =
Mv.MembershipFees.MembershipFeeType
|> Ash.Changeset.for_create(:create, %{
name: "Test Type",
amount: Decimal.new("50.00"),
interval: :yearly
})
|> Ash.create!(actor: actor)
# Create member without fee type first
member =
Mv.Membership.Member
|> Ash.Changeset.for_create(:create_member, %{
first_name: "Test",
last_name: "Member",
email: "test#{System.unique_integer([:positive])}@example.com",
join_date: ~D[2023-01-01]
})
|> Ash.create!(actor: actor)
# Assign fee type
member =
member
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|> Ash.update!(actor: actor)
# Delete any auto-generated cycles
cycles =
Mv.MembershipFees.MembershipFeeCycle
|> Ash.Query.filter(member_id == ^member.id)
|> Ash.read!(actor: actor)
Enum.each(cycles, fn cycle -> Ash.destroy!(cycle, actor: actor) end)
today = Date.utc_today()
current_year_start = %{today | month: 1, day: 1}
current_cycle =
Mv.MembershipFees.MembershipFeeCycle
|> Ash.Changeset.for_create(:create, %{
cycle_start: current_year_start,
amount: Decimal.new("50.00"),
member_id: member.id,
membership_fee_type_id: fee_type.id,
status: :unpaid
})
|> Ash.create!(actor: actor)
# Load cycles with membership_fee_type relationship
member =
member
|> Ash.load!(membership_fee_cycles: [:membership_fee_type])
|> Ash.load!(:membership_fee_type)
result = MembershipFeeHelpers.get_current_cycle(member, today)
assert result.id == current_cycle.id
end
end
describe "status_color/1" do
test "returns correct color classes for statuses" do
assert MembershipFeeHelpers.status_color(:paid) == "badge-success"
assert MembershipFeeHelpers.status_color(:unpaid) == "badge-error"
assert MembershipFeeHelpers.status_color(:suspended) == "badge-ghost"
end
end
describe "status_icon/1" do
test "returns correct icon names for statuses" do
assert MembershipFeeHelpers.status_icon(:paid) == "hero-check-circle"
assert MembershipFeeHelpers.status_icon(:unpaid) == "hero-x-circle"
assert MembershipFeeHelpers.status_icon(:suspended) == "hero-pause-circle"
end
end
end