Gestion des Acomptes et Historique de Paiement
Vue d'ensemble
Cette fonctionnalité permet de gérer les paiements partiels (acomptes) et de tracer l'historique complet des paiements pour chaque commande.
Structure de la base de données
Table payment_transactions
Nouvelle table pour stocker l'historique des transactions de paiement :
- id: UUID (clé primaire)
- commande_id: UUID (référence à la commande)
- user_id: UUID (propriétaire)
- montant: DECIMAL(10,2)
- devise: VARCHAR(3) (EUR par défaut)
- type: ENUM ('acompte', 'solde', 'partiel', 'total')
- label: TEXT (ex: "Acompte", "Livraison", "Solde restant")
- payment_method: VARCHAR(50) ('card', 'cash', 'transfer', 'other')
- payment_link_id: UUID (lien vers payment_links si applicable)
- status: ENUM ('pending', 'completed', 'failed', 'refunded', 'cancelled')
- paid_at: TIMESTAMPTZ
- created_at: TIMESTAMPTZ
- updated_at: TIMESTAMPTZ
- notes: TEXT
- stripe_payment_intent_id: TEXT
Modifications de la table commandes
Ajout du champ :
- acompte_montant: DECIMAL(10,2) (montant d'acompte requis, optionnel)
Architecture du code
Entités
-
PaymentTransaction (
lib/features/calendar/domain/entities/payment_transaction.dart)- Représente une transaction de paiement
- Propriétés calculées :
isPaid,isPending,isEffective,montantFormate
-
PaymentTransactionStatus (enum)
pending: En attentecompleted: Payé ✅failed: Échoué ❌refunded: Remboursé ↩️cancelled: Annulé 🚫
-
PaymentTransactionType (enum)
acompte: Acompte 💰solde: Solde 💵partiel: Paiement partiel 📝total: Paiement total ✅
Modifications de l'entité Commande
Nouvelles propriétés :
final double? acompteMontant;
final List<PaymentTransaction>? transactions;
Nouvelles méthodes calculées :
bool get acompteRequis // Si un acompte est défini
double get montantPaye // Somme des transactions payées
double get montantRestant // Prix total - montant payé
bool get acomptePaye // Si l'acompte a été payé
bool get totalementPaye // Si tout est payé
double get pourcentagePaye // % de paiement
String get montantRestantFormate
String get montantPayeFormate
Repository
PaymentTransactionRepository avec implémentation Supabase :
Méthodes principales :
getTransactionsByCommande(commandeId): Récupère toutes les transactions d'une commandecreateTransaction(...): Crée une nouvelle transactionupdateTransactionStatus(...): Met à jour le statut d'une transactionmarkTransactionAsPaid(...): Marque une transaction comme payéegetTotalPaidAmount(commandeId): Calcule le montant total payégetPendingTransactions(commandeId): Récupère les transactions en attente
UI
PaymentHistoryWidget (lib/features/calendar/presentation/widgets/payment_history_widget.dart)
Widget réutilisable qui affiche :
- ✅ Un résumé du statut de paiement (Payé / Acompte payé / En attente)
- 📊 Une barre de progression du paiement
- 📋 La liste complète des transactions avec :
- Label personnalisé
- Montant
- Statut (avec emoji et couleur)
- Type de transaction
- Date de paiement
- Méthode de paiement
- Notes
Cas d'usage
Scénario 1 : Sans acompte
Commande commande = Commande(
id: '123',
titre: 'Gâteau anniversaire',
prix: 100.0,
// acompteMontant est null (pas d'acompte)
);
// Créer une transaction pour le paiement total
PaymentTransaction transaction = await repository.createTransaction(
commandeId: '123',
montant: 100.0,
label: 'Paiement total',
type: PaymentTransactionType.total,
);
// Marquer comme payé
await repository.markTransactionAsPaid(transactionId: transaction.id);
Scénario 2 : Avec acompte
Commande commande = Commande(
id: '456',
titre: 'Gâteau mariage',
prix: 150.0,
acompteMontant: 50.0, // Acompte de 50€ requis
);
// 1. Créer la transaction d'acompte
PaymentTransaction acompte = await repository.createTransaction(
commandeId: '456',
montant: 50.0,
label: 'Acompte',
type: PaymentTransactionType.acompte,
paymentMethod: 'card',
);
// 2. Marquer l'acompte comme payé
await repository.markTransactionAsPaid(transactionId: acompte.id);
// Vérifier l'acompte
print(commande.acomptePaye); // true
print(commande.montantPaye); // 50.0
print(commande.montantRestant); // 100.0
print(commande.totalementPaye); // false
// 3. Plus tard, créer la transaction pour le solde
PaymentTransaction solde = await repository.createTransaction(
commandeId: '456',
montant: 100.0,
label: 'Livraison',
type: PaymentTransactionType.solde,
paymentMethod: 'cash',
);
// 4. Marquer le solde comme payé
await repository.markTransactionAsPaid(transactionId: solde.id);
// Vérifier le paiement complet
print(commande.montantPaye); // 150.0
print(commande.totalementPaye); // true
Scénario 3 : Paiements multiples
Commande commande = Commande(
id: '789',
titre: 'Gâteau entreprise',
prix: 300.0,
acompteMontant: 100.0,
);
// Créer plusieurs transactions
await repository.createTransaction(
commandeId: '789',
montant: 100.0,
label: 'Acompte',
type: PaymentTransactionType.acompte,
);
await repository.createTransaction(
commandeId: '789',
montant: 100.0,
label: 'Deuxième versement',
type: PaymentTransactionType.partiel,
);
await repository.createTransaction(
commandeId: '789',
montant: 100.0,
label: 'Solde final',
type: PaymentTransactionType.solde,
);
// L'historique complet sera visible dans le PaymentHistoryWidget
Intégration avec le chat IA
Pour permettre au chat IA d'envoyer des demandes de paiement :
1. Lors de la création de commande
// L'agent IA peut demander si un acompte est souhaité
"Souhaitez-vous demander un acompte ? (Oui/Non)"
// Si oui, demander le montant
"Quel montant d'acompte ? (suggéré: 30% = 45€)"
// Créer la commande avec l'acompte
Commande commande = Commande(
titre: 'Gâteau anniversaire',
prix: 150.0,
acompteMontant: 45.0,
);
2. Envoi du lien de paiement
// Créer une transaction pour l'acompte
PaymentTransaction transaction = await repository.createTransaction(
commandeId: commande.id,
montant: commande.acompteMontant!,
label: 'Acompte',
type: PaymentTransactionType.acompte,
paymentMethod: 'card',
);
// Créer un lien de paiement Stripe
// (existant dans payment_links)
PaymentLink link = await createStripePaymentLink(
amount: transaction.montant,
description: transaction.label,
);
// Lier la transaction au payment_link
await repository.updateTransaction(
transaction.copyWith(paymentLinkId: link.id),
);
// Envoyer via WhatsApp
"Bonjour, voici le lien pour payer l'acompte de 45€ : [lien]"
3. Webhook de confirmation
// Quand Stripe confirme le paiement
Future<void> onPaymentConfirmed(String paymentIntentId) async {
// Trouver la transaction liée
final transaction = await repository.getTransactionByPaymentIntent(paymentIntentId);
// Marquer comme payée
await repository.markTransactionAsPaid(
transactionId: transaction.id,
stripePaymentIntentId: paymentIntentId,
);
// Envoyer une confirmation via le chat IA
"Paiement de ${transaction.montantFormate} confirmé pour ${transaction.label} ✅"
}
Migrations à exécuter
Pour activer cette fonctionnalité, exécuter ces migrations dans l'ordre :
supabase/migrations/create_payment_transactions.sqlsupabase/migrations/add_acompte_to_commandes.sql
Utilisation dans l'UI
Dans la page de détails de commande :
import 'package:kazacalendar_mobile/features/calendar/presentation/widgets/payment_history_widget.dart';
// Dans le build method
PaymentHistoryWidget(commande: commande)
Le widget affichera automatiquement :
- L'historique complet si des transactions existent
- Un message "Aucun paiement enregistré" sinon
- Une barre de progression du paiement
- Le statut global (Payé / Acompte payé / En attente)
Avantages de cette approche
- ✅ Flexibilité maximale : N'importe quel nombre de paiements partiels
- ✅ Traçabilité complète : Chaque paiement est enregistré avec tous les détails
- ✅ Compatible avec l'existant : Les commandes sans acompte fonctionnent normalement
- ✅ Calculs automatiques : Montant payé, restant, pourcentage calculés dynamiquement
- ✅ Intégration facile : Repository prêt à l'emploi avec toutes les méthodes nécessaires
- ✅ UI moderne : Widget réutilisable avec barre de progression et emojis
Prochaines étapes
Pour compléter l'intégration :
- Ajouter le
PaymentHistoryWidgetdanscommande_details_page.dart - Créer une interface pour ajouter manuellement des paiements (espèces, virement)
- Intégrer avec le chat IA pour l'envoi automatique de liens de paiement
- Ajouter des notifications quand un paiement est reçu
- Permettre l'édition/suppression de transactions en attente