feat: refactor purchase status handling and add finalize endpoint for purchases
This commit is contained in:
@@ -2,17 +2,15 @@
|
||||
|
||||
namespace App\Domains\Purchase\Controllers;
|
||||
|
||||
use App\Domains\Catalog\Models\ProductVariant;
|
||||
use App\Domains\Purchase\Models\Purchase;
|
||||
use App\Domains\Purchase\Requests\StorePurchaseRequest;
|
||||
use App\Domains\Purchase\Resources\PurchaseResource;
|
||||
use App\Domains\Purchase\Services\CheckoutService;
|
||||
use App\Domains\Tenant\Models\Tenant;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Domains\Purchase\Services\CheckoutService;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
class PurchaseController extends Controller
|
||||
@@ -122,6 +120,15 @@ class PurchaseController extends Controller
|
||||
], 400);
|
||||
}
|
||||
|
||||
public function finalize(Request $request, Tenant $tenant, Purchase $compra, CheckoutService $checkoutService): PurchaseResource
|
||||
{
|
||||
$compra = $this->resolveScopedPurchase($tenant, $request->user()->id, $compra);
|
||||
|
||||
return PurchaseResource::make(
|
||||
$checkoutService->finalizePurchase($compra)
|
||||
);
|
||||
}
|
||||
|
||||
protected function resolveScopedPurchase(Tenant $tenant, int $userId, Purchase $purchase): Purchase
|
||||
{
|
||||
if ($purchase->tenant_codigo !== $tenant->codigo || $purchase->user_id !== $userId) {
|
||||
|
||||
@@ -16,7 +16,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
'tenant_codigo',
|
||||
'user_id',
|
||||
'status',
|
||||
'payment_status',
|
||||
'payment_method',
|
||||
'total',
|
||||
'dni',
|
||||
@@ -28,6 +27,12 @@ class Purchase extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
public const STATUS_CREATED = 'created';
|
||||
public const STATUS_PENDING_PAYMENT = 'pending_payment';
|
||||
public const STATUS_PAID = 'paid';
|
||||
public const STATUS_CANCELLED = 'cancelled';
|
||||
public const STATUS_REJECTED = 'rejected';
|
||||
|
||||
protected $table = 'compras';
|
||||
|
||||
protected function casts(): array
|
||||
@@ -117,11 +122,17 @@ class Purchase extends Model
|
||||
return $cart->getTotalAmount();
|
||||
}
|
||||
|
||||
public function finalize(): void
|
||||
public function markAsPendingPayment(): void
|
||||
{
|
||||
$this->update([
|
||||
'status' => 'paid',
|
||||
'payment_status' => 'approved',
|
||||
'status' => self::STATUS_PENDING_PAYMENT,
|
||||
]);
|
||||
}
|
||||
|
||||
public function markAsPaid(): void
|
||||
{
|
||||
$this->update([
|
||||
'status' => self::STATUS_PAID,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace App\Domains\Purchase\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StorePurchaseRequest extends FormRequest
|
||||
{
|
||||
@@ -18,7 +17,6 @@ class StorePurchaseRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'status' => ['sometimes', 'string', Rule::in(['pending', 'paid', 'cancelled'])],
|
||||
'cart_id' => ['required', 'integer', 'exists:carritos,id'],
|
||||
'dni' => ['required', 'string'],
|
||||
'telefono' => ['required', 'string'],
|
||||
|
||||
@@ -39,7 +39,6 @@ class PurchaseResource extends JsonResource
|
||||
'tenant_codigo' => $this->tenant_codigo,
|
||||
'user_id' => $this->user_id,
|
||||
'status' => $this->status,
|
||||
'payment_status' => $this->payment_status,
|
||||
'payment_method' => $this->payment_method,
|
||||
'dni' => $this->dni,
|
||||
'telefono' => $this->telefono,
|
||||
|
||||
@@ -33,21 +33,62 @@ class CheckoutService
|
||||
$cart->setRelation('items', $cartItems);
|
||||
$totalAmount = $cart->getTotalAmount();
|
||||
|
||||
/** @var Purchase $purchase */
|
||||
$purchase = Purchase::query()->updateOrCreate(
|
||||
[
|
||||
/** @var Purchase|null $purchase */
|
||||
$purchase = Purchase::query()
|
||||
->where('cart_id', $cart->getKey())
|
||||
->where('tenant_codigo', $tenant->codigo)
|
||||
->where('user_id', $userId)
|
||||
->whereIn('status', [Purchase::STATUS_CREATED, Purchase::STATUS_PENDING_PAYMENT])
|
||||
->latest('id')
|
||||
->first();
|
||||
|
||||
if ($purchase === null) {
|
||||
/** @var Purchase $purchase */
|
||||
$purchase = Purchase::query()->create([
|
||||
...$purchaseData,
|
||||
'cart_id' => $cart->getKey(),
|
||||
'status' => 'pending',
|
||||
'tenant_codigo' => $tenant->codigo,
|
||||
'user_id' => $userId,
|
||||
],
|
||||
[
|
||||
...$purchaseData,
|
||||
'payment_status' => 'pending',
|
||||
'status' => Purchase::STATUS_CREATED,
|
||||
'payment_method' => null,
|
||||
'total' => $totalAmount,
|
||||
]
|
||||
);
|
||||
]);
|
||||
} else {
|
||||
$purchase->fill([
|
||||
...$purchaseData,
|
||||
'status' => Purchase::STATUS_CREATED,
|
||||
'payment_method' => null,
|
||||
'total' => $totalAmount,
|
||||
]);
|
||||
$purchase->save();
|
||||
}
|
||||
|
||||
return $purchase->load(['items.variant.product', 'items.variant.definitions.productAttribute.attribute']);
|
||||
});
|
||||
}
|
||||
|
||||
public function finalizePurchase(Purchase $purchase): Purchase
|
||||
{
|
||||
return DB::transaction(function () use ($purchase): Purchase {
|
||||
/** @var Purchase $purchase */
|
||||
$purchase = Purchase::query()
|
||||
->lockForUpdate()
|
||||
->findOrFail($purchase->getKey());
|
||||
|
||||
if ($purchase->payment_method === null) {
|
||||
throw ValidationException::withMessages([
|
||||
'payment_method' => 'The purchase payment method must be selected before finalizing.',
|
||||
]);
|
||||
}
|
||||
|
||||
if (in_array($purchase->status, [Purchase::STATUS_PAID, Purchase::STATUS_CANCELLED, Purchase::STATUS_REJECTED], true)) {
|
||||
return $purchase->load(['items.variant.product', 'items.variant.definitions.productAttribute.attribute']);
|
||||
}
|
||||
|
||||
$purchase->update([
|
||||
'status' => Purchase::STATUS_PENDING_PAYMENT,
|
||||
'total' => $purchase->calculateCurrentTotalAmount(),
|
||||
]);
|
||||
|
||||
return $purchase->load(['items.variant.product', 'items.variant.definitions.productAttribute.attribute']);
|
||||
});
|
||||
|
||||
@@ -6,4 +6,5 @@ use Illuminate\Support\Facades\Route;
|
||||
Route::prefix('tenants/{tenant:codigo}')->middleware(['auth:sanctum', \App\Domains\Cart\Middleware\MergeGuestCartMiddleware::class])->group(function (): void {
|
||||
Route::apiResource('compras', PurchaseController::class)->only(['index', 'store', 'show']);
|
||||
Route::post('compras/{compra}/payment-intent', [PurchaseController::class, 'paymentIntent']);
|
||||
Route::post('compras/{compra}/finalize', [PurchaseController::class, 'finalize']);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user