fix issue
This commit is contained in:
parent
7fbc746968
commit
79c52d0236
@ -116,50 +116,99 @@ class StripeController extends Controller
|
||||
{
|
||||
$clientSessionId = $request->query('client_session_id');
|
||||
|
||||
$payment = Payment::where('client_session_id', $clientSessionId)
|
||||
->where('status', 'succeeded')
|
||||
->first();
|
||||
if (!$clientSessionId) {
|
||||
return response()->json(['error' => 'Client session ID is required'], 400);
|
||||
}
|
||||
|
||||
if ($payment) {
|
||||
// Si la vérification réussit, retournez le nombre de tirages.
|
||||
$payment = Payment::where('client_session_id', $clientSessionId)->first();
|
||||
|
||||
if (!$payment) {
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Payment not found.',
|
||||
], 404);
|
||||
}
|
||||
|
||||
// If payment is already succeeded in our database
|
||||
if ($payment->status === 'succeeded') {
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'drawCount' => $payment->draw_count,
|
||||
'cached' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
// Si la vérification échoue, retournez une erreur.
|
||||
// If payment is pending, check with Stripe directly to handle race condition
|
||||
if ($payment->status === 'pending') {
|
||||
try {
|
||||
Stripe::setApiKey(env('STRIPE_SECRET_KEY'));
|
||||
$session = Session::retrieve($clientSessionId);
|
||||
|
||||
// Check if payment is completed on Stripe side
|
||||
if ($session->payment_status === 'paid' && $session->status === 'complete') {
|
||||
// Update our payment record and mark as succeeded
|
||||
$payment->update(['status' => 'succeeded']);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'drawCount' => $payment->draw_count,
|
||||
'updated' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
// Payment not completed yet, return pending status
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Payment is still being processed.',
|
||||
'status' => 'pending',
|
||||
], 202);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('Stripe validation failed: ' . $e->getMessage(), [
|
||||
'client_session_id' => $clientSessionId,
|
||||
'payment_id' => $payment->id
|
||||
]);
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Payment validation error.',
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
// Payment failed or has other status
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Paiement non validé.',
|
||||
], 404);
|
||||
'message' => 'Payment failed or cancelled.',
|
||||
'status' => $payment->status,
|
||||
], 402);
|
||||
}
|
||||
|
||||
public function getCards(Request $request)
|
||||
{
|
||||
$sessionId = $request->query('client_session_id');
|
||||
|
||||
if(!$sessionId)
|
||||
{
|
||||
if (!$sessionId) {
|
||||
$count = $request->query('count');
|
||||
if($count == 1){
|
||||
if ($count == 1) {
|
||||
$freeCards = $this->cardRepository->draw(1);
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'cards' => $freeCards
|
||||
]);
|
||||
}
|
||||
return response()->json(['success' => false, 'message' => 'Client session ID is required for paid cards.'], 400);
|
||||
}
|
||||
|
||||
// 1. Find the payment record
|
||||
$payment = Payment::where('client_session_id', $sessionId)->first();
|
||||
|
||||
if (!$payment) {
|
||||
\Log::warning('Payment record not found', ['client_session_id' => $sessionId]);
|
||||
return response()->json(['success' => false, 'message' => 'Payment not found.'], 404);
|
||||
}
|
||||
|
||||
// 2. One-Time Use Check
|
||||
if ($payment->status === 'processed') {
|
||||
// 2. One-Time Use Check - prevent double processing
|
||||
if ($payment->status === 'processed' && $payment->cards) {
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'cards' => $payment->cards,
|
||||
@ -167,30 +216,81 @@ class StripeController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
// 3. Verify payment status with Stripe
|
||||
if ($payment->status !== 'succeeded') {
|
||||
// 3. Handle race condition - verify with Stripe if status is pending
|
||||
if ($payment->status === 'pending' || $payment->status === 'failed') {
|
||||
try {
|
||||
Stripe::setApiKey(env('STRIPE_SECRET_KEY'));
|
||||
$session = Session::retrieve($sessionId);
|
||||
if ($session->payment_status !== 'paid' || $session->status !== 'complete') {
|
||||
return response()->json(['success' => false, 'message' => 'Payment not complete.'], 402);
|
||||
|
||||
\Log::info('Checking Stripe session status', [
|
||||
'client_session_id' => $sessionId,
|
||||
'stripe_status' => $session->status,
|
||||
'payment_status' => $session->payment_status,
|
||||
'our_status' => $payment->status
|
||||
]);
|
||||
|
||||
if ($session->payment_status === 'paid' && $session->status === 'complete') {
|
||||
// Payment confirmed, update our record
|
||||
$payment->update(['status' => 'succeeded']);
|
||||
\Log::info('Payment status updated to succeeded via direct Stripe check', [
|
||||
'client_session_id' => $sessionId,
|
||||
'payment_id' => $payment->id
|
||||
]);
|
||||
} else {
|
||||
// Payment still pending or failed
|
||||
\Log::warning('Payment not complete', [
|
||||
'client_session_id' => $sessionId,
|
||||
'stripe_status' => $session->status,
|
||||
'payment_status' => $session->payment_status
|
||||
]);
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Payment is still being processed or failed. Please wait or try again.',
|
||||
'status' => $session->payment_status
|
||||
], 202);
|
||||
}
|
||||
$payment->update(['status' => 'succeeded']);
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('Stripe session retrieval failed: ' . $e->getMessage());
|
||||
return response()->json(['success' => false, 'message' => 'Validation error.'], 500);
|
||||
\Log::error('Stripe session retrieval failed in getCards: ' . $e->getMessage(), [
|
||||
'client_session_id' => $sessionId,
|
||||
'payment_id' => $payment->id,
|
||||
'exception' => $e
|
||||
]);
|
||||
return response()->json(['success' => false, 'message' => 'Unable to verify payment status.'], 500);
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Securely draw the cards and store them
|
||||
$drawnCards = $this->cardRepository->draw($payment->draw_count);
|
||||
$payment->update([
|
||||
'cards' => $drawnCards,
|
||||
'status' => 'processed',
|
||||
]);
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'cards' => $drawnCards,
|
||||
]);
|
||||
// 4. Only proceed if payment is definitely succeeded
|
||||
if ($payment->status !== 'succeeded') {
|
||||
return response()->json(['success' => false, 'message' => 'Payment not completed.'], 402);
|
||||
}
|
||||
|
||||
// 5. Draw the cards and store them atomically
|
||||
try {
|
||||
$drawnCards = $this->cardRepository->draw($payment->draw_count);
|
||||
$payment->update([
|
||||
'cards' => $drawnCards,
|
||||
'status' => 'processed',
|
||||
'processed_at' => now(),
|
||||
]);
|
||||
|
||||
\Log::info('Cards drawn successfully', [
|
||||
'client_session_id' => $sessionId,
|
||||
'payment_id' => $payment->id,
|
||||
'draw_count' => $payment->draw_count
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'cards' => $drawnCards,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
\Log::error('Card drawing failed: ' . $e->getMessage(), [
|
||||
'client_session_id' => $sessionId,
|
||||
'payment_id' => $payment->id,
|
||||
'exception' => $e
|
||||
]);
|
||||
return response()->json(['success' => false, 'message' => 'Failed to draw cards.'], 500);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -34,31 +34,67 @@ class WebhookController extends Controller
|
||||
$session = $event->data->object;
|
||||
$clientSessionId = $session->metadata->client_session_id;
|
||||
|
||||
Log::info('Processing checkout.session.completed webhook', [
|
||||
'client_session_id' => $clientSessionId,
|
||||
'session_id' => $session->id,
|
||||
'payment_status' => $session->payment_status,
|
||||
'status' => $session->status
|
||||
]);
|
||||
|
||||
$payment = Payment::where('client_session_id', $clientSessionId)->first();
|
||||
|
||||
if ($payment) {
|
||||
// Update the payment status to succeeded regardless of current status
|
||||
// This ensures webhook updates work even if user already processed the payment
|
||||
$updateData = ['status' => 'succeeded'];
|
||||
|
||||
if (isset($session->metadata->type_appointment) && $session->metadata->type_appointment === 'true') {
|
||||
$dateTimeObj = new DateTime($session->metadata->appointment_date);
|
||||
$payment->update([
|
||||
'status' => 'succeeded',
|
||||
'appointment_date' => $dateTimeObj->format('Y-m-d')
|
||||
]);
|
||||
$updateData['appointment_date'] = $dateTimeObj->format('Y-m-d');
|
||||
} else {
|
||||
// Original logic for other payments
|
||||
$drawCount = $session->metadata->draw_count;
|
||||
$payment->update([
|
||||
'status' => 'succeeded',
|
||||
'draw_count' => $drawCount,
|
||||
]);
|
||||
// Ensure draw_count is set correctly for card payments
|
||||
if (isset($session->metadata->draw_count)) {
|
||||
$updateData['draw_count'] = $session->metadata->draw_count;
|
||||
}
|
||||
}
|
||||
|
||||
$payment->update($updateData);
|
||||
|
||||
Log::info('Payment status updated via webhook', [
|
||||
'client_session_id' => $clientSessionId,
|
||||
'payment_id' => $payment->id,
|
||||
'new_status' => 'succeeded'
|
||||
]);
|
||||
} else {
|
||||
// Log if no matching payment record is found
|
||||
Log::warning('No pending payment record found for client_session_id: ' . $clientSessionId);
|
||||
Log::warning('No payment record found for webhook processing', [
|
||||
'client_session_id' => $clientSessionId,
|
||||
'stripe_session_id' => $session->id
|
||||
]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'checkout.session.async_payment_failed':
|
||||
case 'checkout.session.expired':
|
||||
$session = $event->data->object;
|
||||
$clientSessionId = $session->metadata->client_session_id ?? null;
|
||||
|
||||
if ($clientSessionId) {
|
||||
$payment = Payment::where('client_session_id', $clientSessionId)->first();
|
||||
if ($payment) {
|
||||
$payment->update(['status' => 'failed']);
|
||||
Log::info('Payment marked as failed via webhook', [
|
||||
'client_session_id' => $clientSessionId,
|
||||
'payment_id' => $payment->id,
|
||||
'event_type' => $event->type
|
||||
]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
Log::info('Received a non-checkout.session.completed webhook event: ' . $event->type);
|
||||
Log::info('Received unhandled webhook event', ['event_type' => $event->type]);
|
||||
break;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
|
||||
@ -5,6 +5,7 @@ use Inertia\Inertia;
|
||||
use App\Models\Payment;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\CardImportController;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
Route::get('/', function () {
|
||||
return Inertia::render('Landing');
|
||||
@ -47,11 +48,19 @@ Route::get('paiement', function () {
|
||||
Route::get('/success', function (Request $request) {
|
||||
$clientSessionId = $request->query('client_session_id');
|
||||
|
||||
$payment = Payment::where('client_session_id', $clientSessionId)
|
||||
->where('status', 'succeeded') // Only check for succeeded payments
|
||||
->first();
|
||||
if (!$clientSessionId) {
|
||||
return Inertia::render('payments/Error', ['message' => 'Invalid payment session.']);
|
||||
}
|
||||
|
||||
if ($payment) {
|
||||
$payment = Payment::where('client_session_id', $clientSessionId)->first();
|
||||
|
||||
if (!$payment) {
|
||||
Log::warning('Payment record not found on success page', ['client_session_id' => $clientSessionId]);
|
||||
return Inertia::render('payments/Error', ['message' => 'Payment record not found.']);
|
||||
}
|
||||
|
||||
// If payment is already succeeded in our database
|
||||
if ($payment->status === 'succeeded') {
|
||||
return Inertia::render('payments/Success', [
|
||||
'paymentSuccess' => true,
|
||||
'drawCount' => $payment->draw_count,
|
||||
@ -59,18 +68,63 @@ Route::get('/success', function (Request $request) {
|
||||
]);
|
||||
}
|
||||
|
||||
// If payment not found as succeeded, check if it's pending (especially for Wise)
|
||||
$pendingPayment = Payment::where('client_session_id', $clientSessionId)->first();
|
||||
// If payment is pending, check with Stripe to handle race condition
|
||||
if ($payment->status === 'pending') {
|
||||
try {
|
||||
\Stripe\Stripe::setApiKey(env('STRIPE_SECRET_KEY'));
|
||||
$session = \Stripe\Checkout\Session::retrieve($clientSessionId);
|
||||
|
||||
if ($pendingPayment && $pendingPayment->status === 'pending') {
|
||||
return Inertia::render('payments/Pending', [
|
||||
'message' => 'Payment is being processed. Please wait...',
|
||||
'clientSessionId' => $clientSessionId,
|
||||
'paymentProvider' => $pendingPayment->payment_provider ?? 'stripe'
|
||||
if ($session->payment_status === 'paid' && $session->status === 'complete') {
|
||||
// Payment confirmed, update our record
|
||||
$payment->update(['status' => 'succeeded']);
|
||||
|
||||
Log::info('Payment status updated on success page via direct Stripe check', [
|
||||
'client_session_id' => $clientSessionId,
|
||||
'payment_id' => $payment->id
|
||||
]);
|
||||
|
||||
return Inertia::render('payments/Success', [
|
||||
'paymentSuccess' => true,
|
||||
'drawCount' => $payment->draw_count,
|
||||
'paymentProvider' => $payment->payment_provider ?? 'stripe'
|
||||
]);
|
||||
}
|
||||
|
||||
// Payment still pending, show pending page
|
||||
return Inertia::render('payments/Pending', [
|
||||
'message' => 'Payment is still being processed. Please wait...',
|
||||
'clientSessionId' => $clientSessionId,
|
||||
'paymentProvider' => $payment->payment_provider ?? 'stripe'
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Stripe session check failed on success page: ' . $e->getMessage(), [
|
||||
'client_session_id' => $clientSessionId,
|
||||
'payment_id' => $payment->id
|
||||
]);
|
||||
|
||||
// Show pending page on Stripe check failure
|
||||
return Inertia::render('payments/Pending', [
|
||||
'message' => 'Verifying payment status. Please wait...',
|
||||
'clientSessionId' => $clientSessionId,
|
||||
'paymentProvider' => $payment->payment_provider ?? 'stripe'
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
// Payment failed or cancelled
|
||||
if ($payment->status === 'failed') {
|
||||
return Inertia::render('payments/Error', [
|
||||
'message' => 'Payment failed. Please try again.',
|
||||
'paymentProvider' => $payment->payment_provider ?? 'stripe'
|
||||
]);
|
||||
}
|
||||
|
||||
return Inertia::render('payments/Error', ['message' => 'Payment validation failed.']);
|
||||
// Any other status
|
||||
return Inertia::render('payments/Error', [
|
||||
'message' => 'Payment status: ' . $payment->status,
|
||||
'paymentProvider' => $payment->payment_provider ?? 'stripe'
|
||||
]);
|
||||
})->name('payment.success');
|
||||
|
||||
Route::get('/rendez-vous/success', function (Request $request){
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user