feat: Version 3.3.4 - Nouvelle architecture pages, optimisations widgets Flutter et API
- Mise à jour VERSION vers 3.3.4 - Optimisations et révisions architecture API (deploy-api.sh, scripts de migration) - Ajout documentation Stripe Tap to Pay complète - Migration vers polices Inter Variable pour Flutter - Optimisations build Android et nettoyage fichiers temporaires - Amélioration système de déploiement avec gestion backups - Ajout scripts CRON et migrations base de données 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
343
api/docs/STRIPE-TAP-TO-PAY-FLOW.md
Normal file
343
api/docs/STRIPE-TAP-TO-PAY-FLOW.md
Normal file
@@ -0,0 +1,343 @@
|
||||
# Flow de paiement Stripe Tap to Pay
|
||||
|
||||
## Vue d'ensemble
|
||||
|
||||
Ce document décrit le flow complet pour les paiements Stripe Tap to Pay dans l'application GeoSector, depuis la création du compte Stripe Connect jusqu'au paiement final.
|
||||
|
||||
---
|
||||
|
||||
## 🏢 PRÉALABLE : Création d'un compte Amicale Stripe Connect
|
||||
|
||||
Avant de pouvoir utiliser les paiements Stripe, chaque amicale doit créer son compte Stripe Connect.
|
||||
|
||||
### 📋 Flow de création du compte
|
||||
|
||||
#### 1. Initiation depuis l'application web admin
|
||||
|
||||
**Endpoint :** `POST /api/stripe/accounts/create`
|
||||
|
||||
**Requête :**
|
||||
```json
|
||||
{
|
||||
"amicale_id": 45,
|
||||
"type": "express", // Type de compte Stripe Connect
|
||||
"country": "FR",
|
||||
"email": "contact@amicale-pompiers-paris.fr",
|
||||
"business_profile": {
|
||||
"name": "Amicale des Pompiers de Paris",
|
||||
"product_description": "Vente de calendriers des pompiers",
|
||||
"mcc": "8398", // Code activité : organisations civiques
|
||||
"url": "https://www.amicale-pompiers-paris.fr"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. Création du compte Stripe
|
||||
|
||||
**Actions API :**
|
||||
1. Appel Stripe API pour créer un compte Express
|
||||
2. Génération d'un lien d'onboarding personnalisé
|
||||
3. Sauvegarde en base de données
|
||||
|
||||
**Réponse :**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"stripe_account_id": "acct_1O3ABC456DEF789",
|
||||
"onboarding_url": "https://connect.stripe.com/express/oauth/authorize?...",
|
||||
"status": "pending"
|
||||
}
|
||||
```
|
||||
|
||||
#### 3. Processus d'onboarding Stripe
|
||||
|
||||
**Actions utilisateur (dirigeant amicale) :**
|
||||
1. Clic sur le lien d'onboarding
|
||||
2. Connexion/création compte Stripe
|
||||
3. Saisie des informations légales :
|
||||
- **Entité** : Association loi 1901
|
||||
- **SIRET** de l'amicale
|
||||
- **RIB** pour les virements
|
||||
- **Pièce d'identité** du représentant légal
|
||||
4. Validation des conditions d'utilisation
|
||||
|
||||
#### 4. Vérification et activation
|
||||
|
||||
**Webhook Stripe → API :**
|
||||
```json
|
||||
POST /api/stripe/webhooks
|
||||
{
|
||||
"type": "account.updated",
|
||||
"data": {
|
||||
"object": {
|
||||
"id": "acct_1O3ABC456DEF789",
|
||||
"charges_enabled": true,
|
||||
"payouts_enabled": true,
|
||||
"details_submitted": true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Actions API :**
|
||||
1. Mise à jour du statut en base
|
||||
2. Notification email à l'amicale
|
||||
3. Activation des fonctionnalités de paiement
|
||||
|
||||
#### 5. Structure en base de données
|
||||
|
||||
**Table `stripe_accounts` :**
|
||||
```sql
|
||||
CREATE TABLE `stripe_accounts` (
|
||||
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`fk_entite` int(10) unsigned NOT NULL,
|
||||
`stripe_account_id` varchar(50) NOT NULL,
|
||||
`account_type` enum('express','standard','custom') DEFAULT 'express',
|
||||
`charges_enabled` tinyint(1) DEFAULT 0,
|
||||
`payouts_enabled` tinyint(1) DEFAULT 0,
|
||||
`details_submitted` tinyint(1) DEFAULT 0,
|
||||
`country` varchar(2) DEFAULT 'FR',
|
||||
`default_currency` varchar(3) DEFAULT 'eur',
|
||||
`business_name` varchar(255) DEFAULT NULL,
|
||||
`support_email` varchar(255) DEFAULT NULL,
|
||||
`onboarding_completed_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`updated_at` timestamp NULL DEFAULT NULL ON UPDATE current_timestamp(),
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `stripe_account_id` (`stripe_account_id`),
|
||||
KEY `fk_entite` (`fk_entite`),
|
||||
CONSTRAINT `stripe_accounts_ibfk_1` FOREIGN KEY (`fk_entite`) REFERENCES `entites` (`id`)
|
||||
);
|
||||
```
|
||||
|
||||
### 🔐 Sécurité et validation
|
||||
|
||||
#### Prérequis pour créer un compte :
|
||||
- ✅ Utilisateur administrateur de l'amicale
|
||||
- ✅ Amicale active avec statut validé
|
||||
- ✅ Email de contact vérifié
|
||||
- ✅ Informations légales complètes (SIRET, adresse)
|
||||
|
||||
#### Validation avant paiements :
|
||||
- ✅ `charges_enabled = 1` (peut recevoir des paiements)
|
||||
- ✅ `payouts_enabled = 1` (peut recevoir des virements)
|
||||
- ✅ `details_submitted = 1` (onboarding terminé)
|
||||
|
||||
### 📊 États du compte Stripe
|
||||
|
||||
| État | Description | Actions possibles |
|
||||
|------|-------------|-------------------|
|
||||
| `pending` | Compte créé, onboarding en cours | Compléter l'onboarding |
|
||||
| `restricted` | Informations manquantes | Fournir documents manquants |
|
||||
| `restricted_soon` | Vérification en cours | Attendre validation Stripe |
|
||||
| `active` | Compte opérationnel | Recevoir des paiements ✅ |
|
||||
| `rejected` | Compte refusé par Stripe | Contacter support |
|
||||
|
||||
### 🚨 Gestion des erreurs
|
||||
|
||||
#### Erreurs courantes lors de la création :
|
||||
- **400** : Données manquantes ou invalides
|
||||
- **409** : Compte Stripe déjà existant pour cette amicale
|
||||
- **403** : Utilisateur non autorisé
|
||||
|
||||
#### Erreurs durant l'onboarding :
|
||||
- Documents manquants ou invalides
|
||||
- Informations bancaires incorrectes
|
||||
- Activité non autorisée par Stripe
|
||||
|
||||
### 📞 Support et résolution
|
||||
|
||||
#### Pour les amicales :
|
||||
1. **Email support** : support@geosector.fr
|
||||
2. **Documentation** : Guides d'onboarding disponibles
|
||||
3. **Assistance téléphonique** : Disponible aux heures ouvrables
|
||||
|
||||
#### Pour les développeurs :
|
||||
1. **Stripe Dashboard** : Accès aux comptes et statuts
|
||||
2. **Logs API** : Traçabilité complète des opérations
|
||||
3. **Webhook monitoring** : Suivi des événements Stripe
|
||||
|
||||
---
|
||||
|
||||
## 🚨 IMPORTANT : Nouveau Flow (v2)
|
||||
|
||||
**Le passage est TOUJOURS créé/modifié EN PREMIER** pour obtenir un ID réel, PUIS le PaymentIntent est créé avec cet ID.
|
||||
|
||||
## Flow détaillé
|
||||
|
||||
### 1. Sauvegarde du passage EN PREMIER
|
||||
|
||||
L'application crée ou modifie d'abord le passage pour obtenir un ID réel :
|
||||
|
||||
```
|
||||
POST /api/passages/create // Nouveau passage
|
||||
PUT /api/passages/456 // Mise à jour passage existant
|
||||
```
|
||||
|
||||
**Réponse avec l'ID réel :**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"passage_id": 456 // ID RÉEL du passage créé/modifié
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Création du PaymentIntent AVEC l'ID réel
|
||||
|
||||
Ensuite seulement, création du PaymentIntent avec le `passage_id` réel :
|
||||
|
||||
```
|
||||
POST /api/stripe/payments/create-intent
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"amount": 2500, // En centimes (25€)
|
||||
"passage_id": 456, // ID RÉEL du passage (JAMAIS 0)
|
||||
"payment_method_types": ["card_present"], // Tap to Pay
|
||||
"location_id": "tml_xxx", // Terminal reader location
|
||||
"amicale_id": 45,
|
||||
"member_id": 67,
|
||||
"stripe_account": "acct_xxx"
|
||||
}
|
||||
```
|
||||
|
||||
#### Réponse
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"client_secret": "pi_3QaXYZ_secret_xyz",
|
||||
"payment_intent_id": "pi_3QaXYZ123ABC456",
|
||||
"amount": 2500,
|
||||
"currency": "eur",
|
||||
"passage_id": 789, // 0 pour nouveau passage
|
||||
"type": "tap_to_pay"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Traitement du paiement côté client
|
||||
|
||||
L'application utilise le SDK Stripe pour traiter le paiement via NFC :
|
||||
|
||||
```dart
|
||||
// Flutter - Utilisation du client_secret
|
||||
final paymentResult = await stripe.collectPaymentMethod(
|
||||
clientSecret: response['client_secret'],
|
||||
// ... configuration Tap to Pay
|
||||
);
|
||||
```
|
||||
|
||||
### 3. Traitement du paiement Tap to Pay
|
||||
|
||||
L'application utilise le SDK Stripe Terminal avec le `client_secret` pour collecter le paiement via NFC.
|
||||
|
||||
### 4. Mise à jour du passage avec stripe_payment_id
|
||||
|
||||
Après succès du paiement, l'app met à jour le passage avec le `stripe_payment_id` :
|
||||
|
||||
```json
|
||||
PUT /api/passages/456
|
||||
{
|
||||
"stripe_payment_id": "pi_3QaXYZ123ABC456", // ← LIEN AVEC STRIPE
|
||||
// ... autres champs si nécessaire
|
||||
}
|
||||
```
|
||||
|
||||
## Points clés du nouveau flow
|
||||
|
||||
### ✅ Avantages
|
||||
|
||||
1. **Passage toujours existant** : Le passage existe toujours avec un ID réel avant le paiement
|
||||
2. **Traçabilité garantie** : Le `passage_id` dans Stripe est toujours valide
|
||||
3. **Gestion d'erreur robuste** : Si le paiement échoue, le passage existe déjà
|
||||
4. **Cohérence des données** : Pas de passage "orphelin" ou de paiement sans passage
|
||||
|
||||
### ❌ Ce qui n'est plus supporté
|
||||
|
||||
1. **passage_id=0** : Plus jamais utilisé dans `/create-intent`
|
||||
2. **operation_id** : Plus nécessaire car le passage existe déjà
|
||||
3. **Création conditionnelle** : Le passage est toujours créé avant
|
||||
|
||||
## Schéma de séquence (Nouveau Flow v2)
|
||||
|
||||
```
|
||||
┌─────────┐ ┌─────────┐ ┌────────┐ ┌────────────┐
|
||||
│ App │ │ API │ │ Stripe │ │ ope_pass │
|
||||
└────┬────┘ └────┬────┘ └────┬───┘ └─────┬──────┘
|
||||
│ │ │ │
|
||||
│ 1. CREATE/UPDATE passage │ │
|
||||
├──────────────>│ │ │
|
||||
│ ├────────────────┼───────────────>│
|
||||
│ │ │ INSERT/UPDATE │
|
||||
│ │ │ │
|
||||
│ 2. passage_id: 456 (réel) │ │
|
||||
│<──────────────│ │ │
|
||||
│ │ │ │
|
||||
│ 3. create-intent (id=456) │ │
|
||||
├──────────────>│ │ │
|
||||
│ │ │ │
|
||||
│ │ 4. Create PI │ │
|
||||
│ ├───────────────>│ │
|
||||
│ │ │ │
|
||||
│ │ 5. PI created │ │
|
||||
│ │<───────────────│ │
|
||||
│ │ │ │
|
||||
│ │ 6. UPDATE │ │
|
||||
│ ├────────────────┼───────────────>│
|
||||
│ │ stripe_payment_id = pi_xxx │
|
||||
│ │ │ │
|
||||
│ 7. client_secret + pi_id │ │
|
||||
│<──────────────│ │ │
|
||||
│ │ │ │
|
||||
│ 8. Tap to Pay │ │ │
|
||||
├───────────────┼───────────────>│ │
|
||||
│ avec SDK │ │ │
|
||||
│ │ │ │
|
||||
│ 9. Payment OK │ │ │
|
||||
│<──────────────┼────────────────│ │
|
||||
│ │ │ │
|
||||
│ 10. UPDATE passage (optionnel) │ │
|
||||
├──────────────>│ │ │
|
||||
│ ├────────────────┼───────────────>│
|
||||
│ │ Confirmer stripe_payment_id │
|
||||
│ │ │ │
|
||||
│ 11. Success │ │ │
|
||||
│<──────────────│ │ │
|
||||
│ │ │ │
|
||||
```
|
||||
|
||||
## Points importants (Nouveau Flow v2)
|
||||
|
||||
1. **Passage créé en premier** : Le passage est TOUJOURS créé/modifié AVANT le PaymentIntent
|
||||
2. **ID réel obligatoire** : Le `passage_id` ne peut jamais être 0 dans `/create-intent`
|
||||
3. **Lien Stripe automatique** : Le `stripe_payment_id` est ajouté automatiquement lors de la création du PaymentIntent
|
||||
4. **Idempotence** : Un passage ne peut avoir qu'un seul `stripe_payment_id`
|
||||
5. **Validation stricte** : Vérification du montant, propriété et existence du passage
|
||||
|
||||
## Erreurs possibles
|
||||
|
||||
- **400** :
|
||||
- `passage_id` manquant ou ≤ 0
|
||||
- Montant invalide (< 1€ ou > 999€)
|
||||
- Passage déjà payé par Stripe
|
||||
- Montant ne correspond pas au passage
|
||||
- **401** : Non authentifié
|
||||
- **403** : Passage non autorisé (pas le bon utilisateur)
|
||||
- **404** : Passage non trouvé
|
||||
|
||||
## Migration base de données
|
||||
|
||||
La colonne `stripe_payment_id VARCHAR(50)` a été ajoutée via :
|
||||
```sql
|
||||
ALTER TABLE `ope_pass` ADD COLUMN `stripe_payment_id` VARCHAR(50) DEFAULT NULL;
|
||||
ALTER TABLE `ope_pass` ADD INDEX `idx_stripe_payment` (`stripe_payment_id`);
|
||||
```
|
||||
|
||||
## Environnements
|
||||
|
||||
- **DEV** : dva-geo sur IN3 - Base mise à jour ✅
|
||||
- **REC** : rca-geo sur IN3 - Base mise à jour ✅
|
||||
- **PROD** : pra-geo sur IN4 - À mettre à jour
|
||||
Reference in New Issue
Block a user