fix: CycleGenerator generates from last cycle, not filling gaps

- Change algorithm to start from last existing cycle instead of start_date
- Deleted cycles (gaps) are no longer automatically filled
- Add test to verify gaps remain unfilled
- Update documentation to clarify gap handling behavior
This commit is contained in:
Moritz 2025-12-12 16:33:39 +01:00
parent 272a8a8afc
commit 0b986db635
2 changed files with 95 additions and 14 deletions

View file

@ -174,6 +174,63 @@ defmodule Mv.MembershipFees.CycleGeneratorTest do
assert second_cycles == []
end
test "does not fill gaps when cycles were deleted" do
setup_settings(true)
fee_type = create_fee_type(%{interval: :yearly})
# Create member without fee type first to control which cycles exist
member =
create_member_without_cycles(%{
join_date: ~D[2020-03-15],
membership_fee_start_date: ~D[2020-01-01]
})
# Manually create cycles for 2020, 2021, 2022, 2023
for year <- [2020, 2021, 2022, 2023] do
MembershipFeeCycle
|> Ash.Changeset.for_create(:create, %{
cycle_start: Date.new!(year, 1, 1),
member_id: member.id,
membership_fee_type_id: fee_type.id,
amount: fee_type.amount,
status: :unpaid
})
|> Ash.create!()
end
# Delete the 2021 cycle (create a gap)
cycle_2021 =
MembershipFeeCycle
|> Ash.Query.filter(member_id == ^member.id and cycle_start == ^~D[2021-01-01])
|> Ash.read_one!()
Ash.destroy!(cycle_2021)
# Now assign fee type to member (this triggers generation)
# Since cycles already exist (2020, 2022, 2023), the generator will
# start from the last existing cycle (2023) and go forward
member =
member
|> Ash.Changeset.for_update(:update_member, %{membership_fee_type_id: fee_type.id})
|> Ash.update!()
# Verify gap was NOT filled and new cycles were generated from last existing
all_cycles = get_member_cycles(member.id)
all_cycle_years = Enum.map(all_cycles, & &1.cycle_start.year) |> Enum.sort()
# 2021 should NOT exist (gap was not filled)
refute 2021 in all_cycle_years, "Gap at 2021 should NOT be filled"
# 2020, 2022, 2023 should exist (original cycles)
assert 2020 in all_cycle_years
assert 2022 in all_cycle_years
assert 2023 in all_cycle_years
# 2024 and 2025 should exist (generated after last existing cycle 2023)
assert 2024 in all_cycle_years
assert 2025 in all_cycle_years
end
test "sets correct amount from membership fee type" do
setup_settings(true)
amount = Decimal.new("75.50")