Abonnements et paiements¶
Ce document décrit les offres d'abonnement, les moyens de paiement acceptés et l'intégration de la passerelle de paiement Djomy (page de paiement hébergée, webhook, API mobile).
Offres d'abonnement¶
Les offres sont stockées en base (entité Plan) et administrables depuis le back-office
(/admin/plans). Chaque plan porte :
| Champ | Description |
|---|---|
name, description |
Intitulé et présentation de l'offre |
monthlyPrice, yearlyPrice |
Tarifs mensuel et annuel |
features |
Liste des fonctionnalités incluses |
cardsIncluded |
Nombre de cartes comprises dans l'offre |
additionalCardPrice |
Tarif d'une carte supplémentaire |
badge, popular |
Mise en avant dans la grille tarifaire |
isActive |
Visibilité de l'offre |
sortOrder |
Ordre d'affichage |
Un abonnement souscrit est représenté par l'entité Subscription :
| Statut | Signification |
|---|---|
PENDING |
Souscrit, en attente de règlement |
ACTIVE |
Actif |
CANCELLED |
Résilié |
EXPIRED |
Échu |
Périodicité de facturation : MONTHLY ou YEARLY.
Tout compte ROLE_USER dépourvu d'abonnement se voit attribuer automatiquement un abonnement
gratuit lors de son premier accès au tableau de bord
(SubscriptionService::createFreeSubscriptionForUser()).
Moyens de paiement¶
L'entité Payment reconnaît les moyens suivants :
| Constante | Valeur | Usage |
|---|---|---|
DJOMY |
DJOMY |
Paiement en ligne via la page hébergée Djomy (web et API mobile) |
CREDIT_CARD |
CREDIT_CARD |
Valeur historique (ancien paiement par carte Stripe), plus utilisée pour de nouveaux paiements |
ORANGE_MONEY |
ORANGE_MONEY |
Paiement mobile — non implémenté : six contrôleurs rejettent ce moyen de paiement dès sa sélection (voir Configuration § Paiements) |
DELIVERY_CASH |
DELIVERY_CASH |
Paiement à la livraison |
PRO_SUBSCRIPTION |
PRO_SUBSCRIPTION |
Règlement d'un abonnement professionnel |
COMPANY_FREE |
COMPANY_FREE |
Attribution gratuite à une entreprise |
MANUAL |
MANUAL |
Saisie manuelle par un administrateur |
Statuts d'un paiement :
| Constante | Valeur |
|---|---|
PENDING_STATUS |
PENDING |
ACCEPTED_STATUS |
ACCEPTED |
COMPLETED_STATUS |
COMPLETED |
REJECTED_STATUS |
REJECTED |
Intégration Djomy¶
Djomy (passerelle guinéenne, mode test « sandbox » ou production) remplace Stripe sur tous les parcours, web et API mobile. Le client est redirigé vers une page de paiement hébergée par Djomy, où il choisit son moyen de paiement (Orange Money, MTN MoMo, Soutra Money, PayCard, Kulu, carte). Les montants sont toujours en GNF. Djomy ne renvoie pas le client vers BCard ni vers l'application mobile après le paiement.
Configuration¶
| Variable | Rôle |
|---|---|
DJOMY_API_URL |
URL de l'API Djomy (sandbox ou production) |
DJOMY_CLIENT_ID |
Identifiant client |
DJOMY_CLIENT_SECRET |
Secret client, aussi utilisé pour vérifier la signature des webhooks |
Ces valeurs sont des secrets : elles ne doivent jamais être committées. Sans elles, le paiement en ligne répond « indisponible » (message sur le web, HTTP 503 sur l'API). Le guide de test est dans paiement-djomy-tests.md.
Composants¶
| Composant | Rôle |
|---|---|
DjomyService |
Client de l'API : jeton, création de la transaction, lecture du statut, signature du webhook, normalisation du téléphone |
DjomyCheckoutService |
Démarre le paiement d'un Payment (référence BCARD-PAY-<id>, jeton de retour, règle des 10 minutes sur une transaction encore PENDING) |
PaymentFulfillmentService |
Valide un paiement réussi : idempotent et verrouillé, il active l'abonnement ou confirme la commande ou la carte physique |
MobilePaymentService |
Briques communes de l'API mobile : relecture du statut, réponses de démarrage et d'erreur |
DjomyReturnController |
Retour du navigateur web (/payment/djomy/return/{token}) |
DjomyWebhookController |
Webhook Djomy (POST /webhook/djomy) |
Règle d'or : seul un statut Djomy SUCCESS, relu auprès de Djomy, prouve un paiement. Le corps d'un
webhook ou d'un retour de navigateur n'est jamais cru tel quel.
Trois chemins de confirmation¶
Tous aboutissent à PaymentFulfillmentService::fulfill() :
- Webhook
POST /webhook/djomy: signatureX-Webhook-Signaturevérifiée, puis statut relu chez Djomy (statutSUCCESS, deviseGNF, référence marchande désignant bien le paiement). - Retour navigateur (web uniquement) : le statut est relu chez Djomy.
- Vérification de statut (API mobile) :
GET /api/payments/{id}/statusrelit le statut chez Djomy (même contrôle de référence que le webhook, sourceapi_status).
Une tâche planifiée de réconciliation sert de filet de sécurité (voir deploiement.md).
API mobile¶
L'application Flutter n'utilise plus de SDK Stripe : elle ouvre l'redirect_url renvoyée par l'API dans un
navigateur, puis interroge le statut du paiement.
| Endpoint | Rôle |
|---|---|
POST /api/subscription/upgrade-to-pro |
Crée (ou reprend) l'abonnement Pro PENDING et son paiement, renvoie redirect_url (201) |
POST /api/physical-cards/{id}/pay |
Crée (ou reprend) la commande et le paiement de la carte, renvoie redirect_url (201) |
GET /api/payments/{id}/status |
Relit le statut chez Djomy : COMPLETED, PENDING ou FAILED |
POST /api/subscription/confirm-payment |
Conservé pour compatibilité : même vérification, payment_id dans le corps |
POST /api/physical-cards/{id}/confirm-payment |
Conservé pour compatibilité : même vérification pour le paiement de la carte |
Erreurs de démarrage : 400 (téléphone ou moyen de paiement invalide), 409 (paiement déjà en cours ou déjà confirmé), 503 (Djomy non configuré ou indisponible). Détail et exemples : api-mobile-paiement-djomy.md.
Colonnes Stripe conservées¶
Les colonnes stripe_payment_intent_id (Payment), stripe_session_id (Order) et
stripe_subscription_id (Subscription) sont conservées en base pour l'historique ; plus aucun code ne
les écrit et la bibliothèque Stripe n'est plus appelée.
Cycle de vie d'une commande de carte physique¶
Panier
└─> Commande créée Order: DRAFT / En attente de paiement
└─> Paiement initié Payment: PENDING PhysicalCard: PENDING_PAYMENT
└─> Djomy confirme Payment: COMPLETED PhysicalCard: CONFIRMED
└─> Fabrication PhysicalCard: PROCESSING
└─> Expédition PhysicalCard: SHIPPED
└─> Réception PhysicalCard: DELIVERED
Les changements de statut opérés depuis le back-office sont consignés dans le journal d'audit
(AuditLog::ACTION_ORDER_STATUS_UPDATED).
Factures¶
Les factures sont générées en PDF par DomPdfService et téléchargeables depuis le back-office :
/admin/invoice/payment/{id}— facture d'un paiement/admin/pro-payments/{id}/invoice— facture d'un paiement professionnel