fiachehr/laravel-pardakht

Professional Laravel payment gateway package for Iranian payment providers with SOLID principles and clean architecture

Installs: 11

Dependents: 0

Suggesters: 0

Security: 0

Stars: 1

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/fiachehr/laravel-pardakht

1.0.6 2025-12-20 13:10 UTC

This package is auto-updated.

Last update: 2025-12-20 13:12:32 UTC


README

Latest Version Total Downloads License Tests

Professional Laravel payment gateway package for Iranian payment providers with full SOLID principles and Clean Architecture.

Table of Contents

Supported Gateways

  • โœ… Bank Mellat (Bank-e Mellat) - SOAP
  • โœ… Mabna Card (Sepehr) - REST API
  • โœ… ZarinPal - REST API

Key Features

Architecture & Design

  • ๐Ÿ—๏ธ SOLID Principles - Full adherence to SOLID principles
  • ๐ŸŽจ Clean Architecture - Clean and maintainable architecture
  • ๐ŸŽฏ Design Patterns - Repository, Factory, Facade patterns
  • ๐Ÿงฉ Contract-Based - Interface-driven programming

Capabilities

  • ๐Ÿ“ฆ Auto Storage - Automatic transaction storage in database
  • ๐Ÿ”„ Easy Switching - Switch between gateways easily
  • ๐Ÿ›ก๏ธ Error Handling - Professional exception handling
  • โœจ Value Objects - Type-safe value objects
  • ๐Ÿงช Test Coverage - Comprehensive unit and feature tests
  • ๐Ÿ”Œ Extensible - Easy to add custom gateways
  • ๐ŸŒ Sandbox Support - Full sandbox/test environment support

Developer Experience

  • ๐Ÿ“ Full Documentation - Comprehensive docs with examples
  • ๐ŸŽ“ Educational - Self-documented, readable code
  • ๐Ÿ”ง Simple Config - Easy configuration via .env

Requirements

  • PHP 8.1 or higher
  • Laravel 10.x or 11.x
  • PHP SOAP extension (for Mellat gateway)
  • PHP JSON extension

Installation

1. Install via Composer

composer require fiachehr/laravel-pardakht

2. Publish Assets

# Publish all (config + migrations)
php artisan vendor:publish --provider="Fiachehr\Pardakht\PardakhtServiceProvider"

Or separately:

# Config only
php artisan vendor:publish --tag=pardakht-config

# Migrations only
php artisan vendor:publish --tag=pardakht-migrations

3. Run Migrations

php artisan migrate

This creates the pardakht_transactions table for storing transactions.

Configuration

Environment Variables

Add to your .env file:

# Default gateway
PARDAKHT_DEFAULT_GATEWAY=mellat

# ========================================
# Bank Mellat (Production)
# ========================================
MELLAT_TERMINAL_ID=your_terminal_id
MELLAT_USERNAME=your_username
MELLAT_PASSWORD=your_password
MELLAT_CALLBACK_URL=https://yoursite.com/payment/callback
MELLAT_SANDBOX=false

# ========================================
# Mabna Card / Sepehr (Production)
# ========================================
MABNA_TERMINAL_ID=your_terminal_id
MABNA_CALLBACK_URL=https://yoursite.com/payment/callback
MABNA_SANDBOX=false

# ========================================
# ZarinPal (Production)
# ========================================
ZARINPAL_MERCHANT_ID=your_merchant_id
ZARINPAL_CALLBACK_URL=https://yoursite.com/payment/callback
ZARINPAL_SANDBOX=false
ZARINPAL_DESCRIPTION="Payment via ZarinPal"

Sandbox Mode (Testing)

For development and testing, enable sandbox mode:

# Bank Mellat - Test Mode
MELLAT_SANDBOX=true
MELLAT_TERMINAL_ID=test_terminal_id
MELLAT_USERNAME=test_username
MELLAT_PASSWORD=test_password

# Mabna - Test Mode
MABNA_SANDBOX=true
MABNA_TERMINAL_ID=test_terminal_id

# ZarinPal - Test Mode
ZARINPAL_SANDBOX=true
ZARINPAL_MERCHANT_ID=test_merchant_id

Get Test Credentials:

Advanced Configuration

The config/pardakht.php file:

return [
    // Default gateway
    'default' => env('PARDAKHT_DEFAULT_GATEWAY', 'mellat'),
    
    // Auto-store transactions
    'store_transactions' => true,
    
    // Gateway configurations
    'gateways' => [
        'mellat' => [
            'driver' => 'mellat',
            'terminal_id' => env('MELLAT_TERMINAL_ID'),
            'username' => env('MELLAT_USERNAME'),
            'password' => env('MELLAT_PASSWORD'),
            'callback_url' => env('MELLAT_CALLBACK_URL'),
            'sandbox' => env('MELLAT_SANDBOX', false),
        ],
        // ...
    ],
];

Usage

1. Create Payment Request

use Fiachehr\Pardakht\Facades\Pardakht;
use Fiachehr\Pardakht\ValueObjects\PaymentRequest;

public function payment()
{
    // Create payment request
    $paymentRequest = new PaymentRequest(
        amount: 100000,              // Amount in Rials
        orderId: 'ORDER-12345',      // Order ID
        callbackUrl: route('payment.callback'),
        description: 'Order payment #12345',
        mobile: '09123456789',       // Optional
        email: 'user@example.com',   // Optional
        metadata: [                  // Optional
            'user_id' => auth()->id(),
            'product_id' => 5
        ]
    );

    try {
        // Send request to default gateway
        $response = Pardakht::request($paymentRequest);
        
        // Or use specific gateway
        // $response = Pardakht::request($paymentRequest, 'zarinpal');
        
        if ($response->isSuccessful()) {
            // Store tracking code in session
            session(['payment_tracking_code' => $response->trackingCode]);
            
            // Redirect user to payment gateway
            return redirect($response->getPaymentUrl());
        }
        
    } catch (\Fiachehr\Pardakht\Exceptions\GatewayException $e) {
        // Handle error
        \Log::error('Payment request failed', [
            'gateway' => $e->getGatewayName(),
            'message' => $e->getMessage(),
            'code' => $e->getGatewayCode()
        ]);
        
        return back()->with('error', 'Payment request failed: ' . $e->getMessage());
    }
}

2. Verify Payment (Callback)

use Fiachehr\Pardakht\Facades\Pardakht;
use Fiachehr\Pardakht\ValueObjects\VerificationRequest;
use Illuminate\Http\Request;

public function callback(Request $request)
{
    // Get tracking code from session
    $trackingCode = session('payment_tracking_code');
    
    if (!$trackingCode) {
        return redirect()->route('payment.failed')
            ->with('error', 'Payment information not found');
    }
    
    // Create verification request
    $verificationRequest = new VerificationRequest(
        trackingCode: $trackingCode,
        gatewayData: $request->all() // All data returned from gateway
    );
    
    try {
        // Verify payment
        $response = Pardakht::verify($verificationRequest);
        
        // Or specify gateway
        // $response = Pardakht::verify($verificationRequest, 'mellat');
        
        if ($response->isSuccessful()) {
            // Payment successful - perform required operations
            
            // Example: Update order status
            $order = Order::where('id', $orderId)->first();
            $order->update([
                'status' => 'paid',
                'payment_reference' => $response->referenceId,
                'paid_at' => now()
            ]);
            
            // Clear session
            session()->forget('payment_tracking_code');
            
            return view('payment.success', [
                'referenceId' => $response->referenceId,
                'cardNumber' => $response->getMaskedCardNumber(),
                'amount' => $response->amount,
                'transactionId' => $response->transactionId,
            ]);
        }
        
    } catch (\Fiachehr\Pardakht\Exceptions\GatewayException $e) {
        \Log::error('Payment verification failed', [
            'gateway' => $e->getGatewayName(),
            'message' => $e->getMessage(),
            'code' => $e->getGatewayCode()
        ]);
        
        return view('payment.failed', [
            'message' => $e->getMessage(),
            'code' => $e->getGatewayCode(),
        ]);
    }
}

3. Advanced Usage

Working with Multiple Gateways

// Get list of available gateways
$gateways = Pardakht::available();
// ['mellat', 'mabna', 'zarinpal']

// Get specific gateway instance
$mellatGateway = Pardakht::gateway('mellat');
$zarinpalGateway = Pardakht::gateway('zarinpal');

// Use gateway directly
$response = $mellatGateway->request($paymentRequest);

Working with Transactions via Repository

use Fiachehr\Pardakht\Contracts\TransactionRepositoryInterface;

class PaymentController extends Controller
{
    public function __construct(
        protected TransactionRepositoryInterface $transactionRepository
    ) {}
    
    public function history()
    {
        // Get successful transactions
        $successful = $this->transactionRepository->getSuccessful();
        
        // Get failed transactions
        $failed = $this->transactionRepository->getFailed();
        
        // Find by tracking code
        $transaction = $this->transactionRepository->findByTrackingCode($trackingCode);
        
        // Find by order ID
        $transaction = $this->transactionRepository->findByOrderId($orderId);
    }
}

Using Transaction Model

use Fiachehr\Pardakht\Models\Transaction;

// Get successful transactions for specific gateway
$transactions = Transaction::gateway('mellat')
    ->successful()
    ->latest()
    ->get();

// Get pending transactions
$pending = Transaction::pending()->get();

// Filter by date
$transactions = Transaction::whereDate('created_at', today())
    ->successful()
    ->get();

// Check transaction status
$transaction = Transaction::find(1);
if ($transaction->isSuccessful()) {
    // Transaction was successful
}

Adding Custom Gateway

use Fiachehr\Pardakht\Facades\Pardakht;
use Fiachehr\Pardakht\Gateways\AbstractGateway;

class CustomGateway extends AbstractGateway
{
    public function getName(): string
    {
        return 'custom';
    }
    
    public function request(PaymentRequest $request): PaymentResponse
    {
        // Implement payment request
    }
    
    public function verify(VerificationRequest $request): VerificationResponse
    {
        // Implement payment verification
    }
    
    protected function validateConfig(): void
    {
        // Validate configuration
    }
}

// Register custom gateway
Pardakht::extend('custom', CustomGateway::class);

Testing

Running Tests

# Run all tests
composer test

# Run with coverage
composer test-coverage

# Run only unit tests
vendor/bin/phpunit --testsuite=Unit

# Run only feature tests
vendor/bin/phpunit --testsuite=Feature

Available Tests

  • โœ… Value Objects Tests
  • โœ… Gateway Manager Tests
  • โœ… Transaction Model Tests
  • โœ… Exception Handling Tests
  • โœ… Facade Tests
  • โœ… Repository Tests

Security

Reporting Security Vulnerabilities

If you discover a security vulnerability, please email fiachehr@example.com.

Best Practices

  • โœ… Always store credentials in .env
  • โœ… Never commit credentials
  • โœ… Always use SSL in production
  • โœ… Ensure SANDBOX=false in production
  • โœ… Review payment logs regularly

Contributing

Contributions are welcome! Please:

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

Contribution Guidelines

  • Code must follow PSR-12
  • Add necessary tests
  • Update documentation
  • Record changes in CHANGELOG.md

Changelog

See CHANGELOG.md for full changelog.

License

This package is open-sourced software licensed under the MIT license. See LICENSE for details.

Author

Fiachehr

Acknowledgments

  • Laravel community
  • Payment gateway developers
  • All contributors

Useful Links

FAQ

How do I switch between gateways?

// Method 1: Change default gateway in .env
PARDAKHT_DEFAULT_GATEWAY=zarinpal

// Method 2: Specify gateway at runtime
Pardakht::request($paymentRequest, 'zarinpal');

How do I disable transaction storage?

// In config/pardakht.php
'store_transactions' => false,

How do I handle errors?

try {
    $response = Pardakht::request($paymentRequest);
} catch (\Fiachehr\Pardakht\Exceptions\GatewayException $e) {
    // Gateway error
    $e->getMessage();
    $e->getGatewayName();
    $e->getGatewayCode();
} catch (\Exception $e) {
    // General error
}

If you find this package useful, give it a โญ๏ธ!

Made by Fiachehr with โค๏ธ for Laravel