findSourceCart($purchase); if ($sourceCart === null) { return false; } if ($sourceCart->origin === Cart::ORIGIN_DIRECT_CHECKOUT) { return false; } /** @var Cart|null $activeCart */ $activeCart = Cart::query() ->where('tenant_codigo', $purchase->tenant_codigo) ->where('user_id', $purchase->user_id) ->where('status', 'active') ->where('id', '!=', $sourceCart->getKey()) ->lockForUpdate() ->first(); if ($activeCart !== null) { $this->mergeIntoActiveCart($sourceCart, $activeCart); $sourceCart->update([ 'status' => 'converted', 'guest_token' => null, ]); if (! $sourceCart->trashed()) { $sourceCart->delete(); } return true; } if ($sourceCart->trashed()) { $sourceCart->restore(); } $sourceCart->update([ 'status' => 'active', 'user_id' => $purchase->user_id, 'guest_token' => null, ]); return true; } public function syncItemQuantity( Purchase $purchase, PurchaseItem $purchaseItem, int $quantity, ): void { $sourceCart = $this->findSourceCart($purchase); if ($sourceCart === null) { return; } $sourceCart->items() ->where('catalog_item_id', $purchaseItem->source_catalog_item_id) ->where('variant_id', $purchaseItem->source_variant_id) ->update(['cantidad' => $quantity]); } public function syncItemSelection( Purchase $purchase, int $catalogItemId, ?int $previousVariantId, int $newVariantId, int $finalQuantity, ): void { $sourceCart = $this->findSourceCart($purchase); if ($sourceCart === null) { return; } /** @var CartItem|null $previousItem */ $previousItem = $sourceCart->items() ->where('catalog_item_id', $catalogItemId) ->where('variant_id', $previousVariantId) ->lockForUpdate() ->first(); /** @var CartItem|null $targetItem */ $targetItem = $sourceCart->items() ->where('catalog_item_id', $catalogItemId) ->where('variant_id', $newVariantId) ->when($previousItem !== null, fn ($query) => $query->whereKeyNot($previousItem->getKey())) ->lockForUpdate() ->first(); if ($targetItem !== null) { $targetItem->update(['cantidad' => $finalQuantity]); $previousItem?->delete(); return; } if ($previousItem !== null) { $previousItem->update([ 'variant_id' => $newVariantId, 'cantidad' => $finalQuantity, ]); return; } $sourceCart->items()->create([ 'catalog_item_id' => $catalogItemId, 'variant_id' => $newVariantId, 'cantidad' => $finalQuantity, ]); } public function removeItem(Purchase $purchase, PurchaseItem $purchaseItem): void { $sourceCart = $this->findSourceCart($purchase); if ($sourceCart === null) { return; } $sourceCart->items() ->where('catalog_item_id', $purchaseItem->source_catalog_item_id) ->where('variant_id', $purchaseItem->source_variant_id) ->delete(); } public function finalize(Purchase $purchase): void { $sourceCart = $this->findSourceCart($purchase); if ($sourceCart === null || $sourceCart->trashed()) { return; } $sourceCart->update([ 'status' => 'converted', 'guest_token' => null, ]); $sourceCart->delete(); } private function findSourceCart(Purchase $purchase): ?Cart { if ($purchase->cart_id === null) { return null; } /** @var Cart|null */ return Cart::withTrashed() ->whereKey($purchase->cart_id) ->lockForUpdate() ->first(); } private function mergeIntoActiveCart(Cart $sourceCart, Cart $activeCart): void { $sourceItems = $sourceCart->items()->lockForUpdate()->get(); foreach ($sourceItems as $sourceItem) { /** @var CartItem|null $activeItem */ $activeItem = $activeCart->items() ->where('catalog_item_id', $sourceItem->catalog_item_id) ->where('variant_id', $sourceItem->variant_id) ->lockForUpdate() ->first(); if ($activeItem === null) { $activeItem = $activeCart->items()->create([ 'catalog_item_id' => $sourceItem->catalog_item_id, 'variant_id' => $sourceItem->variant_id, 'cantidad' => $sourceItem->cantidad, ]); } else { $activeItem->increment('cantidad', (int) $sourceItem->cantidad); } $this->reservations->transfer($sourceItem, $activeItem); } } }