├── .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 | //
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 $name48 | * Name of the property 49 | *
50 | * @param mixed $value51 | * 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 $name63 | * 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 | --------------------------------------------------------------------------------