[FEATURE]: Membership Fee 3 - Cycle Generation System #277

Open
opened 2025-12-11 15:47:29 +01:00 by moritz · 0 comments
Owner

Goal: Implement automatic cycle generation for members.

Scope:

  • Create Mv.MembershipFees.CycleGenerator module
  • Implement cycle generation algorithm:
    • Lock cycle table for duration (prevent race conditions)
    • Determine first cycle from membership_fee_start_date
    • Generate cycles from last existing cycle (or start date) to today
    • Respect left_at boundary
    • Skip existing cycles (idempotent)
    • Set amount from current membership fee type
  • Create Ash change module: set_membership_fee_start_date.ex
    • Auto-calculate start date from joined_at and global setting
    • Handle include_joining_cycle logic
  • Integrate with Member resource (trigger on creation/type assignment)
  • Create scheduled job structure (skeleton, actual scheduling in later issue)

Files to Create:

  • lib/mv/membership_fees/cycle_generator.ex
  • lib/membership_fees/changes/set_membership_fee_start_date.ex
  • Update lib/membership/member.ex to use change module

Tests to Write:

  • Unit Tests for CycleGenerator:

    • Generate cycles from start date to today
    • Generate cycles from last existing cycle
    • Respect left_at boundary (stop generation)
    • Skip existing cycles (idempotent)
    • Set correct amount from membership fee type
    • Handle NULL membership_fee_start_date (calculate from joined_at)
    • Lock mechanism prevents concurrent generation
  • Unit Tests for Start Date Calculation:

    • include_joining_cycle = true: Start date is first day of joining cycle
    • include_joining_cycle = false: Start date is first day of next cycle
    • Works for all interval types (monthly, quarterly, half_yearly, yearly)
    • Manual override works (admin can set custom date)
  • Integration Tests:

    • Member creation triggers cycle generation
    • Member gets membership fee type assigned → cycles generated
    • Multiple members can have cycles generated concurrently
    • Generation is idempotent (can run multiple times safely)
  • Edge Case Tests:

    • Member joins today → current cycle generated
    • Member left yesterday → no future cycles
    • Member has no cycles → generates from start date
    • Member has existing cycles → generates from last cycle
    • Year boundary handling
    • Leap year handling

Acceptance Criteria:

  • Cycles generated correctly for all interval types
  • Idempotent generation (safe to run multiple times)
  • Respects all boundaries (start date, left_at, today)
  • Lock mechanism prevents race conditions
  • Start date calculation works for all scenarios
**Goal:** Implement automatic cycle generation for members. **Scope:** - Create `Mv.MembershipFees.CycleGenerator` module - Implement cycle generation algorithm: - Lock cycle table for duration (prevent race conditions) - Determine first cycle from `membership_fee_start_date` - Generate cycles from last existing cycle (or start date) to today - Respect `left_at` boundary - Skip existing cycles (idempotent) - Set amount from current membership fee type - Create Ash change module: `set_membership_fee_start_date.ex` - Auto-calculate start date from `joined_at` and global setting - Handle `include_joining_cycle` logic - Integrate with Member resource (trigger on creation/type assignment) - Create scheduled job structure (skeleton, actual scheduling in later issue) **Files to Create:** - `lib/mv/membership_fees/cycle_generator.ex` - `lib/membership_fees/changes/set_membership_fee_start_date.ex` - Update `lib/membership/member.ex` to use change module **Tests to Write:** - **Unit Tests for CycleGenerator:** - Generate cycles from start date to today - Generate cycles from last existing cycle - Respect `left_at` boundary (stop generation) - Skip existing cycles (idempotent) - Set correct amount from membership fee type - Handle NULL `membership_fee_start_date` (calculate from joined_at) - Lock mechanism prevents concurrent generation - **Unit Tests for Start Date Calculation:** - `include_joining_cycle = true`: Start date is first day of joining cycle - `include_joining_cycle = false`: Start date is first day of next cycle - Works for all interval types (monthly, quarterly, half_yearly, yearly) - Manual override works (admin can set custom date) - **Integration Tests:** - Member creation triggers cycle generation - Member gets membership fee type assigned → cycles generated - Multiple members can have cycles generated concurrently - Generation is idempotent (can run multiple times safely) - **Edge Case Tests:** - Member joins today → current cycle generated - Member left yesterday → no future cycles - Member has no cycles → generates from start date - Member has existing cycles → generates from last cycle - Year boundary handling - Leap year handling **Acceptance Criteria:** - Cycles generated correctly for all interval types - Idempotent generation (safe to run multiple times) - Respects all boundaries (start date, left_at, today) - Lock mechanism prevents race conditions - Start date calculation works for all scenarios
moritz added this to the Membership Fees milestone 2025-12-11 15:47:29 +01:00
moritz added the
medium priority
M
labels 2025-12-11 15:47:29 +01:00
moritz self-assigned this 2025-12-11 15:47:29 +01:00
moritz added this to the Sprint 10: 11.12-08.01 project 2025-12-11 15:47:29 +01:00
moritz changed title from [FEATURE]: Membership Fee - Cycle Generation System to [FEATURE]: Membership Fee 3 - Cycle Generation System 2025-12-11 15:50:37 +01:00
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: local-it/mitgliederverwaltung#277
No description provided.