Passa al contenuto principale
In questa pagina

Prerequisiti#

Prima di implementare Portafoglio Deuna App pagamenti, assicurarsi di avere:

  • Abilitato Portafoglio Deuna App nel pannello di amministrazione Deuna
  • Generato un ordine di token tramite l'API Deuna
  • Integrato Deuna SDK nel tuo progetto
  • Recensione Pagamento documentazione Widget per la tua piattaforma
  • Selezionato il tuo preferito modalità di pagamento (Codice numerico o QR) nel pannello di amministrazione

Configurazione Widget di pagamento#

Attuazione di base

Inizializzare il Widget di pagamento con il deuna_wallet processore:

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
    },
  },
});

Esempio completo con tutte le opzioni

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,
      });
    },
  },
});

Modalità di pagamento#

Comprendere le due modalità

Il tuo account di commerciante è configurato con una di queste modalità nel pannello di amministrazione:

Modalità 1: Codice numerico (3-finestra intatta)

Cosa vede il cliente:

  • Un codice numerico a 6 cifre visualizzato sullo schermo
  • Timer conto alla rovescia che mostra tempo rimanente (0:00-3:00)
  • Istruzioni per aprire Deuna App e inserire il codice

Flusso del cliente:

  1. Note il codice a 6 cifre
  2. Apre Deuna App
  3. Seleziona "Paga con codice"
  4. Inserisci il codice a 6 cifre
  5. Conferma il pagamento in app
  6. Pagamento confermato immediatamente tramite webhook

Configurazione: Impostare nel pannello di amministrazione sotto le impostazioni del processore di Deuna App Wallet

Modalità 2: Codice QR (15-Minute Window)

Cosa vede il cliente:

  • Un codice QR dinamico sullo schermo
  • Timer conto alla rovescia che mostra tempo rimanente (0:00-15:00)
  • Due opzioni per procedere:
    • Scansione QR con fotocamera Deuna App
    • Fare clic su QR per aprire l'app direttamente

Flusso del cliente:

  1. Opzione A - Scansione:

    • Apre la fotocamera Deuna App
    • Scansiona il codice QR
    • La pagina di pagamento si apre automaticamente
    • Conferma il pagamento in app
    • Pagamento confermato tramite webhook
  2. Opzione B - Cliccare su:

    • Clic QR code o pulsante
    • Apre Deuna App direttamente
    • Mostra la schermata di conferma del pagamento
    • Conferma del pagamento
    • Pagamento confermato tramite webhook

Configurazione: Impostare nel pannello di amministrazione sotto le impostazioni del processore di Deuna App Wallet

Nota: Selezione della modalità avviene una volta durante la configurazione iniziale nel pannello di amministrazione. Tutti gli ordini successivi utilizzeranno la modalità configurata. Contatta il supporto Deuna per cambiare le modalità.

Gestione della conferma di pagamento#

Confermazione basata su Webhook (Primaria)

Il Portafoglio Deuna App invia una notifica webhook al tuo backend quando il cliente conferma il pagamento:

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 });
});

Polling Fallback (Secondo)

Se la consegna webhook è ritardata o non riesce, il sistema sonda i /order endpoint ogni 3 secondi:

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();
};

Oggetti di risposta#

Risposta di successo

Quando il pagamento è confermato, onSuccess callback riceve:

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
  }
}

Risposta di errore

Quando il pagamento non viene eseguito, onError callback riceve:

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

Risposta in attesa

Quando si attende la conferma dell'utente, onPending callback riceve:

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
}

Risposta scaduta

Quando il codice/QR scade, onExpired callback riceve:

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"
}

Migliori pratiche dell'interfaccia utente#

Per la modalità Codice Numerico

  • Visualizzare il codice in modo prominente - Grande, chiaro carattere
  • Mostra il timer conto alla rovescia - Aggiornamento ogni secondo
  • Visualizzare le istruzioni chiare:
    • "Aprire l'App Deuna"
    • "Seleziona la paga con il codice"
    • "Inserire questo codice a 6 cifre"
    • "Conferma pagamento"
  • Mostra lo stato di scadenza - Quando il codice scade dopo 3 minuti
  • Fornire l'opzione rigenerante - "Generare nuovo codice" pulsante

Per la modalità QR Code

  • Visualizzare il codice QR in modo prominente - Centro, scalabile
  • Mostra il timer conto alla rovescia - Aggiornamento ogni secondo
  • Fornire due opzioni di interazione:
    • Scansione QR con Deuna App
    • Fare clic su QR per aprire l'app direttamente
  • Visualizzare le istruzioni chiare
  • Mostra lo stato di scadenza - Quando il QR scade dopo 15 minuti
  • Fornire l'opzione rigenerante - "Generare nuovo codice" pulsante

Linee guida generali

  • Tenere aperto modal/schermo - Non reindirizzare o chiudere fino a quando il pagamento non è confermato o scaduto
  • Disattivare altri metodi di pagamento - Prevenire di selezionare un altro metodo durante l'attesa
  • Riattiva mobile - Assicurare la leggibilità su piccoli schermi
  • Accessibilità - Includere il testo alt per QR, contrasto di colore chiaro per i timer
  • Stati di caricamento - Mostrare il girante mentre genera il codice/QR

Modelli comuni di attuazione#

Modello di gancio reagito

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 };
};