Make seed script deterministic and idempotent for fee type assignments
Fix update action name from :update to :update_member for Member resource
This commit is contained in:
parent
3241dd7d96
commit
a03056e6ae
1 changed files with 48 additions and 17 deletions
|
|
@ -129,7 +129,12 @@ Accounts.create_user!(%{email: "admin@mv.local"}, upsert?: true, upsert_identity
|
|||
|> Ash.update!()
|
||||
|
||||
# Load all membership fee types for assignment
|
||||
all_fee_types = MembershipFeeType |> Ash.read!() |> Enum.to_list()
|
||||
# Sort by name to ensure deterministic order
|
||||
all_fee_types =
|
||||
MembershipFeeType
|
||||
|> Ash.Query.sort(name: :asc)
|
||||
|> Ash.read!()
|
||||
|> Enum.to_list()
|
||||
|
||||
# Create sample members for testing - use upsert to prevent duplicates
|
||||
# Member 1: Hans - All cycles paid
|
||||
|
|
@ -195,17 +200,32 @@ Enum.each(member_attrs_list, fn member_attrs ->
|
|||
member_attrs_without_status = Map.delete(member_attrs, :cycle_status)
|
||||
|
||||
# Use upsert to prevent duplicates based on email
|
||||
# First create/update member without membership_fee_type_id to avoid overwriting existing assignments
|
||||
member_attrs_without_fee_type = Map.delete(member_attrs_without_status, :membership_fee_type_id)
|
||||
|
||||
member =
|
||||
Membership.create_member!(member_attrs_without_status,
|
||||
Membership.create_member!(member_attrs_without_fee_type,
|
||||
upsert?: true,
|
||||
upsert_identity: :unique_email
|
||||
)
|
||||
|
||||
# Only set membership_fee_type_id if member doesn't have one yet (idempotent)
|
||||
final_member =
|
||||
if is_nil(member.membership_fee_type_id) and Map.has_key?(member_attrs_without_status, :membership_fee_type_id) do
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{
|
||||
membership_fee_type_id: member_attrs_without_status.membership_fee_type_id
|
||||
})
|
||||
|> Ash.update!()
|
||||
else
|
||||
member
|
||||
end
|
||||
|
||||
# Generate cycles if member has a fee type
|
||||
if member.membership_fee_type_id do
|
||||
if final_member.membership_fee_type_id do
|
||||
# Load member with cycles to check if they already exist
|
||||
member_with_cycles =
|
||||
member
|
||||
final_member
|
||||
|> Ash.load!(:membership_fee_cycles)
|
||||
|
||||
# Only generate if no cycles exist yet (to avoid duplicates on re-run)
|
||||
|
|
@ -213,7 +233,7 @@ Enum.each(member_attrs_list, fn member_attrs ->
|
|||
if Enum.empty?(member_with_cycles.membership_fee_cycles) do
|
||||
# Generate cycles
|
||||
{:ok, new_cycles, _notifications} =
|
||||
CycleGenerator.generate_cycles_for_member(member.id, skip_lock?: true)
|
||||
CycleGenerator.generate_cycles_for_member(final_member.id, skip_lock?: true)
|
||||
|
||||
new_cycles
|
||||
else
|
||||
|
|
@ -311,36 +331,47 @@ Enum.with_index(linked_members)
|
|||
user = member_attrs.user
|
||||
member_attrs_without_user = Map.delete(member_attrs, :user)
|
||||
|
||||
# Round-robin assignment: continue cycling through fee types
|
||||
# Start from where previous members ended
|
||||
fee_type_index = rem(3 + index, length(all_fee_types))
|
||||
fee_type = Enum.at(all_fee_types, fee_type_index)
|
||||
|
||||
member_attrs_with_fee_type =
|
||||
Map.put(member_attrs_without_user, :membership_fee_type_id, fee_type.id)
|
||||
# Use upsert to prevent duplicates based on email
|
||||
# First create/update member without membership_fee_type_id to avoid overwriting existing assignments
|
||||
member_attrs_without_fee_type = Map.delete(member_attrs_without_user, :membership_fee_type_id)
|
||||
|
||||
# Check if user already has a member
|
||||
member =
|
||||
if user.member_id == nil do
|
||||
# User is free, create member and link - use upsert to prevent duplicates
|
||||
Membership.create_member!(
|
||||
Map.put(member_attrs_with_fee_type, :user, %{id: user.id}),
|
||||
Map.put(member_attrs_without_fee_type, :user, %{id: user.id}),
|
||||
upsert?: true,
|
||||
upsert_identity: :unique_email
|
||||
)
|
||||
else
|
||||
# User already has a member, just create the member without linking - use upsert to prevent duplicates
|
||||
Membership.create_member!(member_attrs_with_fee_type,
|
||||
Membership.create_member!(member_attrs_without_fee_type,
|
||||
upsert?: true,
|
||||
upsert_identity: :unique_email
|
||||
)
|
||||
end
|
||||
|
||||
# Only set membership_fee_type_id if member doesn't have one yet (idempotent)
|
||||
final_member =
|
||||
if is_nil(member.membership_fee_type_id) do
|
||||
# Assign deterministically using round-robin
|
||||
# Start from where previous members ended (3 members before this)
|
||||
fee_type_index = rem(3 + index, length(all_fee_types))
|
||||
fee_type = Enum.at(all_fee_types, fee_type_index)
|
||||
|
||||
member
|
||||
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|
||||
|> Ash.update!()
|
||||
else
|
||||
member
|
||||
end
|
||||
|
||||
# Generate cycles for linked members
|
||||
if member.membership_fee_type_id do
|
||||
if final_member.membership_fee_type_id do
|
||||
# Load member with cycles to check if they already exist
|
||||
member_with_cycles =
|
||||
member
|
||||
final_member
|
||||
|> Ash.load!(:membership_fee_cycles)
|
||||
|
||||
# Only generate if no cycles exist yet (to avoid duplicates on re-run)
|
||||
|
|
@ -348,7 +379,7 @@ Enum.with_index(linked_members)
|
|||
if Enum.empty?(member_with_cycles.membership_fee_cycles) do
|
||||
# Generate cycles
|
||||
{:ok, new_cycles, _notifications} =
|
||||
CycleGenerator.generate_cycles_for_member(member.id, skip_lock?: true)
|
||||
CycleGenerator.generate_cycles_for_member(final_member.id, skip_lock?: true)
|
||||
|
||||
new_cycles
|
||||
else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue