> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oneclickdz.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Étape 3 : Suivi du statut

> Vérification automatique et simple du statut des paiements

## Vue d'ensemble

Vous devez vérifier le statut des paiements car le traitement bancaire est asynchrone. Utilisez deux méthodes simples :

1. **Tâche cron** : Vérifiez les commandes en attente toutes les 20 minutes
2. **Vérification manuelle** : Lorsque le client consulte sa commande

## Méthode 1 : Tâche cron (toutes les 20 minutes)

<CodeGroup>
  ```javascript Node.js avec node-cron theme={null}
  const cron = require("node-cron");

  // Exécuter toutes les 20 minutes
  cron.schedule("*/20 * * * *", async () => {
    console.log("Vérification des paiements en attente...");

    try {
      // Récupérer les commandes en attente des dernières 24 heures
      const pendingOrders = await db.orders.find({
        status: "PENDING",
        paymentRef: { $exists: true },
        createdAt: { $gte: new Date(Date.now() - 24 * 60 * 60 * 1000) },
      });

      for (const order of pendingOrders) {
        await checkAndUpdateOrder(order.id, order.paymentRef);
        await sleep(100); // Petit délai entre les requêtes
      }

      console.log(`Vérifié ${pendingOrders.length} commandes`);
    } catch (error) {
      console.error("Erreur tâche cron :", error);
    }
  });

  async function checkAndUpdateOrder(orderId, paymentRef) {
    try {
      const response = await fetch(
        `https://api.oneclickdz.com/v3/ocpay/checkPayment/${paymentRef}`,
        {
          headers: { "X-Access-Token": process.env.ONECLICK_API_KEY },
        }
      );

      const data = await response.json();
      const status = data.data.status;

      if (status === "CONFIRMED") {
        await db.orders.update(orderId, { status: "PAID" });
        console.log(`✅ Commande ${orderId} marquée comme PAYÉE`);
      } else if (status === "FAILED") {
        await db.orders.update(orderId, { status: "FAILED" });
        console.log(`❌ Commande ${orderId} marquée comme ÉCHOUÉE`);
      }
    } catch (error) {
      console.error(`Erreur vérification commande ${orderId} :`, error);
    }
  }

  function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }
  ```

  ```python Python avec APScheduler theme={null}
  from apscheduler.schedulers.background import BackgroundScheduler
  import requests
  import os
  from datetime import datetime, timedelta
  import time

  scheduler = BackgroundScheduler()

  # Exécuter toutes les 20 minutes
  @scheduler.scheduled_job('interval', minutes=20)
  def check_pending_payments():
      print('Vérification des paiements en attente...')

      try:
          # Récupérer les commandes en attente des dernières 24 heures
          yesterday = datetime.now() - timedelta(days=1)
          pending_orders = db.orders.find({
              'status': 'PENDING',
              'paymentRef': {'$exists': True},
              'createdAt': {'$gte': yesterday}
          })

          count = 0
          for order in pending_orders:
              check_and_update_order(order['id'], order['paymentRef'])
              time.sleep(0.1)  # Petit délai entre les requêtes
              count += 1

          print(f'Vérifié {count} commandes')
      except Exception as e:
          print(f'Erreur tâche cron : {e}')

  def check_and_update_order(order_id, payment_ref):
      try:
          response = requests.get(
              f'https://api.oneclickdz.com/v3/ocpay/checkPayment/{payment_ref}',
              headers={'X-Access-Token': os.getenv('ONECLICK_API_KEY')}
          )

          data = response.json()
          status = data['data']['status']

          if status == 'CONFIRMED':
              db.orders.update(order_id, {'status': 'PAID'})
              print(f'✅ Commande {order_id} marquée comme PAYÉE')
          elif status == 'FAILED':
              db.orders.update(order_id, {'status': 'FAILED'})
              print(f'❌ Commande {order_id} marquée comme ÉCHOUÉE')
      except Exception as e:
          print(f'Erreur vérification commande {order_id} : {e}')

  # Démarrer le planificateur
  scheduler.start()
  ```

  ```php PHP avec Cron theme={null}
  <?php
  // cron-check-payments.php
  // Ajouter au crontab : */20 * * * * php /path/to/cron-check-payments.php

  require_once 'config.php';

  echo "Vérification des paiements en attente...\n";

  try {
      // Récupérer les commandes en attente des dernières 24 heures
      $yesterday = date('Y-m-d H:i:s', strtotime('-24 hours'));

      $stmt = $db->prepare("
          SELECT id, payment_ref
          FROM orders
          WHERE status = 'PENDING'
          AND payment_ref IS NOT NULL
          AND created_at >= ?
      ");
      $stmt->execute([$yesterday]);
      $pendingOrders = $stmt->fetchAll(PDO::FETCH_ASSOC);

      foreach ($pendingOrders as $order) {
          checkAndUpdateOrder($order['id'], $order['payment_ref']);
          usleep(100000); // Délai de 100ms
      }

      echo "Vérifié " . count($pendingOrders) . " commandes\n";
  } catch (Exception $e) {
      echo "Erreur tâche cron : " . $e->getMessage() . "\n";
  }

  function checkAndUpdateOrder($orderId, $paymentRef) {
      global $db;

      try {
          $ch = curl_init("https://api.oneclickdz.com/v3/ocpay/checkPayment/{$paymentRef}");
          curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
          curl_setopt($ch, CURLOPT_HTTPHEADER, [
              'X-Access-Token: ' . getenv('ONECLICK_API_KEY')
          ]);

          $response = curl_exec($ch);
          $data = json_decode($response, true);
          $status = $data['data']['status'];

          if ($status === 'CONFIRMED') {
              $stmt = $db->prepare("UPDATE orders SET status = 'PAID' WHERE id = ?");
              $stmt->execute([$orderId]);
              echo "✅ Commande {$orderId} marquée comme PAYÉE\n";
          } elseif ($status === 'FAILED') {
              $stmt = $db->prepare("UPDATE orders SET status = 'FAILED' WHERE id = ?");
              $stmt->execute([$orderId]);
              echo "❌ Commande {$orderId} marquée comme ÉCHOUÉE\n";
          }
      } catch (Exception $e) {
          echo "Erreur vérification commande {$orderId} : " . $e->getMessage() . "\n";
      }
  }
  ?>
  ```
</CodeGroup>

### Configurer la tâche cron

Ajoutez à votre crontab (Linux/Unix) :

```bash theme={null}
# Modifier le crontab
crontab -e

# Ajouter une ligne pour exécuter toutes les 20 minutes
*/20 * * * * /usr/bin/node /path/to/cron-job.js >> /var/log/payment-check.log 2>&1

# Ou pour Python
*/20 * * * * /usr/bin/python3 /path/to/cron-job.py >> /var/log/payment-check.log 2>&1

# Ou pour PHP
*/20 * * * * /usr/bin/php /path/to/cron-check-payments.php >> /var/log/payment-check.log 2>&1
```

## Méthode 2 : Vérification manuelle (quand le client consulte sa commande)

Déjà implémenté à l'Étape 2 ! Quand le client arrive sur la page de commande, elle vérifie automatiquement une fois.

Optionnel : Ajoutez un bouton pour vérifier à la demande (vérifie au maximum toutes les minutes) :

```html theme={null}
<!DOCTYPE html>
<html>
  <head>
    <title>Statut de la commande</title>
  </head>
  <body>
    <h1>Statut de la commande</h1>
    <p>Statut : <span id="status">PENDING</span></p>

    <button id="checkBtn" onclick="startChecking()">
      Check Payment Status
    </button>

    <p id="message"></p>

    <script>
      let checking = false;
      let checkInterval = null;
      const orderId = window.location.pathname.split("/").pop();

      async function checkPayment() {
        const response = await fetch(`/orders/${orderId}/check`, {
          method: "POST",
        });

        const data = await response.json();
        document.getElementById("status").textContent = data.status;

        if (data.status === "CONFIRMED") {
          document.getElementById("message").textContent =
            "✅ Paiement confirmé !";
          stopChecking();
          setTimeout(() => location.reload(), 2000);
        } else if (data.status === "FAILED") {
          document.getElementById("message").textContent = "❌ Paiement échoué";
          stopChecking();
        } else {
          document.getElementById("message").textContent =
            "⏳ Toujours en attente...";
        }
      }

      function startChecking() {
        if (checking) return;

        checking = true;
        document.getElementById("checkBtn").disabled = true;

        // Check immediately
        checkPayment();

        // Puis vérifier toutes les minutes
        checkInterval = setInterval(checkPayment, 60000);

        // Arrêter après 10 minutes
        setTimeout(stopChecking, 10 * 60000);
      }

      function stopChecking() {
        checking = false;
        document.getElementById("checkBtn").disabled = false;
        if (checkInterval) {
          clearInterval(checkInterval);
          checkInterval = null;
        }
      }

      // Vérification automatique au chargement (si en attente)
      if (document.getElementById("status").textContent === "PENDING") {
        checkPayment();
      }
    </script>
  </body>
</html>
```

## Résumé

<Check>
  **Deux méthodes simples :**

  1. ✅ Tâche cron toutes les 20 minutes pour toutes les commandes en attente
  2. ✅ Vérification manuelle quand le client consulte sa commande (maximum toutes les minutes)
  3. ✅ Vérification automatique une fois au chargement de la page de commande

  Cela couvre tous les scénarios sans surcharger l'API !
</Check>

## Prochaines étapes

<Card title="Continuer vers les bonnes pratiques" icon="arrow-right" href="/fr/ocpay-guides/4-best-practices">
  Apprenez les bonnes pratiques de sécurité et de gestion des erreurs
</Card>
