- 30 Aug, 2026 4 commits
-
-
Mahmoud Aglan authored
fix(members,subscriptions): drop due-date column from family tables, collect annual subscription via الخزنة - Remove the "تاريخ الاستحقاق" column from the spouses/children/temporary members tables on the member show page (display-only, no schema change). - Annual subscription payments no longer post directly from the اشتراك سنوي page. SubscriptionController::payYear() now queues a payment_request instead of calling PaymentService::processPayment() directly; the subscription rows are only marked paid once خزنة العضويات (Membership Treasury / Cashier) actually collects it, via a new payment_request.completed listener (SubscriptionSyncService::completeFamilyYearPayment()). - Closed the same bypass on the legacy generic /payments/process/{id} page, which had its own divergent partial-payment, oldest-year-first logic for annual_subscription that skipped the treasury entirely and violated the all-or-nothing-per-family rule; that path now redirects to the member's subscriptions page instead. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
-
Mahmoud Aglan authored
fix(pricing): require board decision for member special discounts, allow fixed-amount down payment on board offers - special_discounts gains board_decision_number/board_decision_date; the member-facing "special discount" dropdown (fill-form, edit, show, apply) now only lists/accepts discounts backed by a board decision instead of the full unaudited special_discounts catalog, per client request that the dropdown should only read board-approved discounts. - board_offers gains inst_down_payment_type (percentage/fixed_amount) so a board-approved offer's installment down payment (المقدم) can be a fixed cash amount, not only a percentage. Wired through BoardOfferService, InstallmentCalculator (new min_down_amount override) and PaymentLifecycleService so the fixed amount is actually enforced at billing time, not just in the admin form. Co-Authored-By:Claude Sonnet 5 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Users saw sidebar links that returned 403. Root cause was drift between four independently-authored declaration sets that nothing reconciles: the permission catalogue (bootstrap.php), the route gate (Routes.php), the menu gate (MenuRegistry) and the role grants (seeds). Route shadowing (Router::dispatch is first-match-wins over a sorted module glob): - GET /reports was declared by both Members and Reports; Members won and enforced member.reports while the sidebar gated on report.view_membership. Members' report routes moved to /members/reports/*. - GET /sports-dashboard[/export] was declared by three modules, so the dashboard index and its drill-downs were served by different modules. Disciplines -> /disciplines/dashboard, PlaygroundAdmin -> /playgrounds/dashboard[/export]; /sports-dashboard is now wholly owned by SportsDashboard. - Members/Routes.php used unconstrained {id} in 15 routes, so /members/<anything> was swallowed by MemberController@show. Constrained to {id:\d+}, matching every other module. All 25 affected links updated. Gate alignment: - Six menu entries gated on a different permission than the route they link to (/members/search, /sports, /carnets, /rentals/entities, /notifications/templates, /reports). Authorization bypasses: - RetroactiveWizardController hardcoded a role_code = 'super_admin' query, throwing "هذه الأداة متاحة فقط لمدير النظام". Replaced with a registered member.retroactive permission enforced by the route and grantable via the Roles UI. - report_definitions.required_permission was stored and displayed but never checked, so report.view_membership was enough to open ANY report by code, including financial ones. Now enforced on view/export/print; the listing filters to what the viewer can actually run. Role grants (Phase_105_001, idempotent): - Closes the reported gaps for report_viewer, general_manager, receptionist, sports_officer, academy_manager and membership_director; grants the sports report keys to board_member/auditor so enforcing the per-report permission does not silently remove reports; revokes member.view/member.search from facilities_manager, who keeps bookings and reservations. Data correctness: - SaFinanceReportService read base_price from sa_pricing_rules, a facility booking table with neither that column nor activity_type, and derived revenue as headcount x a rate-card price. Now sums actual sa_registrations .registration_fee, matching how subscription and booking revenue are computed. Regression guard: - php cli.php permissions:audit reconciles all four declaration sets, reproduces the router's load order, and exits non-zero on drift. Run it after touching any Routes.php, menu block or role seed. Docs: new docs/architecture-maps/Authorization.md; cross-module authorization section added to DEPENDENCY-GRAPH.md. Note: the live DB was unreachable from the dev environment, so role grants were verified by replaying the seeds and schema came from migrations, not the live DB. PHPUnit is not installed locally; all changed files lint clean. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- ActivitySubscriptions: fix generate/calculateRate querying nonexistent `enrollments` table; use `academy_enrollments` with correct columns - SportsDashboard: fix queries against nonexistent `disciplines` table; use `sport_disciplines` - Sports: unify conversion-fee percentage to a single source (MembershipRulesService::getAthleticMemberConversionRules), preventing the eligibility preview from drifting from what's actually charged - SportsActivity: align absence-threshold fallback defaults between AttendanceRuleService and TrainingAttendanceService via a shared constant - SportsActivity: auto-bill first month on Registration Wizard completion, matching the direct-enrollment path so wizard-registered players aren't left uncharged until the monthly batch runs - ActivitySubscriptions: guard paySubscription() to only transition pending/overdue -> paid, making it idempotent against the (currently unreachable) payment.completed listener path - ActivitySubscriptions: dispatch academy.enrollment_created from the enroll wizard so PlayerAffairs' auto-billing listener actually fires Also adds/updates Architecture Maps for Sports, SportsActivity, SportsDashboard, ActivitySubscriptions and the cross-module Dependency Graph, per this repo's mandatory architecture-map workflow. Co-Authored-By:
Claude Opus 5 <noreply@anthropic.com> Co-Authored-By:
Claude Sonnet 5 <noreply@anthropic.com>
-
- 29 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
Every user previously saw the same dashboard: DashboardDataService::getData() returned one fixed payload with no reference to the current employee. A cashier got membership stats they could not act on; an HR manager got revenue instead of headcount. Each role now gets a curated dashboard. Role presets pick the layout, permissions gate every widget (mirroring MenuRegistry::getVisible), and multi-role users get the deduped union of their presets. Super admin gets a 5-KPI, 16-widget command center across six sections. Wires up WidgetRegistry, which existed fully written but was used by nothing. 144 widgets, all SQL executed and verified against the live schema — 46 were corrected during verification, including a month-to-date figure compared against a full prior month (a fake collapse every month), spouse counts missing their status filter, and receivables that included debt owed by archived deceased members. Only the headline plus first six widgets query on load; the rest hydrate through GET /dashboard/widget/{key}, which re-checks permission server-side and renders via the same partial as the eager path. Employees with no mapped role fall back to the previous shared dashboard, preserved verbatim. Also loads Chart.js, which PlayerAffairs has always called behind a `typeof Chart !== 'undefined'` guard while the library was loaded nowhere — those evaluation charts were silently dead and now render. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
-
- 28 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
Assigns human-friendly usernames, unique passwords, and business-appropriate roles to all 62 imported employees based on their HR job titles. Includes credentials reference sheet for permission testing. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Add board offer "عروض عضويات شيراتون 2026" with 4 tiers (cash 10%, 24mo 0%, 40mo 15%, 60mo 15%) - Add "فوق المتوسط" qualification at 187,500 EGP - Fix crash in show.php: board_offers uses title_ar not name_ar - Rewrite discounts tutorial with full regulatory discount coverage Co-Authored-By:Claude Opus 4.6 (1M context) <noreply@anthropic.com>
-
- 27 Aug, 2026 1 commit
-
-
Mahmoud Aglan authored
Sports Activity Reports: player reports with filters (discipline/program/group/ player type/medical/payment status/branch) and finance reports (revenue/costs/ profit with daily/weekly/monthly/yearly/3yr/5yr/custom periods). CSV and PDF export for both. Role-based access with 3 new permissions. Membership Discounts: fix BillingService to include regulatory discount as bill line item, add regulatory discount section to edit page, add FYI discount guide to show page covering all 3 discount types (special, regulatory, board offers), handle regulatory discount in update controller with document upload. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 26 Aug, 2026 4 commits
-
-
Mahmoud Aglan authored
Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Phase 3: Weekly work schedules - Migration: hr_weekly_schedules table (per-employee per-day shift times + rest days) - Seed: import 59 employees' weekly schedules from club's work schedule sheet - Seed: 13 shift definitions (9-5, 3-11, 10-6, 12-8, etc.) Phase 7B: Job description cards - Migration: hr_job_descriptions table (purpose, authority, duties per job title) - View: printable بطاقة الوصف الوظيفي matching club's official template - Route: GET /hr/job-titles/{id}/description-card Phase 8: Org structure hierarchy - Migration sets parent_id=1 (EXEC) for all other departments Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Phase_05_001: changed department_type from 'edara' to 'idara' (CHECK constraint only allows 'idara'/'qism') - Phase_05_002: create employees table records before hr_employee_profiles to satisfy FK constraint - Generates unique usernames (emp0001, emp0002, ...) - Sets default password 'Club@2026' with force_password_change=1 - Links hr_employee_profiles.employee_id to newly created employees.id Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Phase 1 - Leave System (2025 Law): - Annual leave: 15d (1st year) → 21d (after 1y) → 30d (10y+/age 50+) → 45d (disability) - Maternity: 90 → 120 days (4 months), hajj: now PAID with 5y service min - New leave types: childcare (unpaid, 3 career, 24mo gap), paternity (1d, 3 career), exam - Casual leave: enforce max 2 consecutive days - Childcare gap enforcement, service months validation Phase 2 - Employee Import: - Extract 75 employees from HR registry Excel → JSON seed data - 34 Bank of Alexandria accounts extracted for salary transfers - 14 departments + all job titles auto-created from registry - Migration adds variable_salary + total_allowances columns Phase 4 - Payroll Alignment (July 2026 format): - Solidarity fund: 0.25% of gross (صندوق التكافل) - Stamp duty: 3% of net (دمغة عادية وإضافية) - now percentage-based - Emergency fund + VAT config keys added - calculation_json includes full breakdown Phase 5 - Bank Transfer Export: - BankTransferService generates transfer data from payroll runs - CSV export with BOM for Arabic compatibility - View + route: /hr/payroll/periods/{id}/bank-transfer Phase 6 - Performance Evaluation: - Seed 10-criteria template matching club's official form (100 points) - Dual evaluator support (direct manager + general supervisor) - 5-tier rating labels (ضعيف → ممتاز) Phase 7 - Reports & Forms: - Work receipt printable form (إقرار استلام العمل) - Workforce statement report (بيان القوة الفعلية) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 23 Aug, 2026 3 commits
-
-
Mahmoud Aglan authored
Always-visible reference table on the membership form showing: - All 7 articles with their discount percentages and conditions - Which branches each applies to - What proof is needed (auto-verify vs document upload) - Non-stacking rule note Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
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 7 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>
-