RAPPEL_STRIPE_PAIEMENTS
Récapitulatif – Stripe & Paiements (Checkout, Abonnements)
Ce qui a été fait
1. Terminal de paiement invisible
- Checkout (
/checkout) : pas de redirection Stripe Checkout. Tout reste sur le site. - Stripe Elements : Payment Element pour enregistrer la carte (SetupIntent), puis débit via PaymentIntent
off_sessioncôté serveur. - Adresse / code postal :
fields.billingDetails.address: 'never'sur le Payment Element → plus de collecte ni de vérification postale (évite l’erreur "code postal ne correspond pas"). - Prix : gérés en PHP/Laravel (Tarif, CustomPrice, CalculMontantDuService). Stripe exécute des débits pour des montants variables.
2. Accès au Checkout
- Liens visibles :
- Nav dashboard (desktop) : « Espace Paiement » →
/checkout - Nav paramètres (desktop) : « Espace Paiement » →
/checkout - Burger mobile (dashboard / paramètres) : « Espace Paiement » →
/checkout
- Nav dashboard (desktop) : « Espace Paiement » →
- Depuis l’onglet Abonnement : « Payer maintenant », « Modifier la carte », « Ajouter une carte », « Régler », « Voir toutes les échéances et payer » →
/checkout.
3. Onglet Abonnement (Paramètres / Dashboard)
- Cartes : affichage •••• XXXX, « Modifier » / « Ajouter une carte » → checkout.
- Factures : uniquement factures Stripe payées et montant > 0 (
status === 'paid'etamount_paid > 0). Plus de factures « fantômes » ou $0 quand aucun paiement. - Derniers paiements : échéances payées +
StripeTransaction, dédupliqués. - Prochains paiements : échéances à payer, avec « Régler » et « Annuler » (annulation =
statut → annulé, pas de débit).
4. Audit verbose (protection légale)
- Table
payment_audit_log:action,user_id,stripe_*,amount,currency,status,ip_address,user_agent,request_id,context(JSON),message. - Actions loguées :
setup_intent_created,save_pm_ok,save_pm_fail,charge_ok,charge_fail,charge_3ds,confirm_status_ok,confirm_status_fail. - Consultation : Admin → Paiements → « Journal d’audit paiements (verbose) », ou
/admin/payment-audit-log. Filtres : membre, action, Payment Intent, dates.
5. Mobile
- Barre d’onglets scrollable (Settings + Dashboard) pour naviguer entre les onglets sur mobile.
- Cartes, factures, derniers / prochains paiements, checkout : padding, boutons
min-h-[44px],touch-manipulation, mise en page responsive.
Ce qu’il faut pour que ça marche à 100 %
.env:STRIPE_KEY,STRIPE_SECRET,STRIPE_WEBHOOK_SECRETcorrects.- Migrations :
php artisan migrate(dontpayment_audit_log,stripe_transactions,echeances, etc.). - Webhook :
payment_intent.succeededconfiguré et pointant vers votre handler. Réconciliation via webhook + vérification API + CRON. - CRON :
subscriptions:check-echeancesetsubscriptions:reconcile-echeancesplanifiés (ex. daily). - Checkout : utilisateur authentifié, avec droit d’accès au checkout (même règles que l’onglet abonnement).
Probabilités de bug / à surveiller
| Risque | Probabilité | Mitigation |
|--------|-------------|------------|
| Webhook payment_intent.succeeded non reçu ou en erreur | Moyenne | Vérification directe Stripe après 3DS + CRON de réconciliation. |
| 3DS non terminée (fermeture avant redirect) | Faible | Échéance reste en_attente, CRON peut réconcilier si paiement finalisé côté Stripe. |
| Carte refusée (fonds, 3DS échouée) | Normal | Erreur renvoyée au client, charge_fail dans l’audit. |
| Doublon charge (double clic « Régler ») | Faible | Bouton désactivé pendant le traitement ; idempotence côté Stripe (même echeance_id dans metadata). |
| Factures Stripe sans paiement réel | Réduit | Filtre paid + amount_paid > 0 ; plus d’affichage de factures $0 ou brouillons. |
| Erreur « code postal ne correspond pas » | Réduit | address: 'never' sur le Payment Element. |
| Impossible de trouver le Checkout | Réduit | Liens « Espace Paiement » dans nav, burger et onglet abonnement. |
Vérifier qu’il n’y a pas de bug
- Audit : aller sur
/admin/payment-audit-log, filtrer par utilisateur ou par action. Vérifier que chaquecharge_ok/confirm_status_oka uncharge_failouconfirm_status_failcohérent en cas d’échec. - Échéances : Admin → Paiements → voir les statuts (à payer, en attente, payé, échec, annulé, arrêté).
- Stripe Dashboard : Logs des webhooks, paiements (Payment Intents), clients.
- Logs Laravel :
storage/logs/laravel.logpour erreurs Stripe, vérification, réconciliation.
Fichiers principaux
- Checkout :
CheckoutController,resources/views/checkout/index.blade.php,resources/js/checkout.js - SetupIntent / save PM / charge :
CheckoutController(+StripeCustomerService),PaymentVerificationService - Abonnement :
resources/views/partials/settings/subscription-tab.blade.php,SettingsController,DashboardController - Audit :
PaymentAuditLog,app/Http/Controllers/Admin/PaymentAuditLogController,resources/views/admin/payment-audit-log/index.blade.php - Factures (filtre) :
SettingsController,DashboardController(filterpaid+amount_paid > 0)
À faire éventuellement (tâches restantes)
- p6 : Désactiver reçus Stripe + envoi d’email de confirmation d’échéance.
- p7 : Webhook
payment_intent.succeeded+ réconciliation dédiée. - p8 : Nettoyage Checkout Session, tests admin, CRON.