option('dry'); $query = QrCode::query() ->whereNotNull('expires_at') ->where('expires_at', '<=', $now) ->whereIn('status', [Allocated::$name, Active::$name]); $count = (clone $query)->count(); $this->info(($dry ? '[DRY] ' : '')."Found {$count} expired QR codes"); if ($count === 0 || $dry) { return self::SUCCESS; } // Bulk update — bypasses the state machine but keeps the DB // representation consistent and is safe because we only move // from non-terminal states to a terminal one. $updated = $query->update([ 'status' => Expired::$name, 'updated_at' => $now, ]); $this->info("Expired {$updated} QR codes"); return self::SUCCESS; } }