fereydooni/money-port

A comprehensive Laravel payment package with strategy pattern for multiple payment gateways

v1.0.0-beta.1 2025-08-09 11:30 UTC

This package is auto-updated.

Last update: 2025-09-09 13:18:22 UTC


README

A comprehensive Laravel payment package with strategy pattern for multiple payment gateways, specifically designed for Iranian payment systems.

✨ Features

  • 🔄 Strategy Pattern - Easy to switch between payment gateways
  • 🏦 10 Iranian Gateways - Support for all major Iranian payment providers
  • 🚀 Octane Compatible - Uses scoped bindings for better Octane performance
  • 🔧 Easy Configuration - Simple configuration file with environment variables
  • 🎯 Laravel Integration - Native Laravel service provider and facade
  • 📦 Package Ready - Easy to install and use in any Laravel project
  • 🛡️ Error Handling - Comprehensive error handling and logging
  • 🔒 Secure - Built-in security features and validation

🏦 Supported Payment Gateways

1. Zarinpal - زرین‌پال

  • Most popular Iranian payment gateway
  • Simple API integration
  • Supports sandbox mode

2. Mellat Bank - بانک ملت

  • Official bank gateway
  • SOAP-based API
  • Comprehensive transaction support

3. Parsian Bank - بانک پارسیان

  • PEP (Parsian Electronic Payment) system
  • XML-based API
  • High security standards

4. Saman Bank - بانک سامان

  • SEP (Saman Electronic Payment) system
  • RESTful API
  • Fast transaction processing

5. Pasargad Bank - بانک پاسارگاد

  • Advanced payment system
  • Digital signature support
  • Multi-currency support

6. IDPay - آیدی‌پی

  • Modern REST API
  • Comprehensive documentation
  • Sandbox environment

7. NextPay - نکست‌پی

  • Simple integration
  • Multiple payment methods
  • Developer-friendly API

8. Sepehr - سپهر

  • Shaparak electronic payment
  • Bank-independent
  • High reliability

9. Shaparak - شاپرک

  • Central Bank gateway
  • Standardized API
  • Multi-bank support

10. BehPardakht - به‌پرداخت

  • Comprehensive payment solutions
  • Advanced reporting
  • Multi-terminal support

📋 Requirements

  • PHP 8.1 or higher
  • Laravel 10.x or 11.x
  • Guzzle HTTP Client

Laravel Octane Compatibility

This package is fully compatible with Laravel Octane. It uses scoped() bindings instead of singleton() to ensure that:

  • Each request gets a fresh instance of the PaymentManager
  • No state pollution between requests
  • Better memory management in long-running processes
  • Optimal performance in Octane environments

🚀 Installation

  1. Install the package via Composer:
composer require fereydooni/money-port
  1. Publish the configuration file:
php artisan vendor:publish --provider="Fereydooni\MoneyPort\MoneyPortServiceProvider"
  1. Configure your environment variables:
# Default Gateway
MONEY_PORT_DEFAULT_GATEWAY=zarinpal

# Zarinpal Configuration
ZARINPAL_ENABLED=true
ZARINPAL_MERCHANT_ID=your_merchant_id
ZARINPAL_BASE_URL=https://www.zarinpal.com/pg
ZARINPAL_SANDBOX=false

# Mellat Configuration
MELLAT_ENABLED=false
MELLAT_TERMINAL_ID=your_terminal_id
MELLAT_USERNAME=your_username
MELLAT_PASSWORD=your_password

# Parsian Configuration
PARSIAN_ENABLED=false
PARSIAN_PIN=your_pin
PARSIAN_ORIGINATOR=your_originator

# Saman Configuration
SAMAN_ENABLED=false
SAMAN_TERMINAL_ID=your_terminal_id
SAMAN_SECRET_KEY=your_secret_key

# Pasargad Configuration
PASARGAD_ENABLED=false
PASARGAD_MERCHANT_CODE=your_merchant_code
PASARGAD_TERMINAL_CODE=your_terminal_code
PASARGAD_PRIVATE_KEY=your_private_key

# IDPay Configuration
IDPAY_ENABLED=false
IDPAY_API_KEY=your_api_key
IDPAY_MERCHANT_NAME=your_merchant_name
IDPAY_MERCHANT_PHONE=your_phone
IDPAY_MERCHANT_EMAIL=your_email

# NextPay Configuration
NEXTPAY_ENABLED=false
NEXTPAY_API_KEY=your_api_key
NEXTPAY_CUSTOMER_PHONE=your_phone

# Sepehr Configuration
SEPEHR_ENABLED=false
SEPEHR_TERMINAL_ID=your_terminal_id
SEPEHR_SECRET_KEY=your_secret_key

# Shaparak Configuration
SHAPARAK_ENABLED=false
SHAPARAK_MERCHANT_ID=your_merchant_id

# BehPardakht Configuration
BEHPARDAKHT_ENABLED=false
BEHPARDAKHT_USERNAME=your_username
BEHPARDAKHT_PASSWORD=your_password
BEHPARDAKHT_PAYER_ID=your_payer_id

# Logging Configuration
MONEY_PORT_LOGGING=true
MONEY_PORT_LOG_CHANNEL=payment
MONEY_PORT_LOG_LEVEL=info

# HTTP Configuration
MONEY_PORT_TIMEOUT=30
MONEY_PORT_RETRY_ATTEMPTS=3
MONEY_PORT_RETRY_DELAY=1000

📖 Basic Usage

Gateway Selection Behavior

The package now uses a smart gateway selection system:

  1. Default Gateway: Zarinpal is always the default and fallback gateway
  2. Current Gateway: When you specify a gateway in initialize(), it becomes the current gateway for subsequent operations
  3. Automatic Fallback: If no gateway is specified, the system uses the current gateway or falls back to Zarinpal

Using the Facade

use Fereydooni\MoneyPort\Facades\MoneyPort;

// Initialize payment with default gateway (Zarinpal)
$payment = MoneyPort::initialize([
    'amount' => 100000, // Amount in Rials
    'description' => 'Payment for order #123',
    'callback_url' => 'https://yoursite.com/payment/callback',
    'currency' => 'IRR'
]);

// Initialize payment with specific gateway
$payment = MoneyPort::initialize([
    'amount' => 100000,
    'description' => 'Payment for order #123',
    'callback_url' => 'https://yoursite.com/payment/callback',
    'currency' => 'IRR'
], 'mellat'); // This will set Mellat as current gateway for subsequent operations

// Verify payment (will use the current gateway set in initialize, or default if none specified)
$verification = MoneyPort::verify([
    'token' => 'payment_token_from_callback',
    'amount' => 100000,
    'transaction_id' => 'order_123'
]);

// Or specify a different gateway for verification
$verification = MoneyPort::verify([
    'token' => 'payment_token_from_callback',
    'amount' => 100000,
    'transaction_id' => 'order_123'
], 'mellat');

// Get available gateways
$gateways = MoneyPort::getAvailableGateways();

Using the Service Class

use Fereydooni\MoneyPort\Services\PaymentManager;

class PaymentController extends Controller
{
    public function __construct(
        private PaymentManager $paymentManager
    ) {}

    public function processPayment(Request $request)
    {
        $payment = $this->paymentManager->initialize([
            'amount' => $request->amount,
            'description' => $request->description,
            'callback_url' => route('payment.callback'),
            'currency' => 'IRR'
        ], 'zarinpal');

        return redirect($payment['payment_url']);
    }

    public function verifyPayment(Request $request)
    {
        $verification = $this->paymentManager->verify([
            'token' => $request->token,
            'amount' => $request->amount,
            'transaction_id' => $request->transaction_id
        ], 'zarinpal');

        if ($verification['success']) {
            // Payment successful
            return response()->json(['message' => 'Payment verified']);
        }

        return response()->json(['error' => 'Payment verification failed'], 400);
    }
}

🔧 Adding New Gateways

To add a new payment gateway:

  1. Create a new gateway class:
<?php

namespace App\Gateways;

use Fereydooni\MoneyPort\Abstracts\AbstractPaymentGateway;
use Fereydooni\MoneyPort\Contracts\PaymentDataInterface;

class CustomGateway extends AbstractPaymentGateway
{
    protected function validateConfig(): void
    {
        // Validate required configuration
    }

    public function initialize(array $data): array
    {
        // Initialize payment logic
    }

    public function verify(array $data): array
    {
        // Verify payment logic
    }

    public function refund(array $data): array
    {
        // Refund logic
    }

    public function getStatus(string $transactionId): array
    {
        // Get status logic
    }

    public function getGatewayName(): string
    {
        return 'custom';
    }
}
  1. Add the gateway to the enum:
// In src/Enums/Gateway.php
case CUSTOM = 'custom';

public function getDisplayName(): string
{
    return match($this) {
        // ... existing cases
        self::CUSTOM => 'Custom Gateway',
    };
}
  1. Register the gateway in PaymentManager:
// In src/Services/PaymentManager.php
if (($config['custom']['enabled'] ?? false)) {
    $this->registerGateway(Gateway::CUSTOM, new CustomGateway($config['custom'] ?? []));
}
  1. Add configuration:
// In config/money-port.php
'custom' => [
    'enabled' => env('CUSTOM_ENABLED', false),
    // ... other configuration
],
  1. Register the gateway:
use App\Gateways\CustomGateway;

// In your service provider or controller
MoneyPort::registerGateway('custom', new CustomGateway());

⚙️ Configuration

The package configuration file (config/money-port.php) contains:

  • Default Gateway: Zarinpal is the default gateway (hardcoded)
  • Gateway Configurations: Individual settings for each gateway with enabled/disabled flags
  • Logging Options: Configure payment operation logging
  • HTTP Settings: Timeout, retry attempts, and delay configuration

Gateway Management

Each gateway has an enabled flag that controls whether it's registered and available:

# Enable/disable gateways
ZARINPAL_ENABLED=true      # Default: true (always enabled)
MELLAT_ENABLED=false       # Default: false
PARSIAN_ENABLED=false      # Default: false
# ... other gateways default to false

Only enabled gateways will be registered and available for use. This prevents unnecessary gateway instantiation and improves performance.

🚨 Error Handling

The package includes comprehensive error handling:

use Fereydooni\MoneyPort\Exceptions\PaymentException;

try {
    $payment = MoneyPort::initialize($data);
} catch (PaymentException $e) {
    // Handle payment-specific errors
    Log::error('Payment failed: ' . $e->getMessage());
} catch (Exception $e) {
    // Handle general errors
    Log::error('Unexpected error: ' . $e->getMessage());
}

📝 Logging

Enable logging to track payment operations:

// Logs are automatically created for all payment operations
// Configure in config/money-port.php
'logging' => [
    'enabled' => true,
    'channel' => 'payment',
    'level' => 'info',
],

🧪 Testing

Run the package tests:

composer test

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This package is open-sourced software licensed under the MIT license.

🆘 Support

If you encounter any issues or have questions:

  • Create an issue on GitHub
  • Check the documentation
  • Review the configuration examples

📈 Changelog

v1.1.0

  • Added Gateway enum for type-safe gateway management
  • Implemented smart gateway selection system
  • Added enabled/disabled flags for each gateway
  • Only Zarinpal is enabled by default, others must be explicitly enabled
  • Improved gateway state management with current gateway tracking
  • Better performance by only registering enabled gateways

v1.0.0

  • Initial release with 10 Iranian payment gateways
  • Strategy pattern implementation
  • Laravel Octane compatibility
  • Comprehensive error handling and logging
  • Easy configuration management