Iranian Payment Gateways
This library is inspired by laravel Socialite and PoolPort and larabook/gateway
Available PSPs (Bank):
- Beh Pardakht (
MELLAT
) - SEP (
SAMAN
) - SADAD (
MELLI
) - PEC (
PARSIAN
) - PEP (
PASARGAD
) - Novin Pardakht (
EN Bank
, also known asEghtesad Novin Bank
) - IranKish
- Sepehr
- Asan Pardakht
- Fanava Card
Available 3rd-parties:
- Vandar
- Pay.ir
- ZarinPal
- Zibal
- JibIt
- PayPing
- IDPay
- Jibimo
- NextPay
- DigiPay
- SizPay
- Shepa
- AqayePardakht
- IranDargah
- Bahamta
- ParsPal
- BitPay
- Milyoona
- Sepal
- TiPoul
- SabaPay
- YekPay
composer require parsisolution/gateway
php artisan vendor:publish --provider="Parsisolution\Gateway\GatewayServiceProvider"
php artisan migrate
Change .env
values or config/gateways.php
fields to your specifications.
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' => '',
]);
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' => 'ali@gmail.com',
'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();
}
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');
}
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');