mrroot/orange-money-bundle
最新稳定版本:v1.1.0
Composer 安装命令:
composer require mrroot/orange-money-bundle
包简介
Symfony bundle for Orange Money payment integration with complete webhook, callback and error handling support
README 文档
README
Symfony bundle for Orange Money payment integration with complete webhook support, callbacks, and advanced error handling.
Features
- Orange Money payment initiation with comprehensive validation
- Transaction status verification with enhanced parameters
- Advanced webhook and notification handling with token validation
- Robust error handling with detailed logging
- Flexible configuration via environment variables
- OAuth2 support for secure API authentication
- Symfony compatibility 5.4, 6.x and 7.x
- Automatic data validation and sanitization
- Configurable callback URLs with security features
- Webhook spoofing protection via notification token validation
- Enhanced payment response handling with comprehensive data access
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 mrroot/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
Complete Controller Example
For a complete and detailed implementation example, see: Controller Example
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); // IMPORTANT: Save these values for webhook validation // - $paymentResponse->getPayToken() (payToken) // - $paymentRequest->getOrderId() (orderId) // - $paymentResponse->getNotifToken() (notifToken) return new JsonResponse([ 'success' => true, 'payment_url' => $paymentResponse->getPaymentUrl(), 'pay_token' => $paymentResponse->getPayToken(), 'notif_token' => $paymentResponse->getNotifToken(), '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, string $orderId, float $amount, OrangeMoneyService $orangeMoneyService ): JsonResponse { try { // Enhanced status check with required parameters $response = $orangeMoneyService->checkTransactionStatus($payToken, $orderId, $amount); return new JsonResponse([ 'pay_token' => $payToken, 'order_id' => $response->getOrderId(), 'status' => $response->getStatus(), 'amount' => $response->getAmount(), 'currency' => $response->getCurrency(), 'txn_id' => $response->getTxnId() ]); } catch (\Exception $e) { return new JsonResponse([ 'error' => $e->getMessage() ], 400); } }
Webhook Handling with Security Validation
#[Route('/payment/webhook', name: 'payment_webhook', methods: ['POST'])] public function handleWebhook( Request $request, OrangeMoneyService $orangeMoneyService ): JsonResponse { try { // Retrieve stored values from your database/session // These values should have been saved during payment initiation: $payToken = "your-stored-pay-token"; // Get from database $orderId = "your-stored-order-id"; // Get from database $notifToken = "your-stored-notif-token"; // Get from database $amount = 50.0; // Get from database // Optional: Check transaction status separately if needed // $checkResponse = $orangeMoneyService->checkTransactionStatus( // $payToken, // $orderId, // $amount // ); $webhookData = json_decode($request->getContent(), true); // Automatic notif_token verification $paymentStatus = $orangeMoneyService->processNotification($webhookData, $notifToken); // Your business logic here if ($paymentStatus->getStatus() === 'SUCCESS') { // Confirm order $this->confirmOrder($paymentStatus->getOrderId()); } return new JsonResponse([ 'status' => 'success', 'message' => 'Notification processed', 'txn_id' => $paymentStatus->getTxnId() ]); } catch (\Exception $e) { return new JsonResponse([ 'status' => 'error', 'message' => $e->getMessage() ], 500); } private function getStoredNotifToken(?string $orderId): ?string { // Retrieve the notification token stored during payment initiation // This could be from database, cache, session, etc. return $orderId ? $this->paymentRepository->getNotifTokenByOrderId($orderId) : null; } private function confirmOrder(string $orderId): void { // Your order confirmation logic } }
Transaction Status Verification (Optional)
public function checkStatus(OrangeMoneyService $orangeMoneyService): JsonResponse { try { // Use values saved during payment initiation $response = $orangeMoneyService->checkTransactionStatus( 'pay-token-from-initiation', // Saved payment token 'ORDER-123', // Saved order ID 10000 // Saved amount ); return new JsonResponse([ 'status' => $response->getStatus(), 'transaction_id' => $response->getTxnId(), 'order_id' => $response->getOrderId() ]); } catch (OrangeMoneyException $e) { return new JsonResponse([ 'error' => $e->getMessage() ], 400); } }
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->getNotifToken(); // Notification token (for webhook validation) $response->getTxnId(); // Transaction ID $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->getErrorCode(); // Error code $response->hasPaymentUrl(); // Payment URL validation $response->getRawData(); // Raw data
Security
Enhanced Webhook Validation
The bundle provides comprehensive webhook security:
// Required fields validated automatically $requiredFields = ['status', 'notif_token', 'txnid']; // Process notification with token validation $paymentStatus = $orangeMoneyService->processNotification($data, $expectedNotifToken);
Webhook Spoofing Protection
To prevent webhook spoofing attacks:
- Store the notification token during payment initiation:
$paymentResponse = $orangeMoneyService->initiatePayment($paymentRequest); $notifToken = $paymentResponse->getNotifToken(); // Store this token securely (database, cache, etc.) $this->storeNotifToken($paymentRequest->getOrderId(), $notifToken);
- Validate the token in webhook processing:
$expectedToken = $this->getStoredNotifToken($orderId); $paymentStatus = $orangeMoneyService->processNotification($webhookData, $expectedToken);
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:
- Fork the project
- Create a branch for your feature
- Commit your changes
- Push to the branch
- Open a Pull Request
License
This project is licensed under the MIT License. See the LICENSE file for more details.
Support
- Issues: GitHub Issues
- Email: camaraabdoulayeroo@mail.com
Changelog
v1.1.0
- Enhanced webhook security with notification token validation
- Improved transaction status checking with required parameters (payToken, orderId, amount)
- Extended PaymentResponse model with notifToken and txnId properties
- Code quality improvements and consistency fixes
- Better error handling and validation
- Webhook spoofing protection implementation
v1.0.0
- First stable version
- Complete Orange Money API support
- Webhook handling
- Complete documentation
Developed with ❤️ by Abdoulaye CAMARA alias MrROOT
统计信息
- 总下载量: 16
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 1
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-09-02