walletone 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/BrandyMint/walletone.svg)](https://travis-ci.org/BrandyMint/walletone)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/BrandyMint/walletone/badges/gpa.svg)](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:
|