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
- Le vendeur clique sur le bouton "Payé" dans les détails de la commande
- 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" :
- Un champ de montant pré-rempli s'affiche (30% du prix par défaut)
- Le vendeur peut :
- Modifier le montant manuellement
- Utiliser les suggestions rapides (30%, 50%, 100%)
- Le vendeur clique sur "Confirmer"
4. Confirmation et envoi
-
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 ? -
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
-
commande_status_widget.dart (lignes 305-366)
- Affiche le bouton "Payé"
- Gère la modal de sélection du montant
- Coordonne les callbacks
-
commande_details_page.dart
_createDepositTransaction(): Crée la transaction en DB_createDepositPaymentLink(): Génère le lien Stripe_sendAgentMessage(): Envoie le message WhatsApp
-
payment_amount_dialog.dart
- Modal de sélection du montant
- Suggestions rapides (30%, 50%, 100%)
-
Backend API (
kazalendar-agent-api)- Service de paiement Stripe
- Envoi de messages WhatsApp
-
Base de données (Supabase)
- Table
payment_transactions: Stocke les acomptes - Trigger
send_whatsapp_message_trigger: Envoie automatiquement les messages
- Table
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_netactivée (pour le trigger WhatsApp) - Trigger
send_whatsapp_message_triggerdéployé
4. Backend API
- Service en cours d'exécution
- Variables d'environnement configurées
- Route
/api/system-messages/sendaccessible
Tests
Test du workflow complet
-
Prérequis :
- Mode Stripe TEST activé
- Backend API en cours d'exécution
- Commande avec prix défini (ex: 150€)
- Conversation Agent IA active
-
É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" -
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éro | Résultat |
|---|---|
| 4242 4242 4242 4242 | Paiement réussi |
| 4000 0000 0000 0002 | Paiement refusé |
Troubleshooting
Le message WhatsApp n'est pas envoyé
- Vérifier que la conversation Agent IA existe (
_agentConversation != null) - Vérifier les logs du backend API
- Vérifier la configuration WhatsApp dans
vendor_whatsapp_config - Vérifier que le trigger Supabase est actif
Le lien de paiement n'est pas généré
- Vérifier les clés Stripe dans
.env - Vérifier que le mode (TEST/PROD) est correct
- Consulter les logs Stripe dans le dashboard
- 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
- Vérifier que
onCreateDepositTransactionest bien passé au widget - Vérifier les permissions Supabase (RLS)
- 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