feat(checkout): enforce editing policy on items
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Domains\Purchase\Controllers;
|
||||
|
||||
use App\Domains\Integration\Services\TelepagosIntegrationService;
|
||||
use App\Domains\Purchase\Models\Purchase;
|
||||
use App\Domains\Purchase\Models\PurchaseItem;
|
||||
use App\Domains\Purchase\Requests\PaymentIntentRequest;
|
||||
use App\Domains\Purchase\Requests\StartCheckoutRequest;
|
||||
use App\Domains\Purchase\Requests\UpdatePurchaseCustomerRequest;
|
||||
@@ -112,6 +113,20 @@ class PurchaseController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
public function removeItem(
|
||||
Request $request,
|
||||
Tenant $tenant,
|
||||
Purchase $compra,
|
||||
PurchaseItem $item,
|
||||
CheckoutService $checkoutService,
|
||||
): PurchaseResource {
|
||||
$compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra);
|
||||
|
||||
return PurchaseResource::make(
|
||||
$checkoutService->removeItem($compra, $item),
|
||||
);
|
||||
}
|
||||
|
||||
public function paymentIntent(
|
||||
PaymentIntentRequest $request,
|
||||
Tenant $tenant,
|
||||
|
||||
@@ -30,7 +30,7 @@ class PurchaseItemResource extends JsonResource
|
||||
? $this->sourceCatalogItem
|
||||
: null;
|
||||
$includeVariants = $tenant instanceof Tenant
|
||||
&& $tenant->cart_editing_policy->allowsVariantChanges()
|
||||
&& $tenant->checkout_editing_policy->allowsVariantChanges()
|
||||
&& $catalogItem !== null
|
||||
&& $catalogItem->relationLoaded('variants');
|
||||
|
||||
@@ -67,6 +67,9 @@ class PurchaseItemResource extends JsonResource
|
||||
$imageUrl = $displayImage
|
||||
? $this->resolveImageUrl($selectedItem, $catalogItem)
|
||||
: null;
|
||||
$includeVariants = $tenant instanceof Tenant
|
||||
&& $tenant->checkout_editing_policy->allowsVariantChanges()
|
||||
&& $catalogItem?->relationLoaded('variants');
|
||||
|
||||
return [
|
||||
'id' => $this->id,
|
||||
@@ -82,6 +85,16 @@ class PurchaseItemResource extends JsonResource
|
||||
'imagen' => $imageUrl,
|
||||
'attributes' => $variant === null ? [] : $this->resolveAttributes($variant),
|
||||
],
|
||||
'variants' => $this->when(
|
||||
$includeVariants,
|
||||
fn () => $catalogItem
|
||||
->visibleVariants($this->variant_id)
|
||||
->map(fn (Variant $availableVariant): array => $this->variantData(
|
||||
$catalogItem,
|
||||
$availableVariant,
|
||||
))
|
||||
->values(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -61,13 +61,13 @@ class EditCheckoutService
|
||||
$tenant = $purchase->tenant()->firstOrFail();
|
||||
$finalQuantity = $quantity ?? (int) $purchaseItem->cantidad;
|
||||
|
||||
if ($quantity !== null && ! $tenant->cart_editing_policy->allowsQuantityChanges()) {
|
||||
if ($quantity !== null && ! $tenant->checkout_editing_policy->allowsQuantityChanges()) {
|
||||
throw ValidationException::withMessages([
|
||||
'quantity' => __('api.cart.editing_disabled'),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($updateVariant && ! $tenant->cart_editing_policy->allowsVariantChanges()) {
|
||||
if ($updateVariant && ! $tenant->checkout_editing_policy->allowsVariantChanges()) {
|
||||
throw ValidationException::withMessages([
|
||||
'variant_id' => __('api.purchase.variant_change_disabled'),
|
||||
]);
|
||||
@@ -184,7 +184,7 @@ class EditCheckoutService
|
||||
$purchase = $this->lockPurchase($purchase);
|
||||
$this->assertEditable($purchase);
|
||||
|
||||
if (! $purchase->tenant()->firstOrFail()->cart_editing_policy->allowsModification()) {
|
||||
if (! $purchase->tenant()->firstOrFail()->checkout_editing_policy->allowsModification()) {
|
||||
throw ValidationException::withMessages([
|
||||
'purchase' => __('api.cart.editing_disabled'),
|
||||
]);
|
||||
@@ -204,6 +204,31 @@ class EditCheckoutService
|
||||
});
|
||||
}
|
||||
|
||||
public function removeItem(Purchase $purchase, PurchaseItem $purchaseItem): Purchase
|
||||
{
|
||||
return DB::transaction(function () use ($purchase, $purchaseItem): Purchase {
|
||||
$purchase = $this->lockPurchase($purchase);
|
||||
$this->assertEditable($purchase);
|
||||
|
||||
if (! $purchase->tenant()->firstOrFail()->checkout_editing_policy->allowsRemoval()) {
|
||||
throw ValidationException::withMessages([
|
||||
'item' => __('api.cart.editing_disabled'),
|
||||
]);
|
||||
}
|
||||
|
||||
$purchaseItem = $this->lockPurchaseItem($purchase, $purchaseItem);
|
||||
$selection = $this->selections->resolvePurchaseItem($purchase->tenant, $purchaseItem);
|
||||
$this->inventory->release($selection, (int) $purchaseItem->cantidad);
|
||||
$this->sourceCart->removeItem($purchase, $purchaseItem);
|
||||
$purchaseItem->delete();
|
||||
$purchase->update([
|
||||
'total' => $purchase->calculateCurrentTotalAmount(),
|
||||
]);
|
||||
|
||||
return $this->loadPurchase($purchase);
|
||||
});
|
||||
}
|
||||
|
||||
private function adjustReservation(
|
||||
Purchase $purchase,
|
||||
PurchaseItem $purchaseItem,
|
||||
|
||||
@@ -23,7 +23,7 @@ class PurchaseResponseLoader
|
||||
]);
|
||||
}
|
||||
|
||||
if (! $purchase->tenant->cart_editing_policy->allowsVariantChanges()) {
|
||||
if (! $purchase->tenant->checkout_editing_policy->allowsVariantChanges()) {
|
||||
return $purchase;
|
||||
}
|
||||
|
||||
@@ -35,6 +35,13 @@ class PurchaseResponseLoader
|
||||
'items.sourceCatalogItem.variants.definitions.itemAttribute.attribute.options',
|
||||
'items.sourceCatalogItem.variants.eventDates',
|
||||
'items.sourceCatalogItem.variants.eventDate',
|
||||
'cart.items.catalogItem.itemAttributes.attribute',
|
||||
'cart.items.catalogItem.variants' => fn ($query) => $query->orderBy('id'),
|
||||
'cart.items.catalogItem.variants.inventory',
|
||||
'cart.items.catalogItem.variants.definitions' => fn ($query) => $query->orderBy('id'),
|
||||
'cart.items.catalogItem.variants.definitions.itemAttribute.attribute.options',
|
||||
'cart.items.catalogItem.variants.eventDates',
|
||||
'cart.items.catalogItem.variants.eventDate',
|
||||
]);
|
||||
|
||||
return $purchase;
|
||||
|
||||
@@ -130,6 +130,20 @@ class SourceCartService
|
||||
]);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace App\Domains\Purchase\Services;
|
||||
|
||||
use App\Domains\Catalog\Services\StockReservationService;
|
||||
use App\Domains\Purchase\Models\Purchase;
|
||||
use App\Domains\Purchase\Models\PurchaseItem;
|
||||
use App\Domains\Purchase\Services\Checkout\CompleteCheckoutService;
|
||||
use App\Domains\Purchase\Services\Checkout\EditCheckoutService;
|
||||
use App\Domains\Purchase\Services\Checkout\ReleaseCheckoutService;
|
||||
@@ -69,6 +70,11 @@ class CheckoutService
|
||||
return $this->editor->prepareItemEditing($purchase);
|
||||
}
|
||||
|
||||
public function removeItem(Purchase $purchase, PurchaseItem $purchaseItem): Purchase
|
||||
{
|
||||
return $this->editor->removeItem($purchase, $purchaseItem);
|
||||
}
|
||||
|
||||
public function confirmPurchase(Purchase $purchase): void
|
||||
{
|
||||
$this->completer->confirm($purchase);
|
||||
|
||||
@@ -9,6 +9,7 @@ Route::prefix('tenants/{tenant:codigo}')->middleware('auth:sanctum')->group(func
|
||||
Route::get('compras/{compra}', [PurchaseController::class, 'show']);
|
||||
Route::post('compras/{compra}/edit-items', [PurchaseController::class, 'prepareItemEditing']);
|
||||
Route::patch('compras/{compra}/items/{item}', [PurchaseController::class, 'updateItem']);
|
||||
Route::delete('compras/{compra}/items/{item}', [PurchaseController::class, 'removeItem']);
|
||||
Route::patch('compras/{compra}/customer-data', [PurchaseController::class, 'updateCustomerData']);
|
||||
Route::post('compras/{compra}/payment-intent', [PurchaseController::class, 'paymentIntent']);
|
||||
Route::post('compras/{compra}/complete', [PurchaseController::class, 'complete']);
|
||||
|
||||
Reference in New Issue
Block a user