Commit 98f2d9ec authored by Mahmoud Aglan's avatar Mahmoud Aglan

docs(subscriptions): update architecture map with final migration results

Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 9df6ed31
# Subscriptions Module — Architecture Map # Subscriptions Module — Architecture Map
> **Last updated:** 2026-07-03 (getRate() truthiness bug fixed, cron daemon added to Docker) > **Last updated:** 2026-07-04 (first FY = 2023/2024 enforced, 50% discount applied, full data migration)
> **Status:** Living document — incrementally updated as new information is discovered > **Status:** Living document — incrementally updated as new information is discovered
--- ---
...@@ -319,15 +319,19 @@ the correct values idempotently via ON DUPLICATE KEY UPDATE. ...@@ -319,15 +319,19 @@ the correct values idempotently via ON DUPLICATE KEY UPDATE.
Financial year runs July to June: Financial year runs July to June:
- If month >= 7: FY = thisYear/(thisYear+1) → e.g. "2025/2026" - If month >= 7: FY = thisYear/(thisYear+1) → e.g. "2025/2026"
- If month < 7: FY = (lastYear)/thisYear → e.g. "2024/2025" - If month < 7: FY = (lastYear)/thisYear → e.g. "2024/2025"
CRITICAL: Subscription system started in 2023/2024.
No subscriptions should exist before this year.
``` ```
**Subscription rates (2025/2026):** **Subscription rates by year:**
| Person Type | Base Amount | Dev Fee | Total | | FY | Member/Spouse Base | Child/Temp Base | Discount | Net (M/S) | Net (C/T) |
|-------------|-------------|---------|-------| |----|-------------------|-----------------|----------|-----------|-----------|
| Member | 492.00 | 35.00 | 527.00 | | 2023/2024 | 410.00 | 185.00 | 50% | 205.00 | 92.50 |
| Spouse | 492.00 | 0.00 | 492.00 | | 2024/2025 | 410.00 | 185.00 | — | 410.00 | 185.00 |
| Child | 222.00 | 0.00 | 222.00 | | 2025/2026+ | 492.00 | 222.00 | — | 492.00 | 222.00 |
| Temporary | 222.00 | 0.00 | 222.00 |
**Development fee:** 35.00 EGP (member type only, non-discountable)
--- ---
...@@ -380,9 +384,9 @@ Financial year runs July to June: ...@@ -380,9 +384,9 @@ Financial year runs July to June:
--- ---
## 15. Data Migration (SubscriptionDataMigration) — Added 2026-07-03 ## 15. Data Migration (SubscriptionDataMigration) — Updated 2026-07-04
A one-time migration service (`app/Modules/Subscriptions/Services/SubscriptionDataMigration.php`) that ensures complete subscription coverage for all members from their join date to present. A rerunnable migration service (`app/Modules/Subscriptions/Services/SubscriptionDataMigration.php`) that ensures complete, correct subscription coverage for all members.
**CLI Commands:** **CLI Commands:**
```bash ```bash
...@@ -391,26 +395,27 @@ php cli.php subscriptions:migrate --dry-run # Preview without changes ...@@ -391,26 +395,27 @@ php cli.php subscriptions:migrate --dry-run # Preview without changes
php cli.php subscriptions:validate # Verify data integrity php cli.php subscriptions:validate # Verify data integrity
``` ```
**What it does (5 phases):** **What it does (6 phases):**
1. **Fix orphaned person_ids**: Subscriptions with wrong `person_id` (e.g., member_id used instead of spouse_id). Matches by name, including archived records. 0. **Remove pre-system subscriptions**: Delete unpaid subs before 2023/2024 (system didn't exist). Paid records preserved as historical.
2. **Remove duplicates**: Exact (member_id + financial_year + person_type + person_id) duplicates — keeps lowest ID. 1. **Fix orphaned person_ids**: Match by name (including archived records), or delete if no dependent found.
3. **Fix incorrect amounts**: Zero-amount non-exempt rows get corrected using historical rate table. 2. **Remove duplicates**: Exact (member_id + FY + person_type + person_id) — keeps lowest ID.
4. **Create missing subscriptions**: For each active member + all dependents, ensures subscription exists for every FY from join date to present. Past FYs get `status='overdue'`. 3. **Fix amounts and discounts**: Ensure correct base_amount, discount_amount (50% for 2023/2024), total_amount per year.
5. **Apply fines**: Uses `SubscriptionCalculator::calculateLateFine()` then distributes proportionally per row. 4. **Create missing subscriptions**: For each active member + all dependents, from join date (capped at 2023/2024) to present.
5. **Reset and apply fines**: Clear all fines, recalculate from scratch using SubscriptionCalculator.
**Historical rate table (hardcoded in migration):**
| FY | Member/Spouse | Child/Temp | **Key business rules enforced:**
|----|-------------|-----------| - First FY = 2023/2024 (subscription system inception)
| 2023/2024 | 410.00 | 185.00 | - 2023/2024 gets 50% discount on base rate (from SUBSCRIPTION_YEAR_ADJUSTMENT_2023 rule)
| 2024/2025 | 410.00 | 185.00 | - No other year has a discount currently
| All other years | 492.00 | 222.00 | - Fines start from 2023/2024, progressive: 10%/50%/100%/200%/300%
**Results from first production run (2026-07-03):** **Results from production run (2026-07-04):**
- 568 subscriptions created, 93 orphaned IDs fixed, 32 duplicates removed, 230 fines applied - 255 pre-system subscriptions removed, 130 discount corrections, 149 fines recalculated
- Final count: 1,140 total subscriptions across all FYs - Final count: 885 total subscriptions (2023/2024 through 2026/2027)
- Validation: ALL CLEAN — no issues found - 66 members, 53 spouses, 86-89 children, 1-11 temporary — all matching active dependents
- Validation: ALL CLEAN
**Known limitation**: The `RetroactiveMembershipService` (line 714) has a fallback `$sub['person_id'] ?? $memberId` that can create orphaned records when person_index doesn't map correctly. This is the root cause of orphaned IDs. The data migration service cleans these up.
**Known limitation**: `RetroactiveMembershipService` (line 714) has `$sub['person_id'] ?? $memberId` fallback that creates orphaned records. The migration cleans these up.
--- ---
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment