parsisolution/gateway

A Laravel 包,用于连接所有伊朗支付网关


README

伊朗支付网关

这个库受到 laravel SocialitePoolPort 以及 larabook/gateway 的启发

可用的 PSPs(银行)

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

可用的第三方服务

  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

安装

步骤 1

composer require parsisolution/gateway

步骤 2

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

步骤 3

php artisan migrate

步骤 4

更改 .env 中的值或 config/gateways.php 字段以符合您的需求。

用法

步骤 1

从 Gateway Facade 获取 Gateway 实例 Gateway::of('mellat') 或自行创建: new Mellat(app(), config('gateways.mellat'));

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

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

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

步骤2

然后创建新的支付交易,可以这样做

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();
}

步骤3

在回调中

$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');
}

附录 1

您可以通过扩展 \Parsisolution\Gateway\AbstractProvider 类并在控制器构造函数中添加以下代码片段,轻松地在自己的代码库中添加自己的网关,无需额外努力。

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);
}

之后,您可以在控制器方法中使用添加的网关,就像使用其他网关一样。

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