- 30 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
Icons - No emoji anywhere in the UI. Extracted the sidebar's inline SVG map into a single <x-ui.icon name="..."> component and added the icons the pricing work needed, so there is one source instead of a per-view copy. Discount recipes now carry icon NAMES, not glyphs. Schedule builder - Facilities are scoped to the selected branch. The screen listed every branch's facilities, which is how someone books the wrong building. A ?facility_id= carried over from another branch (bookmark, back button) is now dropped instead of silently overriding the branch scope. - Groups are scoped to the facility's branch AND to the sports that facility hosts, so a football court no longer offers swimming groups. That link did not exist, so this adds a facility_activities pivot. A facility that declares no activities still hosts anything, so nothing breaks for academies that have not filled it in. Facility grid - Removed the arbitrary ceilings (rows/columns capped at 10, lanes at 20). Physical space is not limited to a number we picked. - New facilities never got a layout, which is why the grid silently failed to appear on them. FacilityService::create now seeds one, the migration backfills every existing facility that has none, and the default is a 1x1 grid — "one whole space, not subdivided yet" — rather than inventing a subdivision nobody asked for. - Grid size is editable straight from facility settings, with a live preview of the cells being described. Shrinking onto a segment that holds a confirmed future reservation is refused rather than silently dropping someone's booking. - Sports and starting grid are both settable at creation time too. Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
-
Mahmoud Aglan authored
Two bugs meant no pricing rule has ever applied correctly: 1. Condition keys never matched. The engine reads min/max/values; the wizard wrote min_age/min_children/target_gender and the form blade wrote a third set. Ranges saw null bounds and list rules saw an empty allow-list, both of which passed, so every rule applied to every participant. 2. Percentages were 100x too small. applyAdjustment divides by 10000 (basis points) but both screens stored a plain percent, so "20%" discounted 0.2%. They masked each other, which is why the symptom looked like a broken engine rather than two bugs — and why everyone moved to the untyped super-admin price override instead. Engine - ConditionSchema is now the single owner of the conditions vocabulary; builder, engine, simulator and migration all read keys from it. - Percent handles all basis-point conversion; nothing else touches the raw column. - evaluateInList fails closed instead of treating an empty allow-list as "match everyone". - custom rules no longer auto-apply; they are picker-only. - enrollment_timing honours days_before_start (fails closed without a program start date instead of silently passing). - Global discount cap reads system_settings rather than a hardcoded constant with a TODO. - New: explain(), audience(), wouldApply(), and role-capped manual discounts. Per-branch - pricing_rule_branches pivot so one rule targets many branches, instead of one near-identical row per branch that drifts apart. Stacking - is_stackable now defaults to false; best-of-one is the normal case and stacking is an explicit opt-in. Authoring - The five-step column editor becomes a recipe gallery plus an Arabic sentence, with a live simulator on a real participant and an audience count that warns when a rule would hit everyone. Saving a conditionless rule is refused. Checkout - ManagesDiscounts trait plus <x-pricing.discount-picker>: branch-scoped, searchable, pinned favourites, replace-vs-stack inline, blocked rows show why. Wired into CollectPaymentWizard renewals; discount names are frozen onto invoice.metadata so receipts survive later rule changes. - NewRegistrationWizard now prices through the engine using a provisional context built from the form, since the participant row does not exist yet. The step-4 guard still checks the base price, so a 100% discount is not mistaken for an unpriced program. Migration - Rewrites conditions onto the canonical keys and scales percentages to basis points. Rules whose conditions cannot be mapped confidently are deactivated rather than guessed, with the old JSON kept in metadata.legacy_conditions. Also fixes list and coupon views that rendered the raw column (a 20% rule would have displayed as 2000%), and adds the [x-cloak] CSS rule that was missing app-wide. Co-Authored-By:Claude Opus 5 (1M context) <noreply@anthropic.com>
-
- 27 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Switch streamCsv from chunk() to cursor() to fix truncated export - Mirror Livewire query in ExportController (search by membership_id/national_id) - Apply PermissionService::applyScope() to export query - Fix branch scoping fallback to match UsesBranchScope trait - Add membership_type and is_free filters to list and export - Pass sort params to export so CSV respects current sort order - Whitelist sort columns to prevent SQL injection - Output enum values and is_free column in CSV Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 24 Aug, 2026 1 commit
-
-
Mahmoud Aglan authored
Rebuilt the transfer wizard to support selecting multiple participants from a source group and moving them all to a destination group at once. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 23 Aug, 2026 7 commits
-
-
Mahmoud Aglan authored
When a training schedule is created or updated, immediately generate sessions for the next 7 days so trainers see today's sessions without waiting for the nightly cron. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Trainers now see sessions for groups where they are head_trainer_id in addition to explicit assignments, ensuring no sessions are missed. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Client-side Alpine.js search that filters enrollments by name (Arabic/English) or phone number instantly without server round-trips. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Business rule: non-payment or absence = debt, not removal. Participants stay enrolled and appear in attendance regardless of payment/attendance. - Remove frozen/suspended filter from attendance generation - DeactivateExpiredEnrollments now only logs (no status change) - EnforceAttendanceThresholds only warns (no auto-suspend) - SuspendOnThreshold listener disabled (log only) - BackfillAttendanceRecords no longer skips frozen/suspended Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
SessionCreated event had no listener to generate attendance records for existing enrollments. Added GenerateSessionAttendance listener, fixed rescheduleSession to dispatch SessionCreated, added attendance generation on payment-activated enrollments, and added daily backfill command as safety net. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Qualify status and training_group_id with table name to avoid ambiguity when joining participants/people tables for name sorting. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Add WithSorting trait to POSHistory, ActivityLog, MessageLog - Migrate GroupList and ProgramList to use WithSorting trait (remove duplicate) - Add sortable columns (name, date, payment) to GroupShow enrollments subtable - Add sort-header components to POS, ActivityLog, and MessageLog blade views - Fix FK violation on group/program delete: nullify enrollments.transferred_to_id - Fix Arabic name confirmation: normalize ي/ى, ة/ه, hamza variants before compare Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 22 Aug, 2026 3 commits
-
-
Mahmoud Aglan authored
- ParticipantList: default sort by name_ar ASC, added sort headers for activity and membership columns - EnrollmentList: added sort by participant name (join), group name, and payment_status columns - GroupList: default sort by name_ar ASC instead of created_at Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
UserForm was setting role_id on the users table but not syncing to the role_user pivot table. Permission checks use the pivot (roles() relation), so users appeared to have the correct role in the UI but had zero permissions in practice. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The group view was marking players as "unpaid" if they had ANY unpaid invoice (products, etc.), even if their program subscription was fully paid. Now the logic only checks: 1. Enrollment payment_status (paid/waived = done) 2. Enrollment's linked invoice status 3. Recent subscription invoice with matching program name Also fixed ActivateEnrollmentOnPayment listener to properly set payment_status='paid' on enrollments when subscription invoice is paid (was only activating status, not updating payment_status). Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 20 Aug, 2026 1 commit
-
-
Mahmoud Aglan authored
- Group view: added KPI cards for paid/unpaid/free player counts - Group view: added essential product purchase stats with progress bars - Group view: added installment info column per player in enrollments tab - Fixed PHP 8.2+ trait property conflict: removed $sortBy/$sortDir redeclarations from 13 Livewire components that use WithSorting trait, moved custom defaults to mount() instead Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 19 Aug, 2026 3 commits
-
-
Mahmoud Aglan authored
- Sort header component: blue active arrow, hover-to-reveal for inactive, cursor-pointer, group-hover animation - Participant list: name column now sortable (joins people table) - Trainer list: name column sortable (joins employees→people) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Created WithSorting trait (shared across all 35 list components) - Created <x-ui.sort-header> Blade component with arrow indicators - All table lists now support click-to-sort on key columns (persisted via URL) - Trainer edit form: added salary amount + frequency fields from Employee model - Trainer edit form: person data (name, national_id, phone) already included Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Free player: is_free column, toggle button on participant show, badge component across all views, skip invoice on enrollment/renewal for free players - Trainer delete: full cascade (cancel compensations/advances, remove future attendance, cancel assignments, nullify trainer refs, deactivate user, archive employee/person, free national_id for reimport) - Trainer edit: person data fields (name, national_id, phone) editable from trainer form Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 16 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
This was the THIRD auto-suspend mechanism (alongside send-alerts and the real-time listener). It directly wrote status='suspended' without going through the event/listener. Now all three paths respect the same opt-in setting. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Both the scheduled command and the real-time listener now check 'auto_suspend_on_threshold' setting (default: false). Auto-suspend will only fire if explicitly enabled in system_settings. This prevents participants from being repeatedly suspended after reactivation due to old attendance records in the lookback window. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 15 Aug, 2026 1 commit
-
-
Mahmoud Aglan authored
-
- 13 Aug, 2026 6 commits
-
-
Mahmoud Aglan authored
- New migration: attachment_path + attachment_name columns on expenses - ExpenseForm uses WithFileUploads trait, accepts jpg/png/webp/pdf up to 5MB - Drag-drop upload zone in the form with preview of attached file name - Files stored in storage/app/public/expenses/ Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
When a participant goes from suspended/frozen/inactive → active, the listener now regenerates expected attendance records for all their active enrollments' future sessions. Previously, reactivated participants were invisible in attendance because records were only generated at session creation time. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Payment Collection (CollectPaymentWizard): - Remove branch filter from participant search (POS sells cross-branch) - Include Draft status in outstanding invoice query - Add invoice search mode (search by invoice number/contact name) - Allow walk-in invoices to be found and paid directly - Accept inactive/frozen/registered participants (not just active) Retroactive Enrollment Wizard: - Fix "paid outside system" to use PaymentService (creates proper Payment + Transaction records for financial reports) - Add server-side validation in confirm() before DB transaction - Add national_id duplicate check to prevent duplicate participants - Add price=0 guard (show error if no base price and no override) - Fix rounding loss: remainder goes to last month's invoice - Pass skip_auto_invoice to prevent double invoice creation POS Partial Payment: - Enable allows_partial_payment on all existing products (migration) so the deposit/partial payment UI appears at checkout Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
All financial-related pages are now reachable from the Financial Overview via quick-action buttons with proper permission gates. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Shows all POS receipts (RCP-*) containing this product with: receipt number, customer, total, payment status, method, cashier, date. Each receipt has a print link and invoice link for further actions. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Prominent button with colored border (amber pulse when unpinned, green when pinned) - Dropdown with branch list, selected indicator, and pin status - Pin icon shows when branch is locked - Selecting a branch auto-pins it (persists across logout/login) - Unpin button available to release the lock - Visual hint text explains pin behavior Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 10 Aug, 2026 2 commits
-
-
Mahmoud Aglan authored
Trainers section (purple header) shows first with max 2-3 records. Players section (blue header) shows below with full table. Access control: - Trainer account: can only mark their own attendance (others disabled) - Supervisor/head_trainer (role level >= 60): can mark all trainers Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Branch: saves preferred_branch_id to users table on switch, restores on next login/session so you stay on the branch you last picked. Expenses: adds status column (active/cancelled) with cancel button that creates a reversing double-entry transaction. Cancelled expenses remain visible but excluded from totals. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 09 Aug, 2026 10 commits
-
-
Mahmoud Aglan authored
Shows when the invoice was last paid instead of when it was created. List is already sorted by paid_at DESC. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Shows the method (cash/card/wallet/etc) from the invoice's most recent payment, making it easy to see how each invoice was settled at a glance. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The print receipt was always showing only the total amount, even when the transaction was a partial payment (deposit). Now shows paid amount, remaining balance, and a "مدفوع جزئياً" badge when the linked invoice has outstanding balance. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The payment summary panel was only counting inbound payments, ignoring outbound refunds entirely. Now shows net amounts (inbound - refunds) per method, and displays a refund line when refunds exist in the selected period. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Shows most recently paid invoices at the top so the user sees the latest actual money collected, not just the latest generated. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
CollectPaymentWizard and ReconciliationWizard were creating payments without payer_type/payer_id, making them invisible on participant profiles. Now PaymentService inherits payer from the invoice's billable when callers omit it. Also auto-generates reference if empty. Fixed 113 orphaned payments in production. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Auto-generated renewal invoices are created by the system, but collected_by records the real person who collected the money from the participant. Set on every payment collection via updatePaidAmount. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The old code tried to find 'system@oc-sport.com' then fell back to User::first() which silently attributed 222 invoices to a random Head Trainer. Now uses enrollment.created_by as the actor — if that user no longer exists, the invoice is skipped with an error log. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Bug 1: Attendance threshold was counting 'expected' records in the denominator, causing any player with future sessions to have a low attendance rate and get auto-suspended. Fixed by excluding 'expected' status from rate calculation and requiring minimum 5 evaluated records before triggering threshold enforcement. Bug 2: Registration wizard and POS receipt always showed full amount as "paid" even for partial/deposit payments. Fixed to show actual paid_amount and due_amount from the invoice, with distinct badge for partial payment state. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Add 4 dashboard/financial features: compact renewals, retroactive wizard fix, club revenue, expense shortcuts - Compact overdue renewals alert into summary card with toggle detail list - Rewrite retroactive enrollment wizard to CREATE new participants (not search existing) - Add external revenue import form for club lump-sum payments - Add quick-action buttons to financial overview for expenses/revenue - Migration adds external_revenue to expenses category CHECK constraint Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-