filter(fn ($day) => is_numeric($day) && $day > 0) ->map(fn ($day) => (int) $day) ->unique() ->sortDesc() // handle larger days first ->values(); $eventPackageExpiryDays = collect(config('package-limits.package_expiry_days', [])) ->filter(fn ($day) => is_numeric($day) && $day > 0) ->map(fn ($day) => (int) $day) ->unique() ->sortDesc() ->values(); $creditThresholds = collect(config('package-limits.credit_thresholds', [])) ->filter(fn ($value) => is_numeric($value) && $value >= 0) ->map(fn ($value) => (int) $value) ->unique() ->sortDesc() ->values(); $maxCreditThreshold = $creditThresholds->max(); $now = now(); if ($maxCreditThreshold !== null) { \App\Models\Tenant::query() ->select(['id', 'event_credits_balance', 'credit_warning_sent_at', 'credit_warning_threshold', 'contact_email']) ->chunkById(100, function ($tenants) use ($creditThresholds, $maxCreditThreshold, $now) { foreach ($tenants as $tenant) { $balance = (int) ($tenant->event_credits_balance ?? 0); if ($balance > $maxCreditThreshold && $tenant->credit_warning_sent_at) { $tenant->forceFill([ 'credit_warning_sent_at' => null, 'credit_warning_threshold' => null, ])->save(); continue; } foreach ($creditThresholds as $threshold) { if ( $balance <= $threshold && ( $tenant->credit_warning_sent_at === null || $threshold < ($tenant->credit_warning_threshold ?? PHP_INT_MAX) ) ) { event(new \App\Events\Packages\TenantCreditsLow($tenant, $balance, $threshold)); $tenant->forceFill([ 'credit_warning_sent_at' => $now, 'credit_warning_threshold' => $threshold, ])->save(); break; } } } }); } EventPackage::query() ->whereNotNull('gallery_expires_at') ->chunkById(100, function ($packages) use ($warningDays, $now) { foreach ($packages as $package) { $expiresAt = $package->gallery_expires_at; if (! $expiresAt) { continue; } $daysDiff = $now->diffInDays($expiresAt, false); if ($daysDiff < 0) { if (! $package->gallery_expired_notified_at) { event(new EventPackageGalleryExpired($package)); $package->forceFill([ 'gallery_expired_notified_at' => $now, ])->save(); } continue; } if ($warningDays->isEmpty()) { continue; } if ($package->gallery_warning_sent_at) { continue; } foreach ($warningDays as $day) { if ($daysDiff <= $day && $daysDiff >= 0) { event(new EventPackageGalleryExpiring($package, $day)); $package->forceFill([ 'gallery_warning_sent_at' => $now, ])->save(); break; } } } }); \App\Models\TenantPackage::query() ->with(['tenant', 'package']) ->whereNotNull('expires_at') ->chunkById(100, function ($tenantPackages) use ($eventPackageExpiryDays, $now) { foreach ($tenantPackages as $tenantPackage) { $expiresAt = $tenantPackage->expires_at; if (! $expiresAt) { continue; } $daysDiff = $now->diffInDays($expiresAt, false); if ($daysDiff < 0) { if (! $tenantPackage->expired_notified_at) { event(new \App\Events\Packages\TenantPackageExpired($tenantPackage)); $tenantPackage->forceFill(['expired_notified_at' => $now])->save(); } continue; } if ($tenantPackage->expiry_warning_sent_at) { continue; } foreach ($eventPackageExpiryDays as $day) { if ($daysDiff <= $day && $daysDiff >= 0) { event(new \App\Events\Packages\TenantPackageExpiring($tenantPackage, $day)); $tenantPackage->forceFill(['expiry_warning_sent_at' => $now])->save(); break; } } } }); return self::SUCCESS; } }