tinkoff_client 0.1.0 → 0.3.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 +4 -4
- data/lib/tinkoff_client/configuration.rb +7 -1
- data/lib/tinkoff_client/generators/templates/tinkoff_client_template.rb +5 -0
- data/lib/tinkoff_client/payment/encrypt_card_data.rb +30 -0
- data/lib/tinkoff_client/payment/payment.rb +304 -3
- data/lib/tinkoff_client/payment/request.rb +13 -2
- data/lib/tinkoff_client/payout/encrypt_data.rb +27 -0
- data/lib/tinkoff_client/payout/payout.rb +43 -0
- data/lib/tinkoff_client/payout/request.rb +36 -0
- data/lib/tinkoff_client/send_request.rb +15 -0
- data/lib/tinkoff_client/version.rb +1 -1
- data/lib/tinkoff_client.rb +2 -0
- metadata +35 -6
- data/lib/tinkoff_client/card_data.rb +0 -17
- data/lib/tinkoff_client/generators/service_generator.rb +0 -25
- data/lib/tinkoff_client/generators/templates/service_template.erb +0 -16
- data/lib/tinkoff_client/requests.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8990bbf320ba8d5f805720fcf02f28e09c1df07a6c412be63bab21cfcc50917e
|
4
|
+
data.tar.gz: c1d6ee75bfb21c213623f835f9868c59f75ae7860234875c9dfc4fac80260b9b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dac0bb925a463fa4d2ebc180048d4ba899c4aa7940abfb32a7d6193147f27763a4e4a60b0c4ae37f14b9d17bf045647da6999642636f6fa95610f7de4ec91761
|
7
|
+
data.tar.gz: 451995438000e3e794806b7a1d88413843c6244155856194e40b4ae9fcf432d2e7f6755cb5d31ffa3f9f558348a779f5574f6d08956582bd7c1d880a9d729f71
|
@@ -2,12 +2,18 @@
|
|
2
2
|
|
3
3
|
module TinkoffClient
|
4
4
|
class Configuration
|
5
|
-
attr_accessor :payment_public_key, :payment_terminal_key, :payment_terminal_secret
|
5
|
+
attr_accessor :payment_public_key, :payment_terminal_key, :payment_terminal_secret,
|
6
|
+
:payout_terminal_key, :payout_terminal_secret, :payout_certificate, :payout_private_key
|
6
7
|
|
7
8
|
def initialize
|
8
9
|
@payment_public_key = nil
|
9
10
|
@payment_terminal_key = nil
|
10
11
|
@payment_terminal_secret = nil
|
12
|
+
|
13
|
+
@payout_terminal_key = nil
|
14
|
+
@payout_terminal_secret = nil
|
15
|
+
@payout_certificate = nil
|
16
|
+
@payout_private_key = nil
|
11
17
|
end
|
12
18
|
end
|
13
19
|
end
|
@@ -2,4 +2,9 @@ TinkoffClient.configure do |c|
|
|
2
2
|
#c.payment_public_key = "./public.key"
|
3
3
|
c.payment_terminal_key = ENV["TERMINAL_KEY"]
|
4
4
|
c.payment_terminal_secret = ENV["TERMINAL_SECRET"]
|
5
|
+
|
6
|
+
c.payout_terminal_key = ENV["PAYOUT_TERMINAL_KEY"]
|
7
|
+
c.payout_terminal_secret = ENV["PAYOUT_TERMINAL_SECRET"]
|
8
|
+
c.payout_certificate = "./open-api-cert.pem"
|
9
|
+
c.payout_private_key = "./private.key"
|
5
10
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "openssl"
|
4
|
+
require "base64"
|
5
|
+
|
6
|
+
module TinkoffClient
|
7
|
+
module Payment
|
8
|
+
module EncryptCardData
|
9
|
+
|
10
|
+
# Метод реализует шифрование данных карты
|
11
|
+
#
|
12
|
+
# Используется в методе FinishAuthorize https://www.tinkoff.ru/kassa/develop/api/payments/finishAuthorize-request/
|
13
|
+
#
|
14
|
+
# Объект CardData собирается в виде списка «ключ=значение» (разделитель «;»), зашифровывается открытым ключом (X509 RSA 2048), получившееся бинарное значение кодируется в Base64. Открытый ключ генерируется Банком и выдается при регистрации терминала.
|
15
|
+
#
|
16
|
+
# Все поля обязательны.
|
17
|
+
# @param [Number] PAN
|
18
|
+
# @param [Number] ExpDate
|
19
|
+
# @param [String] CardHolder
|
20
|
+
# @param [String] CVV
|
21
|
+
# @see finish_authorize
|
22
|
+
def encrypt_data(keys)
|
23
|
+
card = keys[:Card]
|
24
|
+
concatenated = card.map { |k, v| [k, v].join("=") }.join(";")
|
25
|
+
public_key = OpenSSL::PKey::RSA.new File.read(TinkoffClient.configuration.payment_public_key)
|
26
|
+
card_data = Base64.encode64(public_key.public_encrypt(concatenated))
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -1,36 +1,337 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "./request"
|
4
|
-
require_relative "
|
4
|
+
require_relative "./encrypt_card_data"
|
5
5
|
|
6
6
|
module TinkoffClient
|
7
7
|
module Payment
|
8
|
-
extend
|
8
|
+
extend EncryptCardData
|
9
9
|
|
10
|
-
|
10
|
+
# Метод создает платеж: продавец получает ссылку на платежную форму и должен перенаправить по ней покупателя
|
11
|
+
#
|
12
|
+
# Полный список параметров https://www.tinkoff.ru/kassa/develop/api/payments/init-request/
|
13
|
+
#
|
14
|
+
# @param [Number] Amount
|
15
|
+
# @param [String] OrderId
|
16
|
+
# @return [Hash]
|
17
|
+
# *
|
18
|
+
# {"Success"=>true,
|
19
|
+
# "ErrorCode"=>"0",
|
20
|
+
# "TerminalKey"=>"1111111111",
|
21
|
+
# "Status"=>"NEW",
|
22
|
+
# "PaymentId"=>"123456789",
|
23
|
+
# "OrderId"=>"3331",
|
24
|
+
# "Amount"=>1000,
|
25
|
+
# "PaymentURL"=>"https://securepayments.tinkoff.ru/q2wER3t0"}
|
26
|
+
# @example
|
27
|
+
# #Предположим, что у нас есть User, Product и Order
|
28
|
+
#
|
29
|
+
# #User
|
30
|
+
# {"id"=>1,
|
31
|
+
# "email"=>"a@test.ru",
|
32
|
+
# "phone"=>"+79031234567"}
|
33
|
+
#
|
34
|
+
# #Product
|
35
|
+
# {"id"=>22,
|
36
|
+
# "name"=>"Наименование товара",
|
37
|
+
# "price"=>1000,
|
38
|
+
# "quantity"=>10}
|
39
|
+
#
|
40
|
+
# #Order
|
41
|
+
# {"id"=>5,
|
42
|
+
# "user_id"=>1,
|
43
|
+
# "product_id"=>22,
|
44
|
+
# "paid"=>false,
|
45
|
+
# "payment_id"=>nil}
|
46
|
+
#
|
47
|
+
# #Простая реализация логики получения платежной ссылки
|
48
|
+
# def create
|
49
|
+
# order = order.find(params[:order_id]) #Объявляем наш order
|
50
|
+
# product = order.product #Объявляем продукт
|
51
|
+
# result = TinkoffClient::Payment.init(Amount: product.amount, OrderId: order.id) #Вызываем наш init метод
|
52
|
+
# if result["Success"] #в случае, если Success (boolean) вернет true
|
53
|
+
# order.update(:order_params)
|
54
|
+
# redirect_to result["PaymentURL"] #Отправляем пользователя по ссылке на форму оплаты
|
55
|
+
# end
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# private
|
59
|
+
# def order_params
|
60
|
+
# params.transform_keys(&:underscore).permit(:payment_id)#Трансформируем ответ из Snake в Camel и пермитим его
|
61
|
+
# end
|
62
|
+
# @see https://www.tinkoff.ru/kassa/develop/api/payments/init-request/
|
63
|
+
def self.init(keys)
|
11
64
|
Request.request(path: "Init", keys: keys)
|
12
65
|
end
|
13
66
|
|
67
|
+
# Метод подтверждает платеж передачей реквизитов, а также списывает средства с карты покупателя при одностадийной оплате и блокирует указанную сумму при двухстадийной.
|
68
|
+
# Используется, если у площадки есть сертификация PCI DSS и собственная платежная форма.
|
69
|
+
#
|
70
|
+
# Полный список параметров https://www.tinkoff.ru/kassa/develop/api/payments/confirm-request/
|
71
|
+
#
|
72
|
+
# @param [Number] PaymentId
|
73
|
+
# @return [Hash]
|
74
|
+
# *
|
75
|
+
# {"Success"=>true,
|
76
|
+
# "ErrorCode"=>"0",
|
77
|
+
# "TerminalKey"=>"1111111111",
|
78
|
+
# "Status"=>"CONFIRMED",
|
79
|
+
# "PaymentId"=>"123456789",
|
80
|
+
# "OrderId"=>"3331"}
|
81
|
+
# @example
|
82
|
+
#
|
83
|
+
# #Order
|
84
|
+
# {"id"=>5,
|
85
|
+
# "user_id"=>1,
|
86
|
+
# "product_id"=>22,
|
87
|
+
# "paid"=>false,
|
88
|
+
# "payment_id"=>"123456789"} #Payment id получен в методе init
|
89
|
+
#
|
90
|
+
# def create
|
91
|
+
# order = order.find(params[:order_id]) #Объявляем наш order
|
92
|
+
# result = TinkoffClient::Payment.confirm(PaymentId: order.payment_id) #Вызываем наш confirm
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# @see https://www.tinkoff.ru/kassa/develop/api/payments/confirm-description/
|
96
|
+
# @see init
|
14
97
|
def self.confirm(keys)
|
15
98
|
Request.request(path: "Confirm", keys: keys)
|
16
99
|
end
|
17
100
|
|
101
|
+
|
102
|
+
# Метод возвращает текущий статус платежа.
|
103
|
+
#
|
104
|
+
# Полный список параметров https://www.tinkoff.ru/kassa/develop/api/payments/getstate-description/
|
105
|
+
#
|
106
|
+
# @param [Number] PaymentId
|
107
|
+
# @return [Hash]
|
108
|
+
# *
|
109
|
+
# {
|
110
|
+
# "Success"=>true,
|
111
|
+
# "ErrorCode"=>"0",
|
112
|
+
# "Message"=>"OK",
|
113
|
+
# "TerminalKey"=>"TinkoffBankTest",
|
114
|
+
# "Status"=>"CONFIRMED",
|
115
|
+
# "PaymentId"=>"2304882",
|
116
|
+
# "OrderId"=>"#419",
|
117
|
+
# "Amount"=>1000
|
118
|
+
# }
|
119
|
+
# @example
|
120
|
+
#
|
121
|
+
# #Order
|
122
|
+
# {"id"=>5,
|
123
|
+
# "user_id"=>1,
|
124
|
+
# "product_id"=>22,
|
125
|
+
# "paid"=>false,
|
126
|
+
# "payment_id"=>"123456789"} #Payment id получен в методе init
|
127
|
+
#
|
128
|
+
# def create
|
129
|
+
# order = order.find(params[:order_id]) #Объявляем наш order
|
130
|
+
# result = TinkoffClient::Payment.get_state(PaymentId: order.payment_id) #Вызываем наш get_state
|
131
|
+
# end
|
132
|
+
#
|
133
|
+
# @see https://www.tinkoff.ru/kassa/develop/api/payments/getstate-description/
|
134
|
+
# @see init
|
18
135
|
def self.get_state(keys)
|
19
136
|
Request.request(path: "GetState", keys: keys)
|
20
137
|
end
|
21
138
|
|
139
|
+
# Метод отменяет платеж.
|
140
|
+
#
|
141
|
+
# Полный список параметров https://www.tinkoff.ru/kassa/develop/api/payments/cancel-description/
|
142
|
+
#
|
143
|
+
# @param [Number] PaymentId
|
144
|
+
# @return [Hash]
|
145
|
+
# *
|
146
|
+
# {
|
147
|
+
# "Success"=>true,
|
148
|
+
# "ErrorCode"=>"0",
|
149
|
+
# "Message"=>"OK",
|
150
|
+
# "TerminalKey"=>"TinkoffBankTest",
|
151
|
+
# "Status"=>"REFUNDED",
|
152
|
+
# "PaymentId"=>"2304882",
|
153
|
+
# "OrderId"=>"#419",
|
154
|
+
# "Amount"=>1000
|
155
|
+
# }
|
156
|
+
# @example
|
157
|
+
#
|
158
|
+
# #Order
|
159
|
+
# {"id"=>5,
|
160
|
+
# "user_id"=>1,
|
161
|
+
# "product_id"=>22,
|
162
|
+
# "paid"=>false,
|
163
|
+
# "payment_id"=>"123456789"} #Payment id получен в методе init
|
164
|
+
#
|
165
|
+
# def create
|
166
|
+
# order = order.find(params[:order_id]) #Объявляем наш order
|
167
|
+
# result = TinkoffClient::Payment.cancel(PaymentId: order.payment_id) #Вызываем наш cancel
|
168
|
+
# end
|
169
|
+
#
|
170
|
+
# @see https://www.tinkoff.ru/kassa/develop/api/payments/cancel-description/
|
171
|
+
# @see init
|
22
172
|
def self.cancel(keys)
|
23
173
|
Request.request(path: "Cancel", keys: keys)
|
24
174
|
end
|
25
175
|
|
176
|
+
# Метод возвращает статус заказа.
|
177
|
+
#
|
178
|
+
# Полный список параметров https://www.tinkoff.ru/kassa/develop/api/payments/checkorder-description/
|
179
|
+
#
|
180
|
+
# @param [Number] OrderId
|
181
|
+
# @return [Hash]
|
182
|
+
# *
|
183
|
+
# {
|
184
|
+
# "Success": true,
|
185
|
+
# "ErrorCode": "0",
|
186
|
+
# "Message": "OK",
|
187
|
+
# "OrderId": "21057",
|
188
|
+
# "TerminalKey": "TinkoffBankTest",
|
189
|
+
# "Payments": [
|
190
|
+
# {
|
191
|
+
# "Status": "REJECTED",
|
192
|
+
# "PaymentId": 10063,
|
193
|
+
# "Rrn": 1234567,
|
194
|
+
# "Amount": 555,
|
195
|
+
# "Success": false,
|
196
|
+
# "ErrorCode": "1051",
|
197
|
+
# "Message": "Недостаточно средств на карте"
|
198
|
+
# },
|
199
|
+
# {
|
200
|
+
# "Status": "AUTH_FAIL",
|
201
|
+
# "PaymentId": 1005563,
|
202
|
+
# "Rrn": 1234567,
|
203
|
+
# "Amount": 555,
|
204
|
+
# "Success": false,
|
205
|
+
# "ErrorCode": "76",
|
206
|
+
# "Message": "Операция по иностранной карте недоступна."
|
207
|
+
# },
|
208
|
+
# {
|
209
|
+
# "Status": "NEW",
|
210
|
+
# "PaymentId": 100553363,
|
211
|
+
# "Rrn": 1234567,
|
212
|
+
# "Amount": 555,
|
213
|
+
# "Success": true,
|
214
|
+
# "ErrorCode": "0",
|
215
|
+
# "Message": "ok"
|
216
|
+
# }
|
217
|
+
# ]
|
218
|
+
# }
|
219
|
+
# @example
|
220
|
+
#
|
221
|
+
# #Order
|
222
|
+
# {"id"=>5,
|
223
|
+
# "user_id"=>1,
|
224
|
+
# "product_id"=>22,
|
225
|
+
# "paid"=>false,
|
226
|
+
# "payment_id"=>"123456789"}
|
227
|
+
#
|
228
|
+
# def create
|
229
|
+
# order = order.find(params[:order_id]) #Объявляем наш order
|
230
|
+
# result = TinkoffClient::Payment.check_order(OrderId: order.id) #Вызываем наш check_order
|
231
|
+
# end
|
232
|
+
#
|
233
|
+
# @see https://www.tinkoff.ru/kassa/develop/api/payments/checkorder-description/
|
234
|
+
# @see init
|
26
235
|
def self.check_order(keys)
|
27
236
|
Request.request(path: "CheckOrder", keys: keys)
|
28
237
|
end
|
29
238
|
|
239
|
+
# Метод позволяет отправить закрывающий чек в кассу.
|
240
|
+
# Условия работы метода:
|
241
|
+
# Закрывающий чек может быть отправлен если платежная сессия по первому чеку находится в статусе CONFIRMED.
|
242
|
+
# В платежной сессии был передан объект Receipt.
|
243
|
+
# В объекте Receipt был передан хотя бы один объект Receipt.Items.PaymentMethod = "full_prepayment" или "prepayment" или "advance"
|
244
|
+
#
|
245
|
+
# Полный список параметров https://www.tinkoff.ru/kassa/develop/api/payments/SendClosingReceipt-description/
|
246
|
+
#
|
247
|
+
# @param [Number] PaymentId
|
248
|
+
# @param [Hash] Receipt
|
249
|
+
# @param [Hash] Items
|
250
|
+
# @return [Hash]
|
251
|
+
# *
|
252
|
+
# {
|
253
|
+
# "Success"=>true,
|
254
|
+
# "ErrorCode"=>"0",
|
255
|
+
# "Message"=>"null",
|
256
|
+
# }
|
257
|
+
# @example
|
258
|
+
#
|
259
|
+
# #User
|
260
|
+
# {"id"=>1,
|
261
|
+
# "email"=>"a@test.ru",
|
262
|
+
# "phone"=>"+79031234567"}
|
263
|
+
#
|
264
|
+
# #Product
|
265
|
+
# {"id"=>22,
|
266
|
+
# "name"=>"Наименование товара",
|
267
|
+
# "price"=>1000,
|
268
|
+
# "quantity"=>10}
|
269
|
+
#
|
270
|
+
# #Order
|
271
|
+
# {"id"=>5,
|
272
|
+
# "user_id"=>1,
|
273
|
+
# "product_id"=>22,
|
274
|
+
# "paid"=>false,
|
275
|
+
# "payment_id"=>"123456789"} #Payment id получен в методе init
|
276
|
+
#
|
277
|
+
# def create
|
278
|
+
# order = order.find(params[:order_id]) #Объявляем наш order
|
279
|
+
# params = {
|
280
|
+
# PaymentId: order.payment_id,
|
281
|
+
# Receipt: { Email: order.user.email, Taxation: "osn",
|
282
|
+
# Items: [{ Name: order.product.title, Quantity: "1",
|
283
|
+
# Amount: order.product.price, Price: order.product.price,
|
284
|
+
# Tax: "vat20", PaymentMethod: "full_payment",
|
285
|
+
# PaymentObject: "lottery_prize" }] }
|
286
|
+
# }
|
287
|
+
# result = TinkoffClient::Payment.send_closing_receipt(params) #Вызываем наш send_closing_receipt
|
288
|
+
# end
|
289
|
+
#
|
290
|
+
# @see https://www.tinkoff.ru/kassa/develop/api/payments/SendClosingReceipt-description/
|
291
|
+
# @see init
|
30
292
|
def self.send_closing_receipt(keys)
|
31
293
|
Request.request(path: "SendClosingReceipt", keys: keys)
|
32
294
|
end
|
33
295
|
|
296
|
+
# Метод подтверждает платеж передачей реквизитов, а также списывает средства с карты покупателя при одностадийной оплате и блокирует указанную сумму при двухстадийной.
|
297
|
+
#
|
298
|
+
# Используется, если у площадки есть сертификация PCI DSS и собственная платежная форма.
|
299
|
+
#
|
300
|
+
# Полный список параметров https://www.tinkoff.ru/kassa/develop/api/payments/finish-authorize/
|
301
|
+
#
|
302
|
+
# @param [Number] PaymentId
|
303
|
+
# @param [Hash] Card
|
304
|
+
# @param [Number] PAN (Card)
|
305
|
+
# @param [Number] ExpDate (Card)
|
306
|
+
# @param [String] CardHolder (Card)
|
307
|
+
# @param [CVV] CardHolder (Card)
|
308
|
+
# @return [Hash]
|
309
|
+
# *
|
310
|
+
# {
|
311
|
+
# "Success"=>true,
|
312
|
+
# "ErrorCode"=>"0",
|
313
|
+
# "Message"=>"null",
|
314
|
+
# }
|
315
|
+
# @example
|
316
|
+
#
|
317
|
+
# #Order
|
318
|
+
# {"id"=>5,
|
319
|
+
# "user_id"=>1,
|
320
|
+
# "product_id"=>22,
|
321
|
+
# "paid"=>false,
|
322
|
+
# "payment_id"=>"123456789"} #Payment id получен в методе init
|
323
|
+
#
|
324
|
+
# def create
|
325
|
+
# order = order.find(params[:order_id]) #Объявляем наш order
|
326
|
+
# params = {
|
327
|
+
# PaymentId: order.payment_id,
|
328
|
+
# Card: { PAN: 5545454545454545, ExpDate: 4545, CardHolder: "IVAN PETROV", CVV: "111"}
|
329
|
+
# }
|
330
|
+
# result = TinkoffClient::Payment.finish_authorize(params) #Вызываем наш finish_authorize
|
331
|
+
# end
|
332
|
+
#
|
333
|
+
# @see https://www.tinkoff.ru/kassa/develop/api/payments/finish-authorize/
|
334
|
+
# @see encrypt_data
|
34
335
|
def self.finish_authorize(keys)
|
35
336
|
card_data = encrypt_data(keys)
|
36
337
|
keys[:CardData] = card_data
|
@@ -1,11 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../
|
3
|
+
require_relative "../send_request"
|
4
4
|
|
5
5
|
module TinkoffClient
|
6
6
|
module Payment
|
7
7
|
class Request
|
8
|
-
include
|
8
|
+
include SendRequest
|
9
9
|
|
10
10
|
attr_reader :url
|
11
11
|
|
@@ -18,6 +18,17 @@ module TinkoffClient
|
|
18
18
|
new(*args, &block).request(path: params[:path], keys: params[:keys])
|
19
19
|
end
|
20
20
|
|
21
|
+
def init_params(keys)
|
22
|
+
payload = {
|
23
|
+
TerminalKey: TinkoffClient.configuration.payment_terminal_key,
|
24
|
+
Password: TinkoffClient.configuration.payment_terminal_secret,
|
25
|
+
**keys,
|
26
|
+
}
|
27
|
+
|
28
|
+
payload[:Token] = generate_token(payload)
|
29
|
+
payload.except(:Password)
|
30
|
+
end
|
31
|
+
|
21
32
|
def generate_token(keys)
|
22
33
|
params = keys.except(:Receipt, :Shops, :DATA).sort.transpose[1].join
|
23
34
|
digest = Digest::SHA2.new(256).hexdigest params
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "openssl"
|
4
|
+
require "base64"
|
5
|
+
|
6
|
+
module TinkoffClient
|
7
|
+
module Payout
|
8
|
+
module EncryptData
|
9
|
+
def encrypt_data(keys)
|
10
|
+
pkey = OpenSSL::PKey::RSA.new File.read(TinkoffClient.configuration.payout_private_key)
|
11
|
+
cert = OpenSSL::X509::Certificate.new File.read(TinkoffClient.configuration.payout_certificate)
|
12
|
+
x509_serial_number = cert.serial.to_s
|
13
|
+
|
14
|
+
context_keys = { :TerminalKey => TinkoffClient.configuration.payout_terminal_key, **keys }
|
15
|
+
concatenated = context_keys.sort.transpose[1].join
|
16
|
+
|
17
|
+
digest = OpenSSL::Digest::SHA256.new concatenated
|
18
|
+
signed_bytes = pkey.sign "SHA256", digest.digest
|
19
|
+
|
20
|
+
signature_value = Base64::strict_encode64 signed_bytes
|
21
|
+
digest_value = Base64::strict_encode64 digest.digest
|
22
|
+
|
23
|
+
result = { signature_value: signature_value, digest_value: digest_value, x509_serial_number: x509_serial_number }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./request"
|
4
|
+
|
5
|
+
module TinkoffClient
|
6
|
+
module Payout
|
7
|
+
def self.add_customer(keys)
|
8
|
+
Request.request(path: "AddCustomer", keys: keys)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.get_customer(keys)
|
12
|
+
Request.request(path: "GetCustomer", keys: keys)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.remove_customer(keys)
|
16
|
+
Request.request(path: "RemoveCustomer", keys: keys)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.add_card(keys)
|
20
|
+
Request.request(path: "AddCard", keys: keys)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.get_card_list(keys)
|
24
|
+
Request.request(path: "GetCardList", keys: keys)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.remove_card(keys)
|
28
|
+
Request.request(path: "RemoveCard", keys: keys)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.init(keys)
|
32
|
+
Request.request(path: "Init", keys: keys)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.payment(keys)
|
36
|
+
Request.request(path: "Payment", keys: keys)
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.get_state(keys)
|
40
|
+
Request.request(path: "GetState", keys: keys)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../send_request"
|
4
|
+
require_relative "./encrypt_data"
|
5
|
+
|
6
|
+
module TinkoffClient
|
7
|
+
module Payout
|
8
|
+
class Request
|
9
|
+
include SendRequest
|
10
|
+
include EncryptData
|
11
|
+
|
12
|
+
attr_reader :url
|
13
|
+
|
14
|
+
def initialize(url)
|
15
|
+
@url = "https://securepay.tinkoff.ru/e2c/v2/".freeze
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.request(*args, &block)
|
19
|
+
params = args[0]
|
20
|
+
new(*args, &block).request(path: params[:path], keys: params[:keys])
|
21
|
+
end
|
22
|
+
|
23
|
+
def init_params(keys)
|
24
|
+
data = encrypt_data(keys)
|
25
|
+
payload = {
|
26
|
+
TerminalKey: TinkoffClient.configuration.payout_terminal_key,
|
27
|
+
SignatureValue: data[:signature_value],
|
28
|
+
DigestValue: data[:digest_value],
|
29
|
+
X509SerialNumber: data[:x509_serial_number],
|
30
|
+
**keys,
|
31
|
+
}
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "rest-client"
|
5
|
+
|
6
|
+
module TinkoffClient
|
7
|
+
module SendRequest
|
8
|
+
def request(path:, keys:)
|
9
|
+
url = @url + path
|
10
|
+
payload = init_params(keys).to_json
|
11
|
+
result = RestClient.post(url, payload, content_type: :json)
|
12
|
+
data = JSON.parse result.body
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/tinkoff_client.rb
CHANGED
@@ -3,11 +3,13 @@
|
|
3
3
|
require_relative "tinkoff_client/version"
|
4
4
|
require_relative "tinkoff_client/configuration"
|
5
5
|
require_relative "tinkoff_client/payment/payment"
|
6
|
+
require_relative "tinkoff_client/payout/payout"
|
6
7
|
|
7
8
|
module TinkoffClient
|
8
9
|
class Error < StandardError; end
|
9
10
|
|
10
11
|
include Payment
|
12
|
+
include Payout
|
11
13
|
|
12
14
|
class << self
|
13
15
|
attr_accessor :configuration
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tinkoff_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- netsky_prod
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
11
|
+
date: 2022-11-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -94,6 +94,34 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '13.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webdrivers
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '5.0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '5.0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: selenium-webdriver
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 4.6.1
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 4.6.1
|
97
125
|
description: Tinkoff Ruby API wrapper for payments and e2c payouts.
|
98
126
|
email:
|
99
127
|
- arenda244@ya.ru
|
@@ -102,15 +130,16 @@ extensions: []
|
|
102
130
|
extra_rdoc_files: []
|
103
131
|
files:
|
104
132
|
- lib/tinkoff_client.rb
|
105
|
-
- lib/tinkoff_client/card_data.rb
|
106
133
|
- lib/tinkoff_client/configuration.rb
|
107
|
-
- lib/tinkoff_client/generators/service_generator.rb
|
108
|
-
- lib/tinkoff_client/generators/templates/service_template.erb
|
109
134
|
- lib/tinkoff_client/generators/templates/tinkoff_client_template.rb
|
110
135
|
- lib/tinkoff_client/generators/tinkoff_client_generator.rb
|
136
|
+
- lib/tinkoff_client/payment/encrypt_card_data.rb
|
111
137
|
- lib/tinkoff_client/payment/payment.rb
|
112
138
|
- lib/tinkoff_client/payment/request.rb
|
113
|
-
- lib/tinkoff_client/
|
139
|
+
- lib/tinkoff_client/payout/encrypt_data.rb
|
140
|
+
- lib/tinkoff_client/payout/payout.rb
|
141
|
+
- lib/tinkoff_client/payout/request.rb
|
142
|
+
- lib/tinkoff_client/send_request.rb
|
114
143
|
- lib/tinkoff_client/version.rb
|
115
144
|
homepage: https://netsky.dev/opensource/tinkoff_client
|
116
145
|
licenses: []
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "json"
|
4
|
-
require "rest-client"
|
5
|
-
require "openssl"
|
6
|
-
require "base64"
|
7
|
-
|
8
|
-
module TinkoffClient
|
9
|
-
module CardData
|
10
|
-
def encrypt_data(keys)
|
11
|
-
card = keys[:Card]
|
12
|
-
concatenated = card.map { |k, v| [k, v].join("=") }.join(";")
|
13
|
-
public_key = OpenSSL::PKey::RSA.new TinkoffClient.configuration.payment_public_key
|
14
|
-
card_data = Base64.encode64(public_key.public_encrypt(concatenated))
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module TinkoffClient
|
2
|
-
module Generators
|
3
|
-
|
4
|
-
class ServiceGenerator < Rails::Generators::NamedBase
|
5
|
-
source_root File.expand_path('../templates', __FILE__)
|
6
|
-
|
7
|
-
argument :methods, type: :array, default: [], banner: "method method"
|
8
|
-
class_option :module, type: :string
|
9
|
-
|
10
|
-
def create_service_file
|
11
|
-
@module_name = options[:module]
|
12
|
-
|
13
|
-
service_dir_path = "app/services"
|
14
|
-
generator_dir_path = service_dir_path + ("/#{@module_name.underscore}" if @module_name.present?).to_s
|
15
|
-
generator_path = generator_dir_path + "/#{file_name}.rb"
|
16
|
-
|
17
|
-
Dir.mkdir(service_dir_path) unless File.exist?(service_dir_path)
|
18
|
-
Dir.mkdir(generator_dir_path) unless File.exist?(generator_dir_path)
|
19
|
-
|
20
|
-
template "service.erb", generator_path
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
<% if @module_name.present? %> module <%= @module_name.camelize %> <% end %>
|
2
|
-
class <%= class_name %>
|
3
|
-
|
4
|
-
def initialize
|
5
|
-
end
|
6
|
-
|
7
|
-
def call
|
8
|
-
end
|
9
|
-
|
10
|
-
<% if methods.present? %> private <% end %>
|
11
|
-
<% for method in methods %>
|
12
|
-
def <%= method %>
|
13
|
-
end
|
14
|
-
<% end %>
|
15
|
-
end
|
16
|
-
<% if @module_name.present? %> end <% end %>
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "json"
|
4
|
-
require "rest-client"
|
5
|
-
|
6
|
-
module TinkoffClient
|
7
|
-
module Requests
|
8
|
-
def request(path:, keys:)
|
9
|
-
url = @url + path
|
10
|
-
payload = init_params(keys).to_json
|
11
|
-
result = RestClient.post(url, payload, content_type: :json)
|
12
|
-
data = JSON.parse result.body
|
13
|
-
end
|
14
|
-
|
15
|
-
def init_params(keys)
|
16
|
-
payload = {
|
17
|
-
TerminalKey: TinkoffClient.configuration.payment_terminal_key,
|
18
|
-
Password: TinkoffClient.configuration.payment_terminal_secret,
|
19
|
-
**keys,
|
20
|
-
}
|
21
|
-
|
22
|
-
payload[:Token] = generate_token(payload)
|
23
|
-
payload.except(:Password)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|