- 19 Jul, 2026 1 commit
-
-
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 15 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>
-
Mahmoud Aglan authored
Add allow_proration (boolean) and renewal_day (number, 1-28) to the enrollment settings schema with descriptive hints so admins can find and toggle partial monthly payment from the UI. Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Add is_essential boolean to products (migration + model + form toggle) - Essential products appear as quick-add buttons in registration wizard step 5 (no search needed), highlighted when added to cart - New EssentialDeliveries page (/inventory/essential-deliveries): lists all players who bought essential products, mark استلم/لم يستلم per item with who delivered and when - Delivery tracking: add is_delivered, delivered_at, delivered_by to invoice_items; hotbuy cart items now store itemable_type/id for proper morph link - Admin price override now stored in invoice item metadata (original_price, overridden_price, override_reason) and displayed on invoice print with crossed-out original price - "أساسي" badge on product list; "تسليم الأساسيات" button on product list header and sidebar Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Payment modes: - Full (default): pays entire invoice amount - Partial: enter amount paid now, remainder stays as balance due on invoice - Split: two methods, amount1 + calculated remainder, both recorded as payments All 7 PaymentMethod values now available: - cash: no extra fields - card: transaction_reference (required) - bank_transfer: transaction_reference (required), bank_name (optional) - online (Instapay/digital wallets): transaction_reference (required) - wallet (club wallet): deducts from member balance - cheque: cheque_number (required), bank_name (optional) - other: notes field Each payment recorded with gateway_data JSON (ref, cheque_number, bank_name) Enrollment payment_status only set to 'paid' when full amount covered Validation rules built dynamically from active mode + method combination Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- EnrollmentSettingsSeeder: fix Organization → Academy class name - ReceiptTemplate: add defaultInvoiceFields/Settings + defaultPaymentFields/Settings - ReceiptSettings: rewritten with pos/invoice/payment tabs; each tab loads its own ReceiptTemplate (type='invoice'|'payment') and saves independently - receipt-settings.blade.php: 3-tab UI with field toggles + appearance settings per document type; link to branding page for logo/colors - print/invoice.blade.php: all 15 fields now gated by invoice template flags (logo, academy name, branch, tax number, client details, items table, subtotal, discount, tax, service fee, paid amount, payments history, signature, terms & conditions, footer text) - print/payment-receipt.blade.php: all 11 fields gated by payment template; footer text pulled from template settings instead of hardcoded string Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
CapRover volume remounts can override build-time chown, leaving storage/logs owned by root. Explicitly touch + chown the log file at container start before php-fpm runs. Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- AuthService: accepts email or phone for login (identifier-based lookup) - Login UI: updated to text input with Arabic labels - EgyptianNidDecoder: decodes 14-digit NID → birth date, gender, governorate - ProrationResult DTO + ProrationService: mid-month enrollment fee proration (x/30 of remaining days based on configurable renewal day) - EnrollmentSettingsSeeder: seeds enrollment.allow_proration and enrollment.renewal_day per academy - NewRegistrationWizard: rewritten — player-first flow, NID auto-decode locks birth/gender/governorate, foreign player toggle, guardian name deduced from player name, phone-only guardian, super admin price override, proration display - EnrollmentService: applies proration to invoice creation - EnrollExistingWizard: adds proratedProgramFee computed property, review step shows original vs prorated fee - Migration: adds governorate column to people table Co-Authored-By:Claude Sonnet 4.6 <noreply@anthropic.com>
-
- 11 Jul, 2026 6 commits
-
-
Mahmoud Aglan authored
Every entity list now has clickable rows that navigate to rich detail pages with KPIs, tabbed content, and related data. New show pages: - TrainerShow: groups, schedule, attendance, financial, qualifications - EmployeeShow: personal info, team hierarchy, documents, timeline - GroupShow: enrollments, schedule, sessions, attendance stats - ProgramShow: groups, enrollments, settings, requirements - FacilityShow: layouts, segments, reservations, schedule - ProductShow: stock levels, movements, analytics Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The old 'inventory.adjustments.wizard' route was removed — now just 'inventory.adjustments'. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The wizard was overengineered for this flow. Programs are created via the existing ProgramForm. Updated dashboard and program-list links. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
1. Stock Count fix: dispatch StockCountCompleted event after completing a count so the ProcessCountAdjustments listener creates inventory movements. Made listener synchronous for immediate feedback. 2. Stock Adjustment: route now points to the existing wizard component instead of the plain form. 3. Purchase Orders: new CreatePurchaseOrderWizard with 4-step flow (supplier → warehouse/dates → items → review & confirm). Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The PaymentMethod and PaymentStatus enums were passed directly to __() which expects a string, causing "Cannot access offset of type enum on array". Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Production had no trainers/employees and only 1 branch. Rewrote seeder to be fully self-contained: creates 2 new branches, 19 people, 11 employees, 12 trainers, then populates all HR tables. Cleans up prior data on re-run. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 10 Jul, 2026 10 commits
-
-
Mahmoud Aglan authored
Covers: 11 employees (6 staff + 4 trainer-employees + 1 resigned), all 12 trainers with bios/sports/qualifications/availability, 3 months of compensation history, 2 closed payroll periods with payslips, advances in all states, rate history. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- SKU is NOT NULL in the database but was nullable in wizard validation, causing a crash when submitted without a SKU value - Auto-generate SKU (PRD-0001, SRV-0001, DIG-0001) when not provided - Catch QueryException in both product forms to show friendly error instead of crashing on unique constraint violations Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- Add explicit $table = 'trainer_compensations' to TrainerCompensation model (Laravel resolved singular 'trainer_compensation' by default) - Wrap TrainerDuesWidget query in try/catch so dashboard loads even if the compensation migration hasn't been run yet Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
- InvoiceService::create() now auto-generates number if not provided - Invoice list/show views fall back to billable.person.name_ar when contact_name is null (matches print view behavior) - Fix participant link to use model route binding (uuid) not raw ID - CSV export no longer restricts to current month by default — exports all invoices matching the active filters (status, search) - CreateInvoiceWizard falls back to participantName for contact_name Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
InvoiceService::create() was not setting issue_date or due_date, causing a NOT NULL violation on the invoices table when the POS checkout flow creates an invoice without explicitly passing dates. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
-
Mahmoud Aglan authored
- Add cascading filters across all list pages (activity→program→group, program→trainer, direction→movement type) - Make sidebar sections collapsible with auto-expand on active page - Route all "Create" buttons to wizards instead of plain forms - Fix low stock count mismatch between dashboard and product list Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
-
Mahmoud Aglan authored
Instances no longer hold WhatsApp API credentials. They send messages via the el-captain-manager messaging hub API using MESSAGING_HUB_URL and MESSAGING_HUB_KEY env vars. The hub handles Meta Graph API calls, rate limiting, and delivery tracking centrally. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
Root cause: format_money() was used in 20+ views but never defined, causing silent fatal errors on every print attempt. Also simplified ReceiptController to render standalone HTML pages instead of depending on ReceiptTemplate records that may not exist in the DB. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
- 09 Jul, 2026 4 commits
-
-
Mahmoud Aglan authored
Cast config values to string with null-coalescing fallback, and add empty-string defaults to env() calls so instances without WhatsApp configured still boot without TypeError. Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-
Mahmoud Aglan authored
The demo_academy DB doesn't have organizations/users tables with those exact names. Use plain indexed columns instead. 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
- WhatsAppService: send text, template, image, document messages - Bulk send to groups/status/custom selections - Message log with status tracking (sent/delivered/read/failed) - Three Livewire pages: Send Message, Send Template, Message Log - Migration for whatsapp_messages table - Added 'whatsapp' channel to NotificationChannel enum - Wired into NotificationService for automated notifications - Sidebar section "واتساب" with 3 items - Config via WHATSAPP_PHONE_NUMBER_ID + WHATSAPP_ACCESS_TOKEN env vars Co-Authored-By:Claude Opus 4.6 <noreply@anthropic.com>
-