feat: Version 3.5.2 - Configuration Stripe et gestion des immeubles

- Configuration complète Stripe pour les 3 environnements (DEV/REC/PROD)
  * DEV: Clés TEST Pierre (mode test)
  * REC: Clés TEST Client (mode test)
  * PROD: Clés LIVE Client (mode live)
- Ajout de la gestion des bases de données immeubles/bâtiments
  * Configuration buildings_database pour DEV/REC/PROD
  * Service BuildingService pour enrichissement des adresses
- Optimisations pages et améliorations ergonomie
- Mises à jour des dépendances Composer
- Nettoyage des fichiers obsolètes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
pierre
2025-11-09 18:26:27 +01:00
parent 21657a3820
commit 2f5946a184
812 changed files with 142105 additions and 25992 deletions

View File

@@ -124,8 +124,8 @@ if (amicale == null || amicale.id == 0) {
"city": "Paris",
"country": "FR"
},
"url": "https://app.geosector.fr/stripe/return",
"refresh_url": "https://app.geosector.fr/stripe/refresh"
"url": "https://app3.geosector.fr/stripe/return",
"refresh_url": "https://app3.geosector.fr/stripe/refresh"
}
```
@@ -148,8 +148,8 @@ $account = \Stripe\Account::create([
// 2. Création du lien d'onboarding
$onboardingLink = \Stripe\AccountLink::create([
'account' => $account->id,
'refresh_url' => 'https://app.geosector.fr/stripe/refresh',
'return_url' => 'https://app.geosector.fr/stripe/return',
'refresh_url' => 'https://app3.geosector.fr/stripe/refresh',
'return_url' => 'https://app3.geosector.fr/stripe/return',
'type' => 'account_onboarding'
]);
@@ -529,6 +529,378 @@ $paymentIntent = \Stripe\PaymentIntent::create([
---
## 📱 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<PaymentLinkResult?> createPaymentLink({
required int amountInCents,
required int passageId,
String? description,
Map<String, dynamic>? 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
@@ -846,8 +1218,9 @@ Log::info('PaymentIntent created', [
| 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 : 28 septembre 2025*
*Dernière mise à jour : 5 novembre 2025*