1. 01 Jul, 2026 1 commit
    • Mahmoud Aglan's avatar
      feat(waiver): live target debt check on create page + require waiver doc · 99e7632a
      Mahmoud Aglan authored
      - Added GET /api/members/{id}/debts endpoint returning comprehensive
        debt check as JSON (clear, debts array, total)
      - Create page now fetches and displays target member debts live after
        selection via AJAX — shows detailed debt table or green "clear" badge
      - Form submission blocked if target has outstanding debts, with error
        message and direct link to payment page
      - Made waiver request document upload required (HTML validation)
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      99e7632a
  2. 28 Jun, 2026 1 commit
    • Mahmoud Aglan's avatar
      feat(waiver): auto-complete waiver after fee payment instead of manual approval · d92f1d38
      Mahmoud Aglan authored
      After the cashier collects the waiver fee, the system now automatically
      executes the waiver completion (membership transfer) without requiring
      a manual "إتمام التنازل" button click.
      
      The auto-complete validates all conditions first:
      - Fee paid (status = fee_paid)
      - Target member specified
      - Board approval exists
      - No debts on source or target member
      - Excess dependent fees properly set
      
      If any condition fails, the waiver stays in fee_paid status with a
      clear checklist showing what's still needed, plus a manual fallback
      button for edge cases.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      d92f1d38
  3. 26 Jun, 2026 4 commits
    • Mahmoud Aglan's avatar
      fix(waiver): handle empty date_of_birth strings in individual fee insert · 26838f17
      Mahmoud Aglan authored
      MySQL rejects empty strings for DATE columns. The approve form sends
      empty strings for persons without a DOB (spouses, temporary members).
      Convert empty strings to null for date_of_birth, relationship, status,
      and notes fields before INSERT.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      26838f17
    • Mahmoud Aglan's avatar
      fix(payments): actually update subscription/fine/installment records when paid from process page · 9044313e
      Mahmoud Aglan authored
      The generic payment process page (linked from waiver "الانتقال إلى السداد") was
      recording payments in the payments table but never updating the source records
      (subscriptions.paid_amount, fines.paid_amount, installment_schedule.paid_amount).
      This caused the debt check to keep showing debts as unpaid after payment.
      
      Added handleSubscriptionPayment, handleFinePayment, and handleInstallmentPayment
      methods that mark the underlying records as paid (oldest first).
      
      Also fixed waiver debt check using wrong fines status ('pending' instead of
      'imposed'/'appeal_upheld') which is what fines actually use.
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      9044313e
    • Mahmoud Aglan's avatar
      feat(waiver): per-individual fee assignment + fix 404 payment button · c8fae48c
      Mahmoud Aglan authored
      - New table `waiver_individual_fees` stores fee per person (not per category)
      - Board approval screen shows each excess person as a separate card with:
        name, DOB, age, age category, relationship, independent fee type/rate
      - Children 25+ flagged with warning and "فصل العضوية" button
      - Live JS calculates per-person amounts and updates grand total instantly
      - Fee breakdown section shows individual names when individual fees exist
      - Fix: /members/{id}/financial → /payments/process/{id} (was 404)
      - WaiverProcessor::getExcessIndividuals() identifies the specific excess persons
      - WaiverProcessor::saveIndividualFees() persists per-person board decisions
      - Age categories expanded: under_12, 12_to_16, 16_to_18, 18_to_25, 25_plus
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      c8fae48c
    • Mahmoud Aglan's avatar
      feat(waiver): Round 2 UX — comprehensive debt check, children details, payment in target's name · 83f24d7a
      Mahmoud Aglan authored
      - checkDebtsComprehensive() returns per-person breakdown (name, type, debt_type, period, amount)
      - getDependentDetails() calculates age, DOB, age category for children
      - New sendToCashier route creates payment request in TARGET member's name (buyer pays)
      - Detailed receipt breakdown with both member names and per-category fees
      - show.php: per-person debt table, children comparison, status indicators, go-to-payment button
      - create.php: detailed debt display with person labels, children age table
      - Status flow: requested → approved → send to cashier → fee_paid → complete
      Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
      83f24d7a
  4. 23 Jun, 2026 1 commit
  5. 22 Jun, 2026 5 commits
  6. 21 Jun, 2026 3 commits
  7. 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
  8. 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
  9. 13 Jun, 2026 9 commits
  10. 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
  11. 11 Jun, 2026 2 commits
  12. 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
  13. 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
  14. 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