feat(cart): enhance item update functionality to support variant changes and stock management; update related request validation and resource formatting; add tests for variant handling in cart

This commit is contained in:
2026-08-10 12:08:09 -03:00
parent 2693df2cbf
commit c6351d706f
8 changed files with 225 additions and 15 deletions

View File

@@ -124,27 +124,85 @@ class Cart extends Model
});
}
public function updateItem(int $cartItemId, int $quantity): CartItem
{
public function updateItem(
int $cartItemId,
int $quantity,
?int $variantId = null,
bool $updateVariant = false,
): CartItem {
if ($quantity <= 0) {
throw ValidationException::withMessages([
'cantidad' => __('api.cart.positive_quantity'),
]);
}
return DB::transaction(function () use ($cartItemId, $quantity): CartItem {
return DB::transaction(function () use (
$cartItemId,
$quantity,
$variantId,
$updateVariant,
): CartItem {
/** @var CartItem $item */
$item = $this->items()
->where('id', $cartItemId)
->lockForUpdate()
->firstOrFail();
$selectedItem = $this->resolveScopedItem(
$currentSelection = $this->resolveScopedItem(
$item->catalog_item_id,
$item->variant_id,
true,
);
$inventoryService = app(CatalogInventoryService::class);
if ($updateVariant && $variantId !== $item->variant_id) {
$nextSelection = $this->resolveScopedItem(
$item->catalog_item_id,
$variantId,
true,
);
$otherVariantsQuantity = (int) $this->items()
->where('catalog_item_id', $item->catalog_item_id)
->whereKeyNot($item->getKey())
->sum('cantidad');
$this->assertUserPurchaseLimit(
$nextSelection,
$otherVariantsQuantity + $quantity,
);
$inventoryService->release($currentSelection, $item->cantidad);
$availableQuantity = $inventoryService->availableQuantity($nextSelection);
if ($availableQuantity !== null && $availableQuantity < $quantity) {
throw ValidationException::withMessages([
'variant_id' => __('api.cart.insufficient_stock', ['max' => $availableQuantity]),
]);
}
$targetItem = $this->items()
->where('catalog_item_id', $item->catalog_item_id)
->where('variant_id', $variantId)
->whereKeyNot($item->getKey())
->lockForUpdate()
->first();
$inventoryService->reserve($nextSelection, $quantity);
if ($targetItem !== null) {
$targetItem->cantidad += $quantity;
$targetItem->save();
$item->delete();
return $targetItem->fresh();
}
$item->variant_id = $variantId;
$item->cantidad = $quantity;
$item->save();
return $item->fresh();
}
$delta = $quantity - $item->cantidad;
if ($delta > 0) {
@@ -153,12 +211,12 @@ class Cart extends Model
->whereKeyNot($item->getKey())
->sum('cantidad');
$this->assertUserPurchaseLimit(
$selectedItem,
$currentSelection,
$otherVariantsQuantity + $quantity,
);
}
$availableQuantity = $inventoryService->availableQuantity($selectedItem);
$availableQuantity = $inventoryService->availableQuantity($currentSelection);
if ($delta > 0 && $availableQuantity !== null && $availableQuantity < $delta) {
$maxAvailable = $availableQuantity + $item->cantidad;
@@ -171,11 +229,11 @@ class Cart extends Model
$item->save();
if ($delta > 0) {
$inventoryService->reserve($selectedItem, $delta);
$inventoryService->reserve($currentSelection, $delta);
}
if ($delta < 0) {
$inventoryService->release($selectedItem, abs($delta));
$inventoryService->release($currentSelection, abs($delta));
}
return $item->fresh();