walletone 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/LICENSE +0 -0
- data/README.md +110 -0
- data/lib/walletone.rb +52 -0
- data/lib/walletone/errors/bad_url_error.rb +4 -0
- data/lib/walletone/errors/walletone_error.rb +4 -0
- data/lib/walletone/fields.rb +81 -0
- data/lib/walletone/form.rb +30 -0
- data/lib/walletone/middleware.rb +5 -0
- data/lib/walletone/middleware/base.rb +68 -0
- data/lib/walletone/middleware/callback.rb +19 -0
- data/lib/walletone/notification.rb +17 -0
- data/lib/walletone/payment.rb +44 -0
- data/lib/walletone/signer.rb +45 -0
- data/lib/walletone/version.rb +3 -0
- data/spec/fabricators/fields_fabricator.rb +6 -0
- data/spec/fabricators/payment_fabricator.rb +5 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/walletone/fields_spec.rb +54 -0
- data/spec/walletone/form_spec.rb +20 -0
- data/spec/walletone/middleware/base_spec.rb +22 -0
- data/spec/walletone/middleware/callback_spec.rb +14 -0
- data/spec/walletone/notification_spec.rb +36 -0
- data/spec/walletone/payment_spec.rb +60 -0
- data/spec/walletone/signer_spec.rb +42 -0
- data/spec/walletone_spec.rb +18 -0
- data/walletone.gemspec +35 -0
- metadata +266 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ab9a944684b8e39c9412cb122c2fd1d7b128a06f
|
4
|
+
data.tar.gz: 9ed98422688067832bed0ca481d1302e80237e47
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a9bf93be1b557b034411849dcdaeceb4280b19a9c75f87c3d57cc85913456ae2528b42d0b6b82837f10e80563e9c34bee779f597b60f0b96587672742d82d16b
|
7
|
+
data.tar.gz: 39f6840032fac8b8fbfc0ab3856338bce8c2095ae59fa592e3a4462715416b53efd456303d6efa1da72495463211c4791fe4b65efdd775a8420069e091552361
|
data/LICENSE
ADDED
File without changes
|
data/README.md
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# walletone checkout client for ruby
|
2
|
+
|
3
|
+
[](https://travis-ci.org/BrandyMint/walletone)
|
4
|
+
[](https://codeclimate.com/github/BrandyMint/walletone)
|
5
|
+
|
6
|
+
---
|
7
|
+
|
8
|
+
## Прием уведомлений об оплате (rack middleware)
|
9
|
+
|
10
|
+
### 1. Создаем rack middleware для приема уведомлений
|
11
|
+
|
12
|
+
Сначала определимся как мы будем получать уведомление об оплате.
|
13
|
+
|
14
|
+
#### Вариант N1. Через callback
|
15
|
+
|
16
|
+
```ruby
|
17
|
+
wm = Walletone::Middleware::Callback.new do |notify, env|
|
18
|
+
# notify is a Walletone::Notification instance
|
19
|
+
|
20
|
+
raise 'Wrong sign' unless notify.valid? W1_SECRET_KEY
|
21
|
+
|
22
|
+
# TODO something with notify
|
23
|
+
|
24
|
+
'Return some message for OK response'
|
25
|
+
end
|
26
|
+
```
|
27
|
+
|
28
|
+
#### Вариант N2. Создаем свой класс middleware
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
class MyApp::WalletoneMiddleware < Waletone::Middleware::Base
|
32
|
+
def perform notify, env
|
33
|
+
raise 'Wrong sign' unless notify.valid? W1_SECRET_KEY
|
34
|
+
|
35
|
+
# TODO something with notify
|
36
|
+
'Return some message for OK response'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
wm = MyApp::WalletoneMiddleware.new
|
41
|
+
```
|
42
|
+
|
43
|
+
### 2. Подключаем middleware
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
# config.ru
|
47
|
+
run wm
|
48
|
+
|
49
|
+
# rails
|
50
|
+
mount wm => '/w1_callback'
|
51
|
+
```
|
52
|
+
|
53
|
+
### 3. Прописываем в настройках мерчанта на walletone.com получившийся url
|
54
|
+
|
55
|
+
Готово. Принимаем уведомления.
|
56
|
+
|
57
|
+
## Генерация формы оплаты
|
58
|
+
|
59
|
+
### Сначала заполняем необходимые для формы поля
|
60
|
+
|
61
|
+
Поля хранятся в объекте типа `Walletone::Payment`, который представляет из
|
62
|
+
себя `Hash` с возможностью прямого доступа к основным полям с префиксом `WMI_`.
|
63
|
+
|
64
|
+
Для полей требующих множественное значение (типа `WMI_PTENABLED`) в качестве
|
65
|
+
значений можно передавать массив строк.
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
payment = Walletone::Payment.new(
|
69
|
+
WMI_MERCHANT_ID: 'Номер вашего merchant ID',
|
70
|
+
WMI_PAYMENT_AMOUNT: 10000, # Сумма
|
71
|
+
WMI_CURRENCY_ID: 643, # ISO номер валюты (По умолчанию 643 - Рубль),
|
72
|
+
WMI_PTENABLED: ['WebMoneyRUB', 'WebMoneyUSD'],
|
73
|
+
SOME_CUSTOM_FIELD: 'value'
|
74
|
+
# etc любые другие поля
|
75
|
+
)
|
76
|
+
```
|
77
|
+
|
78
|
+
|
79
|
+
### Собственно генераця формы
|
80
|
+
|
81
|
+
```haml
|
82
|
+
- form = Walletone::Form.new payment
|
83
|
+
|
84
|
+
%h5 В течение 5-и секунд вы будете переправлены на страницу оплаты.
|
85
|
+
= form_tag form.checkout_url, form.options.merge(data: {autosubmit: true}) do |f|
|
86
|
+
= form.hidden_fields_tags
|
87
|
+
= submit_tag 'Перейти к оплате',
|
88
|
+
:class=>'btn btn-primary',
|
89
|
+
:data =>{:disable_with => 'Переправляю на сайт оплаты..'}
|
90
|
+
|
91
|
+
:coffee
|
92
|
+
# Автоматически сабмитим форму, чтобы не тревожить лишний раз
|
93
|
+
# пользователя
|
94
|
+
$ -> $('[data-autosubmit]').submit()
|
95
|
+
```
|
96
|
+
|
97
|
+
# Прочие ссылки
|
98
|
+
|
99
|
+
1. [Walletone Open API](https://api.w1.ru/OpenApi/)
|
100
|
+
2. [Документация (API)](http://www.walletone.com/ru/merchant/documentation/)
|
101
|
+
|
102
|
+
---
|
103
|
+
|
104
|
+
### Contributing
|
105
|
+
|
106
|
+
1. Fork it
|
107
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
108
|
+
3. Commit your changes (`git commit -am 'add some feature'`)
|
109
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
110
|
+
5. Create new Pull Request
|
data/lib/walletone.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'virtus'
|
3
|
+
|
4
|
+
require 'walletone/errors/walletone_error'
|
5
|
+
require 'walletone/errors/bad_url_error'
|
6
|
+
|
7
|
+
require 'walletone/payment'
|
8
|
+
require 'walletone/notification'
|
9
|
+
require 'walletone/middleware/base'
|
10
|
+
|
11
|
+
module Walletone
|
12
|
+
API_URL = 'https://api.w1.ru/OpenApi/'
|
13
|
+
V1_CHECKOUT_URL = 'https://www.walletone.com/checkout/default.aspx'
|
14
|
+
V2_CHECKOUT_URL = 'https://wl.walletone.com/checkout/checkout/Index'
|
15
|
+
|
16
|
+
class Configuration
|
17
|
+
include ::Singleton
|
18
|
+
attr_accessor :logger, :error_notifier, :error_notify_method, :web_checkout_url
|
19
|
+
|
20
|
+
def self.default_logger
|
21
|
+
logger = Logger.new(STDOUT)
|
22
|
+
logger.progname = 'walletone'
|
23
|
+
logger
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
self.logger = self.class.default_logger
|
28
|
+
self.web_checkout_url = V2_CHECKOUT_URL
|
29
|
+
self.error_notify_method = :notify
|
30
|
+
self.error_notifier = Honeybadger if defined? Honeybadger
|
31
|
+
self.error_notifier = Bugsnag if defined? Bugsnag
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.notify_error error, *args
|
36
|
+
logger.error "Catch error #{error}"
|
37
|
+
return unless config.error_notifier
|
38
|
+
config.error_notifier.send self.config.error_notify_method, error, *args
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.config
|
42
|
+
Configuration.instance
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.configure
|
46
|
+
yield config
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.logger
|
50
|
+
config.logger
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# Базовый класс для полей формы и уведомления
|
2
|
+
#
|
3
|
+
module Walletone
|
4
|
+
class Fields < Hash
|
5
|
+
# http://www.walletone.com/ru/merchant/documentation/#step2
|
6
|
+
#
|
7
|
+
#
|
8
|
+
W1_KEYS = %i(
|
9
|
+
WMI_MERCHANT_ID
|
10
|
+
WMI_PAYMENT_AMOUNT
|
11
|
+
WMI_CURRENCY_ID
|
12
|
+
WMI_PAYMENT_NO
|
13
|
+
WMI_DESCRIPTION
|
14
|
+
WMI_SUCCESS_URL WMI_FAIL_URL
|
15
|
+
WMI_EXPIRED_DATE
|
16
|
+
WMI_PTENABLED WMI_PTDISABLED
|
17
|
+
WMI_RECIPIENT_LOGIN
|
18
|
+
WMI_CUSTOMER_FIRSTNAME WMI_CUSTOMER_LASTNAME WMI_CUSTOMER_EMAIL
|
19
|
+
WMI_CULTURE_ID
|
20
|
+
WMI_SIGNATURE
|
21
|
+
WMI_DELIVERY_REQUEST
|
22
|
+
WMI_DELIVERY_COUNTRY WMI_DELIVERY_REGION WMI_DELIVERY_CITY WMI_DELIVERY_ADDRESS
|
23
|
+
WMI_DELIVERY_CONTACTINFO WMI_DELIVERY_COMMENTS WMI_DELIVERY_ORDERID
|
24
|
+
WMI_DELIVERY_DATEFROM WMI_DELIVERY_DATETILL
|
25
|
+
WMI_PSP_MERCHANT_ID
|
26
|
+
)
|
27
|
+
|
28
|
+
MULTIPLE_VALUES = %i(WMI_PTENABLED WMI_PTDISABLED)
|
29
|
+
|
30
|
+
# Определяем методы для прямого доступа
|
31
|
+
# > payment.WMI_MERCHANT_ID
|
32
|
+
# > payment.WMI_MERCHANT_ID=123
|
33
|
+
#
|
34
|
+
# > payment.WMI_PTENABLED =
|
35
|
+
W1_KEYS.each do |k|
|
36
|
+
define_method k do
|
37
|
+
fetch k
|
38
|
+
end
|
39
|
+
|
40
|
+
define_method "#{k}=" do |value|
|
41
|
+
self[k]= value
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def initialize attrs={}
|
46
|
+
fields = super
|
47
|
+
return fields if attrs.empty?
|
48
|
+
symbolyzed_attrs = attrs.inject({}) { |acc, e| acc[e.first.to_sym]=e.last; acc }
|
49
|
+
fields.merge! symbolyzed_attrs
|
50
|
+
end
|
51
|
+
|
52
|
+
def [] key
|
53
|
+
fetch key.to_sym, nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def []= key, value
|
57
|
+
super key.to_sym, value
|
58
|
+
end
|
59
|
+
|
60
|
+
def fetch key, default=nil
|
61
|
+
super key.to_sym, default
|
62
|
+
end
|
63
|
+
|
64
|
+
def as_list
|
65
|
+
keys.inject([]) do |acc, name|
|
66
|
+
# Делаем именно так, чтобы работало переопределение методов
|
67
|
+
# в Payment
|
68
|
+
value = respond_to?(name) ? send(name) : fetch(name)
|
69
|
+
Array(value).each { |v| acc << [name.to_s, v.to_s] }
|
70
|
+
acc
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def signer
|
77
|
+
Signer.new fields: self
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
module Walletone
|
3
|
+
class Form
|
4
|
+
include Virtus.model strict: true, coerce: false
|
5
|
+
attribute :payment, Payment, required: true
|
6
|
+
|
7
|
+
def checkout_url
|
8
|
+
Walletone.config.web_checkout_url
|
9
|
+
end
|
10
|
+
|
11
|
+
def hidden_fields_tags
|
12
|
+
payment.as_list.map do |field|
|
13
|
+
key, value = field
|
14
|
+
hidden_field_tag(key, value)
|
15
|
+
end.join
|
16
|
+
end
|
17
|
+
|
18
|
+
# Рекомендуемые опции
|
19
|
+
def options
|
20
|
+
{ authenticity_token: false, enforce_utf8: false }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def hidden_field_tag name, value
|
26
|
+
"<input name=\"#{CGI.escapeHTML(name.to_s)}\" type=\"hidden\" value=\"#{CGI.escapeHTML(value.to_s)}\" />"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'walletone/notification'
|
3
|
+
|
4
|
+
# Это rack-middleware который принимает на себя
|
5
|
+
# первый удар с уведомлением от walletone
|
6
|
+
# Несет следующие обязанности:
|
7
|
+
#
|
8
|
+
# 1. Перевести параметры из cp1251 в unicode
|
9
|
+
# 2. Построить объект типа Noficiation
|
10
|
+
# 3. Вызвать метод perform с аргументами notify и env
|
11
|
+
#
|
12
|
+
# Метод peform должет быть переопределен в классах наследниках.
|
13
|
+
# Например Walletone::Middleware::Base
|
14
|
+
#
|
15
|
+
module Walletone::Middleware
|
16
|
+
class Base
|
17
|
+
OK = 'OK'
|
18
|
+
RETRY = 'RETRY'
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
logger.info 'Middleware start'
|
22
|
+
request = Rack::Request.new env
|
23
|
+
encoded_params = from_cp1251_to_utf8 request.params
|
24
|
+
|
25
|
+
logger.info "Middleware parameters is #{encoded_params}"
|
26
|
+
notify = Walletone::Notification.new encoded_params
|
27
|
+
|
28
|
+
logger.info 'Middleware perform'
|
29
|
+
ok_message = perform notify, env
|
30
|
+
|
31
|
+
logger.info "Middleware result is #{ok_message}'"
|
32
|
+
|
33
|
+
body = make_response OK, ok_message
|
34
|
+
[200, {}, [body]]
|
35
|
+
rescue => err
|
36
|
+
Walletone.notify_error err
|
37
|
+
|
38
|
+
[200, {}, [make_response(RETRY, err.message)]]
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def logger
|
44
|
+
Walletone.logger
|
45
|
+
end
|
46
|
+
|
47
|
+
def perform notify, env
|
48
|
+
raise 'Walletone middleware perform method is not implemented'
|
49
|
+
end
|
50
|
+
|
51
|
+
def make_response(result, description)
|
52
|
+
# NOTE А нужно ли тут конвертировать в cp1251?
|
53
|
+
if description
|
54
|
+
"WMI_RESULT=#{result}&WMI_DESCRIPTION=#{description}"
|
55
|
+
else
|
56
|
+
"WMI_RESULT=#{result}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# walletone передает все параметры в cp1251
|
61
|
+
# приводим в uft-8
|
62
|
+
def from_cp1251_to_utf8(params)
|
63
|
+
params.map do |k, v|
|
64
|
+
[k, v.force_encoding("cp1251").encode("utf-8", undef: :replace)]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Walletone::Middleware
|
2
|
+
class Callback < Base
|
3
|
+
|
4
|
+
def initialize callback
|
5
|
+
raise 'Callback must be a Proc' unless callback.is_a? Proc
|
6
|
+
@callback = callback
|
7
|
+
super()
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
attr_reader :callback
|
13
|
+
|
14
|
+
def perform notify, env
|
15
|
+
callback.call notify, env
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'walletone/fields'
|
2
|
+
# Уведомление от walletone которое пришло через rack middleware callback
|
3
|
+
#
|
4
|
+
|
5
|
+
module Walletone
|
6
|
+
class Notification < Fields
|
7
|
+
|
8
|
+
def initialize params
|
9
|
+
super( params ).freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(secret_key, hash_type = Signer::DEFAULT_HASH_TYPE)
|
13
|
+
self.WMI_SIGNATURE == signer.signature( secret_key, hash_type )
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'walletone/fields'
|
2
|
+
require 'walletone/signer'
|
3
|
+
require 'base64'
|
4
|
+
require 'time'
|
5
|
+
|
6
|
+
# Поля для формы оплаты формируемые приложением
|
7
|
+
#
|
8
|
+
module Walletone
|
9
|
+
class Payment < Fields
|
10
|
+
RUB_ISO_NUMBER = 643
|
11
|
+
DEFAULT_CURRENTY = RUB_ISO_NUMBER
|
12
|
+
|
13
|
+
def sign!(secret_key, hash_type=Signer::DEFAULT_HASH_TYPE)
|
14
|
+
raise 'Already signed!' if signed?
|
15
|
+
self.WMI_SIGNATURE = signer.signature secret_key, hash_type
|
16
|
+
|
17
|
+
freeze
|
18
|
+
end
|
19
|
+
|
20
|
+
def signed?
|
21
|
+
self.WMI_SIGNATURE.is_a?(String) && ! self.WMI_SIGNATURE.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
def WMI_CURRENCY_ID
|
25
|
+
super || DEFAULT_CURRENTY
|
26
|
+
end
|
27
|
+
|
28
|
+
def WMI_PAYMENT_AMOUNT
|
29
|
+
value = super
|
30
|
+
"%.2f" % value if value
|
31
|
+
end
|
32
|
+
|
33
|
+
def WMI_DESCRIPTION
|
34
|
+
value = super
|
35
|
+
"BASE64:#{Base64.encode64(value[0...250])[0..-2]}" if value
|
36
|
+
end
|
37
|
+
|
38
|
+
def WMI_EXPIRED_DATE
|
39
|
+
value = super
|
40
|
+
value ? value.iso8601 : value
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
require 'digest/md5'
|
3
|
+
|
4
|
+
require 'walletone/fields'
|
5
|
+
|
6
|
+
module Walletone
|
7
|
+
class Signer
|
8
|
+
include Virtus.model strict: true, coerce: false
|
9
|
+
SIGN_HASH_TYPES = [:md5, :sha1]
|
10
|
+
DEFAULT_HASH_TYPE = :md5
|
11
|
+
WMI_SIGNATURE = 'WMI_SIGNATURE'
|
12
|
+
|
13
|
+
attribute :fields, Walletone::Fields, requried: true
|
14
|
+
|
15
|
+
def signature secret_key, hash_type=DEFAULT_HASH_TYPE
|
16
|
+
case hash_type
|
17
|
+
when :md5
|
18
|
+
Digest::MD5.base64digest( fields_as_string( secret_key ) )
|
19
|
+
when :sha1
|
20
|
+
Digest::SHA1.base64digest( fields_as_string( secret_key ) )
|
21
|
+
else
|
22
|
+
raise ArgumentError, hash_type
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def fields_as_string secret_key
|
29
|
+
[sorted_values, secret_key].join.encode('cp1251')
|
30
|
+
end
|
31
|
+
|
32
|
+
# Удаляем подпись и сортируем поля в алфавитном порядке
|
33
|
+
#
|
34
|
+
def sorted_values
|
35
|
+
fields
|
36
|
+
.as_list
|
37
|
+
.reject { |k, v| k == WMI_SIGNATURE }
|
38
|
+
.sort { |a, b| [ a[0], a[1] ] <=> [ b[0], b[1] ] }
|
39
|
+
.map(&:last)
|
40
|
+
.map(&:to_s)
|
41
|
+
.compact
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'walletone'
|
2
|
+
require 'fabrication'
|
3
|
+
require 'ffaker'
|
4
|
+
require 'pry'
|
5
|
+
|
6
|
+
Dir["./spec/support/**/*.rb"].sort.each { |f| require f}
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.order = :random
|
10
|
+
|
11
|
+
config.before(:all) do
|
12
|
+
Walletone.logger.level = Logger::FATAL
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'walletone/fields'
|
2
|
+
|
3
|
+
describe Walletone::Fields do
|
4
|
+
|
5
|
+
describe 'Именованные поля' do
|
6
|
+
subject { described_class.new }
|
7
|
+
let(:merchant_id) { 'some_id' }
|
8
|
+
|
9
|
+
it 'nill by default' do
|
10
|
+
expect(subject.WMI_MERCHANT_ID).to eq nil
|
11
|
+
end
|
12
|
+
it { expect(subject.WMI_MERCHANT_ID=merchant_id).to eq merchant_id }
|
13
|
+
|
14
|
+
context 'установили заранее' do
|
15
|
+
let(:merchant_id) { 'some_id2' }
|
16
|
+
before { subject.WMI_MERCHANT_ID= merchant_id }
|
17
|
+
it { expect(subject.WMI_MERCHANT_ID).to eq merchant_id }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#initialize' do
|
23
|
+
let(:fail_url) { 'someurl' }
|
24
|
+
let(:attrs) { { 'WMI_FAIL_URL' => fail_url } }
|
25
|
+
subject { described_class.new attrs }
|
26
|
+
|
27
|
+
it { expect(subject.WMI_FAIL_URL).to eq fail_url }
|
28
|
+
it { expect(subject['WMI_FAIL_URL']).to eq fail_url }
|
29
|
+
it { expect(subject[:WMI_FAIL_URL]).to eq fail_url }
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#fetch as keys and keys maybe as symbols or as strings' do
|
33
|
+
let(:fail_url) { 'someurl' }
|
34
|
+
let(:attrs) { { WMI_FAIL_URL: fail_url } }
|
35
|
+
subject { described_class.new attrs }
|
36
|
+
|
37
|
+
it { expect(subject[:WMI_FAIL_URL]).to eq fail_url }
|
38
|
+
it { expect(subject['WMI_FAIL_URL']).to eq fail_url }
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
describe '#as_list' do
|
43
|
+
let(:fail_url) { 'someurl' }
|
44
|
+
let(:pt_enabled) { ['WebMoneyRUB', 'WebMoneyUSD'] }
|
45
|
+
let(:attrs) { { WMI_FAIL_URL: fail_url, WMI_PTENABLED: pt_enabled } }
|
46
|
+
|
47
|
+
subject { described_class.new( attrs ).as_list }
|
48
|
+
|
49
|
+
it 'получаем список полей в строчном варианте' do
|
50
|
+
expect(subject).to eq [["WMI_FAIL_URL", "someurl"], ["WMI_PTENABLED", 'WebMoneyRUB'], ["WMI_PTENABLED", 'WebMoneyUSD']]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'walletone/form'
|
2
|
+
|
3
|
+
describe Walletone::Form do
|
4
|
+
let(:payment) { Fabricate :payment }
|
5
|
+
|
6
|
+
subject { described_class.new payment: payment }
|
7
|
+
|
8
|
+
describe '#checkout_url' do
|
9
|
+
it { expect(subject.checkout_url).to eq Walletone.config.web_checkout_url }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#hidden_fields_tags' do
|
13
|
+
it { expect(subject.hidden_fields_tags).to include 'input name' }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#options' do
|
17
|
+
it { expect(subject.options).to be_a Hash }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'walletone/middleware'
|
2
|
+
require 'walletone/middleware/base'
|
3
|
+
|
4
|
+
describe Walletone::Middleware::Base do
|
5
|
+
let(:middleware) { described_class.new }
|
6
|
+
let!(:params) { { cp1251: 'привет'.encode('windows-1251') } }
|
7
|
+
subject! { Rack::MockRequest.new(middleware).post('/', params: params ) }
|
8
|
+
|
9
|
+
it do
|
10
|
+
expect(subject.status).to eq 200
|
11
|
+
end
|
12
|
+
|
13
|
+
it do
|
14
|
+
expect(subject.body).to eq 'WMI_RESULT=RETRY&WMI_DESCRIPTION=Walletone middleware perform method is not implemented'
|
15
|
+
end
|
16
|
+
|
17
|
+
#Walletone.notify_callback = lambda do |resp, env|
|
18
|
+
#expect(resp.param(:cp1251).first).to eq('привет')
|
19
|
+
#resp.ok
|
20
|
+
#end
|
21
|
+
#end
|
22
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'walletone/middleware'
|
2
|
+
require 'walletone/middleware/callback'
|
3
|
+
|
4
|
+
describe Walletone::Middleware::Callback do
|
5
|
+
let(:callback) { -> (notify, env) { } }
|
6
|
+
let(:middleware) { described_class.new callback }
|
7
|
+
let!(:params) { { cp1251: 'привет'.encode('windows-1251') } }
|
8
|
+
subject! { Rack::MockRequest.new(middleware).post('/', params: params ) }
|
9
|
+
|
10
|
+
it do
|
11
|
+
expect(subject.body).to eq 'WMI_RESULT=OK'
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'walletone/notification'
|
2
|
+
|
3
|
+
describe Walletone::Notification do
|
4
|
+
let(:secret) { '623577687055676e43446f6c474f385165356e64556e474e5d7366' }
|
5
|
+
let(:signature) { '0v/qXN0eonX2+8AuiLLONQ==' }
|
6
|
+
let(:raw_params) do
|
7
|
+
{
|
8
|
+
'WMI_MERCHANT_ID' => '127696943127',
|
9
|
+
'WMI_CURRENCY_ID' => '643',
|
10
|
+
'WMI_PAYMENT_AMOUNT' => '3000.00',
|
11
|
+
'WMI_AUTO_ACCEPT' => '1',
|
12
|
+
'WMI_COMMISSION_AMOUNT' => '120.00',
|
13
|
+
'WMI_CREATE_DATE' => '2014-12-16 20:04:27',
|
14
|
+
'WMI_DESCRIPTION' => 'Браслет цепочка Хамса с цирконами золоченый',
|
15
|
+
'WMI_EXPIRED_DATE' => '2015-01-16 20:04:27',
|
16
|
+
'WMI_EXTERNAL_ACCOUNT_ID' => '4276********3093',
|
17
|
+
'WMI_LAST_NOTIFY_DATE' => '2014-12-16 20:07:44',
|
18
|
+
'WMI_NOTIFY_COUNT' => '3',
|
19
|
+
'WMI_ORDER_ID' => '346935973926',
|
20
|
+
'WMI_ORDER_STATE' => 'Accepted',
|
21
|
+
'WMI_PAYMENT_NO' => 'kiosk:5-604-pro',
|
22
|
+
'WMI_PAYMENT_TYPE' => 'CreditCardRUB',
|
23
|
+
'WMI_FAIL_URL' => 'http://wannabe.kiiiosk.ru/payments/w1/failure',
|
24
|
+
'WMI_SUCCESS_URL' => 'http://wannabe.kiiiosk.ru/payments/w1/success',
|
25
|
+
'WMI_UPDATE_DATE' => '2014-12-16 20:05:51',
|
26
|
+
'WMI_SIGNATURE' => signature
|
27
|
+
}
|
28
|
+
end
|
29
|
+
subject { described_class.new(raw_params) }
|
30
|
+
|
31
|
+
context '#valid?' do
|
32
|
+
it 'compare signatures from request and response' do
|
33
|
+
expect( subject.valid?(secret) ).to be_truthy
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
describe Walletone::Payment do
|
2
|
+
let(:merchant_id) { 127830694690 }
|
3
|
+
let(:secret_key) { '3475706857624f46344e573753316e387c396e5f4b54767b796c4c' }
|
4
|
+
|
5
|
+
subject { described_class.new fields }
|
6
|
+
|
7
|
+
context '.new' do
|
8
|
+
let(:fields) { Walletone::Fields.new WMI_MERCHANT_ID: merchant_id }
|
9
|
+
it 'works' do
|
10
|
+
expect(subject.WMI_MERCHANT_ID).to eq(merchant_id)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context '#sign' do
|
15
|
+
let(:signature) { 'uPmNH+YVl154kSH9hQdWNA==' }
|
16
|
+
let(:fields) { Walletone::Fields.new({
|
17
|
+
WMI_MERCHANT_ID: 127830694690,
|
18
|
+
WMI_PAYMENT_AMOUNT: 100.00,
|
19
|
+
WMI_PAYMENT_NO: '123-45',
|
20
|
+
WMI_CURRENCY_ID: 643,
|
21
|
+
WMI_DESCRIPTION: 'payment test',
|
22
|
+
WMI_EXPIRED_DATE: Time.new(2019, 12, 31, 23, 59, 59, "+00:00").utc,
|
23
|
+
WMI_SUCCESS_URL: 'http://w1.artemeff.com/w1/success',
|
24
|
+
WMI_FAIL_URL: 'http://w1.artemeff.com/w1/fail'
|
25
|
+
})
|
26
|
+
}
|
27
|
+
|
28
|
+
before do
|
29
|
+
subject.sign! secret_key
|
30
|
+
end
|
31
|
+
|
32
|
+
it { expect(subject).to be_frozen }
|
33
|
+
it { expect(subject).to be_signed }
|
34
|
+
it { expect(subject.WMI_SIGNATURE).to eq signature }
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'WMI_PAYMENT_AMOUNT' do
|
39
|
+
payment = Fabricate(:payment, {WMI_PAYMENT_AMOUNT: 1.2})
|
40
|
+
expect(payment.WMI_PAYMENT_AMOUNT).to eq('1.20')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'WMI_DESCRIPTION as base64' do
|
44
|
+
payment = Fabricate(:payment, {WMI_DESCRIPTION: 'test'})
|
45
|
+
expect(payment.WMI_DESCRIPTION).to eq('BASE64:dGVzdA==')
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'WMI_DESCRIPTION reduces to 250 symbols' do
|
49
|
+
description = FFaker::Lorem.sentence(128)
|
50
|
+
payment = Fabricate(:payment, {WMI_DESCRIPTION: description})
|
51
|
+
text = Base64.decode64(payment.WMI_DESCRIPTION)
|
52
|
+
expect(text.size).to eq(255)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'WMI_EXPIRED_DATE as ISO8601' do
|
56
|
+
date = Time.new(2015, 4, 1, 12, 00, 00)
|
57
|
+
payment = Fabricate(:payment, {WMI_EXPIRED_DATE: date})
|
58
|
+
expect(payment.WMI_EXPIRED_DATE).to eq date.iso8601
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'walletone/signer'
|
2
|
+
|
3
|
+
|
4
|
+
describe Walletone::Signer do
|
5
|
+
let(:secret_key) { '3475706857624f46344e573753316e387c396e5f4b54767b796c4c' }
|
6
|
+
|
7
|
+
subject { described_class.new fields: fields }
|
8
|
+
|
9
|
+
context '#sign' do
|
10
|
+
describe 'variant1' do
|
11
|
+
let(:fields) { Walletone::Fields.new(
|
12
|
+
WMI_MERCHANT_ID: '127830694690',
|
13
|
+
WMI_PAYMENT_AMOUNT: '100.00',
|
14
|
+
WMI_PAYMENT_NO: '123-45',
|
15
|
+
WMI_CURRENCY_ID: '643',
|
16
|
+
WMI_DESCRIPTION: 'BASE64:cGF5bWVudCB0ZXN0',
|
17
|
+
WMI_EXPIRED_DATE: '2019-12-31T23:59:59Z',
|
18
|
+
WMI_SUCCESS_URL: 'http://w1.artemeff.com/w1/success',
|
19
|
+
WMI_FAIL_URL: 'http://w1.artemeff.com/w1/fail'
|
20
|
+
)}
|
21
|
+
|
22
|
+
let(:signature) { 'uPmNH+YVl154kSH9hQdWNA==' }
|
23
|
+
it { expect( subject.signature( secret_key ) ).to eq signature }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'variant 2 (complex)' do
|
27
|
+
let(:payment_types) { ['WebMoneyRUB', 'WebMoneyUSD'] }
|
28
|
+
let(:fields) { Walletone::Fields.new({
|
29
|
+
WMI_MERCHANT_ID: 127830694690,
|
30
|
+
WMI_PAYMENT_AMOUNT: '100.00',
|
31
|
+
WMI_CURRENCY_ID: 643,
|
32
|
+
WMI_PTENABLED: payment_types,
|
33
|
+
foo: ['bar', 'baz']
|
34
|
+
}) }
|
35
|
+
let(:signature) { 'BF737gCE9O3JOR5iqQF1kg==' }
|
36
|
+
|
37
|
+
it { expect( subject.signature( secret_key ) ).to eq signature }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#is_valid = response.valid?('0v/qXN0eonX2+8AuiLLONQ==', secret)
|
42
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
describe Walletone do
|
2
|
+
context '.logger' do
|
3
|
+
it 'has logger' do
|
4
|
+
expect(described_class.logger).to be_a(Logger)
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
context '.notify_error' do
|
9
|
+
let(:error) { StandardError.new }
|
10
|
+
it do
|
11
|
+
error_notifier = double
|
12
|
+
allow(Walletone.config).to receive(:error_notifier).and_return error_notifier
|
13
|
+
expect(error_notifier).to receive(:notify).with(error)
|
14
|
+
expect(described_class.logger).to receive(:error)
|
15
|
+
described_class.notify_error error
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/walletone.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require 'walletone/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "walletone"
|
7
|
+
s.version = Walletone::VERSION
|
8
|
+
s.authors = ["Danil Pismenny", "Yuri Artemev"]
|
9
|
+
s.email = ["danil@brandymint.ru", "i@artemeff.com"]
|
10
|
+
s.homepage = "https://github.com/BrandyMint/walletone"
|
11
|
+
s.summary = %q{walleton.com Checkout client}
|
12
|
+
s.description = %q{Клиент для приема оплаты через walletone.com}
|
13
|
+
s.licenses = ['MIT']
|
14
|
+
|
15
|
+
s.files = %w(README.md LICENSE walletone.gemspec)
|
16
|
+
s.files += Dir.glob("lib/**/*.rb")
|
17
|
+
s.files += Dir.glob("spec/**/*")
|
18
|
+
s.require_paths = ['lib']
|
19
|
+
s.test_files = Dir.glob("spec/**/*")
|
20
|
+
|
21
|
+
s.add_dependency 'virtus', '~> 1.0.5'
|
22
|
+
s.add_dependency 'rack', '~> 1.6'
|
23
|
+
|
24
|
+
s.add_development_dependency 'rake'
|
25
|
+
s.add_development_dependency 'rspec', '~> 3.2.0'
|
26
|
+
s.add_development_dependency 'ffaker', '>= 2.0.0'
|
27
|
+
s.add_development_dependency 'fabrication', '~> 2.12.2'
|
28
|
+
s.add_development_dependency "pry"
|
29
|
+
s.add_development_dependency "pry-nav"
|
30
|
+
s.add_development_dependency "webmock"
|
31
|
+
s.add_development_dependency "guard"
|
32
|
+
s.add_development_dependency "guard-rspec"
|
33
|
+
s.add_development_dependency 'guard-ctags-bundler'
|
34
|
+
s.add_development_dependency 'yard'
|
35
|
+
end
|
metadata
ADDED
@@ -0,0 +1,266 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: walletone
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Danil Pismenny
|
8
|
+
- Yuri Artemev
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-04-10 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: virtus
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: 1.0.5
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: 1.0.5
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: rack
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.6'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.6'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rake
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 3.2.0
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 3.2.0
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: ffaker
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 2.0.0
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 2.0.0
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: fabrication
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 2.12.2
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 2.12.2
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: pry
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: pry-nav
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: webmock
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: guard
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
- !ruby/object:Gem::Dependency
|
155
|
+
name: guard-rspec
|
156
|
+
requirement: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - ">="
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
type: :development
|
162
|
+
prerelease: false
|
163
|
+
version_requirements: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - ">="
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: guard-ctags-bundler
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
type: :development
|
176
|
+
prerelease: false
|
177
|
+
version_requirements: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
- !ruby/object:Gem::Dependency
|
183
|
+
name: yard
|
184
|
+
requirement: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - ">="
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0'
|
189
|
+
type: :development
|
190
|
+
prerelease: false
|
191
|
+
version_requirements: !ruby/object:Gem::Requirement
|
192
|
+
requirements:
|
193
|
+
- - ">="
|
194
|
+
- !ruby/object:Gem::Version
|
195
|
+
version: '0'
|
196
|
+
description: "Клиент для приема оплаты через walletone.com"
|
197
|
+
email:
|
198
|
+
- danil@brandymint.ru
|
199
|
+
- i@artemeff.com
|
200
|
+
executables: []
|
201
|
+
extensions: []
|
202
|
+
extra_rdoc_files: []
|
203
|
+
files:
|
204
|
+
- LICENSE
|
205
|
+
- README.md
|
206
|
+
- lib/walletone.rb
|
207
|
+
- lib/walletone/errors/bad_url_error.rb
|
208
|
+
- lib/walletone/errors/walletone_error.rb
|
209
|
+
- lib/walletone/fields.rb
|
210
|
+
- lib/walletone/form.rb
|
211
|
+
- lib/walletone/middleware.rb
|
212
|
+
- lib/walletone/middleware/base.rb
|
213
|
+
- lib/walletone/middleware/callback.rb
|
214
|
+
- lib/walletone/notification.rb
|
215
|
+
- lib/walletone/payment.rb
|
216
|
+
- lib/walletone/signer.rb
|
217
|
+
- lib/walletone/version.rb
|
218
|
+
- spec/fabricators/fields_fabricator.rb
|
219
|
+
- spec/fabricators/payment_fabricator.rb
|
220
|
+
- spec/spec_helper.rb
|
221
|
+
- spec/walletone/fields_spec.rb
|
222
|
+
- spec/walletone/form_spec.rb
|
223
|
+
- spec/walletone/middleware/base_spec.rb
|
224
|
+
- spec/walletone/middleware/callback_spec.rb
|
225
|
+
- spec/walletone/notification_spec.rb
|
226
|
+
- spec/walletone/payment_spec.rb
|
227
|
+
- spec/walletone/signer_spec.rb
|
228
|
+
- spec/walletone_spec.rb
|
229
|
+
- walletone.gemspec
|
230
|
+
homepage: https://github.com/BrandyMint/walletone
|
231
|
+
licenses:
|
232
|
+
- MIT
|
233
|
+
metadata: {}
|
234
|
+
post_install_message:
|
235
|
+
rdoc_options: []
|
236
|
+
require_paths:
|
237
|
+
- lib
|
238
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
239
|
+
requirements:
|
240
|
+
- - ">="
|
241
|
+
- !ruby/object:Gem::Version
|
242
|
+
version: '0'
|
243
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
244
|
+
requirements:
|
245
|
+
- - ">="
|
246
|
+
- !ruby/object:Gem::Version
|
247
|
+
version: '0'
|
248
|
+
requirements: []
|
249
|
+
rubyforge_project:
|
250
|
+
rubygems_version: 2.2.2
|
251
|
+
signing_key:
|
252
|
+
specification_version: 4
|
253
|
+
summary: walleton.com Checkout client
|
254
|
+
test_files:
|
255
|
+
- spec/walletone/payment_spec.rb
|
256
|
+
- spec/walletone/fields_spec.rb
|
257
|
+
- spec/walletone/form_spec.rb
|
258
|
+
- spec/walletone/notification_spec.rb
|
259
|
+
- spec/walletone/middleware/callback_spec.rb
|
260
|
+
- spec/walletone/middleware/base_spec.rb
|
261
|
+
- spec/walletone/signer_spec.rb
|
262
|
+
- spec/spec_helper.rb
|
263
|
+
- spec/fabricators/payment_fabricator.rb
|
264
|
+
- spec/fabricators/fields_fabricator.rb
|
265
|
+
- spec/walletone_spec.rb
|
266
|
+
has_rdoc:
|