├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── config └── gateways.php ├── migrations └── 2018_11_14_193213_create_gateway_transactions_table.php ├── pint.json ├── src ├── AbstractProvider.php ├── ApiType.php ├── Contracts │ ├── Comparable.php │ ├── Factory.php │ ├── HasId.php │ ├── Provider.php │ └── Transaction.php ├── Curl.php ├── Exceptions │ ├── GatewayException.php │ ├── GeneralTransactionException.php │ ├── InvalidRequestException.php │ ├── InvalidStateException.php │ ├── NotFoundTransactionException.php │ ├── NullConfigException.php │ ├── ProviderNotFoundException.php │ ├── RetryException.php │ ├── TransactionException.php │ └── UncomparableException.php ├── Facades │ └── Gateway.php ├── GatewayManager.php ├── GatewayServiceProvider.php ├── Providers │ ├── AqayePardakht │ │ ├── AqayePardakht.php │ │ └── AqayePardakhtException.php │ ├── AsanPardakht │ │ ├── AsanPardakht.php │ │ ├── AsanPardakhtException.php │ │ ├── AsanPardakhtRestException.php │ │ └── AsanPardakhtRestTokenException.php │ ├── Bahamta │ │ ├── Bahamta.php │ │ └── BahamtaException.php │ ├── BitPay │ │ ├── BitPay.php │ │ └── BitPayException.php │ ├── DigiPay │ │ ├── DigiPay.php │ │ ├── DigiPayException.php │ │ └── DigiPayGateway.php │ ├── Fanava │ │ ├── Fanava.php │ │ └── FanavaException.php │ ├── IDPay │ │ ├── IDPay.php │ │ └── IDPayException.php │ ├── IranDargah │ │ ├── IranDargah.php │ │ └── IranDargahException.php │ ├── Irankish │ │ ├── Irankish.php │ │ └── IrankishException.php │ ├── JiBit │ │ ├── JiBit.php │ │ └── JiBitException.php │ ├── Jibimo │ │ ├── Jibimo.php │ │ └── JibimoException.php │ ├── Mellat │ │ ├── Mellat.php │ │ └── MellatException.php │ ├── Milyoona │ │ ├── Milyoona.php │ │ └── MilyoonaException.php │ ├── NextPay │ │ ├── NextPay.php │ │ └── NextPayException.php │ ├── Novin │ │ ├── Novin.php │ │ └── NovinException.php │ ├── ParsPal │ │ ├── ParsPal.php │ │ └── ParsPalException.php │ ├── Parsian │ │ ├── Parsian.php │ │ └── ParsianException.php │ ├── Pasargad │ │ ├── Pasargad.php │ │ ├── PasargadException.php │ │ └── Utilities │ │ │ ├── RSA.php │ │ │ ├── RSAProcessor.php │ │ │ └── XMLGenerator.php │ ├── PayPing │ │ ├── PayPing.php │ │ └── PayPingException.php │ ├── Payir │ │ ├── Payir.php │ │ └── PayirException.php │ ├── SabaPay │ │ ├── SabaPay.php │ │ └── SabaPayException.php │ ├── Sadad │ │ ├── Sadad.php │ │ └── SadadException.php │ ├── Saman │ │ ├── Saman.php │ │ └── SamanException.php │ ├── Sepal │ │ ├── Sepal.php │ │ └── SepalException.php │ ├── Sepehr │ │ ├── Sepehr.php │ │ └── SepehrException.php │ ├── Shepa │ │ ├── Shepa.php │ │ └── ShepaException.php │ ├── Sizpay │ │ ├── Sizpay.php │ │ └── SizpayException.php │ ├── TiPoul │ │ ├── TiPoul.php │ │ └── TiPoulException.php │ ├── Vandar │ │ ├── Vandar.php │ │ └── VandarException.php │ ├── YekPay │ │ ├── YekPay.php │ │ └── YekPayException.php │ ├── Zarinpal │ │ ├── Zarinpal.php │ │ └── ZarinpalException.php │ └── Zibal │ │ ├── Zibal.php │ │ └── ZibalException.php ├── RedirectResponse.php ├── SoapClient.php ├── Traits │ ├── HasIdField.php │ ├── HasOrderIdField.php │ └── HasTransaction.php ├── TransactionDao.php └── Transactions │ ├── AbstractTransaction.php │ ├── Amount.php │ ├── AuthorizedTransaction.php │ ├── FieldsToMatch.php │ ├── RequestTransaction.php │ ├── SettledTransaction.php │ └── UnAuthorizedTransaction.php └── views └── redirector.blade.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /.idea/ 3 | composer.phar 4 | composer.lock 5 | phpunit.xml 6 | .DS_Store 7 | Thumbs.db 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Parsisolution 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "parsisolution/gateway", 3 | "description": "A Laravel package for connecting to all Iraninan payment gateways", 4 | "license": "MIT", 5 | "homepage": "https://github.com/parsisolution/gateway", 6 | "support": { 7 | "issues": "https://github.com/parsisolution/gateway/issues", 8 | "source": "https://github.com/parsisolution/gateway" 9 | }, 10 | "authors": [ 11 | { 12 | "name": "Hamed Ehtesham", 13 | "email": "parsisolution@gmail.com" 14 | } 15 | ], 16 | "require": { 17 | "php": ">=7.1", 18 | "ext-json": "*", 19 | "ext-soap": "*", 20 | "ext-curl": "*", 21 | "illuminate/contracts": ">=5.4", 22 | "illuminate/http": ">=5.4", 23 | "illuminate/view": ">=5.4", 24 | "illuminate/support": ">=5.4", 25 | "illuminate/database": ">=5.4" 26 | }, 27 | "require-dev": { 28 | "laravel/pint": "^1.10", 29 | "mockery/mockery": "^1.0", 30 | "phpunit/phpunit": "^7.0|^8.0" 31 | }, 32 | "autoload": { 33 | "psr-4": { 34 | "Parsisolution\\Gateway\\": "src/" 35 | } 36 | }, 37 | "autoload-dev": { 38 | "psr-4": { 39 | "Tests\\": "tests/" 40 | } 41 | }, 42 | "extra": { 43 | "laravel": { 44 | "providers": [ 45 | "Parsisolution\\Gateway\\GatewayServiceProvider" 46 | ], 47 | "aliases": { 48 | "Gateway": "Parsisolution\\Gateway\\Facades\\Gateway" 49 | } 50 | } 51 | }, 52 | "config": { 53 | "sort-packages": true 54 | }, 55 | "minimum-stability": "dev", 56 | "prefer-stable": true, 57 | "keywords": [ 58 | "laravel", 59 | "iran", 60 | "payment", 61 | "gateway", 62 | "port", 63 | "bank", 64 | "pay", 65 | "mellat", 66 | "saman", 67 | "parsian", 68 | "pep", 69 | "pasargad", 70 | "novin", 71 | "novin-pardakht", 72 | "eghtesad-novin", 73 | "sadad", 74 | "melli", 75 | "payline", 76 | "zarinpal", 77 | "iranian-banks", 78 | "persian-banks", 79 | "pardakht", 80 | "dargah", 81 | "shaparak", 82 | "poolport", 83 | "asan-pardakht", 84 | "irankish", 85 | "fanava", 86 | "fanava-card", 87 | "sepehr", 88 | "saderat", 89 | "mabna", 90 | "ipay", 91 | "vandar", 92 | "idpay", 93 | "pay-ir", 94 | "nextpay", 95 | "jibit", 96 | "sizpay", 97 | "payping", 98 | "irandargah", 99 | "sabapay", 100 | "zibal", 101 | "jibimo", 102 | "shepa", 103 | "aqayepardakht", 104 | "bahamta", 105 | "parspal", 106 | "bitpay", 107 | "milyoona", 108 | "sepal", 109 | "tipoul", 110 | "digipay", 111 | "yekpay" 112 | ] 113 | } 114 | -------------------------------------------------------------------------------- /migrations/2018_11_14_193213_create_gateway_transactions_table.php: -------------------------------------------------------------------------------- 1 | getTableName(), function (Blueprint $table) { 22 | $table->engine = 'innoDB'; 23 | $table->unsignedBigInteger('id', true); 24 | $table->unsignedTinyInteger('provider'); 25 | $table->decimal('amount', 15, 2); 26 | $table->string('currency', 3)->nullable(); 27 | $table->string('order_id', 100)->nullable()->unique(); 28 | $table->string('token', 100)->nullable(); 29 | $table->string('reference_id', 100)->nullable()->index(); 30 | $table->string('trace_number', 100)->nullable()->index(); 31 | $table->string('rrn', 100)->nullable(); 32 | $table->string('card_number', 50)->nullable(); 33 | $table->unsignedTinyInteger('status')->default(0); 34 | $table->string('ip', 20)->nullable(); 35 | $table->json('extra')->nullable(); 36 | $table->json('log')->nullable(); 37 | $table->timestamp('paid_at')->nullable(); 38 | $table->nullableTimestamps(); 39 | $table->softDeletes(); 40 | }); 41 | } 42 | 43 | /** 44 | * Reverse the migrations. 45 | * 46 | * @return void 47 | */ 48 | public function down() 49 | { 50 | Schema::dropIfExists($this->getTableName()); 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "laravel", 3 | "rules": { 4 | "binary_operator_spaces": { 5 | "operators": { 6 | "=>": "align_single_space_minimal" 7 | } 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/ApiType.php: -------------------------------------------------------------------------------- 1 | compareTo($y)) === -gmp_sign($y->compareTo($x))` for all `$x` and `$y`. 20 | * (This implies that `$x->compareTo($y)` must throw an exception if `$y->compareTo($x)` throws an exception.) 21 | * 22 | * The implementor must also ensure that the relation is transitive: 23 | * `$x->compareTo($y) > 0 && $y->compareTo($z) > 0` 24 | * implies `$x->compareTo($z) > 0`. 25 | * 26 | * Finally, the implementor must ensure that `$x->compareTo($y) === 0` implies that `gmp_sign($x->compareTo($z)) === 27 | * gmp_sign($y->compareTo($z))`, for all `$z`. 28 | * 29 | * It is strongly recommended, but not strictly required that `($x->compareTo($y) === 0) === ($x->equals($y))`. 30 | * Generally speaking, any class that implements the {@see Comparable} interface and violates this condition should 31 | * clearly indicate this fact. The recommended language is "Note: this class has a natural ordering that is 32 | * inconsistent with equals." 33 | * 34 | * @param mixed $value 35 | * Value to compare to. 36 | * @return int 37 | * Negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the 38 | * specified value. 39 | * 40 | * @throws UncomparableException 41 | * If the implementor is unable to compare the given value with itself. 42 | */ 43 | public function compareTo($value); 44 | } 45 | -------------------------------------------------------------------------------- /src/Contracts/Factory.php: -------------------------------------------------------------------------------- 1 | $url, 25 | CURLOPT_RETURNTRANSFER => true, 26 | CURLOPT_ENCODING => '', 27 | CURLOPT_MAXREDIRS => 10, 28 | CURLOPT_TIMEOUT => 0, 29 | CURLOPT_FOLLOWLOCATION => true, 30 | CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, 31 | CURLOPT_CUSTOMREQUEST => (strtoupper($method) == self::METHOD_GET) ? null : $method, 32 | CURLOPT_HTTPHEADER => (strtoupper($method) == self::METHOD_GET) ? 33 | [ 34 | 'Accept: application/json', 35 | ] : [ 36 | 'Accept: application/json', 37 | 'Content-Type: application/json', 38 | ], 39 | ] + ( 40 | ((strtoupper($method) == self::METHOD_GET) && empty($fields)) ? [] : [ 41 | CURLOPT_POSTFIELDS => (strtoupper($method) == self::METHOD_GET) ? 42 | http_build_query($fields) : json_encode($fields), 43 | ] 44 | )); 45 | 46 | $response = curl_exec($curl); 47 | $http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE); 48 | $error = curl_error($curl); 49 | 50 | curl_close($curl); 51 | 52 | $result = json_decode($response, $resultAsArray); 53 | 54 | return [$result, $http_code, $error]; 55 | } 56 | 57 | /** 58 | * Perform a cURL session 59 | */ 60 | public static function executeArgs(array $args): array 61 | { 62 | return self::execute($args[0], $args[1], $args[2] ?? true, $args[3] ?? [], $args[4] ?? self::METHOD_POST); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Exceptions/GatewayException.php: -------------------------------------------------------------------------------- 1 | `message` 9 | * 10 | * @return array 11 | */ 12 | protected function getErrors() 13 | { 14 | return []; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Exceptions/InvalidRequestException.php: -------------------------------------------------------------------------------- 1 | `message` 15 | * 16 | * @return array 17 | */ 18 | abstract protected function getErrors(); 19 | 20 | /** 21 | * Get error code's associate message if exist and code itself otherwise 22 | * 23 | * @param mixed $code 24 | * @param null|string $message 25 | * @return string 26 | */ 27 | protected function getMessageFromCode($code, $message) 28 | { 29 | if (isset($message)) { 30 | return $message; 31 | } 32 | 33 | $code = strval($code); 34 | 35 | return Arr::get($this->getErrors(), $code, $code); 36 | } 37 | 38 | /** 39 | * TransactionException constructor. 40 | * 41 | * @param mixed $code 42 | * @param null|string $message 43 | */ 44 | public function __construct($code = 0, $message = null, Throwable $previous = null) 45 | { 46 | parent::__construct($message, 0, $previous); 47 | $this->code = $code; 48 | $this->message = $this->getMessageFromCode($code, $message); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Exceptions/UncomparableException.php: -------------------------------------------------------------------------------- 1 | Two or more things that can’t be compared with each other are uncomparable. Something that is so good that it is 14 | * > beyond comparison is incomparable. Some dictionaries don’t list uncomparable, and your spell check might say it’s 15 | * > wrong, but it’s a perfectly good, useful word. It fills a role not conventionally filled by incomparable. 16 | * > 17 | * > --- [Grammarist](http://grammarist.com/usage/incomparable-uncomparable/) 18 | */ 19 | class UncomparableException extends InvalidArgumentException 20 | { 21 | // Intentionally left blank. 22 | } 23 | -------------------------------------------------------------------------------- /src/Facades/Gateway.php: -------------------------------------------------------------------------------- 1 | publishes([ 30 | $config => config_path(GatewayManager::CONFIG_FILE_NAME.'.php'), 31 | ], 'config'); 32 | 33 | // php artisan vendor:publish --provider="Parsisolution\Gateway\GatewayServiceProvider" --tag=migrations 34 | $this->publishes([ 35 | $migrations => base_path('database/migrations'), 36 | ], 'migrations'); 37 | 38 | $this->loadViewsFrom($views, 'gateway'); 39 | 40 | // php artisan vendor:publish --provider="Parsisolution\Gateway\GatewayServiceProvider" --tag=views 41 | $this->publishes([ 42 | $views => base_path('resources/views/vendor/gateway'), 43 | ], 'views'); 44 | } 45 | 46 | /** 47 | * Register the service provider. 48 | * 49 | * @return void 50 | */ 51 | public function register() 52 | { 53 | $config = __DIR__.'/../config/'.GatewayManager::CONFIG_FILE_NAME.'.php'; 54 | 55 | $this->mergeConfigFrom($config, GatewayManager::CONFIG_FILE_NAME); 56 | 57 | $this->app->singleton(Factory::class, function ($app) { 58 | return new GatewayManager($app); 59 | }); 60 | } 61 | 62 | /** 63 | * Get the services provided by the provider. 64 | * 65 | * @return array 66 | */ 67 | public function provides() 68 | { 69 | return [Factory::class]; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/Providers/AqayePardakht/AqayePardakht.php: -------------------------------------------------------------------------------- 1 | $this->config['pin'], 46 | 'amount' => $transaction->getAmount()->getToman(), 47 | 'callback' => $this->getCallback($transaction), 48 | 'invoice_id' => $transaction->getOrderId(), 49 | 'mobile' => $transaction->getExtraField('mobile'), 50 | 'email' => $transaction->getExtraField('email'), 51 | 'card_number' => $transaction->getExtraField('allowed_card'), 52 | 'description' => $transaction->getExtraField('description'), 53 | ]; 54 | 55 | $result = $this->callApi('create', $fields); 56 | 57 | $gateUrl = $this->config['pin'] == 'sandbox' ? self::GATE_SANDBOX_URL : self::GATE_URL; 58 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, $gateUrl.$result['transid']); 59 | 60 | return AuthorizedTransaction::make($transaction, $result['transid'], null, $redirectResponse); 61 | } 62 | 63 | /** 64 | * {@inheritdoc} 65 | */ 66 | protected function validateSettlementRequest(Request $request) 67 | { 68 | if ($this->config['pin'] != 'sandbox') { 69 | if (! $request->has('status')) { 70 | throw new InvalidRequestException(); 71 | } 72 | 73 | $status = $request->input('status'); 74 | if ($status != 1) { 75 | throw new AqayePardakhtException($status); 76 | } 77 | } 78 | 79 | return new FieldsToMatch(null, $request->input('transid')); 80 | } 81 | 82 | /** 83 | * {@inheritdoc} 84 | */ 85 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 86 | { 87 | $fields = [ 88 | 'pin' => $this->config['pin'], 89 | 'amount' => $transaction->getAmount()->getToman(), 90 | 'transid' => $transaction->getReferenceId(), 91 | ]; 92 | 93 | $result = $this->callApi('verify', $fields); 94 | 95 | if ($result['code'] != '1') { 96 | throw new AqayePardakhtException($result['code']); 97 | } 98 | 99 | $traceNumber = $request->input('tracking_number'); 100 | $cardNumber = $request->input('cardnumber'); 101 | $bank = $request->input('bank'); 102 | 103 | return new SettledTransaction( 104 | $transaction, 105 | $traceNumber, 106 | new FieldsToMatch(), 107 | $cardNumber, 108 | '', 109 | compact('bank') 110 | ); 111 | } 112 | 113 | /** 114 | * @return mixed 115 | * 116 | * @throws AqayePardakhtException 117 | */ 118 | protected function callApi(string $path, array $fields) 119 | { 120 | [$response, $http_code] = Curl::execute(self::SERVER_URL.$path, $fields); 121 | 122 | if ($http_code != 200 || empty($response['status']) || $response['status'] != 'success') { 123 | throw new AqayePardakhtException($response['code'] ?? $http_code); 124 | } 125 | 126 | return $response; 127 | } 128 | 129 | /** 130 | * {@inheritdoc} 131 | */ 132 | public function getSupportedExtraFieldsSample() 133 | { 134 | return [ 135 | 'mobile' => '09124441122', 136 | 'email' => 'test@gmail.com', 137 | 'description' => 'توضیحات', 138 | 'allowed_card' => '(اختیاری) شماره کارت مجاز به پرداخت', 139 | ]; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/Providers/AqayePardakht/AqayePardakhtException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 0 => 'پرداخت انجام نشد', 18 | 1 => 'پرداخت با موفقیت انجام شد', 19 | 2 => 'تراکنش قبلا وریفای شده است', 20 | 21 | -1 => 'amount نمی تواند خالی باشد', 22 | -2 => 'کد پین درگاه نمی تواند خالی باشد', 23 | -3 => 'callback نمی تواند خالی باشد', 24 | -4 => 'amount باید عددی باشد', 25 | -5 => 'amount باید بین 100 تا 50,000,000 تومان باشد', 26 | -6 => 'کد پین درگاه اشتباه هست', 27 | -7 => 'transid نمی تواند خالی باشد', 28 | -8 => 'تراکنش مورد نظر وجود ندارد', 29 | -9 => 'کد پین درگاه با درگاه تراکنش مطابقت ندارد', 30 | -10 => 'مبلغ با مبلغ تراکنش مطابقت ندارد', 31 | -11 => 'درگاه درانتظار تایید و یا غیر فعال است', 32 | -12 => 'امکان ارسال درخواست برای این پذیرنده وجود ندارد', 33 | -13 => 'شماره کارت باید 16 رقم چسبیده بهم باشد', 34 | ]; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Providers/AsanPardakht/AsanPardakhtRestException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 18 | 200 => 'موفقیت آمیز', 19 | 20 | 400 => 'درخواست اشتباه', 21 | 401 => 'پارامتر های غیر مجاز در هدر', 22 | 471 => 'تراکنش انجام نشد', 23 | 472 => 'درخواست تایید راکنش قبلاً داده شده است', 24 | 473 => 'درخواست اصلاح تراکنش قبلاً داده شده است', 25 | 474 => 'درخواست تراکنش برای بازگشت', 26 | 475 => 'درخواست اصلاح تراکنش در لیست قرار گرفته است', 27 | 476 => 'درخواست بازگشت تراکتش در لیست فرار گرفته است', 28 | 477 => 'هویت مورد اعتماد برای ادامه کار نیست', 29 | 478 => 'درخواست قبلا لغو شده است', 30 | 31 | 571 => 'هنوز پردازش نشده است', 32 | 572 => 'وضعیت تراکنش هنور مشخص نیست', 33 | 573 => 'به دلیل خطای داخلی قادر به درخواست تأیید نیست', 34 | 35 | ]; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Providers/AsanPardakht/AsanPardakhtRestTokenException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 18 | 200 => 'موفقیت آمیز', 19 | 20 | 400 => 'ارسال پارامتر های اشتباه', 21 | 401 => 'پارامتر های غیر مجاز در هدر', 22 | 471 => 'هویت معتبر برای ادامه کار یافت نشد', 23 | 472 => 'هیچ رکوردی یافت نشد', 24 | 473 => 'نام کاربر یا رمز عبور ویا مرچنت اشتباه میباشد', 25 | 474 => 'آیپی شما مجاز نمی باشد', 26 | 475 => 'شناسه فاکتور معتبر نمی باشد', 27 | 476 => 'مقدار مبلغ معتبر نمی باشد', 28 | 477 => 'مقدار تاریخ معتبر نمی باشد', 29 | 478 => 'فرمت تاریخ ارسالی معتبر نمی باشد', 30 | 479 => 'شناسه خدمات معتبر نمی باشد', 31 | 480 => 'شناسه پرداخت کننده معتبر نمی باشد', 32 | 481 => 'فرمت حساب تسهیمی نامعتبر می باشد', 33 | 482 => 'مقدار حساب تسهیمی با کل مبلغ انطباق ندارد', 34 | 483 => 'شماره شبا نامعتبر می باشد', 35 | 484 => 'خطای بانکی', 36 | 485 => 'تاریخ محلی نامعتبر می باشد', 37 | 486 => 'مبلغ مورد نظر در محدوده بانکی مجاز این درگاه نمی‌باشد، لطفا از درگاه دیگری استفاده کنید', 38 | 487 => 'سرویسی برای این شناسه یافت نشد', 39 | 488 => 'لینک برگشتی معتبر نمی باشد', 40 | 489 => 'این شماره فاکتور تکراری می باشد', 41 | 490 => 'شناسه غیر فعال و یا اشتباه می باشد', 42 | 491 => 'حساب های تسهیمی زیاد می باشد', 43 | 492 => 'درخواست غیرقابل پردازش', 44 | 493 => 'درخواست غیرقابل پردازش', 45 | 46 | 571 => 'پیکربندی اشتباه', 47 | 572 => 'پیکربندی اشتباه', 48 | 573 => 'سو استفاده آیپی های معتبر برای پیکر بندی سرویس', 49 | 574 => 'خطا در اعتبار سنجی', 50 | 575 => 'شماره شبای معتبری برای این شناسه یافت نشد', 51 | 576 => 'خطای سیستمی', 52 | 577 => 'خطای سیستمی', 53 | 578 => 'هیچ اشتراکی برای این شناسه تعریف نشده است', 54 | 579 => 'نمی توانید بدون شماره شبا درخواستی ارسال کنید', 55 | 580 => 'پردازش خطابرای درخواست های خاص', 56 | 57 | ]; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Providers/Bahamta/Bahamta.php: -------------------------------------------------------------------------------- 1 | setServer(); 46 | } 47 | 48 | /** 49 | * Set server for soap transfers data 50 | * 51 | * @return void 52 | */ 53 | protected function setServer() 54 | { 55 | if (Arr::get($this->config, 'sandbox', false)) { 56 | $this->serverUrl = self::SERVER_SANDBOX_URL; 57 | } else { 58 | $this->serverUrl = self::SERVER_URL; 59 | } 60 | } 61 | 62 | /** 63 | * {@inheritdoc} 64 | */ 65 | protected function authorizeTransaction(UnAuthorizedTransaction $transaction) 66 | { 67 | $fields = [ 68 | 'api_key' => $this->config['api-key'], 69 | 'reference' => $transaction->getOrderId(), 70 | 'amount_irr' => $transaction->getAmount()->getRiyal(), 71 | 'callback_url' => $this->getCallback($transaction), 72 | 'trusted_pan' => $transaction->getExtraField('allowed_card'), 73 | ]; 74 | $mobile = $transaction->getExtraField('mobile'); 75 | if (! empty($mobile)) { 76 | $fields['payer_mobile'] = '98'.substr($mobile, 1); 77 | } 78 | 79 | $result = $this->callApi('create_request', $fields); 80 | 81 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, $result['payment_url']); 82 | 83 | return AuthorizedTransaction::make($transaction, null, null, $redirectResponse); 84 | } 85 | 86 | /** 87 | * {@inheritdoc} 88 | */ 89 | protected function validateSettlementRequest(Request $request) 90 | { 91 | if (! $request->has('state')) { 92 | throw new InvalidRequestException(); 93 | } 94 | 95 | $state = $request->input('state'); 96 | if ($state == 'error') { 97 | throw new BahamtaException($request->input('error_key', $state), $request->input('error_message')); 98 | } 99 | 100 | return new FieldsToMatch($request->input('reference')); 101 | } 102 | 103 | /** 104 | * {@inheritdoc} 105 | */ 106 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 107 | { 108 | $fields = [ 109 | 'api_key' => $this->config['api-key'], 110 | 'reference' => $transaction->getOrderId(), 111 | 'amount_irr' => $transaction->getAmount()->getRiyal(), 112 | ]; 113 | 114 | $result = $this->callApi('confirm_payment', $fields); 115 | 116 | if ($result['state'] != 'paid') { 117 | throw new BahamtaException($result['state']); 118 | } 119 | 120 | $traceNumber = $result['pay_trace']; 121 | $cardNumber = $result['pay_pan']; 122 | 123 | $toMatch = new FieldsToMatch(); 124 | 125 | return new SettledTransaction( 126 | $transaction, 127 | $traceNumber, 128 | $toMatch, 129 | $cardNumber, 130 | '', 131 | [ 132 | 'verify_result' => $result, 133 | 'hashed_card' => $result['pay_cid'], 134 | 'pay_time' => $result['pay_time'], 135 | 'pay_reference' => $result['pay_ref'], 136 | ], 137 | $result['pay_ref'] 138 | ); 139 | } 140 | 141 | /** 142 | * @return mixed 143 | * 144 | * @throws BahamtaException 145 | */ 146 | protected function callApi($path, $fields) 147 | { 148 | [$response, $http_code, $error] = 149 | Curl::execute($this->serverUrl.$path, $fields, true, [], Curl::METHOD_GET); 150 | 151 | if (! isset($response['ok'])) { 152 | throw new BahamtaException($http_code, $error); 153 | } 154 | if (! $response['ok']) { 155 | throw new BahamtaException($response['error'] ?? 'UNKNOWN_ERROR'); 156 | } 157 | 158 | return $response['result']; 159 | } 160 | 161 | /** 162 | * {@inheritdoc} 163 | */ 164 | public function getSupportedExtraFieldsSample() 165 | { 166 | return [ 167 | 'mobile' => '09124441122', 168 | 'description' => 'توضیحات تراکنش', 169 | 'allowed_card' => 'شماره کارت پرداخت‌کننده است'. 170 | ' که این شماره کارت بعد از انجام عملیات پرداخت با شماره کارت دریافتی از بانک تطابق داده می‌شود'. 171 | ' و درصورتی که یکسان نباشد، مبلغ تراکنش به حساب پرداخت‌کننده برمی‌گردد.', 172 | ]; 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/Providers/Bahamta/BahamtaException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 'INVALID_API_CALL' => 'قالب فراخوانی سرویس رعایت نشده است. مثلاً ممکن است پارامترها به درستی از هم جدا نشده باشند و یا حروف غیر مجاز (مثل فاصله) در بین آنها وجود داشته باشد. برای تبدیل حروف غیرمجاز لازم است که مقادیر url encode شده باشند.', 18 | 'INVALID_API_KEY' => 'کلید الکترونیکی صاحب فروشگاه فرستاده نشده و یا ساختار آن نادرست است.', 19 | 'NOT_AUTHORIZED' => 'گرچه ساختار کلید درست است، اما هیچ فروشنده‌ای با این کلید در webpay ثبت نشده است.', 20 | 'INVALID_AMOUNT' => 'پارامتر مبلغ فرستاده نشده و یا نادرست فرستاده شده است. مثلاً ممکن است ارقام مبلغ سه رقم به سه رقم با علامت , جدا شده باشند که نادرست است.', 21 | 'LESS_THAN_WAGE_AMOUNT' => 'مبلغ کمتر از کارمزد پرداختی است.', 22 | 'TOO_LESS_AMOUNT' => 'مبلغ کمتر از حد مجاز (هزار تومان) است.', 23 | 'TOO_MUCH_AMOUNT' => 'مبلغ بیشتر از حد مجاز (پنجاه میلیون تومان) است.', 24 | 'INVALID_REFERENCE' => 'شماره شناسه پرداخت ناردست است. این مقدار باید یک عبارت حرفی با طول بین ۱ تا ۶۴ حرف باشد.', 25 | 'INVALID_TRUSTED_PAN' => 'لیست شماره کارتها نادرست است. هر شماره کارت باید با یک علامت کاما از شماره کارت قبلی خود جدا شده باشد. طول هر شماره کارت باید ۱۶ رقم باشد، و اگر ۶ رقم دوم آن مخفی است، به جای هر یک از رقمهای مخفی باید یک علامت ستاره گذاشته شده باشد.', 26 | 'INVALID_CALLBACK' => 'آدرس فراخوانی نادرست است. این آدرس باید با ://http و یا ://https شروع شود.', 27 | 'INVALID_PARAM' => 'خطایی در مقادیر فرستاده شده وجود دارد که جزو موارد یاد شده بالا نیست.', 28 | 'ALREADY_PAID' => 'درخواست پرداختی با شناسه داده شده قبلاً ثبت و پرداخت شده است. شناسه reference تکراری است و باید برای هر درخواست متفاوت باشد. توجه به این نکته می‌تواند مفید باشد که تکراری بودن شناسه مرجع می‌تواند به دو دلیل رخ دهد: ۱- سایت فروشگاه به اشتباه یک شناسه را برای دو سفارش جداگانه استفاده کرده باشد. که در این صورت این خطا باید در سایت فروشگاه برطرف شود. ۲- ممکن است برای یک سفارش واحد، دو بار درخواست فرستاده شده باشد. در این صورت می‌توان برای دریافت تأیید اقدام کرد و نتیجه پرداخت را به طور مستقم از webpay جویا شد.', 29 | // 'MISMATCHED_DATA' => 'درخواست پرداختی با شناسه داده شده قبلاً ثبت و منتظر پرداخت است، اما مقادیر فرستاده شده در این درخواست، با درخواست اصلی متفاوت است. از آنجا که ممکن است به هر دلیلی، از جمله قطع اینترنت، نتیجه درخواست به دست فرستنده نرسد این امکان وجود دارد که یک درخواست دوباره (و با همان شناسه) فرستاده شود تا نتیجه درخواست به دست فرستنده برسد. اما در چنین حالتی مقادیر اصلی درخواست از جمله مبلغ و کارت‌های بانکی مورد اعتماد باید با مقادیر قبلی یکسان باشند، در غیر این صورت، درخواست با این خطا روبرو خواهد شد.', 30 | 'NO_REG_TERMINAL' => 'ترمینالی برای این فروشنده ثبت نشده است.', 31 | 'NO_AVAILABLE_GATEWAY' => 'درگاههای پرداختی که این فروشنده در آنها ترمینال ثبت شده دارد، قادر به ارائه خدمات نیستند.', 32 | 'UNKNOWN_BILL' => 'پرداختی با شماره شناسه فرستاده شده ثبت نشده است.', 33 | 'MISMATCHED_DATA' => 'مبلغ اعلام شده با آنچه در webpay ثبت شده است مطابقت ندارد.', 34 | 'NOT_CONFIRMED' => 'این پرداخت تأیید نشد.', 35 | 'SERVICE_ERROR' => 'خطای داخلی سرویس رخ داده است.', 36 | 'UNKNOWN_ERROR' => 'خطای نامشخص رخ داده است.', 37 | ]; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Providers/BitPay/BitPayException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 0 => 'خطای تعریف نشده', 18 | -1 => 'API ارسالی با نوع API تعریف شده در bitpay سازگار نیست', 19 | -2 => 'مقدار amount داده عددي نمی‌باشد و یا کمتر از ۱۰۰۰ ریال است', 20 | -3 => 'مقدار redirect رشته null است', 21 | -4 => 'درگاهی با اطالعات ارسالی شما وجود ندارد و یا در حالت انتظار می‌باشد', 22 | -5 => 'خطا در اتصال به درگاه، لطفا مجددا تلاش کنید', 23 | ]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Providers/DigiPay/DigiPay.php: -------------------------------------------------------------------------------- 1 | initDP()->createTicket( 25 | $transaction->getAmount()->getRiyal(), 26 | $transaction->getOrderId(), 27 | $this->getCallback($transaction), 28 | $transaction->getExtraField('mobile') 29 | ); 30 | 31 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, $ticket['url']); 32 | 33 | return AuthorizedTransaction::make($transaction, null, $ticket['ticket'], $redirectResponse); 34 | } 35 | 36 | /** 37 | * {@inheritdoc} 38 | */ 39 | protected function validateSettlementRequest(Request $request) 40 | { 41 | if (! $request->has('result')) { 42 | throw new InvalidRequestException(); 43 | } 44 | 45 | $result = $request->input('result'); 46 | if ($result != 'SUCCESS') { 47 | throw new DigipayException($result); 48 | } 49 | 50 | $providerId = $request->input('providerId'); 51 | $amount = $request->input('amount'); 52 | 53 | return new FieldsToMatch($providerId, null, null, new Amount($amount, 'IRR')); 54 | } 55 | 56 | /** 57 | * {@inheritdoc} 58 | */ 59 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 60 | { 61 | $trackingCode = $request->input('trackingCode'); 62 | 63 | $result = $this->initDP()->verifyTicket($trackingCode); 64 | 65 | $payment_gateway = $result['paymentGateway']; 66 | $toMatch = new FieldsToMatch($result['providerId'], null, null, new Amount($result['amount'], 'IRR')); 67 | 68 | return new SettledTransaction( 69 | $transaction, 70 | $result['trackingCode'] ?? $trackingCode, 71 | $toMatch, 72 | $result['maskedPan'] ?? '', 73 | $result['rrn'] ?? '', 74 | ['verify_result' => $result] + compact('payment_gateway') 75 | ); 76 | } 77 | 78 | protected function initDP(): DigiPayGateway 79 | { 80 | $settings = [ 81 | 'type' => $this->config['type'], 82 | 'username' => $this->config['username'], 83 | 'password' => $this->config['password'], 84 | 'client_id' => $this->config['client-id'], 85 | 'client_secret' => $this->config['client-secret'], 86 | 'access_token' => Cache::get('dp_access_token'), 87 | 'refresh_token' => Cache::get('dp_refresh_token'), 88 | 'live_api' => ! $this->config['sandbox'], 89 | ]; 90 | 91 | return new DigiPayGateway($settings, function ($accessToken, $refreshToken) { 92 | Cache::forever('dp_access_token', $accessToken); 93 | Cache::forever('dp_refresh_token', $refreshToken); 94 | }); 95 | } 96 | 97 | /** 98 | * {@inheritdoc} 99 | */ 100 | public function getSupportedExtraFieldsSample() 101 | { 102 | return [ 103 | 'mobile' => '09124441122', 104 | ]; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/Providers/DigiPay/DigiPayException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 'SUCCESS' => 'تراکنش موفق', 18 | 'FAILURE' => 'خطا در انجام تراکنش', 19 | 'IPG_FAILURE' => 'خطا در انجام تراکنش آی پی جی', 20 | 'CANCELED' => 'پرداخت لغو شده', 21 | 'INTERNAL_ERROR' => 'خطای سیستمی', 22 | 'INVALID_TICKET' => 'تیکت نامعتبر / پرداخت در وضعیت نامعتبر', 23 | 24 | 0 => 'عملیات با موفقیت انجام شد', 25 | 1054 => 'اطلاعات ورودی اشتباه می باشد', 26 | 9000 => 'اطلاعات خرید یافت نشد', 27 | 9001 => 'توکن پرداخت معتبر نمی باشد', 28 | 9003 => 'خرید مورد نظر منقضی شده است', 29 | 9004 => 'خرید مورد نظر درحال انجام است', 30 | 9005 => 'خرید قابل پرداخت نمی باشد', 31 | 9006 => 'خطا در برقراری ارتباط با درگاه پرداخت', 32 | 9007 => 'خرید با موفقیت انجام نشده است', 33 | 9008 => 'این خرید با داده های متفاوتی قبلا ثبت شده است', 34 | 9009 => 'محدوده زمانی تایید تراکنش گذشته است', 35 | 9010 => 'تایید خرید ناموفق بود', 36 | 9011 => 'نتیجه تایید خرید نامشخص است', 37 | 9012 => 'وضعیت خرید برای این درخواست صحیح نمی باشد', 38 | 9030 => 'ورود شماره همراه برای کاربران ثبت نام شده الزامی است', 39 | 9031 => 'اعطای تیکت برای کاربر مورد نظر امکان پذیر نمی‌باشد', 40 | ]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Providers/Fanava/Fanava.php: -------------------------------------------------------------------------------- 1 | $this->config['terminal-id'], 39 | 'RequestType' => $transaction->getExtraField('request_type', 'PU'), 40 | 'InvoiceId' => $transaction->getOrderId(), 41 | 'Amount' => $transaction->getAmount()->getRiyal(), 42 | 'CallBackUrl' => $this->getCallback($transaction), 43 | 'AdditionalData' => $transaction->getExtraField('additional_data'), 44 | 'SettleModel' => $transaction->getExtraField('settle_model'), 45 | ]; 46 | $mobile = $transaction->getExtraField('mobile'); 47 | if (! empty($mobile)) { 48 | $fields['CellNumber'] = substr($mobile, 1); 49 | } 50 | 51 | $token = $this->callApi('GetToken', $fields)->Token; 52 | 53 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_POST, self::GATE_URL, [ 54 | 'Token' => $token, 55 | ]); 56 | 57 | return AuthorizedTransaction::make($transaction, null, $token, $redirectResponse); 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | protected function validateSettlementRequest(Request $request) 64 | { 65 | if (! $request->has('RespCode')) { 66 | throw new InvalidRequestException(); 67 | } 68 | 69 | $code = $request->input('RespCode'); 70 | $message = $request->input('RespMsg'); 71 | 72 | if ($code != 0) { 73 | throw new FanavaException($code, $message); 74 | } 75 | 76 | $invoiceId = $request->input('InvoiceId'); 77 | $amount = $request->input('Amount'); 78 | 79 | return new FieldsToMatch($invoiceId, null, null, new Amount($amount, 'IRR')); 80 | } 81 | 82 | /** 83 | * {@inheritdoc} 84 | */ 85 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 86 | { 87 | $digitalReceipt = $request->input('digitalReceipt'); 88 | $cardNumber = $request->input('CardNumber'); 89 | $RRN = $request->input('RRN'); 90 | 91 | $fields = [ 92 | 'Terminal' => $this->config['terminal-id'], 93 | 'DigitalReceipt' => $digitalReceipt, 94 | ]; 95 | 96 | $response = $this->callApi('Advice', $fields)->RespCode; 97 | $amount = explode(';', $response)[1]; 98 | 99 | $toMatch = new FieldsToMatch(null, null, null, new Amount($amount, 'IRR')); 100 | 101 | return new SettledTransaction($transaction, $digitalReceipt, $toMatch, $cardNumber, $RRN); 102 | } 103 | 104 | /** 105 | * @return mixed 106 | * 107 | * @throws FanavaException 108 | */ 109 | public function rollback(string $digitalReceipt) 110 | { 111 | $fields = [ 112 | 'Terminal' => $this->config['terminal-id'], 113 | 'DigitalReceipt' => $digitalReceipt, 114 | ]; 115 | 116 | return $this->callApi('Rollback', $fields); 117 | } 118 | 119 | /** 120 | * @return mixed 121 | * 122 | * @throws FanavaException 123 | */ 124 | protected function callApi(string $path, array $fields) 125 | { 126 | [$response, $http_code] = Curl::execute(self::SERVER_URL.$path, $fields, false); 127 | 128 | $code = explode(';', $response->RespCode)[0]; 129 | if ($http_code != 200 || $code != 0 || $code != 1) { 130 | throw new FanavaException($code ?? $http_code, $response->RespMsg ?? null); 131 | } 132 | 133 | return $response; 134 | } 135 | 136 | /** 137 | * {@inheritdoc} 138 | */ 139 | public function getSupportedExtraFieldsSample() 140 | { 141 | return [ 142 | 'mobile' => '09124441122', 143 | 'additional_data' => '(json) داده‌های اضافی', 144 | 'settle_model' => '(json) مدل تسویه (نکته: در فاز بعدی توسعه داده می‌شود)', 145 | 'request_type' => 'PU (default) (خرید) || '. 146 | 'BI (قبض) || '. 147 | 'CH (شارژ) || '. 148 | 'BL (موجودی) || '. 149 | 'UD (نامشخص: برای سرویس‌هایی مانند کمک‌های مردمی و غیره استفاده شود)', 150 | ]; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/Providers/Fanava/FanavaException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | -1 => 'تراکنش اصلی یافت نشد', 18 | -2 => 'تراکنش قبلا Reverse شده است', 19 | -3 => 'Total Error خطای عمومی - خطای Exception ها', 20 | -4 => 'امکان انجام درخواست برای این تراکنش وجود ندارد', 21 | -5 => 'دسترسی غیر مجاز، آدرس IP نامعتبر میباشد (IP در لیست آدرس‌های معرفی شده توسط پذیرنده موجود نمی‌باشد)', 22 | -6 => 'عدم فعال بودن سرویس برگشت تراکنش برای پذیرنده', 23 | ]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Providers/IDPay/IDPay.php: -------------------------------------------------------------------------------- 1 | $transaction->getOrderId(), 33 | 'amount' => $transaction->getAmount()->getRiyal(), 34 | 'name' => $transaction->getExtraField('name'), 35 | 'phone' => $transaction->getExtraField('mobile'), 36 | 'mail' => $transaction->getExtraField('email'), 37 | 'desc' => $transaction->getExtraField('description'), 38 | 'callback' => $this->getCallback($transaction), 39 | ]; 40 | 41 | [$result, $http_code] = Curl::execute(self::SERVER_URL, $fields, true, [ 42 | CURLOPT_HTTPHEADER => $this->generateHeaders(), 43 | ]); 44 | 45 | if ($http_code != 201 || empty($result) || empty($result['id']) || empty($result['link'])) { 46 | throw new IDPayException($result['error_code'] ?? $http_code, $result['error_message'] ?? null); 47 | } 48 | 49 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, $result['link']); 50 | 51 | return AuthorizedTransaction::make($transaction, $result['id'], null, $redirectResponse); 52 | } 53 | 54 | /** 55 | * {@inheritdoc} 56 | */ 57 | protected function validateSettlementRequest(Request $request) 58 | { 59 | if (! $request->has('status')) { 60 | throw new InvalidRequestException(); 61 | } 62 | 63 | $status = $request->input('status'); 64 | if ($status != 10) { 65 | throw new IDPayException($status, $this->getStatusMessage($status)); 66 | } 67 | 68 | $orderId = $request->input('order_id'); 69 | $referenceId = $request->input('id'); 70 | $amount = $request->input('amount'); 71 | 72 | return new FieldsToMatch($orderId, $referenceId, null, new Amount($amount, 'IRR')); 73 | } 74 | 75 | /** 76 | * {@inheritdoc} 77 | */ 78 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 79 | { 80 | // $request->input('status'); 81 | // $request->input('track_id'); 82 | // $request->input('id'); 83 | // $request->input('order_id'); 84 | // $request->input('amount'); 85 | // $request->input('card_no'); 86 | // $request->input('hashed_card_no'); 87 | // $request->input('date'); 88 | 89 | $fields = [ 90 | 'id' => $transaction->getReferenceId(), 91 | 'order_id' => $transaction->getOrderId(), 92 | ]; 93 | 94 | [$result, $http_code] = Curl::execute(self::SERVER_URL.'/verify', $fields, true, [ 95 | CURLOPT_HTTPHEADER => $this->generateHeaders(), 96 | ]); 97 | 98 | if ($http_code != 200) { 99 | throw new IDPayException($result['error_code'] ?? $http_code, $result['error_message'] ?? null); 100 | } 101 | 102 | if (empty($result['status']) || empty($result['track_id']) || $result['status'] < 100) { 103 | throw new IDPayException($result['status'], $this->getStatusMessage($result['status'])); 104 | } 105 | 106 | $toMatch = new FieldsToMatch($result['order_id'], $result['id'], null, new Amount($result['amount'], 'IRR')); 107 | 108 | return new SettledTransaction( 109 | $transaction, 110 | $result['track_id'], 111 | $toMatch, 112 | $result['payment']['card_no'] ?? '', 113 | '', 114 | $result['payment'] ?? [] 115 | ); 116 | } 117 | 118 | /** 119 | * @return string[] 120 | */ 121 | protected function generateHeaders(): array 122 | { 123 | return [ 124 | 'Content-Type: application/json', 125 | 'X-API-KEY: '.$this->config['api-key'], 126 | 'X-SANDBOX: '.($this->config['sandbox'] ? 'true' : 'false'), 127 | ]; 128 | } 129 | 130 | protected function getStatusMessage(int $code): ?string 131 | { 132 | $status_codes = [ 133 | 1 => 'پرداخت انجام نشده است', 134 | 2 => 'پرداخت ناموفق بوده است', 135 | 3 => 'خطا رخ داده است', 136 | 4 => 'بلوکه شده', 137 | 5 => 'برگشت به پرداخت کننده', 138 | 6 => 'برگشت خورده سیستمی', 139 | 7 => 'انصراف از پرداخت', 140 | 8 => 'به درگاه پرداخت منتقل شد', 141 | 10 => 'در انتظار تایید پرداخت', 142 | 100 => 'پرداخت تایید شده است', 143 | 101 => 'پرداخت قبلا تایید شده است', 144 | 200 => 'به دریافت کننده واریز شد', 145 | ]; 146 | 147 | return $status_codes[$code] ?? null; 148 | } 149 | 150 | /** 151 | * {@inheritdoc} 152 | */ 153 | public function getSupportedExtraFieldsSample() 154 | { 155 | return [ 156 | 'mobile' => '09124441122', 157 | 'name' => 'نام پرداخت کننده به طول حداکثر 255 کاراکتر', 158 | 'email' => 'پست الکترونیک پرداخت کننده به طول حداکثر 255 کاراکتر', 159 | 'description' => 'توضیح تراکنش به طول حداکثر 255 کاراکتر', 160 | ]; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/Providers/IDPay/IDPayException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | -1 => 'خطای غیر منتظره', 18 | 11 => 'کاربر مسدود شده است.', 19 | 12 => 'API Key یافت نشد.', 20 | 13 => 'درخواست شما از {ip} ارسال شده است. این IP با IP های ثبت شده در وب سرویس همخوانی ندارد.', 21 | 14 => 'وب سرویس شما در حال بررسی است و یا تایید نشده است.', 22 | 15 => 'سرویس مورد نظر در دسترس نمی باشد.', 23 | 21 => 'حساب بانکی متصل به وب سرویس تایید نشده است.', 24 | 22 => 'وب سریس یافت نشد.', 25 | 23 => 'اعتبار سنجی وب سرویس ناموفق بود.', 26 | 24 => 'حساب بانکی مرتبط با این وب سرویس غیر فعال شده است.', 27 | 31 => 'کد تراکنش id نباید خالی باشد.', 28 | 32 => 'شماره سفارش order_id نباید خالی باشد.', 29 | 33 => 'مبلغ amount نباید خالی باشد.', 30 | 34 => 'مبلغ amount باید بیشتر از {min-amount} ریال باشد.', 31 | 35 => 'مبلغ amount باید کمتر از {max-amount} ریال باشد.', 32 | 36 => 'مبلغ amount بیشتر از حد مجاز است.', 33 | 37 => 'آدرس بازگشت callback نباید خالی باشد.', 34 | 38 => 'درخواست شما از آدرس {domain} ارسال شده است. دامنه آدرس بازگشت callback با آدرس ثبت شده در وب سرویس همخوانی ندارد.', 35 | 39 => 'آدرس بازگشت callback نامعتبر است.', 36 | 41 => 'فیلتر وضعیت تراکنش ها می بایست آرایه ای (لیستی) از وضعیت های مجاز در مستندات باشد.', 37 | 42 => 'فیلتر تاریخ پرداخت می بایست آرایه ای شامل المنت های min و max از نوع timestamp باشد.', 38 | 43 => 'فیلتر تاریخ تسویه می بایست آرایه ای شامل المنت های min و max از نوع timestamp باشد.', 39 | 44 => 'فیلتر تراکنش صحیح نمی باشد.', 40 | 51 => 'تراکنش ایجاد نشد.', 41 | 52 => 'استعلام نتیجه ای نداشت.', 42 | 53 => 'تایید پرداخت امکان پذیر نیست.', 43 | 54 => 'مدت زمان تایید پرداخت سپری شده است.', 44 | ]; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Providers/IranDargah/IranDargahException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 200 => 'اتصال به درگاه بانک با موفقیت انجام ‌شده‌است.', 18 | 201 => 'در حال پرداخت در درگاه بانک.', 19 | 100 => 'تراکنش با موفقیت انجام ‌شده‌‌است.', 20 | 101 => 'تراکنش قبلا verify شده‌است.', 21 | 404 => 'تراکنش یافت نشد.', 22 | 403 => 'کد مرچنت صحیح نمی‌باشد.', 23 | -1 => 'کاربر از انجام تراکنش منصرف‌ شده‌است.', 24 | -2 => 'اطلاعات ارسالی صحیح نمی‌باشد.', 25 | -10 => 'مبلغ تراکنش کمتر از 10,000 ریال است.', 26 | -11 => 'مبلغ تراکنش با مبلغ پرداخت، یکسان نیست. مبلغ برگشت‌خورد.', 27 | -12 => 'شماره کارتی که با آن، تراکنش انجام ‌شده‌است با شماره کارت ارسالی، مغایرت دارد. مبلغ برگشت‌خورد.', 28 | -13 => 'تراکنش تکراری است.', 29 | -20 => 'شناسه تراکنش یافت‌‌نشد.', 30 | -21 => 'مدت زمان مجاز، جهت ارسال به بانک گذشته‌است.', 31 | -22 => 'تراکنش برای بانک ارسال شده‌است.', 32 | -23 => 'خطا در اتصال به درگاه بانک.', 33 | -30 => 'اشکالی در فرایند پرداخت ایجاد ‌شده‌است.مبلغ برگشت خورد.', 34 | -31 => 'خطای ناشناخته', 35 | 36 | 'CONNECTION_ERROR' => 'خطا در اتصال به درگاه پرداخت ایران درگاه', 37 | 'TOO_MUCH_AMOUNT' => 'مبلغ از میزان مجاز بیشتر است', 38 | 'UNKNOWN_ERROR' => 'خطای ناشناخته', 39 | ]; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Providers/Irankish/Irankish.php: -------------------------------------------------------------------------------- 1 | [ 45 | 'acceptorId' => $this->config['acceptor-id'], 46 | 'amount' => $transaction->getAmount()->getRiyal(), 47 | 'billInfo' => null, 48 | 'requestId' => $transaction->getOrderId(), 49 | 'paymentId' => $transaction->getOrderId(), 50 | 'requestTimestamp' => time(), 51 | 'revertUri' => $this->getCallback($transaction), 52 | 'terminalId' => $this->config['terminal-id'], 53 | 'transactionType' => 'Purchase', 54 | ], 55 | 'authenticationEnvelope' => $this->generateAuthenticationEnvelope($transaction->getAmount()->getRiyal()), 56 | ]; 57 | $mobile = $transaction->getExtraField('mobile'); 58 | if (! empty($mobile)) { 59 | $fields['request']['cmsPreservationId'] = '98'.substr($mobile, 1); 60 | } 61 | 62 | [$response, $http_code, $error] = Curl::execute(self::SERVER_URL, $fields); 63 | 64 | if (! ($response['result'] ?? false)) { 65 | throw new IrankishException($response['responseCode'] ?? $http_code, $response['description'] ?? $error); 66 | } 67 | 68 | $data = ['tokenIdentity' => $response['result']['token']]; 69 | 70 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_POST, self::GATE_URL, $data); 71 | 72 | return AuthorizedTransaction::make($transaction, null, $response['result']['token'], $redirectResponse); 73 | } 74 | 75 | /** 76 | * {@inheritdoc} 77 | */ 78 | protected function validateSettlementRequest(Request $request) 79 | { 80 | $responseCode = $request->input('responseCode'); 81 | 82 | if ($responseCode != '0' && $responseCode != '00') { 83 | throw new IrankishException($responseCode); 84 | } 85 | 86 | $orderId = $request->input('paymentId'); 87 | $token = $request->input('token'); 88 | $amount = $request->input('amount'); 89 | 90 | return new FieldsToMatch($orderId, null, $token, new Amount($amount, 'IRR')); 91 | } 92 | 93 | /** 94 | * {@inheritdoc} 95 | */ 96 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 97 | { 98 | $fields = [ 99 | 'terminalId' => $this->config['terminal-id'], 100 | 'retrievalReferenceNumber' => $request->input('retrievalReferenceNumber'), 101 | 'systemTraceAuditNumber' => $request->input('systemTraceAuditNumber'), 102 | 'tokenIdentity' => $request->input('token'), 103 | ]; 104 | 105 | [$response] = Curl::execute(self::SERVER_VERIFY_URL, $fields); 106 | 107 | if ($response['responseCode'] != '0' && $response['responseCode'] != '00') { 108 | throw new IrankishException($response['responseCode']); 109 | } 110 | 111 | $result = $response['result']; 112 | 113 | $extraFields = [ 114 | 'status' => $response['status'], 115 | 'provider_description' => $response['description'], 116 | 'sha256OfPan' => $request->input('sha256OfPan'), 117 | ]; 118 | 119 | $toMatch = new FieldsToMatch($result['paymentId'], null, null, new Amount($result['amount'], 'IRR')); 120 | 121 | return new SettledTransaction( 122 | $transaction, 123 | $result['systemTraceAuditNumber'], 124 | $toMatch, 125 | $request->input('maskedPan'), 126 | $result['retrievalReferenceNumber'], 127 | $extraFields 128 | ); 129 | } 130 | 131 | protected function generateAuthenticationEnvelope(float $amount): array 132 | { 133 | $data = $this->config['terminal-id'].$this->config['password'].str_pad($amount, 12, '0', STR_PAD_LEFT).'00'; 134 | $data = hex2bin($data); 135 | $AESSecretKey = openssl_random_pseudo_bytes(16); 136 | $iv_length = openssl_cipher_iv_length($cipher = 'AES-128-CBC'); 137 | $iv = openssl_random_pseudo_bytes($iv_length); 138 | $ciphertext_raw = openssl_encrypt($data, $cipher, $AESSecretKey, OPENSSL_RAW_DATA, $iv); 139 | $hmac = hash('sha256', $ciphertext_raw, true); 140 | $encrypted_data = ''; 141 | 142 | openssl_public_encrypt($AESSecretKey.$hmac, $encrypted_data, $this->config['public-key']); 143 | 144 | return [ 145 | 'data' => bin2hex($encrypted_data), 146 | 'iv' => bin2hex($iv), 147 | ]; 148 | } 149 | 150 | /** 151 | * {@inheritdoc} 152 | */ 153 | public function getSupportedExtraFieldsSample() 154 | { 155 | return [ 156 | 'mobile' => '09124441122', 157 | ]; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /src/Providers/Irankish/IrankishException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 2 => 'تراکنش قبلا برگشت شده است', 18 | 3 => 'پذیرنده فروشگاهی نا معتبر است', 19 | 5 => 'از انجام تراکنش صرف نظر شد', 20 | 14 => 'اطلاعات کارت صحیح نمی باشد', 21 | 17 => 'از انجام تراکنش صرف نظر شد', 22 | 25 => 'تراکنش اصلی یافت نشد', 23 | 30 => 'فرمت پیام نادرست است', 24 | 31 => 'عدم تطابق کد ملی خریدار با دارنده کارت', 25 | 40 => 'عمل درخواستی پشتیبانی نمی شود', 26 | // 42 => 'کارت یا حساب مبدا در وضعیت پذیرش نمی باشد', 27 | 42 => 'کارت یا حساب مقصد در وضعیت پذیرش نمی باشد', 28 | 51 => 'موجودی حساب کافی نمی باشد', 29 | 54 => 'تاریخ انقضا کارت سررسید شده است', 30 | 55 => 'رمز کارت نادرست است', 31 | 56 => 'اطلاعات کارت یافت نشد', 32 | 57 => 'انجام تراکنش مورد درخواست توسط پایانه انجام دهنده مجاز نمی باشد', 33 | 58 => 'انجام تراکنش مورد درخواست توسط پایانه انجام دهنده مجاز نمی باشد', 34 | 59 => 'اطلاعات کارت صحیح نمی باشد یا کارت مظنون به تقلب است', 35 | 61 => 'مبلغ تراکنش بیش از حد مجاز است', 36 | 62 => 'کارت محدود شده است', 37 | // 63 => 'کد اعتبار سنجی پیام نا معتبر است', 38 | 63 => 'تمهیدات امنیتی نقض گردیده است', 39 | 64 => 'مبلغ تراکنش نادرست است،جمع مبالغ تقسیم وجوه برابر مبلغ کل تراکنش نمی باشد', 40 | 65 => 'تعداد دفعات انجام تراکنش بیش از حد مجاز است', 41 | 75 => 'تعداد دفعات ورود رمز اشتباه از حد مجاز فراتر رفته است', 42 | 77 => 'روز مالی تراکنش نا معتبر است', 43 | 78 => 'کارت فعال نیست', 44 | 79 => 'حساب متصل به کارت بسته یا دارای اشکال است', 45 | 86 => 'شتاب در حال Sign Off است', 46 | 94 => 'تراکنش تکراری است', 47 | 96 => 'قوانین سامانه نقض گردیده است ، خطای داخلی سامانه', 48 | 97 => 'کد تولید کد اعتبار سنجی نا معتبر است', 49 | 98 => 'سقف استفاده از رمز دوم ایستا به پایان رسیده است', 50 | 901 => 'درخواست نا معتبر است ( Tokenization )', 51 | 902 => 'پارامترهای اضافی درخواست نامعتبر می باشد ( Tokenization )', 52 | 903 => 'شناسه پرداخت نامعتبر می باشد ( Tokenization )', 53 | 904 => 'اطلاعات مرتبط با قبض نا معتبر می باشد ( Tokenization )', 54 | 905 => 'شناسه درخواست نامعتبر می باشد ( Tokenization )', 55 | 906 => 'درخواست تاریخ گذشته است ( Tokenization )', 56 | 907 => 'آدرس بازگشت نتیجه پرداخت نامعتبر می باشد ( Tokenization )', 57 | 909 => 'پذیرنده نامعتبر می باشد ( Tokenization )', 58 | 910 => 'پارامترهای مورد انتظار پرداخت تسهیمی تامین نگردیده است ( Tokenization )', 59 | 911 => 'پارامترهای مورد انتظار پرداخت تسهیمی نا معتبر یا دارای اشکال می باشد ( Tokenization )', 60 | 912 => 'تراکنش درخواستی برای پذیرنده فعال نیست ( Tokenization )', 61 | 913 => 'تراکنش تسهیم برای پذیرنده فعال نیست ( Tokenization )', 62 | 914 => 'آدرس آی پی دریافتی درخواست نا معتبر می باشد', 63 | 915 => 'شماره پایانه نامعتبر می باشد ( Tokenization )', 64 | 916 => 'شماره پذیرنده نا معتبر می باشد ( Tokenization )', 65 | 917 => 'نوع تراکنش اعلام شده در خواست نا معتبر می باشد ( Tokenization )', 66 | 918 => 'پذیرنده فعال نیست ( Tokenization )', 67 | 919 => 'مبالغ تسهیمی ارائه شده با توجه به قوانین حاکم بر وضعیت تسهیم پذیرنده ، نا معتبر است ( Tokenization )', 68 | 920 => 'شناسه نشانه نامعتبر می باشد', 69 | 921 => 'شناسه نشانه نامعتبر و یا منقضی شده است', 70 | 922 => 'نقض امنیت درخواست ( Tokenization )', 71 | 923 => 'ارسال شناسه پرداخت در تراکنش قبض مجاز نیست ( Tokenization )', 72 | 925 => 'مبلغ مبادله شده نا معتبر می باشد', 73 | 928 => 'مبلغ مبادله شده نا معتبر می باشد ( Tokenization )', 74 | 929 => 'شناسه پرداخت ارائه شده با توجه به الگوریتم متناظر نا معتبر می باشد ( Tokenization )', 75 | 930 => 'کد ملی ارائه شده نا معتبر می باشد ( Tokenization )', 76 | ]; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Providers/JiBit/JiBit.php: -------------------------------------------------------------------------------- 1 | $transaction->getAmount()->getRiyal(), 40 | 'callBackUrl' => $this->getCallback($transaction), 41 | 'userIdentity' => $transaction->getExtraField('mobile'), 42 | 'merchantOrderId' => $transaction->getOrderId(), 43 | 'additionalData' => $transaction->getExtraField('additional'), 44 | 'description' => $transaction->getExtraField('description'), 45 | ]; 46 | 47 | [$response] = Curl::execute(self::SERVER_URL.self::URL_PATH_INITIATE, $fields, true, [ 48 | CURLOPT_SSL_VERIFYPEER => false, 49 | CURLOPT_HTTPHEADER => $this->generateHeaders(), 50 | ]); 51 | 52 | if (! isset($response['errorCode']) || $response['errorCode'] !== 0) { 53 | throw new JiBitException($response['errorCode'] ?? 0, $response['message'] ?? null); 54 | } 55 | 56 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, $response['result']['redirectUrl']); 57 | 58 | return AuthorizedTransaction::make($transaction, $response['result']['orderId'], null, $redirectResponse); 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | */ 64 | protected function validateSettlementRequest(Request $request) 65 | { 66 | $status = $request->input('status'); 67 | 68 | if ($status != 'PURCHASE_BY_USER') { 69 | throw new JiBitException($status); 70 | } 71 | 72 | return new FieldsToMatch(); 73 | } 74 | 75 | /** 76 | * {@inheritdoc} 77 | */ 78 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 79 | { 80 | [$response] = Curl::execute( 81 | self::SERVER_URL.self::URL_PATH_VERIFY.$transaction->getReferenceId(), 82 | [], 83 | true, 84 | [ 85 | CURLOPT_SSL_VERIFYPEER => false, 86 | CURLOPT_HTTPHEADER => $this->generateHeaders(), 87 | ] 88 | ); 89 | 90 | if (! isset($response['errorCode']) || $response['errorCode'] != 0) { 91 | throw new JiBitException($response['message'] ?? 0, @$response['errorCode'] ?? null); 92 | } 93 | 94 | $toMatch = new FieldsToMatch(); 95 | 96 | return new SettledTransaction( 97 | $transaction, 98 | $response['result']['refId'], 99 | $toMatch, 100 | '', 101 | '', 102 | $response['result'] 103 | ); 104 | } 105 | 106 | /** 107 | * Inquiry the transaction's status and return its response 108 | * 109 | * @return array 110 | * 111 | * @throws TransactionException 112 | * @throws Exception 113 | */ 114 | protected function inquiryTransaction(AuthorizedTransaction $transaction) 115 | { 116 | [$response] = Curl::execute( 117 | self::SERVER_URL.self::URL_PATH_INQUIRY.$transaction->getReferenceId(), 118 | [], 119 | true, 120 | [ 121 | CURLOPT_SSL_VERIFYPEER => false, 122 | CURLOPT_HTTPHEADER => $this->generateHeaders(), 123 | ] 124 | ); 125 | 126 | return $response; 127 | } 128 | 129 | /** 130 | * @throws JiBitException 131 | */ 132 | protected function generateHeaders(): array 133 | { 134 | return [ 135 | 'Accept: application/json', 136 | 'Content-Type: application/json', 137 | 'Authorization: Bearer '.$this->getToken(), 138 | ]; 139 | } 140 | 141 | /** 142 | * Get a token from server 143 | * 144 | * @return string 145 | * 146 | * @throws JiBitException 147 | */ 148 | protected function getToken() 149 | { 150 | $fields = [ 151 | 'username' => $this->config['api-key'], 152 | 'password' => $this->config['api-secret'], 153 | ]; 154 | 155 | [$response] = Curl::execute(self::SERVER_URL.self::URL_PATH_AUTHENTICATE, $fields, true, [ 156 | CURLOPT_SSL_VERIFYPEER => false, 157 | ]); 158 | 159 | if (! isset($response['errorCode']) || $response['errorCode'] !== 0) { 160 | throw new JiBitException($response['errorCode'] ?? 0, $response['message'] ?? null); 161 | } 162 | 163 | return $response['result']['token']; 164 | } 165 | 166 | /** 167 | * {@inheritdoc} 168 | */ 169 | public function getSupportedExtraFieldsSample() 170 | { 171 | return [ 172 | 'mobile' => '09124441122', 173 | 'additional' => 'Optional additional data (optional)', 174 | 'description' => 'Description will be show in Jibit QR payment gateway (optional)', 175 | ]; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/Providers/JiBit/JiBitException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 'INITIAL' => 'درخواست Initiate Order انجام شده و OrderId دریافت شده است', 18 | 'PGENTRY' => 'کاربر به درگاه جیبیت منتقل شده است', 19 | 'CANCEL_BY_SYSTEM' => 'درخواست پرداخت توسط سیستم لغو شده است )به عنوان مثال در صورتی که پس از 1۵ دقیقه verify انجام نشود پرداخت به صورت سیستمی لغو خواهد شد(', 20 | 'CANCEL_BY_USER' => 'درخواست پرداخت توسط کاربر لغو شده است', 21 | 'PURCHASE_BY_USER' => 'پرداخت توسط کاربر انجام شده است، اما هنوز Verify نشده است', 22 | 'PURCHASE_CONFIRM_BY_MERCHANT' => 'پرداخت توسط کاربر پرداخت و توسط پذیرنده verify شده است', 23 | ]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Providers/Jibimo/Jibimo.php: -------------------------------------------------------------------------------- 1 | $transaction->getAmount()->getRiyal(), 33 | 'return_url' => $this->getCallback($transaction), 34 | 'check_national_code' => $transaction->getExtraField('check_national_code', false), 35 | ]; 36 | $mobile = $transaction->getExtraField('mobile'); 37 | if (! empty($mobile)) { 38 | $fields['mobile_number'] = '+98'.substr($mobile, 1); 39 | } 40 | $allowedCards = $transaction->getExtraField('allowed_card'); 41 | if (! empty($allowedCards)) { 42 | $fields['authorized_card_numbers'] = $allowedCards; 43 | } 44 | 45 | [$result, $http_code] = Curl::execute(self::SERVER_URL.'request', $fields, true, [ 46 | CURLOPT_HTTPHEADER => $this->generateHeaders(), 47 | ]); 48 | 49 | if ($http_code != 200) { 50 | throw new JibimoException($http_code, print_r($result['errors'], true) ?: null); 51 | } 52 | 53 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, $result['link']); 54 | 55 | return AuthorizedTransaction::make($transaction, $result['trx'], null, $redirectResponse); 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | protected function validateSettlementRequest(Request $request) 62 | { 63 | if (! $request->has('status')) { 64 | throw new InvalidRequestException(); 65 | } 66 | 67 | $status = $request->input('status'); 68 | if ($status != 1) { 69 | throw new JibimoException($request->input('state_code')); 70 | } 71 | 72 | return new FieldsToMatch(null, $request->input('trx')); 73 | } 74 | 75 | /** 76 | * {@inheritdoc} 77 | */ 78 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 79 | { 80 | $fields = [ 81 | 'trx' => $transaction->getReferenceId(), 82 | ]; 83 | 84 | [$result, $http_code] = Curl::execute(self::SERVER_URL.'verify', $fields, true, [ 85 | CURLOPT_HTTPHEADER => $this->generateHeaders(), 86 | ]); 87 | 88 | if ($http_code != 200 || empty($result['status']) || $result['status'] != 1) { 89 | throw new JibimoException($result['state_code'] ?? $http_code); 90 | } 91 | 92 | $tracking_id = $result['tracking_id']; 93 | $amount = $result['amount']; 94 | $trace_number = $result['trace_number']; 95 | $card_number = $result['card_number']; 96 | 97 | $toMatch = new FieldsToMatch(null, $tracking_id, null, new Amount($amount, 'IRR')); 98 | 99 | return new SettledTransaction($transaction, $trace_number, $toMatch, $card_number, '', [ 100 | 'card_hash' => $result['card_hash'], 101 | 'card_owner' => $result['card_owner'], 102 | 'date' => $result['date'], 103 | ]); 104 | } 105 | 106 | public function inquiry(string $transactionId): array 107 | { 108 | return Curl::execute(self::SERVER_URL.'trx/'.$transactionId, [], true, [ 109 | CURLOPT_HTTPHEADER => $this->generateHeaders(true), 110 | ], Curl::METHOD_GET); 111 | } 112 | 113 | /** 114 | * @return string[] 115 | */ 116 | protected function generateHeaders(bool $isGetRequest = false): array 117 | { 118 | $headers = [ 119 | 'Accept: application/json', 120 | 'X-API-KEY: '.$this->config['api-key'], 121 | ]; 122 | 123 | if (! $isGetRequest) { 124 | $headers[] = 'Content-Type: application/json'; 125 | } 126 | 127 | return $headers; 128 | } 129 | 130 | /** 131 | * {@inheritdoc} 132 | */ 133 | public function getSupportedExtraFieldsSample() 134 | { 135 | return [ 136 | 'mobile' => '09124441122', 137 | 'check_national_code' => '(bool) true || false (default is false)'. 138 | 'در صورتی که نیاز دارید که کد ملی دارنده کارت با کد ملی مربوط به صاحب شماره موبایل مطابقت داده شود'. 139 | ' و در صورت عدم تطابق، تراکنش انجام نگردد مقدار این فیلد را true ارسال نمایید.'. 140 | ' در صورتی که این فیلد true ارسال شود، شماره موبایل هم اجباری خواهد شد.', 141 | 'allowed_card' => '(string[] list)'. 142 | 'در صورتی که نیاز دارید تراکنش کاربر فقط با شماره کارت‌های مشخصی امکان پذیر باشد'. 143 | ' و در غیر این صورت تراکنش انجام نگردد، این شماره کارت‌ها به صورت آرایه‌ای از طریق این فیلد ارسال گردد', 144 | ]; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/Providers/Jibimo/JibimoException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 0 => 'کاربر هنوز وارد درگاه نشده', 18 | -3 => 'کاربر در درگاه بانکی روی انصراف کلیک کرده است', 19 | -4 => 'خطا در پرداخت (با پشتیبانی تماس بگیرید)', 20 | 99 => 'پول از حساب کاربر برداشت شده و منتظر verify شدن است', 21 | 100 => 'تراکنش با موفقیت تایید شد', 22 | 101 => 'تراکنش قبلاً تایید شده است', 23 | ]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Providers/Mellat/MellatException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 0 => 'تراکنش با موفقيت انجام شد', 18 | 11 => 'شماره کارت نامعتبر است', 19 | 12 => 'موجودی کافی نیست', 20 | 13 => 'رمز نادرست است', 21 | 14 => 'تعداد دفعات وارد کردن رمز بیش از حد مجاز است', 22 | 15 => 'کارت نامعتبر است', 23 | 16 => 'دفعات برداشت وجه بیش از حد مجاز است', 24 | 17 => 'کاربر از انجام تراکنش منصرف شده است', 25 | 18 => 'تاریخ انقضای کارت گذشته است', 26 | 19 => 'مبلغ برداشت وجه بیش از حد مجاز است', 27 | 111 => 'صادر کننده کارت نامعتبر است', 28 | 112 => 'خطای سوییچ صادر کننده کارت', 29 | 113 => 'پاسخی از صادر کننده کارت دریافت نشد', 30 | 114 => 'دارنده این کارت مجاز به انجام این تراکنش نیست', 31 | 21 => 'پذیرنده نامعتبر است', 32 | 23 => 'خطای امنیتی رخ داده است', 33 | 24 => 'اطلاعات کاربری پذیرنده نامعتبر است', 34 | 25 => 'مبلغ نامعتبر است', 35 | 31 => 'پاسخ نامعتبر است', 36 | 32 => 'فرمت اطلاعات وارد شده صحیح نمی‌باشد', 37 | 33 => 'حساب نامعتبر است', 38 | 34 => 'خطای سیستمی', 39 | 35 => 'تاریخ نامعتبر است', 40 | 41 => 'شماره درخواست تکراری است', 41 | 42 => 'تراکنش Sale یافت نشد', 42 | 43 => 'قبلا درخواست Verfiy داده شده است', 43 | 44 => 'درخواست Verfiy یافت نشد', 44 | 45 => 'تراکنش Settle شده است', 45 | 46 => 'تراکنش Settle نشده است', 46 | 47 => 'تراکنش Settle یافت نشد', 47 | 48 => 'تراکنش Reverse شده است', 48 | 49 => 'تراکنش Refund یافت نشد.', 49 | 412 => 'شناسه قبض نادرست است', 50 | 413 => 'شناسه پرداخت نادرست است', 51 | 414 => 'سازمان صادر کننده قبض نامعتبر است', 52 | 415 => 'مدت زمان مجاز برای انجام تراکنش به پایان رسیده است', 53 | 416 => 'خطا در ثبت اطلاعات', 54 | 417 => 'شناسه پرداخت کننده نامعتبر است', 55 | 418 => 'اشکال در تعریف اطلاعات مشتری', 56 | 419 => 'تعداد دفعات ورود اطلاعات از حد مجاز گذشته است', 57 | 421 => 'IP نامعتبر است', 58 | 51 => 'تراکنش تکراری است', 59 | 54 => 'تراکنش مرجع موجود نیست', 60 | 55 => 'تراکنش نامعتبر است', 61 | 61 => 'خطا در واریز', 62 | 62 => 'مسير بازگشت به سايت در دامنه ثبت شده برای پذيرنده قرار ندارد', 63 | 98 => 'سقف استفاده از رمز ايستا به پايان رسيده است', 64 | ]; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Providers/Milyoona/Milyoona.php: -------------------------------------------------------------------------------- 1 | $transaction->getAmount()->getToman(), 40 | 'callback_url' => $this->getCallback($transaction), 41 | 'order_id' => str_pad($transaction->getOrderId(), 16, '0'), 42 | 'mobile' => $transaction->getExtraField('mobile'), 43 | 'national_code' => $transaction->getExtraField('national_code'), 44 | 'card_no' => $transaction->getExtraField('allowed_card'), 45 | 'description' => $transaction->getExtraField('description'), 46 | ]; 47 | 48 | $result = $this->callApi('token', $fields); 49 | 50 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, self::GATE_URL.$result['token']); 51 | 52 | return AuthorizedTransaction::make($transaction, $result['request_id'], $result['token'], $redirectResponse); 53 | } 54 | 55 | /** 56 | * {@inheritdoc} 57 | */ 58 | protected function validateSettlementRequest(Request $request) 59 | { 60 | if (! $request->has('status')) { 61 | throw new InvalidRequestException(); 62 | } 63 | 64 | $status = $request->input('status'); 65 | if ($status != 'OK') { 66 | throw new MilyoonaException($status); 67 | } 68 | 69 | return new FieldsToMatch(null, null, $request->input('token')); 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | */ 75 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 76 | { 77 | $result = $this->callApi('verify', ['token' => $transaction->getToken()]); 78 | 79 | $token = $result['token']; 80 | $request_id = $result['request_id']; 81 | $order_id = $result['order_id']; 82 | $amount = $result['amount']; 83 | $cardNumber = $result['card_number']; 84 | $fee = $result['fee']; 85 | $paid_at = $result['paid_at']; 86 | 87 | $toMatch = new FieldsToMatch($order_id, $request_id, $token, new Amount($amount)); 88 | 89 | return new SettledTransaction( 90 | $transaction, 91 | $request_id, 92 | $toMatch, 93 | $cardNumber, 94 | '', 95 | ['verify_result' => $result] + compact('fee', 'paid_at') 96 | ); 97 | } 98 | 99 | /** 100 | * @throws MilyoonaException 101 | */ 102 | public function trace(string $token): array 103 | { 104 | return $this->callApi('trace', compact('token')); 105 | } 106 | 107 | /** 108 | * @return mixed 109 | * 110 | * @throws MilyoonaException 111 | */ 112 | protected function callApi(string $path, array $fields) 113 | { 114 | $fields['terminal'] = $this->config['terminal-id']; 115 | [$response, $http_code] = Curl::execute(self::SERVER_URL.$path, $fields); 116 | 117 | if ($http_code != 200 || ! isset($response['status']) || ! in_array($response['status'], [0, 5])) { 118 | throw new MilyoonaException( 119 | $response['status'] ?? $http_code, 120 | ! empty($response['errors']) ? json_encode($response['errors'], JSON_UNESCAPED_UNICODE) : null 121 | ); 122 | } 123 | 124 | return $response['data']; 125 | } 126 | 127 | /** 128 | * {@inheritdoc} 129 | */ 130 | public function getSupportedExtraFieldsSample() 131 | { 132 | return [ 133 | 'mobile' => '09124441122', 134 | 'national_code' => '(اختیاری) در صورت ارسال کدملی پرداخت کننده،'. 135 | ' شماره کارت پرداخت کننده می‌بایست متعلق به کد ملی ارسالی باشد.', 136 | 'allowed_card' => '(اختیاری) در صورت ارسال شماره کارت،'. 137 | ' کاربر تنها قادر به پرداخت وجه با آن شماره کارت خواهد بود.', 138 | 'description' => '(اختیاری) توضیحات ارسالی در پنل کاربری میلیونا به شما نمایش داده خواهد شد.', 139 | ]; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/Providers/Milyoona/MilyoonaException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 'NOK' => 'عملیات پرداخت ناموفق بوده', 18 | 19 | 0 => 'عملیات با موفقیت انجام شد', 20 | 1 => 'تراکنش ناموفق', 21 | 2 => 'مبلغ تراکنش مجاز نیست', 22 | 3 => 'عدم تطابق شماره کارت با پرداخت کننده', 23 | 4 => 'تراکنش استفاده شده', 24 | 5 => 'تراکنش یکبار تائید شده است', 25 | 6 => 'ترمیال مسدود است', 26 | 10 => 'از انجام تراکنش صرف نظر شد', 27 | 11 => 'پذیرنده نامعتبر است', 28 | 24 => 'عدم تطابق کد ملی خریدار با دارنده کارت', 29 | 25 => 'توکن معتبر نمی باشد', 30 | 26 => 'انجام تراکنش با یک کارت خاص از طرف پذیرنده محدود شده است', 31 | 27 => 'ترمینال غیر فعال است', 32 | 28 => 'آیپی معتبر نمی باشد', 33 | 29 => 'مهلت تایید تراکنش به اتمام رسیده است', 34 | 30 => 'مهلت استفاده از کد تخفیف به اتمام رسیده است', 35 | 31 => 'محصول مورد نظر شما به اتمام رسیده است', 36 | 400 => 'خطا در اطلاعات ارسالی', 37 | 500 => 'خطای داخلی سرور', 38 | ]; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Providers/NextPay/NextPayException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 0 => 'پرداخت تکمیل و با موفقیت انجام شده است', 18 | -1 => 'منتظر ارسال تراکنش و ادامه پرداخت', 19 | -2 => 'پرداخت رد شده توسط کاربر یا بانک', 20 | -3 => 'پرداخت در حال انتظار جواب بانک', 21 | -4 => 'پرداخت لغو شده است', 22 | -20 => 'کد api_key ارسال نشده است', 23 | -21 => 'کد trans_id ارسال نشده است', 24 | -22 => 'مبلغ ارسال نشده', 25 | -23 => 'لینک ارسال نشده', 26 | -24 => 'مبلغ صحیح نیست', 27 | -25 => 'تراکنش قبلا انجام و قابل ارسال نیست', 28 | -26 => 'مقدار توکن ارسال نشده است', 29 | -27 => 'شماره سفارش صحیح نیست', 30 | -28 => 'مقدار فیلد سفارشی [custom_json_fields] از نوع json نیست', 31 | -29 => 'کد بازگشت مبلغ صحیح نیست', 32 | -30 => 'مبلغ کمتر از حداقل پرداختی است', 33 | -31 => 'صندوق کاربری موجود نیست', 34 | -32 => 'مسیر بازگشت صحیح نیست', 35 | -33 => 'کلید مجوز دهی صحیح نیست', 36 | -34 => 'کد تراکنش صحیح نیست', 37 | -35 => 'ساختار کلید مجوز دهی صحیح نیست', 38 | -36 => 'شماره سفارش ارسال نشد است', 39 | -37 => 'شماره تراکنش یافت نشد', 40 | -38 => 'توکن ارسالی موجود نیست', 41 | -39 => 'کلید مجوز دهی موجود نیست', 42 | -40 => 'کلید مجوزدهی مسدود شده است', 43 | -41 => 'خطا در دریافت پارامتر، شماره شناسایی صحت اعتبار که از بانک ارسال شده موجود نیست', 44 | -42 => 'سیستم پرداخت دچار مشکل شده است', 45 | -43 => 'درگاه پرداختی برای انجام درخواست یافت نشد', 46 | -44 => 'پاسخ دریاف شده از بانک نامعتبر است', 47 | -45 => 'سیستم پرداخت غیر فعال است', 48 | -46 => 'درخواست نامعتبر', 49 | -47 => 'کلید مجوز دهی یافت نشد [حذف شده]', 50 | -48 => 'نرخ کمیسیون تعیین نشده است', 51 | -49 => 'تراکنش مورد نظر تکراریست', 52 | -50 => 'حساب کاربری برای صندوق مالی یافت نشد', 53 | -51 => 'شناسه کاربری یافت نشد', 54 | -52 => 'حساب کاربری تایید نشده است', 55 | -60 => 'ایمیل صحیح نیست', 56 | -61 => 'کد ملی صحیح نیست', 57 | -62 => 'کد پستی صحیح نیست', 58 | -63 => 'آدرس پستی صحیح نیست و یا بیش از ۱۵۰ کارکتر است', 59 | -64 => 'توضیحات صحیح نیست و یا بیش از ۱۵۰ کارکتر است', 60 | -65 => 'نام و نام خانوادگی صحیح نیست و یا بیش از ۳۵ کاکتر است', 61 | -66 => 'تلفن صحیح نیست', 62 | -67 => 'نام کاربری صحیح نیست یا بیش از ۳۰ کارکتر است', 63 | -68 => 'نام محصول صحیح نیست و یا بیش از ۳۰ کارکتر است', 64 | -69 => 'آدرس ارسالی برای بازگشت موفق صحیح نیست و یا بیش از ۱۰۰ کارکتر است', 65 | -70 => 'آدرس ارسالی برای بازگشت ناموفق صحیح نیست و یا بیش از ۱۰۰ کارکتر است', 66 | -71 => 'موبایل صحیح نیست', 67 | -72 => 'بانک پاسخگو نبوده است لطفا با نکست پی تماس بگیرید', 68 | -73 => 'مسیر بازگشت دارای خطا میباشد یا بسیار طولانیست', 69 | -90 => 'بازگشت مبلغ بدرستی انجام شد', 70 | -91 => 'عملیات ناموفق در بازگشت مبلغ', 71 | -92 => 'در عملیات بازگشت مبلغ خطا رخ داده است', 72 | -93 => 'موجودی صندوق کاربری برای بازگشت مبلغ کافی نیست', 73 | -94 => 'کلید بازگشت مبلغ یافت نشد', 74 | 75 | -1000 => 'خطای تعریف نشده', 76 | ]; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Providers/Novin/NovinException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 'erSucceed' => 'سرویس با موفقیت اجرا شد', 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Providers/ParsPal/ParsPalException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | $errors = [ 17 | 200 => 'OK - دریافت موفق درخواست', 18 | 400 => 'Bad Request - خطا در اطلاعات یا انجام', 19 | 401 => 'Unauthorized - دسترسی غیر مجاز و یا عدم ارسال ApiKey', 20 | 21 | 'UNAUTHORIZED' => 'توکن شناسایی ApiKey ارسال نشده است', 22 | 'INVALID_APIKEY' => 'توکن شناسایی ApiKey صحیح نمی باشد', 23 | 'INVALID_AMOUNT' => 'مبلغ ارسالی صحیح نمی باشد', 24 | 'INVALID_RETURN_URL' => 'مسیر بازگشت ارسالی صحیح نمی باشد', 25 | 'INVALID_CURRENCY' => 'واحد پول ارسالی معتبر نمی باشد', 26 | 'INVALID_IP' => 'آی پی ارسال کننده درخواست معتبر نمی باشد', 27 | 'INACTIVE_GATEWAY' => 'درگاه/حساب غیر فعال است', 28 | 'BLOCKED_GATEWAY' => 'درگاه/حساب مسدود شده است', 29 | 'NOTREADY_GATEWAY' => 'درگاه راه اندازی نشده است', 30 | 'SERVICE_NOT_AVAILABLE' => 'در حال حاضر سرویس در دسترس نمی باشد', 31 | 'BAD_REQUEST' => 'محتوایی برای درخواست ارسال نشده است', 32 | 'UNKNOWN_ERROR' => 'خطای تعریف نشده', 33 | 34 | 100 => 'کاربر عملیات پرداخت را انجام داده است', 35 | 99 => 'انصراف کاربر از پرداخت', 36 | 88 => 'پرداخت ناموفق', 37 | 77 => 'لغو پرداخت توسط کاربر', 38 | 39 | 'ACCEPTED' => 'پذیرش موفقیت آمیز درخواست', 40 | 'FAILED' => 'عدم پذیرش درخواست', 41 | 'SUCCESSFUL' => 'تایید شماره رسید پرداخت', 42 | 'VERIFIED' => 'شماره رسید قبلا تایید گردیده است', 43 | 'AMOUNT_NOT_MATCH' => 'مبلغ اعلامی جهت تایید پرداخت با مبلغ پرداخت شده همخوانی ندارد', 44 | 'INVALID_RECEIPT_NUMBER' => 'شماره رسید پرداخت معتبر نمی باشد', 45 | 'INVALID_DATA' => 'عدم همخوانی یا نداشتن صحت اطلاعات', 46 | ]; 47 | 48 | return array_replace($errors, [ 49 | -2 => $errors['UNAUTHORIZED'], 50 | -1 => $errors['INVALID_APIKEY'], 51 | 1 => $errors['INVALID_AMOUNT'], 52 | 2 => $errors['INVALID_RETURN_URL'], 53 | 3 => $errors['INVALID_CURRENCY'], 54 | 4 => $errors['INVALID_IP'], 55 | 10 => $errors['INACTIVE_GATEWAY'], 56 | 11 => $errors['BLOCKED_GATEWAY'], 57 | 12 => $errors['NOTREADY_GATEWAY'], 58 | 20 => $errors['SERVICE_NOT_AVAILABLE'], 59 | 30 => $errors['BAD_REQUEST'], 60 | 99 => $errors['UNKNOWN_ERROR'], 61 | ]); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Providers/Parsian/Parsian.php: -------------------------------------------------------------------------------- 1 | $this->config['login-account'], 45 | 'Amount' => $transaction->getAmount()->getRiyal(), 46 | 'OrderId' => $transaction->getOrderId(), 47 | 'CallBackUrl' => $this->getCallback($transaction), 48 | 'AdditionalData' => $transaction->getExtraField('description'), 49 | ]; 50 | $mobile = $transaction->getExtraField('mobile'); 51 | if (! empty($mobile)) { 52 | $params['Originator'] = '98'.substr($mobile, 1); 53 | } 54 | 55 | $soap = new SoapClient(self::SERVER_URL, $this->soapConfig()); 56 | $response = $soap->SalePaymentRequest(['requestData' => $params]); 57 | 58 | if ($response->SalePaymentRequestResult->Status === 0) { 59 | $url = self::URL_GATE.$response->SalePaymentRequestResult->Token; 60 | 61 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_POST, $url, []); 62 | 63 | return AuthorizedTransaction::make( 64 | $transaction, 65 | null, 66 | $response->SalePaymentRequestResult->Token, 67 | $redirectResponse 68 | ); 69 | } 70 | 71 | throw new ParsianException( 72 | $response->SalePaymentRequestResult->Status, 73 | $response->SalePaymentRequestResult->Message 74 | ); 75 | } 76 | 77 | /** 78 | * {@inheritdoc} 79 | */ 80 | protected function validateSettlementRequest(Request $request) 81 | { 82 | $status = $request->input('status'); 83 | 84 | if ($status != 0) { 85 | throw new ParsianException($status); 86 | } 87 | 88 | $orderId = $request->input('OrderId'); 89 | $token = $request->input('Token'); 90 | $amount = $request->input('Amount'); 91 | 92 | return new FieldsToMatch($orderId, null, $token, new Amount($amount, 'IRR')); 93 | } 94 | 95 | /** 96 | * {@inheritdoc} 97 | */ 98 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 99 | { 100 | $traceNumber = $request->input('RRN'); 101 | 102 | $params = [ 103 | 'LoginAccount' => $this->config['login-account'], 104 | 'Token' => $transaction->getToken(), 105 | ]; 106 | 107 | $soap = new SoapClient(self::SERVER_VERIFY_URL, $this->soapConfig()); 108 | $result = $soap->ConfirmPayment(['requestData' => $params]); 109 | 110 | if ($result === false || ! isset($result->ConfirmPaymentResult->Status)) { 111 | throw new ParsianException(-1); 112 | } 113 | 114 | if ($result->ConfirmPaymentResult->Status !== 0) { 115 | throw new ParsianException($result->ConfirmPaymentResult->Status); 116 | } 117 | 118 | $toMatch = new FieldsToMatch(null, null, $result->ConfirmPaymentResult->Token); 119 | 120 | $cardNumber = $result->ConfirmPaymentResult->CardNumberMasked; 121 | 122 | return new SettledTransaction($transaction, $traceNumber, $toMatch, $cardNumber); 123 | } 124 | 125 | /** 126 | * {@inheritdoc} 127 | */ 128 | public function getSupportedExtraFieldsSample() 129 | { 130 | return [ 131 | 'mobile' => '09124441122', 132 | 'description' => 'رشته با طول حداکثر ۵۰۰ کاراکتر حاوی داده‌های اضافی است'. 133 | ' که پذیرنده می‌تواند به منظور بهره برداری‌های بعدی آن را به درگاه پرداخت ارسال نماید', 134 | ]; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/Providers/Pasargad/PasargadException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 200 => 'تراکنش ارسالی معتبر نیست', 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Providers/Pasargad/Utilities/RSA.php: -------------------------------------------------------------------------------- 1 | = 0; $i--) { 130 | $digit = ord($data[$i]); 131 | $part_res = bcmul($digit, $radix); 132 | $result = bcadd($result, $part_res); 133 | $radix = bcmul($radix, $base); 134 | } 135 | 136 | return $result; 137 | } 138 | 139 | public static function number_to_binary($number, $blocksize) 140 | { 141 | $base = '256'; 142 | $result = ''; 143 | $div = $number; 144 | while ($div > 0) { 145 | $mod = bcmod($div, $base); 146 | $div = bcdiv($div, $base); 147 | $result = chr($mod).$result; 148 | } 149 | 150 | return str_pad($result, $blocksize, "\x00", STR_PAD_LEFT); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/Providers/Pasargad/Utilities/RSAProcessor.php: -------------------------------------------------------------------------------- 1 | modulus = RSA::binary_to_number(base64_decode($xmlObj->Modulus)); 28 | $this->public_key = RSA::binary_to_number(base64_decode($xmlObj->Exponent)); 29 | $this->private_key = RSA::binary_to_number(base64_decode($xmlObj->D)); 30 | $this->key_length = strlen(base64_decode($xmlObj->Modulus)) * 8; 31 | } 32 | 33 | public function getPublicKey() 34 | { 35 | return $this->public_key; 36 | } 37 | 38 | public function getPrivateKey() 39 | { 40 | return $this->private_key; 41 | } 42 | 43 | public function getKeyLength() 44 | { 45 | return $this->key_length; 46 | } 47 | 48 | public function getModulus() 49 | { 50 | return $this->modulus; 51 | } 52 | 53 | public function encrypt($data) 54 | { 55 | return base64_encode(RSA::rsa_encrypt($data, $this->public_key, $this->modulus, $this->key_length)); 56 | } 57 | 58 | public function decrypt($data) 59 | { 60 | return RSA::rsa_decrypt($data, $this->private_key, $this->modulus, $this->key_length); 61 | } 62 | 63 | public function sign($data) 64 | { 65 | return RSA::rsa_sign($data, $this->private_key, $this->modulus, $this->key_length); 66 | } 67 | 68 | public function verify($data) 69 | { 70 | return RSA::rsa_verify($data, $this->public_key, $this->modulus, $this->key_length); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Providers/Pasargad/Utilities/XMLGenerator.php: -------------------------------------------------------------------------------- 1 | openMemory(); 13 | $xmlWriter->setIndent(true); 14 | $xmlWriter->setIndentString(' '); 15 | 16 | if ($xmlWriter) { 17 | $xmlWriter->startDocument('1.0', 'UTF-8'); 18 | 19 | foreach ($paymentItems as $item) { 20 | // 21 | $xmlWriter->startElement('item'); 22 | 23 | // 24 | $xmlWriter->startElement('iban'); 25 | $xmlWriter->text($item['IBAN']); 26 | $xmlWriter->endElement(); 27 | // 28 | 29 | // 30 | $xmlWriter->startElement('type'); 31 | $xmlWriter->text($item['type']); 32 | $xmlWriter->endElement(); 33 | // 34 | 35 | // 36 | $xmlWriter->startElement('value'); 37 | $xmlWriter->text($item['value']); 38 | $xmlWriter->endElement(); 39 | // 40 | 41 | $xmlWriter->endElement(); 42 | // 43 | } 44 | 45 | $xmlWriter->endDocument(); 46 | 47 | return $xmlWriter->outputMemory(true); 48 | } 49 | 50 | return null; 51 | } 52 | 53 | public static function generateSubPaymentList(array $subPayments): ?string 54 | { 55 | $xmlWriter = new XMLWriter(); 56 | $xmlWriter->openMemory(); 57 | $xmlWriter->setIndent(true); 58 | $xmlWriter->setIndentString(' '); 59 | 60 | if ($xmlWriter) { 61 | $xmlWriter->startDocument('1.0', 'UTF-8'); 62 | 63 | // 64 | $xmlWriter->startElement('SubPaymentList'); 65 | 66 | // 67 | $xmlWriter->startElement('SubPayments'); 68 | 69 | foreach ($subPayments as $subPayment) { 70 | // 71 | $xmlWriter->startElement('SubPayment'); 72 | 73 | // 74 | $xmlWriter->startElement('SubPayID'); 75 | $xmlWriter->text($subPayment['SubPayID']); 76 | $xmlWriter->endElement(); 77 | // 78 | 79 | // 80 | $xmlWriter->startElement('Amount'); 81 | $xmlWriter->text($subPayment['Amount']); 82 | $xmlWriter->endElement(); 83 | // 84 | 85 | // 86 | $xmlWriter->startElement('Date'); 87 | $xmlWriter->text($subPayment['Date']); 88 | $xmlWriter->endElement(); 89 | // 90 | 91 | // 92 | $xmlWriter->startElement('Account'); 93 | $xmlWriter->text($subPayment['Account']); 94 | $xmlWriter->endElement(); 95 | // 96 | 97 | // 98 | $xmlWriter->startElement('Description'); 99 | $xmlWriter->text($subPayment['Description'] ?? ''); 100 | $xmlWriter->endElement(); 101 | // 102 | 103 | $xmlWriter->endElement(); 104 | // 105 | } 106 | 107 | $xmlWriter->endElement(); 108 | // 109 | 110 | $xmlWriter->endElement(); 111 | // 112 | 113 | $xmlWriter->endDocument(); 114 | 115 | return $xmlWriter->outputMemory(true); 116 | } 117 | 118 | return null; 119 | } 120 | 121 | public static function generateInvoiceUpdateList(string $invoiceUID, array $actions): ?string 122 | { 123 | $xmlWriter = new XMLWriter(); 124 | $xmlWriter->openMemory(); 125 | $xmlWriter->setIndent(true); 126 | $xmlWriter->setIndentString(' '); 127 | 128 | if ($xmlWriter) { 129 | $xmlWriter->startDocument('1.0', 'UTF-8'); 130 | 131 | // 132 | $xmlWriter->startElement('invoiceUpdateList'); 133 | 134 | $xmlWriter->startElement('invoiceAction'); 135 | $xmlWriter->startAttribute('invoiceUID'); 136 | $xmlWriter->text($invoiceUID); 137 | $xmlWriter->endAttribute(); 138 | 139 | foreach ($actions as $action) { 140 | // 141 | $xmlWriter->startElement('action'); 142 | 143 | // type= 144 | $xmlWriter->startAttribute('type'); 145 | $xmlWriter->text($action['type']); 146 | $xmlWriter->endAttribute(); 147 | 148 | // subPayID= 149 | $xmlWriter->startAttribute('subPayID'); 150 | $xmlWriter->text($action['subPayID']); 151 | $xmlWriter->endAttribute(); 152 | 153 | // amount= 154 | $xmlWriter->startAttribute('amount'); 155 | $xmlWriter->text($action['amount']); 156 | $xmlWriter->endAttribute(); 157 | 158 | // date= 159 | $xmlWriter->startAttribute('date'); 160 | $xmlWriter->text($action['date']); 161 | $xmlWriter->endAttribute(); 162 | 163 | // account= 164 | $xmlWriter->startAttribute('account'); 165 | $xmlWriter->text($action['account']); 166 | $xmlWriter->endAttribute(); 167 | 168 | $xmlWriter->endElement(); 169 | // 170 | } 171 | 172 | $xmlWriter->endElement(); 173 | // 174 | 175 | $xmlWriter->endDocument(); 176 | 177 | return $xmlWriter->outputMemory(true); 178 | } 179 | 180 | return null; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/Providers/PayPing/PayPing.php: -------------------------------------------------------------------------------- 1 | $transaction->getOrderId(), 45 | 'payerIdentity' => $transaction->getExtraField('mobile'), 46 | 'payerName' => $transaction->getExtraField('name'), 47 | 'amount' => $transaction->getAmount()->getToman(), 48 | 'description' => $transaction->getExtraField('description'), 49 | 'returnUrl' => $this->getCallback($transaction), 50 | ]; 51 | 52 | [$response, $http_code, $error] = Curl::execute(self::SERVER_URL, $fields, true, [ 53 | CURLOPT_TIMEOUT => 45, 54 | CURLOPT_HTTPHEADER => $this->generateHeaders(), 55 | ]); 56 | 57 | if ($error) { 58 | throw new PayPingException($error); 59 | } 60 | 61 | if ($http_code == 400) { 62 | throw new PayPingException(400, json_encode($response, JSON_UNESCAPED_UNICODE)); 63 | } elseif ($http_code != 200) { 64 | throw new PayPingException($http_code); 65 | } 66 | 67 | if (empty($response)) { 68 | throw new PayPingException(200, 'تراکنش ناموفق بود - شرح خطا: عدم وجود کد ارجاع'); 69 | } 70 | 71 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, self::URL_GATE.$response['code']); 72 | 73 | return AuthorizedTransaction::make($transaction, $response['code'], null, $redirectResponse); 74 | } 75 | 76 | /** 77 | * {@inheritdoc} 78 | */ 79 | protected function validateSettlementRequest(Request $request) 80 | { 81 | if (! $request->has('refid')) { 82 | throw new InvalidRequestException(); 83 | } 84 | 85 | $referenceId = $request->input('refid'); 86 | if (! $referenceId) { 87 | throw new PayPingException($referenceId); 88 | } 89 | 90 | return new FieldsToMatch($request->input('clientrefid')); 91 | } 92 | 93 | /** 94 | * {@inheritdoc} 95 | */ 96 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 97 | { 98 | $refId = $request->input('refid'); 99 | $code = $request->input('code'); 100 | $cardNumber = $request->input('cardnumber'); 101 | $hashed_card_number = $request->input('cardhashpan'); 102 | 103 | $fields = [ 104 | 'refId' => $refId, 105 | 'amount' => $transaction->getAmount()->getToman(), 106 | ]; 107 | 108 | [$result, $http_code, $error] = Curl::execute(self::SERVER_VERIFY_URL, $fields, true, [ 109 | CURLOPT_TIMEOUT => 45, 110 | CURLOPT_HTTPHEADER => $this->generateHeaders(), 111 | ]); 112 | 113 | if ($error) { 114 | throw new PayPingException($error); 115 | } 116 | 117 | if ($http_code == 400) { 118 | throw new PayPingException(400, json_encode($result, JSON_UNESCAPED_UNICODE)); 119 | } elseif ($http_code != 200) { 120 | throw new PayPingException($http_code); 121 | } 122 | 123 | if (empty($refId)) { 124 | throw new PayPingException( 125 | 200, 126 | 'متافسانه سامانه قادر به دریافت کد پیگیری نمی‌باشد! نتیجه درخواست: '.$http_code 127 | ); 128 | } 129 | 130 | $cardNumber = $result['cardNumber'] ?? $cardNumber ?? ''; 131 | $extra = ['verify_result' => $result] + compact('code', 'hashed_card_number'); 132 | $toMatch = new FieldsToMatch(); 133 | 134 | return new SettledTransaction($transaction, $refId, $toMatch, $cardNumber, '', $extra); 135 | } 136 | 137 | protected function generateHeaders(): array 138 | { 139 | return [ 140 | 'Accept: application/json', 141 | 'Content-Type: application/json', 142 | 'Authorization: Bearer '.$this->config['api-key'], 143 | 'Cache-Control: no-cache', 144 | ]; 145 | } 146 | 147 | /** 148 | * {@inheritdoc} 149 | */ 150 | public function getSupportedExtraFieldsSample() 151 | { 152 | return [ 153 | 'mobile' => '09124441122', 154 | 'name' => 'نام پرداخت کننده', 155 | 'description' => 'توضیحات', 156 | ]; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/Providers/PayPing/PayPingException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 1 => 'تراكنش توسط شما لغو شد', 18 | 2 => 'رمز کارت اشتباه است.', 19 | 3 => 'cvv2 یا تاریخ انقضای کارت وارد نشده است', 20 | 4 => 'موجودی کارت کافی نیست.', 21 | 5 => 'تاریخ انقضای کارت گذشته است و یا اشتباه وارد شده.', 22 | 6 => 'کارت شما مسدود شده است', 23 | 7 => 'تراکنش مورد نظر توسط درگاه یافت نشد', 24 | 8 => 'بانک صادر کننده کارت شما مجوز انجام تراکنش را صادر نکرده است', 25 | 9 => 'مبلغ تراکنش مشکل دارد', 26 | 10 => 'شماره کارت اشتباه است.', 27 | 11 => 'ارتباط با درگاه برقرار نشد، مجددا تلاش کنید', 28 | 12 => 'خطای داخلی بانک رخ داده است', 29 | 15 => 'این تراکنش قبلا تایید شده است', 30 | 18 => 'کاربر پذیرنده تایید نشده است', 31 | 19 => 'هویت پذیرنده کامل نشده است و نمی تواند در مجموع بیشتر از ۵۰ هزار تومان دریافتی داشته باشد', 32 | 25 => 'سرویس موقتا از دسترس خارج است، لطفا بعدا مجددا تلاش نمایید', 33 | 26 => 'کد پرداخت پیدا نشد', 34 | 27 => 'پذیرنده مجاز به تراکنش با این مبلغ نمی باشد', 35 | 28 => 'لطفا از قطع بودن فیلتر شکن خود مطمئن شوید', 36 | 29 => 'ارتباط با درگاه برقرار نشد', 37 | 31 => 'امکان تایید پرداخت قبل از ورود به درگاه بانک وجود ندارد', 38 | 38 => 'آدرس سایت پذیرنده نا معتبر است', 39 | 39 => 'پرداخت ناموفق، مبلغ به حساب پرداخت کننده برگشت داده خواهد شد', 40 | 44 => 'RefId نامعتبر است', 41 | 46 => 'توکن ساخت پرداخت با توکن تایید پرداخت مغایرت دارد', 42 | 47 => 'مبلغ تراکنش مغایرت دارد', 43 | 48 => 'پرداخت از سمت شاپرک تایید نهایی نشده است', 44 | 49 => 'ترمینال فعال یافت نشد، لطفا مجددا تلاش کنید', 45 | ]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Providers/Payir/Payir.php: -------------------------------------------------------------------------------- 1 | $transaction->getAmount()->getRiyal(), 39 | 'redirect' => $this->getCallback($transaction, true), 40 | 'mobile' => $transaction->getExtraField('mobile'), 41 | 'factorNumber' => $transaction->getOrderId(), 42 | 'description' => $transaction->getExtraField('description'), 43 | 'validCardNumber' => $transaction->getExtraField('allowed_card'), 44 | ]; 45 | 46 | $result = $this->callApi('send', $fields); 47 | 48 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, self::URL_GATE.$result['token']); 49 | 50 | return AuthorizedTransaction::make($transaction, null, $result['token'], $redirectResponse); 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | */ 56 | protected function validateSettlementRequest(Request $request) 57 | { 58 | if (! $request->has('status')) { 59 | throw new InvalidRequestException(); 60 | } 61 | 62 | $status = $request->input('status'); 63 | if ($status != 1) { 64 | throw new PayirException($status ?: -5); 65 | } 66 | 67 | $token = $request->input('token'); 68 | 69 | return new FieldsToMatch(null, null, $token); 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | */ 75 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 76 | { 77 | $result = $this->callApi('verify', ['token' => $transaction->getToken()]); 78 | 79 | $toMatch = new FieldsToMatch($result['factorNumber'], null, null, new Amount($result['amount'], 'IRR')); 80 | 81 | return new SettledTransaction( 82 | $transaction, 83 | $result['transId'], 84 | $toMatch, 85 | $result['cardNumber'], 86 | '', 87 | ['verify_result' => $result] 88 | ); 89 | } 90 | 91 | /** 92 | * @return mixed 93 | * 94 | * @throws PayirException 95 | */ 96 | protected function callApi(string $path, array $fields) 97 | { 98 | $fields['api'] = $this->config['api-key']; 99 | [$response, $http_code, $error] = Curl::execute(self::SERVER_URL.$path, $fields, true, [ 100 | CURLOPT_SSL_VERIFYPEER => false, 101 | ], Curl::METHOD_GET); 102 | 103 | if ($http_code != 200 || empty($response['status']) || $response['status'] != 1) { 104 | throw new PayirException( 105 | $response['errorCode'] ?? $http_code, 106 | $response['errorMessage'] ?? $error ?? null 107 | ); 108 | } 109 | 110 | return $response; 111 | } 112 | 113 | /** 114 | * {@inheritdoc} 115 | */ 116 | public function getSupportedExtraFieldsSample() 117 | { 118 | return [ 119 | 'mobile' => '09124441122', 120 | 'factor_number' => 'شماره فاکتور شما ( اختیاری )', 121 | 'description' => 'توضیحات تراکنش ( اختیاری ، حداکثر 255 کاراکتر )', 122 | 'allowed_card' => 'اعلام شماره کارت مجاز برای انجام تراکنش'. 123 | ' ( اختیاری، بصورت عددی (لاتین) و چسبیده بهم در 16 رقم. مثال 6219861012345678 )', 124 | ]; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Providers/Payir/PayirException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 0 => 'درحال حاضر درگاه بانکی قطع شده و مشکل بزودی برطرف می شود', 18 | -1 => 'API Key ارسال نمی شود', 19 | -2 => 'Token ارسال نمی شود', 20 | -3 => 'API Key ارسال شده اشتباه است', 21 | -4 => 'امکان انجام تراکنش برای این پذیرنده وجود ندارد', 22 | -5 => 'تراکنش با خطا مواجه شده است', 23 | -6 => 'تراکنش تکراریست یا قبلا انجام شده', 24 | -7 => 'مقدار Token ارسالی اشتباه است', 25 | -8 => 'شماره تراکنش ارسالی اشتباه است', 26 | -9 => 'زمان مجاز برای انجام تراکنش تمام شده', 27 | -10 => 'مبلغ تراکنش ارسال نمی شود', 28 | -11 => 'مبلغ تراکنش باید به صورت عددی و با کاراکترهای لاتین باشد', 29 | -12 => 'مبلغ تراکنش می بایست عددی بین 10,000 و 500,000,000 ریال باشد', 30 | -13 => 'مقدار آدرس بازگشتی ارسال نمی شود', 31 | -14 => 'آدرس بازگشتی ارسالی با آدرس درگاه ثبت شده در شبکه پرداخت پی یکسان نیست', 32 | -15 => 'امکان وریفای وجود ندارد. این تراکنش پرداخت نشده است', 33 | -16 => 'یک یا چند شماره موبایل از اطلاعات پذیرندگان ارسال شده اشتباه است', 34 | -17 => 'میزان سهم ارسالی باید بصورت عددی و بین 1 تا 100 باشد', 35 | -18 => 'فرمت پذیرندگان صحیح نمی باشد', 36 | -19 => 'هر پذیرنده فقط یک سهم میتواند داشته باشد', 37 | -20 => 'مجموع سهم پذیرنده ها باید 100 درصد باشد', 38 | -21 => 'Reseller ID ارسالی اشتباه است', 39 | -22 => 'فرمت یا طول مقادیر ارسالی به درگاه اشتباه است', 40 | -23 => 'سوییچ PSP ( درگاه بانک ) قادر به پردازش درخواست نیست. لطفا لحظاتی بعد مجددا تلاش کنید', 41 | -24 => 'شماره کارت باید بصورت 16 رقمی، لاتین و چسبیده بهم باشد', 42 | -25 => 'امکان استفاده از سرویس در کشور مبدا شما وجود نداره', 43 | -26 => 'امکان انجام تراکنش برای این درگاه وجود ندارد', 44 | -27 => 'در انتظار تایید درگاه توسط شاپرک', 45 | -28 => 'امکان تسهیم تراکنش برای این درگاه وجود ندارد', 46 | ]; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Providers/SabaPay/SabaPay.php: -------------------------------------------------------------------------------- 1 | $this->config['api-key'], 44 | 'amount' => $transaction->getAmount()->getToman(), 45 | 'return_url' => $this->getCallback($transaction, true), 46 | ]; 47 | 48 | [$response] = Curl::execute(self::SERVER_URL, $fields, true, [ 49 | CURLOPT_SSL_VERIFYPEER => false, 50 | ], Curl::METHOD_GET); 51 | 52 | if ($response['status'] != 1) { 53 | throw new SabaPayException($response['errorCode']); 54 | } 55 | 56 | $redirectResponse = new RedirectResponse( 57 | RedirectResponse::TYPE_GET, 58 | self::URL_GATE.$response['invoice_key'] 59 | ); 60 | 61 | return AuthorizedTransaction::make($transaction, $response['invoice_key'], null, $redirectResponse); 62 | } 63 | 64 | /** 65 | * {@inheritdoc} 66 | */ 67 | protected function validateSettlementRequest(Request $request) 68 | { 69 | $status = $request->input('status'); 70 | 71 | if ($status != 0) { 72 | throw new SabaPayException($status); 73 | } 74 | 75 | $referenceId = $request->input('invoice_key'); 76 | 77 | return new FieldsToMatch(null, $referenceId); 78 | } 79 | 80 | /** 81 | * {@inheritdoc} 82 | */ 83 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 84 | { 85 | $traceNumber = $request->input('bank_code'); 86 | $cardNumber = $request->input('card_number'); 87 | 88 | $fields = [ 89 | 'api_key' => $this->config['api-key'], 90 | ]; 91 | 92 | [$response] = Curl::execute(self::SERVER_VERIFY_URL.$transaction->getReferenceId(), $fields, true, [ 93 | CURLOPT_SSL_VERIFYPEER => false, 94 | ], Curl::METHOD_GET); 95 | 96 | if ($response['status'] != 1) { 97 | throw new SabaPayException($response['errorCode']); 98 | } 99 | 100 | $toMatch = new FieldsToMatch(); 101 | 102 | return new SettledTransaction($transaction, $traceNumber, $toMatch, $cardNumber); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/Providers/SabaPay/SabaPayException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 100 => 'نوع درخواست باید POST باشد.', 18 | 101 => 'API KEY ارسال نشده است یا صحیح نیست.', 19 | 102 => 'مبلغ ارسال نشده است یا کمتر از 1000 ریال است.', 20 | 103 => 'آدرس بازگشت ارسال نشده است.', 21 | 201 => 'پرداخت انجام نشده است.', 22 | 202 => 'پرداخت کنسل شده است یا در مراحل پرداخت خطایی رخ داده است.', 23 | 200 => 'شناسه پرداخت صحیح نیست.', 24 | 301 => 'خطایی در برقراری ارتباط با سرور بانک رخ داده است.', 25 | ]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Providers/Sadad/Sadad.php: -------------------------------------------------------------------------------- 1 | config['terminal-id']; 38 | $OrderId = $transaction->getOrderId(); 39 | $Amount = $transaction->getAmount()->getRiyal(); 40 | $SignData = $this->encryptPKCS7("$TerminalId;$OrderId;$Amount", $this->config['terminal-key']); 41 | $fields = [ 42 | 'MerchantId' => $this->config['merchant-id'], 43 | 'TerminalId' => $TerminalId, 44 | 'Amount' => $Amount, 45 | 'OrderId' => $OrderId, 46 | 'LocalDateTime' => date('m/d/Y g:i:s a'), 47 | 'ReturnUrl' => $this->getCallback($transaction), 48 | 'SignData' => $SignData, 49 | 'AdditionalData' => $transaction->getExtraField('description'), 50 | 'MultiplexingData' => $transaction->getExtraField('multiplexing_data'), 51 | 'ApplicationName' => $transaction->getExtraField('application_name'), 52 | ]; 53 | $mobile = $transaction->getExtraField('mobile'); 54 | if (! empty($mobile)) { 55 | $fields['UserId'] = '98'.substr($mobile, 1); 56 | } 57 | 58 | [$response] = Curl::execute(self::SERVER_URL.'/Request/PaymentRequest', $fields, false); 59 | 60 | if ($response->ResCode != 0) { 61 | throw new SadadException($response->ResCode, $response->Description); 62 | } 63 | 64 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, self::GATE_URL.$response->Token); 65 | 66 | return AuthorizedTransaction::make($transaction, null, $response->Token, $redirectResponse); 67 | } 68 | 69 | /** 70 | * {@inheritdoc} 71 | */ 72 | protected function validateSettlementRequest(Request $request) 73 | { 74 | $ResCode = $request->input('ResCode'); 75 | // $SwitchResCode = $request->input('SwitchResCode'); 76 | 77 | if ($ResCode != 0) { 78 | throw new InvalidRequestException(); 79 | } 80 | 81 | $OrderId = $request->input('OrderId'); 82 | $Token = $request->input('Token'); 83 | 84 | return new FieldsToMatch($OrderId, null, $Token); 85 | } 86 | 87 | /** 88 | * {@inheritdoc} 89 | */ 90 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 91 | { 92 | $masked_card_number = $request->input('PrimaryAccNo'); 93 | $hashed_card_number = $request->input('HashedCardNo'); 94 | 95 | $fields = [ 96 | 'Token' => $transaction->getToken(), 97 | 'SignData' => $this->encryptPKCS7($transaction->getToken(), $this->config['terminal-key']), 98 | ]; 99 | 100 | [$response] = Curl::execute(self::SERVER_URL.'/Advice/Verify', $fields); 101 | 102 | if ($response['ResCode'] != 0) { 103 | throw new SadadException($response['ResCode'], $response['Description']); 104 | } 105 | 106 | $orderId = $response['OrderId']; 107 | $amount = $response['Amount']; 108 | $traceNumber = $response['SystemTraceNo']; 109 | $cardNumber = $response['CustomerCardNumber']; 110 | $RRN = $response['RetrivalRefNo']; 111 | 112 | return new SettledTransaction( 113 | $transaction, 114 | $traceNumber, 115 | new FieldsToMatch($orderId, null, null, new Amount($amount, 'IRR')), 116 | $cardNumber, 117 | $RRN, 118 | compact('masked_card_number', 'hashed_card_number') 119 | ); 120 | } 121 | 122 | /** 123 | * Create signed data (TripleDES(ECB,PKCS7)) 124 | * 125 | * @param string $str 126 | * @param string $key 127 | * @return string 128 | */ 129 | private function encryptPKCS7($str, $key) 130 | { 131 | $key = base64_decode($key); 132 | $cipherText = openssl_encrypt($str, 'DES-EDE3', $key, OPENSSL_RAW_DATA); 133 | 134 | return base64_encode($cipherText); 135 | } 136 | 137 | /** 138 | * {@inheritdoc} 139 | */ 140 | public function getSupportedExtraFieldsSample() 141 | { 142 | return [ 143 | 'mobile' => '09124441122', 144 | 'description' => 'اطلاعات اضافی تراکنش', 145 | 'multiplexing_data' => [ 146 | 'Type' => 'Amount || Percentage', 147 | 'MultiplexingRows' => [ 148 | [ 149 | 'IbanNumber' => 'رديف يا شماره شبا حساب همراه IR', 150 | 'Value' => '(integer) مبلغ يا درصد', 151 | ], 152 | [ 153 | 'IbanNumber' => 'رديف يا شماره شبا حساب همراه IR', 154 | 'Value' => '(integer) مبلغ يا درصد', 155 | ], 156 | ], 157 | ], 158 | 'application_name' => 'نام اپلیکیشن درخواست کننده - '. 159 | 'اختیاری (برای گزارشات لازم است که اين فیلد مقدار دهی شود)', 160 | ]; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/Providers/Sadad/SadadException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 0 => 'تراکنش موفق', 18 | 3 => 'Invalid merchant (پذيرنده کارت فعال نیست لطفا با بخش امور پذيرندگان، تماس حاصل فرمائید)', 19 | 23 => 'Merchant Inactive (پذيرنده کارت نامعتبر است لطفا با بخش امور پذيرندگان، تماس حاصل فرمائید)', 20 | 58 => 'انجام تراکنش مربوطه توسط پايانه ی انجام دهنده مجاز نمی باشد.', 21 | 61 => 'مبلغ تراکنش از حد مجاز بالاتر است', 22 | 1000 => 'ترتیب پارامترهای ارسالی اشتباه می باشد، لطفا مسئول فنی پذيرنده با بانک تماس حاصل فرمايند', 23 | 1001 => 'لطفا مسئول فنی پذيرنده با بانک تماس حاصل فرمايند،پارامترهای پرداخت اشتباه می باشد', 24 | 1002 => 'خطا در سیستم- تراکنش ناموفق', 25 | 1003 => 'IP پذيرنده اشتباه است.لطفا مسئول فنی پذيرنده با بانک تماس حاصل فرمايند', 26 | 1004 => 'لطفا مسئول فنی پذيرنده با بانک تماس حاصل فرمايند،شماره پذيرنده اشتباه است', 27 | 1005 => 'خطای دسترسی:لطفا بعدا تلاش فرمايید', 28 | 1006 => 'خطا در سیستم', 29 | 1011 => 'درخواست تکراری- شماره سفارش تکراری می باشد', 30 | 1012 => 'اطلاعات پذيرنده صحیح نیست،يکی از موارد تاريخ،زمان يا کلید تراکنش اشتباه است.لطفا مسئول فنی پذيرنده با بانک تماس حاصل فرمايند', 31 | 1015 => 'پاسخ خطای نامشخص از سمت مرکز', 32 | 1017 => 'مبلغ درخواستی شما جهت پرداخت از حد مجاز تعريف شده برای اين پذيرنده بیشتر است', 33 | 1018 => 'اشکال در تاريخ و زمان سیستم. لطفا تاريخ و زمان سرور خود را با بانک هماهنگ نمايید', 34 | 1019 => 'امکان پرداخت از طريق سیستم شتاب برای اين پذيرنده امکان پذير نیست', 35 | 1020 => 'پذيرنده غیرفعال شده است.لطفا جهت فعال سازی با بانک تماس بگیريد', 36 | 1023 => 'آدرس بازگشت پذيرنده نامعتبر است', 37 | 1024 => 'مهر زمانی پذيرنده نامعتبر است', 38 | 1025 => 'امضا تراکنش نامعتبر است', 39 | 1026 => 'شماره سفارش تراکنش نامعتبر است', 40 | 1027 => 'شماره پذيرنده نامعتبر است', 41 | 1028 => 'شماره ترمینال پذيرنده نامعتبر است', 42 | 1029 => 'آدرس IP پرداخت در محدوده آدرس های معتبر اعلام شده توسط پذيرنده نیست .لطفا مسئول فنی پذيرنده با بانک تماس حاصل فرمايند', 43 | 1030 => 'آدرس Domain پرداخت در محدوده آدرس های معتبر اعلام شده توسط پذيرنده نیست .لطفا مسئول فنی پذيرنده با بانک تماس حاصل فرمايند', 44 | 1031 => 'مهلت زمانی شما جهت پرداخت به پايان رسیده است.لطفا مجددا سعی بفرمايید .', 45 | 1032 => 'پرداخت با اين کارت , برای پذيرنده مورد نظر شما امکان پذير نیست.لطفا از کارتهای مجاز که توسط پذيرنده معرفی شده است , استفاده نمايید.', 46 | 1033 => 'به علت مشکل در سايت پذيرنده, پرداخت برای اين پذيرنده غیرفعال شده است.لطفا مسوول فنی سايت پذيرنده با بانک تماس حاصل فرمايند.', 47 | 1036 => 'اطلاعات اضافی ارسال نشده يا دارای اشکال است', 48 | 1037 => 'شماره پذيرنده يا شماره ترمینال پذيرنده صحیح نمیباشد', 49 | 1053 => 'خطا: درخواست معتبر، از سمت پذيرنده صورت نگرفته است لطفا اطلاعات پذيرنده خود را چک کنید.', 50 | 1055 => 'مقدار غیرمجاز در ورود اطلاعات', 51 | 1056 => 'سیستم موقتا قطع میباشد.لطفا بعدا تلاش فرمايید.', 52 | 1058 => 'سرويس پرداخت اينترنتی خارج از سرويس می باشد.لطفا بعدا سعی بفرمايید.', 53 | 1061 => 'اشکال در تولید کد يکتا. لطفا مرورگر خود را بسته و با اجرای مجدد مرورگر عملیات پرداخت را انجام دهید (احتمال استفاده از دکمه «Back» مرورگر)', 54 | 1064 => 'لطفا مجددا سعی بفرمايید', 55 | 1065 => 'ارتباط ناموفق .لطفا چند لحظه ديگر مجددا سعی کنید', 56 | 1066 => 'سیستم سرويس دهی پرداخت موقتا غیر فعال شده است', 57 | 1068 => 'با عرض پوزش به علت بروزرسانی , سیستم موقتا قطع میباشد.', 58 | 1072 => 'خطا در پردازش پارامترهای اختیاری پذيرنده', 59 | 1101 => 'مبلغ تراکنش نامعتبر است', 60 | 1103 => 'توکن ارسالی نامعتبر است', 61 | 1104 => 'اطلاعات تسهیم صحیح نیست', 62 | 1105 => 'تراکنش بازگشت داده شده است(مهلت زمانی به پايان رسیده است)', 63 | 64 | // verify errors 65 | -1 => 'پارامترهای ارسالی صحیح نیست و يا تراکنش در سیستم وجود ندارد.', 66 | 101 => 'مهلت ارسال تراکنش به پايان رسیده است', 67 | ]; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/Providers/Saman/Saman.php: -------------------------------------------------------------------------------- 1 | 'Token', 46 | 'TerminalId' => $this->config['terminal-id'], 47 | 'RedirectUrl' => $this->getCallback($transaction), 48 | 'ResNum' => $transaction->getOrderId(), 49 | 'Amount' => $transaction->getAmount()->getRiyal(), 50 | 'CellNumber' => $transaction->getExtraField('mobile'), 51 | ]; 52 | 53 | $fields = array_merge($fields, $transaction->getExtraField('optional_data', [])); 54 | 55 | [$result] = Curl::execute(self::SERVER_URL, $fields); 56 | 57 | if ($result['status'] != 1) { 58 | throw new SamanException($result['errorCode'], $result['errorDesc']); 59 | } 60 | 61 | $token = $result['token']; 62 | $data = [ 63 | 'Token' => $token, 64 | 'GetMethod' => '', /* true | false | empty string | null */ 65 | ]; 66 | 67 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_POST, self::URL_GATE, $data); 68 | 69 | return AuthorizedTransaction::make($transaction, null, $token, $redirectResponse); 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | */ 75 | protected function validateSettlementRequest(Request $request) 76 | { 77 | $state = $request->input('State'); 78 | $status = $request->input('Status'); 79 | 80 | if ($state != 'OK') { 81 | throw new SamanException($status); 82 | } 83 | 84 | $orderId = $request->input('ResNum'); 85 | $token = $request->input('Token'); 86 | $amount = $request->input('Amount'); 87 | 88 | return new FieldsToMatch($orderId, null, $token, new Amount($amount, 'IRR')); 89 | } 90 | 91 | /** 92 | * {@inheritdoc} 93 | */ 94 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 95 | { 96 | $refId = $request->input('RefNum'); 97 | 98 | $soap = new SoapClient(self::SERVER_VERIFY_URL, $this->soapConfig()); 99 | $response = $soap->VerifyTransaction($refId, $this->config['terminal-id']); 100 | 101 | $response = intval($response); 102 | 103 | if ($response == $transaction->getAmount()->getRiyal()) { 104 | // $toMatch = new FieldsToMatch(null, null, null, new Amount($response, 'IRR')); 105 | $toMatch = new FieldsToMatch(); 106 | 107 | $trace_number = $request->input('TraceNo'); 108 | $hashed_card_number = $request->input('HashedCardNumber'); 109 | $affective_amount = $request->input('AffectiveAmount'); 110 | $wage = $request->input('Wage'); 111 | 112 | return new SettledTransaction( 113 | $transaction, 114 | $refId, 115 | $toMatch, 116 | $request->input('SecurePan'), 117 | $request->input('Rrn'), 118 | compact('trace_number', 'hashed_card_number', 'affective_amount', 'wage'), 119 | $refId 120 | ); 121 | } 122 | 123 | //Reverse Transaction 124 | if ($response > 0) { 125 | $response = $soap->ReverseTransaction( 126 | $refId, 127 | $this->config['terminal-id'], 128 | $this->config['username'], 129 | $this->config['password'] 130 | ); 131 | 132 | throw new SamanException($response, 'Invalid Amount'); 133 | } 134 | 135 | throw new SamanException($response); 136 | } 137 | 138 | /** 139 | * @throws \SoapFault 140 | */ 141 | public function reverse(string $refNum): array 142 | { 143 | $soap = new SoapClient(self::SERVER_VERIFY_URL, $this->soapConfig()); 144 | $response = $soap->ReverseTransaction( 145 | $refNum, 146 | $this->config['terminal-id'], 147 | $this->config['username'], 148 | $this->config['password'] 149 | ); 150 | 151 | $message = (new SamanException($response))->getMessage(); 152 | 153 | return compact('response', 'message'); 154 | } 155 | 156 | /** 157 | * {@inheritdoc} 158 | */ 159 | public function getSupportedExtraFieldsSample() 160 | { 161 | return [ 162 | 'mobile' => '09124441122', 163 | 'optional_data' => [ 164 | 'ResNum1' => 'دیتای اضافی که توسط سایت پذیرنده ارسال و '. 165 | 'فقط هنگام گزارشگیری در پنل گزارش تراکنش قابل دسترسی می باشد. (حداکثر ۵۰ کاراکتر)', 166 | 'ResNum2' => 'دیتای اضافی که توسط سایت پذیرنده ارسال و '. 167 | 'فقط هنگام گزارشگیری در پنل گزارش تراکنش قابل دسترسی می باشد. (حداکثر ۵۰ کاراکتر)', 168 | 'ResNum3' => 'دیتای اضافی که توسط سایت پذیرنده ارسال و '. 169 | 'فقط هنگام گزارشگیری در پنل گزارش تراکنش قابل دسترسی می باشد. (حداکثر ۵۰ کاراکتر)', 170 | 'ResNum4' => 'دیتای اضافی که توسط سایت پذیرنده ارسال و '. 171 | 'فقط هنگام گزارشگیری در پنل گزارش تراکنش قابل دسترسی می باشد. (حداکثر ۵۰ کاراکتر)', 172 | ], 173 | ]; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/Providers/Saman/SamanException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | $errors = [ 17 | 'CanceledByUser' => 'کاربر انصراف داده است', 18 | 'OK' => 'پرداخت با موفقیت انجام شد', 19 | 'Failed' => 'پرداخت انجام نشد.', 20 | 'SessionIsNull' => 'کاربر در بازه زمانی تعیین شده پاسخی ارسال نکرده است.', 21 | 'InvalidParameters' => 'پارامترهای ارسالی نامعتبر است.', 22 | 'MerchantIpAddressIsInvalid' => 'آدرس سرور پذیرنده نامعتبر است (در پرداخت‌های بر پایه توکن)', 23 | 'TokenNotFound' => 'توکن ارسال شده یافت نشد.', 24 | 'TokenRequired' => 'با این شماره ترمینال فقط تراکنش‌های توکنی قابل پرداخت هستند.', 25 | 'TerminalNotFound' => 'شماره ترمینال ارسال شده یافت نشد.', 26 | 27 | -1 => 'خطای در پردازش اطلاعات ارسالی. (مشکل در یکی از ورودی‌ها و ناموفق بودن فراخوانی متد برگشت تراکنش)', 28 | -2 => 'سپرده ها برابر نیستند', 29 | -3 => 'ورودی ها حاوی کاراکترهای غیر مجاز می باشند', 30 | -4 => 'Merchant Authentication Failed (کلمه عبور یا کد فروشنده اشتباه است)', 31 | -5 => 'Database Exception', 32 | -6 => 'تراکنش قبلا برگشت داده شده است', 33 | -7 => 'رسید دیجیتالی تهی است', 34 | -8 => 'طول ورودی‌ها بیشتر از حد مجاز است', 35 | -9 => 'وجود کاراکترهای غیر مجاز در مبلغ برگشتی', 36 | -10 => 'رسید دیجیتالی به صورت Base64 نیست (حاوی کارکترهای غیرمجاز است)', 37 | -11 => 'طول ورودی‌ها کمتر از حد مجاز است', 38 | -12 => 'مبلغ برگشتی منفی است', 39 | -13 => 'مبلغ برگشتی برای برگشت جزئی بیش از مبلغ برگشت نخورده‌ی رسید دیجیتالی است', 40 | -14 => 'چنین تراکنشی تعریف نشده است', 41 | -15 => 'مبلغ برگشتی به صورت اعشاری داده شده است', 42 | -16 => 'خطای داخلی سیستم', 43 | -17 => 'برگشت زدن جزئی تراکنش مجاز نمی باشد', 44 | -18 => 'IP Address فروشنده نا معتبر است', 45 | ]; 46 | 47 | return array_replace($errors, [ 48 | 1 => $errors['CanceledByUser'], 49 | 2 => $errors['OK'], 50 | 3 => $errors['Failed'], 51 | 4 => $errors['SessionIsNull'], 52 | 5 => $errors['InvalidParameters'], 53 | 8 => $errors['MerchantIpAddressIsInvalid'], 54 | 10 => $errors['TokenNotFound'], 55 | 11 => $errors['TokenRequired'], 56 | 12 => $errors['TerminalNotFound'], 57 | ]); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/Providers/Sepal/Sepal.php: -------------------------------------------------------------------------------- 1 | setServer(); 67 | } 68 | 69 | /** 70 | * Set server for soap transfers data 71 | * 72 | * @return void 73 | */ 74 | protected function setServer() 75 | { 76 | if (Arr::get($this->config, 'sandbox', false)) { 77 | $this->serverUrl = self::SERVER_SANDBOX_URL; 78 | $this->gateUrl = self::GATE_SANDBOX_URL; 79 | } else { 80 | $this->serverUrl = self::SERVER_URL; 81 | $this->gateUrl = self::GATE_URL; 82 | } 83 | } 84 | 85 | /** 86 | * {@inheritdoc} 87 | */ 88 | protected function authorizeTransaction(UnAuthorizedTransaction $transaction) 89 | { 90 | $fields = [ 91 | 'amount' => $transaction->getAmount()->getRiyal(), 92 | 'callbackUrl' => $this->getCallback($transaction), 93 | 'invoiceNumber' => $transaction->getOrderId(), 94 | 'payerName' => $transaction->getExtraField('name'), 95 | 'payerMobile' => $transaction->getExtraField('mobile'), 96 | 'payerEmail' => $transaction->getExtraField('email'), 97 | 'description' => $transaction->getExtraField('description'), 98 | 'affiliateCode' => $transaction->getExtraField('affiliate_code'), 99 | ]; 100 | 101 | $result = $this->callApi('request.json', $fields); 102 | 103 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, $this->gateUrl.$result['paymentNumber']); 104 | 105 | return AuthorizedTransaction::make($transaction, $result['paymentNumber'], null, $redirectResponse); 106 | } 107 | 108 | /** 109 | * {@inheritdoc} 110 | */ 111 | protected function validateSettlementRequest(Request $request) 112 | { 113 | if (! $request->has('status')) { 114 | throw new InvalidRequestException(); 115 | } 116 | 117 | $status = $request->input('status'); 118 | if ($status != 1) { 119 | throw new SepalException($status); 120 | } 121 | 122 | return new FieldsToMatch($request->input('invoiceNumber'), $request->input('paymentNumber')); 123 | } 124 | 125 | /** 126 | * {@inheritdoc} 127 | */ 128 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 129 | { 130 | $result = $this->callApi('verify.json', ['paymentNumber' => $transaction->getReferenceId()]); 131 | 132 | $cardNumber = $result['cardNumber'] ?? ''; 133 | 134 | return new SettledTransaction( 135 | $transaction, 136 | $transaction->getReferenceId(), 137 | new FieldsToMatch(), 138 | $cardNumber, 139 | '', 140 | ['verify_result' => $result] 141 | ); 142 | } 143 | 144 | /** 145 | * @return mixed 146 | * 147 | * @throws SepalException 148 | */ 149 | protected function callApi(string $path, array $fields) 150 | { 151 | $fields['apiKey'] = $this->config['api-key']; 152 | [$response, $http_code, $error] = Curl::execute($this->serverUrl.$path, $fields); 153 | 154 | if ($http_code != 200 || empty($response['status'])) { 155 | throw new SepalException( 156 | $response['status'] ?? $http_code, 157 | $response['message'] ?? $error ?? null 158 | ); 159 | } 160 | 161 | return $response; 162 | } 163 | 164 | /** 165 | * {@inheritdoc} 166 | */ 167 | public function getSupportedExtraFieldsSample() 168 | { 169 | return [ 170 | 'mobile' => '09124441122', 171 | 'name' => 'نام پرداخت کننده', 172 | 'email' => 'test@gmail.com', 173 | 'description' => 'توضیحات مربوط به تراکنش که به صورت اختیاری می باشد', 174 | 'affiliate_code' => 'کد معرف، در صورتی که این کد ارسال شود بخشی از کارمزد تراکنش به معرف تعلق میگیرد', 175 | ]; 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/Providers/Sepal/SepalException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 0 => 'خطای تعریف نشده', 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Providers/Sepehr/SepehrException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | -1 => 'تراکنش پیدا نشد', 18 | -2 => 'در زمان دریافت توکن به دلیل عدم وجود (عدم تطابق) IP'. 19 | ' و یا به دلیل بسته بودن خروجی پورت 8081 از سمت Host این خطا ایجاد میگردد.'. 20 | ' تراکنش قبلا Reverse شده است.', 21 | -3 => 'Total Error خطای عمومی – خطای Exception ها', 22 | -4 => 'امکان انجام درخواست برای این تراکنش وجود ندارد', 23 | -5 => 'آدرس IP نامعتبر میباشد (IP در لیست آدرسهای معرفی شده توسط پذیرنده موجود نمیباشد)', 24 | -6 => 'عدم فعال بودن سرویس برگشت تراکنش برای پذیرنده', 25 | ]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Providers/Shepa/Shepa.php: -------------------------------------------------------------------------------- 1 | setServer(); 47 | } 48 | 49 | /** 50 | * Set server for soap transfers data 51 | * 52 | * @return void 53 | */ 54 | protected function setServer() 55 | { 56 | if (Arr::get($this->config, 'sandbox', false)) { 57 | $this->serverUrl = self::SERVER_SANDBOX_URL; 58 | } else { 59 | $this->serverUrl = self::SERVER_URL; 60 | } 61 | } 62 | 63 | /** 64 | * {@inheritdoc} 65 | */ 66 | protected function authorizeTransaction(UnAuthorizedTransaction $transaction) 67 | { 68 | $fields = [ 69 | 'api' => $this->config['api-key'], 70 | 'amount' => $transaction->getAmount()->getTotal(), 71 | 'callback' => $this->getCallback($transaction), 72 | 'mobile' => $transaction->getExtraField('mobile'), 73 | 'email' => $transaction->getExtraField('email'), 74 | 'description' => $transaction->getExtraField('description'), 75 | ]; 76 | 77 | $result = $this->callApi('token', $fields); 78 | 79 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, $result['url']); 80 | 81 | return AuthorizedTransaction::make($transaction, null, $result['token'], $redirectResponse); 82 | } 83 | 84 | /** 85 | * {@inheritdoc} 86 | */ 87 | protected function validateSettlementRequest(Request $request) 88 | { 89 | if (! $request->has('status')) { 90 | throw new InvalidRequestException(); 91 | } 92 | 93 | $status = $request->input('status'); 94 | if ($status != 'success') { 95 | throw new ShepaException($status); 96 | } 97 | 98 | return new FieldsToMatch(null, null, $request->input('token')); 99 | } 100 | 101 | /** 102 | * {@inheritdoc} 103 | */ 104 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 105 | { 106 | $fields = [ 107 | 'api' => $this->config['api-key'], 108 | 'amount' => $transaction->getAmount()->getTotal(), 109 | 'token' => $transaction->getToken(), 110 | ]; 111 | 112 | $result = $this->callApi('verify', $fields); 113 | 114 | $traceNumber = $result['refid']; 115 | $transactionId = $result['transaction_id']; 116 | $date = $result['date']; 117 | $amount = $result['amount']; 118 | $cardNumber = $result['card_pan']; 119 | 120 | $toMatch = new FieldsToMatch(null, null, null, new Amount($amount, $transaction->getAmount()->getCurrency())); 121 | 122 | return new SettledTransaction( 123 | $transaction, 124 | $traceNumber, 125 | $toMatch, 126 | $cardNumber, 127 | '', 128 | compact('date'), 129 | $transactionId 130 | ); 131 | } 132 | 133 | /** 134 | * @return mixed 135 | * 136 | * @throws ShepaException 137 | */ 138 | protected function callApi(string $path, array $fields) 139 | { 140 | [$response, $http_code, $error] = Curl::execute($this->serverUrl.$path, $fields); 141 | 142 | if ($http_code != 200 || empty($response['success']) || ! $response['success']) { 143 | throw new ShepaException( 144 | $response['errorCode'] ?? $http_code, 145 | implode('; ', $response['error']) ?? $error ?? null 146 | ); 147 | } 148 | 149 | return $response['result']; 150 | } 151 | 152 | /** 153 | * {@inheritdoc} 154 | */ 155 | public function getSupportedExtraFieldsSample() 156 | { 157 | return [ 158 | 'mobile' => '09124441122', 159 | 'email' => 'test@gmail.com', 160 | 'description' => 'توضیحات مربوط به تراکش', 161 | ]; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/Providers/Shepa/ShepaException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return []; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Providers/Sizpay/SizpayException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | 0 => 'موفق', 18 | 106 => 'مبلغ پرداختی باید بین 10,000 و 50,000,000 ریال باشد.', 19 | 128 => 'نام کاربری و یا رمزعبور نامعتبر می باشد.', 20 | 21 | 1000 => 'خطای داخلی رخ داده است لطفا درخواست را دوباره ارسال کنید.', 22 | 1001 => 'کد پذیرنده باید به صورت رشته عددی و حداکثر 15 کاراکتر باشد', 23 | 1002 => 'کد ترمینال باید به صورت رشته عددی و صرفا 8 کاراکتر باشد', 24 | 1003 => 'پذیرنده و یا ترمینال معتبر نمی باشد.', 25 | 1004 => 'نوع ترمینال معتبر نمی باشد', 26 | 1005 => 'فرمت مبلغ قابل پرداخت نادرست است', 27 | 1006 => 'مبلغ پرداختی باید بین {0} و {1} ریال باشد', 28 | 1007 => 'تاریخ سند صحیح نمی باشد.', 29 | 1008 => 'آدرس بازگشت نمیتواند خالی باشد', 30 | 1009 => 'آدرس بازگشت باید با http// ویا https// شروع شود.', 31 | 1010 => 'درخواست تراکنش صحیح IP نیست(در لیست اعلامی پذیرنده موجود نیست)', 32 | 1011 => 'درگاه پرداخت فعالی برای این پذیرنده و ترمینال وجود ندارد', 33 | 1012 => 'خطا در اتصال به درگاه پرداخت', 34 | 1013 => 'خطا در دریافت اطلاعات از درگاه پرداخت', 35 | 1014 => 'کلید ترمینال صحیح نمی باشد', 36 | 1015 => 'ورود همه موارد اجباری می باشد.', 37 | 1016 => 'مقادیر ورودی نامعتبر می باشد', 38 | 1017 => 'خطا در دریافت اطلاعات پذیرنده', 39 | 1018 => 'انصراف از پرداخت', 40 | 1019 => 'توکن نامعتبر می باشد', 41 | 1020 => 'توکن منقضی شده است', 42 | 1021 => 'تراکنش یافت نشد', 43 | 1022 => 'تراکنش مربوط به این پذیرنده و ترمینال نمی باشد و یا تراکنش نامعتبر می باشد', 44 | 1023 => 'تراکنش قبلا برگشت شده است و نمی توان آن را تایید کرد.', 45 | 1024 => 'تراکنش قبلا تایید شده است', 46 | 1025 => 'تراکنش قبلا تایید شده است و نمی توان آن را برگشت کرد', 47 | 1026 => 'تراکنش قبلا برگشت شده است', 48 | 1027 => 'شناسه پرداخت نامعتبر می باشد. شناسه پرداخت باید رشته ای فقط عددی باشد', 49 | 1028 => 'نام کاربری و یا رمزعبور نامعتبر می باشد.', 50 | 1029 => 'لطفا مقادیر تایید هویت را به درستی وارد نمایید.', 51 | 1030 => 'این عملیات برای توکن مورد نظر نامعتبر می باشد.', 52 | 1031 => 'تاریخ سند نمی تواند بعد از تاربخ امروز باشد', 53 | 1032 => 'از تاریخ سند نمیتواند بیشتر از {0} روز گذشته باشد', 54 | 1033 => 'شناسه خرید نامعتبر می باشد', 55 | 9999 => 'نامشخص', 56 | ]; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Providers/TiPoul/TiPoulException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | -1 => 'خطای عمومی', 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Providers/Vandar/Vandar.php: -------------------------------------------------------------------------------- 1 | $this->config['api-key'], 39 | 'amount' => $transaction->getAmount()->getRiyal(), 40 | 'callback_url' => $this->getCallback($transaction), 41 | 'mobile_number' => $transaction->getExtraField('mobile'), 42 | 'factorNumber' => $transaction->getOrderId(), 43 | 'description' => $transaction->getExtraField('description'), 44 | 'national_code' => $transaction->getExtraField('national_code'), 45 | 'valid_card_number' => $transaction->getExtraField('allowed_card'), 46 | 'comment' => $transaction->getExtraField('comment'), 47 | ]; 48 | 49 | [$result, $http_code] = Curl::execute(self::SERVER_URL.'/send', $fields); 50 | 51 | if ($http_code != 200 || empty($result['status']) || $result['status'] != 1) { 52 | throw new VandarException($http_code, implode('; ', $result['errors']) ?? null); 53 | } 54 | 55 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, self::GATE_URL.$result['token']); 56 | 57 | return AuthorizedTransaction::make($transaction, null, $result['token'], $redirectResponse); 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | protected function validateSettlementRequest(Request $request) 64 | { 65 | if (! $request->has('payment_status')) { 66 | throw new InvalidRequestException(); 67 | } 68 | 69 | $status = $request->input('payment_status'); 70 | if ($status != 'OK') { 71 | throw new VandarException($status); 72 | } 73 | 74 | return new FieldsToMatch(null, null, $request->input('token')); 75 | } 76 | 77 | /** 78 | * {@inheritdoc} 79 | */ 80 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 81 | { 82 | $fields = [ 83 | 'api_key' => $this->config['api-key'], 84 | 'token' => $transaction->getToken(), 85 | ]; 86 | 87 | [$result, $http_code] = Curl::execute(self::SERVER_URL.'/verify', $fields); 88 | 89 | if ($http_code != 200 || empty($result['status'])) { 90 | if (intval($result['status']) > 1) { 91 | throw new VandarException( 92 | $result['status'], 93 | empty($result['errors']) ? 94 | $this->getStatusMessage($result['status']) : 95 | implode('; ', $result['errors']) 96 | ); 97 | } 98 | throw new VandarException($http_code, implode('; ', $result['errors']) ?? null); 99 | } 100 | 101 | // $amount = $result['amount']; 102 | // $realAmount = $result['realAmount']; 103 | // $wage = $result['wage']; 104 | $traceNumber = $result['transId']; 105 | // $factorNumber = $result['factorNumber']; 106 | // $mobile = $result['mobile']; 107 | // $description = $result['description']; 108 | $cardNumber = $result['cardNumber']; 109 | // $paymentDate = $result['paymentDate']; 110 | $cardId = $result['cid']; 111 | $message = $result['message']; 112 | 113 | $toMatch = new FieldsToMatch($result['factorNumber']); 114 | 115 | return new SettledTransaction( 116 | $transaction, 117 | $traceNumber, 118 | $toMatch, 119 | $cardNumber ?? '', 120 | '', 121 | compact('cardId', 'message', 'result') 122 | ); 123 | } 124 | 125 | protected function getStatusMessage(int $code): ?string 126 | { 127 | $status_codes = [ 128 | 0 => 'مقادیر ارسالی اشتباه است', 129 | 1 => 'پرداخت تایید شده است', 130 | 2 => 'پرداخت از قبل وریفای شده است', 131 | 3 => 'زمان تایید تراکنش (حداکثر ۲۰ دقیقه بعد از ارسال تراکنش) منقضی شده است', 132 | ]; 133 | 134 | return $status_codes[$code] ?? null; 135 | } 136 | 137 | /** 138 | * {@inheritdoc} 139 | */ 140 | public function getSupportedExtraFieldsSample() 141 | { 142 | return [ 143 | 'mobile' => '09124441122', 144 | 'description' => 'توضیحات (اختیاری، حداکثر 255 کاراکتر)', 145 | 'national_code' => 'کد ملی معتبر'. 146 | ' (در صورت ارسال کد ملی، کاربر فقط با کارت‌های بانکی تحت مالکیت آن کد ملی قابلیت پرداخت خواهد داشت.'. 147 | ' برای بررسی کدملی در درگاه پرداخت ارسال شماره موبایل مرتبط با کد ملی نیز الزامی است.)', 148 | 'allowed_card' => 'شماره کارت معتبر'. 149 | ' (در صورت ارسال شماره کارت، کاربر فقط با همان شماره کارت قابلیت پرداخت خواهد داشت.)', 150 | 'comment' => 'یک یادداشت که در داشبورد شما روی تراکنش نمایش داده می شود', 151 | ]; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/Providers/Vandar/VandarException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | // 400 => "Bad Request", 18 | // 401 => "Unauthorized", 19 | // 403 => "Forbidden", 20 | // 404 => "Not Found", 21 | // 405 => "Method Not Allowed", 22 | // 406 => "Not Acceptable -- You requested a format that isn't json", 23 | // 410 => "Gone", 24 | // 422 => "Bad Request", 25 | // 429 => "Too Many Requests", 26 | // 500 => "Internal Server Error", 27 | // 503 => "Service Unavailable -- We're temporarially offline for maintanance. Please try again later.", 28 | 29 | 400 => 'درخواست شما از سرویس وندار اشتباه است', 30 | 401 => 'یا توکن را در درخواست خود ارسال نکردید یا توکن شما معتبر نمی باشد', 31 | 403 => 'شما دسترسی لازم برای دریافت این پاسخ را ندارید', 32 | 404 => 'درخواست ارسال شده با این آدرس در سرویس وندار موجود نیست', 33 | 405 => 'آدرس ارسال شده توسط شما با متد آن همخوانی ندارد لطفا با توجه به مستندات متد خود را اصلاح کنید', 34 | 406 => 'ورودی فرستاده شده از سمت شما برای سرویس وندار باید به فرمت json باشد لطفا فرمت ورودی را اصلاح کنید', 35 | 410 => 'درخواست ارسال شده از سرویس وندار حذف شده است', 36 | 422 => 'یکی از فیلدهایی که برای سرویس ارسال کرده اید اشتباه است', 37 | 429 => 'تعداد درخواست های ارسال شده از سمت شما برای سرویس ما قابل پاسخگویی نیست، لطفا کمی صبر کنید و دوباره درخواست خود را ارسال کنید', 38 | 500 => 'خطای نامشخصی در سرور رخ داده است لطفا کمی صبر کنید و دوباره تلاش کنید', 39 | 503 => 'سرویس وندار در حال حاضر موقتا در دسترس نیست، لطفا کمی صبر کنید و دوباره تلاش کنید', 40 | ]; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Providers/YekPay/YekPayException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | -1 => 'The parameters are incomplete', 18 | -2 => 'Merchant code is incorrect', 19 | -3 => 'Merchant code is not active', 20 | -4 => 'Currencies is not valid', 21 | -5 => 'Maximum/Minimum amount is not valid', 22 | -6 => 'Your IP is restricted', 23 | -7 => 'Order id must be unique', 24 | -8 => 'Currencies is not valid', 25 | -9 => 'Maximum/Minimum amount is not valid', 26 | -10 => 'Your IP is restricted', 27 | -100 => 'Unknown error', 28 | 100 => 'Success', 29 | ]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Providers/Zarinpal/ZarinpalException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | -1 => 'اطلاعات ارسال شده ناقص است.', 18 | -2 => 'IP و یا مرچنت کد پذیرنده صحیح نیست', 19 | -3 => 'رقم باید بالای 100 تومان باشد', 20 | -4 => 'سطح پذیرنده پایین تر از سطح نقره ای است', 21 | -11 => 'درخواست مورد نظر یافت نشد', 22 | -21 => 'هیچ نوع عملیات مالی برای این تراکنش یافت نشد', 23 | -22 => 'تراکنش ناموفق میباشد', 24 | -33 => 'رقم تراکنش با رقم پرداخت شده مطابقت ندارد', 25 | -54 => 'درخواست مورد نظر آرشیو شده', 26 | -99 => 'خطای داخلی از سمت زرین پال', 27 | 100 => 'عملیات با موفقیت انجام شد', 28 | 101 => 'عملیات پرداخت با موفقیت انجام شده ولی قبلا عملیات PaymentVerification بر روی این تراکنش انجام شده است', 29 | ]; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Providers/Zibal/Zibal.php: -------------------------------------------------------------------------------- 1 | $this->config['merchant'], 40 | 'amount' => $transaction->getAmount()->getRiyal(), 41 | 'callbackUrl' => $this->getCallback($transaction), 42 | 'description' => $transaction->getExtraField('description'), 43 | 'orderId' => $transaction->getOrderId(), 44 | 'mobile' => $transaction->getExtraField('mobile'), 45 | 'national_code' => $transaction->getExtraField('national_code'), 46 | 'allowedCards' => $transaction->getExtraField('allowed_card'), 47 | 'linkToPay' => $transaction->getExtraField('link_to_pay'), 48 | 'sms' => $transaction->getExtraField('sms'), 49 | 'percentMode' => ($transaction->getExtraField('percent_mode') ? 1 : 0), 50 | 'feeMode' => $transaction->getExtraField('fee_mode'), 51 | 'multiplexingInfos' => $transaction->getExtraField('multiplexing_infos'), 52 | ]; 53 | 54 | [$response, $http_code] = Curl::execute(self::SERVER_URL.'request', $fields); 55 | 56 | if ($http_code != 200 || empty($response['result']) || $response['result'] != 100) { 57 | throw new ZibalException($response['result'] ?? $http_code, $response['message'] ?? null); 58 | } 59 | 60 | $redirectResponse = new RedirectResponse(RedirectResponse::TYPE_GET, self::GATE_URL.$response['trackId']); 61 | $extra = $transaction->getExtra(); 62 | if (! empty($response['payLink'])) { 63 | $extra['pay_link'] = $response['payLink']; 64 | } 65 | $transaction['extra'] = $extra; 66 | 67 | return AuthorizedTransaction::make($transaction, $response['trackId'], null, $redirectResponse); 68 | } 69 | 70 | /** 71 | * {@inheritdoc} 72 | */ 73 | protected function validateSettlementRequest(Request $request) 74 | { 75 | if (! $request->has('success')) { 76 | throw new InvalidRequestException(); 77 | } 78 | 79 | $success = $request->input('success'); 80 | if ($success != 1) { 81 | throw new ZibalException($request->input('status')); 82 | } 83 | 84 | return new FieldsToMatch($request->input('orderId'), $request->input('trackId')); 85 | } 86 | 87 | /** 88 | * {@inheritdoc} 89 | */ 90 | protected function settleTransaction(Request $request, AuthorizedTransaction $transaction) 91 | { 92 | $fields = [ 93 | 'merchant' => $this->config['merchant'], 94 | 'trackId' => $transaction->getReferenceId(), 95 | ]; 96 | 97 | [$response, $http_code] = Curl::execute(self::SERVER_URL.'verify', $fields); 98 | 99 | if ($http_code != 200 || empty($response['result']) || ! in_array($response['result'], [100, 202])) { 100 | throw new ZibalException($response['result'] ?? $http_code, $response['message'] ?? null); 101 | } 102 | if ($response['result'] == 202) { 103 | throw new ZibalException($response['status'] ?? $response['result'] ?? $http_code); 104 | } 105 | 106 | $orderId = $response['orderId']; 107 | $amount = $response['amount']; 108 | $traceNumber = $response['refNumber'] ?? $transaction->getReferenceId(); 109 | $cardNumber = $response['cardNumber']; 110 | $paid_at = $response['paidAt']; 111 | 112 | $toMatch = new FieldsToMatch($orderId, null, null, new Amount($amount, 'IRR')); 113 | 114 | return new SettledTransaction($transaction, $traceNumber, $toMatch, $cardNumber, '', compact('paid_at')); 115 | } 116 | 117 | /** 118 | * {@inheritdoc} 119 | */ 120 | public function getSupportedExtraFieldsSample() 121 | { 122 | return [ 123 | 'mobile' => '09124441122', 124 | 'description' => 'توضیحات مربوط به سفارش (در گزارشات مختلف نشان‌داده خواهند شد)', 125 | 'allowed_card' => '(string[] list)'. 126 | ' چنانچه تمایل دارید کاربر فقط از شماره کارت‌های مشخصی بتواند پرداخت کند'. 127 | ' لیست کارت(های) 16 رقمی را ارسال کنید', 128 | 'link_to_pay' => '(bool) true || false'. 129 | ' در صورتی که درگاه شما دسترسی ارسال لینک کوتاه پرداخت را داشته باشد،'. 130 | ' با قراردادن این متغیر برابر با true لینک کوتاه پرداخت برای این تراکنش ساخته می‌شود.'. 131 | ' لازم به ذکر است در این حالت callbackUrl میتواند ارسال نشود', 132 | 'sms' => '(bool) true || false '. 133 | ' با قراردادن این متغیر برابر با true لینک کوتاه پرداخت به شماره mobile ارسال خواهد شد', 134 | 'percent_mode' => '(bool) true || false (default is false)'. 135 | ' در صورتی که نحوه تسهیم مبلغ شما به‌صورت درصدی می‌باشد، این مقدار را true ارسال کنید', 136 | 'fee_mode' => '(integer) 0 (کسر از تراکنش) ||'. 137 | ' 1 (کسر کارمزد از کیف پول متصل به درگاه (در پرداختیاری پشتیبانی نمی شود)) ||'. 138 | ' 2 (افزوده شدن مبلغ کارمزد به مبلغ پرداختی توسط مشتری)', 139 | 'multiplexing_infos' => 'لیستی از شی آیتم تسهیم - برای اطلاعات بیشتر مستندات درگاه مطالعه شود', 140 | ]; 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/Providers/Zibal/ZibalException.php: -------------------------------------------------------------------------------- 1 | `message` 11 | * 12 | * @return array 13 | */ 14 | protected function getErrors() 15 | { 16 | return [ 17 | // token generation results 18 | 100 => 'با موفقیت تایید شد.', 19 | 102 => 'merchant یافت نشد.', 20 | 103 => 'merchant غیرفعال', 21 | 104 => 'merchant نامعتبر', 22 | 105 => 'amount بایستی بزرگتر از 1,000 ریال باشد.', 23 | 106 => 'callbackUrl نامعتبر می‌باشد. (شروع با http و یا https)', 24 | 113 => 'amount مبلغ تراکنش از سقف میزان تراکنش بیشتر است.', 25 | 107 => 'percentMode نامعتبر می‌باشد. (تنها 0 و 1 قابل قبول هستند)', 26 | 108 => 'یک یا چند ذی‌نفع در multiplexing_infos نامعتبر می‌باشند. اطلاعات بیشتر', 27 | 109 => 'یک یا چند ذی‌نفع در multiplexing_infos غیرفعال می‌باشند. اطلاعات بیشتر', 28 | 110 => 'id = self در multiplexing_infos وجود ندارد.', 29 | 111 => 'amount با مجموع سهم‌ها در multiplexing_infos برابر نمی‌باشد.', 30 | 112 => 'موجودی کیف‌پول اصلی شما جهت ثبت این سفارش کافی نمی‌باشد. (در صورتی که fee_mode == true )', 31 | 32 | // verify results 33 | 201 => 'قبلا تایید شده.', 34 | 202 => 'سفارش پرداخت نشده یا ناموفق بوده است. جهت اطلاعات بیشتر جدول وضعیت‌ها را مطالعه کنید.', 35 | 203 => 'trackId نامعتبر می‌باشد.', 36 | 37 | // callback status 38 | -1 => 'در انتظار پردخت', 39 | -2 => 'خطای داخلی', 40 | 1 => 'پرداخت شده - تاییدشده', 41 | 2 => 'پرداخت شده - تاییدنشده', 42 | 3 => 'لغوشده توسط کاربر', 43 | 4 => '‌شماره کارت نامعتبر می‌باشد.', 44 | 5 => '‌موجودی حساب کافی نمی‌باشد.', 45 | 6 => 'رمز واردشده اشتباه می‌باشد.', 46 | 7 => '‌تعداد درخواست‌ها بیش از حد مجاز می‌باشد.', 47 | 8 => '‌تعداد پرداخت اینترنتی روزانه بیش از حد مجاز می‌باشد.', 48 | 9 => 'مبلغ پرداخت اینترنتی روزانه بیش از حد مجاز می‌باشد.', 49 | 10 => '‌صادرکننده‌ی کارت نامعتبر می‌باشد.', 50 | 11 => '‌خطای سوییچ', 51 | 12 => 'کارت قابل دسترسی نمی‌باشد.', 52 | ]; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/RedirectResponse.php: -------------------------------------------------------------------------------- 1 | type = $type; 41 | $this->url = $url; 42 | $this->data = $data; 43 | } 44 | 45 | /** 46 | * @return string 47 | */ 48 | public function getType() 49 | { 50 | return $this->type; 51 | } 52 | 53 | /** 54 | * @return string 55 | */ 56 | public function getUrl() 57 | { 58 | return $this->url; 59 | } 60 | 61 | /** 62 | * @return array 63 | */ 64 | public function getData() 65 | { 66 | return $this->data; 67 | } 68 | 69 | /** 70 | * Redirect the user of the application to the provider's payment screen. 71 | * 72 | * @param \Illuminate\Container\Container $app 73 | * @return \Symfony\Component\HttpFoundation\RedirectResponse|\Illuminate\Contracts\View\View 74 | */ 75 | public function redirect($app) 76 | { 77 | if ($this->getType() === RedirectResponse::TYPE_GET) { 78 | return new \Symfony\Component\HttpFoundation\RedirectResponse($this->getUrl()); 79 | } else { 80 | $data = [ 81 | 'URL' => $this->getUrl(), 82 | 'Data' => $this->getData(), 83 | ]; 84 | 85 | return $this->view($app, 'gateway::redirector')->with($data); 86 | } 87 | } 88 | 89 | /** 90 | * Get the evaluated view contents for the given view. 91 | * 92 | * @param \Illuminate\Container\Container $app 93 | * @param string $view 94 | * @param array $data 95 | * @param array $mergeData 96 | * @return \Illuminate\View\View 97 | */ 98 | protected function view($app, $view = null, $data = [], $mergeData = []) 99 | { 100 | $factory = $app->make(\Illuminate\Contracts\View\Factory::class); 101 | 102 | if (func_num_args() === 0) { 103 | return $factory; 104 | } 105 | 106 | return $factory->make($view, $data, $mergeData); 107 | } 108 | 109 | /** 110 | * Get the instance as an array. 111 | * 112 | * @return array 113 | */ 114 | public function toArray() 115 | { 116 | return [ 117 | 'type' => $this->getType(), 118 | 'url' => $this->getUrl(), 119 | 'data' => $this->getData(), 120 | ]; 121 | } 122 | 123 | /** 124 | * Convert the object to its JSON representation. 125 | * 126 | * @param int $options 127 | * @return string 128 | */ 129 | public function toJson($options = 0) 130 | { 131 | $json = json_encode($this->jsonSerialize(), $options); 132 | 133 | if (JSON_ERROR_NONE !== json_last_error()) { 134 | throw new RuntimeException(json_last_error_msg()); 135 | } 136 | 137 | return $json; 138 | } 139 | 140 | /** 141 | * Specify data which should be serialized to JSON 142 | * 143 | * @link http://php.net/manual/en/jsonserializable.jsonserialize.php 144 | * 145 | * @return mixed data which can be serialized by json_encode, 146 | * which is a value of any type other than a resource. 147 | * 148 | * @since 5.4.0 149 | */ 150 | public function jsonSerialize() 151 | { 152 | return $this->toArray(); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/SoapClient.php: -------------------------------------------------------------------------------- 1 | config = $config; 36 | 37 | $this->attempts = intval(Arr::get($config, 'attempts')) ?: 1; 38 | 39 | $this->soap = new MainSoapClient($soapServer, $options); 40 | } 41 | 42 | /** 43 | * Try soap codes for multiple times 44 | * 45 | * @param int $attempts 46 | * @return mixed 47 | * 48 | * @throws \SoapFault 49 | */ 50 | protected function attempt($attempts, Closure $statements) 51 | { 52 | while ($attempts > 0) { 53 | try { 54 | return $statements(); 55 | } catch (\SoapFault $e) { 56 | $attempts--; 57 | 58 | if ($attempts == 0) { 59 | throw $e; 60 | } 61 | } 62 | } 63 | 64 | return false; 65 | } 66 | 67 | /** 68 | * @param string $name 69 | * @return mixed 70 | * 71 | * @throws \SoapFault 72 | */ 73 | public function __call($name, array $arguments) 74 | { 75 | return $this->attempt($this->attempts, function () use ($name, $arguments) { 76 | return call_user_func_array([$this->soap, $name], $arguments); 77 | }); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/Traits/HasIdField.php: -------------------------------------------------------------------------------- 1 | transaction; 20 | } 21 | 22 | /** 23 | * Set the transaction 24 | * 25 | * @param mixed $transaction 26 | */ 27 | public function setTransaction($transaction): void 28 | { 29 | $this->transaction = $transaction; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Transactions/AbstractTransaction.php: -------------------------------------------------------------------------------- 1 | 22 | * Name of the property 23 | *

24 | * @return bool 25 | */ 26 | public function __isset($name) 27 | { 28 | return isset($this->attributes[$name]); 29 | } 30 | 31 | /** 32 | * Get access to a property 33 | * 34 | * @param string $name

35 | * Name of the property 36 | *

37 | * @return mixed Property value 38 | */ 39 | public function &__get($name) 40 | { 41 | return $this->attributes[$name]; 42 | } 43 | 44 | /** 45 | * Overwrite a property 46 | * 47 | * @param string $name

48 | * Name of the property 49 | *

50 | * @param mixed $value

51 | * New property value 52 | *

53 | */ 54 | public function __set($name, $value) 55 | { 56 | $this->attributes[$name] = $value; 57 | } 58 | 59 | /** 60 | * Remove a property 61 | * 62 | * @param string $name

63 | * Name of the property to remove 64 | *

65 | */ 66 | public function __unset($name) 67 | { 68 | unset($this->attributes[$name]); 69 | } 70 | 71 | /** 72 | * {@inheritdoc} 73 | */ 74 | public function offsetExists($offset) 75 | { 76 | return isset($this->attributes[$offset]); 77 | } 78 | 79 | /** 80 | * {@inheritdoc} 81 | */ 82 | public function offsetGet($offset) 83 | { 84 | return isset($this->attributes[$offset]) ? $this->attributes[$offset] : null; 85 | } 86 | 87 | /** 88 | * {@inheritdoc} 89 | */ 90 | public function offsetSet($offset, $value) 91 | { 92 | if (! is_null($offset)) { 93 | $this->attributes[$offset] = $value; 94 | } 95 | } 96 | 97 | /** 98 | * {@inheritdoc} 99 | */ 100 | public function offsetUnset($offset) 101 | { 102 | unset($this->attributes[$offset]); 103 | } 104 | 105 | /** 106 | * {@inheritdoc} 107 | */ 108 | public function getAmount() 109 | { 110 | return $this['amount']; 111 | } 112 | 113 | /** 114 | * {@inheritdoc} 115 | */ 116 | public function getExtra() 117 | { 118 | return is_array($this['extra']) ? $this['extra'] : []; 119 | } 120 | 121 | /** 122 | * {@inheritdoc} 123 | */ 124 | public function getExtraField($key, $default = null) 125 | { 126 | return Arr::get($this['extra'], $key, $default); 127 | } 128 | 129 | /** 130 | * {@inheritdoc} 131 | */ 132 | public function getAttributes() 133 | { 134 | return $this->attributes; 135 | } 136 | 137 | /** 138 | * Set transaction's attributes. 139 | * 140 | * @return self 141 | */ 142 | public function setAttributes(array $attributes) 143 | { 144 | $this->attributes = $attributes; 145 | 146 | return $this; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/Transactions/AuthorizedTransaction.php: -------------------------------------------------------------------------------- 1 | setAttributes($transaction->getAttributes()); 37 | $instance['reference_id'] = $referenceId; 38 | $instance['token'] = $token; 39 | $instance['redirect'] = $redirect; 40 | 41 | return $instance; 42 | } 43 | 44 | /** 45 | * Create new instance from DB transaction table 46 | * 47 | * @param array $transaction 48 | * @return self 49 | */ 50 | public static function makeFromDB($transaction) 51 | { 52 | $instance = new self(); 53 | $instance->setAttributes($transaction); 54 | $instance['amount'] = new Amount($transaction['amount'], $transaction['currency']); 55 | $instance['extra'] = json_decode($transaction['extra'], JSON_OBJECT_AS_ARRAY); 56 | 57 | return $instance; 58 | } 59 | 60 | /** 61 | * Get the reference id of the transaction. 62 | * 63 | * @return string 64 | */ 65 | public function getReferenceId() 66 | { 67 | return $this['reference_id']; 68 | } 69 | 70 | /** 71 | * Get token of the transaction. 72 | * 73 | * @return string 74 | */ 75 | public function getToken() 76 | { 77 | return $this['token']; 78 | } 79 | 80 | /** 81 | * Get redirect response of the transaction. 82 | * 83 | * @return RedirectResponse 84 | */ 85 | public function getRedirect() 86 | { 87 | return $this['redirect']; 88 | } 89 | 90 | /** 91 | * generate equivalent UnAuthorizedTransaction from this instance 92 | * 93 | * @return UnAuthorizedTransaction 94 | */ 95 | public function generateUnAuthorized() 96 | { 97 | $transaction = new RequestTransaction($this->getAmount()); 98 | $transaction->setExtra($this->getExtra()); 99 | $unAuthorizedTransaction = new UnAuthorizedTransaction($transaction, $this->getId(), $this->getOrderId()); 100 | 101 | return $unAuthorizedTransaction; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Transactions/FieldsToMatch.php: -------------------------------------------------------------------------------- 1 | order_id = $order_id; 44 | $this->reference_id = $reference_id; 45 | $this->token = $token; 46 | $this->amount = $amount; 47 | } 48 | 49 | public function matches(Transaction $transaction): bool 50 | { 51 | foreach ($this->asArray() as $key => $value) { 52 | if ($transaction[$key] instanceof Amount && $value instanceof Amount) { 53 | return $transaction[$key]->equals($value); 54 | } elseif ($transaction[$key] != $value) { 55 | return false; 56 | } 57 | } 58 | 59 | return true; 60 | } 61 | 62 | public function asArray(): array 63 | { 64 | $fields = []; 65 | if (! empty($this->order_id)) { 66 | $fields['order_id'] = $this->order_id; 67 | } 68 | if (! empty($this->reference_id)) { 69 | $fields['reference_id'] = $this->reference_id; 70 | } 71 | if (! empty($this->token)) { 72 | $fields['token'] = $this->token; 73 | } 74 | if (! empty($this->amount)) { 75 | $fields['amount'] = $this->amount; 76 | } 77 | 78 | return $fields; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/Transactions/RequestTransaction.php: -------------------------------------------------------------------------------- 1 | setAmount($amount); 15 | } 16 | 17 | /** 18 | * Set the amount of transaction. 19 | * 20 | * @param Amount $amount 21 | * @return self 22 | */ 23 | public function setAmount($amount) 24 | { 25 | $this['amount'] = $amount; 26 | 27 | return $this; 28 | } 29 | 30 | /** 31 | * Set the extra information about the transaction. 32 | * 33 | * @param array $extra 34 | * @return self 35 | */ 36 | public function setExtra($extra) 37 | { 38 | $this['extra'] = $extra; 39 | 40 | return $this; 41 | } 42 | 43 | /** 44 | * Set the extra information field about the transaction. 45 | * 46 | * @param string $key 47 | * @param mixed $value 48 | * @return self 49 | */ 50 | public function setExtraField($key, $value) 51 | { 52 | $extra = $this['extra']; 53 | Arr::set($extra, $key, $value); 54 | $this['extra'] = $extra; 55 | 56 | return $this; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Transactions/SettledTransaction.php: -------------------------------------------------------------------------------- 1 | setAttributes($transaction->getAttributes()); 33 | $this['trace_number'] = $traceNumber; 34 | $this['to_match'] = $toMatch; 35 | $this['card_number'] = $cardNumber; 36 | $this['rrn'] = $RRN; 37 | $this['extra'] = array_merge($transaction->getExtra(), $extraFields); 38 | if (! empty($referenceId)) { 39 | $this['reference_id'] = $referenceId; 40 | } 41 | } 42 | 43 | /** 44 | * Get the trace number of transaction. 45 | * 46 | * @return string 47 | */ 48 | public function getTraceNumber() 49 | { 50 | return $this['trace_number']; 51 | } 52 | 53 | /** 54 | * Get fields to match. 55 | * 56 | * @return FieldsToMatch 57 | */ 58 | public function getFieldsToMatch() 59 | { 60 | return $this['to_match']; 61 | } 62 | 63 | /** 64 | * Get the card number of transaction. 65 | * 66 | * @return string 67 | */ 68 | public function getCardNumber() 69 | { 70 | return $this['card_number']; 71 | } 72 | 73 | /** 74 | * Get the Retrieval Reference Number of transaction. 75 | * 76 | * @return string 77 | */ 78 | public function getRRN() 79 | { 80 | return $this['rrn']; 81 | } 82 | 83 | /** 84 | * Get the reference id of the transaction. 85 | * 86 | * @return string 87 | */ 88 | public function getReferenceId() 89 | { 90 | return $this['reference_id']; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Transactions/UnAuthorizedTransaction.php: -------------------------------------------------------------------------------- 1 | setAttributes($transaction->getAttributes()); 22 | $this['id'] = $id; 23 | $this['order_id'] = $orderId; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /views/redirector.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 29 | 30 | --------------------------------------------------------------------------------