Commit 485ed365 authored by Mahmoud Aglan's avatar Mahmoud Aglan

lol

parents
APP_NAME="نادي الآركيد"
APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_TIMEZONE=Africa/Cairo
APP_URL=http://localhost
APP_LOCALE=ar
APP_FALLBACK_LOCALE=en
LOG_CHANNEL=stack
LOG_STACK=single
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=srv-captain--mysql-db
DB_PORT=3306
DB_DATABASE=club_management
DB_USERNAME=club_admin
DB_PASSWORD=Alarcade123#
SESSION_DRIVER=database
SESSION_LIFETIME=120
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=file
CACHE_PREFIX=club_
MAIL_MAILER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="noreply@club.local"
MAIL_FROM_NAME="${APP_NAME}"
# Club-specific
CLUB_NAME_AR="نادي الآركيد"
CLUB_NAME_EN="AL-ARCADE Club"
CLUB_CURRENCY=EGP
CLUB_CURRENCY_NAME_AR="جنيه"
CLUB_CURRENCY_SUBUNIT_AR="قرش"
CLUB_FISCAL_YEAR_START_MONTH=1
CLUB_FISCAL_YEAR_START_DAY=1
CLUB_DEFAULT_LANGUAGE=ar
CLUB_DATE_FORMAT=d/m/Y
CLUB_MAX_DEPENDENTS_PER_MEMBER=10
CLUB_MEMBER_PHOTO_MAX_KB=2048
CLUB_DOCUMENT_MAX_KB=5120
\ No newline at end of file
This diff is collapsed.
<?php
namespace App\Actions\Subscription;
use App\Models\SubscriptionPeriod;
use App\Services\Subscription\RenewalService;
class ApplyLateFeesAction
{
public function __construct(
protected RenewalService $renewalService,
) {}
/**
* Apply late fees to all overdue subscriptions in a period.
*/
public function execute(SubscriptionPeriod $period): array
{
return $this->renewalService->applyLateFees($period);
}
}
\ No newline at end of file
<?php
namespace App\Actions\Subscription;
use App\Models\SubscriptionPeriod;
use App\Services\Subscription\RenewalService;
class BulkRenewSubscriptions
{
public function __construct(
protected RenewalService $renewalService,
) {}
/**
* Generate subscriptions for all active members in a period.
*/
public function execute(SubscriptionPeriod $period): array
{
return $this->renewalService->bulkGenerate($period);
}
}
\ No newline at end of file
<?php
namespace App\Actions\Subscription;
use App\Models\Member;
use App\Models\SubscriptionPeriod;
use App\Services\Subscription\SubscriptionCalculatorService;
class CalculateSubscriptionFees
{
public function __construct(
protected SubscriptionCalculatorService $calculator,
) {}
/**
* Execute fee calculation and return structured result.
*/
public function execute(Member $member, SubscriptionPeriod $period, float $discount = 0): array
{
return $this->calculator->calculate($member, $period, $discount);
}
}
\ No newline at end of file
<?php
namespace App\Actions\Subscription;
use App\Models\Member;
use App\Models\Subscription;
use App\Models\SubscriptionPeriod;
use App\Services\Subscription\SubscriptionService;
class RenewMemberSubscription
{
public function __construct(
protected SubscriptionService $subscriptionService,
) {}
/**
* Create a subscription for a specific member and period.
*/
public function execute(
Member $member,
SubscriptionPeriod $period,
float $discountAmount = 0,
?string $discountReason = null,
?string $notes = null,
): Subscription {
return $this->subscriptionService->createSubscription(
member: $member,
period: $period,
discountAmount: $discountAmount,
discountReason: $discountReason,
notes: $notes,
);
}
}
\ No newline at end of file
<?php
namespace App\Casts;
use Carbon\Carbon;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
class ArabicDateCast implements CastsAttributes
{
public function get(Model $model, string $key, mixed $value, array $attributes): ?string
{
if ($value === null) {
return null;
}
return Carbon::parse($value)->format(config('club.date_format', 'd/m/Y'));
}
public function set(Model $model, string $key, mixed $value, array $attributes): ?string
{
if ($value === null) {
return null;
}
return Carbon::parse($value)->format('Y-m-d');
}
}
\ No newline at end of file
<?php
namespace App\Casts;
use Illuminate\Contracts\Database\Eloquent\CastsAttributes;
use Illuminate\Database\Eloquent\Model;
class MoneyCast implements CastsAttributes
{
public function get(Model $model, string $key, mixed $value, array $attributes): ?float
{
if ($value === null) {
return null;
}
return round((float) $value, 2);
}
public function set(Model $model, string $key, mixed $value, array $attributes): ?string
{
if ($value === null) {
return null;
}
return number_format((float) $value, 2, '.', '');
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Models\SubscriptionPeriod;
use App\Services\Subscription\RenewalService;
use Illuminate\Console\Command;
class ApplySubscriptionLateFees extends Command
{
protected $signature = 'subscriptions:apply-late-fees {--period= : Specific period ID}';
protected $description = 'Apply late fees to overdue subscriptions past grace period';
public function handle(RenewalService $renewalService): int
{
$periodId = $this->option('period');
$periods = $periodId
? SubscriptionPeriod::where('id', $periodId)->get()
: SubscriptionPeriod::active()->get();
if ($periods->isEmpty()) {
$this->warn('لا توجد فترات اشتراك نشطة.');
return self::SUCCESS;
}
foreach ($periods as $period) {
$this->info("Processing period: {$period->year} ({$period->name_ar})");
$results = $renewalService->applyLateFees($period);
$this->info(" Applied: {$results['applied']}");
$this->info(" Skipped: {$results['skipped']}");
if (count($results['errors']) > 0) {
$this->warn(" Errors: " . count($results['errors']));
foreach ($results['errors'] as $error) {
$this->error(" Member #{$error['member_id']}: {$error['error']}");
}
}
}
$this->info('Done.');
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Services\Cards\CardService;
use Illuminate\Console\Command;
class AutoExpireCards extends Command
{
protected $signature = 'cards:auto-expire';
protected $description = 'تلقائياً تحديث حالة الكروت منتهية الصلاحية';
public function handle(CardService $cardService): int
{
$count = $cardService->autoExpireCards();
$this->info("تم تحديث {$count} كارنيه منتهي الصلاحية.");
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Services\Documents\DocumentService;
use Illuminate\Console\Command;
class CheckExpiringDocuments extends Command
{
protected $signature = 'documents:check-expiring {--days=30 : عدد الأيام قبل الانتهاء}';
protected $description = 'فحص المستندات التي تقترب من تاريخ الانتهاء';
public function handle(DocumentService $documentService): int
{
$days = (int) $this->option('days');
$expiring = $documentService->getExpiringDocuments($days);
$expired = $documentService->getExpiredDocuments();
$this->info("مستندات تنتهي خلال {$days} يوم: {$expiring->count()}");
$this->info("مستندات منتهية: {$expired->count()}");
if ($expiring->count() > 0) {
$this->table(
['العضو', 'نوع المستند', 'تاريخ الانتهاء'],
$expiring->map(fn ($doc) => [
$doc->member?->full_name_ar ?? '-',
$doc->documentType?->name_ar ?? '-',
$doc->expiry_date,
])->toArray()
);
}
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Services\Admin\BackupService;
use Illuminate\Console\Command;
class CleanOldBackups extends Command
{
protected $signature = 'admin:clean-backups {--keep=10 : Number of backups to keep}';
protected $description = 'تنظيف النسخ الاحتياطية القديمة';
public function handle(BackupService $backupService): int
{
$keep = (int) $this->option('keep');
$this->info("الاحتفاظ بآخر {$keep} نسخة...");
$count = $backupService->cleanOldBackups($keep);
$this->info("تم حذف {$count} نسخة.");
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Services\Disciplinary\PenaltyService;
use Illuminate\Console\Command;
class CompletePenaltiesCommand extends Command
{
protected $signature = 'disciplinary:complete-penalties';
protected $description = 'Auto-complete penalties that have expired and have no outstanding fines';
public function handle(PenaltyService $service): int
{
$count = $service->autoCompleteExpiredPenalties();
$this->info("Completed {$count} penalty(ies).");
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Services\Admin\BackupService;
use Illuminate\Console\Command;
class CreateBackup extends Command
{
protected $signature = 'admin:backup {--type=full : Backup type (full/db)}';
protected $description = 'إنشاء نسخة احتياطية لقاعدة البيانات';
public function handle(BackupService $backupService): int
{
$type = $this->option('type');
$this->info("إنشاء نسخة احتياطية ({$type})...");
$result = $backupService->createBackup($type);
if ($result['success']) {
$this->info("تم بنجاح: {$result['filename']}");
return self::SUCCESS;
}
$this->error("فشل: {$result['error']}");
return self::FAILURE;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Services\Membership\MembershipWorkflowService;
use Illuminate\Console\Command;
class ExpireOverdueApplicationsCommand extends Command
{
protected $signature = 'members:expire-overdue';
protected $description = 'تنتهي صلاحية الطلبات التي تجاوزت مهلة 15 يوم بعد موافقة المجلس بدون سداد';
public function handle(MembershipWorkflowService $service): int
{
$this->info('جاري فحص الطلبات المتأخرة...');
$count = $service->expireOverdueApplications();
if ($count > 0) {
$this->warn("تم إنهاء {$count} طلب متأخر عن السداد");
} else {
$this->info('لا توجد طلبات متأخرة');
}
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
declare(strict_types=1);
namespace App\Console\Commands;
use App\Services\Disciplinary\SuspensionService;
use Illuminate\Console\Command;
class ExpireSuspensionsCommand extends Command
{
protected $signature = 'disciplinary:expire-suspensions';
protected $description = 'Auto-expire suspensions past their end date and restore member status';
public function handle(SuspensionService $service): int
{
$count = $service->autoExpireSuspensions();
$this->info("Expired {$count} suspension(s).");
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Services\Financial\SubscriptionService;
use Illuminate\Console\Command;
class GenerateAnnualSubscriptions extends Command
{
protected $signature = 'subscriptions:generate {year?}';
protected $description = 'Generate annual subscriptions for all active members';
public function handle(SubscriptionService $service): int
{
$year = (int) ($this->argument('year') ?? now()->year);
$this->info("Generating subscriptions for year {$year}...");
$result = $service->generateBulkSubscriptions($year);
$this->info("Generated: {$result['generated']} / Total eligible: {$result['total_members']}");
if (count($result['errors']) > 0) {
$this->warn("Errors: " . count($result['errors']));
foreach ($result['errors'] as $error) {
$this->error(" - Member {$error['membership_number']}: {$error['error']}");
}
}
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Models\SubscriptionPeriod;
use App\Services\Subscription\RenewalService;
use Illuminate\Console\Command;
class GenerateSubscriptions extends Command
{
protected $signature = 'subscriptions:generate {period? : Period ID to generate for}';
protected $description = 'Generate subscriptions for all active members in a period';
public function handle(RenewalService $renewalService): int
{
$periodId = $this->argument('period');
$period = $periodId
? SubscriptionPeriod::findOrFail($periodId)
: SubscriptionPeriod::active()->where('auto_generate', true)->first();
if (!$period) {
$this->warn('لا توجد فترة اشتراك نشطة مع الإنشاء التلقائي.');
return self::SUCCESS;
}
$this->info("Generating subscriptions for: {$period->year} ({$period->name_ar})");
$results = $renewalService->bulkGenerate($period);
$this->info("Created: {$results['created']}");
$this->info("Skipped (already exist): {$results['skipped']}");
if (count($results['errors']) > 0) {
$this->warn("Errors: " . count($results['errors']));
foreach ($results['errors'] as $error) {
$this->error(" Member #{$error['member_id']} ({$error['member_name']}): {$error['error']}");
}
}
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Services\Financial\InstallmentService;
use Illuminate\Console\Command;
class MarkOverdueInstallments extends Command
{
protected $signature = 'installments:mark-overdue';
protected $description = 'Mark installments that have passed their due date as overdue';
public function handle(InstallmentService $service): int
{
$count = $service->markOverdueInstallments();
$this->info("Marked {$count} installments as overdue.");
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Models\SubscriptionPeriod;
use App\Services\Subscription\RenewalService;
use Illuminate\Console\Command;
class MarkOverdueSubscriptions extends Command
{
protected $signature = 'subscriptions:mark-overdue';
protected $description = 'Mark pending subscriptions as overdue past grace period';
public function handle(RenewalService $renewalService): int
{
$periods = SubscriptionPeriod::active()->get();
foreach ($periods as $period) {
$count = $renewalService->markOverdue($period);
$this->info("Period {$period->year}: Marked {$count} subscriptions as overdue.");
}
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Enums\MembershipStatus;
use App\Models\Member;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
class MemberStatsCacheCommand extends Command
{
protected $signature = 'members:cache-stats';
protected $description = 'تحديث ذاكرة التخزين المؤقت لإحصائيات الأعضاء';
public function handle(): int
{
$stats = [
'total' => Member::count(),
'active' => Member::where('membership_status', MembershipStatus::ACTIVE)->count(),
'pending' => Member::where('membership_status', MembershipStatus::PENDING)->count(),
'suspended' => Member::where('membership_status', MembershipStatus::SUSPENDED)->count(),
'frozen' => Member::where('membership_status', MembershipStatus::FROZEN)->count(),
'cancelled' => Member::where('membership_status', MembershipStatus::CANCELLED)->count(),
'deceased' => Member::where('membership_status', MembershipStatus::DECEASED)->count(),
'by_stage' => Member::where('membership_status', MembershipStatus::PENDING)
->selectRaw('workflow_stage, COUNT(*) as count')
->groupBy('workflow_stage')
->pluck('count', 'workflow_stage')
->toArray(),
'new_this_month' => Member::whereMonth('created_at', now()->month)
->whereYear('created_at', now()->year)
->count(),
'activated_this_month' => Member::where('membership_status', MembershipStatus::ACTIVE)
->whereMonth('activation_date', now()->month)
->whereYear('activation_date', now()->year)
->count(),
];
Cache::put('member_stats', $stats, now()->addMinutes(30));
$this->info('تم تحديث إحصائيات الأعضاء');
$this->table(
['المؤشر', 'القيمة'],
collect($stats)->except('by_stage')->map(fn($v, $k) => [$k, $v])->values()->toArray()
);
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Services\Admin\AuditService;
use App\Services\Admin\SettingsService;
use Illuminate\Console\Command;
class PurgeAuditLogs extends Command
{
protected $signature = 'admin:purge-audit-logs {--days= : Number of days to retain}';
protected $description = 'تنظيف سجلات النشاط القديمة';
public function handle(AuditService $auditService, SettingsService $settingsService): int
{
$days = $this->option('days')
?? $settingsService->get('system.audit_retention_days', 1825);
$this->info("حذف سجلات أقدم من {$days} يوم...");
$count = $auditService->purgeOlderThan((int) $days);
$this->info("تم حذف {$count} سجل.");
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Services\Admin\SequenceService;
use Illuminate\Console\Command;
class ResetFiscalYearSequences extends Command
{
protected $signature = 'admin:reset-sequences {--force : Skip confirmation}';
protected $description = 'إعادة تعيين تسلسلات السنة المالية';
public function handle(SequenceService $sequenceService): int
{
if (!$this->option('force') && !$this->confirm('هل أنت متأكد من إعادة تعيين جميع تسلسلات السنة المالية؟')) {
$this->info('تم الإلغاء.');
return self::SUCCESS;
}
$count = $sequenceService->resetAllFiscalYearSequences();
$this->info("تم إعادة تعيين {$count} تسلسل.");
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
// Add to app/Console/Kernel.php or bootstrap/app.php schedule:
// $schedule->command('admin:backup')->dailyAt('02:00');
// $schedule->command('admin:clean-backups --keep=30')->weeklyOn(0, '03:00');
// $schedule->command('admin:purge-audit-logs')->monthlyOn(1, '04:00');
\ No newline at end of file
<?php
namespace App\Console\Commands;
use App\Enums\MembershipStatus;
use App\Models\Member;
use Filament\Notifications\Notification;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
class SendPaymentRemindersCommand extends Command
{
protected $signature = 'members:payment-reminders';
protected $description = 'إرسال تنبيهات السداد للأعضاء في المرحلة 7 (أيام 10، 13، 14، 15)';
public function handle(): int
{
$reminderDays = [10, 13, 14, 15];
$members = Member::where('workflow_stage', 7)
->where('membership_status', MembershipStatus::PENDING)
->whereNotNull('approval_date')
->get();
$sentCount = 0;
foreach ($members as $member) {
$daysSinceApproval = Carbon::parse($member->approval_date)->diffInDays(now());
if (in_array($daysSinceApproval, $reminderDays)) {
$remaining = 15 - $daysSinceApproval;
// Database notification for admins
$recipients = \App\Models\User::role(['super_admin', 'finance_manager', 'membership_manager'])->get();
Notification::make()
->title("⚠️ تنبيه سداد: {$member->full_name_ar}")
->body("متبقي {$remaining} يوم على انتهاء مهلة السداد — تاريخ الموافقة: {$member->approval_date->format('Y-m-d')}")
->warning()
->sendToDatabase($recipients);
activity()
->performedOn($member)
->withProperties([
'days_since_approval' => $daysSinceApproval,
'days_remaining' => $remaining,
])
->log("تنبيه سداد: متبقي {$remaining} يوم");
$sentCount++;
}
}
$this->info("تم إرسال {$sentCount} تنبيه سداد");
return self::SUCCESS;
}
}
\ No newline at end of file
<?php
namespace App\Console;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
protected function schedule(Schedule $schedule): void
{
// Mark overdue subscriptions daily at midnight
$schedule->command('subscriptions:mark-overdue')
->dailyAt('00:30')
->withoutOverlapping()
->appendOutputTo(storage_path('logs/overdue-subscriptions.log'));
// Mark overdue installments daily
$schedule->command('installments:mark-overdue')
->dailyAt('00:45')
->withoutOverlapping()
->appendOutputTo(storage_path('logs/overdue-installments.log'));
// Generate subscriptions for new year on Jan 1
$schedule->command('subscriptions:generate')
->yearlyOn(1, 1, '01:00')
->withoutOverlapping()
->appendOutputTo(storage_path('logs/annual-subscriptions.log'));
}
protected function commands(): void
{
$this->load(__DIR__ . '/Commands');
}
}
\ No newline at end of file
<?php
namespace App\DTOs;
class FeeCalculationResult
{
public function __construct(
public readonly float $baseAmount,
public readonly float $discountAmount,
public readonly float $lateFeeAmount,
public readonly float $totalAmount,
public readonly array $breakdown = [],
public readonly ?string $notes = null,
) {}
public static function simple(float $amount): static
{
return new static(
baseAmount: $amount,
discountAmount: 0,
lateFeeAmount: 0,
totalAmount: $amount,
);
}
}
\ No newline at end of file
<?php
namespace App\DTOs;
class MemberData
{
public function __construct(
public readonly string $full_name_ar,
public readonly string $phone_primary,
public readonly int $membership_type_id,
public readonly ?string $full_name_en = null,
public readonly ?string $national_id = null,
public readonly ?string $passport_number = null,
public readonly ?string $gender = null,
public readonly ?string $date_of_birth = null,
public readonly ?int $nationality_id = null,
public readonly ?int $religion_id = null,
public readonly ?int $marital_status_id = null,
public readonly ?int $birth_governorate_id = null,
public readonly ?string $job_title = null,
public readonly ?string $employer_name = null,
public readonly ?int $educational_qualification_id = null,
public readonly ?string $phone_secondary = null,
public readonly ?string $email = null,
public readonly ?int $address_governorate_id = null,
public readonly ?string $address_city = null,
public readonly ?string $address_street = null,
public readonly ?string $address_postal_code = null,
public readonly ?string $full_address_ar = null,
public readonly ?string $full_address_en = null,
public readonly ?string $application_form_number = null,
public readonly ?string $application_form_date = null,
public readonly ?int $sponsor_member_1_id = null,
public readonly ?int $sponsor_member_2_id = null,
public readonly ?string $referral_source = null,
public readonly ?string $notes = null,
) {}
public static function fromArray(array $data): static
{
return new static(...collect($data)->only([
'full_name_ar', 'phone_primary', 'membership_type_id',
'full_name_en', 'national_id', 'passport_number', 'gender',
'date_of_birth', 'nationality_id', 'religion_id', 'marital_status_id',
'birth_governorate_id', 'job_title', 'employer_name',
'educational_qualification_id', 'phone_secondary', 'email',
'address_governorate_id', 'address_city', 'address_street',
'address_postal_code', 'full_address_ar', 'full_address_en',
'application_form_number', 'application_form_date',
'sponsor_member_1_id', 'sponsor_member_2_id', 'referral_source', 'notes',
])->toArray());
}
public function toArray(): array
{
return array_filter(get_object_vars($this), fn ($v) => $v !== null);
}
}
\ No newline at end of file
<?php
namespace App\DTOs;
class ReceiptData
{
public function __construct(
public readonly int $member_id,
public readonly string $fee_category,
public readonly float $total_amount,
public readonly string $payment_method,
public readonly ?int $fiscal_year_id = null,
public readonly ?int $cash_register_id = null,
public readonly ?string $notes = null,
public readonly array $items = [],
public readonly ?float $discount_amount = null,
public readonly ?string $discount_reason = null,
) {}
public static function fromArray(array $data): static
{
return new static(
member_id: $data['member_id'],
fee_category: $data['fee_category'],
total_amount: (float) $data['total_amount'],
payment_method: $data['payment_method'],
fiscal_year_id: $data['fiscal_year_id'] ?? null,
cash_register_id: $data['cash_register_id'] ?? null,
notes: $data['notes'] ?? null,
items: $data['items'] ?? [],
discount_amount: isset($data['discount_amount']) ? (float) $data['discount_amount'] : null,
discount_reason: $data['discount_reason'] ?? null,
);
}
public function toArray(): array
{
return array_filter(get_object_vars($this), fn ($v) => $v !== null);
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum AuditAction: string
{
case Created = 'created';
case Updated = 'updated';
case Deleted = 'deleted';
case Restored = 'restored';
case Archived = 'archived';
case StatusChanged = 'status_changed';
case Login = 'login';
case Logout = 'logout';
case FailedLogin = 'failed_login';
case Exported = 'exported';
case Imported = 'imported';
case Printed = 'printed';
case Approved = 'approved';
case Rejected = 'rejected';
public function getLabel(): string
{
return match ($this) {
self::Created => 'إنشاء',
self::Updated => 'تعديل',
self::Deleted => 'حذف',
self::Restored => 'استرجاع',
self::Archived => 'أرشفة',
self::StatusChanged => 'تغيير حالة',
self::Login => 'تسجيل دخول',
self::Logout => 'تسجيل خروج',
self::FailedLogin => 'محاولة دخول فاشلة',
self::Exported => 'تصدير',
self::Imported => 'استيراد',
self::Printed => 'طباعة',
self::Approved => 'موافقة',
self::Rejected => 'رفض',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Created => 'Created',
self::Updated => 'Updated',
self::Deleted => 'Deleted',
self::Restored => 'Restored',
self::Archived => 'Archived',
self::StatusChanged => 'Status Changed',
self::Login => 'Login',
self::Logout => 'Logout',
self::FailedLogin => 'Failed Login',
self::Exported => 'Exported',
self::Imported => 'Imported',
self::Printed => 'Printed',
self::Approved => 'Approved',
self::Rejected => 'Rejected',
};
}
public function getColor(): string
{
return match ($this) {
self::Created => 'success',
self::Updated => 'info',
self::Deleted => 'danger',
self::Restored => 'success',
self::Archived => 'gray',
self::StatusChanged => 'warning',
self::Login => 'success',
self::Logout => 'gray',
self::FailedLogin => 'danger',
self::Exported => 'info',
self::Imported => 'info',
self::Printed => 'gray',
self::Approved => 'success',
self::Rejected => 'danger',
};
}
public function getIcon(): string
{
return match ($this) {
self::Created => 'heroicon-o-plus-circle',
self::Updated => 'heroicon-o-pencil',
self::Deleted => 'heroicon-o-trash',
self::Restored => 'heroicon-o-arrow-uturn-left',
self::Archived => 'heroicon-o-archive-box',
self::StatusChanged => 'heroicon-o-arrow-path',
self::Login => 'heroicon-o-arrow-right-on-rectangle',
self::Logout => 'heroicon-o-arrow-left-on-rectangle',
self::FailedLogin => 'heroicon-o-shield-exclamation',
self::Exported => 'heroicon-o-arrow-down-tray',
self::Imported => 'heroicon-o-arrow-up-tray',
self::Printed => 'heroicon-o-printer',
self::Approved => 'heroicon-o-check-circle',
self::Rejected => 'heroicon-o-x-circle',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum BoardDecisionResult: string
{
case Approved = 'approved';
case Rejected = 'rejected';
case Deferred = 'deferred';
case ConditionallyApproved = 'conditionally_approved';
case Tabled = 'tabled';
public function getLabel(): string
{
return match ($this) {
self::Approved => 'موافق',
self::Rejected => 'مرفوض',
self::Deferred => 'مؤجل',
self::ConditionallyApproved => 'موافق مشروط',
self::Tabled => 'مؤجل للدراسة',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Approved => 'Approved',
self::Rejected => 'Rejected',
self::Deferred => 'Deferred',
self::ConditionallyApproved => 'Conditionally Approved',
self::Tabled => 'Tabled',
};
}
public function getColor(): string
{
return match ($this) {
self::Approved => 'success',
self::Rejected => 'danger',
self::Deferred => 'warning',
self::ConditionallyApproved => 'info',
self::Tabled => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::Approved => 'heroicon-o-hand-thumb-up',
self::Rejected => 'heroicon-o-hand-thumb-down',
self::Deferred => 'heroicon-o-clock',
self::ConditionallyApproved => 'heroicon-o-question-mark-circle',
self::Tabled => 'heroicon-o-document-minus',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum BoardDecisionType: string
{
case MembershipApproval = 'membership_approval';
case MembershipRejection = 'membership_rejection';
case Suspension = 'suspension';
case Expulsion = 'expulsion';
case Reinstatement = 'reinstatement';
case Transfer = 'transfer';
case FeeAdjustment = 'fee_adjustment';
case PolicyChange = 'policy_change';
case PenaltyImposition = 'penalty_imposition';
case AppealDecision = 'appeal_decision';
case HonoraryMembership = 'honorary_membership';
case Other = 'other';
public function getLabel(): string
{
return match ($this) {
self::MembershipApproval => 'موافقة على عضوية',
self::MembershipRejection => 'رفض عضوية',
self::Suspension => 'إيقاف',
self::Expulsion => 'فصل',
self::Reinstatement => 'إعادة عضوية',
self::Transfer => 'نقل',
self::FeeAdjustment => 'تعديل رسوم',
self::PolicyChange => 'تغيير سياسة',
self::PenaltyImposition => 'فرض عقوبة',
self::AppealDecision => 'قرار استئناف',
self::HonoraryMembership => 'عضوية فخرية',
self::Other => 'أخرى',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::MembershipApproval => 'Membership Approval',
self::MembershipRejection => 'Membership Rejection',
self::Suspension => 'Suspension',
self::Expulsion => 'Expulsion',
self::Reinstatement => 'Reinstatement',
self::Transfer => 'Transfer',
self::FeeAdjustment => 'Fee Adjustment',
self::PolicyChange => 'Policy Change',
self::PenaltyImposition => 'Penalty Imposition',
self::AppealDecision => 'Appeal Decision',
self::HonoraryMembership => 'Honorary Membership',
self::Other => 'Other',
};
}
public function getColor(): string
{
return match ($this) {
self::MembershipApproval => 'success',
self::MembershipRejection => 'danger',
self::Suspension => 'warning',
self::Expulsion => 'danger',
self::Reinstatement => 'success',
self::Transfer => 'info',
self::FeeAdjustment => 'warning',
self::PolicyChange => 'info',
self::PenaltyImposition => 'danger',
self::AppealDecision => 'info',
self::HonoraryMembership => 'primary',
self::Other => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::MembershipApproval => 'heroicon-o-check-circle',
self::MembershipRejection => 'heroicon-o-x-circle',
self::Suspension => 'heroicon-o-pause-circle',
self::Expulsion => 'heroicon-o-x-mark',
self::Reinstatement => 'heroicon-o-arrow-uturn-left',
self::Transfer => 'heroicon-o-arrows-right-left',
self::FeeAdjustment => 'heroicon-o-currency-dollar',
self::PolicyChange => 'heroicon-o-document-text',
self::PenaltyImposition => 'heroicon-o-exclamation-circle',
self::AppealDecision => 'heroicon-o-scale',
self::HonoraryMembership => 'heroicon-o-star',
self::Other => 'heroicon-o-ellipsis-horizontal',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum BoardOfferStatus: string
{
case Draft = 'draft';
case Submitted = 'submitted';
case OnAgenda = 'on_agenda';
case Discussed = 'discussed';
case Decided = 'decided';
case Withdrawn = 'withdrawn';
public function getLabel(): string
{
return match ($this) {
self::Draft => 'مسودة',
self::Submitted => 'مقدم',
self::OnAgenda => 'على جدول الأعمال',
self::Discussed => 'تمت مناقشته',
self::Decided => 'تم البت فيه',
self::Withdrawn => 'مسحوب',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Draft => 'Draft',
self::Submitted => 'Submitted',
self::OnAgenda => 'On Agenda',
self::Discussed => 'Discussed',
self::Decided => 'Decided',
self::Withdrawn => 'Withdrawn',
};
}
public function getColor(): string
{
return match ($this) {
self::Draft => 'gray',
self::Submitted => 'info',
self::OnAgenda => 'warning',
self::Discussed => 'info',
self::Decided => 'success',
self::Withdrawn => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::Draft => 'heroicon-o-pencil-square',
self::Submitted => 'heroicon-o-paper-airplane',
self::OnAgenda => 'heroicon-o-clipboard-document-list',
self::Discussed => 'heroicon-o-chat-bubble-left-right',
self::Decided => 'heroicon-o-check-circle',
self::Withdrawn => 'heroicon-o-arrow-uturn-left',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum BookingStatus: string
{
case Pending = 'pending';
case Confirmed = 'confirmed';
case CheckedIn = 'checked_in';
case Completed = 'completed';
case Cancelled = 'cancelled';
case NoShow = 'no_show';
public function getLabel(): string
{
return match ($this) {
self::Pending => 'معلق',
self::Confirmed => 'مؤكد',
self::CheckedIn => 'تم الحضور',
self::Completed => 'مكتمل',
self::Cancelled => 'ملغي',
self::NoShow => 'لم يحضر',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Pending => 'Pending',
self::Confirmed => 'Confirmed',
self::CheckedIn => 'Checked In',
self::Completed => 'Completed',
self::Cancelled => 'Cancelled',
self::NoShow => 'No Show',
};
}
public function getColor(): string
{
return match ($this) {
self::Pending => 'warning',
self::Confirmed => 'info',
self::CheckedIn => 'success',
self::Completed => 'success',
self::Cancelled => 'gray',
self::NoShow => 'danger',
};
}
public function getIcon(): string
{
return match ($this) {
self::Pending => 'heroicon-o-clock',
self::Confirmed => 'heroicon-o-check',
self::CheckedIn => 'heroicon-o-check-circle',
self::Completed => 'heroicon-o-check-badge',
self::Cancelled => 'heroicon-o-x-circle',
self::NoShow => 'heroicon-o-user-minus',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum CardStatus: string
{
case Requested = 'requested';
case Printing = 'printing';
case Printed = 'printed';
case Issued = 'issued';
case Active = 'active';
case Expired = 'expired';
case Lost = 'lost';
case Damaged = 'damaged';
case Revoked = 'revoked';
case Replaced = 'replaced';
public function getLabel(): string
{
return match ($this) {
self::Requested => 'مطلوب',
self::Printing => 'قيد الطباعة',
self::Printed => 'مطبوع',
self::Issued => 'صادر',
self::Active => 'نشط',
self::Expired => 'منتهي',
self::Lost => 'مفقود',
self::Damaged => 'تالف',
self::Revoked => 'ملغي',
self::Replaced => 'مستبدل',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Requested => 'Requested',
self::Printing => 'Printing',
self::Printed => 'Printed',
self::Issued => 'Issued',
self::Active => 'Active',
self::Expired => 'Expired',
self::Lost => 'Lost',
self::Damaged => 'Damaged',
self::Revoked => 'Revoked',
self::Replaced => 'Replaced',
};
}
public function getColor(): string
{
return match ($this) {
self::Requested => 'info',
self::Printing => 'warning',
self::Printed => 'info',
self::Issued => 'success',
self::Active => 'success',
self::Expired => 'gray',
self::Lost => 'danger',
self::Damaged => 'danger',
self::Revoked => 'danger',
self::Replaced => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::Requested => 'heroicon-o-credit-card',
self::Printing => 'heroicon-o-printer',
self::Printed => 'heroicon-o-check',
self::Issued => 'heroicon-o-identification',
self::Active => 'heroicon-o-check-circle',
self::Expired => 'heroicon-o-clock',
self::Lost => 'heroicon-o-question-mark-circle',
self::Damaged => 'heroicon-o-exclamation-triangle',
self::Revoked => 'heroicon-o-x-circle',
self::Replaced => 'heroicon-o-arrow-path',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum CashRegisterStatus: string
{
case Open = 'open';
case Closed = 'closed';
case Suspended = 'suspended';
public function getLabel(): string
{
return match ($this) {
self::Open => 'مفتوح',
self::Closed => 'مغلق',
self::Suspended => 'معلق',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Open => 'Open',
self::Closed => 'Closed',
self::Suspended => 'Suspended',
};
}
public function getColor(): string
{
return match ($this) {
self::Open => 'success',
self::Closed => 'gray',
self::Suspended => 'warning',
};
}
public function getIcon(): string
{
return match ($this) {
self::Open => 'heroicon-o-lock-open',
self::Closed => 'heroicon-o-lock-closed',
self::Suspended => 'heroicon-o-pause-circle',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum DependentStatus: string
{
case Active = 'active';
case Inactive = 'inactive';
case Suspended = 'suspended';
case Removed = 'removed';
case AgedOut = 'aged_out';
case PendingApproval = 'pending_approval';
public function getLabel(): string
{
return match ($this) {
self::Active => 'نشط',
self::Inactive => 'غير نشط',
self::Suspended => 'موقوف',
self::Removed => 'محذوف',
self::AgedOut => 'تجاوز السن',
self::PendingApproval => 'بانتظار الموافقة',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Active => 'Active',
self::Inactive => 'Inactive',
self::Suspended => 'Suspended',
self::Removed => 'Removed',
self::AgedOut => 'Aged Out',
self::PendingApproval => 'Pending Approval',
};
}
public function getColor(): string
{
return match ($this) {
self::Active => 'success',
self::Inactive => 'gray',
self::Suspended => 'danger',
self::Removed => 'gray',
self::AgedOut => 'warning',
self::PendingApproval => 'info',
};
}
public function getIcon(): string
{
return match ($this) {
self::Active => 'heroicon-o-check-circle',
self::Inactive => 'heroicon-o-minus-circle',
self::Suspended => 'heroicon-o-pause-circle',
self::Removed => 'heroicon-o-x-circle',
self::AgedOut => 'heroicon-o-clock',
self::PendingApproval => 'heroicon-o-question-mark-circle',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum FeeCategory: string
{
case ApplicationForm = 'application_form';
case MembershipValue = 'membership_value';
case AnnualSubscription = 'annual_subscription';
case DependentFee = 'dependent_fee';
case CardIssuance = 'card_issuance';
case CardReplacement = 'card_replacement';
case TransferFee = 'transfer_fee';
case PenaltyFine = 'penalty_fine';
case ReinstatementFee = 'reinstatement_fee';
case FacilityBooking = 'facility_booking';
case LateFee = 'late_fee';
case Other = 'other';
public function getLabel(): string
{
return match ($this) {
self::ApplicationForm => 'استمارة تقديم',
self::MembershipValue => 'ثمن العضوية',
self::AnnualSubscription => 'اشتراك سنوي',
self::DependentFee => 'رسوم تابع',
self::CardIssuance => 'إصدار كارنيه',
self::CardReplacement => 'بدل فاقد كارنيه',
self::TransferFee => 'رسوم نقل',
self::PenaltyFine => 'غرامة',
self::ReinstatementFee => 'رسوم استعادة',
self::FacilityBooking => 'حجز مرفق',
self::LateFee => 'رسوم تأخير',
self::Other => 'أخرى',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::ApplicationForm => 'Application Form',
self::MembershipValue => 'Membership Value',
self::AnnualSubscription => 'Annual Subscription',
self::DependentFee => 'Dependent Fee',
self::CardIssuance => 'Card Issuance',
self::CardReplacement => 'Card Replacement',
self::TransferFee => 'Transfer Fee',
self::PenaltyFine => 'Penalty Fine',
self::ReinstatementFee => 'Reinstatement Fee',
self::FacilityBooking => 'Facility Booking',
self::LateFee => 'Late Fee',
self::Other => 'Other',
};
}
public function getColor(): string
{
return match ($this) {
self::ApplicationForm => 'info',
self::MembershipValue => 'primary',
self::AnnualSubscription => 'success',
self::DependentFee => 'info',
self::CardIssuance => 'warning',
self::CardReplacement => 'warning',
self::TransferFee => 'info',
self::PenaltyFine => 'danger',
self::ReinstatementFee => 'warning',
self::FacilityBooking => 'success',
self::LateFee => 'danger',
self::Other => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::ApplicationForm => 'heroicon-o-document-text',
self::MembershipValue => 'heroicon-o-banknotes',
self::AnnualSubscription => 'heroicon-o-calendar',
self::DependentFee => 'heroicon-o-user-plus',
self::CardIssuance => 'heroicon-o-identification',
self::CardReplacement => 'heroicon-o-arrow-path',
self::TransferFee => 'heroicon-o-arrows-right-left',
self::PenaltyFine => 'heroicon-o-exclamation-circle',
self::ReinstatementFee => 'heroicon-o-arrow-uturn-left',
self::FacilityBooking => 'heroicon-o-building-office',
self::LateFee => 'heroicon-o-clock',
self::Other => 'heroicon-o-ellipsis-horizontal',
};
}
public function getReceiptPrefix(): string
{
return match ($this) {
self::ApplicationForm => 'APP',
self::MembershipValue => 'MBV',
self::AnnualSubscription => 'SUB',
self::DependentFee => 'DEP',
self::CardIssuance => 'CRD',
self::CardReplacement => 'CRD',
self::TransferFee => 'TRN',
self::PenaltyFine => 'PEN',
self::ReinstatementFee => 'RST',
self::FacilityBooking => 'BKG',
self::LateFee => 'PEN',
self::Other => 'GEN',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum Gender: string
{
case Male = 'male';
case Female = 'female';
public function getLabel(): string
{
return match ($this) {
self::Male => 'ذكر',
self::Female => 'أنثى',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Male => 'Male',
self::Female => 'Female',
};
}
public function getColor(): string
{
return match ($this) {
self::Male => 'info',
self::Female => 'danger',
};
}
public function getIcon(): string
{
return match ($this) {
self::Male => 'heroicon-o-user',
self::Female => 'heroicon-o-user',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum GenderRestriction: string
{
case MaleOnly = 'male_only';
case FemaleOnly = 'female_only';
case Mixed = 'mixed';
public function getLabel(): string
{
return match ($this) {
self::MaleOnly => 'ذكور فقط',
self::FemaleOnly => 'إناث فقط',
self::Mixed => 'مختلط',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::MaleOnly => 'Male Only',
self::FemaleOnly => 'Female Only',
self::Mixed => 'Mixed',
};
}
public function getColor(): string
{
return match ($this) {
self::MaleOnly => 'info',
self::FemaleOnly => 'danger',
self::Mixed => 'success',
};
}
public function getIcon(): string
{
return match ($this) {
self::MaleOnly => 'heroicon-o-user-group',
self::FemaleOnly => 'heroicon-o-user-group',
self::Mixed => 'heroicon-o-users',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum InstallmentPlanStatus: string
{
case Active = 'active';
case Completed = 'completed';
case Defaulted = 'defaulted';
case Cancelled = 'cancelled';
case PendingApproval = 'pending_approval';
public function getLabel(): string
{
return match ($this) {
self::Active => 'نشطة',
self::Completed => 'مكتملة',
self::Defaulted => 'متعثرة',
self::Cancelled => 'ملغاة',
self::PendingApproval => 'بانتظار الموافقة',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Active => 'Active',
self::Completed => 'Completed',
self::Defaulted => 'Defaulted',
self::Cancelled => 'Cancelled',
self::PendingApproval => 'Pending Approval',
};
}
public function getColor(): string
{
return match ($this) {
self::Active => 'success',
self::Completed => 'info',
self::Defaulted => 'danger',
self::Cancelled => 'gray',
self::PendingApproval => 'warning',
};
}
public function getIcon(): string
{
return match ($this) {
self::Active => 'heroicon-o-play',
self::Completed => 'heroicon-o-check-circle',
self::Defaulted => 'heroicon-o-exclamation-circle',
self::Cancelled => 'heroicon-o-x-circle',
self::PendingApproval => 'heroicon-o-clock',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum InstallmentStatus: string
{
case Pending = 'pending';
case Paid = 'paid';
case Overdue = 'overdue';
case PartiallyPaid = 'partially_paid';
case Waived = 'waived';
case Cancelled = 'cancelled';
public function getLabel(): string
{
return match ($this) {
self::Pending => 'معلق',
self::Paid => 'مدفوع',
self::Overdue => 'متأخر',
self::PartiallyPaid => 'مدفوع جزئياً',
self::Waived => 'معفى',
self::Cancelled => 'ملغي',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Pending => 'Pending',
self::Paid => 'Paid',
self::Overdue => 'Overdue',
self::PartiallyPaid => 'Partially Paid',
self::Waived => 'Waived',
self::Cancelled => 'Cancelled',
};
}
public function getColor(): string
{
return match ($this) {
self::Pending => 'warning',
self::Paid => 'success',
self::Overdue => 'danger',
self::PartiallyPaid => 'info',
self::Waived => 'gray',
self::Cancelled => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::Pending => 'heroicon-o-clock',
self::Paid => 'heroicon-o-check-circle',
self::Overdue => 'heroicon-o-exclamation-circle',
self::PartiallyPaid => 'heroicon-o-minus-circle',
self::Waived => 'heroicon-o-hand-raised',
self::Cancelled => 'heroicon-o-x-circle',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum InterviewResult: string
{
case Passed = 'passed';
case Failed = 'failed';
case Pending = 'pending';
case ConditionalPass = 'conditional_pass';
public function getLabel(): string
{
return match ($this) {
self::Passed => 'ناجح',
self::Failed => 'غير ناجح',
self::Pending => 'معلق',
self::ConditionalPass => 'ناجح مشروط',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Passed => 'Passed',
self::Failed => 'Failed',
self::Pending => 'Pending',
self::ConditionalPass => 'Conditional Pass',
};
}
public function getColor(): string
{
return match ($this) {
self::Passed => 'success',
self::Failed => 'danger',
self::Pending => 'warning',
self::ConditionalPass => 'info',
};
}
public function getIcon(): string
{
return match ($this) {
self::Passed => 'heroicon-o-check-circle',
self::Failed => 'heroicon-o-x-circle',
self::Pending => 'heroicon-o-clock',
self::ConditionalPass => 'heroicon-o-question-mark-circle',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum InterviewStatus: string
{
case Scheduled = 'scheduled';
case InProgress = 'in_progress';
case Completed = 'completed';
case Cancelled = 'cancelled';
case NoShow = 'no_show';
case Rescheduled = 'rescheduled';
public function getLabel(): string
{
return match ($this) {
self::Scheduled => 'مجدولة',
self::InProgress => 'جارية',
self::Completed => 'مكتملة',
self::Cancelled => 'ملغاة',
self::NoShow => 'لم يحضر',
self::Rescheduled => 'أعيد جدولتها',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Scheduled => 'Scheduled',
self::InProgress => 'In Progress',
self::Completed => 'Completed',
self::Cancelled => 'Cancelled',
self::NoShow => 'No Show',
self::Rescheduled => 'Rescheduled',
};
}
public function getColor(): string
{
return match ($this) {
self::Scheduled => 'info',
self::InProgress => 'warning',
self::Completed => 'success',
self::Cancelled => 'gray',
self::NoShow => 'danger',
self::Rescheduled => 'warning',
};
}
public function getIcon(): string
{
return match ($this) {
self::Scheduled => 'heroicon-o-calendar',
self::InProgress => 'heroicon-o-chat-bubble-left-right',
self::Completed => 'heroicon-o-check-circle',
self::Cancelled => 'heroicon-o-x-circle',
self::NoShow => 'heroicon-o-user-minus',
self::Rescheduled => 'heroicon-o-arrow-path',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum MembershipStatus: string
{
case Applicant = 'applicant';
case PendingDocuments = 'pending_documents';
case PendingInterview = 'pending_interview';
case PendingBoardReview = 'pending_board_review';
case PendingPayment = 'pending_payment';
case Active = 'active';
case Suspended = 'suspended';
case Frozen = 'frozen';
case Expelled = 'expelled';
case Withdrawn = 'withdrawn';
case Deceased = 'deceased';
case Rejected = 'rejected';
case Lapsed = 'lapsed';
case TransferredOut = 'transferred_out';
case Honorary = 'honorary';
public function getLabel(): string
{
return match ($this) {
self::Applicant => 'مقدم طلب',
self::PendingDocuments => 'بانتظار المستندات',
self::PendingInterview => 'بانتظار المقابلة',
self::PendingBoardReview => 'بانتظار مراجعة المجلس',
self::PendingPayment => 'بانتظار السداد',
self::Active => 'نشط',
self::Suspended => 'موقوف',
self::Frozen => 'مجمد',
self::Expelled => 'مفصول',
self::Withdrawn => 'منسحب',
self::Deceased => 'متوفى',
self::Rejected => 'مرفوض',
self::Lapsed => 'منتهي',
self::TransferredOut => 'منقول',
self::Honorary => 'فخري',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Applicant => 'Applicant',
self::PendingDocuments => 'Pending Documents',
self::PendingInterview => 'Pending Interview',
self::PendingBoardReview => 'Pending Board Review',
self::PendingPayment => 'Pending Payment',
self::Active => 'Active',
self::Suspended => 'Suspended',
self::Frozen => 'Frozen',
self::Expelled => 'Expelled',
self::Withdrawn => 'Withdrawn',
self::Deceased => 'Deceased',
self::Rejected => 'Rejected',
self::Lapsed => 'Lapsed',
self::TransferredOut => 'Transferred Out',
self::Honorary => 'Honorary',
};
}
public function getColor(): string
{
return match ($this) {
self::Applicant => 'gray',
self::PendingDocuments => 'warning',
self::PendingInterview => 'warning',
self::PendingBoardReview => 'warning',
self::PendingPayment => 'warning',
self::Active => 'success',
self::Suspended => 'danger',
self::Frozen => 'info',
self::Expelled => 'danger',
self::Withdrawn => 'gray',
self::Deceased => 'gray',
self::Rejected => 'danger',
self::Lapsed => 'warning',
self::TransferredOut => 'info',
self::Honorary => 'primary',
};
}
public function getIcon(): string
{
return match ($this) {
self::Applicant => 'heroicon-o-document-plus',
self::PendingDocuments => 'heroicon-o-document',
self::PendingInterview => 'heroicon-o-chat-bubble-left-right',
self::PendingBoardReview => 'heroicon-o-clipboard-document-check',
self::PendingPayment => 'heroicon-o-banknotes',
self::Active => 'heroicon-o-check-circle',
self::Suspended => 'heroicon-o-pause-circle',
self::Frozen => 'heroicon-o-stop-circle',
self::Expelled => 'heroicon-o-x-circle',
self::Withdrawn => 'heroicon-o-arrow-right-on-rectangle',
self::Deceased => 'heroicon-o-heart',
self::Rejected => 'heroicon-o-x-mark',
self::Lapsed => 'heroicon-o-clock',
self::TransferredOut => 'heroicon-o-arrow-right',
self::Honorary => 'heroicon-o-star',
};
}
public function isActive(): bool
{
return $this === self::Active || $this === self::Honorary;
}
public function isPending(): bool
{
return in_array($this, [
self::Applicant,
self::PendingDocuments,
self::PendingInterview,
self::PendingBoardReview,
self::PendingPayment,
]);
}
public function isTerminal(): bool
{
return in_array($this, [
self::Expelled,
self::Withdrawn,
self::Deceased,
self::Rejected,
self::TransferredOut,
]);
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
public static function activeStatuses(): array
{
return [self::Active, self::Honorary];
}
public static function pendingStatuses(): array
{
return [
self::Applicant,
self::PendingDocuments,
self::PendingInterview,
self::PendingBoardReview,
self::PendingPayment,
];
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum MembershipType: string
{
case Working = 'working';
case Affiliate = 'affiliate';
case Honorary = 'honorary';
case Seasonal = 'seasonal';
case Temporary = 'temporary';
case SportingAssociate = 'sporting_associate';
public function getLabel(): string
{
return match ($this) {
self::Working => 'عضو عامل',
self::Affiliate => 'عضو منتسب',
self::Honorary => 'عضو فخري',
self::Seasonal => 'عضو موسمي',
self::Temporary => 'عضو مؤقت',
self::SportingAssociate => 'عضو رياضي',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Working => 'Working Member',
self::Affiliate => 'Affiliate Member',
self::Honorary => 'Honorary Member',
self::Seasonal => 'Seasonal Member',
self::Temporary => 'Temporary Member',
self::SportingAssociate => 'Sporting Associate',
};
}
public function getColor(): string
{
return match ($this) {
self::Working => 'primary',
self::Affiliate => 'info',
self::Honorary => 'warning',
self::Seasonal => 'success',
self::Temporary => 'gray',
self::SportingAssociate => 'danger',
};
}
public function getIcon(): string
{
return match ($this) {
self::Working => 'heroicon-o-briefcase',
self::Affiliate => 'heroicon-o-link',
self::Honorary => 'heroicon-o-star',
self::Seasonal => 'heroicon-o-sun',
self::Temporary => 'heroicon-o-clock',
self::SportingAssociate => 'heroicon-o-trophy',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum NotificationChannel: string
{
case Database = 'database';
case Email = 'email';
case Sms = 'sms';
case Push = 'push';
public function getLabel(): string
{
return match ($this) {
self::Database => 'إشعار نظام',
self::Email => 'بريد إلكتروني',
self::Sms => 'رسالة نصية',
self::Push => 'إشعار فوري',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Database => 'System Notification',
self::Email => 'Email',
self::Sms => 'SMS',
self::Push => 'Push Notification',
};
}
public function getColor(): string
{
return match ($this) {
self::Database => 'info',
self::Email => 'primary',
self::Sms => 'success',
self::Push => 'warning',
};
}
public function getIcon(): string
{
return match ($this) {
self::Database => 'heroicon-o-bell',
self::Email => 'heroicon-o-envelope',
self::Sms => 'heroicon-o-device-phone-mobile',
self::Push => 'heroicon-o-bell-alert',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum NotificationPriority: string
{
case Low = 'low';
case Normal = 'normal';
case High = 'high';
case Urgent = 'urgent';
public function getLabel(): string
{
return match ($this) {
self::Low => 'منخفضة',
self::Normal => 'عادية',
self::High => 'عالية',
self::Urgent => 'عاجلة',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Low => 'Low',
self::Normal => 'Normal',
self::High => 'High',
self::Urgent => 'Urgent',
};
}
public function getColor(): string
{
return match ($this) {
self::Low => 'gray',
self::Normal => 'info',
self::High => 'warning',
self::Urgent => 'danger',
};
}
public function getIcon(): string
{
return match ($this) {
self::Low => 'heroicon-o-arrow-down',
self::Normal => 'heroicon-o-minus',
self::High => 'heroicon-o-arrow-up',
self::Urgent => 'heroicon-o-exclamation-triangle',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum PaymentMethod: string
{
case CASH = 'cash';
case CHECK = 'check';
case BANK_TRANSFER = 'bank_transfer';
case CARD = 'card';
public function label(): string
{
return match ($this) {
self::CASH => 'نقدي',
self::CHECK => 'شيك',
self::BANK_TRANSFER => 'تحويل بنكي',
self::CARD => 'بطاقة',
};
}
public function labelEn(): string
{
return match ($this) {
self::CASH => 'Cash',
self::CHECK => 'Check',
self::BANK_TRANSFER => 'Bank Transfer',
self::CARD => 'Card',
};
}
public function icon(): string
{
return match ($this) {
self::CASH => 'heroicon-o-banknotes',
self::CHECK => 'heroicon-o-document-check',
self::BANK_TRANSFER => 'heroicon-o-building-library',
self::CARD => 'heroicon-o-credit-card',
};
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum PaymentStatus: string
{
case Pending = 'pending';
case Completed = 'completed';
case Failed = 'failed';
case Refunded = 'refunded';
case Cancelled = 'cancelled';
public function getLabel(): string
{
return match ($this) {
self::Pending => 'معلق',
self::Completed => 'مكتمل',
self::Failed => 'فشل',
self::Refunded => 'مسترد',
self::Cancelled => 'ملغي',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Pending => 'Pending',
self::Completed => 'Completed',
self::Failed => 'Failed',
self::Refunded => 'Refunded',
self::Cancelled => 'Cancelled',
};
}
public function getColor(): string
{
return match ($this) {
self::Pending => 'warning',
self::Completed => 'success',
self::Failed => 'danger',
self::Refunded => 'info',
self::Cancelled => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::Pending => 'heroicon-o-clock',
self::Completed => 'heroicon-o-check-circle',
self::Failed => 'heroicon-o-x-circle',
self::Refunded => 'heroicon-o-arrow-uturn-left',
self::Cancelled => 'heroicon-o-no-symbol',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum PenaltyStatus: string
{
case Imposed = 'imposed';
case Active = 'active';
case PendingPayment = 'pending_payment';
case Paid = 'paid';
case Served = 'served';
case Appealed = 'appealed';
case Overturned = 'overturned';
case Reduced = 'reduced';
case Cancelled = 'cancelled';
public function getLabel(): string
{
return match ($this) {
self::Imposed => 'مفروضة',
self::Active => 'نشطة',
self::PendingPayment => 'بانتظار السداد',
self::Paid => 'مدفوعة',
self::Served => 'تم التنفيذ',
self::Appealed => 'تم الاستئناف',
self::Overturned => 'ملغاة بحكم',
self::Reduced => 'مخففة',
self::Cancelled => 'ملغاة',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Imposed => 'Imposed',
self::Active => 'Active',
self::PendingPayment => 'Pending Payment',
self::Paid => 'Paid',
self::Served => 'Served',
self::Appealed => 'Appealed',
self::Overturned => 'Overturned',
self::Reduced => 'Reduced',
self::Cancelled => 'Cancelled',
};
}
public function getColor(): string
{
return match ($this) {
self::Imposed => 'danger',
self::Active => 'danger',
self::PendingPayment => 'warning',
self::Paid => 'success',
self::Served => 'success',
self::Appealed => 'info',
self::Overturned => 'gray',
self::Reduced => 'warning',
self::Cancelled => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::Imposed => 'heroicon-o-exclamation-circle',
self::Active => 'heroicon-o-fire',
self::PendingPayment => 'heroicon-o-banknotes',
self::Paid => 'heroicon-o-check-circle',
self::Served => 'heroicon-o-check-badge',
self::Appealed => 'heroicon-o-arrow-path',
self::Overturned => 'heroicon-o-arrow-uturn-left',
self::Reduced => 'heroicon-o-arrow-down',
self::Cancelled => 'heroicon-o-x-circle',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum ReceiptStatus: string
{
case Draft = 'draft';
case Issued = 'issued';
case Paid = 'paid';
case PartiallyPaid = 'partially_paid';
case Cancelled = 'cancelled';
case Refunded = 'refunded';
case Void = 'void';
public function getLabel(): string
{
return match ($this) {
self::Draft => 'مسودة',
self::Issued => 'صادر',
self::Paid => 'مدفوع',
self::PartiallyPaid => 'مدفوع جزئياً',
self::Cancelled => 'ملغي',
self::Refunded => 'مسترد',
self::Void => 'باطل',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Draft => 'Draft',
self::Issued => 'Issued',
self::Paid => 'Paid',
self::PartiallyPaid => 'Partially Paid',
self::Cancelled => 'Cancelled',
self::Refunded => 'Refunded',
self::Void => 'Void',
};
}
public function getColor(): string
{
return match ($this) {
self::Draft => 'gray',
self::Issued => 'info',
self::Paid => 'success',
self::PartiallyPaid => 'warning',
self::Cancelled => 'danger',
self::Refunded => 'warning',
self::Void => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::Draft => 'heroicon-o-pencil-square',
self::Issued => 'heroicon-o-document-text',
self::Paid => 'heroicon-o-check-circle',
self::PartiallyPaid => 'heroicon-o-clock',
self::Cancelled => 'heroicon-o-x-circle',
self::Refunded => 'heroicon-o-arrow-uturn-left',
self::Void => 'heroicon-o-no-symbol',
};
}
public function isFinal(): bool
{
return in_array($this, [self::Paid, self::Cancelled, self::Refunded, self::Void]);
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum SubscriptionStatus: string
{
case PENDING = 'pending';
case PARTIAL = 'partial';
case PAID = 'paid';
case OVERDUE = 'overdue';
case WAIVED = 'waived';
case CANCELLED = 'cancelled';
public function label(): string
{
return match ($this) {
self::PENDING => 'معلق',
self::PARTIAL => 'مدفوع جزئياً',
self::PAID => 'مدفوع',
self::OVERDUE => 'متأخر',
self::WAIVED => 'معفى',
self::CANCELLED => 'ملغى',
};
}
public function labelEn(): string
{
return match ($this) {
self::PENDING => 'Pending',
self::PARTIAL => 'Partial',
self::PAID => 'Paid',
self::OVERDUE => 'Overdue',
self::WAIVED => 'Waived',
self::CANCELLED => 'Cancelled',
};
}
public function color(): string
{
return match ($this) {
self::PENDING => 'warning',
self::PARTIAL => 'info',
self::PAID => 'success',
self::OVERDUE => 'danger',
self::WAIVED => 'gray',
self::CANCELLED => 'gray',
};
}
public function icon(): string
{
return match ($this) {
self::PENDING => 'heroicon-o-clock',
self::PARTIAL => 'heroicon-o-banknotes',
self::PAID => 'heroicon-o-check-circle',
self::OVERDUE => 'heroicon-o-exclamation-triangle',
self::WAIVED => 'heroicon-o-shield-check',
self::CANCELLED => 'heroicon-o-x-circle',
};
}
public function isPayable(): bool
{
return in_array($this, [self::PENDING, self::PARTIAL, self::OVERDUE]);
}
public function isTerminal(): bool
{
return in_array($this, [self::PAID, self::WAIVED, self::CANCELLED]);
}
public static function payableStatuses(): array
{
return [self::PENDING, self::PARTIAL, self::OVERDUE];
}
public static function unpaidStatuses(): array
{
return [self::PENDING, self::PARTIAL, self::OVERDUE];
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum SuspensionStatus: string
{
case Active = 'active';
case Lifted = 'lifted';
case Expired = 'expired';
case Extended = 'extended';
case ConvertedToExpulsion = 'converted_to_expulsion';
public function getLabel(): string
{
return match ($this) {
self::Active => 'ساري',
self::Lifted => 'تم رفعه',
self::Expired => 'منتهي',
self::Extended => 'ممدد',
self::ConvertedToExpulsion => 'تحول لفصل',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Active => 'Active',
self::Lifted => 'Lifted',
self::Expired => 'Expired',
self::Extended => 'Extended',
self::ConvertedToExpulsion => 'Converted to Expulsion',
};
}
public function getColor(): string
{
return match ($this) {
self::Active => 'danger',
self::Lifted => 'success',
self::Expired => 'gray',
self::Extended => 'warning',
self::ConvertedToExpulsion => 'danger',
};
}
public function getIcon(): string
{
return match ($this) {
self::Active => 'heroicon-o-pause-circle',
self::Lifted => 'heroicon-o-check-circle',
self::Expired => 'heroicon-o-clock',
self::Extended => 'heroicon-o-arrow-path',
self::ConvertedToExpulsion => 'heroicon-o-x-circle',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum TransferStatus: string
{
case Requested = 'requested';
case PendingApproval = 'pending_approval';
case PendingPayment = 'pending_payment';
case Approved = 'approved';
case Completed = 'completed';
case Rejected = 'rejected';
case Cancelled = 'cancelled';
public function getLabel(): string
{
return match ($this) {
self::Requested => 'مطلوب',
self::PendingApproval => 'بانتظار الموافقة',
self::PendingPayment => 'بانتظار السداد',
self::Approved => 'موافق عليه',
self::Completed => 'مكتمل',
self::Rejected => 'مرفوض',
self::Cancelled => 'ملغي',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Requested => 'Requested',
self::PendingApproval => 'Pending Approval',
self::PendingPayment => 'Pending Payment',
self::Approved => 'Approved',
self::Completed => 'Completed',
self::Rejected => 'Rejected',
self::Cancelled => 'Cancelled',
};
}
public function getColor(): string
{
return match ($this) {
self::Requested => 'info',
self::PendingApproval => 'warning',
self::PendingPayment => 'warning',
self::Approved => 'success',
self::Completed => 'success',
self::Rejected => 'danger',
self::Cancelled => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::Requested => 'heroicon-o-paper-airplane',
self::PendingApproval => 'heroicon-o-clock',
self::PendingPayment => 'heroicon-o-banknotes',
self::Approved => 'heroicon-o-check',
self::Completed => 'heroicon-o-check-circle',
self::Rejected => 'heroicon-o-x-circle',
self::Cancelled => 'heroicon-o-no-symbol',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum TransferType: string
{
case Upgrade = 'upgrade';
case Downgrade = 'downgrade';
case CategoryChange = 'category_change';
case BranchTransfer = 'branch_transfer';
public function getLabel(): string
{
return match ($this) {
self::Upgrade => 'ترقية',
self::Downgrade => 'تنزيل',
self::CategoryChange => 'تغيير فئة',
self::BranchTransfer => 'نقل فرع',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Upgrade => 'Upgrade',
self::Downgrade => 'Downgrade',
self::CategoryChange => 'Category Change',
self::BranchTransfer => 'Branch Transfer',
};
}
public function getColor(): string
{
return match ($this) {
self::Upgrade => 'success',
self::Downgrade => 'danger',
self::CategoryChange => 'info',
self::BranchTransfer => 'warning',
};
}
public function getIcon(): string
{
return match ($this) {
self::Upgrade => 'heroicon-o-arrow-up-circle',
self::Downgrade => 'heroicon-o-arrow-down-circle',
self::CategoryChange => 'heroicon-o-arrows-right-left',
self::BranchTransfer => 'heroicon-o-building-office',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum ViolationSeverity: string
{
case Minor = 'minor';
case Moderate = 'moderate';
case Major = 'major';
case Critical = 'critical';
public function getLabel(): string
{
return match ($this) {
self::Minor => 'بسيطة',
self::Moderate => 'متوسطة',
self::Major => 'جسيمة',
self::Critical => 'حرجة',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Minor => 'Minor',
self::Moderate => 'Moderate',
self::Major => 'Major',
self::Critical => 'Critical',
};
}
public function getColor(): string
{
return match ($this) {
self::Minor => 'info',
self::Moderate => 'warning',
self::Major => 'danger',
self::Critical => 'danger',
};
}
public function getIcon(): string
{
return match ($this) {
self::Minor => 'heroicon-o-information-circle',
self::Moderate => 'heroicon-o-exclamation-triangle',
self::Major => 'heroicon-o-exclamation-circle',
self::Critical => 'heroicon-o-fire',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum ViolationStatus: string
{
case Reported = 'reported';
case UnderInvestigation = 'under_investigation';
case PendingHearing = 'pending_hearing';
case PendingBoardDecision = 'pending_board_decision';
case Resolved = 'resolved';
case Dismissed = 'dismissed';
case Appealed = 'appealed';
case Closed = 'closed';
public function getLabel(): string
{
return match ($this) {
self::Reported => 'تم الإبلاغ',
self::UnderInvestigation => 'قيد التحقيق',
self::PendingHearing => 'بانتظار الجلسة',
self::PendingBoardDecision => 'بانتظار قرار المجلس',
self::Resolved => 'تم الحل',
self::Dismissed => 'مرفوض',
self::Appealed => 'تم الاستئناف',
self::Closed => 'مغلق',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Reported => 'Reported',
self::UnderInvestigation => 'Under Investigation',
self::PendingHearing => 'Pending Hearing',
self::PendingBoardDecision => 'Pending Board Decision',
self::Resolved => 'Resolved',
self::Dismissed => 'Dismissed',
self::Appealed => 'Appealed',
self::Closed => 'Closed',
};
}
public function getColor(): string
{
return match ($this) {
self::Reported => 'warning',
self::UnderInvestigation => 'info',
self::PendingHearing => 'warning',
self::PendingBoardDecision => 'warning',
self::Resolved => 'success',
self::Dismissed => 'gray',
self::Appealed => 'danger',
self::Closed => 'gray',
};
}
public function getIcon(): string
{
return match ($this) {
self::Reported => 'heroicon-o-flag',
self::UnderInvestigation => 'heroicon-o-magnifying-glass',
self::PendingHearing => 'heroicon-o-chat-bubble-bottom-center-text',
self::PendingBoardDecision => 'heroicon-o-clipboard-document-check',
self::Resolved => 'heroicon-o-check-circle',
self::Dismissed => 'heroicon-o-x-mark',
self::Appealed => 'heroicon-o-arrow-path',
self::Closed => 'heroicon-o-lock-closed',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Enums;
enum WorkflowProgressStatus: string
{
case Pending = 'pending';
case InProgress = 'in_progress';
case Completed = 'completed';
case Skipped = 'skipped';
case Failed = 'failed';
case Blocked = 'blocked';
public function getLabel(): string
{
return match ($this) {
self::Pending => 'معلق',
self::InProgress => 'قيد التنفيذ',
self::Completed => 'مكتمل',
self::Skipped => 'تم تخطيه',
self::Failed => 'فشل',
self::Blocked => 'محظور',
};
}
public function getLabelEn(): string
{
return match ($this) {
self::Pending => 'Pending',
self::InProgress => 'In Progress',
self::Completed => 'Completed',
self::Skipped => 'Skipped',
self::Failed => 'Failed',
self::Blocked => 'Blocked',
};
}
public function getColor(): string
{
return match ($this) {
self::Pending => 'gray',
self::InProgress => 'warning',
self::Completed => 'success',
self::Skipped => 'info',
self::Failed => 'danger',
self::Blocked => 'danger',
};
}
public function getIcon(): string
{
return match ($this) {
self::Pending => 'heroicon-o-clock',
self::InProgress => 'heroicon-o-arrow-path',
self::Completed => 'heroicon-o-check-circle',
self::Skipped => 'heroicon-o-forward',
self::Failed => 'heroicon-o-x-circle',
self::Blocked => 'heroicon-o-no-symbol',
};
}
public static function toFilamentOptions(): array
{
return collect(self::cases())
->mapWithKeys(fn (self $case) => [$case->value => $case->getLabel()])
->toArray();
}
}
\ No newline at end of file
<?php
namespace App\Exceptions;
use Exception;
class BusinessRuleException extends Exception
{
protected string $ruleKey;
public function __construct(string $message, string $ruleKey = '', int $code = 422, ?\Throwable $previous = null)
{
$this->ruleKey = $ruleKey;
parent::__construct($message, $code, $previous);
}
public function getRuleKey(): string
{
return $this->ruleKey;
}
}
\ No newline at end of file
<?php
declare(strict_types=1);
namespace App\Exceptions;
use RuntimeException;
final class DependentAgeRestrictionException extends RuntimeException
{
}
\ No newline at end of file
<?php
declare(strict_types=1);
namespace App\Exceptions;
use RuntimeException;
final class DependentLimitExceededException extends RuntimeException
{
}
\ No newline at end of file
<?php
declare(strict_types=1);
namespace App\Exceptions;
use RuntimeException;
final class DuplicateNationalIdException extends RuntimeException
{
}
\ No newline at end of file
<?php
namespace App\Exceptions;
class InsufficientBalanceException extends BusinessRuleException
{
public function __construct(string $message = 'رصيد غير كافي', ?\Throwable $previous = null)
{
parent::__construct($message, 'insufficient_balance', 422, $previous);
}
}
\ No newline at end of file
<?php
declare(strict_types=1);
namespace App\Exceptions;
use RuntimeException;
class InvalidStatusTransitionException extends RuntimeException
{
//
}
\ No newline at end of file
<?php
namespace App\Exceptions;
class MemberNotEligibleException extends BusinessRuleException
{
public function __construct(string $action = '', string $reason = '', ?\Throwable $previous = null)
{
$message = 'العضو غير مؤهل';
if ($action) {
$message .= " لـ {$action}";
}
if ($reason) {
$message .= ": {$reason}";
}
parent::__construct($message, 'member_not_eligible', 422, $previous);
}
}
\ No newline at end of file
<?php
namespace App\Exceptions;
class SequenceGenerationException extends BusinessRuleException
{
public function __construct(string $sequenceKey, ?\Throwable $previous = null)
{
parent::__construct(
"فشل في توليد رقم تسلسلي للمفتاح: {$sequenceKey}",
'sequence_generation_failed',
500,
$previous
);
}
}
\ No newline at end of file
<?php
namespace App\Exports;
use App\Services\Reporting\FinancialReportService;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithTitle;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
class FinancialExport implements FromQuery, WithHeadings, WithMapping, WithStyles, ShouldAutoSize, WithTitle
{
public function __construct(
protected array $filters = []
) {}
public function query()
{
$service = app(FinancialReportService::class);
return $service->getReceiptsQuery($this->filters);
}
public function headings(): array
{
return [
'رقم الإيصال',
'رقم العضوية',
'اسم العضو',
'تاريخ الإيصال',
'المبلغ الإجمالي',
'الخصم',
'الضريبة',
'صافي المبلغ',
'طريقة الدفع',
'حالة الإيصال',
'بواسطة',
'ملاحظات',
];
}
public function map($receipt): array
{
return [
$receipt->receipt_number,
$receipt->member?->membership_number ?? '',
$receipt->member?->full_name_ar ?? '',
$receipt->receipt_date?->format('d/m/Y') ?? '',
number_format($receipt->total_amount, 2),
number_format($receipt->discount_amount ?? 0, 2),
number_format($receipt->tax_amount ?? 0, 2),
number_format($receipt->net_amount ?? $receipt->total_amount, 2),
$receipt->payment_method ?? '',
$receipt->status?->getLabel() ?? '',
$receipt->createdByUser?->name ?? '',
$receipt->notes ?? '',
];
}
public function styles(Worksheet $sheet): array
{
return [
1 => [
'font' => ['bold' => true, 'color' => ['argb' => 'FFFFFFFF']],
'fill' => [
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
'startColor' => ['argb' => 'FF2E7D32'],
],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
],
];
}
public function title(): string
{
return 'التقرير المالي';
}
}
\ No newline at end of file
<?php
namespace App\Exports;
use App\Services\Reporting\MembershipReportService;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithTitle;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
class MembersExport implements FromQuery, WithHeadings, WithMapping, WithStyles, ShouldAutoSize, WithTitle
{
public function __construct(
protected array $filters = []
) {}
public function query()
{
$service = app(MembershipReportService::class);
return $service->getMembersQuery($this->filters);
}
public function headings(): array
{
return [
'رقم العضوية',
'الاسم بالعربية',
'الاسم بالإنجليزية',
'الرقم القومي',
'نوع العضوية',
'حالة العضوية',
'الجنس',
'تاريخ الميلاد',
'الهاتف',
'البريد الإلكتروني',
'تاريخ الانضمام',
'عدد التابعين',
];
}
public function map($member): array
{
return [
$member->membership_number,
$member->full_name_ar,
$member->full_name_en,
$member->national_id,
$member->membershipType?->name_ar ?? '',
$member->membership_status?->getLabel() ?? '',
$member->gender?->getLabel() ?? '',
$member->date_of_birth?->format('d/m/Y') ?? '',
$member->phone,
$member->email,
$member->join_date?->format('d/m/Y') ?? '',
$member->dependents_count ?? $member->dependents()->count(),
];
}
public function styles(Worksheet $sheet): array
{
return [
1 => [
'font' => ['bold' => true, 'size' => 12],
'fill' => [
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
'startColor' => ['argb' => 'FF4472C4'],
],
'font' => ['bold' => true, 'color' => ['argb' => 'FFFFFFFF']],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
],
];
}
public function title(): string
{
return 'تقرير العضويات';
}
}
\ No newline at end of file
<?php
namespace App\Exports;
use App\Services\Reporting\SubscriptionReportService;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithTitle;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
class SubscriptionsExport implements FromQuery, WithHeadings, WithMapping, WithStyles, ShouldAutoSize, WithTitle
{
public function __construct(
protected array $filters = []
) {}
public function query()
{
$service = app(SubscriptionReportService::class);
return $service->getSubscriptionsQuery($this->filters);
}
public function headings(): array
{
return [
'رقم العضوية',
'اسم العضو',
'خطة الاشتراك',
'تاريخ البداية',
'تاريخ النهاية',
'الحالة',
'المبلغ',
];
}
public function map($subscription): array
{
return [
$subscription->member?->membership_number ?? '',
$subscription->member?->full_name_ar ?? '',
$subscription->subscriptionPlan?->name_ar ?? '',
$subscription->start_date?->format('d/m/Y') ?? '',
$subscription->end_date?->format('d/m/Y') ?? '',
$subscription->status?->getLabel() ?? '',
number_format($subscription->amount ?? 0, 2),
];
}
public function styles(Worksheet $sheet): array
{
return [
1 => [
'font' => ['bold' => true, 'color' => ['argb' => 'FFFFFFFF']],
'fill' => [
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
'startColor' => ['argb' => 'FF1565C0'],
],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
],
];
}
public function title(): string
{
return 'تقرير الاشتراكات';
}
}
\ No newline at end of file
<?php
namespace App\Exports;
use App\Services\Reporting\ViolationReportService;
use Maatwebsite\Excel\Concerns\FromQuery;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithMapping;
use Maatwebsite\Excel\Concerns\WithStyles;
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
use Maatwebsite\Excel\Concerns\WithTitle;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
class ViolationsExport implements FromQuery, WithHeadings, WithMapping, WithStyles, ShouldAutoSize, WithTitle
{
public function __construct(
protected array $filters = []
) {}
public function query()
{
$service = app(ViolationReportService::class);
return $service->getViolationsQuery($this->filters);
}
public function headings(): array
{
return [
'#',
'رقم العضوية',
'اسم العضو',
'نوع المخالفة',
'الخطورة',
'الحالة',
'تاريخ المخالفة',
'المبلّغ',
'الوصف',
];
}
public function map($violation): array
{
return [
$violation->id,
$violation->member?->membership_number ?? '',
$violation->member?->full_name_ar ?? '',
$violation->violationType?->name_ar ?? '',
$violation->severity?->getLabel() ?? '',
$violation->status?->getLabel() ?? '',
$violation->violation_date?->format('d/m/Y') ?? '',
$violation->reportedByUser?->name ?? '',
$violation->description ?? '',
];
}
public function styles(Worksheet $sheet): array
{
return [
1 => [
'font' => ['bold' => true, 'color' => ['argb' => 'FFFFFFFF']],
'fill' => [
'fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
'startColor' => ['argb' => 'FFC62828'],
],
'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
],
];
}
public function title(): string
{
return 'تقرير المخالفات';
}
}
\ No newline at end of file
<?php
namespace App\Filament\Pages;
use App\Services\Admin\BackupService;
use Filament\Pages\Page;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Filament\Tables;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
class BackupManagement extends Page implements HasTable
{
use InteractsWithTable;
protected static ?string $navigationIcon = 'heroicon-o-server-stack';
protected static ?string $navigationGroup = 'إدارة النظام';
protected static ?string $navigationLabel = 'النسخ الاحتياطية';
protected static ?string $title = 'إدارة النسخ الاحتياطية';
protected static ?int $navigationSort = 7;
protected static string $view = 'filament.pages.backup-management';
public Collection $backups;
public function mount(): void
{
$this->refreshBackups();
}
public function refreshBackups(): void
{
$this->backups = app(BackupService::class)->listBackups();
}
protected function getHeaderActions(): array
{
return [
Action::make('createBackup')
->label('إنشاء نسخة احتياطية')
->icon('heroicon-o-plus-circle')
->color('primary')
->requiresConfirmation()
->modalHeading('إنشاء نسخة احتياطية جديدة')
->modalDescription('سيتم إنشاء نسخة احتياطية كاملة لقاعدة البيانات. قد تستغرق العملية بضع دقائق.')
->action(function () {
$result = app(BackupService::class)->createBackup();
if ($result['success']) {
Notification::make()
->title('تم إنشاء النسخة الاحتياطية بنجاح')
->body("الملف: {$result['filename']}")
->success()
->send();
} else {
Notification::make()
->title('فشل إنشاء النسخة الاحتياطية')
->body($result['error'] ?? 'خطأ غير معروف')
->danger()
->send();
}
$this->refreshBackups();
}),
Action::make('cleanOld')
->label('تنظيف القديمة')
->icon('heroicon-o-trash')
->color('danger')
->requiresConfirmation()
->modalHeading('تنظيف النسخ الاحتياطية القديمة')
->modalDescription('سيتم الاحتفاظ بآخر 10 نسخ وحذف الباقي.')
->action(function () {
$count = app(BackupService::class)->cleanOldBackups(10);
Notification::make()
->title("تم حذف {$count} نسخة احتياطية قديمة")
->success()
->send();
$this->refreshBackups();
}),
];
}
public function deleteBackup(string $filename): void
{
try {
app(BackupService::class)->deleteBackup($filename);
Notification::make()->title('تم حذف النسخة الاحتياطية')->success()->send();
} catch (\Throwable $e) {
Notification::make()->title($e->getMessage())->danger()->send();
}
$this->refreshBackups();
}
public function downloadBackup(string $filename)
{
try {
$path = app(BackupService::class)->downloadPath($filename);
return response()->download($path, $filename);
} catch (\Throwable $e) {
Notification::make()->title($e->getMessage())->danger()->send();
}
}
// HasTable is for future implementation if backups are stored in DB
// For now, we use a simple Livewire table in the blade view
public function table(Table $table): Table
{
// Placeholder — not used since backups are file-based
return $table->query(\App\Models\SystemSetting::query()->whereRaw('1=0'))
->columns([]);
}
}
\ No newline at end of file
<?php
namespace App\Filament\Pages;
use App\Enums\CardStatus;
use App\Models\MemberCard;
use App\Services\Cards\CardService;
use Filament\Actions;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Illuminate\Contracts\Support\Htmlable;
class CardPreview extends Page
{
protected static ?string $navigationIcon = 'heroicon-o-printer';
protected static ?string $navigationGroup = 'البطاقات والمستندات';
protected static ?int $navigationSort = 5;
protected static ?string $title = 'معاينة طباعة الكارنيه';
protected static ?string $navigationLabel = 'طباعة الكارنيه';
protected static ?string $slug = 'card-preview';
protected static string $view = 'filament.pages.card-preview';
protected static bool $shouldRegisterNavigation = true;
public ?int $cardId = null;
public ?array $cardData = null;
public ?array $eligibilityErrors = [];
public bool $isEligible = false;
public function mount(): void
{
$this->cardId = request()->query('card', null);
if ($this->cardId) {
$this->loadCardData();
}
}
public function loadCardData(): void
{
$card = MemberCard::with(['member.membershipType', 'member.status'])->find($this->cardId);
if (!$card) {
Notification::make()->title('الكارنيه غير موجود')->danger()->send();
return;
}
$cardService = app(CardService::class);
$this->cardData = $cardService->getCardPrintData($card);
// Check eligibility
$eligibility = $cardService->canPrintCard($card->member);
$this->isEligible = $eligibility['eligible'];
$this->eligibilityErrors = $eligibility['errors'];
}
public function printCard(): void
{
if (!$this->cardId) {
return;
}
$card = MemberCard::find($this->cardId);
if ($card && in_array($card->status, [CardStatus::ACTIVE->value])) {
app(CardService::class)->markAsPrinted($card);
Notification::make()->title('تم تسجيل الطباعة بنجاح')->success()->send();
$this->loadCardData();
}
}
public function getTitle(): string|Htmlable
{
return 'معاينة طباعة الكارنيه';
}
protected function getHeaderActions(): array
{
return [
Actions\Action::make('back_to_cards')
->label('العودة للكروت')
->icon('heroicon-o-arrow-right')
->url(route('filament.admin.resources.member-cards.index'))
->color('gray'),
];
}
}
\ No newline at end of file
<?php
namespace App\Filament\Pages;
use App\Filament\Widgets\MembershipGrowthChart;
use App\Filament\Widgets\MembershipStatusChart;
use App\Filament\Widgets\OverdueInstallmentsWidget;
use App\Filament\Widgets\PendingActionsWidget;
use App\Filament\Widgets\RecentMembersWidget;
use App\Filament\Widgets\RevenueByCategoryChart;
use App\Filament\Widgets\RevenueChart;
use App\Filament\Widgets\StatsOverviewWidget;
use App\Filament\Widgets\UpcomingExpirationsWidget;
use App\Filament\Widgets\ViolationsOverviewWidget;
use Filament\Pages\Dashboard as BaseDashboard;
class Dashboard extends BaseDashboard
{
protected static ?string $navigationIcon = 'heroicon-o-home';
protected static ?string $navigationGroup = 'الرئيسية';
protected static ?string $title = 'لوحة التحكم';
protected static ?int $navigationSort = 1;
public function getWidgets(): array
{
return [
StatsOverviewWidget::class,
MembershipGrowthChart::class,
RevenueChart::class,
MembershipStatusChart::class,
RevenueByCategoryChart::class,
PendingActionsWidget::class,
RecentMembersWidget::class,
UpcomingExpirationsWidget::class,
ViolationsOverviewWidget::class,
OverdueInstallmentsWidget::class,
];
}
public function getColumns(): int | string | array
{
return [
'default' => 1,
'sm' => 1,
'md' => 2,
'lg' => 2,
'xl' => 2,
];
}
}
\ No newline at end of file
<?php
namespace App\Filament\Pages;
use App\Models\Member;
use App\Models\MemberDocument;
use App\Services\Documents\DocumentService;
use Filament\Actions;
use Filament\Forms;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Forms\Form;
use Filament\Notifications\Notification;
use Filament\Pages\Page;
use Illuminate\Contracts\Support\Htmlable;
use Illuminate\Http\UploadedFile;
class DocumentChecklist extends Page implements HasForms
{
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-clipboard-document-list';
protected static ?string $navigationGroup = 'البطاقات والمستندات';
protected static ?int $navigationSort = 6;
protected static ?string $title = 'قائمة مراجعة المستندات';
protected static ?string $navigationLabel = 'قائمة المراجعة';
protected static ?string $slug = 'document-checklist';
protected static string $view = 'filament.pages.document-checklist';
public ?int $selectedMemberId = null;
public ?string $selectedStage = null;
public ?array $checklist = null;
public ?array $memberInfo = null;
public function mount(): void
{
$memberId = request()->query('member', null);
if ($memberId) {
$this->selectedMemberId = (int) $memberId;
$this->loadChecklist();
}
}
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Grid::make(3)
->schema([
Forms\Components\Select::make('selectedMemberId')
->label('اختر العضو')
->options(function () {
return Member::where('is_archived', false)
->limit(100)
->get()
->mapWithKeys(fn ($m) => [$m->id => "{$m->membership_number} - {$m->full_name_ar}"])
->toArray();
})
->searchable()
->live()
->afterStateUpdated(fn () => $this->loadChecklist()),
Forms\Components\Select::make('selectedStage')
->label('مرحلة العمل')
->options([
'' => 'تلقائي',
'application' => 'تقديم الطلب',
'review' => 'المراجعة',
'interview' => 'المقابلة',
'board_approval' => 'موافقة المجلس',
'payment' => 'الدفع',
'active' => 'العضوية النشطة',
'renewal' => 'التجديد',
'transfer' => 'النقل',
])
->live()
->afterStateUpdated(fn () => $this->loadChecklist()),
]),
]);
}
public function loadChecklist(): void
{
if (!$this->selectedMemberId) {
$this->checklist = null;
$this->memberInfo = null;
return;
}
$member = Member::with(['membershipType', 'status'])->find($this->selectedMemberId);
if (!$member) {
$this->checklist = null;
return;
}
$this->memberInfo = [
'id' => $member->id,
'name' => $member->full_name_ar,
'membership_number' => $member->membership_number,
'type' => $member->membershipType->name_ar ?? '',
'status' => $member->status->name_ar ?? '',
];
$documentService = app(DocumentService::class);
$stage = !empty($this->selectedStage) ? $this->selectedStage : null;
$this->checklist = $documentService->getDocumentChecklist($member, $stage);
}
public function verifyDocument(int $documentId): void
{
$document = MemberDocument::find($documentId);
if ($document) {
app(DocumentService::class)->verifyDocument($document);
Notification::make()->title('تم التحقق من المستند')->success()->send();
$this->loadChecklist();
}
}
public function getTitle(): string|Htmlable
{
return 'قائمة مراجعة المستندات';
}
protected function getHeaderActions(): array
{
return [
Actions\Action::make('back_to_documents')
->label('العودة للمستندات')
->icon('heroicon-o-arrow-right')
->url(route('filament.admin.resources.member-documents.index'))
->color('gray'),
];
}
}
\ No newline at end of file
<?php
namespace App\Filament\Pages\Reports;
use App\Services\Reporting\FinancialReportService;
use Filament\Pages\Page;
use Filament\Tables;
use Filament\Tables\Table;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Barryvdh\DomPDF\Facade\Pdf;
class AgingReport extends Page implements HasTable, HasForms
{
use InteractsWithTable;
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-clock';
protected static ?string $navigationGroup = 'التقارير';
protected static ?string $navigationLabel = 'تقرير أعمار الديون';
protected static ?string $title = 'تقرير أعمار الديون';
protected static ?int $navigationSort = 5;
protected static string $view = 'filament.pages.reports.aging-report';
public array $agingBrackets = [];
public function mount(): void
{
$service = app(FinancialReportService::class);
$this->agingBrackets = $service->getAgingReport();
}
public function table(Table $table): Table
{
$service = app(FinancialReportService::class);
return $table
->query($service->getOutstandingBalancesReport())
->columns([
Tables\Columns\TextColumn::make('receipt_number')
->label('رقم الإيصال')
->sortable()
->searchable()
->badge()
->color('primary'),
Tables\Columns\TextColumn::make('member.full_name_ar')
->label('العضو')
->searchable()
->limit(30),
Tables\Columns\TextColumn::make('member.membership_number')
->label('رقم العضوية')
->badge()
->color('gray'),
Tables\Columns\TextColumn::make('receipt_date')
->label('تاريخ الإيصال')
->date('d/m/Y')
->sortable(),
Tables\Columns\TextColumn::make('total_amount')
->label('المبلغ المستحق')
->money('EGP')
->sortable()
->color('danger')
->summarize(Tables\Columns\Summarizers\Sum::make()->money('EGP')->label('الإجمالي')),
Tables\Columns\TextColumn::make('days_outstanding')
->label('أيام التأخير')
->state(fn ($record) => now()->diffInDays($record->receipt_date))
->sortable(query: fn ($query, $direction) => $query->orderBy('receipt_date', $direction === 'asc' ? 'desc' : 'asc'))
->badge()
->color(fn ($state) => match (true) {
$state > 120 => 'danger',
$state > 90 => 'danger',
$state > 60 => 'warning',
$state > 30 => 'warning',
default => 'info',
}),
Tables\Columns\TextColumn::make('status')
->label('الحالة')
->badge()
->formatStateUsing(fn ($state) => $state?->getLabel())
->color(fn ($state) => $state?->getColor()),
])
->defaultSort('receipt_date', 'asc')
->striped()
->paginated([10, 25, 50, 100])
->defaultPaginationPageOption(25)
->headerActions([
Tables\Actions\Action::make('export_pdf')
->label('تصدير PDF')
->icon('heroicon-o-document-arrow-down')
->color('danger')
->action(fn () => $this->exportPdf()),
]);
}
public function exportPdf()
{
$service = app(FinancialReportService::class);
$receipts = $service->getOutstandingBalancesReport()->limit(500)->get();
$pdf = Pdf::loadView('reports.aging', [
'receipts' => $receipts,
'aging_brackets' => $this->agingBrackets,
'generated_at' => now(),
]);
$pdf->setPaper('A4', 'landscape');
return response()->streamDownload(
fn () => print($pdf->output()),
'aging_report_' . now()->format('Y-m-d_His') . '.pdf'
);
}
}
\ No newline at end of file
<?php
namespace App\Filament\Pages\Reports;
use App\Services\Reporting\MembershipReportService;
use Filament\Pages\Page;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Barryvdh\DomPDF\Facade\Pdf;
class ChurnReport extends Page implements HasForms
{
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-arrow-trending-down';
protected static ?string $navigationGroup = 'التقارير';
protected static ?string $navigationLabel = 'تقرير التسرب';
protected static ?string $title = 'تقرير تسرب الأعضاء';
protected static ?int $navigationSort = 8;
protected static string $view = 'filament.pages.reports.churn-report';
public array $churnData = [];
public int $months = 12;
public function mount(): void
{
$this->loadData();
}
public function loadData(): void
{
$service = app(MembershipReportService::class);
$this->churnData = $service->getChurnReport($this->months);
}
public function setMonths(int $months): void
{
$this->months = $months;
$this->loadData();
}
public function exportPdf()
{
$pdf = Pdf::loadView('reports.churn', [
'churn_data' => $this->churnData,
'months' => $this->months,
'generated_at' => now(),
]);
$pdf->setPaper('A4', 'landscape');
return response()->streamDownload(
fn () => print($pdf->output()),
'churn_report_' . now()->format('Y-m-d_His') . '.pdf'
);
}
}
\ No newline at end of file
<?php
namespace App\Filament\Pages\Reports;
use App\Enums\ReceiptStatus;
use App\Enums\PaymentStatus;
use App\Exports\FinancialExport;
use App\Services\Reporting\FinancialReportService;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Tables;
use Filament\Tables\Table;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Maatwebsite\Excel\Facades\Excel;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Carbon;
class FinancialReport extends Page implements HasTable, HasForms
{
use InteractsWithTable;
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-banknotes';
protected static ?string $navigationGroup = 'التقارير';
protected static ?string $navigationLabel = 'التقرير المالي';
protected static ?string $title = 'التقرير المالي';
protected static ?int $navigationSort = 2;
protected static string $view = 'filament.pages.reports.financial-report';
public ?array $filters = [];
public array $collectionSummary = [];
public array $revenueByCategory = [];
public array $revenueByPaymentMethod = [];
public array $agingReport = [];
public function mount(): void
{
$this->filters = [
'date_from' => Carbon::now()->startOfMonth()->format('Y-m-d'),
'date_to' => Carbon::now()->endOfMonth()->format('Y-m-d'),
];
$this->loadSummaryData();
}
protected function loadSummaryData(): void
{
$service = app(FinancialReportService::class);
$from = Carbon::parse($this->filters['date_from'] ?? Carbon::now()->startOfMonth());
$to = Carbon::parse($this->filters['date_to'] ?? Carbon::now()->endOfMonth());
$this->collectionSummary = $service->getCollectionSummary($from, $to);
$this->revenueByCategory = $service->getRevenueByCategory($from, $to);
$this->revenueByPaymentMethod = $service->getRevenueByPaymentMethod($from, $to);
$this->agingReport = $service->getAgingReport();
}
public function filtersForm(Form $form): Form
{
return $form
->schema([
Forms\Components\Grid::make(4)
->schema([
Forms\Components\Select::make('status')
->label('حالة الإيصال')
->options(ReceiptStatus::toFilamentOptions())
->placeholder('الكل'),
Forms\Components\Select::make('payment_method')
->label('طريقة الدفع')
->options([
'cash' => 'نقدي',
'card' => 'بطاقة',
'bank_transfer' => 'تحويل بنكي',
'cheque' => 'شيك',
])
->placeholder('الكل'),
Forms\Components\DatePicker::make('date_from')
->label('من تاريخ')
->native(false)
->displayFormat('d/m/Y')
->default(Carbon::now()->startOfMonth()),
Forms\Components\DatePicker::make('date_to')
->label('إلى تاريخ')
->native(false)
->displayFormat('d/m/Y')
->default(Carbon::now()->endOfMonth()),
Forms\Components\TextInput::make('amount_from')
->label('المبلغ من')
->numeric()
->prefix('ج.م'),
Forms\Components\TextInput::make('amount_to')
->label('المبلغ إلى')
->numeric()
->prefix('ج.م'),
]),
])
->statePath('filters');
}
public function table(Table $table): Table
{
$service = app(FinancialReportService::class);
return $table
->query($service->getReceiptsQuery($this->getFilterValues()))
->columns([
Tables\Columns\TextColumn::make('receipt_number')
->label('رقم الإيصال')
->sortable()
->searchable()
->badge()
->color('primary'),
Tables\Columns\TextColumn::make('member.full_name_ar')
->label('العضو')
->searchable()
->limit(30),
Tables\Columns\TextColumn::make('member.membership_number')
->label('رقم العضوية')
->sortable()
->badge()
->color('gray'),
Tables\Columns\TextColumn::make('receipt_date')
->label('التاريخ')
->date('d/m/Y')
->sortable(),
Tables\Columns\TextColumn::make('total_amount')
->label('المبلغ الإجمالي')
->money('EGP')
->sortable()
->summarize(Tables\Columns\Summarizers\Sum::make()->money('EGP')->label('الإجمالي')),
Tables\Columns\TextColumn::make('discount_amount')
->label('الخصم')
->money('EGP')
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('tax_amount')
->label('الضريبة')
->money('EGP')
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('payment_method')
->label('طريقة الدفع')
->badge()
->color('info'),
Tables\Columns\TextColumn::make('status')
->label('الحالة')
->badge()
->formatStateUsing(fn ($state) => $state?->getLabel())
->color(fn ($state) => $state?->getColor()),
Tables\Columns\TextColumn::make('createdByUser.name')
->label('بواسطة')
->toggleable(isToggledHiddenByDefault: true),
])
->defaultSort('receipt_date', 'desc')
->striped()
->paginated([10, 25, 50, 100])
->defaultPaginationPageOption(25)
->headerActions([
Tables\Actions\Action::make('export_excel')
->label('تصدير Excel')
->icon('heroicon-o-arrow-down-tray')
->color('success')
->action(fn () => $this->exportExcel()),
Tables\Actions\Action::make('export_pdf')
->label('تصدير PDF')
->icon('heroicon-o-document-arrow-down')
->color('danger')
->action(fn () => $this->exportPdf()),
]);
}
protected function getFilterValues(): array
{
return array_filter($this->filters ?? [], fn ($value) => $value !== null && $value !== '');
}
public function applyFilters(): void
{
$this->loadSummaryData();
$this->resetTable();
}
public function resetFilters(): void
{
$this->filters = [
'date_from' => Carbon::now()->startOfMonth()->format('Y-m-d'),
'date_to' => Carbon::now()->endOfMonth()->format('Y-m-d'),
];
$this->loadSummaryData();
$this->resetTable();
}
public function exportExcel()
{
return Excel::download(
new FinancialExport($this->getFilterValues()),
'financial_report_' . now()->format('Y-m-d_His') . '.xlsx'
);
}
public function exportPdf()
{
$service = app(FinancialReportService::class);
$receipts = $service->getReceiptsQuery($this->getFilterValues())->limit(500)->get();
$pdf = Pdf::loadView('reports.financial', [
'receipts' => $receipts,
'filters' => $this->getFilterValues(),
'collection_summary' => $this->collectionSummary,
'revenue_by_category' => $this->revenueByCategory,
'generated_at' => now(),
]);
$pdf->setPaper('A4', 'landscape');
return response()->streamDownload(
fn () => print($pdf->output()),
'financial_report_' . now()->format('Y-m-d_His') . '.pdf'
);
}
}
\ No newline at end of file
<?php
namespace App\Filament\Pages\Reports;
use App\Enums\InstallmentPlanStatus;
use App\Services\Reporting\FinancialReportService;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Tables;
use Filament\Tables\Table;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Barryvdh\DomPDF\Facade\Pdf;
class InstallmentReport extends Page implements HasTable, HasForms
{
use InteractsWithTable;
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-calculator';
protected static ?string $navigationGroup = 'التقارير';
protected static ?string $navigationLabel = 'تقرير الأقساط';
protected static ?string $title = 'تقرير الأقساط';
protected static ?int $navigationSort = 6;
protected static string $view = 'filament.pages.reports.installment-report';
public ?array $filters = [];
public function filtersForm(Form $form): Form
{
return $form
->schema([
Forms\Components\Grid::make(3)
->schema([
Forms\Components\Select::make('status')
->label('حالة خطة الأقساط')
->options(InstallmentPlanStatus::toFilamentOptions())
->placeholder('الكل'),
]),
])
->statePath('filters');
}
public function table(Table $table): Table
{
$service = app(FinancialReportService::class);
return $table
->query($service->getInstallmentReport($this->getFilterValues()))
->columns([
Tables\Columns\TextColumn::make('member.membership_number')
->label('رقم العضوية')
->sortable()
->searchable()
->badge()
->color('primary'),
Tables\Columns\TextColumn::make('member.full_name_ar')
->label('العضو')
->searchable()
->limit(30),
Tables\Columns\TextColumn::make('total_amount')
->label('المبلغ الإجمالي')
->money('EGP')
->sortable(),
Tables\Columns\TextColumn::make('number_of_installments')
->label('عدد الأقساط')
->sortable(),
Tables\Columns\TextColumn::make('paid_installments')
->label('المسدد')
->state(fn ($record) => $record->installments->where('status', 'paid')->count())
->badge()
->color('success'),
Tables\Columns\TextColumn::make('remaining_installments')
->label('المتبقي')
->state(fn ($record) => $record->installments->where('status', 'pending')->count())
->badge()
->color(fn ($state) => $state > 0 ? 'warning' : 'success'),
Tables\Columns\TextColumn::make('total_paid')
->label('المبلغ المسدد')
->state(fn ($record) => $record->installments->where('status', 'paid')->sum('amount'))
->money('EGP')
->color('success'),
Tables\Columns\TextColumn::make('total_remaining')
->label('المبلغ المتبقي')
->state(fn ($record) => $record->installments->where('status', 'pending')->sum('amount'))
->money('EGP')
->color('danger'),
Tables\Columns\TextColumn::make('status')
->label('الحالة')
->badge()
->formatStateUsing(fn ($state) => $state?->getLabel())
->color(fn ($state) => $state?->getColor()),
Tables\Columns\TextColumn::make('created_at')
->label('تاريخ الإنشاء')
->date('d/m/Y')
->sortable(),
])
->defaultSort('created_at', 'desc')
->striped()
->paginated([10, 25, 50, 100])
->defaultPaginationPageOption(25)
->headerActions([
Tables\Actions\Action::make('export_pdf')
->label('تصدير PDF')
->icon('heroicon-o-document-arrow-down')
->color('danger')
->action(fn () => $this->exportPdf()),
]);
}
protected function getFilterValues(): array
{
return array_filter($this->filters ?? [], fn ($value) => $value !== null && $value !== '');
}
public function applyFilters(): void
{
$this->resetTable();
}
public function resetFilters(): void
{
$this->filters = [];
$this->resetTable();
}
public function exportPdf()
{
$service = app(FinancialReportService::class);
$plans = $service->getInstallmentReport($this->getFilterValues())->limit(500)->get();
$pdf = Pdf::loadView('reports.installments', [
'plans' => $plans,
'generated_at' => now(),
]);
$pdf->setPaper('A4', 'landscape');
return response()->streamDownload(
fn () => print($pdf->output()),
'installment_report_' . now()->format('Y-m-d_His') . '.pdf'
);
}
}
\ No newline at end of file
<?php
namespace App\Filament\Pages\Reports;
use App\Enums\Gender;
use App\Enums\MembershipStatus;
use App\Exports\MembersExport;
use App\Models\MembershipType;
use App\Services\Reporting\MembershipReportService;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Tables;
use Filament\Tables\Table;
use Filament\Tables\Concerns\InteractsWithTable;
use Filament\Tables\Contracts\HasTable;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Filament\Actions\Action;
use Filament\Notifications\Notification;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Facades\Excel;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Carbon;
class MembershipReport extends Page implements HasTable, HasForms
{
use InteractsWithTable;
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-user-group';
protected static ?string $navigationGroup = 'التقارير';
protected static ?string $navigationLabel = 'تقرير العضويات';
protected static ?string $title = 'تقرير العضويات';
protected static ?int $navigationSort = 1;
protected static string $view = 'filament.pages.reports.membership-report';
public ?array $filters = [];
public ?string $membership_status = null;
public ?string $membership_type_id = null;
public ?string $gender = null;
public ?string $join_date_from = null;
public ?string $join_date_to = null;
public ?string $name = null;
public ?string $has_dependents = null;
public array $summaryByType = [];
public array $ageDistribution = [];
public array $genderDistribution = [];
public function mount(): void
{
$this->loadSummaryData();
}
protected function loadSummaryData(): void
{
$service = app(MembershipReportService::class);
$this->summaryByType = $service->getMembershipSummaryByType();
$this->ageDistribution = $service->getAgeDistribution();
$this->genderDistribution = $service->getGenderDistribution();
}
public function filtersForm(Form $form): Form
{
return $form
->schema([
Forms\Components\Grid::make(4)
->schema([
Forms\Components\Select::make('membership_status')
->label('حالة العضوية')
->options(MembershipStatus::toFilamentOptions())
->placeholder('الكل'),
Forms\Components\Select::make('membership_type_id')
->label('نوع العضوية')
->options(MembershipType::pluck('name_ar', 'id'))
->placeholder('الكل'),
Forms\Components\Select::make('gender')
->label('الجنس')
->options(Gender::toFilamentOptions())
->placeholder('الكل'),
Forms\Components\Select::make('has_dependents')
->label('التابعين')
->options([
'yes' => 'لديه تابعين',
'no' => 'بدون تابعين',
])
->placeholder('الكل'),
Forms\Components\DatePicker::make('join_date_from')
->label('تاريخ الانضمام من')
->native(false)
->displayFormat('d/m/Y'),
Forms\Components\DatePicker::make('join_date_to')
->label('تاريخ الانضمام إلى')
->native(false)
->displayFormat('d/m/Y'),
Forms\Components\TextInput::make('name')
->label('اسم العضو')
->placeholder('بحث بالاسم...'),
]),
])
->statePath('filters');
}
public function table(Table $table): Table
{
$service = app(MembershipReportService::class);
return $table
->query($service->getMembersQuery($this->getFilterValues()))
->columns([
Tables\Columns\TextColumn::make('membership_number')
->label('رقم العضوية')
->sortable()
->searchable()
->badge()
->color('primary'),
Tables\Columns\TextColumn::make('full_name_ar')
->label('الاسم بالعربية')
->sortable()
->searchable()
->limit(35),
Tables\Columns\TextColumn::make('full_name_en')
->label('الاسم بالإنجليزية')
->sortable()
->searchable()
->limit(35)
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('national_id')
->label('الرقم القومي')
->searchable()
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('membershipType.name_ar')
->label('نوع العضوية')
->badge()
->color('info'),
Tables\Columns\TextColumn::make('membership_status')
->label('الحالة')
->badge()
->formatStateUsing(fn ($state) => $state?->getLabel())
->color(fn ($state) => $state?->getColor()),
Tables\Columns\TextColumn::make('gender')
->label('الجنس')
->formatStateUsing(fn ($state) => $state?->getLabel())
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('date_of_birth')
->label('تاريخ الميلاد')
->date('d/m/Y')
->toggleable(isToggledHiddenByDefault: true),
Tables\Columns\TextColumn::make('phone')
->label('الهاتف')
->searchable(),
Tables\Columns\TextColumn::make('join_date')
->label('تاريخ الانضمام')
->date('d/m/Y')
->sortable(),
Tables\Columns\TextColumn::make('dependents_count')
->label('التابعين')
->counts('dependents')
->badge()
->color('gray'),
])
->defaultSort('membership_number')
->striped()
->paginated([10, 25, 50, 100])
->defaultPaginationPageOption(25)
->headerActions([
Tables\Actions\Action::make('export_excel')
->label('تصدير Excel')
->icon('heroicon-o-arrow-down-tray')
->color('success')
->action(fn () => $this->exportExcel()),
Tables\Actions\Action::make('export_pdf')
->label('تصدير PDF')
->icon('heroicon-o-document-arrow-down')
->color('danger')
->action(fn () => $this->exportPdf()),
]);
}
protected function getFilterValues(): array
{
return array_filter($this->filters ?? [], fn ($value) => $value !== null && $value !== '');
}
public function applyFilters(): void
{
$this->resetTable();
}
public function resetFilters(): void
{
$this->filters = [];
$this->resetTable();
}
public function exportExcel()
{
$filters = $this->getFilterValues();
return Excel::download(
new MembersExport($filters),
'membership_report_' . now()->format('Y-m-d_His') . '.xlsx'
);
}
public function exportPdf()
{
$service = app(MembershipReportService::class);
$members = $service->getMembersQuery($this->getFilterValues())->limit(500)->get();
$pdf = Pdf::loadView('reports.membership', [
'members' => $members,
'filters' => $this->getFilterValues(),
'generated_at' => now(),
'summary_by_type' => $this->summaryByType,
]);
$pdf->setPaper('A4', 'landscape');
$pdf->setOption('defaultFont', 'Arial');
return response()->streamDownload(
fn () => print($pdf->output()),
'membership_report_' . now()->format('Y-m-d_His') . '.pdf'
);
}
}
\ No newline at end of file
This diff is collapsed.
<?php
namespace App\Filament\Pages\Reports;
use App\Services\Reporting\FinancialReportService;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Pages\Page;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Support\Carbon;
class TopPayingMembersReport extends Page implements HasForms
{
use InteractsWithForms;
protected static ?string $navigationIcon = 'heroicon-o-trophy';
protected static ?string $navigationGroup = 'التقارير';
protected static ?string $navigationLabel = 'أعلى الأعضاء سداداً';
protected static ?string $title = 'أعلى الأعضاء سداداً';
protected static ?int $navigationSort = 7;
protected static string $view = 'filament.pages.reports.top-paying-members';
public ?string $date_from = null;
public ?string $date_to = null;
public int $limit = 20;
public array $topMembers = [];
public function mount(): void
{
$this->date_from = Carbon::now()->startOfYear()->format('Y-m-d');
$this->date_to = Carbon::now()->endOfYear()->format('Y-m-d');
$this->loadData();
}
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Grid::make(3)
->schema([
Forms\Components\DatePicker::make('date_from')
->label('من تاريخ')
->native(false)
->displayFormat('d/m/Y')
->required(),
Forms\Components\DatePicker::make('date_to')
->label('إلى تاريخ')
->native(false)
->displayFormat('d/m/Y')
->required(),
Forms\Components\TextInput::make('limit')
->label('عدد النتائج')
->numeric()
->default(20)
->minValue(5)
->maxValue(100),
]),
]);
}
public function loadData(): void
{
$service = app(FinancialReportService::class);
$from = Carbon::parse($this->date_from);
$to = Carbon::parse($this->date_to);
$this->topMembers = $service->getTopPayingMembers($from, $to, $this->limit);
}
public function applyFilters(): void
{
$this->loadData();
}
public function exportPdf()
{
$pdf = Pdf::loadView('reports.top-paying-members', [
'members' => $this->topMembers,
'date_from' => $this->date_from,
'date_to' => $this->date_to,
'generated_at' => now(),
]);
$pdf->setPaper('A4', 'portrait');
return response()->streamDownload(
fn () => print($pdf->output()),
'top_paying_members_' . now()->format('Y-m-d_His') . '.pdf'
);
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?php
namespace App\Filament\Resources\ActivityLogResource\Pages;
use App\Filament\Resources\ActivityLogResource;
use App\Services\Admin\AuditService;
use Filament\Actions;
use Filament\Resources\Pages\ListRecords;
use Filament\Notifications\Notification;
class ListActivityLogs extends ListRecords
{
protected static string $resource = ActivityLogResource::class;
protected function getHeaderActions(): array
{
return [
Actions\Action::make('purge')
->label('تنظيف السجلات القديمة')
->icon('heroicon-o-trash')
->color('danger')
->requiresConfirmation()
->modalHeading('تنظيف السجلات القديمة')
->form([
\Filament\Forms\Components\TextInput::make('days')
->label('حذف السجلات الأقدم من (أيام)')
->numeric()
->default(365)
->required()
->minValue(30),
])
->action(function (array $data) {
$count = app(AuditService::class)->purgeOlderThan($data['days']);
Notification::make()->title("تم حذف {$count} سجل")->success()->send();
}),
];
}
}
\ No newline at end of file
<?php
namespace App\Filament\Resources\ActivityLogResource\Pages;
use App\Filament\Resources\ActivityLogResource;
use Filament\Resources\Pages\ViewRecord;
class ViewActivityLog extends ViewRecord
{
protected static string $resource = ActivityLogResource::class;
}
\ No newline at end of file
This diff is collapsed.
<?php
namespace App\Filament\Resources\BoardOfferResource\Pages;
use App\Filament\Resources\BoardOfferResource;
use App\Services\Admin\BoardService;
use Filament\Resources\Pages\CreateRecord;
class CreateBoardOffer extends CreateRecord
{
protected static string $resource = BoardOfferResource::class;
protected function mutateFormDataBeforeCreate(array $data): array
{
$sequenceService = app(\App\Services\Admin\SequenceService::class);
$data['offer_number'] = $sequenceService->getNextNumber('board_offer_number');
$data['status'] = \App\Enums\BoardOfferStatus::PENDING;
$data['submitted_by'] = auth()->id();
$data['submitted_at'] = now();
return $data;
}
protected function getRedirectUrl(): string
{
return $this->getResource()::getUrl('index');
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment