sberbank-acquiring 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +11 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +21 -0
- data/README.md +220 -0
- data/Rakefile +10 -0
- data/bin/console +7 -0
- data/bin/setup +8 -0
- data/lib/sberbank/acquiring.rb +32 -0
- data/lib/sberbank/acquiring/client.rb +67 -0
- data/lib/sberbank/acquiring/command_parameters_convertor.rb +51 -0
- data/lib/sberbank/acquiring/command_response_decorator.rb +38 -0
- data/lib/sberbank/acquiring/request.rb +36 -0
- data/lib/sberbank/acquiring/response.rb +23 -0
- data/lib/sberbank/acquiring/symmetric_key_checksum_validator.rb +34 -0
- data/lib/sberbank/acquiring/version.rb +7 -0
- data/sberbank-acquiring.gemspec +23 -0
- metadata +63 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 7f8468504447448f4c59173b580560f9a320ead9
|
|
4
|
+
data.tar.gz: 1eb948165621a4bb2cf43e426243b8366f1d7694
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 445a28f80ae3fc93ff514e89ff9720dbd8539705b338638c09e83977fa826ded919a303f38d19bc78ad0e978363160ca4b915b2b3caaae0e752afc10baf340b7
|
|
7
|
+
data.tar.gz: b720936ba81b9e777da382c4fa2bbbc3db768a02af4e819c7595fae38c5a8792fb15c7cc1b175bfc0858abac0b9a3d2370741dbbb652a1ca9fe2331c19c0d525
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sberbank-acquiring
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2.1.10
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Aleksandr Panasyuk
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Sberbank::Acquiring
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/panasyuk/sberbank-acquiring)
|
|
4
|
+
|
|
5
|
+
## Описание
|
|
6
|
+
|
|
7
|
+
GEM sberbank-acquiring предоставляет функциональность для взаимодействия с API эквайринга банка Сбербанк. Он использует RESTful API эквайринга Сбербанка.
|
|
8
|
+
|
|
9
|
+
Перед тем, как приступить к использованию этого гема, автор настоятельно рекомендует (хотя бы бегло) ознакомиться с официальной [документацией к JSON API эквайринга Сбербанка](https://securepayments.sberbank.ru/wiki/doku.php/integration:api:start), а так же [Wiki](https://github.com/panasyuk/sberbank-acquiring/wiki), кому интересно
|
|
10
|
+
|
|
11
|
+
## Установка
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
# Gemfile
|
|
15
|
+
gem 'sberbank-acquiring', github: 'panasyuk/sberbank-acquiring'
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Использование
|
|
19
|
+
|
|
20
|
+
### SBRF::Acquiring::Client
|
|
21
|
+
|
|
22
|
+
```ruby
|
|
23
|
+
# client отправляет запросы на боевой сервер эквайринга
|
|
24
|
+
client = SBRF::Acquiring::Client.new(username: 'username', password: 'password')
|
|
25
|
+
|
|
26
|
+
# test_client отправляет запросы на тестовый сервер эквайринга
|
|
27
|
+
test_client = SBRF::Acquiring::Client.new(token: 'token', test: true)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Клиент может выполнять следующие вызовы к API:
|
|
31
|
+
|
|
32
|
+
| Название метода | Путь API |
|
|
33
|
+
| -------------------------------- | --------------------------------------- |
|
|
34
|
+
| deposit | /payment/rest/deposit.do |
|
|
35
|
+
| get_order_status_extended | /payment/rest/getOrderStatusExtended.do |
|
|
36
|
+
| payment | /payment/rest/payment.do |
|
|
37
|
+
| payment_sber_pay | /payment/rest/paymentSberPay.do |
|
|
38
|
+
| refund | /payment/rest/refund.do |
|
|
39
|
+
| register | /payment/rest/register.do |
|
|
40
|
+
| register_pre_auth | /payment/rest/registerPreAuth.do |
|
|
41
|
+
| reverse | /payment/rest/reverse.do |
|
|
42
|
+
| verify_enrollment | /payment/rest/verifyEnrollment.do |
|
|
43
|
+
|
|
44
|
+
Все методы ожидают в качестве агрумента `Hash`, с ключами в **underscore**.
|
|
45
|
+
При подготовке параметров к отправке, эта структура претерпит следующие изменения:
|
|
46
|
+
|
|
47
|
+
1. Все ключи рекурсивно будут сконвертированы в **camelCase**
|
|
48
|
+
2. Все значения класса `Hash` будут переданы в виде JSON
|
|
49
|
+
|
|
50
|
+
Например этот код:
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
client.register(
|
|
54
|
+
amount: 1000,
|
|
55
|
+
order_number: 'order#1',
|
|
56
|
+
return_url: 'https://example.com/sberbank/success',
|
|
57
|
+
json_params: { user_email: 'test@example.com' }
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
сначала приведет параметры к следующему виду:
|
|
62
|
+
|
|
63
|
+
```ruby
|
|
64
|
+
{
|
|
65
|
+
'amount' => 1000,
|
|
66
|
+
'orderNumber' => 'order#1',
|
|
67
|
+
'returnUrl' => 'https://example.com/sberbank/success',
|
|
68
|
+
'jsonParams' => '{"userEmail":"test@example.com"}'
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
a затем превратит их в параметры запроса:
|
|
73
|
+
`amount=1000&orderNumber=order%231&returnUrl=https%3A%2F%2Fexample.com%2Fsberbank%2Fsuccess&jsonParams=%7B%22userEmail%22%3A%22test%40example.com%22%7D`
|
|
74
|
+
|
|
75
|
+
#### Создание заказа на 10 рублей
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
response = client.register(
|
|
79
|
+
amount: 1000, # в самых мелких долях валюты
|
|
80
|
+
order_number: 'order#1',
|
|
81
|
+
return_url: 'https://example.com/sberbank/success'
|
|
82
|
+
)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
response.success? # => true
|
|
87
|
+
response.error? # => false
|
|
88
|
+
|
|
89
|
+
response.data # => { "orderId" => "f3ced54d-45df-7c1a-f3ce-d54d04b11830", "formUrl" => "https://3dsec.sberbank.ru/payment/merchants/sbersafe/payment_ru.html?mdOrder=f3ced54d-45df-7c1a-f3ce-d54d04b11830" }
|
|
90
|
+
|
|
91
|
+
response.order_id # => "f3ced54d-45df-7c1a-f3ce-d54d04b11830"
|
|
92
|
+
response.form_url # => "https://3dsec.sberbank.ru/payment/merchants/sbersafe/payment_ru.html?mdOrder=f3ced54d-45df-7c1a-f3ce-d54d04b11830"
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### Проверка состояния заказа
|
|
97
|
+
```ruby
|
|
98
|
+
response = client.get_order_status_extended(order_id: 'f3ced54d-45df-7c1a-f3ce-d54d04b11830')
|
|
99
|
+
```
|
|
100
|
+
или
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
response = client.get_order_status_extended(order_number: 'order#1')
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
```ruby
|
|
107
|
+
response.data # =>
|
|
108
|
+
# {
|
|
109
|
+
# "errorCode" => "0",
|
|
110
|
+
# "errorMessage" => "Успешно",
|
|
111
|
+
# "orderNumber" => "order#2",
|
|
112
|
+
# "orderStatus" => 0,
|
|
113
|
+
# "actionCode" => -100,
|
|
114
|
+
# "actionCodeDescription" => "",
|
|
115
|
+
# "amount" => 1000,
|
|
116
|
+
# "currency" => "643",
|
|
117
|
+
# "date" => 1531643056391,
|
|
118
|
+
# "merchantOrderParams" => [],
|
|
119
|
+
# "attributes" => [{ "name" => "mdOrder", "value" => "aefeb658-48fb-7f37-aefe-b65804b11830" }],
|
|
120
|
+
# "terminalId" => "123456",
|
|
121
|
+
# "paymentAmountInfo" => { "paymentState" => "CREATED", "approvedAmount" => 0, "depositedAmount" => 0, "refundedAmount" => 0},
|
|
122
|
+
# "bankInfo" => { "bankCountryCode" => "UNKNOWN", "bankCountryName" => "<Неизвестно>" }
|
|
123
|
+
# }
|
|
124
|
+
|
|
125
|
+
response.attributes # => [{ "name" => "mdOrder", "value" => "aefeb658-48fb-7f37-aefe-b65804b11830" }]
|
|
126
|
+
response.bank_info # => { "bankCountryCode" => "UNKNOWN", "bankCountryName" => "<Неизвестно>" }
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Запрос состояния заказа с результатом на английском языке:
|
|
130
|
+
```ruby
|
|
131
|
+
response = client.get_order_status_extended(language: 'en', order_number: 'order#1')
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```ruby
|
|
135
|
+
response.data # =>
|
|
136
|
+
# {
|
|
137
|
+
# "errorCode" => "0",
|
|
138
|
+
# "errorMessage" => "Success",
|
|
139
|
+
# "orderNumber" => "order#2",
|
|
140
|
+
# "orderStatus" => 0,
|
|
141
|
+
# "actionCode" => -100,
|
|
142
|
+
# "actionCodeDescription" => "",
|
|
143
|
+
# "amount" => 1000,
|
|
144
|
+
# "currency" => "643",
|
|
145
|
+
# "date" => 1531643056391,
|
|
146
|
+
# "merchantOrderParams" => [],
|
|
147
|
+
# "attributes" => [{ "name" => "mdOrder", "value" => "aefeb658-48fb-7f37-aefe-b65804b11830" }],
|
|
148
|
+
# "terminalId" => "123456",
|
|
149
|
+
# "paymentAmountInfo" => { "paymentState" => "CREATED", "approvedAmount" => 0, "depositedAmount" => 0, "refundedAmount" => 0},
|
|
150
|
+
# "bankInfo" => { "bankCountryCode" => "UNKNOWN", "bankCountryName" => "<Unknown>" }
|
|
151
|
+
# }
|
|
152
|
+
|
|
153
|
+
response.terminal_id # => "123456"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Проверка контрольной суммы callback-уведомлений
|
|
157
|
+
|
|
158
|
+
API эквайринга Сбербанка поддерживает два вида callback-уведомлений: без контрольной суммы и с контрольной суммой.
|
|
159
|
+
В случае обработки уведомления с контрольной суммой, алгоритм проверки включает в себя выполнение запроса 'getOrderStatusExtended' к API эквайринга для проверки действительного статуса платежа. В остальных случаях требуется проверка параметра `checksum` с использованием симметричного или асимметричного ключа.
|
|
160
|
+
|
|
161
|
+
#### Симметричный ключ
|
|
162
|
+
|
|
163
|
+
```ruby
|
|
164
|
+
# params = {}
|
|
165
|
+
symmetric_key = '20546026a3675994185a132875efe41a'
|
|
166
|
+
|
|
167
|
+
callback_params = params.dup
|
|
168
|
+
checksum = callback_params.delete('checksum')
|
|
169
|
+
|
|
170
|
+
validator = Sberbank::Acquiring::SymmetricKeyChecksumValidator.new(symmetric_key)
|
|
171
|
+
if validator.validate(checksum, callback_params)
|
|
172
|
+
# запрос успешно прошел валидацию, контрольная сумма верна
|
|
173
|
+
else
|
|
174
|
+
# запрос не может быть обработан, так как контрольная сумма неверна
|
|
175
|
+
end
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Разработка
|
|
179
|
+
|
|
180
|
+
После клонирования репозитория, выполните `bin/setup` чтобы установить зависимости. Затем выполните `rake test`, чтобы запустить тесты. Так же можно запустить интерактивную консоль для экспериментов, выполнив `bin/console`.
|
|
181
|
+
|
|
182
|
+
## TODO
|
|
183
|
+
|
|
184
|
+
1. Добавить проверку Callback-уведомлений для асимметричного ключа
|
|
185
|
+
2. v0.1.0
|
|
186
|
+
3. Добавить API для того чтобы сделать удобнее отправку заказов по ФФД 1.05. Примерный API:
|
|
187
|
+
```ruby
|
|
188
|
+
sberbank_order = SBRF::Acquiring::Order.new(
|
|
189
|
+
number: 'order#1',
|
|
190
|
+
amount: 1,
|
|
191
|
+
amount_cents: 100,
|
|
192
|
+
return_url: 'https://',
|
|
193
|
+
fail_url: 'https://',
|
|
194
|
+
params: { email: 'email@example.com' },
|
|
195
|
+
tax_system: SBRF::USN_INCOME
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
item =
|
|
199
|
+
SBRF::Acquiring::Item.new(
|
|
200
|
+
name: 'item#1',
|
|
201
|
+
quantity: 2,
|
|
202
|
+
measure: 'pcs',
|
|
203
|
+
price: 1,
|
|
204
|
+
code: 'item#1',
|
|
205
|
+
tax: SBRF::VAT0)
|
|
206
|
+
|
|
207
|
+
item.tax = SBRF::VAT18
|
|
208
|
+
|
|
209
|
+
item.to_h #=> { name: '', quantity: 2. ... amount: 200, tax: { tax_type: 3, tax_sum: 36 } }
|
|
210
|
+
|
|
211
|
+
sberbank_order.items << item
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Contributing
|
|
215
|
+
|
|
216
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/panasyuk/sberbank-acquiring.
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/setup
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'sberbank/acquiring/version'
|
|
4
|
+
require 'sberbank/acquiring/response'
|
|
5
|
+
require 'sberbank/acquiring/request'
|
|
6
|
+
require 'sberbank/acquiring/command_parameters_convertor'
|
|
7
|
+
require 'sberbank/acquiring/command_response_decorator'
|
|
8
|
+
require 'sberbank/acquiring/client'
|
|
9
|
+
require 'sberbank/acquiring/symmetric_key_checksum_validator'
|
|
10
|
+
|
|
11
|
+
module Sberbank
|
|
12
|
+
module Acquiring
|
|
13
|
+
# Order statuses according to https://securepayments.sberbank.ru/wiki/doku.php/integration:api:rest:requests:getorderstatusextended
|
|
14
|
+
ORDER_NOT_PAID = 0 # order is registered but not paid
|
|
15
|
+
ORDER_HOLDED = 1 # pre-auth amount is holded (for 2-step payments)
|
|
16
|
+
ORDER_AUTHORIZED = 2 # order amount is fully authorized
|
|
17
|
+
ORDER_CANCELLED = 3 # authorization is cancelled
|
|
18
|
+
ORDER_REFUNDED = 4 # transaction amount was refunded
|
|
19
|
+
ORDER_PENDING = 5 # authorization pending
|
|
20
|
+
ORDER_REJECTED = 6 # authorization rejected
|
|
21
|
+
|
|
22
|
+
OPERATION_SUCCEEDED = 1
|
|
23
|
+
OPERATION_FAILED = 0
|
|
24
|
+
|
|
25
|
+
OPERATION_APPROVED = 'approved'.freeze # amount holded
|
|
26
|
+
OPERATION_DEPOSITED = 'deposited'.freeze # oparation finished
|
|
27
|
+
OPERATION_REVERSED = 'reversed'.freeze # operation cancelled
|
|
28
|
+
OPERATION_REFUNDED = 'refunded'.freeze # amount refunded
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
SBRF = Sberbank
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sberbank
|
|
4
|
+
module Acquiring
|
|
5
|
+
class Client
|
|
6
|
+
attr_reader :test
|
|
7
|
+
alias test? test
|
|
8
|
+
|
|
9
|
+
def initialize(username: nil, password: nil, token: nil, test: false)
|
|
10
|
+
@test = !!test
|
|
11
|
+
@parameters_convertor = build_parameters_convertor(username: username, password: password, token: token)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def execute(path:, params:)
|
|
15
|
+
CommandResponseDecorator.new(
|
|
16
|
+
Request.new(path: path, params: @parameters_convertor.convert(params), test: test).perform
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def deposit(params)
|
|
21
|
+
execute(path: '/payment/rest/deposit.do', params: params)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def get_order_status_extended(params)
|
|
25
|
+
execute(path: '/payment/rest/getOrderStatusExtended.do', params: params)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def payment(params)
|
|
29
|
+
execute(path: '/payment/rest/payment.do', params: params)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def payment_sber_pay(params)
|
|
33
|
+
execute(path: '/payment/rest/paymentSberPay.do', params: params)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def refund(params)
|
|
37
|
+
execute(path: '/payment/rest/refund.do', params: params)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def register(params)
|
|
41
|
+
execute(path: '/payment/rest/register.do', params: params)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def register_pre_auth(params)
|
|
45
|
+
execute(path: '/payment/rest/registerPreAuth.do', params: params)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def reverse(params)
|
|
49
|
+
execute(path: '/payment/rest/reverse.do', params: params)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def verify_enrollment(params)
|
|
53
|
+
execute(path: '/payment/rest/verifyEnrollment.do', params: params)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
|
|
58
|
+
def build_parameters_convertor(username: nil, password: nil, token: nil)
|
|
59
|
+
CommandParametersConvertor.new(
|
|
60
|
+
token &&
|
|
61
|
+
{ 'token' => token } ||
|
|
62
|
+
{ 'userName' => username, 'password' => password }
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sberbank
|
|
4
|
+
module Acquiring
|
|
5
|
+
class CommandParametersConvertor
|
|
6
|
+
attr_reader :default_params
|
|
7
|
+
|
|
8
|
+
def initialize(default_params = {})
|
|
9
|
+
@default_params = default_params
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def convert(params)
|
|
13
|
+
jsonify_hash_values(camelize(params).merge!(default_params))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def camelize(params)
|
|
17
|
+
case params
|
|
18
|
+
when Hash then camelize_hash(params)
|
|
19
|
+
when Enumerable then camelize_enumerable(params)
|
|
20
|
+
else params
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def jsonify_hash_values(hash)
|
|
25
|
+
result = hash.dup
|
|
26
|
+
|
|
27
|
+
result.each do |k, v|
|
|
28
|
+
result[k] = v.is_a?(Hash) && v.to_json || v
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
result
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def camelize_string(string)
|
|
37
|
+
string.gsub(/_([a-z])/) { $1.upcase }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def camelize_hash(hash)
|
|
41
|
+
result = {}
|
|
42
|
+
hash.each { |k, v| result[camelize_string(k.to_s)] = camelize(v) }
|
|
43
|
+
result
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def camelize_enumerable(enumerable)
|
|
47
|
+
enumerable.map { |e| camelize(e) }
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
|
|
5
|
+
module Sberbank
|
|
6
|
+
module Acquiring
|
|
7
|
+
class CommandResponseDecorator
|
|
8
|
+
extend Forwardable
|
|
9
|
+
|
|
10
|
+
attr_reader :response
|
|
11
|
+
def_delegators :response, :data, :http_response, :http, :request
|
|
12
|
+
def_delegators :http, :body
|
|
13
|
+
|
|
14
|
+
def initialize(response)
|
|
15
|
+
@response = response
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def error?
|
|
19
|
+
data.nil? || data['errorCode'].to_i > 0
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def success?
|
|
23
|
+
!error?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def method_missing(name, *attrs)
|
|
27
|
+
key = camelize_string(name.to_s)
|
|
28
|
+
data.key?(key) ? data[key] : super
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def camelize_string(string)
|
|
34
|
+
string.gsub(/_([a-z])/) { $1.upcase }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'net/http'
|
|
4
|
+
require 'uri'
|
|
5
|
+
|
|
6
|
+
module Sberbank
|
|
7
|
+
module Acquiring
|
|
8
|
+
class Request
|
|
9
|
+
TEST_HOST = '3dsec.sberbank.ru'.freeze
|
|
10
|
+
PRODUCTION_HOST = 'securepayments.sberbank.ru'.freeze
|
|
11
|
+
|
|
12
|
+
attr_reader :path, :params, :response, :test, :http_request, :host
|
|
13
|
+
alias test? test
|
|
14
|
+
alias http http_request
|
|
15
|
+
|
|
16
|
+
def initialize(host: nil, params:, path:, test: false)
|
|
17
|
+
@host = host || test && TEST_HOST || PRODUCTION_HOST
|
|
18
|
+
@params = params
|
|
19
|
+
@path = path
|
|
20
|
+
@test = test
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def build_uri
|
|
24
|
+
URI::HTTPS.build(host: host, path: path, query: URI.encode_www_form(params))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def perform
|
|
28
|
+
uri = build_uri
|
|
29
|
+
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
|
30
|
+
@http_request = Net::HTTP::Get.new(uri)
|
|
31
|
+
@response = Response.new(http_response: http.request(@http_request), request: self)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Sberbank
|
|
4
|
+
module Acquiring
|
|
5
|
+
class Response
|
|
6
|
+
attr_reader :http_response, :request, :data
|
|
7
|
+
alias http http_response
|
|
8
|
+
|
|
9
|
+
def initialize(http_response:, request:)
|
|
10
|
+
@http_response = http_response
|
|
11
|
+
@request = request
|
|
12
|
+
@data = parse_response_body!
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def parse_response_body!
|
|
18
|
+
JSON.parse(@http_response.body)
|
|
19
|
+
rescue JSON::ParserError
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'openssl'
|
|
4
|
+
|
|
5
|
+
module Sberbank
|
|
6
|
+
module Acquiring
|
|
7
|
+
class SymmetricKeyChecksumValidator
|
|
8
|
+
DIGEST_CLASS = OpenSSL::Digest::SHA256
|
|
9
|
+
|
|
10
|
+
def initialize(key, digest = DIGEST_CLASS.new)
|
|
11
|
+
@key = key
|
|
12
|
+
@digest = digest
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def validate(checksum, params = {})
|
|
16
|
+
checksum == calculate_checksum(generate_digest_data(params))
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def calculate_checksum(data)
|
|
20
|
+
OpenSSL::HMAC.hexdigest(@digest, @key, data).upcase!
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def generate_digest_data(params)
|
|
26
|
+
params.
|
|
27
|
+
keys.
|
|
28
|
+
sort { |a, b| a.to_s <=> b.to_s }.
|
|
29
|
+
map { |param_key| "#{param_key};#{params[param_key]};" }.
|
|
30
|
+
join
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
|
+
require 'sberbank/acquiring/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'sberbank-acquiring'
|
|
7
|
+
spec.version = Sberbank::Acquiring::VERSION
|
|
8
|
+
spec.authors = ['Aleksandr Panasyuk']
|
|
9
|
+
spec.email = ['panasmeister@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'GEM that makes integration of Sberbank Acquiring easier'
|
|
12
|
+
spec.description = 'This is an implementation of Sberbank Acuiring API client'
|
|
13
|
+
spec.homepage = 'https://github.com/panasyuk/sberbank-acquiring'
|
|
14
|
+
spec.license = 'MIT'
|
|
15
|
+
|
|
16
|
+
# Specify which files should be added to the gem when it is released.
|
|
17
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
18
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
spec.require_paths = ['lib']
|
|
23
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: sberbank-acquiring
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Aleksandr Panasyuk
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2018-12-10 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: This is an implementation of Sberbank Acuiring API client
|
|
14
|
+
email:
|
|
15
|
+
- panasmeister@gmail.com
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files: []
|
|
19
|
+
files:
|
|
20
|
+
- ".gitignore"
|
|
21
|
+
- ".ruby-gemset"
|
|
22
|
+
- ".ruby-version"
|
|
23
|
+
- ".travis.yml"
|
|
24
|
+
- Gemfile
|
|
25
|
+
- LICENSE.txt
|
|
26
|
+
- README.md
|
|
27
|
+
- Rakefile
|
|
28
|
+
- bin/console
|
|
29
|
+
- bin/setup
|
|
30
|
+
- lib/sberbank/acquiring.rb
|
|
31
|
+
- lib/sberbank/acquiring/client.rb
|
|
32
|
+
- lib/sberbank/acquiring/command_parameters_convertor.rb
|
|
33
|
+
- lib/sberbank/acquiring/command_response_decorator.rb
|
|
34
|
+
- lib/sberbank/acquiring/request.rb
|
|
35
|
+
- lib/sberbank/acquiring/response.rb
|
|
36
|
+
- lib/sberbank/acquiring/symmetric_key_checksum_validator.rb
|
|
37
|
+
- lib/sberbank/acquiring/version.rb
|
|
38
|
+
- sberbank-acquiring.gemspec
|
|
39
|
+
homepage: https://github.com/panasyuk/sberbank-acquiring
|
|
40
|
+
licenses:
|
|
41
|
+
- MIT
|
|
42
|
+
metadata: {}
|
|
43
|
+
post_install_message:
|
|
44
|
+
rdoc_options: []
|
|
45
|
+
require_paths:
|
|
46
|
+
- lib
|
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
48
|
+
requirements:
|
|
49
|
+
- - ">="
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '0'
|
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
|
+
requirements:
|
|
54
|
+
- - ">="
|
|
55
|
+
- !ruby/object:Gem::Version
|
|
56
|
+
version: '0'
|
|
57
|
+
requirements: []
|
|
58
|
+
rubyforge_project:
|
|
59
|
+
rubygems_version: 2.4.8
|
|
60
|
+
signing_key:
|
|
61
|
+
specification_version: 4
|
|
62
|
+
summary: GEM that makes integration of Sberbank Acquiring easier
|
|
63
|
+
test_files: []
|