*/ public function availableAssets(DateTimeInterface $startsAt, DateTimeInterface $endsAt): Builder { return SnipeAsset::query() ->where('active', true) ->where('requestable', true) ->whereNull('assigned_id') ->whereDoesntHave('reservationItems', fn (Builder $query): Builder => $query ->whereIn('status', ReservationItemStatus::blockingValues()) ->where('starts_at', '<', $endsAt) ->where('ends_at', '>', $startsAt)) ->whereDoesntHave('blocks', fn (Builder $query): Builder => $query ->where('starts_at', '<', $endsAt) ->where('ends_at', '>', $startsAt)); } public function isAvailable( SnipeAsset $asset, DateTimeInterface $startsAt, DateTimeInterface $endsAt, ?int $exceptReservationId = null, ): bool { if (! $asset->active || ! $asset->requestable || $asset->assigned_id !== null) { return false; } $hasReservationConflict = $asset->reservationItems() ->whereIn('status', ReservationItemStatus::blockingValues()) ->when($exceptReservationId, fn (Builder $query): Builder => $query->where('reservation_id', '!=', $exceptReservationId)) ->where('starts_at', '<', $endsAt) ->where('ends_at', '>', $startsAt) ->exists(); if ($hasReservationConflict) { return false; } return ! $asset->blocks() ->where('starts_at', '<', $endsAt) ->where('ends_at', '>', $startsAt) ->exists(); } }