# Fichier: python_cheats/cheatsheets/stripe.txt
# Cheatsheet Stripe Suite 1 - Guide Ultra-Détaillé pour Grands Débutants


[OK] CONCEPTS FONDAMENTAUX (EXPLICATIONS TRÈS DÉTAILLÉES)

# === QU'EST-CE QUE STRIPE EXACTEMENT ? ===

# Imagine la situation suivante:
# Tu crées une boutique en ligne pour vendre des t-shirts
# Un client veut acheter un t-shirt à 25€
# Il clique sur "Acheter" et doit payer avec sa carte bancaire

# QUESTION: Comment faire pour que l'argent de sa carte arrive sur ton compte?

# === LA SOLUTION CLASSIQUE (TRÈS COMPLEXE) ===

# Option 1: Créer ton propre système de paiement
# Tu aurais besoin de:
# 1. Négocier avec des banques (6+ mois de paperasse!)
# 2. Obtenir une licence "acquiring" (très cher: 10 000€+)
# 3. Implémenter PCI-DSS (norme de sécurité ultra-stricte)
#    - Serveurs sécurisés
#    - Cryptage des données
#    - Audits annuels (5 000€+)
# 4. S'intégrer avec les réseaux de cartes:
#    - Visa
#    - Mastercard  
#    - American Express
#    - Chacun a son propre protocole!
# 5. Gérer les fraudes (machine learning, règles complexes)
# 6. Gérer les remboursements et litiges
# 7. S'adapter aux lois de chaque pays
# 8. Maintenir tout ça 24/7

# Coût total: 50 000€+ et 12+ mois de développement
# Équipe nécessaire: 5+ développeurs + avocats + comptables
# = IMPOSSIBLE pour un petit projet!

# Option 2: Utiliser un système bancaire classique
# - Frais élevés et opaques (3-5% + frais fixes)
# - Intégration technique horrible (documentation de 500 pages)
# - Support client inexistant
# - Délais de paiement: 30+ jours

# === LA SOLUTION STRIPE (SIMPLE ET MODERNE) ===

# Stripe fait TOUT le travail complexe pour toi!

# Ce que Stripe gère automatiquement:
# [OK] Accepte toutes les cartes (Visa, Mastercard, Amex, etc.)
# [OK] Conformité PCI-DSS (sécurité maximale)
# [OK] Prévention de la fraude (IA intégrée)
# [OK] Conversion de devises (135+ devises)
# [OK] 3D Secure / SCA (authentification forte)
# [OK] Gestion des remboursements
# [OK] Facturation automatique
# [OK] Récupération des paiements échoués
# [OK] Webhooks pour les notifications
# [OK] Dashboard professionnel
# [OK] API moderne et bien documentée

# Ce que TU fais:
# 1. Créer un compte Stripe (5 minutes, gratuit)
# 2. Copier 15 lignes de code dans ton app
# 3. Tester avec des cartes de test
# 4. Activer le mode production
# 5. BOOM! Tu acceptes des paiements du monde entier

# Résultat:
# - Temps de setup: 1 heure au lieu de 12 mois
# - Coût de setup: 0€ au lieu de 50 000€
# - Maintenance: 0 (Stripe s'en occupe)
# - Frais: 1.4% + 0.25€ par transaction en Europe (transparent)


# === VOCABULAIRE STRIPE ULTRA-DÉTAILLÉ ===

# === CUSTOMER (Client) ===

# Définition:
# Un Customer = Une personne qui achète quelque chose sur ton site
# Stripe stocke ses informations pour que tu puisses:
# - Le facturer plusieurs fois
# - Voir son historique d'achats
# - Gérer ses abonnements
# - Lui envoyer des factures

# Informations stockées:
# - ID unique: cus_xxxxxxxxxxxxx
# - Email: client@example.com
# - Nom: Jean Dupont
# - Adresse (optionnel)
# - Téléphone (optionnel)
# - Méthodes de paiement sauvegardées
# - Métadonnées personnalisées

# Exemple concret:
# Jean achète sur ton site pour la première fois
# Stripe crée: Customer ID: cus_ABC123
# Jean revient 1 mois plus tard
# Tu reconnais Jean grâce à son ID
# Tu peux:
# - Afficher son historique: 3 achats, 127€ total
# - Lui proposer un abonnement
# - Facturer sans redemander sa carte

# Code Python:
customer = stripe.Customer.create(
    email="jean@example.com",
    name="Jean Dupont",
    description="Client VIP - Fidèle depuis 2024",
    metadata={
        "user_id": "123",
        "source": "website"
    }
)
# Retourne: Customer(id='cus_ABC123', ...)


# === CHARGE (Transaction simple) ===

# Définition:
# Un Charge = Un paiement unique et immédiat
# Tu débites une carte bancaire UNE SEULE FOIS
# Une fois créé, un Charge est final (pas de modification possible)

# Cas d'usage:
# - Vente d'un produit physique: t-shirt à 25€
# - Service ponctuel: consultation 1h à 80€
# - Don unique: 10€ pour une association

# Informations d'un Charge:
# - ID: ch_xxxxxxxxxxxxx
# - Montant: 2500 (en centimes! 2500 = 25.00€)
# - Devise: eur, usd, gbp, etc.
# - Statut: succeeded, failed, pending
# - Description: "T-shirt taille M rouge"
# - Customer: cus_ABC123 (optionnel)
# - Receipt Email: Envoi du reçu par email

# Flux complet:
# 1. Client entre ses infos de carte
# 2. Tu crées un Charge
# 3. Stripe contacte la banque du client
# 4. La banque vérifie les fonds
# 5. La banque autorise ou refuse
# 6. Stripe retourne le résultat
# 7a. Si succès: Argent réservé, tu livres le produit
# 7b. Si échec: Tu informes le client

# Code Python:
charge = stripe.Charge.create(
    amount=2500,  # 25.00€ en centimes
    currency="eur",
    source="tok_visa",  # Token de la carte
    description="T-shirt rouge taille M",
    receipt_email="client@example.com"
)

# IMPORTANT: Charge est l'ancienne API
# Aujourd'hui, utilise PaymentIntent (plus moderne)


# === PAYMENT INTENT (Intention de paiement moderne) ===

# Définition:
# Un PaymentIntent = Version moderne et sécurisée du Charge
# Gère automatiquement l'authentification 3D Secure (SCA)
# Recommandé depuis 2019 (réglementations européennes PSD2)

# Pourquoi PaymentIntent > Charge?
# 1. Conformité PSD2/SCA automatique
# 2. Gère les paiements différés
# 3. Support de plusieurs méthodes de paiement
# 4. Retry automatique en cas d'échec
# 5. États intermédiaires (requires_action, processing)

# Cycle de vie d'un PaymentIntent:
# 
# Étape 1: CRÉATION
# Statut: requires_payment_method
# = "J'ai besoin d'une carte bancaire"
#
# Étape 2: AJOUT DE LA CARTE
# Statut: requires_confirmation
# = "J'ai la carte, attends confirmation"
#
# Étape 3: CONFIRMATION
# Statut: requires_action (si 3D Secure nécessaire)
# = "Le client doit s'authentifier (code SMS)"
# OU
# Statut: processing
# = "Paiement en cours de traitement"
#
# Étape 4: FINALISATION
# Statut: succeeded
# = "Paiement réussi! [BRAVO]"
# OU
# Statut: canceled / requires_payment_method
# = "Échec, réessaie avec une autre carte"

# États possibles:
# - requires_payment_method: Attends une carte
# - requires_confirmation: Attends confirmation
# - requires_action: Attends action client (3D Secure)
# - processing: En cours de traitement
# - succeeded: Réussi! [OK]
# - canceled: Annulé
# - requires_capture: Attends capture (pour paiement différé)

# Code Python complet:
# Étape 1: Créer l'intention
intent = stripe.PaymentIntent.create(
    amount=5000,  # 50.00€
    currency="eur",
    payment_method_types=["card"],
    description="Formation Python avancé",
    metadata={
        "order_id": "ORDER-123",
        "customer_name": "Jean Dupont"
    }
)
# Retourne: PaymentIntent(id='pi_xyz', status='requires_payment_method')

# Étape 2: Le client entre sa carte (côté frontend)
# JavaScript: stripe.confirmCardPayment(client_secret)

# Étape 3: Stripe gère 3D Secure si nécessaire
# Affiche popup bancaire pour code SMS

# Étape 4: Vérifier le résultat (côté backend)
intent = stripe.PaymentIntent.retrieve('pi_xyz')
if intent.status == 'succeeded':
    print("Paiement réussi!")
    # Livrer le produit, activer l'accès, etc.


# === PAYMENT METHOD (Méthode de paiement) ===

# Définition:
# Un PaymentMethod = Les informations d'une carte bancaire
# Ou tout autre moyen de paiement (SEPA, Apple Pay, etc.)

# Types de PaymentMethod:
# - card: Carte bancaire (Visa, Mastercard, etc.)
# - sepa_debit: Prélèvement SEPA (Europe)
# - ideal: iDEAL (Pays-Bas)
# - giropay: Giropay (Allemagne)
# - bancontact: Bancontact (Belgique)
# - sofort: Sofort (Europe)
# - ... et 40+ autres méthodes

# Informations d'une carte (PaymentMethod card):
# - ID: pm_xxxxxxxxxxxxx
# - Type: card
# - Card:
#   - Brand: visa, mastercard, amex
#   - Last4: 4242 (4 derniers chiffres)
#   - Exp Month: 12
#   - Exp Year: 2025
#   - Country: FR
#   - Funding: credit, debit, prepaid
#   - Checks:
#     - CVC: pass / fail
#     - Address: pass / fail / unavailable

# Créer un PaymentMethod:
payment_method = stripe.PaymentMethod.create(
    type="card",
    card={
        "number": "4242424242424242",
        "exp_month": 12,
        "exp_year": 2025,
        "cvc": "123"
    },
    billing_details={
        "name": "Jean Dupont",
        "email": "jean@example.com",
        "address": {
            "line1": "123 rue de la Paix",
            "city": "Paris",
            "postal_code": "75001",
            "country": "FR"
        }
    }
)

# Attacher à un Customer (pour réutilisation):
stripe.PaymentMethod.attach(
    "pm_xxxxxxxxxxxxx",
    customer="cus_ABC123"
)

# Lister les PaymentMethods d'un client:
payment_methods = stripe.PaymentMethod.list(
    customer="cus_ABC123",
    type="card"
)


# === SUBSCRIPTION (Abonnement récurrent) ===

# Définition:
# Une Subscription = Paiement automatique et récurrent
# Le client est débité à intervalles réguliers
# Jusqu'à annulation

# Cas d'usage:
# - SaaS: Logiciel à 29€/mois
# - Streaming: Netflix 13€/mois
# - Gym: Abonnement salle de sport 50€/mois
# - Box: Livraison mensuelle de produits
# - Formation: Accès cours 15€/mois

# Fréquences possibles:
# - day: Quotidien (rare)
# - week: Hebdomadaire
# - month: Mensuel (le plus commun)
# - year: Annuel
# - Custom: Tous les 3 mois, 6 mois, etc.

# Cycle de vie d'une Subscription:
#
# Jour 1: CRÉATION
# Statut: active
# Le client souscrit à "Plan Pro - 29€/mois"
# Premier paiement: 29€ débité immédiatement
#
# Jour 30: RENOUVELLEMENT AUTOMATIQUE
# Statut: active
# Stripe débite automatiquement 29€
# Si succès: Abonnement continue
# Si échec: Statut devient past_due
#
# Jour 33: PAIEMENT ÉCHOUÉ (optionnel)
# Statut: past_due
# Stripe réessaie automatiquement (3-4 fois)
# Envoie email au client: "Mettre à jour votre carte"
#
# Jour 37: PAIEMENT RÉUSSI (après retry)
# Statut: active
# Tout rentre dans l'ordre
#
# Jour 60: ANNULATION
# Statut: canceled
# Le client annule l'abonnement
# Plus de débit

# États d'une Subscription:
# - incomplete: En attente du premier paiement
# - incomplete_expired: Premier paiement échoué (expiré)
# - trialing: Période d'essai gratuite
# - active: Active et paiements réussis
# - past_due: Paiement en retard (échec)
# - canceled: Annulée
# - unpaid: Impayée (après plusieurs échecs)

# Code Python:
# D'abord, créer un Price (tarif):
price = stripe.Price.create(
    unit_amount=2900,  # 29.00€
    currency="eur",
    recurring={
        "interval": "month"  # Mensuel
    },
    product_data={
        "name": "Plan Pro"
    }
)

# Puis créer la Subscription:
subscription = stripe.Subscription.create(
    customer="cus_ABC123",
    items=[{
        "price": price.id  # ou "price_xxxxx" si déjà créé
    }],
    trial_period_days=7,  # 7 jours gratuits
    metadata={
        "plan": "pro",
        "source": "website"
    }
)

# Gérer les échecs de paiement:
# Stripe réessaie automatiquement selon ta configuration
# Dashboard > Settings > Subscriptions > Payment retry


# === PRODUCT (Produit) ===

# Définition:
# Un Product = Ce que tu vends (description générale)
# Ce n'est PAS un prix! C'est juste une description

# Informations d'un Product:
# - ID: prod_xxxxxxxxxxxxx
# - Name: "Abonnement Premium"
# - Description: "Accès illimité à tous les cours"
# - Images: ["https://...image1.jpg", "..."]
# - Active: true / false (actif ou archivé)
# - Metadata: Données personnalisées

# Relation Product <-> Price:
# 1 Product peut avoir PLUSIEURS Prices
# Exemple:
# Product: "Abonnement Premium"
# - Price 1: 10€/mois (mensuel)
# - Price 2: 100€/an (annuel, -16% de réduction)
# - Price 3: 5€/mois (pour étudiants)

# Code Python:
product = stripe.Product.create(
    name="Abonnement Premium",
    description="Accès illimité à tous nos cours de programmation",
    images=[
        "https://monsite.com/images/premium.png"
    ],
    metadata={
        "category": "subscription",
        "level": "premium"
    }
)

# Créer un Price pour ce Product:
price_mensuel = stripe.Price.create(
    product=product.id,
    unit_amount=1000,  # 10.00€
    currency="eur",
    recurring={
        "interval": "month"
    }
)

price_annuel = stripe.Price.create(
    product=product.id,
    unit_amount=10000,  # 100.00€
    currency="eur",
    recurring={
        "interval": "year"
    }
)


# === PRICE (Prix / Tarif) ===

# Définition:
# Un Price = Le montant à payer pour un Product
# Contient: montant, devise, fréquence

# Types de Price:
# 1. One-time (paiement unique):
#    - Achat d'un cours: 49€
#    - Vente d'un ebook: 19€
#
# 2. Recurring (récurrent):
#    - Abonnement: 29€/mois
#    - Location: 500€/mois

# Informations d'un Price:
# - ID: price_xxxxxxxxxxxxx
# - Product: prod_xxxxx (lié à un Product)
# - Unit Amount: 2900 (29.00€ en centimes)
# - Currency: eur
# - Type: one_time ou recurring
# - Recurring (si applicable):
#   - Interval: day, week, month, year
#   - Interval Count: 1, 2, 3... (ex: tous les 3 mois)
# - Active: true / false

# Code Python:
# Price one-time:
price_unique = stripe.Price.create(
    product="prod_xxxxx",
    unit_amount=4900,  # 49.00€
    currency="eur"
    # Pas de recurring = one-time par défaut
)

# Price recurring mensuel:
price_mensuel = stripe.Price.create(
    product="prod_xxxxx",
    unit_amount=2900,  # 29.00€
    currency="eur",
    recurring={
        "interval": "month",
        "interval_count": 1  # Tous les 1 mois
    }
)

# Price recurring tous les 3 mois:
price_trimestriel = stripe.Price.create(
    product="prod_xxxxx",
    unit_amount=7900,  # 79.00€
    currency="eur",
    recurring={
        "interval": "month",
        "interval_count": 3  # Tous les 3 mois
    }
)

# Lister tous les Prices d'un Product:
prices = stripe.Price.list(product="prod_xxxxx")


# === INVOICE (Facture) ===

# Définition:
# Une Invoice = Document qui liste ce que le client doit payer
# Contient: ligne d'articles, montant total, taxes, date d'échéance

# Stripe génère des Invoices automatiquement pour:
# - Les abonnements (chaque période de facturation)
# - Les paiements différés
# - Les one-time payments avec invoice

# Informations d'une Invoice:
# - ID: in_xxxxxxxxxxxxx
# - Customer: cus_ABC123
# - Status: draft, open, paid, void, uncollectible
# - Amount Due: 2900 (29.00€)
# - Currency: eur
# - Lines: Liste des articles facturés
# - PDF: URL pour télécharger la facture PDF
# - Hosted Invoice URL: Page pour payer en ligne

# États d'une Invoice:
# - draft: Brouillon (pas encore finalisée)
# - open: Ouverte (en attente de paiement)
# - paid: Payée [OK]
# - void: Annulée
# - uncollectible: Impayable (abandon)

# Cycle de vie:
# Jour 1: Invoice créée (status: draft)
# Jour 1: Invoice finalisée (status: open)
# Jour 1: Client paie (status: paid)
# OU
# Jour 7: Échéance dépassée (status: open, past_due)
# Jour 30: Abandon (status: uncollectible)

# Code Python:
# Créer une Invoice manuelle:
invoice = stripe.Invoice.create(
    customer="cus_ABC123",
    auto_advance=True,  # Finaliser automatiquement
    collection_method="send_invoice",  # Envoyer par email
    days_until_due=7  # Échéance: 7 jours
)

# Ajouter des lignes:
stripe.InvoiceItem.create(
    customer="cus_ABC123",
    invoice=invoice.id,
    amount=4900,  # 49.00€
    currency="eur",
    description="Formation Python avancé"
)

# Finaliser et envoyer:
invoice = stripe.Invoice.finalize_invoice(invoice.id)

# Télécharger le PDF:
pdf_url = invoice.invoice_pdf
# Exemple: https://pay.stripe.com/invoice/invst_xxx/pdf


# === WEBHOOK (Notification automatique) ===

# Définition:
# Un Webhook = Message que Stripe t'envoie quand un événement se produit
# C'est une requête HTTP POST vers ton serveur
# Contient les détails de l'événement

# Pourquoi c'est important?
# Exemples:
# - Un paiement réussit -> Active l'accès du client
# - Un abonnement expire -> Désactive l'accès
# - Un paiement échoue -> Envoie email de relance
# - Une fraude détectée -> Bloque la transaction

# Sans Webhooks:
# Tu dois constamment vérifier: "Y a-t-il un nouveau paiement?"
# = Polling (inefficace, lent, coûteux)

# Avec Webhooks:
# Stripe te prévient instantanément!
# = Push (efficace, temps réel, gratuit)

# Types d'événements (300+):
# - payment_intent.succeeded: Paiement réussi
# - payment_intent.payment_failed: Paiement échoué
# - customer.subscription.created: Abonnement créé
# - customer.subscription.deleted: Abonnement annulé
# - invoice.paid: Facture payée
# - invoice.payment_failed: Facture impayée
# - charge.refunded: Remboursement effectué
# - customer.created: Client créé
# - ...

# Structure d'un Webhook:
webhook_event = {
    "id": "evt_xxxxxxxxxxxxx",
    "type": "payment_intent.succeeded",  # Type d'événement
    "data": {
        "object": {
            "id": "pi_xxxxxxxxxxxxx",
            "amount": 5000,
            "currency": "eur",
            "customer": "cus_ABC123",
            # ... toutes les infos du PaymentIntent
        }
    },
    "created": 1234567890
}

# Code Python (Flask):
@app.route('/webhook', methods=['POST'])
def stripe_webhook():
    payload = request.data
    sig_header = request.headers.get('Stripe-Signature')
    
    try:
        # Vérifier la signature (sécurité!)
        event = stripe.Webhook.construct_event(
            payload, sig_header, webhook_secret
        )
    except ValueError:
        return "Invalid payload", 400
    except stripe.error.SignatureVerificationError:
        return "Invalid signature", 400
    
    # Gérer l'événement
    if event['type'] == 'payment_intent.succeeded':
        payment_intent = event['data']['object']
        customer_id = payment_intent['customer']
        
        # Activer l'accès du client
        activate_customer_access(customer_id)
    
    elif event['type'] == 'customer.subscription.deleted':
        subscription = event['data']['object']
        customer_id = subscription['customer']
        
        # Désactiver l'accès
        deactivate_customer_access(customer_id)
    
    return "Success", 200


# === API KEY (Clé d'accès) ===

# Définition:
# Une API Key = Mot de passe pour communiquer avec Stripe
# C'est comme un jeton d'authentification

# 2 types de clés:

# 1. PUBLISHABLE KEY (Clé publique)
# Format: pk_test_xxxxxxxxxxxxx (test) ou pk_live_xxxxx (live)
# Utilisation: Côté client (navigateur, app mobile)
# Visible par: TOUT LE MONDE (c'est OK!)
# Permissions: Limitées (créer tokens, checkout sessions)
# Danger: Faible (ne peut pas voler d'argent)

# 2. SECRET KEY (Clé secrète)
# Format: sk_test_xxxxxxxxxxxxx (test) ou sk_live_xxxxx (live)
# Utilisation: Côté serveur uniquement
# Visible par: PERSONNE (top secret!)
# Permissions: TOTALES (créer charges, remboursements, etc.)
# Danger: ÉLEVÉ (peut tout faire!)

# RÈGLE D'OR:
# [OK] Publishable Key -> Frontend (OK si visible)
# [X] Secret Key -> JAMAIS dans le frontend!
# [X] Secret Key -> JAMAIS dans git/GitHub!
# [OK] Secret Key -> Serveur uniquement, variable d'environnement

# Modes:

# TEST MODE:
# - Clés: pk_test_xxx, sk_test_xxx
# - Argent: Virtuel (pas de vrai argent)
# - Cartes: Cartes de test (4242 4242 4242 4242)
# - Dashboard: Données séparées du live
# - Parfait pour: Développement, tests

# LIVE MODE:
# - Clés: pk_live_xxx, sk_live_xxx
# - Argent: RÉEL (vraies transactions!)
# - Cartes: Vraies cartes bancaires
# - Dashboard: Données réelles
# - Parfait pour: Production

# Code Python:
import stripe

# Configuration avec Secret Key
stripe.api_key = "sk_test_51xxxxxxxxxxxxxxxxxx"

# Toutes les requêtes utilisent cette clé


# === CHECKOUT SESSION (Session de paiement hébergée) ===

# Définition:
# Une Checkout Session = Page de paiement hébergée par Stripe
# C'est la solution LA PLUS SIMPLE pour accepter des paiements

# Avantages énormes:
# [OK] Stripe héberge la page (pas de code frontend complexe!)
# [OK] Sécurité PCI-DSS gérée par Stripe
# [OK] Design professionnel et responsive
# [OK] Supporte 40+ moyens de paiement (cartes, Apple Pay, Google Pay, etc.)
# [OK] Multilingue (25+ langues détectées automatiquement)
# [OK] Mobile-friendly
# [OK] 3D Secure automatique
# [OK] Gestion des taxes automatique
# [OK] Codes promo intégrés

# Flux complet:
# 1. Client sur ton site clique "Acheter"
# 2. Ton serveur crée une Checkout Session
# 3. Tu rediriges le client vers l'URL Stripe
# 4. Client entre ses infos sur la page Stripe
# 5. Client paie
# 6. Stripe redirige vers ton site (success_url)
# 7. Ton serveur reçoit un webhook (checkout.session.completed)
# 8. Tu actives l'accès / livres le produit

# Modes de Checkout Session:
# 1. payment: Paiement unique
# 2. subscription: Créer un abonnement
# 3. setup: Sauvegarder une carte sans payer

# Code Python:
session = stripe.checkout.Session.create(
    # Moyens de paiement acceptés
    payment_method_types=['card', 'apple_pay', 'google_pay'],
    
    # Mode: payment (paiement unique)
    mode='payment',
    
    # Articles à acheter
    line_items=[{
        'price_data': {
            'currency': 'eur',
            'product_data': {
                'name': 'Formation Python Complet',
                'description': 'Cours de 20h + exercices',
                'images': ['https://monsite.com/python.png'],
            },
            'unit_amount': 4900,  # 49.00€
        },
        'quantity': 1,
    }],
    
    # URLs de redirection
    success_url='https://monsite.com/success?session_id={CHECKOUT_SESSION_ID}',
    cancel_url='https://monsite.com/cancel',
    
    # Client (optionnel mais recommandé)
    customer_email='client@example.com',
    
    # Collecter l'adresse
    billing_address_collection='required',
    
    # Activer les codes promo
    allow_promotion_codes=True,
    
    # Métadonnées personnalisées
    metadata={
        'order_id': 'ORDER-123',
        'user_id': '456'
    }
)

# Rediriger le client:
return redirect(session.url)


# === POURQUOI UTILISER STRIPE? (ARGUMENTS CONCRETS) ===

# Comparaison avec les alternatives:

# PAYPAL:
# Avantages PayPal:
# - Connu du grand public
# - Compte PayPal = paiement rapide
# Inconvénients PayPal:
# [X] API complexe et mal documentée
# [X] Interface utilisateur datée
# [X] Support client horrible


[OK] INSTALLATION SUPER DÉTAILLÉE

# === ÉTAPE 1: CRÉER UN COMPTE STRIPE ===

# Pourquoi? Tu dois avoir un compte pour recevoir des paiements

# Instructions:
# 1. Ouvre un navigateur
# 2. Va sur: https://stripe.com/
# 3. Clique sur "Start now" ou "Commencer" (en haut à droite)
# 4. Remplis le formulaire:
#    - Email: ton adresse email professionnelle
#    - Nom complet: ton nom ou nom de ta société
#    - Pays: ton pays de résidence
#    - Mot de passe: sécurisé (>= 8 caractères)
# 5. Vérifie ton email: Stripe envoie un lien de confirmation
# 6. Clique sur le lien dans l'email
# 7. YAY! Ton compte est créé!

# Note: C'est 100% GRATUIT! Pas de carte bancaire demandée pour commencer


# === ÉTAPE 2: ACTIVER LE MODE TEST ===

# Stripe a 2 modes:
# - TEST MODE: Pour développer et tester (argent virtuel)
# - LIVE MODE: Pour accepter de vrais paiements (argent réel)

# Toujours commencer en TEST MODE!

# Sur le dashboard Stripe:
# 1. En haut à droite, tu vois un interrupteur "Test mode"
# 2. Assure-toi qu'il est ACTIVÉ (fond violet/bleu)
# 3. Tu verras: "Test mode" ou "Mode test" écrit quelque part

# En test mode:
# - Aucun argent réel n'est débité
# - Tu utilises des cartes de test (4242 4242 4242 4242)
# - Parfait pour développer sans risque!


# === ÉTAPE 3: RÉCUPÉRER TES CLÉS API ===

# Tu as besoin de 2 clés pour communiquer avec Stripe:
# 1. Publishable Key (publique): Pour le frontend (navigateur)
# 2. Secret Key (privée): Pour le backend (serveur)

# Sur le dashboard:
# 1. Dans la barre de gauche, clique sur "Developers" (Développeurs)
# 2. Clique sur "API keys" (Clés API)
# 3. Tu vois 2 clés:

# Publishable key (publique):
# pk_test_51xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# = Commence toujours par "pk_test_" en mode test
# = Tu peux la mettre dans ton code frontend (visible par tous)

# Secret key (privée):
# sk_test_51xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# = Commence toujours par "sk_test_" en mode test
# = NE JAMAIS la partager ou la commiter dans git!
# = À garder sur ton serveur uniquement

# COPIE CES 2 CLÉS dans un fichier temporaire
# Tu en auras besoin dans les étapes suivantes


# === ÉTAPE 4: INSTALLER LA BIBLIOTHÈQUE STRIPE (PYTHON) ===

# Stripe fournit des bibliothèques officielles pour:
# - Python, Ruby, PHP, Node.js, Go, Java, .NET

# Nous utilisons Python ici

# Créer un environnement virtuel (recommandé):
python -m venv venv

# Activer l'environnement:
# macOS/Linux:
source venv/bin/activate

# Windows:
venv\Scripts\activate

# Tu vois maintenant: (venv) $ ou (venv) C:\...

# Installer Stripe:
pip install stripe

# Affiche:
# Collecting stripe
# Downloading stripe-X.X.X-py2.py3-none-any.whl
# ...
# Successfully installed stripe-X.X.X

# Vérifier l'installation:
pip show stripe
# Affiche:
# Name: stripe
# Version: 8.0.0 (ou plus récent)
# Summary: Python bindings for the Stripe API


# === ÉTAPE 5: CONFIGURER LES CLÉS DANS TON CODE ===

# Créer un fichier .env pour stocker les secrets:

# macOS/Linux:
cat > .env << 'EOF'
STRIPE_SECRET_KEY=sk_test_51xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
STRIPE_PUBLISHABLE_KEY=pk_test_51xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
EOF

# Windows PowerShell:
@"
STRIPE_SECRET_KEY=sk_test_51xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
STRIPE_PUBLISHABLE_KEY=pk_test_51xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
"@ | Out-File .env -Encoding UTF8

# REMPLACE les valeurs par TES vraies clés!

# IMPORTANT: Ajoute .env au .gitignore!
echo ".env" >> .gitignore

# Installer python-dotenv pour charger .env:
pip install python-dotenv

# Dans ton code Python:
from dotenv import load_dotenv
import os
import stripe

# Charger les variables d'environnement
load_dotenv()

# Configurer Stripe avec ta clé secrète
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY')

# Maintenant tu peux utiliser l'API Stripe!



[OK] STRIPE CHECKOUT SESSION - GUIDE COMPLET ULTRA-DÉTAILLÉ

# === QU'EST-CE QU'UNE CHECKOUT SESSION? ===

# Imagine la situation:
# Tu veux vendre un cours Python à 49€
# Le client clique "Acheter maintenant"
# Il doit entrer ses infos de carte bancaire

# PROBLÈME 1: Où afficher le formulaire de paiement?
# Option A: Créer ton propre formulaire HTML
# = DANGER! Tu gères les numéros de carte (PCI-DSS compliance = $$$)
# = Tu dois coder la validation, l'envoi sécurisé, etc.
# = Des MOIS de travail + risques légaux!

# Option B: Utiliser Stripe Checkout Session
# = Stripe héberge TOUT le formulaire de paiement
# = Tu ne touches JAMAIS les numéros de carte
# = Conforme PCI-DSS automatiquement
# = 5 lignes de code Python!

# PROBLÈME 2: Et si le client a Apple Pay? Google Pay?
# Avec ton propre formulaire: Tu dois intégrer chaque méthode (semaines!)
# Avec Stripe Checkout: AUTOMATIQUE! Stripe détecte et affiche tout!

# === FLUX COMPLET D'UNE CHECKOUT SESSION ===

# Étape 1: CLIENT sur ton site
# Voit: "Formation Python - 49€"
# Clique: Bouton "Acheter maintenant"

# Étape 2: TON SERVEUR (Python/Flask/Django)
# Reçoit: Requête "créer un paiement"
# Appelle: stripe.checkout.Session.create(...)
# Stripe retourne: Une URL unique (https://checkout.stripe.com/pay/cs_test_xxx)

# Étape 3: TON SERVEUR
# Redirige le client: vers l'URL Stripe

# Étape 4: CLIENT sur Stripe Checkout
# Voit: Page de paiement professionnelle Stripe
# Contient:
#   - Nom du produit: "Formation Python"
#   - Prix: 49.00 EUR
#   - Formulaire carte bancaire
#   - OU boutons Apple Pay / Google Pay si disponibles
# Entre: Numéro carte, date expiration, CVC
# Clique: "Payer"

# Étape 5: STRIPE
# Vérifie: La carte est-elle valide?
# Contacte: La banque du client
# Gère: 3D Secure si nécessaire (code SMS)
# Débite: 49€ de la carte

# Étape 6: REDIRECTION
# Si succès: Stripe redirige vers success_url (https://monsite.com/success)
# Si échec: Stripe redirige vers cancel_url (https://monsite.com/cancel)

# Étape 7: TON SERVEUR reçoit un Webhook
# Stripe envoie: POST request vers ton endpoint /webhook
# Contient: Toutes les infos du paiement
# Tu actives: L'accès au cours pour le client
# Tu envoies: Email de confirmation

# === AVANTAGES CHECKOUT SESSION ===

# [OK] SÉCURITÉ MAXIMALE
#   - Stripe héberge tout (pas de risque PCI-DSS)
#   - Tu ne touches JAMAIS les données de carte
#   - Chiffrement SSL automatique
#   - Protection anti-fraude IA intégrée

# [OK] CONVERSION OPTIMISÉE
#   - Design testé sur des milliards de transactions
#   - Optimisé pour mobile et desktop
#   - Auto-completion des infos (clients Stripe)
#   - Remplissage automatique des adresses

# [OK] MÉTHODES DE PAIEMENT MULTIPLES
#   - Cartes: Visa, Mastercard, Amex, etc.
#   - Wallets: Apple Pay, Google Pay
#   - Europe: SEPA, iDEAL, Bancontact, Giropay
#   - Asie: Alipay, WeChat Pay
#   - BNPL: Klarna, Afterpay
#   - 40+ méthodes au total!

# [OK] INTERNATIONALISATION
#   - 25+ langues détectées automatiquement
#   - 135+ devises supportées
#   - Taxes calculées automatiquement
#   - Adaptation aux règlements locaux

# [OK] EXPÉRIENCE CLIENT
#   - Page de paiement rapide (<1 sec)
#   - Pas de bugs (Stripe maintient)
#   - Toujours à jour avec les nouvelles normes
#   - Support client Stripe 24/7

# [OK] FEATURES AVANCÉES
#   - Codes promo intégrés
#   - Collecte d'adresse de facturation
#   - Collecte d'adresse de livraison
#   - Champs personnalisés
#   - Sauvegarde automatique des cartes
#   - Paiements récurrents (abonnements)


# === CRÉER UNE CHECKOUT SESSION: CODE DÉTAILLÉ ===

import stripe
import os
from flask import Flask, redirect, request, jsonify

app = Flask(__name__)

# Configuration Stripe
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY')

@app.route('/create-checkout-session', methods=['POST'])
def create_checkout_session():
    """
    Créer une Checkout Session pour un paiement unique
    
    Cette route:
    1. Reçoit une requête du frontend (bouton "Acheter")
    2. Crée une Checkout Session via Stripe API
    3. Retourne l'URL de paiement au frontend
    """
    
    try:
        # Créer la Checkout Session
        checkout_session = stripe.checkout.Session.create(
            
            # === CONFIGURATION DES MÉTHODES DE PAIEMENT ===
            payment_method_types=[
                'card',        # Cartes bancaires (Visa, Mastercard, Amex)
                'apple_pay',   # Apple Pay (si disponible)
                'google_pay',  # Google Pay (si disponible)
            ],
            # Stripe affiche automatiquement les méthodes disponibles
            # pour le client (selon son pays, appareil, etc.)
            
            # === MODE DE LA SESSION ===
            mode='payment',
            # Options:
            # - 'payment': Paiement unique (one-time)
            # - 'subscription': Créer un abonnement récurrent
            # - 'setup': Sauvegarder une carte sans payer
            
            # === ARTICLES À ACHETER ===
            line_items=[
                {
                    # Données du produit (inline)
                    'price_data': {
                        'currency': 'eur',  # EUR, USD, GBP, etc.
                        'product_data': {
                            'name': 'Formation Python Complet',
                            'description': 'Cours de 20h avec certificat',
                            'images': [
                                'https://monsite.com/images/python-course.png'
                            ],
                            # Images visibles sur la page de paiement
                            # Recommandé: 1200x630px (ratio 1.91:1)
                        },
                        'unit_amount': 4900,  # 49.00€ en centimes!
                        # IMPORTANT: Toujours en centimes!
                        # 49.00€ = 4900 centimes
                        # 100.50€ = 10050 centimes
                    },
                    'quantity': 1,  # Nombre d'articles
                },
                
                # Tu peux ajouter plusieurs articles:
                {
                    'price_data': {
                        'currency': 'eur',
                        'product_data': {
                            'name': 'Ebook bonus: 100 exercices Python',
                        },
                        'unit_amount': 1000,  # 10.00€
                    },
                    'quantity': 1,
                },
            ],
            
            # === URLS DE REDIRECTION ===
            success_url='https://monsite.com/success?session_id={CHECKOUT_SESSION_ID}',
            # URL où le client est redirigé après paiement réussi
            # {CHECKOUT_SESSION_ID} = placeholder remplacé par Stripe
            # avec l'ID réel de la session
            
            cancel_url='https://monsite.com/cancel',
            # URL où le client est redirigé s'il annule le paiement
            
            # === INFORMATIONS CLIENT ===
            customer_email='client@example.com',
            # Pré-remplir l'email du client (optionnel mais recommandé)
            # Si tu as déjà l'email, évite au client de le retaper!
            
            # === COLLECTE D'INFORMATIONS ===
            billing_address_collection='required',
            # Options:
            # - 'auto': Collecte seulement si nécessaire
            # - 'required': Collecte toujours l'adresse de facturation
            
            shipping_address_collection={
                'allowed_countries': ['FR', 'BE', 'CH', 'LU', 'MC'],
                # Liste des pays autorisés pour la livraison
                # Codes ISO 3166-1 alpha-2 (2 lettres)
            },
            # Si ton produit nécessite une livraison physique
            
            # === CODES PROMO ===
            allow_promotion_codes=True,
            # Affiche un champ "Code promo" sur la page de paiement
            # Les clients peuvent entrer des codes créés dans ton Dashboard
            
            # === OPTIONS DE PAIEMENT ===
            payment_intent_data={
                'capture_method': 'automatic',
                # Options:
                # - 'automatic': Débite immédiatement (défaut)
                # - 'manual': Réserve les fonds, tu captures plus tard
                
                'setup_future_usage': 'off_session',
                # Options:
                # - 'off_session': Sauvegarde la carte pour usage futur
                # - 'on_session': Ne pas sauvegarder
                # Utile pour facturer le client plus tard sans qu'il re-entre sa carte
                
                'description': 'Achat Formation Python - Utilisateur #123',
                # Description visible dans ton Dashboard Stripe
                
                'metadata': {
                    'user_id': '123',
                    'order_id': 'ORDER-456',
                    'source': 'website',
                },
                # Métadonnées personnalisées
                # Tu peux ajouter n'importe quelle info utile
                # Visible dans Dashboard et Webhooks
            },
            
            # === EXPIRATION ===
            expires_at=int(time.time()) + (30 * 60),
            # Session expire après 30 minutes
            # time.time() = timestamp actuel en secondes
            # +30*60 = +30 minutes
            
            # === LANGUE ===
            locale='fr',
            # Langue de la page de paiement
            # Options: 'en', 'fr', 'de', 'es', 'it', 'nl', etc.
            # Si omis, Stripe détecte automatiquement selon le navigateur
            
            # === AFFICHAGE ===
            submit_type='pay',
            # Options:
            # - 'pay': "Payer 49.00€" (défaut)
            # - 'book': "Réserver 49.00€"
            # - 'donate': "Faire un don de 49.00€"
            
            # === APRÈS PAIEMENT ===
            automatic_tax={'enabled': True},
            # Calcul automatique des taxes selon la localisation du client
            # Nécessite configuration dans Dashboard > Settings > Tax
        )
        
        # Retourner l'URL au frontend
        return jsonify({
            'url': checkout_session.url,
            'session_id': checkout_session.id
        })
    
    except Exception as e:
        # Gérer les erreurs
        return jsonify({'error': str(e)}), 400


# === EXEMPLE COMPLET: FRONTEND HTML + JAVASCRIPT ===

"""
<!DOCTYPE html>
<html>
<head>
    <title>Acheter Formation Python</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 600px;
            margin: 50px auto;
            padding: 20px;
        }
        .product {
            border: 1px solid #ddd;
            padding: 20px;
            border-radius: 8px;
            background: #f9f9f9;
        }
        .product h2 {
            margin-top: 0;
        }
        .price {
            font-size: 24px;
            color: #28a745;
            font-weight: bold;
            margin: 15px 0;
        }
        button {
            background: #5469d4;
            color: white;
            padding: 12px 24px;
            border: none;
            border-radius: 4px;
            font-size: 16px;
            cursor: pointer;
        }
        button:hover {
            background: #3d52b3;
        }
        button:disabled {
            background: #ccc;
            cursor: not-allowed;
        }
        #error-message {
            color: #dc3545;
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <div class="product">
        <h2>Formation Python Complet</h2>
        <p>Cours de 20h avec exercices pratiques et certificat</p>
        
        <ul>
            <li>20 heures de vidéo</li>
            <li>100+ exercices corrigés</li>
            <li>Projets réels</li>
            <li>Certificat de fin de formation</li>
            <li>Accès à vie</li>
        </ul>
        
        <div class="price">49.00 EUR</div>
        
        <button id="checkout-button">Acheter maintenant</button>
        <div id="error-message"></div>
    </div>

    <script>
        // Gérer le clic sur le bouton
        document.getElementById('checkout-button').addEventListener('click', async function() {
            const button = this;
            const errorDiv = document.getElementById('error-message');
            
            // Désactiver le bouton pendant le chargement
            button.disabled = true;
            button.textContent = 'Chargement...';
            errorDiv.textContent = '';
            
            try {
                // Appeler ton serveur pour créer la Checkout Session
                const response = await fetch('/create-checkout-session', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                });
                
                const data = await response.json();
                
                if (data.error) {
                    // Afficher l'erreur
                    errorDiv.textContent = data.error;
                    button.disabled = false;
                    button.textContent = 'Acheter maintenant';
                } else {
                    // Rediriger vers Stripe Checkout
                    window.location.href = data.url;
                    // Le client voit maintenant la page de paiement Stripe!
                }
            } catch (error) {
                errorDiv.textContent = 'Erreur réseau. Réessayez.';
                button.disabled = false;
                button.textContent = 'Acheter maintenant';
            }
        });
    </script>
</body>
</html>
"""


# === PAGE DE SUCCÈS: /success ===

@app.route('/success')
def success():
    """
    Page affichée après un paiement réussi
    
    IMPORTANT: Ne te fie PAS uniquement à cette page!
    Le client peut l'atteindre sans payer (en tapant l'URL)
    
    Utilise les Webhooks pour confirmer le paiement!
    """
    
    # Récupérer l'ID de la session depuis l'URL
    session_id = request.args.get('session_id')
    
    if session_id:
        # Récupérer les détails de la session
        session = stripe.checkout.Session.retrieve(session_id)
        
        # Vérifier le statut
        if session.payment_status == 'paid':
            # Paiement confirmé!
            customer_email = session.customer_details.email
            amount = session.amount_total / 100  # Convertir centimes en euros
            
            return f"""
            <html>
            <body style="font-family: Arial; text-align: center; padding: 50px;">
                <h1 style="color: #28a745;">[OK] Paiement réussi!</h1>
                <p>Merci pour votre achat de {amount:.2f}€</p>
                <p>Un email de confirmation a été envoyé à: {customer_email}</p>
                <p>Vous allez recevoir vos accès dans quelques instants.</p>
                <a href="/" style="color: #5469d4;">Retour à l'accueil</a>
            </body>
            </html>
            """
    
    return "Session invalide", 400


# === PAGE D'ANNULATION: /cancel ===

@app.route('/cancel')
def cancel():
    """
    Page affichée si le client annule le paiement
    """
    
    return """
    <html>
    <body style="font-family: Arial; text-align: center; padding: 50px;">
        <h1>Paiement annulé</h1>
        <p>Vous avez annulé le paiement.</p>
        <p>Aucun montant n'a été débité.</p>
        <a href="/" style="color: #5469d4;">Retour à l'accueil</a>
    </body>
    </html>
    """


# === CHECKOUT SESSION AVEC PRIX PRÉ-CRÉÉ ===

# Au lieu de créer le price inline, tu peux utiliser un Price existant

# Étape 1: Créer un Price dans le Dashboard ou via API

price = stripe.Price.create(
    unit_amount=4900,  # 49.00€
    currency='eur',
    product_data={
        'name': 'Formation Python Complet',
    },
)
# Retourne: Price(id='price_1234567890abcdef')

# Étape 2: Utiliser ce Price dans la Checkout Session

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    mode='payment',
    line_items=[{
        'price': 'price_1234567890abcdef',  # ID du Price
        'quantity': 1,
    }],
    success_url='https://monsite.com/success?session_id={CHECKOUT_SESSION_ID}',
    cancel_url='https://monsite.com/cancel',
)

# Avantage: Tu gères tes prix dans le Dashboard
# Change le prix sans redéployer le code!


# === CHECKOUT SESSION AVEC QUANTITÉ AJUSTABLE ===

# Permet au client de choisir la quantité (ex: billets d'événement)

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    mode='payment',
    line_items=[{
        'price': 'price_ticket_event',  # ID du Price
        'quantity': 1,
        'adjustable_quantity': {
            'enabled': True,
            'minimum': 1,
            'maximum': 10,
        },
    }],
    success_url='https://monsite.com/success?session_id={CHECKOUT_SESSION_ID}',
    cancel_url='https://monsite.com/cancel',
)

# Sur la page Stripe, le client voit:
# [Billet d'événement] [- 1 +] [20.00€]
# Il peut augmenter/diminuer la quantité!


# === CHECKOUT SESSION POUR ABONNEMENT ===

# Créer un abonnement récurrent (mensuel, annuel, etc.)

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    mode='subscription',  # Mode abonnement!
    line_items=[{
        'price': 'price_subscription_monthly',  # Price récurrent
        'quantity': 1,
    }],
    success_url='https://monsite.com/success?session_id={CHECKOUT_SESSION_ID}',
    cancel_url='https://monsite.com/cancel',
    
    # Options spécifiques abonnements:
    subscription_data={
        'trial_period_days': 7,
        # 7 jours gratuits avant le premier paiement
        
        'metadata': {
            'user_id': '123',
            'plan': 'premium',
        },
    },
)

# Le client paie 0€ aujourd'hui (essai gratuit)
# Dans 7 jours: Premier paiement automatique
# Puis tous les mois: Renouvellement automatique


# === CHECKOUT SESSION AVEC FRAIS D'APPLICATION ===

# Si tu es une plateforme (marketplace), tu peux prendre une commission

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    mode='payment',
    line_items=[{
        'price_data': {
            'currency': 'eur',
            'product_data': {'name': 'Cours de yoga'},
            'unit_amount': 5000,  # 50.00€
        },
        'quantity': 1,
    }],
    success_url='https://monsite.com/success',
    cancel_url='https://monsite.com/cancel',
    
    # Commission de 10% pour la plateforme
    payment_intent_data={
        'application_fee_amount': 500,  # 5.00€ (10% de 50€)
        'transfer_data': {
            'destination': 'acct_professeur_yoga',
            # Compte Stripe Connect du vendeur
        },
    },
)

# Résultat:
# - Client paie: 50.00€
# - Professeur reçoit: 45.00€
# - Tu gardes: 5.00€ (commission)


[OK] WEBHOOKS - ÉCOUTER LES ÉVÉNEMENTS STRIPE (ULTRA-DÉTAILLÉ)

# === POURQUOI LES WEBHOOKS SONT CRITIQUES ===

# Imagine:
# 1. Client paie 49€ sur Stripe Checkout
# 2. Stripe redirige vers /success
# 3. Tu actives l'accès au cours
# 4. PROBLÈME: Le client ferme le navigateur AVANT la redirection!
# 5. Résultat: Il a payé mais pas d'accès!

# OU PIRE:
# 1. Client tape l'URL /success directement (sans payer)
# 2. Ton code voit la page /success = accès activé
# 3. Résultat: Accès gratuit sans payer!

# SOLUTION: Les Webhooks!
# Stripe envoie une requête POST à ton serveur
# Contient: Confirmation du paiement
# Tu vérifies: La signature (sécurité)
# Tu actives: L'accès seulement si signature valide

# === QU'EST-CE QU'UN WEBHOOK? ===

# Un Webhook = Une notification HTTP de Stripe vers ton serveur
# Format: POST request avec un body JSON
# Envoyé: Automatiquement quand un événement se produit

# Événements possibles:
# - checkout.session.completed: Checkout Session terminée
# - payment_intent.succeeded: Paiement réussi
# - payment_intent.payment_failed: Paiement échoué
# - customer.subscription.created: Abonnement créé
# - customer.subscription.deleted: Abonnement annulé
# - invoice.paid: Facture payée
# - invoice.payment_failed: Facture impayée
# - charge.refunded: Remboursement effectué
# - ... 300+ événements!

# === FLUX COMPLET D'UN WEBHOOK ===

# Étape 1: ÉVÉNEMENT se produit sur Stripe
# Exemple: Un client paie 49€ via Checkout

# Étape 2: STRIPE envoie immédiatement une requête
# POST https://monsite.com/webhook
# Headers:
#   - Stripe-Signature: t=1234567890,v1=abc123...
# Body (JSON):
#   {
#     "id": "evt_1234567890",
#     "type": "checkout.session.completed",
#     "data": {
#       "object": {
#         "id": "cs_test_abc123",
#         "amount_total": 4900,
#         "customer_email": "client@example.com",
#         ...
#       }
#     }
#   }

# Étape 3: TON SERVEUR reçoit la requête
# Vérifie: La signature (sécurité critique!)
# Parse: Le JSON
# Exécute: L'action appropriée

# Étape 4: TON SERVEUR répond
# Retourne: HTTP 200 OK
# Si erreur: Stripe réessaie automatiquement!


# === CONFIGURER LES WEBHOOKS ===

# Méthode 1: Via Dashboard (Production)

# 1. Ouvre: https://dashboard.stripe.com/webhooks
# 2. Clique: "Add endpoint"
# 3. Entre URL: https://monsite.com/webhook
# 4. Sélectionne événements:
#    - checkout.session.completed
#    - payment_intent.succeeded
#    - customer.subscription.created
#    - Ou "Tous les événements" (pour débuter)
# 5. Clique: "Add endpoint"
# 6. Copie: Signing secret (whsec_...)
#    Exemple: whsec_1234567890abcdefghijklmnopqrstuvwxyz

# Méthode 2: Via CLI (Développement local)

# Installer Stripe CLI:
# https://stripe.com/docs/stripe-cli

# macOS:
brew install stripe/stripe-cli/stripe

# Windows:
# Télécharge: https://github.com/stripe/stripe-cli/releases/latest

# Linux:
wget https://github.com/stripe/stripe-cli/releases/download/v1.15.0/stripe_1.15.0_linux_x86_64.tar.gz
tar -xvf stripe_1.15.0_linux_x86_64.tar.gz
sudo mv stripe /usr/local/bin/

# Se connecter:
stripe login
# Ouvre un navigateur pour authentification

# Lancer le tunnel (forward webhooks vers localhost):
stripe listen --forward-to localhost:5000/webhook

# Affiche:
# > Ready! Your webhook signing secret is whsec_abc123xyz (^C to quit)

# Maintenant, tous les webhooks Stripe arrivent sur http://localhost:5000/webhook


# === IMPLÉMENTER LE ENDPOINT WEBHOOK ===

import stripe
from flask import Flask, request, jsonify
import os

app = Flask(__name__)

stripe.api_key = os.environ.get('STRIPE_SECRET_KEY')
webhook_secret = os.environ.get('STRIPE_WEBHOOK_SECRET')
# whsec_... (depuis Dashboard ou CLI)


@app.route('/webhook', methods=['POST'])
def stripe_webhook():
    """
    Endpoint pour recevoir les webhooks de Stripe
    
    SÉCURITÉ CRITIQUE: Toujours vérifier la signature!
    Sans ça, n'importe qui peut envoyer de fausses requêtes!
    """
    
    # Récupérer le body brut (raw) de la requête
    payload = request.data
    # IMPORTANT: request.data (pas request.json)
    # Sinon la signature ne correspondra pas!
    
    # Récupérer la signature du header
    sig_header = request.headers.get('Stripe-Signature')
    
    try:
        # Vérifier la signature et construire l'événement
        event = stripe.Webhook.construct_event(
            payload,         # Body brut
            sig_header,      # Signature
            webhook_secret   # Secret partagé
        )
        # Si la signature est invalide, une exception est levée!
        
    except ValueError as e:
        # Body JSON invalide
        print(f'[X] Invalid payload: {e}')
        return jsonify({'error': 'Invalid payload'}), 400
    
    except stripe.error.SignatureVerificationError as e:
        # Signature invalide = requête frauduleuse!
        print(f'[X] Invalid signature: {e}')
        return jsonify({'error': 'Invalid signature'}), 400
    
    # Signature valide! On peut traiter l'événement
    
    # Récupérer le type d'événement
    event_type = event['type']
    
    print(f'[OK] Webhook reçu: {event_type}')
    
    # === GÉRER LES DIFFÉRENTS ÉVÉNEMENTS ===
    
    if event_type == 'checkout.session.completed':
        # Checkout Session terminée
        handle_checkout_session_completed(event)
    
    elif event_type == 'payment_intent.succeeded':
        # Paiement réussi
        handle_payment_intent_succeeded(event)
    
    elif event_type == 'payment_intent.payment_failed':
        # Paiement échoué
        handle_payment_intent_failed(event)
    
    elif event_type == 'customer.subscription.created':
        # Abonnement créé
        handle_subscription_created(event)
    
    elif event_type == 'customer.subscription.deleted':
        # Abonnement annulé
        handle_subscription_deleted(event)
    
    elif event_type == 'invoice.paid':
        # Facture payée
        handle_invoice_paid(event)
    
    elif event_type == 'invoice.payment_failed':
        # Facture impayée
        handle_invoice_payment_failed(event)
    
    else:
        # Événement non géré
        print(f'[ATTENTION] Unhandled event type: {event_type}')
    
    # === IMPLÉMENTER LE ENDPOINT WEBHOOK (SUITE) ===

    # Retourner 200 OK (important!)
    # Si tu ne retournes pas 200, Stripe réessaie!
    return jsonify({'status': 'success'}), 200


# === FONCTIONS DE GESTION DES ÉVÉNEMENTS ===

def handle_checkout_session_completed(event):
    """
    Gérer la fin d'une Checkout Session
    
    Appelé quand:
    - Client a terminé le paiement sur la page Stripe
    - Paiement confirmé (ou période d'essai commencée)
    
    Actions typiques:
    - Activer l'accès au produit
    - Envoyer email de confirmation
    - Créer un compte utilisateur
    - Enregistrer la commande dans ta DB
    """
    
    # Récupérer les données de la session
    session = event['data']['object']
    
    # Informations importantes:
    session_id = session['id']                    # cs_test_abc123
    customer_id = session['customer']             # cus_ABC123
    customer_email = session['customer_details']['email']  # client@example.com
    payment_status = session['payment_status']    # paid, unpaid, no_payment_required
    amount_total = session['amount_total']        # 4900 (49.00€ en centimes)
    currency = session['currency']                # eur
    
    # Métadonnées personnalisées (si tu en as ajouté):
    metadata = session.get('metadata', {})
    user_id = metadata.get('user_id')             # Ex: "123"
    order_id = metadata.get('order_id')           # Ex: "ORDER-456"
    
    print(f"[OK] Checkout Session complétée!")
    print(f"  - Session ID: {session_id}")
    print(f"  - Customer: {customer_email}")
    print(f"  - Montant: {amount_total / 100:.2f} {currency.upper()}")
    print(f"  - Statut: {payment_status}")
    
    # Actions à effectuer:
    
    if payment_status == 'paid':
        # Paiement réussi!
        
        # 1. Activer l'accès au produit
        activate_user_access(user_id, customer_id)
        
        # 2. Envoyer email de confirmation
        send_confirmation_email(customer_email, session_id)
        
        # 3. Enregistrer la commande
        save_order_to_database(order_id, session)
        
        print(f"[OK] Accès activé pour {customer_email}")
    
    elif payment_status == 'unpaid':
        # Paiement pas encore effectué (rare)
        print(f"[ATTENTION] Paiement en attente pour {customer_email}")
    
    elif payment_status == 'no_payment_required':
        # Période d'essai gratuite (aucun paiement)
        print(f"[OK] Période d'essai commencée pour {customer_email}")
        activate_trial_access(user_id, customer_id)


def handle_payment_intent_succeeded(event):
    """
    Gérer un paiement réussi
    
    Appelé quand:
    - Un PaymentIntent est confirmé avec succès
    - L'argent a été débité de la carte
    
    Note: Si tu utilises Checkout Session, tu recevras AUSSI
    checkout.session.completed. Évite de traiter 2 fois!
    """
    
    payment_intent = event['data']['object']
    
    # Informations:
    payment_intent_id = payment_intent['id']      # pi_abc123
    amount = payment_intent['amount']             # 5000 (50.00€)
    currency = payment_intent['currency']         # eur
    customer_id = payment_intent['customer']      # cus_ABC123
    
    print(f"[OK] Paiement réussi!")
    print(f"  - PaymentIntent ID: {payment_intent_id}")
    print(f"  - Montant: {amount / 100:.2f} {currency.upper()}")
    
    # Action: Enregistrer le paiement
    record_payment_success(payment_intent_id, amount, customer_id)


def handle_payment_intent_failed(event):
    """
    Gérer un paiement échoué
    
    Appelé quand:
    - La carte est refusée
    - Fonds insuffisants
    - Carte expirée
    - Erreur de 3D Secure
    """
    
    payment_intent = event['data']['object']
    
    # Informations:
    payment_intent_id = payment_intent['id']
    amount = payment_intent['amount']
    customer_id = payment_intent['customer']
    
    # Raison de l'échec:
    last_payment_error = payment_intent.get('last_payment_error')
    if last_payment_error:
        error_code = last_payment_error.get('code')       # Ex: card_declined
        error_message = last_payment_error.get('message') # Ex: "Your card was declined"
    else:
        error_code = "unknown"
        error_message = "Unknown error"
    
    print(f"[X] Paiement échoué!")
    print(f"  - PaymentIntent ID: {payment_intent_id}")
    print(f"  - Raison: {error_code} - {error_message}")
    
    # Actions:
    
    # 1. Enregistrer l'échec
    record_payment_failure(payment_intent_id, error_code)
    
    # 2. Envoyer email au client
    send_payment_failed_email(customer_id, error_message)
    
    # 3. Proposer un autre moyen de paiement
    # (envoie un lien vers une nouvelle Checkout Session)


def handle_subscription_created(event):
    """
    Gérer la création d'un abonnement
    
    Appelé quand:
    - Un client souscrit à un abonnement
    - Après le premier paiement (ou début de période d'essai)
    """
    
    subscription = event['data']['object']
    
    # Informations:
    subscription_id = subscription['id']          # sub_abc123
    customer_id = subscription['customer']        # cus_ABC123
    status = subscription['status']               # active, trialing, etc.
    current_period_end = subscription['current_period_end']  # Timestamp
    
    # Items de l'abonnement (produits):
    items = subscription['items']['data']
    for item in items:
        price_id = item['price']['id']
        product_id = item['price']['product']
        quantity = item['quantity']
        
        print(f"[OK] Abonnement créé!")
        print(f"  - Subscription ID: {subscription_id}")
        print(f"  - Customer: {customer_id}")
        print(f"  - Product: {product_id}")
        print(f"  - Statut: {status}")
    
    # Actions:
    
    if status == 'active':
        # Abonnement actif (paiement réussi)
        activate_subscription_access(customer_id, subscription_id)
    
    elif status == 'trialing':
        # Période d'essai gratuite
        activate_trial_subscription(customer_id, subscription_id)


def handle_subscription_deleted(event):
    """
    Gérer l'annulation d'un abonnement
    
    Appelé quand:
    - Client annule son abonnement
    - Abonnement expire après non-paiement
    """
    
    subscription = event['data']['object']
    
    subscription_id = subscription['id']
    customer_id = subscription['customer']
    
    print(f"[X] Abonnement annulé!")
    print(f"  - Subscription ID: {subscription_id}")
    print(f"  - Customer: {customer_id}")
    
    # Actions:
    
    # 1. Désactiver l'accès
    deactivate_subscription_access(customer_id, subscription_id)
    
    # 2. Envoyer email de confirmation
    send_cancellation_email(customer_id)
    
    # 3. Enregistrer la raison (si disponible)
    cancellation_details = subscription.get('cancellation_details')
    if cancellation_details:
        reason = cancellation_details.get('reason')  # Ex: "customer_canceled"
        print(f"  - Raison: {reason}")


def handle_invoice_paid(event):
    """
    Gérer une facture payée
    
    Appelé quand:
    - Facture d'abonnement payée (renouvellement)
    - Facture manuelle payée
    """
    
    invoice = event['data']['object']
    
    invoice_id = invoice['id']                    # in_abc123
    customer_id = invoice['customer']             # cus_ABC123
    amount_paid = invoice['amount_paid']          # 2900 (29.00€)
    subscription_id = invoice.get('subscription') # sub_abc123 (si abonnement)
    
    print(f"[OK] Facture payée!")
    print(f"  - Invoice ID: {invoice_id}")
    print(f"  - Montant: {amount_paid / 100:.2f} EUR")
    
    # Actions:
    
    # 1. Prolonger l'abonnement (si applicable)
    if subscription_id:
        extend_subscription_period(customer_id, subscription_id)
    
    # 2. Envoyer le reçu par email
    send_invoice_receipt(customer_id, invoice_id)


def handle_invoice_payment_failed(event):
    """
    Gérer une facture impayée
    
    Appelé quand:
    - Renouvellement d'abonnement échoue
    - Carte expirée / refusée
    """
    
    invoice = event['data']['object']
    
    invoice_id = invoice['id']
    customer_id = invoice['customer']
    amount_due = invoice['amount_due']
    subscription_id = invoice.get('subscription')
    
    print(f"[X] Facture impayée!")
    print(f"  - Invoice ID: {invoice_id}")
    print(f"  - Montant dû: {amount_due / 100:.2f} EUR")
    
    # Actions:
    
    # 1. Marquer l'abonnement comme "past_due"
    if subscription_id:
        mark_subscription_past_due(customer_id, subscription_id)
    
    # 2. Envoyer email de relance
    send_payment_reminder_email(customer_id, amount_due)
    
    # 3. Stripe réessaiera automatiquement selon ta config
    # (Dashboard > Settings > Subscriptions > Payment retry)


# === FONCTIONS HELPER (À IMPLÉMENTER SELON TON APP) ===

def activate_user_access(user_id, customer_id):
    """Activer l'accès au produit pour l'utilisateur"""
    # Exemple: Mettre à jour la base de données
    # db.execute("UPDATE users SET has_access=TRUE WHERE id=?", user_id)
    pass

def send_confirmation_email(email, session_id):
    """Envoyer email de confirmation"""
    # Exemple: Utiliser SendGrid, Mailgun, etc.
    pass

def save_order_to_database(order_id, session_data):
    """Enregistrer la commande dans la DB"""
    pass

def activate_trial_access(user_id, customer_id):
    """Activer l'accès période d'essai"""
    pass

def record_payment_success(payment_intent_id, amount, customer_id):
    """Enregistrer le paiement réussi"""
    pass

def record_payment_failure(payment_intent_id, error_code):
    """Enregistrer l'échec de paiement"""
    pass

def send_payment_failed_email(customer_id, error_message):
    """Envoyer email d'échec de paiement"""
    pass

def activate_subscription_access(customer_id, subscription_id):
    """Activer l'accès abonnement"""
    pass

def activate_trial_subscription(customer_id, subscription_id):
    """Activer période d'essai abonnement"""
    pass

def deactivate_subscription_access(customer_id, subscription_id):
    """Désactiver l'accès abonnement"""
    pass

def send_cancellation_email(customer_id):
    """Envoyer email de confirmation d'annulation"""
    pass

def extend_subscription_period(customer_id, subscription_id):
    """Prolonger la période d'abonnement"""
    pass

def send_invoice_receipt(customer_id, invoice_id):
    """Envoyer le reçu de facture"""
    pass

def mark_subscription_past_due(customer_id, subscription_id):
    """Marquer abonnement en retard de paiement"""
    pass

def send_payment_reminder_email(customer_id, amount_due):
    """Envoyer email de relance paiement"""
    pass


# === TESTER LES WEBHOOKS LOCALEMENT ===

# Stripe CLI permet de tester les webhooks sur ton ordinateur!

# Étape 1: Installer Stripe CLI (si pas fait)
# https://stripe.com/docs/stripe-cli

# Étape 2: Se connecter
stripe login

# Étape 3: Lancer le serveur Flask
python app.py
# Ton app tourne sur http://localhost:5000

# Étape 4: Dans un autre terminal, lancer le tunnel
stripe listen --forward-to localhost:5000/webhook

# Affiche:
# > Ready! Your webhook signing secret is whsec_abc123xyz (^C to quit)

# COPIE ce secret dans ton .env:
# STRIPE_WEBHOOK_SECRET=whsec_abc123xyz

# Étape 5: Déclencher un événement test
stripe trigger checkout.session.completed

# Affiche:
# Running fixture for: checkout.session.completed
# Trigger succeeded! Check dashboard for event details.

# Ton terminal Flask affiche:
# [OK] Webhook reçu: checkout.session.completed
# [OK] Checkout Session complétée!

# Tu peux tester tous les événements:
stripe trigger payment_intent.succeeded
stripe trigger payment_intent.payment_failed
stripe trigger customer.subscription.created
stripe trigger invoice.paid


# === DÉPLOYER LES WEBHOOKS EN PRODUCTION ===

# Étape 1: Déployer ton app sur Heroku (ou autre)
# Ton endpoint webhook doit être accessible publiquement
# Exemple: https://monapp.herokuapp.com/webhook

# Étape 2: Ajouter l'endpoint dans le Dashboard Stripe
# 1. Ouvre: https://dashboard.stripe.com/webhooks
# 2. Clique: "Add endpoint"
# 3. Entre URL: https://monapp.herokuapp.com/webhook
# 4. Sélectionne les événements:
#    - checkout.session.completed
#    - payment_intent.succeeded
#    - payment_intent.payment_failed
#    - customer.subscription.created
#    - customer.subscription.deleted
#    - invoice.paid
#    - invoice.payment_failed
# 5. Clique: "Add endpoint"

# Étape 3: Copier le Signing Secret
# Dashboard affiche: whsec_live_xxxxxxxxxxxxxxxx
# Ajoute-le aux variables d'environnement Heroku:
heroku config:set STRIPE_WEBHOOK_SECRET=whsec_live_xxxxxxxxxxxxxxxx

# Étape 4: Vérifier
# Fais un vrai paiement test
# Dashboard > Events
# Tu vois les webhooks envoyés!


[OK] ABONNEMENTS AVANCÉS (TRÈS DÉTAILLÉ)

# === CRÉER UN ABONNEMENT COMPLET ===

# Scénario:
# Tu veux vendre un abonnement "Pro" à 29€/mois
# Avec 7 jours d'essai gratuit

# === ÉTAPE 1: Créer le Product ===

product = stripe.Product.create(
    name="Abonnement Pro",
    description="Accès complet à toutes les fonctionnalités",
    metadata={
        "plan_level": "pro"
    }
)

print(f"Product créé: {product.id}")
# Exemple: prod_abc123


# === ÉTAPE 2: Créer le Price (tarif récurrent) ===

price = stripe.Price.create(
    product=product.id,
    unit_amount=2900,  # 29.00€
    currency="eur",
    recurring={
        "interval": "month",  # Mensuel
        "interval_count": 1   # Tous les 1 mois
    },
    metadata={
        "plan": "pro_monthly"
    }
)

print(f"Price créé: {price.id}")
# Exemple: price_xyz789


# === ÉTAPE 3: Créer une Checkout Session pour l'abonnement ===

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    
    mode='subscription',  # Mode abonnement!
    
    line_items=[{
        'price': price.id,  # Le Price créé précédemment
        'quantity': 1,
    }],
    
    success_url='https://monsite.com/success?session_id={CHECKOUT_SESSION_ID}',
    cancel_url='https://monsite.com/cancel',
    
    # === OPTIONS SPÉCIFIQUES ABONNEMENT ===
    
    # Période d'essai gratuite
    subscription_data={
        'trial_period_days': 7,  # 7 jours gratuits
        
        # Métadonnées personnalisées
        'metadata': {
            'user_id': '123',
            'plan': 'pro',
            'source': 'website'
        },
        
        # Description de l'abonnement
        'description': 'Abonnement Pro - Utilisateur #123',
    },
    
    # Email pré-rempli
    customer_email='client@example.com',
    
    # Permettre codes promo
    allow_promotion_codes=True,
)

print(f"Checkout Session: {checkout_session.url}")
# Redirige le client vers cette URL!


# === CYCLE DE VIE D'UN ABONNEMENT ===

# JOUR 1: Création
# - Client souscrit via Checkout Session
# - Statut: trialing (période d'essai)
# - Webhook: customer.subscription.created
# - Aucun paiement débité

# JOUR 7: Fin de la période d'essai
# - Statut: active
# - Premier paiement: 29.00€ débité
# - Webhook: invoice.paid
# - Abonnement démarre officiellement

# JOUR 37: Renouvellement automatique (30 jours après J7)
# - Stripe débite automatiquement 29.00€
# - Webhook: invoice.paid
# - Abonnement continue

# SI PAIEMENT ÉCHOUE:
# - Statut: past_due (en retard)
# - Webhook: invoice.payment_failed
# - Stripe réessaie selon ta configuration (3-4 fois)

# JOUR 40: Paiement réussi après retry
# - Statut: active (retour à la normale)
# - Webhook: invoice.paid

# CLIENT ANNULE:
# - Statut: canceled (si annulation immédiate)
# - OU active jusqu'à la fin de la période payée
# - Webhook: customer.subscription.deleted


# === GÉRER LES ABONNEMENTS ===

# === Récupérer un abonnement ===

subscription = stripe.Subscription.retrieve('sub_abc123')

print(f"Abonnement: {subscription.id}")
print(f"Statut: {subscription.status}")
print(f"Customer: {subscription.customer}")
print(f"Prix: {subscription.plan.amount / 100:.2f} EUR")
print(f"Prochain paiement: {subscription.current_period_end}")


# === Lister les abonnements d'un client ===

subscriptions = stripe.Subscription.list(
    customer='cus_ABC123',
    status='active'  # Filtre: seulement les actifs
)

for sub in subscriptions.data:
    print(f"- {sub.id}: {sub.status}")


# === Modifier un abonnement ===

# Exemple: Changer de plan (upgrade/downgrade)

# Client veut passer de "Pro" (29€) à "Premium" (49€)

subscription = stripe.Subscription.modify(
    'sub_abc123',
    items=[{
        'id': subscription.items.data[0].id,  # Item actuel
        'price': 'price_premium_monthly',     # Nouveau Price
    }],
    proration_behavior='create_prorations'  # Calculer au prorata
)

# Explications:
# proration_behavior options:
# - 'create_prorations': Crée un crédit/débit pour la différence
# - 'none': Pas de prorata, change au prochain cycle
# - 'always_invoice': Facture immédiatement la différence

# Exemple de prorata:
# Client a payé 29€ le 1er janvier pour janvier
# Il upgrade le 15 janvier (mi-mois)
# Il a utilisé 15 jours de "Pro" (29€ / 31 jours × 15 = ~14€)
# Il lui reste 16 jours (29€ / 31 jours × 16 = ~15€ de crédit)
# Nouveau plan "Premium" pour 16 jours: 49€ / 31 × 16 = ~25€
# Différence: 25€ - 15€ = 10€ à payer immédiatement


# === Annuler un abonnement ===

# Option 1: Annulation immédiate
subscription = stripe.Subscription.delete('sub_abc123')
# L'abonnement s'arrête MAINTENANT
# Webhook: customer.subscription.deleted

# Option 2: Annulation à la fin de la période
subscription = stripe.Subscription.modify(
    'sub_abc123',
    cancel_at_period_end=True
)
# L'abonnement continue jusqu'à la fin du mois payé
# Puis s'annule automatiquement
# Webhook: customer.subscription.deleted (à la fin de la période)


# === Réactiver un abonnement annulé ===

# Si cancel_at_period_end=True et pas encore expiré:
subscription = stripe.Subscription.modify(
    'sub_abc123',
    cancel_at_period_end=False
)
# L'abonnement continue normalement


# === Suspendre un abonnement (pause) ===

# Exemple: Client en vacances, veut suspendre 2 mois

subscription = stripe.Subscription.modify(
    'sub_abc123',
    pause_collection={
        'behavior': 'mark_uncollectible',  # Ne pas facturer
        'resumes_at': 1704067200  # Timestamp: 1er mars 2024
    }
)

# Pendant la pause:
# - Pas de facture générée
# - Pas de paiement débité
# - Statut: paused
# - À la date spécifiée: reprend automatiquement


# === Ajouter une période d'essai à un abonnement existant ===

subscription = stripe.Subscription.modify(
    'sub_abc123',
    trial_end=int(time.time()) + (7 * 24 * 60 * 60)  # +7 jours
)


# === GÉRER LES ÉCHECS DE PAIEMENT ===

# Stripe gère automatiquement les retries!
# Configuration dans: Dashboard > Settings > Subscriptions > Payment retry

# Par défaut:
# - Jour 0: Échec initial
# - Jour 3: Retry 1
# - Jour 5: Retry 2
# - Jour 7: Retry 3
# - Jour 7+: Abonnement marqué "unpaid" ou "canceled"

# Tu peux personnaliser:
# - Nombre de retries
# - Délais entre retries
# - Actions automatiques (email, suspension, annulation)


# === CODES PROMO ET RÉDUCTIONS ===

# === Créer un code promo ===

# Option 1: Réduction en pourcentage

coupon = stripe.Coupon.create(
    percent_off=20,  # 20% de réduction
    duration='repeating',
    duration_in_months=3,  # 3 premiers mois
    name="PROMO20",
    metadata={
        "campaign": "summer_2024"
    }
)

# Option 2: Réduction montant fixe

coupon = stripe.Coupon.create(
    amount_off=500,  # 5.00€ de réduction
    currency='eur',
    duration='once',  # Une seule fois
    name="WELCOME5"
)

# Option 3: Réduction permanente

coupon = stripe.Coupon.create(
    percent_off=10,
    duration='forever',  # Pour toujours!
    name="VIP10"
)


# === Créer un code promo (avec code à entrer) ===

promotion_code = stripe.PromotionCode.create(
    coupon=coupon.id,
    code='SUMMER2024',  # Code à entrer sur Checkout
    max_redemptions=100,  # Limite: 100 utilisations
    restrictions={
        'first_time_transaction': True,  # Seulement nouveaux clients
        'minimum_amount': 2000,  # Minimum 20.00€
        'minimum_amount_currency': 'eur'
    }
)


# === Appliquer un code promo à une Checkout Session ===

checkout_session = stripe.checkout.Session.create(
    # ... configuration normale ...
    
    allow_promotion_codes=True,
    # Affiche un champ "Code promo" sur la page de paiement
    
    # OU appliquer automatiquement:
    discounts=[{
        'promotion_code': promotion_code.id
    }]
)


# === Appliquer un code promo à un abonnement existant ===

subscription = stripe.Subscription.modify(
    'sub_abc123',
    coupon=coupon.id
)


# === FACTURATION AVANCÉE ===

# === Créer une facture manuelle ===

# Étape 1: Créer des items de facture

stripe.InvoiceItem.create(
    customer='cus_ABC123',
    amount=4900,  # 49.00€
    currency='eur',
    description='Consultation 1h - Développement web'
)

stripe.InvoiceItem.create(
    customer='cus_ABC123',
    amount=2000,  # 20.00€
    currency='eur',
    description='Hébergement mensuel'
)

# Étape 2: Créer la facture

invoice = stripe.Invoice.create(
    customer='cus_ABC123',
    auto_advance=True,  # Finaliser automatiquement
    collection_method='send_invoice',  # Envoyer par email
    days_until_due=7  # Échéance: 7 jours
)

# Étape 3: Finaliser et envoyer

invoice = stripe.Invoice.finalize_invoice(invoice.id)

# Stripe envoie automatiquement l'email avec:
# - Lien pour payer en ligne
# - PDF de la facture


# === Générer un PDF de facture ===

invoice = stripe.Invoice.retrieve('in_abc123')

pdf_url = invoice.invoice_pdf
# Exemple: https://pay.stripe.com/invoice/invst_xxx/pdf

# Télécharger le PDF:
import requests
response = requests.get(pdf_url)
with open('facture.pdf', 'wb') as f:
    f.write(response.content)


# === MÉTHODES DE PAIEMENT MULTIPLES ===

# Stripe supporte 40+ méthodes de paiement!

# === Checkout Session avec plusieurs méthodes ===

checkout_session = stripe.checkout.Session.create(
    payment_method_types=[
        'card',          # Cartes bancaires
        'apple_pay',     # Apple Pay
        'google_pay',    # Google Pay
        'sepa_debit',    # Prélèvement SEPA (Europe)
        'ideal',         # iDEAL (Pays-Bas)
        'bancontact',    # Bancontact (Belgique)
        'giropay',       # Giropay (Allemagne)
        'sofort',        # Sofort (Europe)
        'klarna',        # Klarna (Buy Now Pay Later)
        'afterpay_clearpay',  # Afterpay (BNPL)
        'alipay',        # Alipay (Chine)
        'wechat_pay',    # WeChat Pay (Chine)
    ],
    mode='payment',
    line_items=[{
        'price_data': {
            'currency': 'eur',
            'product_data': {'name': 'Produit'},
            'unit_amount': 5000,
        },
        'quantity': 1,
    }],
    success_url='https://monsite.com/success',
    cancel_url='https://monsite.com/cancel',
)

# Stripe affiche automatiquement les méthodes disponibles
# selon le pays du client!


# === REMBOURSEMENTS ===

# === Rembourser un paiement entièrement ===

refund = stripe.Refund.create(
    payment_intent='pi_abc123',
    reason='requested_by_customer'  # Raison
)

# Reasons possibles:
# - 'duplicate': Paiement en double
# - 'fraudulent': Fraude détectée
# - 'requested_by_customer': Demande du client


# === Remboursement partiel ===

refund = stripe.Refund.create(
    payment_intent='pi_abc123',
    amount=2000,  # Rembourser 20.00€ seulement
    reason='requested_by_customer'
)


# === Vérifier le statut d'un remboursement ===

refund = stripe.Refund.retrieve('re_abc123')

print(f"Statut: {refund.status}")
# statuses:
# - pending: En cours
# - succeeded: Remboursement effectué
# - failed: Échec du remboursement
# - canceled: Annulé

print(f"Montant remboursé: {refund.amount / 100:.2f} EUR")


# === Lister tous les remboursements d'un paiement ===

refunds = stripe.Refund.list(payment_intent='pi_abc123')

for refund in refunds.data:
    print(f"- {refund.id}: {refund.amount / 100:.2f} EUR - {refund.status}")


[OK] TESTS ET CARTES DE TEST (ULTRA-DÉTAILLÉ)

# === POURQUOI TESTER? ===

# Avant de déployer en production avec de VRAIS paiements:
# - Tu dois tester TOUS les scénarios (succès, échec, 3D Secure, etc.)
# - Stripe fournit des cartes de test pour simuler différentes situations
# - AUCUN argent réel n'est débité en mode test!

# === ACTIVER LE MODE TEST ===

# Sur le Dashboard Stripe:
# 1. En haut à droite: toggle "Test mode"
# 2. Le fond devient violet/bleu
# 3. Toutes les clés API commencent par "pk_test_" et "sk_test_"

# Dans ton code Python:
stripe.api_key = "sk_test_51xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# Utilise TOUJOURS les clés test en développement!


# === CARTES DE TEST STRIPE ===

# === CARTE 1: Succès (toujours) ===
# Numéro: 4242 4242 4242 4242
# Date expiration: N'importe quelle date future (ex: 12/25)
# CVC: N'importe quel 3 chiffres (ex: 123)
# ZIP: N'importe quel code postal (ex: 75001)

# Utilisation:
# - Teste un paiement qui RÉUSSIT toujours
# - Parfait pour tester le flow nominal

# Test:
payment_intent = stripe.PaymentIntent.create(
    amount=5000,
    currency='eur',
    payment_method_types=['card'],
)

# Frontend: Client entre 4242 4242 4242 4242
# Résultat: payment_intent.status = 'succeeded'


# === CARTE 2: Refus (toujours) ===
# Numéro: 4000 0000 0000 0002
# Utilisation:
# - Teste un paiement qui ÉCHOUE toujours
# - Raison: "generic_decline"

# Test:
# Client entre cette carte
# Résultat: Erreur "Your card was declined"
# payment_intent.status = 'requires_payment_method'


# === CARTE 3: Fonds insuffisants ===
# Numéro: 4000 0000 0000 9995
# Utilisation:
# - Teste un refus pour "insufficient_funds"
# - Simule un compte bancaire vide


# === CARTE 4: Carte expirée ===
# Numéro: 4000 0000 0000 0069
# Utilisation:
# - Teste un refus pour "expired_card"


# === CARTE 5: Carte volée ===
# Numéro: 4000 0000 0000 9979
# Utilisation:
# - Teste un refus pour "stolen_card"
# - Stripe bloque automatiquement


# === CARTE 6: CVC incorrect ===
# Numéro: 4000 0000 0000 0127
# Utilisation:
# - Teste un refus pour "incorrect_cvc"


# === CARTE 7: 3D Secure requis ===
# Numéro: 4000 0027 6000 3184
# Utilisation:
# - Teste l'authentification 3D Secure
# - Stripe affiche une popup d'authentification
# - Client doit cliquer "Authenticate" pour valider

# Test:
# Client entre cette carte
# Stripe affiche: "Authentification requise"
# Client clique "Authenticate" (ou "Complete authentication")
# Résultat: Paiement réussi


# === CARTE 8: 3D Secure échoué ===
# Numéro: 4000 0000 0000 0341
# Utilisation:
# - Teste un échec d'authentification 3D Secure
# - Client clique "Fail authentication"
# - Résultat: Paiement échoué


# === CARTE 9: Paiement en attente (asynchrone) ===
# Numéro: 4000 0000 0000 3220
# Utilisation:
# - Teste un paiement qui reste "processing" pendant 5 secondes
# - Puis devient "succeeded"
# - Simule un paiement lent


# === CARTE 10: Déclencheur de dispute (chargeback) ===
# Numéro: 4000 0000 0000 0259
# Utilisation:
# - Crée un paiement réussi
# - Puis déclenche automatiquement une dispute
# - Simule un client qui conteste le paiement


# === AUTRES CARTES PAR PAYS ===

# Visa (France):
# 4000 0025 0000 0003

# Visa (USA):
# 4000 0084 0000 0000

# Mastercard (général):
# 5555 5555 5555 4444

# American Express:
# 3782 822463 10005

# Discover:
# 6011 1111 1111 1117

# Diners Club:
# 3056 9300 0902 0004

# JCB:
# 3566 0020 2036 0505


# === TESTER LES WEBHOOKS ===

# === Méthode 1: Stripe CLI (local) ===

# Installer Stripe CLI:
# https://stripe.com/docs/stripe-cli

# Se connecter:
stripe login

# Lancer ton serveur Flask:
python app.py
# Tourne sur http://localhost:5000

# Lancer le tunnel webhooks:
stripe listen --forward-to localhost:5000/webhook

# Affiche:
# Ready! Your webhook signing secret is whsec_abc123
# (Copie ce secret dans .env)

# Déclencher un événement:
stripe trigger payment_intent.succeeded

# Ton serveur reçoit le webhook!
# Vérifie les logs Flask


# === Méthode 2: Dashboard Stripe (test mode) ===

# 1. Va sur: Dashboard > Developers > Webhooks
# 2. Clique sur ton endpoint webhook
# 3. Onglet "Send test webhook"
# 4. Choisis un événement (ex: payment_intent.succeeded)
# 5. Clique "Send test webhook"
# 6. Vérifie que ton serveur reçoit et traite correctement


# === SCÉNARIOS DE TEST COMPLETS ===

# === Scénario 1: Paiement simple réussi ===

# 1. Créer Checkout Session:
session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    mode='payment',
    line_items=[{
        'price_data': {
            'currency': 'eur',
            'product_data': {'name': 'Test Product'},
            'unit_amount': 2000,
        },
        'quantity': 1,
    }],
    success_url='http://localhost:5000/success',
    cancel_url='http://localhost:5000/cancel',
)

# 2. Ouvre session.url dans le navigateur
# 3. Entre carte: 4242 4242 4242 4242
# 4. Date: 12/25, CVC: 123
# 5. Clique "Payer"
# 6. Vérifie redirection vers /success
# 7. Vérifie webhook reçu: checkout.session.completed


# === Scénario 2: Paiement échoué ===

# 1. Même setup que Scénario 1
# 2. Entre carte: 4000 0000 0000 0002 (refus)
# 3. Stripe affiche: "Your card was declined"
# 4. Vérifie webhook reçu: payment_intent.payment_failed
# 5. Teste l'affichage de l'erreur côté client


# === Scénario 3: 3D Secure ===

# 1. Même setup
# 2. Entre carte: 4000 0027 6000 3184
# 3. Stripe affiche popup: "Authentification requise"
# 4. Clique "Complete authentication"
# 5. Vérifie paiement réussi
# 6. Vérifie webhook: payment_intent.succeeded


# === Scénario 4: Abonnement avec période d'essai ===

# 1. Créer Price récurrent:
price = stripe.Price.create(
    product='prod_test',
    unit_amount=2900,
    currency='eur',
    recurring={'interval': 'month'}
)

# 2. Créer Checkout Session:
session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    mode='subscription',
    line_items=[{'price': price.id, 'quantity': 1}],
    subscription_data={'trial_period_days': 7},
    success_url='http://localhost:5000/success',
    cancel_url='http://localhost:5000/cancel',
)

# 3. Entre carte test
# 4. Vérifie: subscription.status = 'trialing'
# 5. Vérifie: Aucun paiement immédiat
# 6. Simule fin période d'essai:
stripe trigger invoice.payment_succeeded


# === Scénario 5: Remboursement ===

# 1. Créer un paiement réussi (Scénario 1)
# 2. Récupérer PaymentIntent ID
# 3. Créer remboursement:
refund = stripe.Refund.create(payment_intent='pi_test_xxx')

# 4. Vérifie: refund.status = 'succeeded'
# 5. Vérifie webhook: charge.refunded


[OK] GESTION DES DISPUTES (CHARGEBACKS)

# === QU'EST-CE QU'UNE DISPUTE? ===

# Une dispute (chargeback) = Un client conteste un paiement
# Exemples de raisons:
# - "Je n'ai jamais reçu le produit"
# - "Ce n'est pas moi qui ai acheté" (fraude)
# - "Le produit est défectueux"
# - "J'ai été facturé 2 fois"

# Conséquences:
# - L'argent est gelé pendant l'enquête
# - Frais de dispute: 15€ (même si tu gagnes!)
# - Si tu perds: Le client récupère l'argent + tu paies les frais
# - Trop de disputes = Compte Stripe suspendu

# === PRÉVENIR LES DISPUTES ===

# Bonnes pratiques:

# 1. Description claire des produits
checkout_session = stripe.checkout.Session.create(
    # ...
    line_items=[{
        'price_data': {
            'product_data': {
                'name': 'Formation Python Complet',
                'description': 'Cours vidéo 20h + certificat + support',
                # Description TRÈS claire!
                'images': ['https://monsite.com/image.png']
            },
            # ...
        }
    }]
)

# 2. Envoyer des emails de confirmation
# Après chaque paiement, envoie:
# - Reçu détaillé
# - Informations de livraison / accès
# - Contact support

# 3. Utiliser Stripe Radar (détection fraude)
# Activé automatiquement!
# Bloque les paiements suspects

# 4. Demander la signature pour livraisons physiques

# 5. Garder des preuves:
# - Screenshots des emails envoyés
# - Logs d'accès au produit
# - Conversations support


# === RECEVOIR UNE DISPUTE ===

# Stripe envoie un webhook: charge.dispute.created

def handle_dispute_created(event):
    """Gérer une nouvelle dispute"""
    
    dispute = event['data']['object']
    
    dispute_id = dispute['id']              # dp_abc123
    charge_id = dispute['charge']           # ch_abc123
    amount = dispute['amount']              # 5000 (50.00€)
    reason = dispute['reason']              # Raison de la dispute
    status = dispute['status']              # needs_response, under_review, etc.
    
    # Raisons possibles:
    # - 'fraudulent': Fraude suspectée
    # - 'product_not_received': Produit non reçu
    # - 'product_unacceptable': Produit défectueux
    # - 'duplicate': Facturation en double
    # - 'subscription_canceled': Abonnement annulé mais facturé
    # - 'general': Autre raison
    
    print(f"[ATTENTION] DISPUTE reçue!")
    print(f"  - Dispute ID: {dispute_id}")
    print(f"  - Montant: {amount / 100:.2f} EUR")
    print(f"  - Raison: {reason}")
    
    # Actions:
    
    # 1. Alerter l'équipe
    send_alert_to_team(dispute_id, reason)
    
    # 2. Récupérer les preuves
    gather_evidence(charge_id)
    
    # 3. Préparer la réponse


# === RÉPONDRE À UNE DISPUTE ===

# Tu as 7 JOURS pour répondre avec des preuves!

# Récupérer la dispute:
dispute = stripe.Dispute.retrieve('dp_abc123')

# Soumettre des preuves:
dispute = stripe.Dispute.modify(
    'dp_abc123',
    evidence={
        # Nom du client:
        'customer_name': 'Jean Dupont',
        
        # Email du client:
        'customer_email_address': 'jean@example.com',
        
        # Adresse de facturation:
        'billing_address': '123 rue de la Paix, 75001 Paris, France',
        
        # Adresse IP du client lors de l'achat:
        'customer_purchase_ip': '81.2.3.4',
        
        # Reçu envoyé au client:
        'receipt': 'https://monsite.com/receipt/12345.pdf',
        
        # Politique de remboursement:
        'refund_policy': 'https://monsite.com/refund-policy',
        
        # URL de livraison / suivi:
        'shipping_tracking_number': '1Z999AA1234567890',
        'shipping_carrier': 'UPS',
        'shipping_date': '2024-01-15',
        
        # Preuve que le client a accédé au service:
        'access_activity_log': 'Client a accédé au cours 15 fois entre le 10/01 et le 20/01',
        
        # Correspondance avec le client:
        'customer_communication': 'Email de confirmation envoyé le 10/01, client a répondu "Merci"',
        
        # Description détaillée:
        'uncategorized_text': '''
        Le client a acheté la Formation Python le 10/01/2024.
        Il a immédiatement reçu un email de confirmation avec lien d'accès.
        Logs montrent qu'il a accédé au cours 15 fois du 10/01 au 20/01.
        Il a téléchargé 5 vidéos et complété 3 exercices.
        Aucune plainte ou demande de remboursement avant la dispute.
        '''
    },
    metadata={
        'internal_notes': 'Client actif, probable fraude friendly'
    }
)

# Stripe examine les preuves et décide:
# - Si tu gagnes: Argent débloqué, pas de frais
# - Si tu perds: Client récupère l'argent, tu paies 15€


# === UPLOADER DES FICHIERS COMME PREUVES ===

# Exemple: Screenshot d'email, facture PDF, etc.

# Étape 1: Uploader le fichier
with open('facture.pdf', 'rb') as f:
    file = stripe.File.create(
        purpose='dispute_evidence',
        file=f
    )

# Étape 2: Attacher à la dispute
dispute = stripe.Dispute.modify(
    'dp_abc123',
    evidence={
        'receipt': file.id  # Utilise l'ID du fichier uploadé
    }
)


# === FERMER UNE DISPUTE ===

# Si tu veux abandonner (tu reconnais avoir tort):
dispute = stripe.Dispute.close('dp_abc123')


[OK] STRIPE CONNECT (PLATEFORMES / MARKETPLACES)

# === QU'EST-CE QUE STRIPE CONNECT? ===

# Stripe Connect = Solution pour les plateformes/marketplaces
# Exemples:
# - Airbnb: Plateforme (Airbnb) + Vendeurs (hôtes)
# - Uber: Plateforme (Uber) + Vendeurs (chauffeurs)
# - Etsy: Plateforme (Etsy) + Vendeurs (artisans)

# Fonctionnalités:
# - Les vendeurs ont leur propre compte Stripe
# - Tu collectes les paiements pour eux
# - Tu prends une commission automatiquement
# - Ils gèrent leurs remboursements, disputes, etc.

# === TYPES DE COMPTES CONNECT ===

# 1. STANDARD ACCOUNTS
# - Le vendeur crée son propre compte Stripe
# - Il a accès complet au Dashboard
# - Il voit toutes ses transactions
# - Il gère ses propres taxes, factures
# Parfait pour: Vendeurs expérimentés, indépendants

# 2. EXPRESS ACCOUNTS
# - Compte simplifié
# - Onboarding rapide (5 minutes)
# - Dashboard limité
# - Tu gères une partie de la complexité
# Parfait pour: Petits vendeurs, freelancers

# 3. CUSTOM ACCOUNTS
# - Tu contrôles tout l'onboarding
# - Le vendeur ne voit jamais Stripe
# - Interface complètement personnalisée
# - Complexe à implémenter
# Parfait pour: Plateformes avec UX très spécifique


# === CRÉER UN COMPTE CONNECT (EXPRESS) ===

# Étape 1: Créer le compte

account = stripe.Account.create(
    type='express',
    country='FR',
    email='vendeur@example.com',
    capabilities={
        'card_payments': {'requested': True},
        'transfers': {'requested': True},
    },
    business_type='individual',  # ou 'company'
    metadata={
        'user_id': '123',
        'shop_name': 'Boutique de Jean'
    }
)

print(f"Account créé: {account.id}")
# Exemple: acct_abc123

# Étape 2: Générer un lien d'onboarding

# Le vendeur doit compléter son profil (infos bancaires, identité, etc.)

account_link = stripe.AccountLink.create(
    account=account.id,
    refresh_url='https://monsite.com/onboarding/refresh',
    return_url='https://monsite.com/onboarding/success',
    type='account_onboarding',
)

print(f"Lien d'onboarding: {account_link.url}")
# Redirige le vendeur vers ce lien!

# Le vendeur remplit le formulaire Stripe:
# - Nom, adresse
# - Numéro IBAN (pour recevoir l'argent)
# - Pièce d'identité (vérification)
# - Informations business

# Après complétion: Redirigé vers return_url


# === ACCEPTER UN PAIEMENT POUR UN VENDEUR ===

# Scénario:
# Client achète un produit à 100€ chez un vendeur
# Ta plateforme prend 10€ de commission
# Le vendeur reçoit 90€

# Méthode 1: Destination Charge

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    mode='payment',
    line_items=[{
        'price_data': {
            'currency': 'eur',
            'product_data': {'name': 'Produit du vendeur'},
            'unit_amount': 10000,  # 100.00€
        },
        'quantity': 1,
    }],
    success_url='https://monsite.com/success',
    cancel_url='https://monsite.com/cancel',
    
    # Configuration Connect:
    payment_intent_data={
        'application_fee_amount': 1000,  # 10.00€ (ta commission)
        'transfer_data': {
            'destination': account.id,  # Compte du vendeur
        },
    },
)

# Résultat:
# - Client paie: 100.00€
# - Vendeur reçoit: 90.00€ (100 - 10 commission)
# - Tu gardes: 10.00€ (commission)
# - Frais Stripe: Déduits des 90€ du vendeur


# Méthode 2: Direct Charge (paiement direct au vendeur)

checkout_session = stripe.checkout.Session.create(
    # ... configuration normale ...
    
    # Paiement direct au vendeur:
    stripe_account=account.id,  # Compte du vendeur
)

# Le vendeur reçoit tout l'argent
# Tu factureS ta commission séparément


# === TRANSFÉRER DE L'ARGENT À UN VENDEUR ===

# Si tu as collecté l'argent sur TON compte:

transfer = stripe.Transfer.create(
    amount=9000,  # 90.00€
    currency='eur',
    destination=account.id,  # Compte du vendeur
    description='Vente produit #12345',
    metadata={
        'order_id': 'ORDER-456'
    }
)


# === GÉRER LES REMBOURSEMENTS SUR CONNECT ===

# Si le vendeur veut rembourser un client:

# Option 1: Remboursement depuis TON compte
refund = stripe.Refund.create(
    payment_intent='pi_abc123',
    reverse_transfer=True,  # Récupère l'argent du vendeur
)

# Résultat:
# - Client récupère 100€
# - Tu récupères ta commission (10€) du vendeur
# - Le vendeur paie les 90€ + 10€ = perd 100€


# Option 2: Remboursement depuis le compte du vendeur
refund = stripe.Refund.create(
    payment_intent='pi_abc123',
    stripe_account=account.id,  # Compte du vendeur
)


# === DASHBOARD POUR VENDEURS ===

# Générer un lien vers le Dashboard Express:

login_link = stripe.Account.create_login_link(account.id)

print(f"Dashboard link: {login_link.url}")
# Redirige le vendeur vers ce lien
# Il voit ses transactions, payouts, etc.


# === WEBHOOKS STRIPE CONNECT ===

# Tu reçois des webhooks pour:
# - Tes propres événements (compte plateforme)
# - Les événements des vendeurs (si configuré)

# Exemple: Webhook quand un vendeur complète l'onboarding

def handle_account_updated(event):
    """Vendeur a complété son profil"""
    
    account = event['data']['object']
    
    account_id = account['id']
    charges_enabled = account['charges_enabled']
    payouts_enabled = account['payouts_enabled']
    
    if charges_enabled and payouts_enabled:
        print(f"[OK] Vendeur {account_id} prêt à recevoir des paiements!")
        activate_vendor_shop(account_id)
    else:
        print(f"[ATTENTION] Vendeur {account_id} incomplet")


[OK] RAPPORTS ET ANALYTICS

# === RÉCUPÉRER LES STATISTIQUES ===

# === Total des paiements réussis (30 derniers jours) ===

import time
from datetime import datetime, timedelta

# Date: il y a 30 jours (timestamp)
thirty_days_ago = int((datetime.now() - timedelta(days=30)).timestamp())

# Lister tous les PaymentIntents réussis
payment_intents = stripe.PaymentIntent.list(
    created={'gte': thirty_days_ago},  # Greater Than or Equal
    limit=100
)

# Calculer le total
total_amount = 0
count = 0

for pi in payment_intents.auto_paging_iter():
    if pi.status == 'succeeded':
        total_amount += pi.amount
        count += 1

print(f"Nombre de paiements: {count}")
print(f"Montant total: {total_amount / 100:.2f} EUR")


# === Récupérer le nombre de clients ===

customers = stripe.Customer.list(limit=100)

total_customers = customers['total_count']
print(f"Nombre total de clients: {total_customers}")


# === Abonnements actifs ===

subscriptions = stripe.Subscription.list(
    status='active',
    limit=100
)

active_subs = subscriptions['total_count']
print(f"Abonnements actifs: {active_subs}")


# === MRR (Monthly Recurring Revenue) ===

# Calculer le revenu mensuel récurrent

subscriptions = stripe.Subscription.list(status='active', limit=100)

mrr = 0

for sub in subscriptions.auto_paging_iter():
    for item in sub['items']['data']:
        price = item['price']
        amount = price['unit_amount']
        quantity = item['quantity']
        interval = price['recurring']['interval']
        
        # Convertir en mensuel
        if interval == 'month':
            monthly_amount = amount * quantity
        elif interval == 'year':
            monthly_amount = (amount * quantity) / 12
        elif interval == 'week':
            monthly_amount = (amount * quantity) * 4.33
        elif interval == 'day':
            monthly_amount = (amount * quantity) * 30
        
        mrr += monthly_amount

print(f"MRR: {mrr / 100:.2f} EUR/mois")


# === Taux de churn (annulations) ===

# Nombre d'abonnements annulés dans le mois

canceled_subs = stripe.Subscription.list(
    status='canceled',
    created={'gte': thirty_days_ago},
    limit=100
)

churn_count = canceled_subs['total_count']
churn_rate = (churn_count / active_subs) * 100 if active_subs > 0 else 0

print(f"Churn rate: {churn_rate:.2f}%")


# === EXPORTER DES DONNÉES ===

# Dashboard > Reports > Export
# Ou via API:

# Créer un export de toutes les transactions
export = stripe.reporting.ReportRun.create(
    report_type='balance.summary.1',
    parameters={
        'interval_start': thirty_days_ago,
        'interval_end': int(time.time()),
        'columns': [
            'created',
            'available_on',
            'currency',
            'gross',
            'fee',
            'net',
            'reporting_category',
            'description'
        ]
    }
)

# Attendre la fin de la génération (peut prendre quelques minutes)
while export.status != 'succeeded':
    time.sleep(5)
    export = stripe.reporting.ReportRun.retrieve(export.id)

# Télécharger le CSV
import requests

file_obj = stripe.File.retrieve(export.result.id)
csv_url = file_obj.links.data[0].url

response = requests.get(csv_url)
with open('stripe_export.csv', 'wb') as f:
    f.write(response.content)

print("Export téléchargé: stripe_export.csv")


# Fichier: python_cheats/cheatsheets/stripe-suite-2.txt
# Cheatsheet Stripe Suite 2 - Guide Ultra-Détaillé pour Grands Débutants


[OK] STRIPE BILLING PORTAL (PORTAIL CLIENT SELF-SERVICE)

# === QU'EST-CE QUE LE BILLING PORTAL? ===

# Le Billing Portal = Une page hébergée par Stripe où TES CLIENTS peuvent:
# - Voir leurs abonnements
# - Mettre à jour leur carte bancaire
# - Télécharger leurs factures
# - Annuler leur abonnement
# - Voir leur historique de paiements

# ÉNORME AVANTAGE:
# Tu n'as PAS à construire toutes ces pages!
# Stripe les héberge pour toi, sécurisées et conformes

# === POURQUOI C'EST IMPORTANT? ===

# Sans Billing Portal:
# Client: "Je veux annuler mon abonnement"
# Tu dois: Créer une page, gérer la sécurité, coder l'annulation, etc.
# = DES JOURS de travail!

# Avec Billing Portal:
# Tu crées UN lien -> Le client gère tout lui-même
# = 5 MINUTES de setup!


# === ACTIVER LE BILLING PORTAL ===

# Étape 1: Aller sur le Dashboard
# https://dashboard.stripe.com/settings/billing/portal

# Étape 2: Configurer les fonctionnalités
# Coche ce que tu veux autoriser:
# [x] Mettre à jour les méthodes de paiement
# [x] Annuler les abonnements
# [x] Télécharger les factures
# [x] Changer de plan

# Étape 3: Personnaliser l'apparence
# - Logo de ton entreprise
# - Couleurs de ta marque
# - Lien vers ton site web


# === CRÉER UN LIEN VERS LE PORTAL ===

# Code Python (Flask exemple):

from flask import Flask, redirect, session
import stripe
import os

app = Flask(__name__)
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY')

@app.route('/customer-portal')
def customer_portal():
    """
    Route pour rediriger le client vers son Billing Portal
    """
    
    # Récupérer l'ID du customer depuis ta session/DB
    customer_id = session.get('stripe_customer_id')
    # Ex: 'cus_ABC123'
    
    if not customer_id:
        return "Vous devez être connecté", 401
    
    # Créer une session Portal
    portal_session = stripe.billing_portal.Session.create(
        customer=customer_id,
        return_url='https://monsite.com/account'
        # URL où le client revient après avoir terminé
    )
    
    # Rediriger vers le Portal
    return redirect(portal_session.url)


# === CE QUE VOIT LE CLIENT ===

# 1. Page d'accueil du Portal:
#    - "Abonnements"
#    - "Méthodes de paiement"
#    - "Historique de facturation"

# 2. Si il clique "Annuler l'abonnement":
#    - "Êtes-vous sûr de vouloir annuler?"
#    - Options: Annuler maintenant / Annuler à la fin du cycle
#    - Feedback: "Pourquoi annulez-vous?"

# 3. Si il clique "Mettre à jour la carte":
#    - Formulaire sécurisé pour entrer nouvelle carte
#    - Sauvegarde automatique

# 4. Si il clique "Factures":
#    - Liste de toutes ses factures
#    - Bouton "Télécharger PDF" pour chaque facture


# === PERSONNALISATION AVANCÉE ===

# Tu peux configurer différentes actions:

# Configuration: Que se passe-t-il lors de l'annulation?
configuration = stripe.billing_portal.Configuration.create(
    business_profile={
        'headline': 'Gérez votre abonnement',
        'privacy_policy_url': 'https://monsite.com/privacy',
        'terms_of_service_url': 'https://monsite.com/terms',
    },
    features={
        # Autoriser mise à jour carte
        'payment_method_update': {
            'enabled': True
        },
        # Autoriser annulation
        'subscription_cancel': {
            'enabled': True,
            'mode': 'at_period_end',  # Annule à la fin du cycle
            'cancellation_reason': {
                'enabled': True,  # Demander la raison
                'options': [
                    'too_expensive',
                    'missing_features',
                    'switched_service',
                    'unused',
                    'customer_service',
                    'too_complex',
                    'low_quality',
                    'other'
                ]
            }
        },
        # Autoriser changement de plan
        'subscription_update': {
            'enabled': True,
            'default_allowed_updates': ['price', 'quantity'],
            'proration_behavior': 'always_invoice'
        }
    }
)

# Utiliser cette configuration:
portal_session = stripe.billing_portal.Session.create(
    customer='cus_ABC123',
    configuration=configuration.id,
    return_url='https://monsite.com/account'
)


# === EXEMPLE COMPLET: INTÉGRATION FLASK ===

from flask import Flask, render_template, session, redirect, url_for
import stripe
import os

app = Flask(__name__)
app.secret_key = 'dev-secret-key'
stripe.api_key = os.environ.get('STRIPE_SECRET_KEY')

@app.route('/account')
def account():
    """Page compte client"""
    
    # Vérifier si l'utilisateur est connecté
    if 'user_id' not in session:
        return redirect(url_for('login'))
    
    # Récupérer le Customer ID
    customer_id = session.get('stripe_customer_id')
    
    # Récupérer les infos du customer
    customer = stripe.Customer.retrieve(customer_id)
    
    # Récupérer les abonnements
    subscriptions = stripe.Subscription.list(
        customer=customer_id,
        status='active'
    )
    
    return render_template('account.html',
                         customer=customer,
                         subscriptions=subscriptions.data)

@app.route('/billing-portal')
def billing_portal():
    """Rediriger vers le Billing Portal"""
    
    customer_id = session.get('stripe_customer_id')
    
    if not customer_id:
        return "Non autorisé", 401
    
    # Créer session Portal
    portal_session = stripe.billing_portal.Session.create(
        customer=customer_id,
        return_url=url_for('account', _external=True)
    )
    
    return redirect(portal_session.url)


# Template HTML: templates/account.html
"""
<!DOCTYPE html>
<html>
<head>
    <title>Mon Compte</title>
</head>
<body>
    <h1>Mon Compte</h1>
    
    <h2>Mes Abonnements</h2>
    {% if subscriptions %}
        {% for sub in subscriptions %}
        <div>
            <p>Plan: {{ sub.plan.nickname }}</p>
            <p>Statut: {{ sub.status }}</p>
            <p>Prix: {{ sub.plan.amount / 100 }} EUR/mois</p>
            <p>Prochain paiement: {{ sub.current_period_end }}</p>
        </div>
        {% endfor %}
    {% else %}
        <p>Aucun abonnement actif</p>
    {% endif %}
    
    <a href="{{ url_for('billing_portal') }}">
        Gérer mon abonnement
    </a>
</body>
</html>
"""


# === WEBHOOKS DU BILLING PORTAL ===

# Quand le client fait des actions dans le Portal,
# Stripe envoie des webhooks:

def handle_billing_portal_events(event):
    """Gérer les événements du Portal"""
    
    event_type = event['type']
    
    if event_type == 'customer.subscription.updated':
        # Client a changé son abonnement
        subscription = event['data']['object']
        customer_id = subscription['customer']
        
        print(f"Abonnement modifié pour {customer_id}")
        # Mettre à jour ta base de données
    
    elif event_type == 'customer.subscription.deleted':
        # Client a annulé son abonnement
        subscription = event['data']['object']
        customer_id = subscription['customer']
        
        print(f"Abonnement annulé pour {customer_id}")
        # Désactiver l'accès, envoyer email, etc.
    
    elif event_type == 'payment_method.attached':
        # Client a ajouté une nouvelle carte
        payment_method = event['data']['object']
        customer_id = payment_method['customer']
        
        print(f"Nouvelle carte ajoutée pour {customer_id}")


[OK] STRIPE RADAR (PRÉVENTION FRAUDE AVANCÉE)

# === QU'EST-CE QUE RADAR? ===

# Radar = Système d'intelligence artificielle de Stripe
# Analysant CHAQUE paiement pour détecter les fraudes

# Comment ça marche?
# 1. Client essaie de payer
# 2. Radar analyse en temps réel:
#    - L'adresse IP
#    - Le pays
#    - L'appareil utilisé
#    - L'historique de la carte
#    - Le montant du paiement
#    - Le comportement de navigation
#    - Des MILLIARDS d'autres données
# 3. Radar attribue un "Risk Score" de 0 à 100
# 4. Selon le score:
#    - 0-30: Paiement accepté
#    - 31-65: Paiement surveillé
#    - 66-100: Paiement bloqué ou demande 3D Secure


# === RADAR EST ACTIVÉ AUTOMATIQUEMENT ===

# Bonne nouvelle: Tu n'as rien à faire!
# Dès que tu crées un compte Stripe, Radar est actif
# Et c'est GRATUIT pour la version de base


# === COMPRENDRE LE RISK SCORE ===

# Chaque PaymentIntent a un risk_score

# Récupérer le risk score:
payment_intent = stripe.PaymentIntent.retrieve('pi_abc123')

# Récupérer le Charge associé:
charge = stripe.Charge.retrieve(payment_intent.latest_charge)

# Informations sur le risque:
risk_score = charge.outcome['risk_score']  # 0-100
risk_level = charge.outcome['risk_level']  # normal, elevated, highest
network_status = charge.outcome['network_status']

print(f"Risk Score: {risk_score}/100")
print(f"Risk Level: {risk_level}")
print(f"Network Status: {network_status}")

# Explications:
# risk_score:
#   - 0-30: Risque faible -> paiement sûr
#   - 31-65: Risque moyen -> surveiller
#   - 66-100: Risque élevé -> probable fraude

# risk_level:
#   - normal: Paiement normal, rien à signaler
#   - elevated: Risque légèrement élevé
#   - highest: Risque très élevé, attention!

# network_status:
#   - approved_by_network: La banque a approuvé
#   - declined_by_network: La banque a refusé
#   - not_sent_to_network: Radar a bloqué AVANT d'envoyer à la banque


# === CRÉER DES RÈGLES PERSONNALISÉES ===

# Tu peux créer tes propres règles dans le Dashboard:
# https://dashboard.stripe.com/radar/rules

# Exemples de règles:

# Règle 1: Bloquer les cartes prépayées
# IF card_funding = 'prepaid' THEN block

# Règle 2: Bloquer les paiements > 500€ avec email jetable
# IF amount > 50000 AND email_domain IN ::disposable_email_domains THEN block

# Règle 3: Demander 3D Secure si risque élevé
# IF risk_score > 60 THEN request_three_d_secure

# Règle 4: Bloquer certains pays
# IF ip_country IN ('NG', 'GH', 'PK') THEN block
# (Nigeria, Ghana, Pakistan - pays avec beaucoup de fraudes)

# Règle 5: Limiter les tentatives
# IF failed_charge_count_24h > 3 THEN block
# Bloque si plus de 3 échecs dans les 24h


# === CRÉER UNE RÈGLE VIA API ===

# Créer une liste de blocage d'emails:
blocked_emails = stripe.radar.ValueList.create(
    alias='blocked_emails',
    name='Emails frauduleux',
    item_type='email'
)

# Ajouter des emails à la liste:
stripe.radar.ValueListItem.create(
    value_list=blocked_emails.id,
    value='fraudeur@example.com'
)

stripe.radar.ValueListItem.create(
    value_list=blocked_emails.id,
    value='scammer@fake.com'
)

# Créer la règle:
stripe.radar.Rule.create(
    action='block',
    predicate=f"email IN :blocked_emails"
)


# === RADAR FOR FRAUD TEAMS (VERSION PREMIUM) ===

# Version avancée, payante: 0.05€ par transaction validée

# Fonctionnalités supplémentaires:
# - Machine Learning personnalisé pour TON business
# - Règles plus complexes avec AND/OR
# - Révision manuelle des paiements suspects
# - Listes blanches et noires plus avancées
# - Intégrations avec outils anti-fraude tiers
# - Support prioritaire

# Activation:
# Dashboard > Radar > Upgrade to Radar for Fraud Teams

# Exemple de règle avancée:
# IF (risk_score > 70 AND card_country != billing_country)
#    OR (amount > 100000 AND customer_age_days < 7)
# THEN review
# = Si score élevé ET pays différent
#   OU gros montant ET nouveau client
# = Mettre en révision manuelle


# === LISTES PERSONNALISÉES ===

# Tu peux créer différents types de listes:

# === BLOQUER UNE IP ===

blocked_ips = stripe.radar.ValueList.create(
    alias='blocked_ips',
    name='IPs bloquées',
    item_type='ip_address'
)

# Ajouter des IPs:
stripe.radar.ValueListItem.create(
    value_list=blocked_ips.id,
    value='192.168.1.100'
)

# Créer la règle:
stripe.radar.Rule.create(
    action='block',
    predicate="ip_address IN :blocked_ips"
)


# === BLOQUER UN PAYS ===

# Règle simple dans Dashboard:
# IF ip_country = 'NG' THEN block

# Ou plusieurs pays:
# IF ip_country IN ('NG', 'GH', 'PK', 'RU') THEN block


# === BLOQUER DES CARTES SPÉCIFIQUES ===

blocked_cards = stripe.radar.ValueList.create(
    alias='blocked_cards',
    name='Cartes bloquées',
    item_type='card_fingerprint'
)

# Le fingerprint = identifiant unique de la carte
# Tu le récupères après un paiement:
payment_method = stripe.PaymentMethod.retrieve('pm_abc123')
card_fingerprint = payment_method.card.fingerprint

# Ajouter à la liste:
stripe.radar.ValueListItem.create(
    value_list=blocked_cards.id,
    value=card_fingerprint
)


# === EXEMPLE COMPLET: INTÉGRATION RADAR ===

from flask import Flask, request, jsonify
import stripe

app = Flask(__name__)
stripe.api_key = 'sk_test_...'

@app.route('/create-payment-intent', methods=['POST'])
def create_payment_intent():
    """
    Créer un PaymentIntent avec vérification Radar
    """
    
    try:
        data = request.json
        amount = data.get('amount')
        
        # Créer le PaymentIntent
        intent = stripe.PaymentIntent.create(
            amount=amount,
            currency='eur',
            payment_method_types=['card'],
            
            # Forcer Radar à être strict
            radar_options={
                'session': data.get('radar_session_id')
                # ID de session généré côté client
            }
        )
        
        return jsonify({
            'client_secret': intent.client_secret
        })
    
    except stripe.error.CardError as e:
        # Carte refusée
        return jsonify({'error': str(e)}), 400


@app.route('/check-payment-risk', methods=['POST'])
def check_payment_risk():
    """
    Vérifier le risque d'un paiement après confirmation
    """
    
    data = request.json
    payment_intent_id = data.get('payment_intent_id')
    
    # Récupérer le PaymentIntent
    intent = stripe.PaymentIntent.retrieve(payment_intent_id)
    
    # Récupérer le Charge
    charge = stripe.Charge.retrieve(intent.latest_charge)
    
    # Analyser le risque
    risk_score = charge.outcome['risk_score']
    risk_level = charge.outcome['risk_level']
    
    if risk_score > 70:
        # Risque très élevé!
        # Actions possibles:
        
        # 1. Envoyer alerte à l'équipe
        send_alert_to_fraud_team(charge.id, risk_score)
        
        # 2. Mettre le paiement en révision
        mark_payment_for_review(payment_intent_id)
        
        # 3. Demander vérification manuelle
        request_manual_verification(charge.customer)
        
        return jsonify({
            'status': 'high_risk',
            'risk_score': risk_score,
            'message': 'Paiement en révision'
        })
    
    elif risk_score > 40:
        # Risque moyen
        # Envoyer email de confirmation au client
        send_confirmation_email(charge.customer)
        
        return jsonify({
            'status': 'medium_risk',
            'risk_score': risk_score
        })
    
    else:
        # Risque faible, tout va bien
        return jsonify({
            'status': 'low_risk',
            'risk_score': risk_score
        })


def send_alert_to_fraud_team(charge_id, risk_score):
    """Alerter l'équipe anti-fraude"""
    # Envoyer email, Slack, etc.
    pass

def mark_payment_for_review(payment_intent_id):
    """Marquer pour révision manuelle"""
    # Sauvegarder dans ta base de données
    pass

def request_manual_verification(customer_id):
    """Demander vérification client"""
    # Envoyer email au client
    pass

def send_confirmation_email(customer_id):
    """Envoyer email de confirmation"""
    # Email standard
    pass


# === INTÉGRATION FRONTEND: RADAR SESSION ===

# JavaScript côté client:

"""
<script src="https://js.stripe.com/v3/"></script>
<script>
const stripe = Stripe('pk_test_...');

// Créer une Radar Session
const radarSession = await stripe.createRadarSession();

// Envoyer l'ID au backend
fetch('/create-payment-intent', {
    method: 'POST',
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({
        amount: 5000,
        radar_session_id: radarSession.id
    })
});
</script>
"""

# Cela donne plus de contexte à Radar:
# - Comportement de navigation du client
# - Appareil utilisé
# - Temps passé sur la page
# = Meilleure détection de fraude!


[OK] STRIPE IDENTITY (VÉRIFICATION D'IDENTITÉ)

# === QU'EST-CE QUE STRIPE IDENTITY? ===

# Stripe Identity = Service de vérification d'identité
# Permet de vérifier l'identité de tes utilisateurs

# Cas d'usage:
# - Plateformes de location (Airbnb-like)
# - Services financiers (néo-banques)
# - Marketplaces (vendeurs doivent être vérifiés)
# - Conformité KYC (Know Your Customer)

# Comment ça marche?
# 1. Tu crées une VerificationSession
# 2. Le client est redirigé vers une page Stripe
# 3. Il prend en photo:
#    - Sa pièce d'identité (passeport, carte d'identité, permis)
#    - Un selfie
# 4. Stripe vérifie automatiquement:
#    - Validité du document
#    - Correspondance photo/selfie
#    - Détection de faux documents
# 5. Tu reçois le résultat: vérifié ou non


# === CRÉER UNE VERIFICATION SESSION ===

verification_session = stripe.identity.VerificationSession.create(
    type='document',  # Vérification de document
    
    metadata={
        'user_id': '123',
        'purpose': 'kyc_verification'
    },
    
    # Options de vérification:
    options={
        'document': {
            'allowed_types': ['passport', 'driving_license', 'id_card'],
            'require_id_number': True,
            'require_live_capture': True,
            'require_matching_selfie': True
        }
    }
)

# Rediriger l'utilisateur:
redirect_url = verification_session.url
# Ex: https://verify.stripe.com/start/vs_abc123


# === CE QUE VOIT L'UTILISATEUR ===

# 1. Page d'accueil Stripe:
#    "Vérifiez votre identité"
#    "Préparez votre pièce d'identité"

# 2. Choix du document:
#    [WHITE_CIRCLE] Passeport
#    [WHITE_CIRCLE] Carte d'identité
#    [WHITE_CIRCLE] Permis de conduire

# 3. Prise de photo du document:
#    - Recto
#    - Verso (si carte d'identité)

# 4. Prise de selfie:
#    "Prenez une photo de votre visage"

# 5. Résultat:
#    [OK] "Vérification réussie!"
#    OU
#    [X] "Document invalide, réessayez"


# === VÉRIFIER LE RÉSULTAT ===

# Récupérer la session:
session = stripe.identity.VerificationSession.retrieve('vs_abc123')

# Vérifier le statut:
status = session.status
# Valeurs possibles:
# - requires_input: En attente
# - processing: En cours de vérification
# - verified: Vérifiée! [OK]
# - canceled: Annulée

if status == 'verified':
    # Récupérer les données vérifiées:
    verified_data = session.verified_outputs
    
    # Informations disponibles:
    full_name = verified_data['name']
    date_of_birth = verified_data['dob']
    address = verified_data['address']
    id_number = verified_data['id_number']
    
    print(f"Nom: {full_name}")
    print(f"Date de naissance: {date_of_birth}")
    print(f"Adresse: {address}")


# === WEBHOOKS IDENTITY ===

def handle_identity_verification(event):
    """Gérer les événements de vérification"""
    
    event_type = event['type']
    
    if event_type == 'identity.verification_session.verified':
        # Vérification réussie!
        session = event['data']['object']
        user_id = session['metadata']['user_id']
        
        print(f"Utilisateur {user_id} vérifié!")
        
        # Activer des fonctionnalités premium
        enable_premium_features(user_id)
        
        # Envoyer email de confirmation
        send_verification_success_email(user_id)
    
    elif event_type == 'identity.verification_session.canceled':
        # Vérification annulée
        session = event['data']['object']
        user_id = session['metadata']['user_id']
        
        print(f"Vérification annulée pour {user_id}")
        
        # Envoyer rappel
        send_verification_reminder(user_id)


# === EXEMPLE COMPLET: INTÉGRATION FLASK ===

from flask import Flask, render_template, redirect, session as flask_session
import stripe

app = Flask(__name__)
app.secret_key = 'dev-secret'
stripe.api_key = 'sk_test_...'

@app.route('/verify-identity')
def verify_identity():
    """Démarrer la vérification d'identité"""
    
    user_id = flask_session.get('user_id')
    
    if not user_id:
        return "Non connecté", 401
    
    # Créer la VerificationSession
    verification = stripe.identity.VerificationSession.create(
        type='document',
        metadata={'user_id': user_id},
        options={
            'document': {
                'allowed_types': ['passport', 'id_card'],
                'require_matching_selfie': True
            }
        }
    )
    
    # Sauvegarder l'ID de la session
    flask_session['verification_session_id'] = verification.id
    
    # Rediriger vers Stripe
    return redirect(verification.url)


@app.route('/verification-return')
def verification_return():
    """Page de retour après vérification"""
    
    session_id = flask_session.get('verification_session_id')
    
    if not session_id:
        return "Session invalide", 400
    
    # Récupérer le résultat
    verification = stripe.identity.VerificationSession.retrieve(session_id)
    
    if verification.status == 'verified':
        # Succès!
        return render_template('verification_success.html',
                             name=verification.verified_outputs['name'])
    
    elif verification.status == 'requires_input':
        # Pas encore terminé
        return "Vérification en cours...", 202
    
    else:
        # Échec
        return render_template('verification_failed.html')


[OK] STRIPE ISSUING (CRÉER DES CARTES BANCAIRES)

# === QU'EST-CE QUE STRIPE ISSUING? ===

# Stripe Issuing = Créer et émettre tes PROPRES cartes bancaires
# Tu deviens émetteur de cartes!

# Cas d'usage:
# - Cartes d'entreprise pour tes employés
# - Cartes virtuelles pour achats en ligne
# - Cartes prépayées pour tes clients
# - Programmes de récompenses

# Exemple concret:
# Tu crées une néo-banque
# Chaque utilisateur reçoit une carte Visa avec TON logo
# Tu contrôles tout: limites, catégories autorisées, etc.


# === CRÉER UN CARDHOLDER (TITULAIRE) ===

cardholder = stripe.issuing.Cardholder.create(
    type='individual',  # ou 'company'
    
    name='Jean Dupont',
    email='jean@example.com',
    phone_number='+33612345678',
    
    billing={
        'address': {
            'line1': '123 rue de la Paix',
            'city': 'Paris',
            'postal_code': '75001',
            'country': 'FR'
        }
    },
    
    metadata={
        'user_id': '123',
        'department': 'Engineering'
    }
)

print(f"Cardholder créé: {cardholder.id}")


# === CRÉER UNE CARTE ===

card = stripe.issuing.Card.create(
    cardholder=cardholder.id,
    
    currency='eur',
    type='virtual',  # ou 'physical'
    
    # Limites de dépense:
    spending_controls={
        'spending_limits': [
            {
                'amount': 100000,  # 1000€ max
                'interval': 'monthly'  # par mois
            }
        ],
        'allowed_categories': [
            'computer_software_stores',
            'eating_places_restaurants'
        ],
        'blocked_categories': [
            'gambling'
        ]
    },
    
    metadata={
        'purpose': 'work_expenses'
    }
)

print(f"Carte créée: {card.id}")
print(f"Numéro: {card.number}")  # Numéro complet de la carte!
print(f"CVC: {card.cvc}")
print(f"Expire: {card.exp_month}/{card.exp_year}")


# === TYPES DE CARTES ===

# CARTES VIRTUELLES:
# - Numéro généré instantanément
# - Utilisable immédiatement en ligne
# - Pas de carte physique
# - Idéal pour achats en ligne sécurisés

virtual_card = stripe.issuing.Card.create(
    cardholder=cardholder.id,
    currency='eur',
    type='virtual'
)

# CARTES PHYSIQUES:
# - Carte plastique envoyée par courrier
# - Utilisable en magasin et en ligne
# - Livraison en 5-7 jours

physical_card = stripe.issuing.Card.create(
    cardholder=cardholder.id,
    currency='eur',
    type='physical',
    
    shipping={
        'name': 'Jean Dupont',
        'address': {
            'line1': '123 rue de la Paix',
            'city': 'Paris',
            'postal_code': '75001',
            'country': 'FR'
        },
        'service': 'standard'  # ou 'express'
    }
)


# === CONTRÔLES DE DÉPENSES AVANCÉS ===

# Limites par catégorie:
card = stripe.issuing.Card.create(
    cardholder=cardholder.id,
    currency='eur',
    type='virtual',
    
    spending_controls={
        # Limite globale: 500€/mois
        'spending_limits': [
            {
                'amount': 50000,
                'interval': 'monthly'
            }
        ],
        
        # Catégories autorisées:
        'allowed_categories': [
            'computer_software_stores',  # Logiciels
            'eating_places_restaurants',  # Restaurants
            'hotels_motels_resorts',      # Hôtels
            'airlines',                   # Vols
        ],
        
        # Catégories bloquées:
        'blocked_categories': [
            'gambling',                   # Jeux d'argent
            'dating_services',            # Sites de rencontre
            'direct_marketing'            # Marketing direct
        ],
        
        # Limites par transaction:
        'spending_limits_currency': 'eur'
    }
)


# === AUTORISER/REFUSER DES TRANSACTIONS ===

# Quand un employé utilise sa carte, Stripe envoie un webhook
# Tu peux approuver ou refuser en temps réel!

def handle_issuing_authorization(event):
    """Gérer une demande d'autorisation de paiement"""
    
    authorization = event['data']['object']
    
    # Informations:
    card_id = authorization['card']
    amount = authorization['amount']  # en centimes
    merchant = authorization['merchant_data']['name']
    category = authorization['merchant_data']['category']
    
    print(f"Autorisation demandée:")
    print(f"  Carte: {card_id}")
    print(f"  Montant: {amount / 100}€")
    print(f"  Marchand: {merchant}")
    print(f"  Catégorie: {category}")
    
    # Logique personnalisée:
    
    # Vérifier si c'est un week-end
    import datetime
    if datetime.datetime.now().weekday() >= 5:
        # Bloquer les achats le week-end
        stripe.issuing.Authorization.decline(
            authorization.id,
            metadata={'reason': 'weekend_blocked'}
        )
        return
    
    # Vérifier le budget du département
    cardholder = stripe.issuing.Cardholder.retrieve(
        authorization['cardholder']
    )
    department = cardholder['metadata'].get('department')
    
    if not check_department_budget(department, amount):
        # Budget dépassé
        stripe.issuing.Authorization.decline(
            authorization.id,
            metadata={'reason': 'budget_exceeded'}
        )
        return
    
    # Approuver
    stripe.issuing.Authorization.approve(
        authorization.id,
        amount=amount
    )


def check_department_budget(department, amount):
    """Vérifier le budget disponible"""
    # Ta logique métier
    pass


# === WEBHOOKS ISSUING ===

# issuing.authorization.created: Nouvelle demande d'autorisation
# issuing.authorization.updated: Autorisation mise à jour
# issuing.card.created: Nouvelle carte créée
# issuing.transaction.created: Transaction effectuée


# === GÉRER LES CARTES ===

# Activer/Désactiver une carte:
stripe.issuing.Card.modify(
    'ic_abc123',
    status='inactive'  # ou 'active', 'canceled'
)

# Mettre à jour les limites:
stripe.issuing.Card.modify(
    'ic_abc123',
    spending_controls={
        'spending_limits': [
            {
                'amount': 200000,  # 2000€
                'interval': 'monthly'
            }
        ]
    }
)

# Remplacer une carte perdue:
new_card = stripe.issuing.Card.create(
    cardholder=cardholder.id,
    currency='eur',
    type='virtual',
    replacement_for='ic_abc123',  # Carte à remplacer
    replacement_reason='lost'      # lost, stolen, damaged
)


# === TRANSACTIONS ET RÉCONCILIATION ===

# Lister les transactions d'une carte:
transactions = stripe.issuing.Transaction.list(
    card='ic_abc123',
    limit=100
)

for txn in transactions.data:
    print(f"Transaction: {txn.amount / 100}€")
    print(f"Marchand: {txn.merchant_data['name']}")
    print(f"Date: {txn.created}")


# === EXEMPLE COMPLET: PLATEFORME DE CARTES D'ENTREPRISE ===

from flask import Flask, request, jsonify
import stripe

app = Flask(__name__)
stripe.api_key = 'sk_test_...'

@app.route('/create-employee-card', methods=['POST'])
def create_employee_card():
    """Créer une carte pour un employé"""
    
    data = request.json
    
    # Créer le Cardholder
    cardholder = stripe.issuing.Cardholder.create(
        type='individual',
        name=data['name'],
        email=data['email'],
        phone_number=data['phone'],
        billing={'address': data['address']},
        metadata={
            'employee_id': data['employee_id'],
            'department': data['department']
        }
    )
    
    # Créer la carte
    card = stripe.issuing.Card.create(
        cardholder=cardholder.id,
        currency='eur',
        type='virtual',
        spending_controls={
            'spending_limits': [
                {
                    'amount': data['monthly_limit'] * 100,
                    'interval': 'monthly'
                }
            ],
            'allowed_categories': data['allowed_categories']
        }
    )
    
    return jsonify({
        'card_id': card.id,
        'card_number': card.number,
        'cvc': card.cvc,
        'exp_month': card.exp_month,
        'exp_year': card.exp_year
    })


@app.route('/card-transactions/<card_id>')
def card_transactions(card_id):
    """Voir les transactions d'une carte"""
    
    transactions = stripe.issuing.Transaction.list(
        card=card_id,
        limit=50
    )
    
    return jsonify({
        'transactions': [
            {
                'amount': txn.amount / 100,
                'merchant': txn.merchant_data['name'],
                'category': txn.merchant_data['category'],
                'date': txn.created
            }
            for txn in transactions.data
        ]
    })


@app.route('/freeze-card/<card_id>', methods=['POST'])
def freeze_card(card_id):
    """Geler une carte"""
    
    stripe.issuing.Card.modify(
        card_id,
        status='inactive'
    )
    
    return jsonify({'status': 'frozen'})


[OK] STRIPE TREASURY (COMPTES BANCAIRES)

# === QU'EST-CE QUE STRIPE TREASURY? ===

# Stripe Treasury = Créer des comptes bancaires pour tes utilisateurs
# Tu deviens une néo-banque!

# Fonctionnalités:
# - Comptes bancaires avec IBAN
# - Cartes de débit
# - Virements
# - Dépôts directs
# - Intérêts sur les dépôts

# Cas d'usage:
# - Plateforme de freelancing (comptes pour freelancers)
# - Marketplace (comptes pour vendeurs)
# - App de gestion financière
# - Programme de paie


# === CRÉER UN FINANCIAL ACCOUNT ===

financial_account = stripe.treasury.FinancialAccount.create(
    supported_currencies=['eur'],
    features={
        'card_issuing': {'requested': True},
        'deposit_insurance': {'requested': True},
        'financial_addresses': {
            'aba': {'requested': True}  # Numéro de compte US
        },
        'inbound_transfers': {
            'ach': {'requested': True}  # Virements ACH
        },
        'intra_stripe_flows': {'requested': True},
        'outbound_payments': {
            'ach': {'requested': True},
            'us_domestic_wire': {'requested': True}
        },
        'outbound_transfers': {
            'ach': {'requested': True},
            'us_domestic_wire': {'requested': True}
        }
    },
    metadata={
        'user_id': '123',
        'purpose': 'freelancer_account'
    }
)

print(f"Compte créé: {financial_account.id}")
print(f"Balance: {financial_account.balance['cash']['eur']} EUR")


# === OBTENIR L'IBAN/NUMÉRO DE COMPTE ===

# Récupérer les détails bancaires:
financial_addresses = stripe.treasury.FinancialAccount.retrieve_features(
    financial_account.id
)

# IBAN pour Europe:
iban = financial_addresses['financial_addresses']['iban']['iban']
bic = financial_addresses['financial_addresses']['iban']['bic']

print(f"IBAN: {iban}")
print(f"BIC: {bic}")


# === EFFECTUER UN VIREMENT SORTANT ===

outbound_transfer = stripe.treasury.OutboundTransfer.create(
    financial_account=financial_account.id,
    destination_payment_method='pm_bank_account_xxx',
    amount=10000,  # 100.00 EUR
    currency='eur',
    description='Paiement freelance',
    statement_descriptor='PAIEMENT'
)

print(f"Virement créé: {outbound_transfer.id}")


# === RECEVOIR UN VIREMENT ===

# Les virements entrants sont automatiquement crédités
# Tu reçois un webhook:

def handle_inbound_transfer(event):
    """Gérer un virement entrant"""
    
    transfer = event['data']['object']
    
    financial_account_id = transfer['financial_account']
    amount = transfer['amount']
    
    print(f"Virement reçu: {amount / 100} EUR")
    print(f"Compte: {financial_account_id}")
    
    # Notifier l'utilisateur
    notify_user_of_deposit(financial_account_id, amount)


# === TRANSACTIONS ===

# Lister toutes les transactions:
transactions = stripe.treasury.Transaction.list(
    financial_account=financial_account.id,
    limit=50
)

for txn in transactions.data:
    print(f"Transaction: {txn.amount / 100} EUR")
    print(f"Type: {txn.type}")
    print(f"Description: {txn.description}")


# === EXEMPLE: PLATEFORME DE FREELANCING ===

from flask import Flask, request, jsonify
import stripe

app = Flask(__name__)
stripe.api_key = 'sk_test_...'

@app.route('/create-freelancer-account', methods=['POST'])
def create_freelancer_account():
    """Créer un compte bancaire pour un freelancer"""
    
    data = request.json
    
    # Créer le compte financier
    account = stripe.treasury.FinancialAccount.create(
        supported_currencies=['eur'],
        features={
            'card_issuing': {'requested': True},
            'inbound_transfers': {'ach': {'requested': True}},
            'outbound_transfers': {'ach': {'requested': True}}
        },
        metadata={
            'freelancer_id': data['freelancer_id']
        }
    )
    
    # Obtenir l'IBAN
    features = stripe.treasury.FinancialAccount.retrieve_features(
        account.id
    )
    
    iban = features['financial_addresses']['iban']['iban']
    
    return jsonify({
        'account_id': account.id,
        'iban': iban,
        'balance': account.balance['cash']['eur'] / 100
    })


@app.route('/pay-freelancer', methods=['POST'])
def pay_freelancer():
    """Payer un freelancer"""
    
    data = request.json
    
    # Créer un virement
    transfer = stripe.treasury.OutboundTransfer.create(
        financial_account=data['financial_account_id'],
        destination_payment_method=data['destination_bank'],
        amount=data['amount'] * 100,
        currency='eur',
        description=f"Paiement projet #{data['project_id']}"
    )
    
    return jsonify({
        'transfer_id': transfer.id,
        'status': transfer.status
    })


@app.route('/account-balance/<account_id>')
def account_balance(account_id):
    """Voir le solde d'un compte"""
    
    account = stripe.treasury.FinancialAccount.retrieve(account_id)
    
    return jsonify({
        'balance': account.balance['cash']['eur'] / 100,
        'currency': 'EUR'
    })


[OK] STRIPE TAX (CALCUL AUTOMATIQUE DES TAXES)

# === QU'EST-CE QUE STRIPE TAX? ===

# Stripe Tax = Calcul automatique des taxes selon la localisation
# Gère la TVA, sales tax, GST, etc. dans 40+ pays

# Pourquoi c'est compliqué?
# - Chaque pays a ses propres règles
# - Les taux varient par région (US: 50 states différents!)
# - Règles spéciales pour produits numériques
# - Seuils de taxation
# - Reverse charge B2B en Europe

# Stripe Tax fait TOUT ça automatiquement!


# === ACTIVER STRIPE TAX ===

# Dashboard > Settings > Tax > Activate Stripe Tax

# Configuration:
# 1. Choisis où tu es enregistré fiscalement
# 2. Entre tes numéros de TVA
# 3. Active pour tes pays cibles


# === UTILISER TAX DANS CHECKOUT SESSION ===

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    mode='payment',
    
    line_items=[{
        'price_data': {
            'currency': 'eur',
            'product_data': {'name': 'Formation Python'},
            'unit_amount': 10000  # 100€ HT
        },
        'quantity': 1
    }],
    
    # Activer le calcul automatique des taxes:
    automatic_tax={'enabled': True},
    
    # Collecter l'adresse de facturation:
    billing_address_collection='required',
    
    success_url='https://monsite.com/success',
    cancel_url='https://monsite.com/cancel'
)

# Résultat:
# - Client en France: TVA 20% -> Total: 120€
# - Client en Belgique: TVA 21% -> Total: 121€
# - Client en Suisse: Pas de TVA UE -> Total: 100€
# - Client entreprise UE avec numéro TVA: Reverse charge -> Total: 100€


# === CRÉER UNE TRANSACTION AVEC TAX ===

# Pour une facture manuelle:
tax_transaction = stripe.tax.Transaction.create_from_calculation(
    calculation='txcd_abc123',  # ID d'un calcul précédent
    reference='ORDER-123'
)


# === CALCULER LES TAXES AVANT PAIEMENT ===

# Si tu veux montrer le total avant Checkout:

tax_calculation = stripe.tax.Calculation.create(
    currency='eur',
    line_items=[
        {
            'amount': 10000,  # 100€
            'reference': 'PRODUCT-123'
        }
    ],
    customer_details={
        'address': {
            'line1': '123 rue de la Paix',
            'city': 'Paris',
            'postal_code': '75001',
            'country': 'FR'
        },
        'address_source': 'billing'
    }
)

# Résultat:
print(f"Subtotal: {tax_calculation.amount_total / 100}€")
print(f"Taxe: {tax_calculation.tax_amount_exclusive / 100}€")
print(f"Total: {(tax_calculation.amount_total + tax_calculation.tax_amount_exclusive) / 100}€")


# === NUMÉRO DE TVA CLIENT (B2B) ===

# Si le client est une entreprise, il peut fournir son numéro de TVA:

checkout_session = stripe.checkout.Session.create(
    # ... config normale ...
    
    automatic_tax={'enabled': True},
    
    # Permettre au client d'entrer son numéro de TVA:
    tax_id_collection={'enabled': True}
)

# Stripe vérifie automatiquement avec VIES (système européen)
# Si valide: Reverse charge appliqué (pas de TVA facturée)


# === TAUX DE TAXE MANUELS ===

# Si tu ne veux pas utiliser Stripe Tax automatique:

tax_rate = stripe.TaxRate.create(
    display_name='TVA France',
    description='TVA française 20%',
    jurisdiction='FR',
    percentage=20.0,
    inclusive=False  # False = prix HT, True = prix TTC
)

# Utiliser dans Checkout:
checkout_session = stripe.checkout.Session.create(
    # ...
    line_items=[{
        'price_data': {
            'currency': 'eur',
            'product_data': {'name': 'Produit'},
            'unit_amount': 10000,
            'tax_behavior': 'exclusive'  # Prix HT
        },
        'quantity': 1,
        'tax_rates': [tax_rate.id]  # Appliquer la TVA
    }],
    # ...
)


# === RAPPORTS FISCAUX ===

# Stripe Tax génère des rapports pour ta déclaration:
# Dashboard > Tax > Reports

# Tu peux télécharger:
# - Montant total collecté par pays
# - Détail par transaction
# - Prêt pour ta déclaration fiscale


[OK] STRIPE CLIMATE (COMPENSATION CARBONE)

# === QU'EST-CE QUE STRIPE CLIMATE? ===

# Stripe Climate = Contribuer à la lutte contre le changement climatique
# Tu peux reverser un % de tes revenus à des projets de capture de CO2

# Comment ça marche?
# 1. Tu actives Stripe Climate
# 2. Tu choisis un pourcentage (ex: 1% de tes revenus)
# 3. Stripe prélève automatiquement ce montant
# 4. L'argent finance des projets de capture de carbone

# Projets financés:
# - Capture directe de CO2 dans l'air
# - Stockage souterrain de CO2
# - Biochar (charbon végétal)
# - Minéralisation du CO2


# === ACTIVER STRIPE CLIMATE ===

# Dashboard > Climate > Get started

# Configurer:
contribution = stripe.climate.Contribution.create(
    amount=100,  # 1€
    currency='eur'
)

# Ou via Dashboard:
# 1. Dashboard > Climate
# 2. Choisir "Contribute a % of revenue"
# 3. Entrer le pourcentage (ex: 1%)
# 4. Activer

# Résultat:
# - Chaque paiement = 1% automatiquement reversé
# - Badge "Climate Contributor" pour ton site
# - Rapport d'impact (tonnes de CO2 capturées)


# === AFFICHER LE BADGE SUR TON SITE ===

"""
<a href="https://climate.stripe.com/XXXX">
  <img src="https://b.stripecdn.com/climate-badge/v1/badge-light.png" 
       alt="Climate Badge">
</a>
"""

# Le badge montre:
# "Nous contribuons à la capture de CO2"
# "X tonnes de CO2 capturées grâce à nous"


[OK] STRIPE SIGMA (REQUÊTES SQL SUR TES DONNÉES)

# === QU'EST-CE QUE STRIPE SIGMA? ===

# Stripe Sigma = Interface SQL pour interroger tes données Stripe
# Tu peux écrire des requêtes SQL directement sur ta base de données Stripe!

# Disponible uniquement sur les plans:
# - Standard ($10/mois)
# - Professional ($25/mois)

# Cas d'usage:
# - Analytics avancées
# - Rapports personnalisés
# - Détection d'anomalies
# - Export de données


# === TABLES DISPONIBLES ===

# Principales tables:
# - customers: Tous tes clients
# - charges: Tous les paiements
# - subscriptions: Tous les abonnements
# - invoices: Toutes les factures
# - refunds: Tous les remboursements
# - disputes: Toutes les contestations


# === EXEMPLES DE REQUÊTES SQL ===

# Requête 1: Top 10 clients par revenu total

"""
SELECT
  customers.id,
  customers.email,
  SUM(charges.amount) / 100 as total_spent
FROM charges
  JOIN customers ON charges.customer_id = customers.id
WHERE charges.status = 'succeeded'
GROUP BY customers.id, customers.email
ORDER BY total_spent DESC
LIMIT 10
"""


# Requête 2: Revenu mensuel des 12 derniers mois

"""
SELECT
  DATE_TRUNC('month', created) as month,
  SUM(amount) / 100 as revenue,
  COUNT(*) as num_charges
FROM charges
WHERE status = 'succeeded'
  AND created >= CURRENT_DATE - INTERVAL '12 months'
GROUP BY month
ORDER BY month
"""


# Requête 3: Taux de churn par mois

"""
SELECT
  DATE_TRUNC('month', canceled_at) as month,
  COUNT(*) as canceled_subscriptions
FROM subscriptions
WHERE canceled_at IS NOT NULL
  AND canceled_at >= CURRENT_DATE - INTERVAL '12 months'
GROUP BY month
ORDER BY month
"""


# Requête 4: Clients avec échecs de paiement récents

"""
SELECT
  customers.email,
  COUNT(charges.id) as failed_charges,
  MAX(charges.created) as last_failure
FROM charges
  JOIN customers ON charges.customer_id = customers.id
WHERE charges.status = 'failed'
  AND charges.created >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY customers.email
HAVING COUNT(charges.id) >= 3
"""


# === CRÉER UN RAPPORT SIGMA ===

# Dashboard > Sigma > Create query

# 1. Écrire ta requête SQL
# 2. Tester
# 3. Sauvegarder
# 4. Planifier l'envoi par email (quotidien/hebdomadaire)


# === EXPORT DES DONNÉES ===

# Tu peux exporter les résultats:
# - CSV
# - JSON
# - Intégration avec Google Sheets
# - Webhook vers ton système


[OK] OPTIMISATION & BONNES PRATIQUES

# === IDEMPOTENCE (ÉVITER LES DUPLICATIONS) ===

# Problème:
# Client clique "Payer" 2 fois
# = 2 PaymentIntents créés
# = Client débité 2 fois!

# Solution: Idempotency Key

import uuid

# Générer une clé unique par tentative:
idempotency_key = str(uuid.uuid4())

# Utiliser dans la requête:
payment_intent = stripe.PaymentIntent.create(
    amount=5000,
    currency='eur',
    idempotency_key=idempotency_key
)

# Si même clé utilisée 2 fois:
# 1ère fois: Crée le PaymentIntent
# 2ème fois: Retourne le MÊME PaymentIntent (pas de duplication!)


# === PAGINATION EFFICACE ===

# Mauvais: Récupérer tout d'un coup
all_customers = stripe.Customer.list(limit=10000)  # TRÈS LENT!

# Bon: Pagination automatique
for customer in stripe.Customer.list(limit=100).auto_paging_iter():
    print(customer.email)
    # Traite 100 par 100 automatiquement


# === EXPAND (ÉVITER LES REQUÊTES MULTIPLES) ===

# Mauvais: 2 requêtes API
charge = stripe.Charge.retrieve('ch_abc123')
customer = stripe.Customer.retrieve(charge.customer)  # 2ème requête!

# Bon: 1 seule requête avec expand
charge = stripe.Charge.retrieve('ch_abc123', expand=['customer'])
customer = charge.customer  # Déjà chargé!


# === RETRY AVEC BACKOFF EXPONENTIEL ===

import time

def stripe_request_with_retry(func, max_retries=3):
    """Réessayer en cas d'erreur réseau"""
    
    for attempt in range(max_retries):
        try:
            return func()
        
        except stripe.error.APIConnectionError as e:
            if attempt == max_retries - 1:
                raise
            
            # Attendre avant retry (1s, 2s, 4s)
            wait = 2 ** attempt
            print(f"Erreur réseau, retry dans {wait}s...")
            time.sleep(wait)

# Utilisation:
payment_intent = stripe_request_with_retry(
    lambda: stripe.PaymentIntent.create(
        amount=5000,
        currency='eur'
    )
)


# === CACHING ===

# Pour des données qui changent rarement:

from functools import lru_cache
import time

@lru_cache(maxsize=100)
def get_product_cached(product_id):
    """Cache les produits pendant 5 minutes"""
    return stripe.Product.retrieve(product_id)

# Première fois: requête API
product = get_product_cached('prod_abc123')

# Fois suivantes: depuis le cache (rapide!)
product = get_product_cached('prod_abc123')


# === WEBHOOKS: VÉRIFIER LA SIGNATURE ===

# TOUJOURS vérifier la signature des webhooks!
# Sinon, n'importe qui peut envoyer de faux webhooks

from flask import request
import stripe

@app.route('/webhook', methods=['POST'])
def webhook():
    payload = request.data
    sig_header = request.headers.get('Stripe-Signature')
    webhook_secret = 'whsec_...'
    
    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, webhook_secret
        )
    except ValueError:
        return "Invalid payload", 400
    except stripe.error.SignatureVerificationError:
        return "Invalid signature", 400
    
    # Signature valide, traiter l'événement
    handle_event(event)
    return "Success", 200


# === LOGS ET MONITORING ===

# Activer les logs détaillés:
import logging

logging.basicConfig(level=logging.DEBUG)

# Stripe log automatiquement toutes les requêtes:
# - URL appelée
# - Paramètres
# - Réponse
# - Temps de réponse


# === TESTS UNITAIRES ===

# Utiliser les mocks pour tester sans vraies requêtes:

import unittest
from unittest.mock import patch
import stripe

class TestPayments(unittest.TestCase):
    
    @patch('stripe.PaymentIntent.create')
    def test_create_payment(self, mock_create):
        # Mock la réponse
        mock_create.return_value = {
            'id': 'pi_test123',
            'status': 'succeeded'
        }
        
        # Tester ta fonction
        result = create_payment(5000)
        
        # Vérifier
        self.assertEqual(result['status'], 'succeeded')
        mock_create.assert_called_once()


[OK] SÉCURITÉ AVANCÉE

# === RÈGLES DE SÉCURITÉ STRIPE ===

# 1. JAMAIS commiter les clés API dans git
# 2. Utiliser des variables d'environnement
# 3. Clés test (sk_test) en développement
# 4. Clés production (sk_live) SEULEMENT en production
# 5. TOUJOURS vérifier les signatures de webhooks
# 6. Ne JAMAIS exposer la Secret Key côté client
# 7. Utiliser HTTPS PARTOUT
# 8. Valider les montants côté serveur (pas côté client!)


# === ROTATION DES CLÉS API ===

# Si une clé est compromise:
# 1. Dashboard > Developers > API keys
# 2. Cliquer "Roll key"
# 3. Nouvelle clé générée
# 4. Ancienne clé révoquée après 24h


# === RESTRICTED API KEYS ===

# Créer des clés avec permissions limitées:
# Dashboard > Developers > Restricted keys

# Exemple: Clé read-only pour analytics
# Permissions:
# [x] Read customers
# [x] Read charges
# [x] Read subscriptions
# [ ] Write (tout désactivé)


# === WEBHOOK SIGNING SECRET ROTATION ===

# Changer régulièrement le webhook secret:
# Dashboard > Developers > Webhooks
# Cliquer sur ton endpoint > Roll secret


# === IP WHITELISTING ===

# Limiter l'accès API à certaines IPs:
# (Disponible sur plan Enterprise)


# === AUDIT LOGS ===

# Voir toutes les actions dans ton compte:
# Dashboard > Developers > Events

# Filtrer par:
# - Type d'événement
# - Date
# - Utilisateur


# === STRIPE RADAR (DÉTECTION FRAUDE) ===

# Radar = IA de Stripe qui détecte les paiements frauduleux
# Activé automatiquement sur TOUS les comptes!

# Fonctionnement:
# - Analyse chaque paiement en temps réel
# - Vérifie: localisation, appareil, comportement, historique
# - Attribue un "Risk Score" de 0 à 100
# - Bloque automatiquement les paiements très suspects

# === COMPRENDRE LE RISK SCORE ===

# Chaque PaymentIntent a un risk_score:
# - 0-30: Risque faible (paiement normal)
# - 31-65: Risque moyen (surveiller)
# - 66-100: Risque élevé (fraude probable)

# Récupérer le risk score:
payment_intent = stripe.PaymentIntent.retrieve('pi_abc123')
charge = stripe.Charge.retrieve(payment_intent.latest_charge)

risk_score = charge.outcome['risk_score']  # 0-100
risk_level = charge.outcome['risk_level']  # normal, elevated, highest

print(f"Risk Score: {risk_score}/100")
print(f"Risk Level: {risk_level}")

# Informations supplémentaires:
network_status = charge.outcome['network_status']
# - approved_by_network: Approuvé par le réseau de cartes
# - declined_by_network: Refusé par le réseau
# - not_sent_to_network: Bloqué avant envoi (Radar)

seller_message = charge.outcome['seller_message']
# Message explicatif pour toi
# Exemple: "The charge was blocked by Stripe because it's a high risk charge"


# === CONFIGURER RADAR (RÈGLES PERSONNALISÉES) ===

# Tu peux créer des règles pour bloquer/autoriser certains paiements

# Exemples de règles dans Dashboard > Radar > Rules:

# Bloquer les cartes prépayées:
# IF card_funding = prepaid THEN block

# Bloquer les paiements > 500€ avec email jetable:
# IF amount > 50000 AND email_domain IN disposable_email_domains THEN block

# Demander 3D Secure si risque élevé:
# IF risk_score > 60 THEN request_three_d_secure

# Bloquer les paiements depuis certains pays:
# IF ip_country IN (NG, GH) THEN block
# (NG = Nigeria, GH = Ghana - pays avec beaucoup de fraudes)


# === RADAR FOR FRAUD TEAMS (Avancé, payant) ===

# Version premium de Radar avec plus de fonctionnalités
# Coût: 0.05€ par transaction validée

# Fonctionnalités supplémentaires:
# - Machine Learning personnalisé
# - Règles plus complexes
# - Révision manuelle des paiements suspects
# - Listes de blocage personnalisées
# - Intégration avec outils de fraude tiers


# === 3D SECURE / SCA (STRONG CUSTOMER AUTHENTICATION) ===

# 3D Secure = Popup qui demande au client de s'authentifier
# Exemples:
# - Code SMS de la banque
# - Scan d'empreinte digitale
# - Reconnaissance faciale
# - Code depuis l'app bancaire

# === POURQUOI 3D SECURE? ===

# Réglementation PSD2 (Europe):
# - Depuis 2019, obligatoire pour la plupart des paiements
# - Réduit la fraude de ~70%
# - Protège TOI contre les chargebacks
# Si un paiement avec 3D Secure est contesté, TU es protégé!

# === QUAND 3D SECURE EST REQUIS? ===

# Stripe détermine automatiquement selon:
# - Montant du paiement
# - Historique du client
# - Règles bancaires
# - Réglementations locales

# Exemple:
# - Paiement 15€: Pas de 3D Secure (seuil bas)
# - Paiement 150€: 3D Secure demandé
# - Paiement 15€ depuis nouvelle carte: 3D Secure demandé


# === FORCER 3D SECURE POUR PLUS DE SÉCURITÉ ===

# Tu peux forcer 3D Secure sur TOUS les paiements:

payment_intent = stripe.PaymentIntent.create(
    amount=2000,
    currency='eur',
    payment_method_types=['card'],
    payment_method_options={
        'card': {
            'request_three_d_secure': 'any'
            # Options:
            # - 'automatic': Stripe décide (défaut)
            # - 'any': Toujours demander 3D Secure
        }
    }
)

# Avantages:
# [OK] Sécurité maximale
# [OK] Protection contre chargebacks
# Inconvénients:
# [X] Conversion plus basse (certains clients abandonnent)
# [X] Expérience utilisateur moins fluide


# === EXEMPTIONS 3D SECURE ===

# Certains paiements sont exemptés de 3D Secure:
# - Montants < 30€ (Low-Value Exemption)
# - Paiements récurrents après le premier
# - Transactions avec faible risque (Radar Score < 30)
# - Whitelist: Client a marqué le marchand comme "de confiance"

# Code pour demander une exemption:
payment_intent = stripe.PaymentIntent.create(
    amount=2000,
    currency='eur',
    payment_method_types=['card'],
    payment_method_options={
        'card': {
            'request_three_d_secure': 'automatic',
            # Stripe essaie d'obtenir une exemption
        }
    }
)


# === VÉRIFICATIONS DE CARTE ===

# Stripe vérifie automatiquement:
# - CVC (Code de sécurité à 3/4 chiffres)
# - Adresse de facturation
# - Code postal

# === VÉRIFIER LES RÉSULTATS ===

payment_method = stripe.PaymentMethod.retrieve('pm_abc123')

# Vérification CVC:
cvc_check = payment_method.card.checks.cvc_check
# Résultats possibles:
# - 'pass': CVC correct [OK]
# - 'fail': CVC incorrect [X]
# - 'unavailable': Banque ne supporte pas
# - 'unchecked': Pas vérifié

# Vérification adresse:
address_line1_check = payment_method.card.checks.address_line1_check
# - 'pass': Adresse correspond
# - 'fail': Adresse ne correspond pas
# - 'unavailable': Non disponible

address_postal_code_check = payment_method.card.checks.address_postal_code_check
# - 'pass': Code postal correspond
# - 'fail': Code postal ne correspond pas
# - 'unavailable': Non disponible


# === BLOQUER LES PAIEMENTS SELON LES VÉRIFICATIONS ===

# Dans Dashboard > Radar > Rules:

# Bloquer si CVC échoue:
# IF cvc_check = fail THEN block

# Bloquer si adresse ET postal échouent:
# IF address_line1_check = fail AND address_postal_code_check = fail THEN block


# === LISTES DE BLOCAGE ===

# Tu peux bloquer des emails, IPs, cartes spécifiques

# === BLOQUER UN EMAIL ===

# Via Dashboard:
# Radar > Lists > Create list
# Type: Email
# Action: Block

# Via API:
blocked_email = stripe.radar.ValueList.create(
    alias='blocked_emails',
    name='Emails bloqués',
    item_type='email'
)

# Ajouter un email à la liste:
stripe.radar.ValueListItem.create(
    value_list=blocked_email.id,
    value='fraudeur@example.com'
)

# Créer une règle Radar:
# IF email IN :blocked_emails THEN block


# === BLOQUER UNE IP ===

blocked_ips = stripe.radar.ValueList.create(
    alias='blocked_ips',
    name='IPs bloquées',
    item_type='ip_address'
)

stripe.radar.ValueListItem.create(
    value_list=blocked_ips.id,
    value='192.168.1.100'
)

# Règle:
# IF ip_address IN :blocked_ips THEN block


# === BLOQUER UN PAYS ENTIER ===

# Règle:
# IF ip_country = NG THEN block
# (NG = Nigeria)

# Ou plusieurs pays:
# IF ip_country IN (NG, GH, ZA) THEN block


# === LIMITER LE NOMBRE DE TENTATIVES ===

# Bloquer si trop de paiements échoués:

# Règle:
# IF failed_charge_count_24h > 3 THEN block

# Explications:
# failed_charge_count_24h = Nombre de paiements échoués dans les 24h
# > 3 = Plus de 3 échecs
# THEN block = Bloquer le paiement suivant


# === IDEMPOTENCE KEYS (ÉVITER LES DOUBLES PAIEMENTS) ===

# Problème:
# Client clique "Payer" 2 fois rapidement
# = 2 PaymentIntents créés
# = Client débité 2 fois!

# Solution: Idempotence Key
# = Clé unique pour chaque tentative de paiement
# Si la même clé est utilisée 2 fois, Stripe retourne le même résultat

import uuid

# Générer une clé unique:
idempotency_key = str(uuid.uuid4())
# Exemple: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

# Créer un PaymentIntent avec cette clé:
payment_intent = stripe.PaymentIntent.create(
    amount=5000,
    currency='eur',
    idempotency_key=idempotency_key
)

# Si le client clique 2 fois:
# 1ère fois: PaymentIntent créé, id = pi_abc123
# 2ème fois: Même idempotency_key, Stripe retourne pi_abc123 (pas de nouveau paiement!)


# === LOGS ET AUDITS ===

# Stripe garde un historique de TOUTES les actions

# Voir les événements récents:
events = stripe.Event.list(limit=10)

for event in events.data:
    print(f"{event.created}: {event.type}")
    # Affiche:
    # 1705354800: payment_intent.succeeded
    # 1705354700: customer.created
    # 1705354600: charge.succeeded

# Filtrer par type:
events = stripe.Event.list(type='payment_intent.succeeded', limit=10)

# Filtrer par date:
import time
yesterday = int(time.time()) - 86400  # 86400 = 24h en secondes

events = stripe.Event.list(created={'gte': yesterday})


[OK] OPTIMISATION DES PERFORMANCES

# === CONVERSION RATE (TAUX DE CONVERSION) ===

# Conversion = % de clients qui complètent le paiement
# Exemple:
# - 100 clients visitent la page de paiement
# - 70 complètent le paiement
# = 70% de conversion

# === COMMENT AMÉLIORER LA CONVERSION? ===

# 1. UTILISER CHECKOUT SESSION (au lieu de PaymentIntent custom)
# Pourquoi?
# - Interface optimisée par Stripe
# - Testée sur des milliards de transactions
# - Conversion ~10-15% meilleure

# 2. ACTIVER TOUS LES MOYENS DE PAIEMENT
checkout_session = stripe.checkout.Session.create(
    payment_method_types=[
        'card',
        'apple_pay',
        'google_pay',
        'sepa_debit',  # Prélèvement SEPA (Europe)
        'ideal',       # iDEAL (Pays-Bas)
        'bancontact',  # Bancontact (Belgique)
    ],
    # ...
)
# Impact: +5-10% conversion (clients préfèrent leur méthode favorite)

# 3. CODES PROMO
allow_promotion_codes=True
# Impact: +3-5% conversion (sentiment de "bonne affaire")

# 4. LANGUE LOCALE
locale='auto'
# Stripe détecte la langue du navigateur
# Impact: +2-3% conversion

# 5. AUTO-COMPLÉTION
customer_email='client@example.com'
# Pré-remplir l'email
# Impact: +1-2% conversion (moins de friction)

# 6. AFFICHER LE MONTANT TOTAL AVANT CHECKOUT
# Avant de rediriger vers Stripe, affiche:
# "Vous allez payer 49.00€"
# Impact: +5% conversion (transparence)


# === RÉDUCTION DE LA LATENCE ===

# Latence = Temps entre l'action du client et la réponse

# === PROBLÈME: API LENTE ===

# Exemple:
import time
start = time.time()

payment_intent = stripe.PaymentIntent.create(
    amount=5000,
    currency='eur'
)

end = time.time()
print(f"Temps: {end - start:.2f}s")
# Affiche: Temps: 0.35s (350ms)

# Si ton serveur est en Europe et Stripe en US:
# = Latence réseau ~200ms
# = Requête totale ~400ms

# === SOLUTION 1: Utiliser la bonne région ===

# Stripe a des data centers en:
# - US (par défaut)
# - Europe

# Si tes clients sont en Europe:
# Dashboard > Settings > Regional processing
# Active: European payment processing
# = Latence réduite de 200ms à ~50ms!

# === SOLUTION 2: Cacher les données ===

# Au lieu de récupérer un Customer à chaque fois:

# LENT (3 requêtes):
customer = stripe.Customer.retrieve('cus_abc123')
subscription = stripe.Subscription.retrieve('sub_xyz789')
invoice = stripe.Invoice.retrieve('in_123456')

# RAPIDE (1 requête):
customer = stripe.Customer.retrieve('cus_abc123', expand=['subscriptions', 'invoices'])
# Tout est récupéré en une fois!


# === BATCH PROCESSING (TRAITEMENT PAR LOTS) ===

# Si tu dois créer 1000 PaymentIntents:

# LENT (1000 requêtes, ~5 minutes):
for i in range(1000):
    payment_intent = stripe.PaymentIntent.create(
        amount=1000,
        currency='eur'
    )

# RAPIDE (utilise des workers asynchrones):
import concurrent.futures

def create_payment_intent(amount):
    return stripe.PaymentIntent.create(
        amount=amount,
        currency='eur'
    )

amounts = [1000] * 1000

# Exécuter en parallèle (10 workers):
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
    results = list(executor.map(create_payment_intent, amounts))

# Temps: ~30 secondes au lieu de 5 minutes!


# === RETRY AVEC BACKOFF ===

# Si une requête échoue (réseau instable):

import time

def stripe_request_with_retry(func, max_retries=3):
    """Réessaie une requête Stripe en cas d'échec"""
    
    for attempt in range(max_retries):
        try:
            return func()
        except stripe.error.APIConnectionError as e:
            if attempt == max_retries - 1:
                raise  # Dernière tentative, on abandonne
            
            # Attendre avant de réessayer (exponential backoff)
            wait_time = 2 ** attempt  # 1s, 2s, 4s
            print(f"Erreur réseau. Retry dans {wait_time}s...")
            time.sleep(wait_time)

# Utilisation:
payment_intent = stripe_request_with_retry(
    lambda: stripe.PaymentIntent.create(
        amount=5000,
        currency='eur'
    )
)


[OK] GESTION DES TAXES (TVA)

# === STRIPE TAX ===

# Stripe Tax = Calcul automatique des taxes selon la localisation
# Supporté dans 40+ pays

# === ACTIVER STRIPE TAX ===

# Dashboard > Settings > Tax
# Active: "Automatically calculate tax"

# === UTILISER TAX DANS CHECKOUT SESSION ===

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    mode='payment',
    line_items=[{
        'price_data': {
            'currency': 'eur',
            'product_data': {'name': 'Produit'},
            'unit_amount': 10000,  # 100.00€ HT
        },
        'quantity': 1,
    }],
    success_url='https://monsite.com/success',
    cancel_url='https://monsite.com/cancel',
    
    # Activer le calcul automatique des taxes:
    automatic_tax={'enabled': True},
    
    # Adresse du client (pour déterminer le taux de TVA):
    billing_address_collection='required',
)

# Stripe calcule automatiquement:
# - Client en France: TVA 20% -> Total: 120.00€
# - Client en Belgique: TVA 21% -> Total: 121.00€
# - Client en Suisse: Pas de TVA UE -> Total: 100.00€


# === CONFIGURER LES TAUX DE TVA MANUELLEMENT ===

# Si tu ne veux pas utiliser Stripe Tax:

# Créer un taux de TVA:
tax_rate = stripe.TaxRate.create(
    display_name='TVA France',
    description='TVA française 20%',
    jurisdiction='FR',
    percentage=20.0,  # 20%
    inclusive=False,  # False = prix HT, True = prix TTC
)

# Utiliser dans une Checkout Session:
checkout_session = stripe.checkout.Session.create(
    # ...
    line_items=[{
        'price_data': {
            'currency': 'eur',
            'product_data': {'name': 'Produit'},
            'unit_amount': 10000,
            'tax_behavior': 'exclusive',  # Prix HT
        },
        'quantity': 1,
        'tax_rates': [tax_rate.id],  # Appliquer la TVA
    }],
    # ...
)


# === REVERSE CHARGE (AUTOLIQUIDATION B2B) ===

# En Europe, ventes B2B intra-UE:
# - Pas de TVA facturée
# - Client paie la TVA dans son pays

# Vérifier le numéro de TVA du client:
tax_id = stripe.tax_id.create(
    customer='cus_abc123',
    type='eu_vat',
    value='FR12345678901'  # Numéro TVA du client
)

# Stripe vérifie automatiquement avec VIES (système UE)


[OK] INTERNATIONALISATION (MULTI-DEVISES)

# === ACCEPTER PLUSIEURS DEVISES ===

# Stripe supporte 135+ devises!
# USD, EUR, GBP, JPY, AUD, CAD, CHF, SEK, NOK, DKK, etc.

# Exemple: Vendre en USD et EUR

# Créer 2 Prices pour le même Product:
product = stripe.Product.create(name='Formation Python')

price_usd = stripe.Price.create(
    product=product.id,
    unit_amount=5000,  # 50.00 USD
    currency='usd'
)

price_eur = stripe.Price.create(
    product=product.id,
    unit_amount=4500,  # 45.00 EUR
    currency='eur'
)

# Checkout Session avec choix de devise:
# (tu détectes le pays du client et choisis le Price approprié)

if client_country == 'US':
    selected_price = price_usd.id
elif client_country in ['FR', 'DE', 'IT', 'ES']:
    selected_price = price_eur.id
else:
    selected_price = price_usd.id  # Défaut: USD

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card'],
    mode='payment',
    line_items=[{
        'price': selected_price,
        'quantity': 1,
    }],
    success_url='https://monsite.com/success',
    cancel_url='https://monsite.com/cancel',
)


# === CONVERSION AUTOMATIQUE DE DEVISES ===

# Stripe peut convertir automatiquement:

payment_intent = stripe.PaymentIntent.create(
    amount=5000,  # 50.00 EUR
    currency='eur',
    payment_method_types=['card'],
    
    # Autoriser la conversion automatique:
    payment_method_options={
        'card': {
            'request_multicurrency': True
        }
    }
)

# Si la carte du client est en USD:
# - Stripe débite en USD (conversion automatique)
# - Taux de change: celui de Visa/Mastercard
# - Frais additionnels: 1-2%


# === AFFICHER LES PRIX DANS LA DEVISE LOCALE ===

import locale

def format_price(amount, currency):
    """Formatte un montant selon la devise"""
    
    if currency == 'eur':
        return f"{amount/100:.2f} €"
    elif currency == 'usd':
        return f"${amount/100:.2f}"
    elif currency == 'gbp':
        return f"£{amount/100:.2f}"
    elif currency == 'jpy':
        return f"¥{amount}"  # Yen n'a pas de centimes
    else:
        return f"{amount/100:.2f} {currency.upper()}"

# Exemple:
print(format_price(4500, 'eur'))  # "45.00 €"
print(format_price(5000, 'usd'))  # "$50.00"


[OK] MÉTHODES DE PAIEMENT ALTERNATIVES

# === APPLE PAY ===

# Apple Pay = Paiement avec iPhone/iPad/Mac
# Avantages:
# - Très rapide (1 clic)
# - Sécurisé (Touch ID / Face ID)
# - Conversion excellente

# Activation:
# 1. Dashboard > Settings > Payment methods
# 2. Active "Apple Pay"
# 3. Vérifie ton domaine (pour le web)

# Dans Checkout Session:
checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card', 'apple_pay'],
    # ...
)

# Stripe affiche Apple Pay automatiquement si:
# - Client utilise Safari sur iOS/macOS
# - Client a une carte dans Wallet


# === GOOGLE PAY ===

# Même principe qu'Apple Pay
# Fonctionne sur Android et Chrome

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card', 'google_pay'],
    # ...
)


# === SEPA DIRECT DEBIT (PRÉLÈVEMENT SEPA) ===

# SEPA = Prélèvement bancaire en Europe
# Client donne son IBAN
# Tu débites automatiquement

# Avantages:
# - Frais très bas: 0.35€ par transaction
# - Pas de carte nécessaire
# Inconvénients:
# - Délai: 5 jours pour débiter
# - Chargebacks possibles pendant 8 semaines

# Créer un SetupIntent (pour sauvegarder l'IBAN):
setup_intent = stripe.SetupIntent.create(
    payment_method_types=['sepa_debit'],
    customer='cus_abc123'
)

# Ensuite, débiter via PaymentIntent:
payment_intent = stripe.PaymentIntent.create(
    amount=5000,
    currency='eur',
    payment_method_types=['sepa_debit'],
    customer='cus_abc123',
    payment_method='pm_sepa_debit_xxx',
    confirm=True
)


# === KLARNA / AFTERPAY (BUY NOW PAY LATER) ===

# BNPL = Acheter maintenant, payer plus tard
# Client paie en 3-4 fois sans frais

# Activation:
# Dashboard > Settings > Payment methods
# Active "Klarna" et "Afterpay"

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card', 'klarna', 'afterpay_clearpay'],
    mode='payment',
    line_items=[{
        'price_data': {
            'currency': 'eur',
            'product_data': {'name': 'Produit'},
            'unit_amount': 20000,  # 200.00€
        },
        'quantity': 1,
    }],
    success_url='https://monsite.com/success',
    cancel_url='https://monsite.com/cancel',
)

# Sur la page Stripe, client voit:
# - Payer par carte
# - Payer avec Klarna (3x sans frais)
# - Payer avec Afterpay (4x sans frais)


# === BANCONTACT (BELGIQUE) ===

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card', 'bancontact'],
    # ...
)

# Client belge voit l'option Bancontact
# Redirige vers sa banque pour approuver


# === IDEAL (PAYS-BAS) ===

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card', 'ideal'],
    # ...
)

# Client néerlandais choisit sa banque
# (ING, Rabobank, ABN AMRO, etc.)


# === ALIPAY / WECHAT PAY (CHINE) ===

checkout_session = stripe.checkout.Session.create(
    payment_method_types=['card', 'alipay', 'wechat_pay'],
    # ...
)

# Clients chinois peuvent payer avec leurs apps


[OK] PAIEMENTS RÉCURRENTS AVANCÉS

# === METERED BILLING (FACTURATION À L'USAGE) ===

# Exemple: Facturer selon l'utilisation
# - API calls: 0.01€ par appel
# - Storage: 0.10€ par GB
# - SMS envoyés: 0.05€ par SMS

# Créer un Price "metered":
price = stripe.Price.create(
    product='prod_api_calls',
    unit_amount=1,  # 0.01€
    currency='eur',
    recurring={
        'interval': 'month',
        'usage_type': 'metered'  # Facturation à l'usage
    }
)

# Créer l'abonnement:
subscription = stripe.Subscription.create(
    customer='cus_abc123',
    items=[{
        'price': price.id
    }]
)

# Enregistrer l'utilisation:
stripe.SubscriptionItem.create_usage_record(
    subscription.items.data[0].id,
    quantity=100,  # 100 API calls ce mois
    timestamp=int(time.time())
)

# À la fin du mois:
# - Stripe compte: 100 calls × 0.01€ = 1.00€
# - Facture le client: 1.00€


# === TIERED PRICING (PRIX PAR PALIERS) ===

# Exemple:
# - 0-1000 API calls: 0.01€ chacun
# - 1001-10000 API calls: 0.005€ chacun
# - 10001+ API calls: 0.001€ chacun

price = stripe.Price.create(
    product='prod_api_calls',
    currency='eur',
    recurring={'interval': 'month'},
    billing_scheme='tiered',
    tiers=[
        {
            'up_to': 1000,
            'unit_amount': 1  # 0.01€
        },
        {
            'up_to': 10000,
            'unit_amount': 0.5  # 0.005€
        },
        {
            'up_to': 'inf',  # Infini
            'unit_amount': 0.1  # 0.001€
        }
    ],
    tiers_mode='graduated'
)


# === ESSAIS GRATUITS AVANCÉS ===

# Essai gratuit avec carte obligatoire:
subscription = stripe.Subscription.create(
    customer='cus_abc123',
    items=[{'price': 'price_monthly'}],
    trial_period_days=14,
    payment_behavior='default_incomplete'
    # Le client doit entrer sa carte pendant l'essai
)

# Essai gratuit sans carte:
subscription = stripe.Subscription.create(
    customer='cus_abc123',
    items=[{'price': 'price_monthly'}],
    trial_period_days=14,
    payment_behavior='allow_incomplete'
    # Pas de carte nécessaire, demandée à la fin
)


# === COUPONS RÉCURRENTS ===

# Réduction permanente:
coupon = stripe.Coupon.create(
    percent_off=20,
    duration='forever'
)

# Réduction pendant 3 mois:
coupon = stripe.Coupon.create(
    percent_off=50,
    duration='repeating',
    duration_in_months=3
)

# Appliquer à un abonnement:
subscription = stripe.Subscription.create(
    customer='cus_abc123',
    items=[{'price': 'price_monthly'}],
    coupon=coupon.id
)

[OK] TROUBLESHOOTING (DÉPANNAGE)

# === ERREUR: "No such customer" ===

# Cause: ID customer invalide
# Solution:
try:
    customer = stripe.Customer.retrieve('cus_abc123')
except stripe.error.InvalidRequestError as e:
    print(f"Customer non trouvé: {e}")
    # Créer un nouveau customer


# === ERREUR: "Your card was declined" ===

# Causes possibles:
# - Fonds insuffisants
# - Carte expirée
# - CVC incorrect
# - Banque bloque le paiement

# Solution: Afficher message clair au client
try:
    payment_intent = stripe.Payment
