Aller au contenu principal
Sur cette page

Conditions préalables#

Avant de mettre en œuvre Portefeuille d'applications Deuna paiements, assurez-vous d’avoir :

  • Activé Portefeuille d'applications Deuna dans le panneau d'administration de Deuna
  • Généré un jeton de commande via l'API Deuna
  • Intégré le SDK Deuna dans votre projet
  • Examiné le Documentation du widget de paiement pour votre plateforme
  • Sélectionnez votre préféré mode de paiement (Code numérique ou QR) dans le panneau d'administration

Configuration du widget de paiement#

Implémentation de base

Initialisez le widget de paiement avec le deuna_wallet processeur :

JavaScript
DeunaSDK.initPaymentWidget({
  orderToken: '',
  paymentMethods: [
    {
      paymentMethod: 'voucher',
      processors: ['deuna_wallet'],
    },
  ],
  callbacks: {
    onSuccess: (data) => {
      console.log('Payment successful:', data);
      // Redirect to success page
    },
    onError: (error) => {
      console.log('Payment failed:', error);
      // Show error message to user
    },
    onPending: (data) => {
      console.log('Payment pending confirmation:', data);
      // Show waiting screen
    },
  },
});

Exemple complet avec toutes les options

JavaScript
DeunaSDK.initPaymentWidget({
  orderToken: '',
  paymentMethods: [
    {
      paymentMethod: 'voucher',
      processors: ['deuna_wallet'],
      metadata: {
        // Optional: Pass additional data
        orderId: 'your-internal-order-id',
      },
    },
  ],
  callbacks: {
    onSuccess: (response) => {
      console.log('Payment confirmed:', {
        orderId: response.order_id,
        orderToken: response.order_token,
        status: response.status,
        amount: response.amount,
        currency: response.currency,
      });
      
      // Verify payment on your backend
      fetch('/api/verify-payment', {
        method: 'POST',
        body: JSON.stringify({
          orderToken: response.order_token,
          orderId: response.order_id,
        }),
      })
      .then(res => res.json())
      .then(data => {
        if (data.verified) {
          window.location.href = '/order-confirmation';
        }
      });
    },
    
    onError: (error) => {
      console.error('Payment error:', {
        code: error.code,
        message: error.message,
      });
      
      // Show user-friendly error message
      showErrorModal({
        title: 'Payment Failed',
        message: 'Unable to process your payment. Please try again.',
      });
    },
    
    onPending: (response) => {
      console.log('Payment pending user confirmation:', {
        orderId: response.order_id,
        expiresAt: response.expires_at,
      });
    },
    
    onExpired: (response) => {
      console.log('Payment code/QR expired:', {
        orderId: response.order_id,
        expiredAt: response.expired_at,
      });
    },
  },
});

Modes de paiement#

Comprendre les deux modes

Votre compte marchand est configuré avec un de ces modes dans le panneau d'administration :

Mode 1 : Code numérique (fenêtre de 3 minutes)

Ce que voit le client :

  • Un code numérique à 6 chiffres affiché à l'écran
  • Compte à rebours indiquant le temps restant (0:00-3:00)
  • Instructions pour ouvrir l'application Deuna et saisir le code

Flux client :

  1. Note le code à 6 chiffres
  2. Ouvre l'application Deuna
  3. Sélectionne « Payer avec code »
  4. Saisit le code à 6 chiffres
  5. Confirme le paiement dans l'application
  6. Paiement confirmé immédiatement via webhook

Configuration : Défini dans le panneau d'administration sous les paramètres du processeur Deuna App Wallet

Mode 2 : code QR (fenêtre de 15 minutes)

Ce que voit le client :

  • Un code QR dynamique à l'écran
  • Compte à rebours indiquant le temps restant (0:00-15:00)
  • Deux options pour procéder :
    • Scannez QR avec la caméra de l'application Deuna
    • Cliquez sur QR pour ouvrir l'application directement

Flux client :

  1. Option A – Numériser :

    • Ouvre la caméra de l'application Deuna
    • Scanne le code QR
    • La page de paiement s'ouvre automatiquement
    • Confirme le paiement dans l'application
    • Paiement confirmé via webhook
  2. Option B - Cliquez :

    • Clique sur le code QR ou sur le bouton
    • Ouvre directement l'application Deuna
    • Affiche l'écran de confirmation du paiement
    • Confirme le paiement
    • Paiement confirmé via webhook

Configuration : Défini dans le panneau d'administration sous les paramètres du processeur Deuna App Wallet

Remarque : La sélection du mode se produit une fois lors de la configuration initiale dans le panneau d'administration. Toutes les commandes ultérieures utiliseront le mode configuré. Contactez l'assistance Deuna pour changer de mode.

Traitement de la confirmation de paiement#

Confirmation basée sur un webhook (primaire)

Le Deuna App Wallet envoie une notification webhook à votre backend lorsque le client confirme le paiement :

JavaScript
// Your backend webhook endpoint
app.post('/webhooks/deuna-wallet', (req, res) => {
  const { order_id, order_token, status, amount, currency } = req.body;
  
  // Verify webhook signature (recommended)
  const isValid = verifyWebhookSignature(req);
  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  
  // Handle confirmation
  if (status === 'confirmed') {
    // Update your database
    updateOrder(order_id, {
      status: 'paid',
      paidAt: new Date(),
      amount: amount,
      currency: currency,
    });
    
    // Send confirmation email to customer
    sendConfirmationEmail(order_id);
  }
  
  // Acknowledge receipt
  res.json({ success: true });
});

Repli d'interrogation (secondaire)

Si la livraison du webhook est retardée ou échoue, le système interroge le /order point final toutes les 3 secondes :

JavaScript
// Client-side polling (handled automatically by SDK)
// But you can also implement it manually if needed

const pollOrderStatus = async (orderToken) => {
  const maxAttempts = 60; // 3 minutes for numeric code
  let attempts = 0;
  
  while (attempts < maxAttempts) {
    try {
      const response = await fetch(`/api/order/${orderToken}`);
      const order = await response.json();
      
      if (order.status === 'confirmed') {
        handlePaymentSuccess(order);
        return;
      }
      
      if (order.status === 'expired') {
        handlePaymentExpired(order);
        return;
      }
      
      // Wait 3 seconds before polling again
      await new Promise(resolve => setTimeout(resolve, 3000));
      attempts++;
      
    } catch (error) {
      console.error('Polling error:', error);
    }
  }
  
  handlePaymentExpired();
};

Objets de réponse#

Réponse réussie

Lorsque le paiement est confirmé, onSuccess le rappel reçoit :

JavaScript
{
  order_id: "order_abc123def456",
  order_token: "token_xyz789",
  status: "confirmed",
  payment_method: "deuna_wallet",
  amount: 99.99,
  currency: "USD",
  timestamp: "2024-03-20T14:30:45Z",
  metadata: {
    // Any metadata passed during initialization
  }
}

Réponse à l'erreur

Lorsque le paiement échoue, onError le rappel reçoit :

JavaScript
{
  code: "PAYMENT_FAILED",
  message: "Unable to process payment",
  order_id: "order_abc123def456",
  details: {
    reason: "Insufficient funds in Deuna wallet"
  }
}

En attente de réponse

En attendant la confirmation de l'utilisateur, onPending le rappel reçoit :

JavaScript
{
  order_id: "order_abc123def456",
  order_token: "token_xyz789",
  status: "pending",
  payment_method: "deuna_wallet",
  code_or_qr: "123456", // For numeric code mode
  expires_at: "2024-03-20T14:33:45Z",
  expires_in_seconds: 180
}

Réponse expirée

Lorsque le code/QR expire, onExpired le rappel reçoit :

JavaScript
{
  order_id: "order_abc123def456",
  order_token: "token_xyz789",
  status: "expired",
  payment_method: "deuna_wallet",
  expired_at: "2024-03-20T14:33:45Z",
  message: "Code has expired"
}

Meilleures pratiques de l'interface utilisateur#

Pour le mode code numérique

  • Afficher le code bien en évidence - Grande police claire
  • Afficher le compte à rebours - Mettre à jour toutes les secondes
  • Afficher des instructions claires :
    • "Ouvrez l'application Deuna"
    • "Sélectionnez Payer avec le code"
    • "Entrez ce code à 6 chiffres"
    • "Confirmer le paiement"
  • Afficher l'état d'expiration - Lorsque le code expire après 3 minutes
  • Fournir une option de régénération - Bouton "Générer un nouveau code"

Pour le mode code QR

  • Afficher le code QR bien en évidence - Centré, évolutif
  • Afficher le compte à rebours - Mettre à jour toutes les secondes
  • Proposez deux options d'interaction :
    • Scanner QR avec l'application Deuna
    • Cliquez sur QR pour ouvrir l'application directement
  • Afficher des instructions claires
  • Afficher l'état d'expiration - Lorsque le QR expire après 15 minutes
  • Fournir une option de régénération - Bouton "Générer un nouveau code"

Directives générales

  • Gardez le modal/l'écran ouvert - Ne pas rediriger ou fermer jusqu'à ce que le paiement soit confirmé ou expiré
  • Désactivez les autres méthodes de paiement - Empêcher de sélectionner une autre méthode en attendant
  • Adapté aux mobiles - Assurer la lisibilité sur les petits écrans
  • Accessibilité - Inclure un texte alternatif pour QR, un contraste de couleurs clair pour les minuteries
  • États de chargement - Afficher le spinner lors de la génération du code/QR

Modèles de mise en œuvre courants#

Modèle de crochet de réaction

JavaScript
import { useEffect, useState } from 'react';

export const useDeunaWalletPayment = (orderToken) => {
  const [status, setStatus] = useState('idle'); // idle | pending | success | error | expired
  const [expiresAt, setExpiresAt] = useState(null);

  useEffect(() => {
    if (!orderToken) return;

    DeunaSDK.initPaymentWidget({
      orderToken,
      paymentMethods: [
        {
          paymentMethod: 'voucher',
          processors: ['deuna_wallet'],
        },
      ],
      callbacks: {
        onPending: (data) => {
          setStatus('pending');
          setExpiresAt(data.expires_at);
        },
        onSuccess: (data) => {
          setStatus('success');
        },
        onError: (error) => {
          setStatus('error');
        },
        onExpired: () => {
          setStatus('expired');
        },
      },
    });
  }, [orderToken]);

  const regenerate = () => {
    setStatus('idle');
    window.location.reload();
  };

  return { status, expiresAt, regenerate };
};