Skip to content

parsisolution/gateway

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

85 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Parsisolution Gateway

Iranian Payment Gateways

This library is inspired by laravel Socialite and PoolPort and larabook/gateway

Available PSPs (Bank):

  1. Beh Pardakht (MELLAT)
  2. SEP (SAMAN)
  3. SADAD (MELLI)
  4. PEC (PARSIAN)
  5. PEP (PASARGAD)
  6. Novin Pardakht (EN Bank, also known as Eghtesad Novin Bank)
  7. IranKish
  8. Sepehr
  9. Asan Pardakht
  10. Fanava Card

Available 3rd-parties:

  1. Vandar
  2. Pay.ir
  3. ZarinPal
  4. Zibal
  5. JibIt
  6. PayPing
  7. IDPay
  8. Jibimo
  9. NextPay
  10. DigiPay
  11. SizPay
  12. Shepa
  13. AqayePardakht
  14. IranDargah
  15. Bahamta
  16. ParsPal
  17. BitPay
  18. Milyoona
  19. Sepal
  20. TiPoul
  21. SabaPay
  22. YekPay

Install

Step 1:

composer require parsisolution/gateway

Step 2:

php artisan vendor:publish --provider="Parsisolution\Gateway\GatewayServiceProvider"

Step 3:

php artisan migrate

Step 4:

Change .env values or config/gateways.php fields to your specifications.

Usage

Step 1:

Get instance of Gateway from Gateway Facade Gateway::of('mellat') Or create one yourself: new Mellat(app(), config('gateways.mellat')); Or

$gateway = Gateway::of('mellat');

$gateway = new Mellat(app(), config('gateways.mellat'));

$gateway = new Mellat(app(), [
    'username'    => '',
    'password'    => '',
    'terminal-id' => '',
]);

Step2:

Then to create new payment transaction you can do like this:

try {
    $gateway = Gateway::of('PayIR'); // $gateway = new Payir(app(), config('gateways.payir')); 
    $gateway->callbackUrl(route('callback')); // You can change the callback
    
    // You can make it stateless.
    // in default mode it uses session to store and retrieve transaction id 
    // (and other gateway specific or user provided (using $gateway->with) required parameters)
    // but in stateless mode it gets transaction id and other required parameters from callback url
    // Caution: you should use same stateless value in callback too
    $gateway->stateless();
    
    // You can get supported extra fields sample for each gateway and then set these fields with your desired values
    // (most gateways support `mobile` field)
    $supportedExtraFieldsSample = $gateway->getSupportedExtraFieldsSample();
    
    return compact('supportedExtraFieldsSample');

    // Then you should create a transaction to be processed by the gateway
    // Amount is in `Toman` by default, but you can set the currency in second argument as well. IRR (for `Riyal`)
    $transaction = new RequestTransaction(new Amount(12000)); // 12000 Toman
    $transaction->setExtra([
        'mobile' => '09124441122',
        'email'  => '[email protected]',
        'person' => 12345,
    ]);
    $transaction->setExtraField('description', 'توضیحات من');
    
    // if you added additional fields in your migration you can assign a value to it in the beginning like this
    $transaction['person_id'] = auth()->user()->id;
    
    $authorizedTransaction = $gateway->authorize($transaction);

    $transactionId = $authorizedTransaction->getId(); // شماره‌ی تراکنش در جدول پایگاه‌داده
    $orderId = $authorizedTransaction->getOrderId(); // شماره‌ی تراکنش اعلامی به درگاه
    $referenceId = $authorizedTransaction->getReferenceId(); // شناسه‌ی تراکنش در درگاه (در صورت وجود)
    $token = $authorizedTransaction->getToken(); // توکن درگاه (در صورت وجود)

    // در اینجا
    // شماره تراکنش(ها) را با توجه به نوع ساختار پایگاه‌داده‌ی خود 
    // در جداول مورد نیاز و بسته به نیاز سیستم‌تان ذخیره کنید.

    // this object tells us how to redirect to gateway
    $redirectResponse = $authorizedTransaction->getRedirect();

    // if you're developing an Api just return it and handle redirect in your frontend
    // (this gives you redirect method [get or post], url and fields)
    // (you can use a code like `redirector.blade.php`)
    return $redirectResponse;

    // otherwise use this solution to redirect user to gateway with proper response
    return $redirectResponse->redirect(app());

} catch (\Exception $e) {

    echo $e->getMessage();
}

Step3:

And in callback

$all = $request->all();

try {

    // first argument defines stateless/stateful state (true for stateless / default is false (stateful))
    // if you want to update fields that you added in migration on successful transaction
    // you can pass them in second argument as associative array
    $settledTransaction = Gateway::settle(true, ['person_id' => 333, 'invoice_id' => 5233]);

    $id = $settledTransaction->getId();
    $orderId = $settledTransaction->getOrderId();
    $amount = strval($settledTransaction->getAmount());
    $extra = $settledTransaction->getExtra();
    $person = $settledTransaction->getExtraField('person');
    $referenceId = $settledTransaction->getReferenceId();
    $traceNumber = $settledTransaction->getTraceNumber();
    $cardNumber = $settledTransaction->getCardNumber();
    $RRN = $settledTransaction->getRRN();
    $person_id = $settledTransaction['person_id'];
    $attributes = $settledTransaction->getAttributes();
    
    // تراکنش با موفقیت سمت درگاه تایید گردید
    // در این مرحله عملیات خرید کاربر را تکمیل میکنیم

    return compact('all', 'id', 'orderId', 'amount', 'extra', 'person', 'referenceId',
        'traceNumber', 'cardNumber', 'RRN', 'person_id', 'attributes');
        
} catch (\Parsisolution\Gateway\Exceptions\GeneralTransactionException $e) {
    $code = $e->getCode();
    $message = $e->getMessage();
    /** @var AuthorizedTransaction $transaction */
    $transaction = $e->getTransaction();
    $attributes = $transaction->getAttributes();
    $throwable = $e->getPrevious();
    $previous_class = get_class($throwable);
    $previous_trace = $throwable->getTrace();

    // تراکنش با خطا مواجه شده است

    return compact('previous_class', 'code', 'message', 'attributes', 'previous_trace');
    
} catch (\Parsisolution\Gateway\Exceptions\RetryException $e) {
    $class = get_class($e);
    $code = $e->getCode();
    $message = $e->getMessage();
    /** @var AuthorizedTransaction $transaction */
    $transaction = $e->getTransaction();
    $attributes = $transaction->getAttributes();
    $trace = $e->getTrace();
    
    // تراکنش قبلا سمت درگاه تاییده شده است و
    // کاربر احتمالا صفحه را مجددا رفرش کرده است
    // لذا تنها فاکتور خرید قبل را مجدد به کاربر نمایش میدهیم

    return compact('class', 'code', 'message', 'attributes', 'trace');
    
} catch (\Parsisolution\Gateway\Exceptions\TransactionException|\Parsisolution\Gateway\Exceptions\InvalidRequestException $e) {
    $class = get_class($e);
    $code = $e->getCode();
    $message = $e->getMessage();
    /** @var AuthorizedTransaction $transaction */
    $transaction = $e->getTransaction();
    $attributes = $transaction->getAttributes();
    $trace = $e->getTrace();

    // تراکنش با خطا مواجه شده است

    return compact('class', 'code', 'message', 'attributes', 'trace');
    
} catch (\Exception $e) {
    $class = get_class($e);
    $code = $e->getCode();
    $message = $e->getMessage();
    $trace = $e->getTrace();

    // تراکنش با خطا مواجه شده است

    return compact('class', 'code', 'message', 'trace');
}

Appendix 1:

You can easily add your own gateway with no effort in your own code base by extending \Parsisolution\Gateway\AbstractProvider class and then add snippet code below to your controller's constructor

public function __construct()
{
    $createIDPay = function () {
        return new IDPay(app(), config('gateways.idpay2'));
    };
    Gateway::extend('idpay2', $createIDPay);
    // below number (60) should match the return value of gateway's `getProviderId` method
    Gateway::extend(60, $createIDPay);
}

after that you can use added gateway in controller's methods like other gateways:

$gateway = Gateway::of('idpay2');