mrroot/orange-money-bundle

Bundle Symfony pour l'intégration des paiements Orange Money avec support complet des webhooks, callbacks et gestion d'erreurs

v1.0.0 2025-09-02 12:38 UTC

This package is not auto-updated.

Last update: 2025-09-02 20:57:41 UTC


README

License: MIT Symfony PHP

Symfony bundle for Orange Money payment integration with complete webhook support, callbacks, and advanced error handling.

Features

  • Orange Money payment initiation
  • Transaction status verification
  • Webhook and notification handling
  • Robust error handling with logging
  • Flexible configuration via environment variables
  • OAuth2 support for API authentication
  • Symfony compatibility 5.4, 6.x and 7.x
  • Automatic data validation
  • Configurable callback URLs

Bundle Architecture

File Structure

src/OrangeMoneyBundle/
├── DependencyInjection/
│   ├── Configuration.php          # Bundle configuration
│   └── OrangeMoneyExtension.php    # Symfony extension
├── Exception/
│   └── OrangeMoneyException.php    # Custom exceptions
├── Model/
│   ├── PaymentRequest.php          # Payment request model
│   └── PaymentResponse.php         # Payment response model
├── Service/
│   └── OrangeMoneyService.php      # Main service
└── OrangeMoneyBundle.php           # Main bundle class

Flow Diagram

Application → PaymentRequest → OrangeMoneyService → Orange Money API
     ↓              ↓                ↓                    ↓
Controller ← PaymentResponse ← Token Management ← OAuth2 Response

Installation

1. Installation via Composer

composer require mrrootc/orange-money-bundle

2. Bundle Registration

Add the bundle to config/bundles.php:

<?php

return [
    Mrroot\OrangeMoneyBundle\OrangeMoneyBundle::class => ['all' => true],
];

3. Configuration

Create the file config/packages/orange_money.yaml:

orange_money:
    client_id: '%env(OM_CLIENT_ID)%'
    client_secret: '%env(OM_CLIENT_SECRET)%'
    api_base_url: '%env(OM_API_BASE_URL)%'
    token_endpoint: '%env(OM_TOKEN_ENDPOINT)%'
    payment_endpoint: '%env(OM_PAYMENT_ENDPOINT)%'
    transaction_status_endpoint: '%env(OM_TRANSACTIONSTATUS_ENDPOINT)%'

parameters:
    OM_RETURN_URL: '%env(OM_RETURN_URL)%'
    OM_CANCEL_URL: '%env(OM_CANCEL_URL)%'
    OM_NOTIF_URL: '%env(OM_NOTIF_URL)%'
    OM_MERCHANT_KEY: '%env(OM_MERCHANT_KEY)%'

4. Environment Variables

Add these variables to your .env file:

# Orange Money API Configuration
OM_CLIENT_ID=your_client_id
OM_CLIENT_SECRET=your_client_secret
OM_MERCHANT_KEY=your_merchant_key
OM_API_BASE_URL=https://api.orange.com

# API Endpoints
OM_TOKEN_ENDPOINT=/oauth/v3/token
OM_PAYMENT_ENDPOINT=/orange-money-webpay/dev/v1/webpayment
OM_TRANSACTIONSTATUS_ENDPOINT=/orange-money-webpay/dev/v1/transactionstatus

# Callback URLs
OM_RETURN_URL=https://your-site.com/payment/success
OM_CANCEL_URL=https://your-site.com/payment/cancel
OM_NOTIF_URL=https://your-site.com/payment/webhook

Usage

Payment Initiation

<?php

namespace App\Controller;

use Mrroot\OrangeMoneyBundle\Model\PaymentRequest;
use Mrroot\OrangeMoneyBundle\Service\OrangeMoneyService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class PaymentController extends AbstractController
{
    #[Route('/payment/initiate', name: 'payment_initiate', methods: ['POST'])]
    public function initiatePayment(
        Request $request,
        OrangeMoneyService $orangeMoneyService
    ): JsonResponse {
        try {
            // Create payment request
            $paymentRequest = new PaymentRequest(
                orderId: 'ORDER_' . uniqid(),
                amount: 10000, 
                currency: 'GNF', 
                reference: 'REF_' . time(),
                merchantKey: $this->getParameter('OM_MERCHANT_KEY'),
                returnUrl: $this->getParameter('OM_RETURN_URL'),
                cancelUrl: $this->getParameter('OM_CANCEL_URL'),
                notifUrl: $this->getParameter('OM_NOTIF_URL')
            );

            // Initiate payment
            $paymentResponse = $orangeMoneyService->initiatePayment($paymentRequest);

            return new JsonResponse([
                'success' => true,
                'payment_url' => $paymentResponse->getPaymentUrl(),
                'pay_token' => $paymentResponse->getPayToken(),
                'order_id' => $paymentRequest->getOrderId()
            ]);

        } catch (\Exception $e) {
            return new JsonResponse([
                'success' => false,
                'error' => $e->getMessage()
            ], 400);
        }
    }
}

Payment Status Verification

#[Route('/payment/status/{payToken}', name: 'payment_status')]
public function checkPaymentStatus(
    string $payToken,
    OrangeMoneyService $orangeMoneyService
): JsonResponse {
    try {
        $status = $orangeMoneyService->checkTransactionStatus($payToken);

        return new JsonResponse([
            'pay_token' => $payToken,
            'status' => $status->getStatus(),
            'amount' => $status->getAmount(),
            'currency' => $status->getCurrency()
        ]);

    } catch (\Exception $e) {
        return new JsonResponse([
            'error' => $e->getMessage()
        ], 400);
    }
}

Webhook Handling

#[Route('/payment/webhook', name: 'payment_webhook', methods: ['POST'])]
public function handleWebhook(
    Request $request,
    OrangeMoneyService $orangeMoneyService
): JsonResponse {
    try {
        $data = json_decode($request->getContent(), true);
        
        // Process notification
        $paymentStatus = $orangeMoneyService->processNotification($data);
        
        // Your business logic here
        if ($paymentStatus->getStatus() === 'SUCCESS') {
            // Confirm order
        }

        return new JsonResponse([
            'status' => 'success',
            'message' => 'Notification processed'
        ]);

    } catch (\Exception $e) {
        return new JsonResponse([
            'status' => 'error',
            'message' => $e->getMessage()
        ], 500);
    }
}

Data Models

PaymentRequest

$paymentRequest = new PaymentRequest(
    orderId: 'ORDER_123',        // Unique order ID
    amount: 10000,               // Amount 
    currency: 'OUV',             // Currency (OUV for Ouguiya)
    reference: 'REF_123',        // Optional reference
    merchantKey: 'merchant_key', // Merchant key
    returnUrl: 'https://...',    // Success return URL
    cancelUrl: 'https://...',    // Cancellation URL
    notifUrl: 'https://...'      // Notification URL
);

PaymentResponse

// Available methods
$response->getPaymentUrl();    // Payment URL
$response->getPayToken();      // Payment token
$response->getStatus();        // Payment status
$response->getOrderId();       // Order ID
$response->getAmount();        // Amount
$response->getCurrency();      // Currency
$response->isSuccessful();     // Success verification
$response->hasError();         // Error verification
$response->getErrorMessage();  // Error message
$response->getRawData();       // Raw data

Security

Webhook Validation

The bundle automatically validates webhook data:

// Required fields validated automatically
$requiredFields = ['pay_token', 'order_id', 'amount'];

Error Handling

All errors are encapsulated in OrangeMoneyException:

try {
    $paymentResponse = $orangeMoneyService->initiatePayment($paymentRequest);
} catch (OrangeMoneyException $e) {
    // Orange Money specific error
    $errorMessage = $e->getMessage();
    $errorData = $e->getData();
}

Logging

The bundle uses Symfony's logging system:

# config/packages/monolog.yaml
monolog:
    channels: ['orange_money']
    handlers:
        orange_money:
            type: rotating_file
            path: '%kernel.logs_dir%/orange_money.log'
            level: info
            channels: ['orange_money']

Advanced Configuration

Endpoint Customization for Development or Production Environment

# config/packages/orange_money.yaml
orange_money:
    api_base_url: 'https://api.orange.com'
    payment_endpoint: '/orange-money-webpay/dev/v1/webpayment'
    transaction_status_endpoint: '/orange-money-webpay/dev/v1/transactionstatus'

Complete Examples

Implementation examples are integrated directly into this documentation and include:

  • Complete payment controller
  • Callback handling
  • Transaction status verification
  • Webhook handling

Contributing

Contributions are welcome! Please:

  1. Fork the project
  2. Create a branch for your feature
  3. Commit your changes
  4. Push to the branch
  5. Open a Pull Request

License

This project is licensed under the MIT License. See the LICENSE file for more details.

Support

Changelog

v1.0.0

  • First stable version
  • Complete Orange Money API support
  • Webhook handling
  • Complete documentation

Developed with ❤️ by Abdoulaye CAMARA alias MrROOT