$eventDateIds */ public function invalidate( Tenant $tenant, Collection $eventDateIds, string $reason = StockReservationService::REASON_EVENT_DATE_RESCHEDULED, ): void { DB::transaction(function () use ($tenant, $eventDateIds, $reason): void { $carts = Cart::query() ->where('tenant_codigo', $tenant->codigo) ->where('status', Cart::STATUS_ACTIVE) ->whereNull('current_purchase_id') ->whereHas('currentStockReservation', fn ($reservation) => $reservation ->where('status', StockReservation::STATUS_ACTIVE)) ->whereHas('items.variant', fn ($variant) => $variant ->withTrashed() ->where(fn ($dates) => $dates ->whereIn('event_date_id', $eventDateIds) ->orWhereHas('eventDates', fn ($date) => $date ->whereIn('event_dates.id', $eventDateIds)))) ->orderBy('id') ->lockForUpdate() ->get(); foreach ($carts as $cart) { // Checkout keeps the cart and purchase attached to the same reservation. if (Purchase::query() ->where('stock_reservation_id', $cart->current_stock_reservation_id) ->exists()) { continue; } $this->reservations->releaseCurrentCartReservation( $cart, $reason, ); // Reuse the existing expired-cart flow: stale mutations receive the // expiration response and the next GET replaces the whole cart. $cart->update(['status' => Cart::STATUS_EXPIRED]); } }); } }