# FLOW STRIPE - DOCUMENTATION TECHNIQUE COMPLรˆTE ## ๐ŸŽฏ Vue d'ensemble Ce document dรฉtaille le flow complet des paiements Stripe dans l'application GEOSECTOR, incluant la crรฉation des comptes Stripe Connect pour les amicales, les paiements web et Tap to Pay via l'application Flutter. --- ## ๐Ÿ›๏ธ FLOW STRIPE CONNECT - CRร‰ATION COMPTE AMICALE ### ๐Ÿ”„ Processus de crรฉation et configuration Le systรจme utilise **Stripe Connect** pour permettre ร  chaque amicale de recevoir directement ses paiements sur son propre compte bancaire. ### ๐Ÿ“‹ Prรฉrequis et conditions #### Configuration requise - **Plateforme** : Web uniquement (pas disponible sur mobile) - **Rรดle utilisateur** : Admin amicale (rรดle โ‰ฅ 2) minimum - **Statut amicale** : Amicale existante avec donnรฉes complรจtes #### Vรฉrifications automatiques ```dart // Contrรดles avant activation Stripe if (!kIsWeb) { // Afficher dialog "Configuration Web requise" return; } if (userRole < 2) { // Seuls les admins d'amicale peuvent configurer Stripe return; } if (amicale == null || amicale.id == 0) { // L'amicale doit exister en base return; } ``` ### ๐Ÿ”„ Diagramme de sรฉquence - Onboarding Stripe Connect ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Admin Web โ”‚ โ”‚ App Web โ”‚ โ”‚ API PHP โ”‚ โ”‚ Stripe โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ [1] โ”‚ Coche "CB acceptรฉ"โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [2] โ”‚ Clic "Configurer" โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [3] โ”‚ โ”‚ POST /stripe/create-account โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ (amicale_data) โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [4] โ”‚ โ”‚ โ”‚ Create Account โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [5] โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ account_id โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [6] โ”‚ โ”‚ โ”‚ Create Onboarding โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [7] โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ onboarding_url โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [8] โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ onboarding_url โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [9] โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ Redirection Stripeโ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [10] โ”‚ STRIPE ONBOARDING โ”‚ โ”‚ โ”‚ โ”‚ ================== โ”‚ โ”‚ โ”‚ โ”‚ โ€ข Infos entreprise โ”‚ โ”‚ โ”‚ โ”‚ โ€ข Infos bancaires โ”‚ โ”‚ โ”‚ โ”‚ โ€ข Vรฉrifications โ”‚ โ”‚ โ”‚ โ”‚ ================== โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [11] โ”‚ Retour application โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [12] โ”‚ โ”‚ GET /stripe/statusโ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [13] โ”‚ โ”‚ โ”‚ Retrieve Account โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [14] โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ account_status โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [15] โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ status_response โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [16] โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ Affichage statut โ”‚ โ”‚ โ”‚ ``` ### ๐Ÿ“‹ Dรฉtail des รฉtapes #### ร‰tape 1-2 : ACTIVATION INTERFACE **Acteur:** Admin amicale sur interface web **Actions:** - Activation de la checkbox "Accepte les rรจglements en CB" - Clic sur le bouton "Configurer Stripe" - Affichage dialog de confirmation avec informations sur le processus #### ร‰tape 3 : CRร‰ATION DU COMPTE STRIPE **Requรชte:** `POST /api/stripe/create-account` **Payload:** ```json { "amicale_id": 45, "business_name": "Amicale des Pompiers de Paris", "business_type": "non_profit", "email": "contact@pompiers-paris.fr", "phone": "0145123456", "address": { "line1": "123 Rue de la Caserne", "postal_code": "75001", "city": "Paris", "country": "FR" }, "url": "https://app3.geosector.fr/stripe/return", "refresh_url": "https://app3.geosector.fr/stripe/refresh" } ``` #### ร‰tape 4-7 : ONBOARDING STRIPE **Processus cรดtรฉ API:** ```php // 1. Crรฉation du compte Stripe Connect $account = \Stripe\Account::create([ 'type' => 'express', 'country' => 'FR', 'business_type' => 'non_profit', 'company' => [ 'name' => $amicale->name, 'phone' => $amicale->phone, 'address' => [...], ], 'email' => $amicale->email ]); // 2. Crรฉation du lien d'onboarding $onboardingLink = \Stripe\AccountLink::create([ 'account' => $account->id, 'refresh_url' => 'https://app3.geosector.fr/stripe/refresh', 'return_url' => 'https://app3.geosector.fr/stripe/return', 'type' => 'account_onboarding' ]); // 3. Sauvegarde en base $amicale->stripe_id = $account->id; $amicale->save(); return ['onboarding_url' => $onboardingLink->url]; ``` #### ร‰tape 8-11 : ONBOARDING UTILISATEUR **Processus cรดtรฉ Stripe:** 1. **Redirection** vers l'interface Stripe dรฉdiรฉe 2. **Collecte informations** : - Informations lรฉgales de l'amicale - Coordonnรฉes bancaires (IBAN franรงais) - Documents justificatifs si nรฉcessaire - Vรฉrification d'identitรฉ du reprรฉsentant lรฉgal 3. **Validation** automatique ou manuelle par Stripe 4. **Retour** vers l'application GEOSECTOR #### ร‰tape 12-16 : Vร‰RIFICATION STATUT **Requรชte:** `GET /api/stripe/status/{amicale_id}` **Rรฉponse:** ```json { "account_id": "acct_1234567890", "onboarding_completed": true, "can_accept_payments": true, "capabilities": { "card_payments": "active", "transfers": "active" }, "requirements": { "currently_due": [], "pending_verification": [] }, "status_message": "Compte actif - Prรชt pour les paiements", "status_color": "#4CAF50" } ``` ### ๐ŸŽฎ Interface utilisateur et รฉtats #### ร‰tats possibles du compte Stripe | ร‰tat | Description | Interface | Actions | |------|-------------|-----------|---------| | **Non configurรฉ** | Checkbox dรฉcochรฉe | Gris | Cocher la case | | **En cours de config** | Onboarding incomplet | Orange + โณ | Complรฉter sur Stripe | | **Actif** | Prรชt pour paiements | Vert + โœ… | Aucune action requise | | **En attente** | Vรฉrifications Stripe | Orange + โš ๏ธ | Attendre validation | | **Rejetรฉ** | Compte refusรฉ | Rouge + โŒ | Contacter support | #### Affichage dynamique **1. CONFIGURATION NON Dร‰MARRร‰E** ``` โ˜ Accepte les rรจglements en CB [Configurer Stripe] ๐Ÿ’ณ Activez les paiements par carte bancaire pour vos membres ``` **2. CONFIGURATION EN COURS** ``` โ˜‘ Accepte les rรจglements en CB [โณ Configuration en cours] [โš ๏ธ Tooltip: "Veuillez complรฉter..."] โณ Configuration Stripe en cours. Veuillez complรฉter le processus d'onboarding. ``` **3. COMPTE ACTIF** ``` โ˜‘ Accepte les rรจglements en CB [โœ… Compte actif] [โœ… Tooltip: "Compte configurรฉ"] โœ… Compte Stripe configurรฉ - 100% des paiements pour votre amicale ``` ### ๐Ÿ” Sรฉcuritรฉ et conformitรฉ #### Conformitรฉ Stripe Connect - **PCI DSS** : Stripe gรจre la conformitรฉ PCI - **KYC/AML** : Vรฉrifications d'identitรฉ automatiques - **Comptes sรฉparรฉs** : Chaque amicale a son propre compte - **Fonds isolรฉs** : Pas de commingling des fonds #### Validation cรดtรฉ serveur ```php // Vรฉrifications obligatoires if (!$user->canManageAmicale($amicaleId)) { throw new UnauthorizedException(); } if (!$amicale->isComplete()) { throw new ValidationException('Amicale incomplรจte'); } if ($amicale->stripe_id && $this->stripeService->accountExists($amicale->stripe_id)) { throw new ConflictException('Compte dรฉjร  existant'); } ``` ### ๐Ÿ“Š Suivi et monitoring #### Mรฉtriques importantes - **Taux de completion** de l'onboarding (objectif > 85%) - **Temps moyen** de configuration (< 10 minutes) - **Taux d'approbation** Stripe (> 95%) - **Dรฉlai d'activation** des comptes #### Logs et audit ```php Log::info('Stripe onboarding started', [ 'amicale_id' => $amicaleId, 'user_id' => $userId, 'account_id' => $accountId ]); Log::info('Stripe account activated', [ 'amicale_id' => $amicaleId, 'account_id' => $accountId, 'capabilities' => $capabilities ]); ``` --- ## ๐Ÿ“ฑ FLOW TAP TO PAY (Application Flutter) ### ๐ŸŽฏ Architecture technique Le flow Tap to Pay repose sur trois composants principaux : 1. **DeviceInfoService** - Vรฉrification de compatibilitรฉ hardware (Android SDK โ‰ฅ 28, NFC disponible) 2. **StripeTapToPayService** - Gestion du SDK Stripe Terminal et des paiements 3. **Backend API** - Endpoints PHP pour les tokens de connexion et PaymentIntents ### ๐Ÿ”„ Diagramme de sรฉquence complet ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ App Flutter โ”‚ โ”‚ DeviceInfo โ”‚ โ”‚ API โ”‚ โ”‚ Stripe โ”‚ โ”‚ SDK Terminal โ”‚ โ”‚ โ”‚ โ”‚ Service โ”‚ โ”‚ PHP โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [1] โ”‚ Login utilisateur โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [2] โ”‚ โ”‚ checkStripeCertification() โ”‚ โ”‚ โ”‚ โ”‚ โ€ข Android SDK โ‰ฅ 28 โ”‚ โ”‚ โ”‚ โ”‚ โ€ข NFC disponible โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [3] โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โœ… Compatible โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [4] โ”‚ Validation form โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ + montant CB โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [5] โ”‚ POST/PUT passage โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [6] โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ Passage ID: 456 โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [7] โ”‚ initialize() โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [8] โ”‚ โ”‚ โ”‚ โ”‚ Terminal.initTerminal() โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ (fetchToken callback) โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [9] โ”‚ โ”‚ โ”‚ POST /terminal/connection-token โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ {amicale_id, stripe_account, location_id} โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [10] โ”‚ โ”‚ โ”‚ CreateConnectionToken โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [11] โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ {secret: "..."}โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [12] โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ Connection Token โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [13] โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ Token delivered to SDK โ”‚ โ”‚ โœ… SDK Ready โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [14] โ”‚ createPaymentIntent() โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ {amount, passage_id, amicale_id} โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [15] โ”‚ โ”‚ โ”‚ Create PaymentIntent โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [16] โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ pi_xxx + secretโ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [17] โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ PaymentIntent ID โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [18] โ”‚ collectPayment() โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [19] โ”‚ โ”‚ โ”‚ โ”‚ discoverReaders() โ”‚ โ”‚ โ”‚ โ”‚ + connectReader() โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [20] โ”‚ โ”‚ โ”‚ โ”‚ collectPaymentMethod() โ”‚ ๐Ÿ’ณ "Prรฉsentez la carte" โ”‚ โ”‚ โณ Attente NFC โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [21] โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ ๐Ÿ“ฑ TAP CARTE โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [22] โ”‚ confirmPayment() โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [23] โ”‚ โ”‚ โ”‚ โ”‚ confirmPaymentIntent() โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [24] โ”‚ โ”‚ โ”‚ โ”‚ โœ… Succeeded โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ Payment Success โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [25] โ”‚ PUT passage/456 โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ {stripe_payment_id: "pi_xxx"} โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [26] โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ โœ… Passage updated โ”‚ โ”‚ โ”‚ โ”‚ ``` ### ๐ŸŽฎ Gestion du Terminal de Paiement #### ร‰tats du Terminal Le terminal de paiement reste affichรฉ jusqu'ร  la rรฉponse dรฉfinitive de Stripe. Il gรจre plusieurs รฉtats : | ร‰tat | Description | Actions disponibles | |------|-------------|-------------------| | `confirming` | Demande confirmation utilisateur | Annuler / Lancer paiement | | `initializing` | Initialisation du SDK | Aucune (attente) | | `awaiting_tap` | Attente carte NFC | Annuler uniquement | | `processing` | Traitement paiement | Aucune (bloquรฉ) | | `success` | Paiement rรฉussi | Fermeture auto (2s) | | `error` | ร‰chec paiement | Annuler / Rรฉessayer | #### Interface utilisateur **1. ATTENTE CARTE** ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Prรฉsentez la carte โ”‚ โ”‚ ๐Ÿ“ฑ โ”‚ โ”‚ [===========] โ”‚ โ† Barre de progression โ”‚ Montant: 20.00โ‚ฌ โ”‚ โ”‚ โ”‚ โ”‚ [Annuler] โ”‚ โ† Seul bouton disponible โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` **2. TRAITEMENT** ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Traitement... โ”‚ โ”‚ โŸณ โ”‚ โ† Spinner โ”‚ Ne pas retirer โ”‚ โ”‚ la carte โ”‚ โ”‚ โ”‚ โ† Pas de bouton โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` **3. Rร‰SULTAT** - **Succรจs** : Message de confirmation + fermeture automatique aprรจs 2 secondes - **Erreur** : Message d'erreur + options Annuler/Rรฉessayer #### Points importants - **Dialog non-dismissible** : `barrierDismissible: false` empรชche la fermeture accidentelle - **Timeout** : 60 secondes pour prรฉsenter la carte, 30 secondes pour le traitement - **Persistence** : Le terminal reste ouvert jusqu'ร  rรฉponse dรฉfinitive de Stripe - **Gestion d'erreur** : Possibilitรฉ de rรฉessayer sans perdre le contexte ### ๐Ÿ”‘ Connection Token - Flow dรฉtaillรฉ Le Connection Token est crucial pour le SDK Stripe Terminal. Il est rรฉcupรฉrรฉ via un callback au moment de l'initialisation. **Code cรดtรฉ App (stripe_tap_to_pay_service.dart:87-89) :** ```dart await Terminal.initTerminal( fetchToken: _fetchConnectionToken, // Callback appelรฉ automatiquement ); ``` **Callback de rรฉcupรฉration (lignes 137-161) :** ```dart Future _fetchConnectionToken() async { debugPrint('๐Ÿ”‘ Rรฉcupรฉration du token de connexion Stripe...'); final response = await ApiService.instance.post( '/stripe/terminal/connection-token', data: { 'amicale_id': CurrentAmicaleService.instance.amicaleId, 'stripe_account': _stripeAccountId, 'location_id': _locationId, } ); final token = response.data['secret']; if (token == null || token.isEmpty) { throw Exception('Token de connexion invalide'); } debugPrint('โœ… Token de connexion rรฉcupรฉrรฉ'); return token; } ``` **Backend PHP :** ```php // POST /stripe/terminal/connection-token $token = \Stripe\Terminal\ConnectionToken::create([], [ 'stripe_account' => $amicale->stripe_id, ]); return response()->json([ 'secret' => $token->secret, ]); ``` **Points importants :** - โœ… Le token est **temporaire** (valide quelques minutes) - โœ… Un nouveau token est crรฉรฉ ร  **chaque initialisation** du SDK - โœ… Le token est spรฉcifique au **compte Stripe Connect** de l'amicale - โœ… Utilisรฉ pour **authentifier** le Terminal SDK auprรจs de Stripe ### ๐Ÿ“‹ Dรฉtail des รฉtapes #### ร‰tape 1 : VALIDATION DU FORMULAIRE **Acteur:** Application Flutter **Actions:** - L'utilisateur remplit le formulaire de passage complet - Saisie du montant du don - Sรฉlection du mode de paiement "Carte Bancaire" - Validation de tous les champs obligatoires #### ร‰tape 2 : SAUVEGARDE DU PASSAGE **Requรชte:** `POST /api/passages` (nouveau) ou `PUT /api/passages/{id}` (modification) **Payload:** ```json { "numero": "10", "rue": "Rue de la Paix", "ville": "Paris", "montant": "20.00", "fk_type_reglement": 3, // CB "fk_type": 1, // Effectuรฉ // ... autres champs sans stripe_payment_id } ``` **Rรฉponse:** ```json { "id": 456, // ID rรฉel du passage crรฉรฉ/modifiรฉ "status": "created" } ``` **Note:** Le passage est TOUJOURS sauvegardรฉ en premier pour obtenir un ID rรฉel. #### ร‰tape 3 : DEMANDE DE PAYMENT INTENT **Requรชte:** `POST /api/stripe/payments/create-intent` **Payload envoyรฉ par l'app:** ```json { "amount": 2000, // Montant en centimes (20โ‚ฌ) "currency": "eur", "payment_method_types": ["card_present"], // Pour Tap to Pay "passage_id": 456, // ID Rร‰EL du passage sauvegardรฉ "amicale_id": 45, // ID de l'amicale "member_id": 67, // ID du membre pompier "stripe_account": "acct_1234", // Compte Stripe Connect "location_id": "loc_xyz", // Location Terminal (optionnel) "metadata": { "passage_id": "456", // ID rรฉel, jamais 0 "amicale_name": "Pompiers de Paris", "member_name": "Jean Dupont", "type": "tap_to_pay" } } ``` #### ร‰tape 4 : CRร‰ATION Cร”Tร‰ STRIPE **Acteur:** API PHP โ†’ Stripe **Actions de l'API:** 1. Validation des donnรฉes reรงues 2. Vรฉrification des permissions utilisateur 3. Appel Stripe API : ```php $paymentIntent = \Stripe\PaymentIntent::create([ 'amount' => 2000, 'currency' => 'eur', 'payment_method_types' => ['card_present'], 'capture_method' => 'automatic', 'metadata' => [ 'passage_id' => '123', 'amicale_id' => '45', 'member_id' => '67' ] ], ['stripe_account' => 'acct_1234']); ``` #### ร‰tape 5 : RETOUR DU PAYMENT INTENT **Rรฉponse API โ†’ App:** ```json { "success": true, "payment_intent_id": "pi_3O123abc", "client_secret": "pi_3O123abc_secret_xyz", "amount": 2000, "status": "requires_payment_method" } ``` #### ร‰tape 6 : COLLECTE NFC **Acteur:** Application Flutter (SDK Stripe Terminal) **Actions:** 1. Initialisation du Terminal SDK 2. Activation du NFC 3. Affichage interface "Approchez la carte" 4. Lecture des donnรฉes de la carte 5. Animation visuelle pendant la lecture #### ร‰tape 7 : TRAITEMENT STRIPE **Acteur:** SDK โ†’ Stripe **Actions automatiques:** - Envoi sรฉcurisรฉ des donnรฉes carte - Vรฉrification 3D Secure si nรฉcessaire - Autorisation bancaire - Capture automatique du paiement - Retour du statut ร  l'application #### ร‰tape 8 : CONFIRMATION **Requรชte:** `POST /api/stripe/payments/confirm` **Payload:** ```json { "payment_intent_id": "pi_3O123abc", "status": "succeeded", "amount": 2000, "amicale_id": 45, "member_id": 67 } ``` **Note importante:** Cette confirmation est envoyรฉe AVANT la sauvegarde du passage. Elle permet ร  l'API de : - Tracker la tentative de paiement - Vรฉrifier la cohรฉrence avec Stripe - Enregistrer le succรจs/รฉchec indรฉpendamment du passage #### ร‰tape 9 : MISE ร€ JOUR DU PASSAGE **Requรชte:** `PUT /api/passages/456` **Payload:** ```json { "id": 456, "stripe_payment_id": "pi_3O123abc", // Ajout du payment ID // ... autres champs inchangรฉs } ``` **Note:** Seul le `stripe_payment_id` est ajoutรฉ au passage dรฉjร  existant. #### ร‰tape 10 : CONFIRMATION FINALE **Rรฉponse API โ†’ App:** ```json { "success": true, "passage": { "id": 123, "stripe_payment_id": "pi_3O123abc", "status": "completed" } } ``` --- ## ๐Ÿ“ฑ FLOW PAIEMENT QR CODE (Web + Mobile) ### ๐ŸŽฏ Vue d'ensemble Le paiement par QR Code permet aux clients de payer directement avec leur tรฉlรฉphone en scannant un code QR gรฉnรฉrรฉ par l'application. Cette mรฉthode fonctionne sur **Web et Mobile** et ne nรฉcessite pas de matรฉriel spรฉcifique. ### ๐Ÿ”„ Diagramme de sรฉquence complet ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ App Flutter โ”‚ โ”‚ API PHP โ”‚ โ”‚ Stripe โ”‚ โ”‚ Client โ”‚ โ”‚ Passage โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [1] โ”‚ Validation form โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ + montant CB โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [2] โ”‚ POST/PUT passage โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [3] โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ Passage ID: 456 โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [4] โ”‚ Vรฉrif Stripe โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ chkStripe=true โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ + stripeId rempli โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [5] โ”‚ Dialog Sรฉlection โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ "Rรจglement CB" โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [QRCode|TapToPay] โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [6] โ”‚ Clic "QR Code" โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [7] โ”‚ POST payment-linksโ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ (passage_id: 456)โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [8] โ”‚ โ”‚ Create PaymentLink โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [9] โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ link_id + url โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [10] โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ PaymentLink data โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [11] โ”‚ Gรฉnรฉration QR โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ avec URL Stripe โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [12] โ”‚ Affichage dialog โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ QR Code โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ QR Code โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–“โ–“โ–“โ–“โ–“โ–“โ–“โ–“ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 20.00 โ‚ฌ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [13] โ”‚ โ”‚ โ”‚ Scan QR Code โ”‚ โ”‚ โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [14] โ”‚ โ”‚ โ”‚ Page paiement โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ Stripe hosted โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [15] โ”‚ โ”‚ โ”‚ Saisie CB โ”‚ โ”‚ โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [16] โ”‚ โ”‚ โ”‚ Validation โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [17] โ”‚ โ”‚ Webhook โ”‚ โ”‚ โ”‚ โ”‚ โ”‚<โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ payment_succeededโ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [18] โ”‚ โ”‚ Update passage โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ stripe_payment_idโ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ [19] โ”‚ โ”‚ โ”‚ Confirmation โ”‚ โ”‚ โ”‚ โ”‚ โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€>โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ "Merci!" โ”‚ โ”‚ ``` ### ๐Ÿ“‹ Dรฉtail des รฉtapes #### ร‰tape 1-3 : SAUVEGARDE DU PASSAGE **Identique au flow Tap to Pay** - Le passage est toujours crรฉรฉ en premier pour obtenir un ID rรฉel. #### ร‰tape 4 : Vร‰RIFICATION STRIPE **Acteur:** Application Flutter **Conditions vรฉrifiรฉes:** ```dart final amicale = CurrentAmicaleService.instance.currentAmicale; final stripeEnabled = amicale?.chkStripe == true && amicale?.stripeId != null && amicale!.stripeId.isNotEmpty; if (stripeEnabled && fkTypeReglement == 3 && montant > 0) { // Afficher dialog de sรฉlection de mรฉthode } ``` #### ร‰tape 5 : DIALOG DE Sร‰LECTION DE Mร‰THODE **Widget:** `PaymentMethodSelectionDialog` **Interface affichรฉe:** ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Rรจglement CB โ”‚ โ”‚ โ”‚ โ”‚ ๐Ÿ‘ค Jean Dupont โ”‚ โ”‚ ๐Ÿ’ฐ 20.00 โ‚ฌ โ”‚ โ”‚ โ”‚ โ”‚ Sรฉlectionnez une mรฉthode : โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ ๐Ÿ“ฑ Paiement par QR Code โ”‚ โ”‚ โ”‚ โ”‚ Le client scanne le code โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ (Si compatible) โ”‚ โ”‚ ๐Ÿ’ณ Tap to Pay โ”‚ โ”‚ โ”‚ โ”‚ Paiement sans contact โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ ๐Ÿ”’ Sรฉcurisรฉ par Stripe โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` #### ร‰tape 6-10 : CRร‰ATION DU PAYMENT LINK **Requรชte:** `POST /api/stripe/payment-links` **Payload:** ```json { "amount": 2000, "currency": "eur", "description": "Calendrier pompiers - Jean Dupont", "passage_id": 456, "metadata": { "passage_id": "456", "habitant_name": "Jean Dupont", "adresse": "10 Rue de la Paix, Paris" } } ``` **Rรฉponse:** ```json { "success": true, "payment_link_id": "plink_1234567890", "url": "https://buy.stripe.com/test_xxxxxxxxxxxxx", "amount": 2000, "passage_id": 456 } ``` **Code PHP Backend:** ```php $paymentLink = \Stripe\PaymentLink::create([ 'line_items' => [[ 'price_data' => [ 'currency' => 'eur', 'product_data' => [ 'name' => 'Calendrier pompiers', ], 'unit_amount' => 2000, ], 'quantity' => 1, ]], 'metadata' => [ 'passage_id' => '456', 'type' => 'qr_code_payment', ], 'after_completion' => [ 'type' => 'hosted_confirmation', 'hosted_confirmation' => [ 'custom_message' => 'Merci pour votre paiement !', ], ], ], [ 'stripe_account' => $amicale->stripe_id, ]); ``` #### ร‰tape 11-12 : AFFICHAGE DU QR CODE **Widget:** `QRCodePaymentDialog` **Interface:** ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Paiement par QR Code โ”‚ โ”‚ โ”‚ โ”‚ ๐Ÿ’ฐ 20.00 โ‚ฌ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–“โ–“โ–“โ–“โ–“ โ–“โ–“โ–“โ–“โ–“โ–“โ–“ โ”‚ โ”‚ โ”‚ โ”‚ โ–“โ–“โ–“โ–“โ–“ โ–“โ–“ โ–“โ–“ โ”‚ โ”‚ โ”‚ โ”‚ โ–“โ–“โ–“โ–“โ–“ โ–“โ–“โ–“โ–“โ–“โ–“โ–“ โ”‚ โ”‚ โ”‚ โ”‚ QR CODE HERE โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ Scannez ce QR code avec โ”‚ โ”‚ votre tรฉlรฉphone โ”‚ โ”‚ โ”‚ โ”‚ Vous serez redirigรฉ vers โ”‚ โ”‚ une page sรฉcurisรฉe Stripe โ”‚ โ”‚ โ”‚ โ”‚ ๐Ÿ”’ Paiement sรฉcurisรฉ โ”‚ โ”‚ โ”‚ โ”‚ [Fermer] โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` #### ร‰tape 13-16 : PAIEMENT CLIENT **Acteur:** Client final **Actions:** 1. Scan du QR Code avec son smartphone 2. Ouverture automatique de l'URL Stripe dans le navigateur 3. Affichage de la page de paiement Stripe hรฉbergรฉe 4. Saisie des informations de carte bancaire 5. Validation 3D Secure si nรฉcessaire 6. Confirmation du paiement #### ร‰tape 17-18 : WEBHOOK ET MISE ร€ JOUR **Requรชte Webhook:** `POST /api/stripe/webhook` **Event:** `checkout.session.completed` ou `payment_intent.succeeded` **Payload Stripe:** ```json { "type": "payment_intent.succeeded", "data": { "object": { "id": "pi_1234567890", "amount": 2000, "metadata": { "passage_id": "456" } } } } ``` **Action Backend:** ```php // Rรฉcupรฉrer le passage $passage = Passage::find($paymentIntent->metadata->passage_id); // Mettre ร  jour avec le payment ID $passage->stripe_payment_id = $paymentIntent->id; $passage->save(); Log::info('Payment confirmed via QR Code', [ 'passage_id' => $passage->id, 'payment_id' => $paymentIntent->id, ]); ``` ### ๐Ÿ”„ Comparaison QR Code vs Tap to Pay | Aspect | QR Code | Tap to Pay | |--------|---------|------------| | **Plateformes** | Web + Mobile | Mobile uniquement | | **Matรฉriel requis** | Aucun | NFC (iPhone XS+ / Android certifiรฉ) | | **Client utilise** | Son propre tรฉlรฉphone | Le tรฉlรฉphone du pompier | | **payment_method_types** | `["card"]` | `["card_present"]` | | **Interface paiement** | Page Stripe hรฉbergรฉe | NFC sur l'app | | **Dรฉlai confirmation** | Immรฉdiat (webhook) | Immรฉdiat (SDK) | | **Expรฉrience client** | Scan + saisie CB | Approche carte | | **Sans contact physique** | โœ… Oui (COVID-safe) | โŒ Non (proximitรฉ requise) | | **Montant minimum** | 0.50โ‚ฌ | 1.00โ‚ฌ | | **Cas d'usage idรฉal** | Client ร  distance | Face ร  face | ### โœ… Conditions d'รฉligibilitรฉ #### Affichage du bouton "QR Code" ```dart // Conditions cumulatives : final canShowQRCode = amicale.chkStripe == true && // Stripe activรฉ amicale.stripeId.isNotEmpty && // Compte configurรฉ fkTypeReglement == 3 && // CB sรฉlectionnรฉe montant > 0; // Montant valide ``` #### Diffรฉrences avec Tap to Pay - **Pas besoin de** `stripeLocationId` (spรฉcifique Terminal) - **Pas de vรฉrification** device (fonctionne partout) - **Pas de batterie** minimum requise ### ๐ŸŽจ Widgets crรฉรฉs #### 1. PaymentMethodSelectionDialog **Fichier:** `lib/presentation/widgets/payment_method_selection_dialog.dart` **Rรดle:** Choisir entre QR Code et Tap to Pay **Props:** ```dart PaymentMethodSelectionDialog({ required PassageModel passage, required double amount, required String habitantName, required StripeConnectService stripeConnectService, VoidCallback? onTapToPaySelected, }) ``` #### 2. QRCodePaymentDialog **Fichier:** `lib/presentation/widgets/qr_code_payment_dialog.dart` **Rรดle:** Afficher le QR Code gรฉnรฉrรฉ **Props:** ```dart QRCodePaymentDialog({ required PaymentLinkResult paymentLink, VoidCallback? onClose, }) ``` ### ๐Ÿ”ง Services modifiรฉs #### StripeConnectService **Nouvelle mรฉthode:** ```dart Future createPaymentLink({ required int amountInCents, required int passageId, String? description, Map? metadata, }) ``` ### ๐Ÿ“Š Modรจles crรฉรฉs #### PaymentLinkResult **Fichier:** `lib/core/data/models/payment_link_result.dart` ```dart class PaymentLinkResult { final String paymentLinkId; final String url; final int amount; final int? passageId; } ``` ### ๐Ÿ” Sรฉcuritรฉ #### Validation Backend ```php // Vรฉrifications obligatoires $request->validate([ 'amount' => 'required|integer|min:50', 'passage_id' => 'required|integer|exists:ope_pass,id', ]); // Vรฉrifier Stripe activรฉ if (!$amicale->chk_stripe || empty($amicale->stripe_id)) { return response()->json(['error' => 'Stripe non activรฉ'], 403); } // Crรฉer sur le compte Connect de l'amicale \Stripe\PaymentLink::create([...], [ 'stripe_account' => $amicale->stripe_id, ]); ``` ### ๐Ÿ“ฑ Package ajoutรฉ **pubspec.yaml:** ```yaml dependencies: qr_flutter: ^4.1.0 # Gรฉnรฉration de QR codes ``` --- ## ๐Ÿ’ป FLOW PAIEMENT WEB ### ๐Ÿ”„ Principales diffรฉrences avec Tap to Pay | Aspect | Web | Tap to Pay | |--------|-----|------------| | **payment_method_types** | `["card"]` | `["card_present"]` | | **SDK** | Stripe.js dans navigateur | Stripe Terminal SDK natif | | **Interface paiement** | Formulaire carte web | NFC tรฉlรฉphone | | **capture_method** | `manual` ou `automatic` | Toujours `automatic` | | **Metadata type** | `"web"` | `"tap_to_pay"` | | **Client secret usage** | Pour Stripe Elements | Pour Terminal SDK | ### ๐Ÿ“‹ Flow Web simplifiรฉ ``` 1. Utilisateur remplit formulaire web avec montant 2. POST /api/stripe/payments/create-intent - payment_method_types: ["card"] - metadata.type: "web" 3. API crรฉe PaymentIntent et retourne client_secret 4. Frontend utilise Stripe.js pour afficher formulaire carte 5. Utilisateur saisit donnรฉes carte 6. Stripe.js confirme le paiement 7. Webhook Stripe notifie l'API du succรจs 8. API met ร  jour le passage en base ``` --- ## ๐Ÿ“ฑ VALIDATION ET CONTRร”LES Cร”Tร‰ APP ### Vรฉrifications avant affichage du Terminal L'application effectue une sรฉrie de vรฉrifications **avant** d'afficher le terminal de paiement : #### 1. Dans le formulaire de passage ```dart void _handleSubmit() { // โœ… Validation des champs du formulaire if (!_formKey.currentState!.validate()) return; // โœ… Vรฉrification CB sรฉlectionnรฉe + montant > 0 if (_fkTypeReglement == 3 && montant > 0) { await _attemptTapToPay(); // Lance le flow } } ``` #### 2. Dans le service StripeTapToPayService ```dart initialize() { // โœ… User connectรฉ if (!CurrentUserService.instance.isLoggedIn) return false; // โœ… Amicale avec Stripe activรฉ if (!amicale.chkStripe || amicale.stripeId.isEmpty) return false; // โœ… Appareil compatible (iPhone XS+, iOS 16.4+) if (!DeviceInfoService.instance.canUseTapToPay()) return false; // โœ… Configuration Stripe rรฉcupรฉrรฉe await _fetchConfiguration(); } ``` #### 3. Dans le Dialog Tap to Pay ```dart _startPayment() { // โœ… Service initialisรฉ ou initialisation rรฉussie if (!initialized) throw Exception('Impossible d\'initialiser'); // โœ… Prรชt pour paiements (toutes conditions remplies) if (!isReadyForPayments()) throw Exception('Appareil non prรชt'); // Crรฉation PaymentIntent et collecte NFC... } ``` ### Flow de sauvegarde et paiement Le nouveau flow garantit que le passage existe TOUJOURS avant le paiement : ```dart // 1. SAUVEGARDE DU PASSAGE EN PREMIER Future _savePassage() { // Crรฉer ou modifier le passage PassageModel? savedPassage; if (widget.passage == null) { // Crรฉation avec retour de l'ID savedPassage = await passageRepository.createPassageWithReturn(passageData); } else { // Modification savedPassage = passageData; } // 2. SI CB Sร‰LECTIONNร‰E, LANCER TAP TO PAY if (typeReglement == CB && montant > 0) { await _attemptTapToPayWithPassage(savedPassage, montant); } } // 3. PAIEMENT AVEC ID Rร‰EL _attemptTapToPayWithPassage(PassageModel passage, double montant) { _TapToPayFlowDialog( passageId: passage.id, // โ† ID rรฉel, jamais 0 onSuccess: (paymentIntentId) { // 4. MISE ร€ JOUR DU PASSAGE final updated = passage.copyWith( stripePaymentId: paymentIntentId ); passageRepository.updatePassage(updated); } ); } ``` ## ๐Ÿ” Sร‰CURITร‰ ET BONNES PRATIQUES ### ๐Ÿ›ก๏ธ Principes de sรฉcuritรฉ 1. **Jamais de donnรฉes carte en clair** - Toujours via SDK Stripe 2. **HTTPS obligatoire** - Toutes communications chiffrรฉes 3. **Validation cรดtรฉ serveur** - Ne jamais faire confiance au client 4. **Tokens temporaires** - Connection tokens ร  durรฉe limitรฉe 5. **Logs sans donnรฉes sensibles** - Pas de numรฉros carte dans les logs ### โœ… Validations requises #### Cรดtรฉ App Flutter: - Vรฉrifier compatibilitรฉ appareil (iPhone XS+, iOS 16.4+) - Valider montant (min 1โ‚ฌ, max 999โ‚ฌ) - Vรฉrifier connexion internet avant paiement - Gรฉrer timeouts rรฉseau #### Cรดtรฉ API: - Authentification utilisateur obligatoire - Vรฉrification appartenance ร  l'amicale - Validation montants et devises - Vรฉrification compte Stripe actif - Rate limiting sur endpoints --- ## ๐Ÿ“Š DOUBLE CONFIRMATION API ### Pourquoi deux appels distincts ? Le systรจme utilise **deux endpoints sรฉparรฉs** pour une meilleure traรงabilitรฉ : #### 1. Confirmation du paiement (`/api/stripe/payments/confirm`) ```json POST /api/stripe/payments/confirm { "payment_intent_id": "pi_xxx", "status": "succeeded", // ou "failed" "amount": 2000 } ``` **Rรดle :** Notifier l'API du rรฉsultat Stripe (succรจs/รฉchec) #### 2. Sauvegarde du passage (`/api/passages`) ```json POST/PUT /api/passages { "stripe_payment_id": "pi_xxx", "montant": "20.00", "fk_type_reglement": 3 // CB } ``` **Rรดle :** Sauvegarder le passage **uniquement si paiement rรฉussi** ### Avantages du nouveau flow | Aspect | Bรฉnรฉfice | |--------|----------| | **Passage toujours crรฉรฉ** | Mรชme si le paiement รฉchoue, le passage existe | | **ID rรฉel dans Stripe** | Les metadata contiennent toujours le vrai `passage_id` | | **Traรงabilitรฉ complรจte** | Liaison bidirectionnelle garantie (passage โ†’ Stripe et Stripe โ†’ passage) | | **Gestion d'erreur robuste** | Si paiement รฉchoue, le passage reste sans `stripe_payment_id` | | **Mode offline** | Le passage peut รชtre crรฉรฉ localement avec ID temporaire | ## ๐Ÿ”„ GESTION DES ERREURS ### ๐Ÿ“ฑ Erreurs Tap to Pay - Messages utilisateur clairs L'application dรฉtecte automatiquement le type d'erreur et affiche un message adaptรฉ : #### Gestion intelligente des erreurs (passage_form_dialog.dart) ```dart catch (e) { final errorMsg = e.toString().toLowerCase(); String userMessage; bool shouldCancelPayment = true; if (errorMsg.contains('canceled') || errorMsg.contains('cancelled')) { // Annulation volontaire userMessage = 'Paiement annulรฉ'; } else if (errorMsg.contains('cardreadtimedout') || errorMsg.contains('timed out')) { // Timeout NFC avec conseils userMessage = 'Lecture de la carte impossible.\n\n' 'Conseils :\n' 'โ€ข Maintenez la carte contre le dos du tรฉlรฉphone\n' 'โ€ข Ne bougez pas jusqu\'ร  confirmation\n' 'โ€ข Retirez la coque si nรฉcessaire\n' 'โ€ข Essayez diffรฉrentes positions sur le tรฉlรฉphone'; } else if (errorMsg.contains('already') && errorMsg.contains('payment')) { // PaymentIntent existe dรฉjร  userMessage = 'Un paiement est dรฉjร  en cours pour ce passage.\n' 'Veuillez rรฉessayer dans quelques instants.'; shouldCancelPayment = false; } // Annulation automatique du PaymentIntent pour permettre nouvelle tentative if (shouldCancelPayment && _paymentIntentId != null) { await StripeTapToPayService.instance.cancelPayment(_paymentIntentId!); } } ``` #### Table des erreurs et actions | Type erreur | Message utilisateur | Action automatique | |-------------|--------------------|--------------------| | `canceled` / `cancelled` | "Paiement annulรฉ" | Annulation PaymentIntent โœ… | | `cardReadTimedOut` | Message avec 4 conseils NFC | Annulation PaymentIntent โœ… | | `already payment` | "Paiement dรฉjร  en cours" | Pas d'annulation โณ | | `device_not_compatible` | "Appareil non compatible" | Annulation PaymentIntent โœ… | | `nfc_disabled` | "NFC dรฉsactivรฉ" | Annulation PaymentIntent โœ… | | Autre erreur | Message technique complet | Annulation PaymentIntent โœ… | ### โš ๏ธ Contraintes NFC - Tap to Pay vs Google Pay **Diffรฉrence fondamentale :** - **Google Pay (รฉmission)** : Le tรฉlรฉphone *รฉmet* un signal NFC puissant โ†’ fonctionne avec coque - **Tap to Pay (rรฉception)** : Le tรฉlรฉphone *lit* le signal de la carte โ†’ trรจs sensible aux interfรฉrences #### Coques problรฉmatiques - โŒ **Kevlar / Carbone** : Fibres conductrices perturbent la rรฉception NFC - โŒ **Mรฉtal** : Bloque complรจtement les ondes NFC - โŒ **Coque รฉpaisse** : Rรฉduit la portรฉe effective - โœ… **TPU / Silicone** : Compatible #### Bonnes pratiques pour rรฉussite NFC **Position optimale :** ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ ๐Ÿ“ฑ Tรฉlรฉphone โ”‚ โ”‚ โ”‚ โ”‚ [Capteur NFC]โ”‚ โ† Gรฉnรฉralement vers le haut du dos โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ ๐Ÿ’ณ Carte ici โ”‚ โ† Maintenir immobile 3-5 secondes โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` **Checklist utilisateur :** 1. โœ… Retirer la coque si รฉchec 2. โœ… Carte ร  plat contre le dos du tรฉlรฉphone 3. โœ… Ne pas bouger pendant toute la lecture 4. โœ… Essayer diffรฉrentes positions (haut/milieu du tรฉlรฉphone) 5. โœ… Carte sans contact activรฉe (logo sans contact visible) ### ๐Ÿ”„ Flow de retry automatique ``` 1. Erreur dรฉtectรฉe โ†’ Analyse du type 2. Annulation automatique PaymentIntent (si applicable) 3. Message clair avec conseils contextuels 4. Bouton "Rรฉessayer" disponible 5. Nouveau PaymentIntent crรฉรฉ automatiquement 6. Conservation du contexte (montant, passage) ``` **Avantages :** - โœ… Pas de blocage "PaymentIntent dรฉjร  existant" - โœ… Nombre illimitรฉ de tentatives - โœ… Contexte prรฉservรฉ (pas besoin de tout ressaisir) - โœ… Messages orientรฉs solution plutรดt qu'erreur technique ### ๐Ÿ—๏ธ Environnement et Build Release #### Dรฉtection automatique de l'environnement L'application dรฉtecte l'environnement via l'URL de l'API (plus fiable que `kDebugMode`) : ```dart // stripe_tap_to_pay_service.dart (lignes 236-252) Future _ensureReaderConnected() async { // Dรฉtection via URL API final apiUrl = ApiService.instance.baseUrl; final isProduction = apiUrl.contains('app3.geosector.fr'); final isSimulated = !isProduction; final config = TapToPayDiscoveryConfiguration( isSimulated: isSimulated, ); debugPrint('๐Ÿ”ง Environnement: ${isProduction ? "PRODUCTION (rรฉel)" : "DEV/REC (simulรฉ)"}'); debugPrint('๐Ÿ”ง isSimulated: $isSimulated'); } ``` **Mapping environnement :** | URL API | Environnement | Reader Stripe | Cartes acceptรฉes | |---------|---------------|---------------|------------------| | `dapp.geosector.fr` | DEV | Simulรฉ | Cartes test uniquement | | `rapp.geosector.fr` | REC | Simulรฉ | Cartes test uniquement | | `app3.geosector.fr` | PROD | Rรฉel | Cartes rรฉelles uniquement | #### โš ๏ธ Restriction Stripe - Build Release obligatoire en PROD **Erreur si app debuggable en PROD :** ``` Debuggable applications are not supported when using the production version of the Tap to Pay reader. Please use a simulated version of the reader by setting TapToPayDiscoveryConfiguration.isSimulated to true. ``` **Solution - Build release :** ```bash # Build APK optimisรฉ pour production flutter build apk --release # Installation sur device adb install build/app/outputs/flutter-apk/app-release.apk ``` **Diffรฉrences debug vs release :** | Aspect | Debug (`flutter run`) | Release (`flutter build`) | |--------|-----------------------|--------------------| | **Optimisation** | โŒ Code non optimisรฉ | โœ… R8/ProGuard activรฉ | | **Taille APK** | ~200 MB | ~30-50 MB | | **Performance** | Lente (dev mode) | Rapide (optimisรฉe) | | **Tap to Pay PROD** | โŒ Refusรฉ par Stripe | โœ… Acceptรฉ | | **Dรฉbogage** | โœ… Hot reload, logs | โŒ Pas de hot reload | **Pourquoi Stripe refuse les apps debug :** - **Sรฉcuritรฉ renforcรฉe** : Les apps debuggables peuvent รชtre inspectรฉes - **Conformitรฉ PCI-DSS** : Exigences de sรฉcuritรฉ pour paiements rรฉels - **Protection production** : ร‰viter utilisation accidentelle de readers rรฉels en dev --- ## ๐Ÿ“Š MONITORING ET LOGS ### ๐Ÿ“ˆ Mรฉtriques ร  suivre 1. **Taux de succรจs** des paiements (objectif > 95%) 2. **Temps moyen** de transaction (< 15 secondes) 3. **Types d'erreurs** les plus frรฉquentes 4. **Appareils utilisรฉs** (modรจles iPhone) 5. **Montants moyens** des transactions ### ๐Ÿ“ Logs essentiels #### App Flutter: ```dart debugPrint('๐Ÿš€ PaymentIntent crรฉรฉ: $paymentIntentId'); debugPrint('๐Ÿ’ณ Collecte NFC dรฉmarrรฉe'); debugPrint('โœ… Paiement confirmรฉ: $amount โ‚ฌ'); debugPrint('โŒ Erreur paiement: $errorCode'); ``` #### API PHP: ```php Log::info('PaymentIntent created', [ 'id' => $paymentIntent->id, 'amount' => $amount, 'amicale_id' => $amicaleId ]); ``` --- ## ๐Ÿš€ OPTIMISATIONS ET PERFORMANCES ### โšก Optimisations implรฉmentรฉes 1. **Cache Box Hive** - ร‰viter accรจs rรฉpรฉtรฉs 2. **Batch API calls** - Grouper les requรชtes 3. **Lazy loading** - Charger donnรฉes ร  la demande 4. **Connection pooling** - Rรฉutiliser connexions HTTP 5. **Queue offline** - File d'attente locale ### ๐ŸŽฏ Points d'amรฉlioration - [ ] Prรฉ-crรฉation PaymentIntent pendant saisie montant - [ ] Cache des configurations Stripe - [ ] Compression des payloads API - [ ] Optimisation animations NFC - [ ] Rรฉduction taille APK/IPA --- ## ๐Ÿ“ฑ COMPATIBILITร‰ APPAREILS ### ๐ŸŽ iOS - Tap to Pay **Appareils compatibles:** - iPhone XS, XS Max, XR - iPhone 11, 11 Pro, 11 Pro Max - iPhone 12, 12 mini, 12 Pro, 12 Pro Max - iPhone 13, 13 mini, 13 Pro, 13 Pro Max - iPhone 14, 14 Plus, 14 Pro, 14 Pro Max - iPhone 15, 15 Plus, 15 Pro, 15 Pro Max - iPhone 16 (tous modรจles) **Prรฉrequis:** - iOS 16.4 minimum - NFC activรฉ - Bluetooth activรฉ (pour certains cas) ### ๐Ÿค– Android - Tap to Pay (V2.2+) **ร€ venir - Liste dynamique via API** - Appareils certifiรฉs Google Pay - Android 9.0+ (API 28+) - NFC requis --- ## ๐Ÿ”— RESSOURCES ET DOCUMENTATION ### ๐Ÿ“š Documentation officielle - [Stripe Terminal Flutter](https://stripe.com/docs/terminal/payments/collect-payment?platform=flutter) - [Stripe PaymentIntents API](https://stripe.com/docs/api/payment_intents) - [Apple Tap to Pay](https://developer.apple.com/tap-to-pay/) - [PCI DSS Compliance](https://stripe.com/docs/security/guide) ### ๐Ÿ› ๏ธ Outils de test - **Cartes de test Stripe**: 4242 4242 4242 4242 - **iPhone Simulator**: Ne supporte pas NFC - **Stripe CLI**: Pour webhooks locaux - **Postman**: Collection API fournie ### ๐Ÿ“ž Support - **Stripe Support**: support@stripe.com - **ร‰quipe Backend**: API PHP GEOSECTOR - **ร‰quipe Mobile**: Flutter GEOSECTOR --- ## ๐Ÿ“… HISTORIQUE DES VERSIONS | Version | Date | Modifications | |---------|------|--------------| | 1.0 | 28/09/2025 | Crรฉation documentation initiale | | 1.1 | 28/09/2025 | Ajout flow complet Tap to Pay | | 1.2 | 28/09/2025 | Intรฉgration passage_id et metadata | | 1.3 | 05/11/2025 | Ajout flow paiement par QR Code | --- *Document technique - Flow Stripe GEOSECTOR* *Derniรจre mise ร  jour : 5 novembre 2025*