withoutGlobalScope(OrganisationScope::class) ->where('booking_status', ArtistEngagementStatus::Option->value) ->whereNotNull('option_expires_at') ->where('option_expires_at', '<=', now()) ->whereNull('deleted_at') ->get(); $demotedIds = []; foreach ($expired as $engagement) { // Re-check status under fresh state — another worker / a // user UI action may have already transitioned this row. if ($engagement->booking_status !== ArtistEngagementStatus::Option) { continue; } $service->transitionStatus($engagement, ArtistEngagementStatus::Draft); activity('artist_engagement') ->performedOn($engagement) ->event('option_expired') ->withProperties([ 'organisation_id' => $engagement->organisation_id, 'event_id' => $engagement->event_id, 'option_expires_at' => optional($engagement->option_expires_at)->toIso8601String(), ]) ->log('option_expired'); $demotedIds[] = (string) $engagement->id; } $count = count($demotedIds); $this->info("Demoted {$count} option(s) on ".now()->toDateString().'.'); if ($count > 0) { $this->line('IDs: '.implode(', ', $demotedIds)); } return self::SUCCESS; } }