feat(membership-fees): add database schema and Ash domain structure
This commit is contained in:
parent
e563d12be3
commit
4d1b33357e
14 changed files with 1405 additions and 7 deletions
220
test/membership_fees/foreign_key_test.exs
Normal file
220
test/membership_fees/foreign_key_test.exs
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
defmodule Mv.MembershipFees.ForeignKeyTest do
|
||||
@moduledoc """
|
||||
Tests for foreign key behaviors (CASCADE and RESTRICT).
|
||||
"""
|
||||
use Mv.DataCase, async: true
|
||||
|
||||
alias Mv.MembershipFees.MembershipFeeCycle
|
||||
alias Mv.MembershipFees.MembershipFeeType
|
||||
alias Mv.Membership.Member
|
||||
|
||||
describe "CASCADE behavior" do
|
||||
test "deleting member deletes associated membership_fee_cycles" do
|
||||
# Create member
|
||||
{:ok, member} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "Cascade",
|
||||
last_name: "Test",
|
||||
email: "cascade.test.#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|
||||
# Create fee type
|
||||
{:ok, fee_type} =
|
||||
Ash.create(MembershipFeeType, %{
|
||||
name: "Cascade Test Fee #{System.unique_integer([:positive])}",
|
||||
amount: Decimal.new("100.00"),
|
||||
interval: :monthly
|
||||
})
|
||||
|
||||
# Create multiple cycles for this member
|
||||
{:ok, cycle1} =
|
||||
Ash.create(MembershipFeeCycle, %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
})
|
||||
|
||||
{:ok, cycle2} =
|
||||
Ash.create(MembershipFeeCycle, %{
|
||||
cycle_start: ~D[2025-02-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
})
|
||||
|
||||
# Verify cycles exist
|
||||
assert {:ok, _} = Ash.get(MembershipFeeCycle, cycle1.id)
|
||||
assert {:ok, _} = Ash.get(MembershipFeeCycle, cycle2.id)
|
||||
|
||||
# Delete member
|
||||
assert :ok = Ash.destroy(member)
|
||||
|
||||
# Verify cycles are also deleted (CASCADE)
|
||||
# NotFound is wrapped in Ash.Error.Invalid
|
||||
assert {:error, %Ash.Error.Invalid{}} = Ash.get(MembershipFeeCycle, cycle1.id)
|
||||
assert {:error, %Ash.Error.Invalid{}} = Ash.get(MembershipFeeCycle, cycle2.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "RESTRICT behavior" do
|
||||
test "cannot delete membership_fee_type if cycles reference it" do
|
||||
# Create member
|
||||
{:ok, member} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "Restrict",
|
||||
last_name: "Test",
|
||||
email: "restrict.test.#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|
||||
# Create fee type
|
||||
{:ok, fee_type} =
|
||||
Ash.create(MembershipFeeType, %{
|
||||
name: "Restrict Test Fee #{System.unique_integer([:positive])}",
|
||||
amount: Decimal.new("100.00"),
|
||||
interval: :monthly
|
||||
})
|
||||
|
||||
# Create a cycle referencing this fee type
|
||||
{:ok, _cycle} =
|
||||
Ash.create(MembershipFeeCycle, %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
})
|
||||
|
||||
# Try to delete fee type - should fail due to RESTRICT
|
||||
assert {:error, error} = Ash.destroy(fee_type)
|
||||
|
||||
# Check that it's a foreign key violation error
|
||||
assert is_struct(error, Ash.Error.Invalid) or is_struct(error, Ash.Error.Unknown)
|
||||
end
|
||||
|
||||
test "can delete membership_fee_type if no cycles reference it" do
|
||||
# Create fee type without any cycles
|
||||
{:ok, fee_type} =
|
||||
Ash.create(MembershipFeeType, %{
|
||||
name: "Deletable Fee #{System.unique_integer([:positive])}",
|
||||
amount: Decimal.new("100.00"),
|
||||
interval: :monthly
|
||||
})
|
||||
|
||||
# Should be able to delete
|
||||
assert :ok = Ash.destroy(fee_type)
|
||||
|
||||
# Verify it's gone (NotFound is wrapped in Ash.Error.Invalid)
|
||||
assert {:error, %Ash.Error.Invalid{}} = Ash.get(MembershipFeeType, fee_type.id)
|
||||
end
|
||||
|
||||
test "cannot delete membership_fee_type if members reference it" do
|
||||
# Create fee type
|
||||
{:ok, fee_type} =
|
||||
Ash.create(MembershipFeeType, %{
|
||||
name: "Member Ref Fee #{System.unique_integer([:positive])}",
|
||||
amount: Decimal.new("100.00"),
|
||||
interval: :monthly
|
||||
})
|
||||
|
||||
# Create member with this fee type
|
||||
{:ok, _member} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "FeeType",
|
||||
last_name: "Reference",
|
||||
email: "feetype.ref.#{System.unique_integer([:positive])}@example.com",
|
||||
membership_fee_type_id: fee_type.id
|
||||
})
|
||||
|
||||
# Try to delete fee type - should fail due to RESTRICT
|
||||
assert {:error, error} = Ash.destroy(fee_type)
|
||||
assert is_struct(error, Ash.Error.Invalid) or is_struct(error, Ash.Error.Unknown)
|
||||
end
|
||||
end
|
||||
|
||||
describe "member extensions" do
|
||||
test "member can be created with membership_fee_type_id" do
|
||||
# Create fee type first
|
||||
{:ok, fee_type} =
|
||||
Ash.create(MembershipFeeType, %{
|
||||
name: "Create Test Fee #{System.unique_integer([:positive])}",
|
||||
amount: Decimal.new("100.00"),
|
||||
interval: :yearly
|
||||
})
|
||||
|
||||
# Create member with fee type
|
||||
{:ok, member} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "With",
|
||||
last_name: "FeeType",
|
||||
email: "with.feetype.#{System.unique_integer([:positive])}@example.com",
|
||||
membership_fee_type_id: fee_type.id
|
||||
})
|
||||
|
||||
assert member.membership_fee_type_id == fee_type.id
|
||||
end
|
||||
|
||||
test "member can be created with membership_fee_start_date" do
|
||||
{:ok, member} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "With",
|
||||
last_name: "StartDate",
|
||||
email: "with.startdate.#{System.unique_integer([:positive])}@example.com",
|
||||
membership_fee_start_date: ~D[2025-01-01]
|
||||
})
|
||||
|
||||
assert member.membership_fee_start_date == ~D[2025-01-01]
|
||||
end
|
||||
|
||||
test "member can be created without membership fee fields" do
|
||||
{:ok, member} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "No",
|
||||
last_name: "FeeFields",
|
||||
email: "no.feefields.#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|
||||
assert member.membership_fee_type_id == nil
|
||||
assert member.membership_fee_start_date == nil
|
||||
end
|
||||
|
||||
test "member can be updated with membership_fee_type_id" do
|
||||
# Create fee type
|
||||
{:ok, fee_type} =
|
||||
Ash.create(MembershipFeeType, %{
|
||||
name: "Update Test Fee #{System.unique_integer([:positive])}",
|
||||
amount: Decimal.new("100.00"),
|
||||
interval: :yearly
|
||||
})
|
||||
|
||||
# Create member without fee type
|
||||
{:ok, member} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "Update",
|
||||
last_name: "Test",
|
||||
email: "update.test.#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|
||||
assert member.membership_fee_type_id == nil
|
||||
|
||||
# Update member with fee type
|
||||
{:ok, updated_member} = Ash.update(member, %{membership_fee_type_id: fee_type.id})
|
||||
|
||||
assert updated_member.membership_fee_type_id == fee_type.id
|
||||
end
|
||||
|
||||
test "member can be updated with membership_fee_start_date" do
|
||||
{:ok, member} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "Start",
|
||||
last_name: "Date",
|
||||
email: "start.date.#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|
||||
assert member.membership_fee_start_date == nil
|
||||
|
||||
{:ok, updated_member} = Ash.update(member, %{membership_fee_start_date: ~D[2025-06-01]})
|
||||
|
||||
assert updated_member.membership_fee_start_date == ~D[2025-06-01]
|
||||
end
|
||||
end
|
||||
end
|
||||
258
test/membership_fees/membership_fee_cycle_test.exs
Normal file
258
test/membership_fees/membership_fee_cycle_test.exs
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
defmodule Mv.MembershipFees.MembershipFeeCycleTest do
|
||||
@moduledoc """
|
||||
Tests for MembershipFeeCycle resource.
|
||||
"""
|
||||
use Mv.DataCase, async: true
|
||||
|
||||
alias Mv.MembershipFees.MembershipFeeCycle
|
||||
alias Mv.MembershipFees.MembershipFeeType
|
||||
alias Mv.Membership.Member
|
||||
|
||||
setup do
|
||||
# Create a member for testing
|
||||
{:ok, member} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "Test",
|
||||
last_name: "Member",
|
||||
email: "test.member.#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|
||||
# Create a fee type for testing
|
||||
{:ok, fee_type} =
|
||||
Ash.create(MembershipFeeType, %{
|
||||
name: "Test Fee Type #{System.unique_integer([:positive])}",
|
||||
amount: Decimal.new("100.00"),
|
||||
interval: :monthly
|
||||
})
|
||||
|
||||
%{member: member, fee_type: fee_type}
|
||||
end
|
||||
|
||||
describe "create MembershipFeeCycle" do
|
||||
test "can create cycle with valid attributes", %{member: member, fee_type: fee_type} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
}
|
||||
|
||||
assert {:ok, %MembershipFeeCycle{} = cycle} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert cycle.cycle_start == ~D[2025-01-01]
|
||||
assert Decimal.equal?(cycle.amount, Decimal.new("100.00"))
|
||||
assert cycle.member_id == member.id
|
||||
assert cycle.membership_fee_type_id == fee_type.id
|
||||
end
|
||||
|
||||
test "can create cycle with notes", %{member: member, fee_type: fee_type} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id,
|
||||
notes: "First payment cycle"
|
||||
}
|
||||
|
||||
assert {:ok, cycle} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert cycle.notes == "First payment cycle"
|
||||
end
|
||||
|
||||
test "requires cycle_start", %{member: member, fee_type: fee_type} do
|
||||
attrs = %{
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
}
|
||||
|
||||
assert {:error, error} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert error_on_field?(error, :cycle_start)
|
||||
end
|
||||
|
||||
test "requires amount", %{member: member, fee_type: fee_type} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
}
|
||||
|
||||
assert {:error, error} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert error_on_field?(error, :amount)
|
||||
end
|
||||
|
||||
test "requires member_id", %{fee_type: fee_type} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
membership_fee_type_id: fee_type.id
|
||||
}
|
||||
|
||||
assert {:error, error} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert error_on_field?(error, :member_id) or error_on_field?(error, :member)
|
||||
end
|
||||
|
||||
test "requires membership_fee_type_id", %{member: member} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id
|
||||
}
|
||||
|
||||
assert {:error, error} = Ash.create(MembershipFeeCycle, attrs)
|
||||
|
||||
assert error_on_field?(error, :membership_fee_type_id) or
|
||||
error_on_field?(error, :membership_fee_type)
|
||||
end
|
||||
|
||||
test "status defaults to :unpaid", %{member: member, fee_type: fee_type} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
}
|
||||
|
||||
assert {:ok, cycle} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert cycle.status == :unpaid
|
||||
end
|
||||
|
||||
test "validates status enum values - unpaid", %{member: member, fee_type: fee_type} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id,
|
||||
status: :unpaid
|
||||
}
|
||||
|
||||
assert {:ok, cycle} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert cycle.status == :unpaid
|
||||
end
|
||||
|
||||
test "validates status enum values - paid", %{member: member, fee_type: fee_type} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-02-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id,
|
||||
status: :paid
|
||||
}
|
||||
|
||||
assert {:ok, cycle} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert cycle.status == :paid
|
||||
end
|
||||
|
||||
test "validates status enum values - suspended", %{member: member, fee_type: fee_type} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-03-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id,
|
||||
status: :suspended
|
||||
}
|
||||
|
||||
assert {:ok, cycle} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert cycle.status == :suspended
|
||||
end
|
||||
|
||||
test "rejects invalid status values", %{member: member, fee_type: fee_type} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id,
|
||||
status: :cancelled
|
||||
}
|
||||
|
||||
assert {:error, error} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert error_on_field?(error, :status)
|
||||
end
|
||||
end
|
||||
|
||||
describe "uniqueness constraint" do
|
||||
test "cannot create duplicate cycle for same member and cycle_start", %{
|
||||
member: member,
|
||||
fee_type: fee_type
|
||||
} do
|
||||
attrs = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
}
|
||||
|
||||
assert {:ok, _cycle1} = Ash.create(MembershipFeeCycle, attrs)
|
||||
assert {:error, error} = Ash.create(MembershipFeeCycle, attrs)
|
||||
|
||||
# Should fail due to uniqueness constraint
|
||||
assert is_struct(error, Ash.Error.Invalid)
|
||||
end
|
||||
|
||||
test "can create cycles for same member with different cycle_start", %{
|
||||
member: member,
|
||||
fee_type: fee_type
|
||||
} do
|
||||
attrs1 = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
}
|
||||
|
||||
attrs2 = %{
|
||||
cycle_start: ~D[2025-02-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
}
|
||||
|
||||
assert {:ok, _cycle1} = Ash.create(MembershipFeeCycle, attrs1)
|
||||
assert {:ok, _cycle2} = Ash.create(MembershipFeeCycle, attrs2)
|
||||
end
|
||||
|
||||
test "can create cycles for different members with same cycle_start", %{fee_type: fee_type} do
|
||||
{:ok, member1} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "Member",
|
||||
last_name: "One",
|
||||
email: "member.one.#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|
||||
{:ok, member2} =
|
||||
Ash.create(Member, %{
|
||||
first_name: "Member",
|
||||
last_name: "Two",
|
||||
email: "member.two.#{System.unique_integer([:positive])}@example.com"
|
||||
})
|
||||
|
||||
attrs1 = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member1.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
}
|
||||
|
||||
attrs2 = %{
|
||||
cycle_start: ~D[2025-01-01],
|
||||
amount: Decimal.new("100.00"),
|
||||
member_id: member2.id,
|
||||
membership_fee_type_id: fee_type.id
|
||||
}
|
||||
|
||||
assert {:ok, _cycle1} = Ash.create(MembershipFeeCycle, attrs1)
|
||||
assert {:ok, _cycle2} = Ash.create(MembershipFeeCycle, attrs2)
|
||||
end
|
||||
end
|
||||
|
||||
# Helper to check if an error occurred on a specific field
|
||||
defp error_on_field?(%Ash.Error.Invalid{} = error, field) do
|
||||
Enum.any?(error.errors, fn e ->
|
||||
case e do
|
||||
%{field: ^field} -> true
|
||||
%{fields: fields} when is_list(fields) -> field in fields
|
||||
_ -> false
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp error_on_field?(_, _), do: false
|
||||
end
|
||||
154
test/membership_fees/membership_fee_type_test.exs
Normal file
154
test/membership_fees/membership_fee_type_test.exs
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
defmodule Mv.MembershipFees.MembershipFeeTypeTest do
|
||||
@moduledoc """
|
||||
Tests for MembershipFeeType resource.
|
||||
"""
|
||||
use Mv.DataCase, async: true
|
||||
|
||||
alias Mv.MembershipFees.MembershipFeeType
|
||||
|
||||
describe "create MembershipFeeType" do
|
||||
test "can create membership fee type with valid attributes" do
|
||||
attrs = %{
|
||||
name: "Standard Membership",
|
||||
amount: Decimal.new("120.00"),
|
||||
interval: :yearly,
|
||||
description: "Standard yearly membership fee"
|
||||
}
|
||||
|
||||
assert {:ok, %MembershipFeeType{} = fee_type} =
|
||||
Ash.create(MembershipFeeType, attrs)
|
||||
|
||||
assert fee_type.name == "Standard Membership"
|
||||
assert Decimal.equal?(fee_type.amount, Decimal.new("120.00"))
|
||||
assert fee_type.interval == :yearly
|
||||
assert fee_type.description == "Standard yearly membership fee"
|
||||
end
|
||||
|
||||
test "can create membership fee type without description" do
|
||||
attrs = %{
|
||||
name: "Basic",
|
||||
amount: Decimal.new("60.00"),
|
||||
interval: :monthly
|
||||
}
|
||||
|
||||
assert {:ok, %MembershipFeeType{}} = Ash.create(MembershipFeeType, attrs)
|
||||
end
|
||||
|
||||
test "requires name" do
|
||||
attrs = %{
|
||||
amount: Decimal.new("100.00"),
|
||||
interval: :yearly
|
||||
}
|
||||
|
||||
assert {:error, error} = Ash.create(MembershipFeeType, attrs)
|
||||
assert error_on_field?(error, :name)
|
||||
end
|
||||
|
||||
test "requires amount" do
|
||||
attrs = %{
|
||||
name: "Test Fee",
|
||||
interval: :yearly
|
||||
}
|
||||
|
||||
assert {:error, error} = Ash.create(MembershipFeeType, attrs)
|
||||
assert error_on_field?(error, :amount)
|
||||
end
|
||||
|
||||
test "requires interval" do
|
||||
attrs = %{
|
||||
name: "Test Fee",
|
||||
amount: Decimal.new("100.00")
|
||||
}
|
||||
|
||||
assert {:error, error} = Ash.create(MembershipFeeType, attrs)
|
||||
assert error_on_field?(error, :interval)
|
||||
end
|
||||
|
||||
test "validates interval enum values - monthly" do
|
||||
attrs = %{name: "Monthly", amount: Decimal.new("10.00"), interval: :monthly}
|
||||
assert {:ok, fee_type} = Ash.create(MembershipFeeType, attrs)
|
||||
assert fee_type.interval == :monthly
|
||||
end
|
||||
|
||||
test "validates interval enum values - quarterly" do
|
||||
attrs = %{name: "Quarterly", amount: Decimal.new("30.00"), interval: :quarterly}
|
||||
assert {:ok, fee_type} = Ash.create(MembershipFeeType, attrs)
|
||||
assert fee_type.interval == :quarterly
|
||||
end
|
||||
|
||||
test "validates interval enum values - half_yearly" do
|
||||
attrs = %{name: "Half Yearly", amount: Decimal.new("60.00"), interval: :half_yearly}
|
||||
assert {:ok, fee_type} = Ash.create(MembershipFeeType, attrs)
|
||||
assert fee_type.interval == :half_yearly
|
||||
end
|
||||
|
||||
test "validates interval enum values - yearly" do
|
||||
attrs = %{name: "Yearly", amount: Decimal.new("120.00"), interval: :yearly}
|
||||
assert {:ok, fee_type} = Ash.create(MembershipFeeType, attrs)
|
||||
assert fee_type.interval == :yearly
|
||||
end
|
||||
|
||||
test "rejects invalid interval values" do
|
||||
attrs = %{name: "Invalid", amount: Decimal.new("100.00"), interval: :weekly}
|
||||
assert {:error, error} = Ash.create(MembershipFeeType, attrs)
|
||||
assert error_on_field?(error, :interval)
|
||||
end
|
||||
|
||||
test "name must be unique" do
|
||||
attrs = %{name: "Unique Name", amount: Decimal.new("100.00"), interval: :yearly}
|
||||
|
||||
assert {:ok, _} = Ash.create(MembershipFeeType, attrs)
|
||||
assert {:error, error} = Ash.create(MembershipFeeType, attrs)
|
||||
|
||||
# Check for uniqueness error
|
||||
assert error_on_field?(error, :name)
|
||||
end
|
||||
end
|
||||
|
||||
describe "update MembershipFeeType" do
|
||||
setup do
|
||||
{:ok, fee_type} =
|
||||
Ash.create(MembershipFeeType, %{
|
||||
name: "Original Name",
|
||||
amount: Decimal.new("100.00"),
|
||||
interval: :yearly,
|
||||
description: "Original description"
|
||||
})
|
||||
|
||||
%{fee_type: fee_type}
|
||||
end
|
||||
|
||||
test "can update name", %{fee_type: fee_type} do
|
||||
assert {:ok, updated} = Ash.update(fee_type, %{name: "Updated Name"})
|
||||
assert updated.name == "Updated Name"
|
||||
end
|
||||
|
||||
test "can update amount", %{fee_type: fee_type} do
|
||||
assert {:ok, updated} = Ash.update(fee_type, %{amount: Decimal.new("150.00")})
|
||||
assert Decimal.equal?(updated.amount, Decimal.new("150.00"))
|
||||
end
|
||||
|
||||
test "can update description", %{fee_type: fee_type} do
|
||||
assert {:ok, updated} = Ash.update(fee_type, %{description: "Updated description"})
|
||||
assert updated.description == "Updated description"
|
||||
end
|
||||
|
||||
test "can clear description", %{fee_type: fee_type} do
|
||||
assert {:ok, updated} = Ash.update(fee_type, %{description: nil})
|
||||
assert updated.description == nil
|
||||
end
|
||||
end
|
||||
|
||||
# Helper to check if an error occurred on a specific field
|
||||
defp error_on_field?(%Ash.Error.Invalid{} = error, field) do
|
||||
Enum.any?(error.errors, fn e ->
|
||||
case e do
|
||||
%{field: ^field} -> true
|
||||
%{fields: fields} when is_list(fields) -> field in fields
|
||||
_ -> false
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp error_on_field?(_, _), do: false
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue