- 25 Jul, 2026 6 commits
-
-
Mahmoud Aglan authored
1. Low stock: use min_stock_level (not reorder_point), eager-load inventoryLevels 2. Inventory movements: reference is a morphTo — show class_basename#id instead of raw object 3. Product sales: pos_transaction_items has item_type/item_id (not product_id) 4. POS transactions: relationship is processedBy (not user), field is receipt_number 5. Collect payment wizard: only search participants with outstanding invoices Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
1. Session completion: column is 'session_date' not 'date' 2. Trainer workload: TrainingGroup has no assignments() — use TrainingSession.trainer_id via employee→user link, count groups via head_trainer_id 3. Wallet balances: Wallet uses polymorphic owner() not participant() — use owner with owner_type filter Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
1. Enrollments by program: replace PostgreSQL-incompatible HAVING on alias with get()->filter() 2. New report "المتغيبون حسب المدرب": shows absent participants grouped by trainer, with min-absences filter (1/2/3/5 sessions), excludes suspended participants 3. Also fixes existing absentee report to exclude suspended via the new report variant Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
1. Daily revenue: group by date only (removed method split per manager request) 2. Cash sessions: fix column names (cash_in→total_cash_in, cash_out→total_cash_out) and null-safe arithmetic to prevent string/int type error 3. Revenue by activity: fix column name (line_total→total_amount) and replace broken whereHasMorph with proper join for branch filter 4. Money formatting: cast to int before division to prevent type error on empty values Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
1. Status/gender/method columns now display Arabic labels instead of raw English values 2. Enrollment search (receptionist wizard) includes 'registered' participants, not just 'active' 3. New report: participants without medical clearance (بدون شهادة طبية) 4. Expired memberships report no longer crashes when date field is cleared (empty string fallback) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Add print_count and last_printed_at to invoices and payments tables - InvoicePrintController increments count on every print view - ReceiptController increments count on every payment receipt print - Print count badge shown next to print button on invoice show page - Print receipt button component accepts optional printCount prop - Rename dashboard revenue widget label from الإيرادات to التحصيلات Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 24 Jul, 2026 5 commits
-
-
Mahmoud Aglan authored
The guardians_relationship_type_check constraint allows: father, mother, grandfather, grandmother, uncle, aunt, sibling, legal_guardian, other. The ParticipantForm was inserting 'guardian' which isn't a valid value. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Remove draft-only restriction on delete button in EventShow - EventService::delete() no longer blocks deletion based on status - Migration sets website_settings.is_published default to true and updates existing rows - Fixes 404 on public event pages caused by unpublished website settings Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Add radio, national_id, location, section_divider, terms field types to FormFieldType enum - Add field uniqueness constraint (blocks duplicate registrations per unique field) - Add Google Maps locations support (JSONB column + map embed on public page) - Add conditional field visibility (show field only when another field equals a value) - Add min/max length, min/max value, regex pattern validation per field - Add allow_other option for select/radio/multi_select fields - Add field description/help text, placeholder, default value - Add duplicate field action in form builder - Add section dividers for visual grouping - Add terms acceptance field type with URL link - Sanitize form fields before save (auto-fill values, strip invalid options) - Public registration form uses Alpine.js for conditional visibility - Character counters shown when max_length is set Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- PublicEventController: pass $sections to views (navbar/footer crash without it) - Navbar: replace href="#" with href="#section-hero" (forbidden pattern) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Complete events module with admin CRUD, public registration, and management: - Migrations: events, event_registrations, media collections, permissions - Domain: Event/Enums (5), Models (2), Services (EventService, EventRegistrationService) - Admin: EventList, CreateEventWizard (4-step with form builder), EventShow, EventRegistrationList - Public: event listing + detail pages under /site/{slug}/events with Livewire registration form - Form builder: button-based add/remove/reorder fields stored as JSONB - Registration: dynamic validation from form_fields, person matching, registration numbers - Admin registrations: dynamic columns, bulk confirm/cancel, CSV export - Livewire scripts added to website layout for public forms Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 22 Jul, 2026 11 commits
-
-
Mahmoud Aglan authored
Salaried trainers now get asked for their monthly amount, which is stored on the employee record (salary_amount + salary_frequency='monthly'). 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
- ParticipantForm: add missing created_by when creating new guardian person - Fix 7 route references using .index instead of .list (trainers, employees, enrollments, groups) and other mismatches (inventory.levels.index, parent.excuse-form, pricing.rules.index) Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Users with 'refunds.initiate' permission see a "استرداد" button next to each confirmed inbound payment. Confirms before executing. 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
This was the root cause of repeated migration FK failures in production. 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
- New tables: facility_rent_payments, expenses with double-entry transactions - ExpenseService handles both rent and misc expenses with account resolution - Livewire CRUD: FacilityRentForm/List, ExpenseForm/List - Dashboard quick action buttons for recording expenses - Facility show page: new "Rent" tab with payment history - Sidebar nav links under Financial section - Reports: expense_summary and facility_rent_summary added to ReportsHub - New permission: expenses.create/list/view + seeded account 5050 Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Livewire's validate([]) falls back to looking for a $rules property on the component. Steps 6 and 7 intentionally have no validation rules, so only call validate() when the rules array is non-empty. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
1. Participant edit: guardian section now allows creating a new guardian (name + phone) OR selecting existing + editing phone. Checkbox toggles between modes. 2. Receptionist wizard: guardian name auto-fill now takes ALL names after the first (was only taking 2). "محمود أحمد عبد الفتاح علي" → guardian gets "أحمد عبد الفتاح علي" instead of just "أحمد عبد الفتاح". 3. Receptionist wizard step 5: added enrollment_start_date field so the user can specify when the player actually started (for accurate proration). Defaults to today if left empty. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Reports: 30 business reports in 6 categories (financial, participants, attendance, enrollments, operations, inventory) with CSV export. New ReportsHub grid page and generic ReportViewer with date/branch filters. Fixes: refund now creates double-entry transaction + deducts from cash session, branch switcher properly persists "all branches" selection, trainer wizard compensation step reactive, gender display on edit, participant edit supports national_id and guardian phone, participant list shows membership column + searches by national_id/membership_id. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 20 Jul, 2026 3 commits
-
-
Mahmoud Aglan authored
The grid was blank because lanes and zones segments have null row_index/col_index. The old code assumed all layouts were grid-type and collapsed to 0×0. - Grid layouts: keep the spreadsheet-style row/col selector view - Lanes layouts: render as horizontal strips (label + cell side by side) - Zones/custom layouts: responsive card grid (no row/col concept) Layout type is now read from Facility::activeLayout (new HasOne relationship) with a null-safe fallback to row_index detection. Segment cell HTML extracted to _segment-cell.blade.php partial to avoid triplication. Co-Authored-By:Claude Opus 4.8 <noreply@anthropic.com>
-
Mahmoud Aglan authored
/facilities/space-assignment and /facilities/schedule-builder were registered after /facilities/{facility}, so Laravel matched the wildcard first and tried to resolve the literal slugs as UUIDs, crashing with invalid uuid syntax. Static routes are now declared before the wildcard. Co-Authored-By:Claude Opus 4.8 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Adds محصّل vs إجمالي الإيرادات with a progress bar and remaining balance. Collection is computed as a pro-rata share of invoice.paid_amount based on the product line's fraction of the invoice total — so mixed invoices (product + program) correctly attribute only the product's share of each payment. Price overrides are excluded from the product's line because they always land on the program item, leaving the product total_amount intact. Co-Authored-By:Claude Opus 4.8 <noreply@anthropic.com>
-
- 19 Jul, 2026 3 commits
-
-
Mahmoud Aglan authored
Products with track_inventory=false never create InventoryMovements on sale, so the old movement-based queries always returned 0. Revenue and units sold now come from InvoiceItem (the authoritative source for what was actually invoiced). Stock-in (إجمالي الوارد) still uses InventoryMovement since that genuinely is a stock-receipt concept. Added إجمالي الإيرادات KPI card. Co-Authored-By:Claude Opus 4.8 <noreply@anthropic.com>
-
Mahmoud Aglan authored
ParticipantStatus is a backed enum — concatenating it directly throws. Use ->value to get the string value. Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The program invoice item was stored with unit_price = original programFee, then recalculateTotals() summed items and overwrote total_amount back to the original — so the printed invoice showed the pre-override amount. Fix: apply the override delta directly to the item's unit_price so the item row and invoice total are consistent. Metadata now stores original_price = programFee (per-item, not order total) for the strikethrough display on print. Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
- 17 Jul, 2026 4 commits
-
-
Mahmoud Aglan authored
Super admin and financial admin can select up to 2 confirmed payments from a participant's profile and refund them in a single atomic transaction. If a refunded payment is linked to a program enrollment, the enrollment is automatically cancelled and the group seat is freed. Changes: - RefundService: creates outbound refund record, marks original as refunded, reverses invoice paid_amount — all within the caller's DB::transaction - ParticipantShow: checkbox selection on confirmed inbound payments, preview modal showing impact (including enrollment cancellation warning), reason field, atomic commit via DB::transaction wrapping both domains Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Passing ?participant=uuid from the participant profile button now skips step 1 entirely — the wizard opens directly on step 2 (invoice selection) with the participant already selected. Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Adds a live summary panel above the invoices table showing total payments broken down by method for a configurable date range (default: this month). Includes two big comparison cards (selected method vs all others), a full horizontal mini-bar breakdown for every method, and preset range shortcuts. Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Super admins can now edit the payment method on any existing payment directly from the invoice detail page. The change is automatically captured in the audit log via the Auditable trait on the Payment model. Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
- 16 Jul, 2026 8 commits
-
-
Mahmoud Aglan authored
This file contained OC Sport-specific data and does not belong in the shared multi-tenant codebase. Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Imports Team (99) and Academy (93) players from HTML sheet one at a time using existing services (InvoiceService, PaymentService). Creates Person → Participant → Enrollment → Invoice → Payment per player, with installment plan attachment for partial القيد payments. Cross-sheet duplicates are written to storage/app/july_import_duplicates.json. Idempotent by name. Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Generated codes like TEAM2001-10 exceed 10 chars when there are 10+ duplicate program names within an academy. Widen to varchar(20). Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Migration: add installment_amounts JSONB (nullable) to product_installment_plans - ProductInstallmentPlan: new buildSchedule() method — uses explicit piaster amounts per slot where set, auto-calculates remainder evenly for blank slots; downPaymentAmount/regularInstallmentAmount respect slot[0] override - ProductForm: syncInstallmentSlots() keeps slot array in sync when count changes; plan rows load/save installment_amounts (stored as piasters, shown as pounds); slot inputs appear under collapsible "تحديد مبلغ كل قسط" toggle per plan row - Wizard confirm(): uses buildSchedule() so each Installment row gets its correct explicit or auto-calculated amount - Wizard blade breakdown preview: renders individual amounts when slots differ, uniform "N × amount" when all regular slots match Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- New migration: billing_cycle (one_time/annual), member_price, non_member_price on products; product_installment_plans table (per-product, per-tier plan templates) - ProductInstallmentPlan model with scopeActive/forTier, downPaymentAmount/regularInstallmentAmount helpers - Product model: priceForTier(), isAnnual(), installmentPlans() relationship - ProductForm: annual billing section with member/non-member dual prices and installment plan builder (add/remove rows, upsert on save) - Registration wizard: essentialProducts() and hotbuyResults() now return billing_cycle and plans[]; addHotbuyItem() carries plans into cart; setHotbuyPlan() selects a plan per cart item; confirm() generates PaymentPlan + Installment rows for annual items with a selected plan - Wizard blade: annual cart items show purple "سنوي" badge, plan pills (full payment + per-plan buttons), and installment breakdown preview on selection Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Two bugs: 1. save() wrote bare key "allow_proration" but ProrationService reads dotted "enrollment.allow_proration" — now always writes "{group}.{key}" 2. loadAllSettings() tried to read bare keys but DB had dotted keys from seeder — now strips group prefix on read so UI always sees bare keys Result: toggle saves correctly, ProrationService reads the live value, mid-month enrollment now shows prorated fee (e.g. day 16 = 15/30 × fee). Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
JSONB column has NOT NULL constraint — pass empty array instead of null when no price override metadata exists. Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Fields already existed on the guardians table (occupation, workplace) but had no UI. Now: - Registration wizard step 2 shows المهنة + جهة العمل fields (optional) - Saved to Guardian on create; updates existing guardian if already found - Pre-populated when selecting an existing guardian via search - Participant show → أولياء الأمور tab adds المهنة / جهة العمل column Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-