lockPurchase($purchase); if ($purchase->payment_method === null) { throw ValidationException::withMessages([ 'payment_method' => __('api.purchase.payment_method_required'), ]); } if ($this->isTerminal($purchase)) { return $this->loadPurchase($purchase); } $purchase->update([ 'status' => Purchase::STATUS_PENDING_PAYMENT, 'total' => $purchase->calculateCurrentTotalAmount(), ]); return $this->loadPurchase($purchase); }); } public function submitForReview(Purchase $purchase): Purchase { return DB::transaction(function () use ($purchase): Purchase { $purchase = $this->lockPurchase($purchase); if ($purchase->status === Purchase::STATUS_PAID) { return $this->loadPurchase($purchase); } if ( $purchase->status !== Purchase::STATUS_PENDING_PAYMENT || ($purchase->expires_at !== null && $purchase->expires_at->isPast()) ) { throw ValidationException::withMessages([ 'purchase' => __('api.purchase.not_available_for_review'), ]); } $purchase->update(['expires_at' => null]); return $this->loadPurchase($purchase); }); } public function confirm(Purchase $purchase): void { DB::transaction(function () use ($purchase): void { $purchase = $this->lockPurchase($purchase); if ($purchase->status === Purchase::STATUS_PAID) { return; } if (in_array($purchase->status, [ Purchase::STATUS_CANCELLED, Purchase::STATUS_REJECTED, Purchase::STATUS_EXPIRED, ], true)) { throw ValidationException::withMessages([ 'purchase' => __('api.purchase.cannot_confirm'), ]); } $items = $purchase->items() ->where('reservation_status', PurchaseItem::RESERVATION_ACTIVE) ->lockForUpdate() ->get(); foreach ($items as $item) { $selection = $this->selections->resolvePurchaseItem($purchase->tenant, $item); try { $this->inventory->commit($selection, (int) $item->cantidad); } catch (\InvalidArgumentException) { throw ValidationException::withMessages([ 'items' => __('api.purchase.inconsistent_reservation'), ]); } $item->update([ 'reservation_status' => PurchaseItem::RESERVATION_COMMITTED, ]); } $this->sourceCart->finalize($purchase); }); } private function isTerminal(Purchase $purchase): bool { return in_array($purchase->status, [ Purchase::STATUS_PAID, Purchase::STATUS_CANCELLED, Purchase::STATUS_REJECTED, Purchase::STATUS_EXPIRED, ], true); } private function lockPurchase(Purchase $purchase): Purchase { /** @var Purchase */ return Purchase::query()->lockForUpdate()->findOrFail($purchase->getKey()); } private function loadPurchase(Purchase $purchase): Purchase { return $purchase->load(['items.imageAttachment']); } }