1. 21 Jun, 2026 1 commit
    • Mahmoud Aglan's avatar
      Enforce waiver bylaws: dependent count validation + annual renewal check · c2e440e4
      Mahmoud Aglan authored
      Per bylaws requirements for التنازل عن العضوية:
      
      1. Target member's dependents must NOT exceed source member's original
         dependent count — blocks with error if exceeded, requiring board
         approval + extra fees before proceeding.
      
      2. All annual subscriptions must be paid (no pending/overdue) before
         the waiver can be completed.
      
      3. Show view now displays dependent counts and renewal status.
      
      4. Create view updated with full bylaws summary (5 conditions).
      
      5. Displays current membership value (from pricing_configs) not old stored value.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      c2e440e4
  2. 19 Jun, 2026 1 commit
    • Mahmoud Aglan's avatar
      Fix waiver duplicate key error + wrong fee calculation + member search name mismatch · 6c3db858
      Mahmoud Aglan authored
      TKT-71: Fixed duplicate entry for membership_number by reversing operation
      order in WaiverProcessor — source member's number is now NULLed BEFORE
      assigning it to target member, preventing unique constraint violation.
      
      TKT-71: Waiver fee now calculated from current pricing_configs value instead
      of the member's stored membership_value (old/historical price).
      
      TKT-69: Member search duplicate check now shows the entity type (spouse/child)
      and the parent member's number, clarifying which person is being shown.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      6c3db858
  3. 17 Jun, 2026 3 commits
    • Mahmoud Aglan's avatar
      Remove child fees from divorce transfer — fees only on new additions post-separation · 42f0ccc6
      Mahmoud Aglan authored
      Per bylaws clarification: children transferred during divorce separation move
      without fees. Age-based fees (15%/20%/25%/30%) apply only when the new
      independent member adds NEW children after the separation is complete.
      
      - Removed child fee calculation from boardApprove flow
      - Children selection is now transfer-only (no fee columns)
      - Updated fee preview JS to exclude child fees
      - Fee breakdown shows "transferred without fees" for moved children
      - Total = percentage_fee + form_fee (570) + annual_subscription only
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      42f0ccc6
    • Mahmoud Aglan's avatar
      Use current membership value from pricing_configs for divorce fee calculation · 94e1f426
      Mahmoud Aglan authored
      Instead of using the stored member.membership_value (which may be outdated),
      the divorce module now fetches the current active price from pricing_configs
      based on the member's branch and qualification at the time of the request.
      
      - Added DivorceFeeCalculator::getCurrentMembershipValue() method
      - Updated boardApprove, show, and create to use current pricing
      - Views now display "قيمة العضوية الحالية" with source indicator
      - Payment breakdown shows which source was used for the calculation
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      94e1f426
    • Mahmoud Aglan's avatar
      Fix divorce fee calculation: add both_working case, restore child <12 to 15%, unify 50% · e64c8865
      Mahmoud Aglan authored
      - Added 'both_working' case type detection via spouse.classification field
        (annual subscription only, 0% separation fee per bylaws)
      - Restored DIVORCE_CHILD_UNDER_12 percentage from 5% back to 15% per bylaws
      - Unified joined_after suggested percentage to 50% regardless of spouse order
      - Updated show.php to display both_working scenario in board panel
      - Updated architecture map with corrected business rules
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      e64c8865
  4. 13 Jun, 2026 9 commits
  5. 12 Jun, 2026 7 commits
    • Mahmoud Aglan's avatar
      Separate dev fee from subscription total: single 35 EGP added at invoice level · e381d4e9
      Mahmoud Aglan authored
      Business rule: مصاريف تنمية is a single flat 35 EGP fee per family per year,
      NOT per person, NOT included in discountable base, added AFTER all calculations.
      
      Changes:
      - Generator: total_amount = base - discount (dev fee stored separately, not in total)
      - Migration: subtracts dev_fee from total_amount for existing unpaid rows
      - payYear(): adds single dev fee on top of subscription+fine totals at payment
      - View: dev fee shown as separate line below the subscription subtotal, before
        the invoice grand total. Table columns simplified (no per-row dev fee column)
      
      Calculation order:
      1. Sum all family subscription bases
      2. Apply year discount (e.g. 50% for 2023/2024) to subscription amounts
      3. Add single 35 EGP dev fee as standalone charge at the end
      4. Add fines (on subscription only, not dev fee)
      = Final invoice total
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      e381d4e9
    • Mahmoud Aglan's avatar
      Implement unified family payment: single button pays entire year · 2d63c655
      Mahmoud Aglan authored
      - New payYear() controller action: processes all unpaid subscriptions for a
        member's financial year in one transaction with a single receipt
      - Route: POST /members/{memberId}/subscriptions/{year}/pay
      - View: replaced per-row pay buttons with a single "سداد اشتراك بالكامل" button
        at the bottom of each year section showing total due
      - Itemized table remains for transparency (shows each person's breakdown)
      - Added discount_amount column to the table display
      - FIFO still enforced: only oldest unpaid year's button is active
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      2d63c655
    • Mahmoud Aglan's avatar
      Fix discount calculation: مصاريف تنمية excluded from discountable base · cd3c2724
      Mahmoud Aglan authored
      Business rule: the 35 EGP development fee is a flat non-discountable surcharge
      added AFTER all discounts are applied. Discount applies only to base_amount.
      
      Correct formula: discount = base × pct, total = (base - discount) + dev_fee
      Previous (wrong): discount = (base + dev_fee) × pct
      
      For member 51 (2023/2024): 410×50% = 205 discount, total = 205 + 35 = 240
      (was incorrectly: 445×50% = 222.50, total = 222.50)
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      cd3c2724
    • Mahmoud Aglan's avatar
      Apply mandated 50% discount for 2023/2024 subscriptions · 2e65dd2e
      Mahmoud Aglan authored
      - Migration: retroactively applies 50% discount to all unpaid 2023/2024
        subscription rows (discount on gross total = base + dev fee)
      - SubscriptionGenerator: year-specific discount now applied on per-row total
        (base + dev_fee) and stored in discount_amount column, not just on base rate
      
      Business rule: SUBSCRIPTION_YEAR_ADJUSTMENT_2023 mandates 50% reduction on
      the final subscription total for all person types in that fiscal year.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      2e65dd2e
    • Mahmoud Aglan's avatar
      Fix cron job: delegate to OverdueFineApplicator, enforce consecutive-year drop rule · fc2128c5
      Mahmoud Aglan authored
      - OverdueFineJob now delegates fine calculation/distribution/drop to
        OverdueFineApplicator::run() which already does proportional distribution
      - Added reinstatement expiry call (12-month window enforcement)
      - Only marks subscriptions overdue when financial_year < current (grace period)
      - SubscriptionCalculator: drop check now verifies 5 CONSECUTIVE unpaid years
        instead of just checking if oldest overdue >= 5 (prevents false drops when
        a member paid middle years)
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      fc2128c5
    • Mahmoud Aglan's avatar
      Fix fine distribution: proportionally split across subscription rows per year · 5287a41a
      Mahmoud Aglan authored
      Previously the year-level fine (e.g. 897 EGP) was stamped identically on
      every row in the year, tripling the displayed fine. Now distributes
      proportionally based on each row's total_amount relative to the year total.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      5287a41a
    • Mahmoud Aglan's avatar
      Overhaul subscription display: FIFO enforcement, fine calculations, year grouping · 194da186
      Mahmoud Aglan authored
      - Add FIFO payment validation: must pay oldest year first before newer years
      - Add OverdueFineApplicator::applyForMember() for on-demand fine recalculation
      - Rewrite view with year-grouped sections, fine breakdown panels, totals
      - Add data migration to fix corrupted rows (paid_amount with no payment_id)
      - Show fine calculation details (percentage × base = amount, from rules engine)
      - Disable pay buttons for non-oldest years with Arabic tooltip
      - Summary cards showing total debt, fines, and years overdue
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      194da186
  6. 11 Jun, 2026 2 commits
  7. 10 Jun, 2026 1 commit
    • Mahmoud Aglan's avatar
      Fix membership fee calculations, subscription escalation, and over-25 children freeze · 0dd4abfc
      Mahmoud Aglan authored
      - TemporaryFeeCalculator: resolve current pricing_configs price instead of stored
        membership_value, matching SpouseFeeCalculator and ChildFeeCalculator behaviour
      - SubscriptionGenerator: add per-dependent dedup guards (spouse/child/temporary)
        to prevent duplicate subscription rows on repeated batch runs
      - Phase_89_001 migration: idempotent fix for subscription late-fine escalation rules
        (10/50/100/200/300% over 5 years, correct from the broken seed 100/200/300%)
      - Members show view: add warning banner listing active male children aged 25+ with
        direct freeze button, surfacing the existing freeze route that was never linked
      Co-Authored-By: 's avatarClaude Sonnet 4.6 <noreply@anthropic.com>
      0dd4abfc
  8. 08 Jun, 2026 1 commit
    • Mahmoud Aglan's avatar
      Fix children age display: compute dynamically from DOB, auto-separate at 25 · 110d7771
      Mahmoud Aglan authored
      - MemberController: SELECT TIMESTAMPDIFF for age_years/age_months in children query
      - children-table.php: compute age from DOB in view (fallback for static column)
      - show.php (member): same dynamic age + add 'separated' status translation
      - show.php (child): compute age from DOB dynamically, fix 25+ threshold check
      - AgeMonitorJob: add daily age recalculation for all children, change auto-freeze
        to auto-separate (status='separated', classification='separated')
      - AutoFreezeService: update processAutoFreeze() to separate instead of just freeze
      - DB fixes: corrected DOBs from NIDs, updated all ages, separated 3 children >= 25
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      110d7771
  9. 07 Jun, 2026 1 commit
    • Mahmoud Aglan's avatar
      Fix transfer fee calculation and remove dev fee from dependents · 7e3ac060
      Mahmoud Aglan authored
      - SeparationFeeCalculator: handle NULL qualification_id with fallback
        pricing lookup, use actual membership_type instead of hardcoded 'working'
      - SeparationFeeCalculator companion surcharge: use current pricing_configs
        instead of stale member.membership_value
      - SubscriptionGeneratorJob: set development_fee=0.00 for spouse/child/temp
        (matching SubscriptionGenerator service that was already fixed)
      - RetroactiveMembershipService: default dev fee to 0.00 for non-member types
      - RetroactiveWizardController: same default logic for missing form fields
      - Retroactive wizard JS: generate 0.00 dev fee for dependent subscriptions
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      7e3ac060
  10. 03 Jun, 2026 2 commits
    • Mahmoud Aglan's avatar
      Fix fee calculation: handle NULL qualification_id in pricing lookup · c8353344
      Mahmoud Aglan authored
      Members with qualification_id=NULL (old retroactive entries) were falling
      back to the stored membership_value (e.g. 119,800) instead of using the
      current pricing (150,000). Now when qualification is NULL, we look up the
      minimum price for that branch+type, which gives the correct base value.
      
      Also fixed 26 existing subscription records in live DB: removed dev fee
      (35.00) from spouse/child/temp subscriptions and recalculated totals.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      c8353344
    • Mahmoud Aglan's avatar
      Fix fee calculations: use current pricing, remove dev fee for dependents · 6873f19e
      Mahmoud Aglan authored
      Business rule fixes per ticket #68:
      
      1. Spouse/child fee percentages now use CURRENT membership value from
         pricing_configs (150k/225k/300k) instead of old stored value at creation
      
      2. Spouse annual subscription = 492 (SVC_ANNUAL_SPOUSE) WITHOUT dev fee
         Was incorrectly using child rate (222) + dev fee (35) = 257
      
      3. Child/temp annual subscription = 222 WITHOUT dev fee
         Was incorrectly adding 35 dev fee = 257
      
      4. Late marriage penalty: now calculated from LATER of (marriage_date,
         member_activated_at) to TODAY — not from marriage to member creation
      
      5. SubscriptionGenerator batch: spouse/child/temp subscriptions no longer
         include development_fee (set to 0.00). Only member keeps dev fee.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      6873f19e
  11. 01 Jun, 2026 3 commits
    • Mahmoud Aglan's avatar
      Overhaul coach create form: full validation, NID auto-parse, edge cases · e1f1837a
      Mahmoud Aglan authored
      Frontend:
      - Client-side NID parser (no API call) — extracts DOB, gender, age, governorate
      - Shows green badge with parsed info (governorate, gender, age)
      - Red highlight + Arabic message on every invalid field
      - Validates: code, name, employment_type, payment_model (non-academy),
        academy_id (academy), NID length, email format, phone format
      - Hides payment/rate fields for academy coaches (not needed)
      - Shows note explaining academy coaches follow salary system
      - Gender/DOB auto-locked when NID is valid, manual otherwise
      - Age displayed under DOB field
      
      Backend:
      - Strips non-digits from NID input
      - Uppercase code automatically
      - Checks NID uniqueness against existing coaches
      - Validates email with filter_var
      - Academy coach requires academy_id selected
      - payment_model defaults to 'salary' for academy, 'per_session' fallback
      - max_groups minimum 1
      - Success message includes coach name
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      e1f1837a
    • Mahmoud Aglan's avatar
      Migration: add updated_by/created_by to all 17 tables with autoTrackAuthor · 646d11e6
      Mahmoud Aglan authored
      Tables fixed (already applied to live DB directly):
      reservations, academy_settlements, achievement_definitions,
      activity_subscriptions, facility_grids, facility_monthly_plans,
      facility_zone_schedules, player_evaluations, player_injuries,
      pool_bookings, pool_configurations, pool_schedules,
      sa_player_documents, sa_pricing_rules, tournaments,
      training_groups, training_sessions
      
      Migration is idempotent — checks column existence before ALTER.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      646d11e6
    • Mahmoud Aglan's avatar
      Fix 2 boot failures: reservations.updated_by missing, sa_coaches.payment_model NULL · 299e67a6
      Mahmoud Aglan authored
      - reservations: added updated_by column (model has autoTrackAuthor=true but column didn't exist)
      - sa_coaches: academy coaches now default to payment_model='salary' instead of NULL (NOT NULL column)
      - Also applied column fix directly to live DB via SSH
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      299e67a6
  12. 31 May, 2026 5 commits
  13. 30 May, 2026 3 commits
    • Mahmoud Aglan's avatar
      Add seed: 32 bot players + test tournament for bracket testing · 56cb4395
      Mahmoud Aglan authored
      Run: php cli.php seed:run Phase_88_001_seed_tournament_bot_players
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      56cb4395
    • Mahmoud Aglan's avatar
      Fix retroactive wizard: parse NID for date_of_birth and gender · 0f4ca990
      Mahmoud Aglan authored
      The members table has date_of_birth as NOT NULL, but the wizard passed
      null when no explicit DOB was entered. Now NationalIdParser extracts
      DOB and gender from the 14-digit national ID for the main member,
      spouses, children, and temporary members.
      
      If no NID and no DOB provided, returns a clear validation error instead
      of letting the DB constraint violation propagate.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      0f4ca990
    • Mahmoud Aglan's avatar
      Fix 5 support ticket bugs: AJAX errors, capacity validation, audit export,... · 30062682
      Mahmoud Aglan authored
      Fix 5 support ticket bugs: AJAX errors, capacity validation, audit export, player lookup, fee display
      
      TKT-59: ExceptionHandler now returns JSON for AJAX/XHR requests instead of
      HTML error pages. Booking wizard JS improved to show actual error messages.
      
      TKT-57: Pricing rule creation now validates group_size_max against the
      facility unit's max_capacity, preventing over-capacity rules.
      
      TKT-46: Added audit log CSV export with all current filters applied.
      New route GET /audit/export and export button in the filter bar.
      
      TKT-55: Player registration member lookup now uses only the DB id
      (set by AJAX member lookup) instead of ambiguous membership_number/id
      fallback. National ID field locked when auto-filled from member record.
      
      TKT-50: Fee breakdown text now shows base amount and development fee
      separately (e.g. "اشتراك سنوي: 222.00 + تنمية: 35.00 = 257.00")
      instead of just the combined total.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      30062682
  14. 24 May, 2026 1 commit