Aller au contenu principal

Workflow de Paiement par Acompte

Vue d'ensemble

Cette fonctionnalité permet aux vendeurs de demander un acompte pour confirmer une commande, au lieu d'exiger le paiement complet immédiat. Le lien de paiement est automatiquement envoyé au client via WhatsApp dans la conversation Agent IA.

Flux utilisateur

1. Créer une commande

  • La commande doit avoir un prix défini
  • La commande doit avoir le statut "Acceptée"

2. Demander le paiement

  1. Le vendeur clique sur le bouton "Payé" dans les détails de la commande
  2. Une modal s'affiche avec deux options :
    • Paiement complet : Le client paie la totalité
    • Acompte : Le client paie une partie maintenant

3. Sélectionner le montant d'acompte

Si le vendeur choisit "Acompte" :

  1. Un champ de montant pré-rempli s'affiche (30% du prix par défaut)
  2. Le vendeur peut :
    • Modifier le montant manuellement
    • Utiliser les suggestions rapides (30%, 50%, 100%)
  3. Le vendeur clique sur "Confirmer"

4. Confirmation et envoi

  1. Une boîte de dialogue de confirmation s'affiche :

    Un lien de paiement pour Acompte de 45.00 EUR
    sera envoyé au client par WhatsApp.

    Confirmer ?
  2. Si le vendeur confirme :

    • ✅ Une transaction d'acompte est créée dans la base de données
    • ✅ Un lien de paiement Stripe est généré pour le montant exact
    • ✅ Le message est envoyé au client via WhatsApp dans la conversation Agent IA

5. Message WhatsApp envoyé

Le client reçoit automatiquement ce message :

💰 Lien de paiement pour votre acompte

Montant: 45.00 EUR

Pour confirmer votre commande, veuillez effectuer le paiement de l'acompte via ce lien sécurisé :
https://buy.stripe.com/xxxxx

Merci ! 🙏

Architecture technique

Composants impliqués

  1. commande_status_widget.dart (lignes 305-366)

    • Affiche le bouton "Payé"
    • Gère la modal de sélection du montant
    • Coordonne les callbacks
  2. commande_details_page.dart

    • _createDepositTransaction() : Crée la transaction en DB
    • _createDepositPaymentLink() : Génère le lien Stripe
    • _sendAgentMessage() : Envoie le message WhatsApp
  3. payment_amount_dialog.dart

    • Modal de sélection du montant
    • Suggestions rapides (30%, 50%, 100%)
  4. Backend API (kazalendar-agent-api)

    • Service de paiement Stripe
    • Envoi de messages WhatsApp
  5. Base de données (Supabase)

    • Table payment_transactions : Stocke les acomptes
    • Trigger send_whatsapp_message_trigger : Envoie automatiquement les messages

Tables de base de données

payment_transactions

CREATE TABLE payment_transactions (
id UUID PRIMARY KEY,
commande_id UUID REFERENCES commandes(id),
user_id UUID REFERENCES auth.users(id),

-- Montant
montant DECIMAL(10,2) NOT NULL,
devise VARCHAR(3) DEFAULT 'EUR',

-- Type
type payment_transaction_type NOT NULL, -- 'acompte', 'solde', 'partiel', 'total'
label TEXT NOT NULL,

-- Paiement
payment_method VARCHAR(50),
payment_link_id UUID REFERENCES payment_links(id),

-- Statut
status payment_transaction_status DEFAULT 'pending',
paid_at TIMESTAMPTZ,

created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);

Commandes (statuts)

Important : Le statut de la commande reste "accepted" après la demande d'acompte.

  • Le passage au statut "paid" se fait uniquement quand le paiement complet est reçu
  • L'acompte crée seulement une transaction dans payment_transactions

Contrainte SQL importante

-- Contrainte check_payment_logic
CHECK (
(status = 'paid' AND payment_type IS NOT NULL) OR
(status != 'paid')
)

Cette contrainte garantit que si une commande a le statut "paid", elle doit avoir un payment_type défini.

Workflow des statuts

┌─────────────────┐
│ pending │ Commande créée
└────────┬────────┘
│ Vendeur accepte

┌─────────────────┐
│ accepted │ Commande acceptée
└────────┬────────┘

│ Vendeur clique "Payé"

┌────┴────┐
│ │
▼ ▼
┌─────────┐ ┌──────────────────────┐
│ Acompte │ │ Paiement complet │
└────┬────┘ └──────────┬───────────┘
│ │
│ Reste "accepted"│ Passe à "paid"
│ + Crée transaction │
│ │
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ accepted │ │ paid │
│ + transaction │ └────────┬────────┘
└────────┬────────┘ │
│ │
│ Client paie solde │
│ │
▼ │
┌─────────────────┐ │
│ paid │◄──────────┘
└────────┬────────┘
│ Livraison

┌─────────────────┐
│ in_delivery │
└────────┬────────┘
│ Terminé

┌─────────────────┐
│ completed │
└─────────────────┘

Callbacks et fonctions

CommandeStatusWidget

// Callbacks requis
final Future<String> Function(double montant, String label)? onCreateDepositTransaction;
final Future<PaymentLink> Function(double amount)? onCreateDepositPaymentLink;
final Future<void> Function(String message)? onSendAgentMessage;

Exemple d'utilisation

CommandeStatusWidget(
commande: currentCommande,
isAdminMode: true,

// Callbacks standards
onStatusUpdate: _updateCommandeStatus,
onStatusUpdateWithPayment: _updateCommandeStatusWithPayment,

// Callbacks pour l'acompte
onCreateDepositTransaction: _createDepositTransaction,
onCreateDepositPaymentLink: _createDepositPaymentLink,
onSendAgentMessage: _sendAgentMessage,
)

Configuration requise

1. Stripe

  • Compte Stripe activé
  • Clés API configurées dans .env
  • Mode TEST ou PRODUCTION selon l'environnement

2. WhatsApp Business

  • Compte WhatsApp Business activé
  • Configuration dans vendor_whatsapp_config
  • Access token valide

3. Supabase

  • Extension pg_net activée (pour le trigger WhatsApp)
  • Trigger send_whatsapp_message_trigger déployé

4. Backend API

  • Service en cours d'exécution
  • Variables d'environnement configurées
  • Route /api/system-messages/send accessible

Tests

Test du workflow complet

  1. Prérequis :

    • Mode Stripe TEST activé
    • Backend API en cours d'exécution
    • Commande avec prix défini (ex: 150€)
    • Conversation Agent IA active
  2. Étapes :

    1. Accepter la commande
    2. Cliquer sur "Payé"
    3. Sélectionner "Acompte"
    4. Modifier le montant (ex: 45€)
    5. Cliquer "Confirmer"
    6. Cliquer "Confirmer et envoyer"
  3. Vérifications :

    • ✅ Transaction créée dans la DB
    • ✅ Lien Stripe généré (commençant par https://buy.stripe.com/)
    • ✅ Message envoyé sur WhatsApp
    • ✅ Statut reste "accepted"
    • ✅ Notification de succès affichée

Cartes de test Stripe

NuméroRésultat
4242 4242 4242 4242Paiement réussi
4000 0000 0000 0002Paiement refusé

Troubleshooting

Le message WhatsApp n'est pas envoyé

  1. Vérifier que la conversation Agent IA existe (_agentConversation != null)
  2. Vérifier les logs du backend API
  3. Vérifier la configuration WhatsApp dans vendor_whatsapp_config
  4. Vérifier que le trigger Supabase est actif

Le lien de paiement n'est pas généré

  1. Vérifier les clés Stripe dans .env
  2. Vérifier que le mode (TEST/PROD) est correct
  3. Consulter les logs Stripe dans le dashboard
  4. Vérifier que le compte Stripe n'est pas en review

Erreur "check_payment_logic"

Cette erreur signifie qu'on essaie de passer au statut "paid" sans payment_type.

Solution : Ne jamais passer au statut "paid" pour un acompte. Le statut reste "accepted".

La transaction n'est pas créée

  1. Vérifier que onCreateDepositTransaction est bien passé au widget
  2. Vérifier les permissions Supabase (RLS)
  3. Consulter les logs de l'application

Améliorations futures

  • Rappels automatiques si l'acompte n'est pas payé après X jours
  • Support Instagram (en plus de WhatsApp)
  • Gestion du solde restant (paiement du reste)
  • Historique des relances
  • Notifications push en plus de WhatsApp
  • Personnalisation du message d'acompte
  • Pourcentage d'acompte par défaut configurable

Dernière mise à jour : 10 novembre 2025