- 23 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
- Add regulatory_discount_id/amount/document columns to members table - Add eligibility type selector with conditional sections per type - Auto-verification for cross-branch (checks members DB) and club employee (HR) - Document upload for types requiring manual proof (gov, ministry, board, group) - AJAX eligibility check button calls /pricing/regulatory-discounts/check-eligibility - Creates audit trail application record on form submit (status: pending) - Dynamic UI: shows/hides relevant fields based on selected type Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Full-cycle implementation of club bylaw discount rules: - Art 97: Cross-branch member discounts (50% Sheraton
↔ 6th Oct, 25% →Admin Capital) - Art 98: Government employees 50%, Ministry of Youth 62.5% at Admin Capital - Art 99: Ministry of Youth 25% at Sheraton/6th Oct - Art 100: Board of Trustees 50% + 2yr interest-free installment - Art 101: Ministry employees installment-only (no discount) - Art 102: Club employees (5+ yrs) up to 15% - Art 110: Group membership tiered (5-10→3%, 11-20→7%, 21+→10%) Includes: migration, seed data, model, service with eligibility engine, controller (CRUD + eligibility check API + application workflow), views (index, form, applications), routes, permissions, menu entry, and PricingEngine integration. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 20 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Board Offers: - Add board_offer_tiers table for multiple payment plans per offer - Each offer now supports 4 tiers: cash (10% discount), 24mo/0%, 40mo/15%, 60mo/15% - View shows all tiers as selectable cards with pre-calculated breakdowns - Controller accepts offer_tier_id and uses tier-specific terms - Seed populates tiers for all active board offers - Legacy fallback preserved when no tiers are configured Subscription Fix: - First-year members no longer get subscription rows (membership fee covers current FY) - First-year dependents no longer get subscription rows (addition fee covers current FY) - MembershipValidationService bypasses subscription check for first-year members - AutoFreezeService.checkSubscriptionBlock bypasses for first-year members - MembershipRulesService.canPrintCarnet bypasses for first-year members - SubscriptionGenerator skips first-year members/dependents entirely - Individual subscription pay() now redirects to payYear() (all-or-nothing family payment) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 19 Aug, 2026 3 commits
-
-
Mahmoud Aglan authored
The hidden input had min=1 with value=0, causing browser validation error "not focusable" when form submits. Changed to min=0 with empty default. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Complete guide covering board offers lifecycle, special discounts, subscription adjustments, accumulation rules, edge cases, scenarios, and anti-patterns. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Fixed crash: pagination used `total_pages` key but Pagination class returns `last_page` - Board offers index: card-based layout with status indicators, usage counts, branch names (joined), days-until-expiry warnings, and stat summary at top - Board offers form: two-column layout with live preview sidebar that shows real-time calculation examples, date validation warnings, and contextual help - Model search now joins branches table and counts payment_request usage per offer Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 18 Aug, 2026 9 commits
-
-
Mahmoud Aglan authored
SubscriptionSyncService was recreating subscription rows for waiver-acquired members on every page view and event. Added early return when transferred_from_waiver_id is set — waiver fee covers annual subscription, no separate subscription rows should exist. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Waiver-acquired members should not have subscription rows created — the waiver fee covers the annual subscription implicitly. Also sets join_date on all dependents (spouses, children, temps) when they are activated during waiver completion, using COALESCE to preserve any pre-existing value. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Both completion paths (last installment paid + early cash settlement) now set remaining_balance = 0.00. Fixed 14 existing completed plans in live DB. Archive view colors remaining green when 0, red when outstanding. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
remaining_balance is set at plan creation and never updated. For completed plans, display "0.00 (مكتمل)" in green instead of the misleading original balance. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
1. Removed the green/blue financial summary stat cards (membership value + total paid) from member profile — only the "سجل المدفوعات" button remains 2. Deceased children and spouses now show a red "حالة الوفاة" button linking to their death case record 3. Deceased spouses now appear in the spouse table (were previously hidden by is_archived filter) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Adds comprehensive translation maps for DB column names (field labels), enum values (status, relationship, classification, gender), section headers, and boolean fields. All archive snapshot data now displays in Arabic. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Three issues fixed: 1. Deceased/archived dependents now transfer with membership (Death, Transfer, Waiver) 2. Archive snapshots (full membership history) follow the membership number on all transfer types 3. Missing Arabic labels added for transfer subtypes in Archive views Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
1. Transfer & Divorce now block completion if source member has debts (extracted DebtCheckService from WaiverProcessor to shared service) 2. MemberNumberGenerator retries on UNIQUE constraint race (3 attempts) 3. Acquired member detection uses direct members.transferred_from_* columns instead of fragile 4-table query with exception swallowing 4. Waiver auto-complete moved to cron job (unblocks cashier HTTP response) 5. Reconcile on profile view now flashes warning when status changes Also deletes all 77 outdated architecture maps per request. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 16 Aug, 2026 3 commits
-
-
Mahmoud Aglan authored
The waiver system was incorrectly moving spouses, children, and temporary members from the source to the target. The target member enters their own new dependents — source dependents should be archived with the source member, not transferred. Also removed transfer of subscriptions, installments, fines, documents, and payment requests since debt check ensures those are cleared before execution anyway. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Replaced every emoji in show.php, edit.php, create.php, search.php, changelog.php, and _partials/profile-header.php with proper Lucide SVG icons for a professional, consistent UI appearance. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
When a waiver completes, all dependents on the target member should be marked as active since their fees are included in the waiver fee payment. Previously only activated_by_payment_id was set but status remained 'pending_payment', leaving dependents stuck. Also ensures qualification_id is transferred from source to target member. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 12 Aug, 2026 16 commits
-
-
Mahmoud Aglan authored
The qualification (مؤهل) chosen during separation fee calculation is now locked in the form fill step — it cannot be changed. This ensures the new member gets the correct qualification_id, and all dependent fee calculations (children, spouses) use the full price of that qualification. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Dependents added after July 1st already pay their subscription via the addition fee. Instead of skipping them entirely, create the subscription row with status='paid' so they appear in the subscription list correctly. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Children, spouses, and temporary members added on or after July 1st of the financial year already have their annual subscription included in the addition fee. The generator now excludes them from batch renewal generation for that year to avoid double-charging. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
When a separating child's wife is foreign (أجنبي), 15% of the full membership value (based on the chosen qualification) is added per foreign spouse to the separation fee total. - Add foreignSpouseCount param to calculateForChildSeparation - Count foreign spouses from dep_spouses nationality field in controller - Add foreign_spouse_fee column to transfer_requests - Display surcharge in transfer show page breakdown Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Validates that the computed effective transfer date for male dependents cannot be earlier than the parent member's membership start date. Female path already had this check; now both paths enforce the rule. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Rebuild board_offers table with unified schema (cash path + installment path in one record) - Add grace period support (first_n_months and full_free_under_n modes) - Add offer snapshot to payment_requests for persistence across offer expiry - Add offer context (board_offer_id, grace_months) to installment_plans - Refactor BoardOfferService with branch-aware offer resolution - Enhance InstallmentCalculator with grace period math - Full admin CRUD (BoardOfferController + views + routes + permissions) - Integrate offer display in member show page payment section - Snapshot offer at payment request creation, use snapshot in plan creation - Fix BillingService to use new BoardOfferService API Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Member header photo: camera icon to upload/change, X to delete - Spouses: hover avatar to upload/delete photo (routes + controller) - Children: hover avatar to upload/delete photo (routes + controller) - Temporary members: hover avatar to upload/delete photo (routes + controller) - All use existing PhotoUploadService with compression + thumbnails - CSS hover reveals action buttons on dependent avatars Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Member header now has a gradient banner with a large circular photo (or initials fallback). Spouses, children, and temporary members show inline 36px avatar circles with gender-colored gradients when no photo is uploaded. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The treasury queue page filtered by payment_type whitelist and didn't include sa_game_ticket, sa_pool_ticket, or pool_reservation — so those payment requests were created but never appeared in the cashier queue. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The issueTicket response was passing the raw Model object to json(), which could fail serialization. Now returns entry_id instead, and wraps recordEntry in try-catch for proper error reporting. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The service desk ticket form allows issuing tickets to walk-in guests without a carnet or membership, but the carnet_guest_entries table had NOT NULL + FK constraints on both columns, causing a 500 error. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The PoolReservationService already called PaymentRequestService::createRequest() but with member_id=0 and payment_type='pool_reservation' — which was silently rejected because 'pool_reservation' wasn't in the non-member whitelist. - Added 'pool_reservation' to PaymentRequestService whitelist - Added payment type label (حجز حارة سباحة) - Added payment completion handler → marks reservation as paid - Added void handler → reverts reservation to pending Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Game tickets now create payment requests (sa_game_ticket type) sent to the cashier sub-queue, matching pool ticket and booking patterns - Added session lifecycle actions: start, complete, cancel with UI buttons - Fixed session status bug: allow issuing tickets during 'in_progress' sessions - Fixed GuestEntryService crash when no carnet exists (skip UPDATE on id=0) - Added payment completion/void handlers for game and pool tickets - Extended PaymentRequestService whitelist for sa_game_ticket/sa_pool_ticket - Added comprehensive tutorial sections 9-14 covering entertainment workflows Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The ticket form and lookup in service-desk sent '_token' but the CSRF middleware expects '_csrf_token'. This caused HTTP 419 on every ticket issuance attempt. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Critical fixes: - submitFormPayment() now checks sa_players.registration_fee_paid as a safety net before creating any payment request - startRegistration() member_id fallback only used when NID matches the member's actual national_id (prevents NID-swap fee bypass) - lookupPlayer() validates NID-to-member consistency before proceeding - Existing registration lookup now includes 'pending_payment' status - Frontend clears membership_number when NID is manually changed after auto-fill Feature: - Player profile page now shows "Print Form" and "Generate Card" buttons for completing registration steps outside the wizard Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 11 Aug, 2026 5 commits
-
-
Mahmoud Aglan authored
- Convert migrations 103_007 and 103_008 to closures that check column existence before ALTER TABLE (fixes boot failure when columns were already added manually) - Add docs/tutorials/discounts-and-offers-guide.md Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Add file upload field on violation creation (image/PDF/doc, max 5MB) - Store proof_file path in violations table (new column) - Show proof file link (
📎 ) in violations index table - Auto-send monetary fines to cashier queue on imposition - Add manual "طابور الدفع" button on fines index for unpaid fines - Add sendToQueue controller method + route Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The base Model::create() auto-appends created_by when timestamps are enabled, but workflow_instances and workflow_transition_log were missing this column — causing PDOException on fine imposition. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Add qualification dropdown to first screen of child separation — the fee is a percentage of new membership value which varies by qualification - Pass selected qualification_code to SeparationFeeCalculator (was null) - Add /api/members/check-nid endpoint for real-time NID conflict detection - Add client-side NID conflict check on both form_fill and create pages - Block submission when active member has same NID (show clear error) - Warn (orange) when potential/inactive member exists (will auto-archive) - Server-side validation: reject if active NID conflict in store/saveFillForm - Validate qualification_code required for child_separation in store() - Add phone format validation on form_fill submit Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Transfer #14 failed because the national_id already existed on a potential (never-activated) member record. Now archives any conflicting potential/inactive/pending member with the same national_id before inserting the new active member. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-