rubykassa-fixed 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +28 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +71 -0
- data/Gemfile +28 -0
- data/Guardfile +5 -0
- data/MIT-LICENSE +20 -0
- data/README.md +121 -0
- data/Rakefile +7 -0
- data/app/controllers/robokassa_controller.rb +33 -0
- data/config/routes.rb +12 -0
- data/lib/generators/rubykassa/install_generator.rb +11 -0
- data/lib/generators/rubykassa/templates/rubykassa.rb +22 -0
- data/lib/rubykassa/action_view_extension.rb +16 -0
- data/lib/rubykassa/client.rb +36 -0
- data/lib/rubykassa/configuration.rb +43 -0
- data/lib/rubykassa/engine.rb +9 -0
- data/lib/rubykassa/notification.rb +27 -0
- data/lib/rubykassa/payment_interface.rb +66 -0
- data/lib/rubykassa/signature_generator.rb +58 -0
- data/lib/rubykassa/version.rb +3 -0
- data/lib/rubykassa/xml_interface.rb +88 -0
- data/lib/rubykassa.rb +27 -0
- data/rubykassa-fixed.gemspec +28 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/controllers/welcome_controller.rb +4 -0
- data/spec/dummy/app/views/layouts/application.html.erb +12 -0
- data/spec/dummy/app/views/welcome/index.html.erb +24 -0
- data/spec/dummy/config/application.rb +62 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +39 -0
- data/spec/dummy/config/environments/production.rb +69 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/rubykassa.rb +8 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +5 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/rubykassa/client_configuration_spec.rb +81 -0
- data/spec/rubykassa/notification_spec.rb +39 -0
- data/spec/rubykassa/payment_interface_spec.rb +37 -0
- data/spec/rubykassa/xml_interface_spec.rb +60 -0
- data/spec/spec_helper.rb +11 -0
- metadata +201 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 54d8c8b1a3a97c93010713ca5d875eb0fce98d1bf297c78c7c7f48c01d3edb2d
|
4
|
+
data.tar.gz: 2f985d14fe9e00888571396846fbf38e46abaf7f5d74c15250ba9e579c5183b6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e60209eb1a66887fa1073fd8566ae6681e6545898e6116c1a86831d8a476e6faa021cebd607bcd8b430cab0af949be345d27a59dc476473c699e37d98b7d70aa
|
7
|
+
data.tar.gz: 34a643e2287e1a1e303af4407c08703a29bd077c612ad2b324887cdbfef19ac9b24fbdcf0569bcfff0c1f6ee8ba4700ac2b6ec51000376d9e21eb7ad4817f9c3
|
data/.gitignore
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
.bundle/
|
2
|
+
log/*.log
|
3
|
+
pkg/
|
4
|
+
spec/dummy/log
|
5
|
+
spec/dummy/db/*.sqlite3
|
6
|
+
spec/dummy/tmp/
|
7
|
+
spec/dummy/.sass-cache
|
8
|
+
*.gem
|
9
|
+
*.rbc
|
10
|
+
.config
|
11
|
+
coverage
|
12
|
+
InstalledFiles
|
13
|
+
lib/bundler/man
|
14
|
+
rdoc
|
15
|
+
spec/reports
|
16
|
+
spec/tmp
|
17
|
+
spec/version_tmp
|
18
|
+
tmp
|
19
|
+
.DS_Store
|
20
|
+
passenger.3000.log
|
21
|
+
passenger.3000.pid.lock
|
22
|
+
.idea
|
23
|
+
|
24
|
+
# YARD artifacts
|
25
|
+
.yardoc
|
26
|
+
_yardoc
|
27
|
+
doc/
|
28
|
+
Gemfile.lock
|
data/.travis.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 2.0.0
|
5
|
+
- 2.1.8
|
6
|
+
- 2.2.4
|
7
|
+
- 2.3.0
|
8
|
+
env:
|
9
|
+
- "RAILS_VERSION=3.2.18"
|
10
|
+
- "RAILS_VERSION=4.0.0"
|
11
|
+
- "RAILS_VERSION=4.1.0"
|
12
|
+
- "RAILS_VERSION=4.2.0"
|
13
|
+
- "RAILS_VERSION=master"
|
14
|
+
matrix:
|
15
|
+
allow_failures:
|
16
|
+
- env: "RAILS_VERSION=master"
|
17
|
+
- env: "RAILS_VERSION=3.2.18"
|
18
|
+
- rvm: 1.9.3
|
19
|
+
before_install:
|
20
|
+
- gem install bundler
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
## Edge (not released)
|
2
|
+
|
3
|
+
* Change `XmlInterface` to support dynamic attributes in initialzer, add posibility to use it in test mode by @vidmantas [#23][], [#24][]
|
4
|
+
* Update base URL to reflect the changes in Robokassa API.
|
5
|
+
* Allow `pay_url` to accept block
|
6
|
+
* Hash algorithms implemented (Алгоритм расчёта хэша — http://docs.robokassa.ru/#3733) [#29][]
|
7
|
+
|
8
|
+
[#23]:https://github.com/ZeroOneStudio/rubykassa/pull/23
|
9
|
+
[#24]:https://github.com/ZeroOneStudio/rubykassa/pull/24
|
10
|
+
[#29]:https://github.com/ZeroOneStudio/rubykassa/pull/29
|
11
|
+
|
12
|
+
## 0.4.2
|
13
|
+
|
14
|
+
* force converting notification params to `HashWithIndifferentAccess` by @shir [#17][], [#18][]
|
15
|
+
|
16
|
+
[#17]:https://github.com/ZeroOneStudio/rubykassa/pull/17
|
17
|
+
[#18]:https://github.com/ZeroOneStudio/rubykassa/pull/18
|
18
|
+
|
19
|
+
## 0.4.1
|
20
|
+
|
21
|
+
* Add support html options in params by @JuraSN [#16][]
|
22
|
+
|
23
|
+
[#16]:https://github.com/ZeroOneStudio/rubykassa/pull/16
|
24
|
+
|
25
|
+
## 0.4.0
|
26
|
+
|
27
|
+
* Simplify callbacks logic: no more necessity to pass `controller` variable to lambda. Thanks @BrainNya for active promotion.
|
28
|
+
|
29
|
+
## 0.3.2
|
30
|
+
|
31
|
+
* Add confugurable result callback [#14][]
|
32
|
+
|
33
|
+
[#14]:https://github.com/ZeroOneStudio/rubykassa/pull/14
|
34
|
+
|
35
|
+
## 0.3.1
|
36
|
+
|
37
|
+
* Pass `controller` and `notification` variables to callback block by @1um [#12][]
|
38
|
+
* Create `@notification` for `RobokassaController#fail` by @1um [#13][]
|
39
|
+
|
40
|
+
[#12]:https://github.com/ZeroOneStudio/rubykassa/pull/12
|
41
|
+
[#13]:https://github.com/ZeroOneStudio/rubykassa/pull/13
|
42
|
+
|
43
|
+
## 0.3.0
|
44
|
+
|
45
|
+
* Add confugurable success and fail callbacks
|
46
|
+
|
47
|
+
## 0.2.6
|
48
|
+
|
49
|
+
* Fix bug with wrong signature generating with custom user params
|
50
|
+
|
51
|
+
## 0.2.5
|
52
|
+
|
53
|
+
* Fix bug with passing custom params
|
54
|
+
|
55
|
+
## 0.2.4
|
56
|
+
|
57
|
+
* Fix naming issue with pay helper: rename 'link_to_pay' to 'pay_url'.
|
58
|
+
|
59
|
+
## 0.2.3
|
60
|
+
|
61
|
+
* Fix bug with calling incorrect signature validating method in `robokassa_controller#paid`. [#3][]
|
62
|
+
* Fix bug with signatures comparison. Should compare downcased. [#4][]
|
63
|
+
|
64
|
+
[#3]:https://github.com/ZeroOneStudio/rubykassa/issues/3
|
65
|
+
[#4]:https://github.com/ZeroOneStudio/rubykassa/issues/4
|
66
|
+
|
67
|
+
## 0.2.2
|
68
|
+
|
69
|
+
* Fix description param name from `'InvDesc'` to `'Desc'`. Closes [#2][]
|
70
|
+
|
71
|
+
[#2]: https://github.com/ZeroOneStudio/rubykassa/issues/2
|
data/Gemfile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
rails_version = ENV["RAILS_VERSION"] || "default"
|
4
|
+
|
5
|
+
rails = case rails_version
|
6
|
+
when "master"
|
7
|
+
{ github: "rails/rails" }
|
8
|
+
when "3.0.0"
|
9
|
+
"~> 3.0.0"
|
10
|
+
when "3.1.0"
|
11
|
+
"~> 3.1.0"
|
12
|
+
when "3.2.0"
|
13
|
+
"~> 3.2.0"
|
14
|
+
when "4.0.0"
|
15
|
+
"~> 4.0.0"
|
16
|
+
when "default"
|
17
|
+
"~> 4.0.0"
|
18
|
+
else
|
19
|
+
"~> #{rails_version}"
|
20
|
+
end
|
21
|
+
|
22
|
+
gem "rails", rails
|
23
|
+
|
24
|
+
group :test do
|
25
|
+
gem "coveralls", require: false
|
26
|
+
end
|
27
|
+
|
28
|
+
gemspec
|
data/Guardfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
## The Rubykassa gem
|
2
|
+
|
3
|
+
[](http://badge.fury.io/rb/rubykassa)
|
4
|
+
[](http://travis-ci.org/ZeroOneStudio/rubykassa)
|
5
|
+
[](https://coveralls.io/r/ZeroOneStudio/rubykassa)
|
6
|
+
[](https://codeclimate.com/github/ZeroOneStudio/rubykassa)
|
7
|
+
[](https://gemnasium.com/ZeroOneStudio/rubykassa)
|
8
|
+
[](http://inch-ci.org/github/ZeroOneStudio/rubykassa)
|
9
|
+
|
10
|
+
by [Zero One][]
|
11
|
+
|
12
|
+
[Zero One]: http://zeroone.st
|
13
|
+
|
14
|
+
Yet another Ruby wrapper for [Robokassa API][]. Make Robokassa to work with your Rails project without pain. Rubykassa took the best from [robokassa gem][] and [Active Merchant Robokassa integration] but easier to use and setup.
|
15
|
+
|
16
|
+
[Robokassa API]: http://robokassa.ru/ru/Doc/Ru/Interface.aspx
|
17
|
+
[robokassa gem]: https://github.com/shaggyone/robokassa
|
18
|
+
[Active Merchant Robokassa integration]: https://github.com/Shopify/active_merchant/tree/master/lib/active_merchant/billing/integrations/robokassa
|
19
|
+
|
20
|
+
## Have questions?
|
21
|
+
|
22
|
+
[](https://gitter.im/ZeroOneStudio/rubykassa)
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
Add to your `Gemfile`:
|
27
|
+
|
28
|
+
gem "rubykassa"
|
29
|
+
|
30
|
+
## Usage
|
31
|
+
|
32
|
+
Run `rails g rubykassa:install`, get an initializer with the following code:
|
33
|
+
|
34
|
+
Rubykassa.configure do |config|
|
35
|
+
config.login = ENV["ROBOKASSA_LOGIN"]
|
36
|
+
config.first_password = ENV["ROBOKASSA_FIRST_PASSWORD"]
|
37
|
+
config.second_password = ENV["ROBOKASSA_SECOND_PASSWORD"]
|
38
|
+
config.mode = :test # or :production
|
39
|
+
config.http_method = :get # or :post
|
40
|
+
config.xml_http_method = :get # or :post
|
41
|
+
config.hash_algorithm = :md5 # or :ripemd160, :sha1, :sha256, :sha384, :sha512
|
42
|
+
end
|
43
|
+
|
44
|
+
and configure it with your credentials. NB! Keep in mind that we are using environment variables. So do not forget to configure your `ENV`. For example using [figaro gem](https://github.com/laserlemon/figaro).
|
45
|
+
|
46
|
+
Also, you need to specify Result URL, Success URL and Fail URL at the "Technical Settings" (Технические настройки) in your Robokassa dashboard:
|
47
|
+
|
48
|
+
* Result URL: `http://<your_domain>/robokassa/result`
|
49
|
+
* Success URL: `http://<your_domain>/robokassa/success`
|
50
|
+
* Fail URL: `http://<your_domain>/robokassa/fail`
|
51
|
+
|
52
|
+
To define custom success/fail callbacks you can also use the initializer:
|
53
|
+
|
54
|
+
Rubykassa.configure do |config|
|
55
|
+
...
|
56
|
+
config.success_callback = ->(notification) { render text: 'success' }
|
57
|
+
config.fail_callback = ->(notification) { redirect_to root_path }
|
58
|
+
config.result_callback = ->(notification) { render text: notification.success }
|
59
|
+
end
|
60
|
+
|
61
|
+
Lambdas are called in RobokassaController so you can respond with [any kind that is supported by Rails](http://guides.rubyonrails.org/layouts_and_rendering.html#creating-responses).
|
62
|
+
|
63
|
+
NOTE: `result_callback` should always return `"OK#{invoice_id}"` string. So, implement your custom logic above `render text: notification.success` line.
|
64
|
+
|
65
|
+
IMPORTANT: Don't forget to restart web server after every change
|
66
|
+
|
67
|
+
Mode is `:test` by default. For production you have to use `:production`.
|
68
|
+
`http_method` and `xml_http_method` are `:get` by default but can be configured as `:post`
|
69
|
+
|
70
|
+
Once you are done, simply use `pay_url` helper in your view:
|
71
|
+
|
72
|
+
<%= pay_url "Pay with Robokassa", ivoice_id, total_sum %>
|
73
|
+
|
74
|
+
Additionally you may want to pass extra options. There is no problem:
|
75
|
+
|
76
|
+
<%= pay_url "Pay with Robokassa", ivoice_id, total_sum, { description: "Invoice description", email: "foo@bar.com", currency: "WMZM", culture: :ru } %>
|
77
|
+
|
78
|
+
Or if you would like to pass some custom params use `custom` key in options hash:
|
79
|
+
|
80
|
+
<%= pay_url "Pay with Robokassa", ivoice_id, total_sum, { description: "Invoice description", email: "foo@bar.com", currency: "WMZM", culture: :ru, custom: { param1: "value1", param2: "value2" }} %>
|
81
|
+
|
82
|
+
Also `pay_url` helper can accept block:
|
83
|
+
|
84
|
+
<%= pay_url ivoice_id, total_sum do %>
|
85
|
+
Pay with Robokassa
|
86
|
+
<% end %>
|
87
|
+
|
88
|
+
You can also pass some HTML options with `html` key in options hash (Bootstrap 3 example):
|
89
|
+
|
90
|
+
<%= pay_url "Pay with Robokassa", ivoice_id, total_sum, { html: { class: 'btn btn-primary btn-bg' }}
|
91
|
+
|
92
|
+
If you need to implement Robokassa's XML interface functionality you have to the following:
|
93
|
+
|
94
|
+
xml_interface = Rubykassa::XmlInterface.new do |interface|
|
95
|
+
interface.invoice_id = your_invioce_id
|
96
|
+
interface.total = your_total_sum
|
97
|
+
interface.language = :ru # can be :en, :ru is default
|
98
|
+
end
|
99
|
+
|
100
|
+
then call whatever you need
|
101
|
+
|
102
|
+
xml_interface.get_currencies_list
|
103
|
+
xml_interface.get_payment_methods
|
104
|
+
xml_interface.get_rates
|
105
|
+
xml_interface.op_state
|
106
|
+
|
107
|
+
In test mode, `op_state` accepts hash with additional attributes you would like to get back with response, for example `{ 'StateCode' => 5 }` (more about [StateCode](http://robokassa.ru/en/Doc/En/Interface.aspx#interfeys)). Please note, that any additional parameters to `op_state` are discarded in production mode.
|
108
|
+
|
109
|
+
## Supported Rubies and Rails versions
|
110
|
+
|
111
|
+
See the CI build [](http://travis-ci.org/ZeroOneStudio/rubykassa)
|
112
|
+
|
113
|
+
## License
|
114
|
+
|
115
|
+
This project rocks and uses MIT-LICENSE
|
116
|
+
Copyright (c) 2013-2016 [Zero One][]
|
117
|
+
|
118
|
+
[ZERO.ONE]: http://www.zeroone.st
|
119
|
+
|
120
|
+
|
121
|
+
[](https://bitdeli.com/free "Bitdeli Badge")
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
class RobokassaController < ActionController::Base
|
2
|
+
before_action :create_notification
|
3
|
+
|
4
|
+
def result
|
5
|
+
if @notification.valid_result_signature?
|
6
|
+
instance_exec @notification, &Rubykassa.result_callback
|
7
|
+
else
|
8
|
+
instance_exec @notification, &Rubykassa.fail_callback
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def success
|
13
|
+
if @notification.valid_success_signature?
|
14
|
+
instance_exec @notification, &Rubykassa.success_callback
|
15
|
+
else
|
16
|
+
instance_exec @notification, &Rubykassa.fail_callback
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def fail
|
21
|
+
instance_exec @notification, &Rubykassa.fail_callback
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def create_notification
|
27
|
+
if request.get?
|
28
|
+
@notification = Rubykassa::Notification.new request.query_parameters
|
29
|
+
elsif request.post?
|
30
|
+
@notification = Rubykassa::Notification.new request.request_parameters
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module Rubykassa
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
def create_initializer_file
|
7
|
+
template 'rubykassa.rb',
|
8
|
+
File.join('config', 'initializers', 'rubykassa.rb')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Rubykassa.configure do |config|
|
2
|
+
config.login = ENV['ROBOKASSA_LOGIN']
|
3
|
+
config.first_password = ENV['ROBOKASSA_FIRST_PASSWORD']
|
4
|
+
config.second_password = ENV['ROBOKASSA_SECOND_PASSWORD']
|
5
|
+
config.mode = :test # or :production
|
6
|
+
config.http_method = :get # or :post
|
7
|
+
config.xml_http_method = :get # or :post
|
8
|
+
config.hash_algorithm = :md5 # or :ripemd160, :sha1, :sha256, :sha384, :sha512
|
9
|
+
|
10
|
+
# Result callback is called in RobokassaController#result action if valid signature
|
11
|
+
# was generated. It should always return "OK#{ invoice_id }" string, so implement
|
12
|
+
# your custom logic above `render text: notification.success` line
|
13
|
+
|
14
|
+
config.result_callback = ->(notification) do
|
15
|
+
render text: notification.success
|
16
|
+
end
|
17
|
+
|
18
|
+
# Define success or failure callbacks here like:
|
19
|
+
|
20
|
+
# config.success_callback = ->(notification) { render text: 'success' }
|
21
|
+
# config.fail_callback = ->(notification) { redirect_to root_path }
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rubykassa
|
2
|
+
module ActionViewExtension
|
3
|
+
def pay_url(phrase, invoice_id, total, options = {}, &block)
|
4
|
+
total, invoice_id = total.to_s, invoice_id.to_s
|
5
|
+
extra_params = options.except :custom, :html
|
6
|
+
custom_params = options[:custom] ||= {}
|
7
|
+
html_params = options[:html] ||= {}
|
8
|
+
url = Rubykassa.pay_url invoice_id, total, custom_params, extra_params
|
9
|
+
if block_given?
|
10
|
+
link_to phrase, url, html_params, &block
|
11
|
+
else
|
12
|
+
link_to phrase, url, html_params
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rubykassa/configuration'
|
2
|
+
|
3
|
+
module Rubykassa
|
4
|
+
class ConfigurationError < StandardError
|
5
|
+
ENV_MESSAGE =
|
6
|
+
'Invalid mode: only :test or :production are allowed'.freeze
|
7
|
+
HTTP_METHOD_MESSAGE =
|
8
|
+
'Invalid http method: only :get or :post are allowed'.freeze
|
9
|
+
HASH_ALGORITHM_MESSAGE = <<-MESSAGE.squish.freeze
|
10
|
+
Invalid hash algorithm: only
|
11
|
+
#{Configuration::HASH_ALGORITHMS.map(&:upcase).join ', '} are allowed
|
12
|
+
MESSAGE
|
13
|
+
|
14
|
+
def self.raise_errors_for(configuration)
|
15
|
+
if !configuration.correct_mode?
|
16
|
+
raise ConfigurationError, ENV_MESSAGE
|
17
|
+
end
|
18
|
+
if !configuration.correct_http_method? ||
|
19
|
+
!configuration.correct_xml_http_method?
|
20
|
+
raise ConfigurationError, HTTP_METHOD_MESSAGE
|
21
|
+
end
|
22
|
+
if !configuration.correct_hash_algorithm?
|
23
|
+
raise ConfigurationError, HASH_ALGORITHM_MESSAGE
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Client
|
29
|
+
cattr_accessor :configuration
|
30
|
+
def self.configure
|
31
|
+
self.configuration = Rubykassa::Configuration.new
|
32
|
+
yield self.configuration
|
33
|
+
ConfigurationError.raise_errors_for(self.configuration)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Rubykassa
|
2
|
+
class Configuration
|
3
|
+
ATTRIBUTES = [
|
4
|
+
:login, :first_password, :second_password, :mode, :http_method,
|
5
|
+
:xml_http_method, :success_callback, :fail_callback, :result_callback,
|
6
|
+
:hash_algorithm
|
7
|
+
]
|
8
|
+
HASH_ALGORITHMS = [:md5, :ripemd160, :sha1, :sha256, :sha384, :sha512]
|
9
|
+
|
10
|
+
attr_accessor *ATTRIBUTES
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
self.login = 'your_login'
|
14
|
+
self.first_password = 'first_password'
|
15
|
+
self.second_password = 'second_password'
|
16
|
+
self.mode = :test
|
17
|
+
self.http_method = :get
|
18
|
+
self.xml_http_method = :get
|
19
|
+
self.hash_algorithm = :md5
|
20
|
+
self.success_callback = ->(notification) { render text: 'success' }
|
21
|
+
self.fail_callback = ->(notification) { render text: 'fail' }
|
22
|
+
self.result_callback = ->(notification) do
|
23
|
+
render text: notification.success
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def correct_mode?
|
28
|
+
[:test, :production].include?(mode)
|
29
|
+
end
|
30
|
+
|
31
|
+
def correct_http_method?
|
32
|
+
[:get, :post].include?(http_method)
|
33
|
+
end
|
34
|
+
|
35
|
+
def correct_xml_http_method?
|
36
|
+
[:get, :post].include?(xml_http_method)
|
37
|
+
end
|
38
|
+
|
39
|
+
def correct_hash_algorithm?
|
40
|
+
HASH_ALGORITHMS.include?(hash_algorithm)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubykassa/signature_generator'
|
2
|
+
|
3
|
+
module Rubykassa
|
4
|
+
class Notification
|
5
|
+
include SignatureGenerator
|
6
|
+
|
7
|
+
attr_accessor :params
|
8
|
+
attr_reader :invoice_id, :total
|
9
|
+
|
10
|
+
def initialize(params = {})
|
11
|
+
@params = HashWithIndifferentAccess.new(params)
|
12
|
+
@invoice_id = @params['InvId']
|
13
|
+
@total = @params['OutSum']
|
14
|
+
end
|
15
|
+
|
16
|
+
%w(result success).map do |kind|
|
17
|
+
define_method "valid_#{kind}_signature?" do
|
18
|
+
@params['SignatureValue'].to_s.downcase ==
|
19
|
+
generate_signature_for(kind.to_sym)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def success
|
24
|
+
"OK#{@invoice_id}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'rubykassa/signature_generator'
|
2
|
+
|
3
|
+
module Rubykassa
|
4
|
+
class PaymentInterface
|
5
|
+
include SignatureGenerator
|
6
|
+
|
7
|
+
BASE_URL = 'https://auth.robokassa.ru/Merchant/Index.aspx'.freeze
|
8
|
+
PARAMS_CONFORMITY = {
|
9
|
+
login: 'MerchantLogin'.freeze,
|
10
|
+
total: 'OutSum'.freeze,
|
11
|
+
invoice_id: 'InvId'.freeze,
|
12
|
+
signature: 'SignatureValue'.freeze,
|
13
|
+
email: 'Email'.freeze,
|
14
|
+
currency: 'IncCurrLabel'.freeze,
|
15
|
+
description: 'Desc'.freeze,
|
16
|
+
culture: 'Culture'.freeze,
|
17
|
+
is_test: 'IsTest'.freeze,
|
18
|
+
receipt: 'Receipt'.freeze
|
19
|
+
}.freeze
|
20
|
+
|
21
|
+
attr_accessor :invoice_id, :total, :params
|
22
|
+
|
23
|
+
def initialize(&block)
|
24
|
+
instance_eval &block if block_given?
|
25
|
+
shpfy_params
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_mode?
|
29
|
+
Rubykassa.mode == :test
|
30
|
+
end
|
31
|
+
|
32
|
+
def pay_url(extra_params = {})
|
33
|
+
@receipt = extra_params.delete(:receipt).to_json
|
34
|
+
extra_params = extra_params.slice :currency, :description, :email, :culture
|
35
|
+
result_params = initial_options.merge(extra_params).map do |key, value|
|
36
|
+
if key =~ /^shp/
|
37
|
+
"#{key}=#{value}"
|
38
|
+
else
|
39
|
+
"#{PARAMS_CONFORMITY[key]}=#{value}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
result_params << URI.encode_www_form([[PARAMS_CONFORMITY[:receipt], @receipt]])
|
43
|
+
BASE_URL.dup << '?' << result_params.compact.join('&')
|
44
|
+
end
|
45
|
+
|
46
|
+
def initial_options
|
47
|
+
result = {
|
48
|
+
login: Rubykassa.login,
|
49
|
+
total: @total,
|
50
|
+
invoice_id: @invoice_id,
|
51
|
+
is_test: test_mode? ? 1 : 0,
|
52
|
+
signature: generate_signature_for(:payment)
|
53
|
+
}
|
54
|
+
custom_params = @params.sort.map { |param_name| param_name.first 2 }
|
55
|
+
result.merge Hash[custom_params]
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def shpfy_params
|
61
|
+
@params = @params.map do |param_name|
|
62
|
+
["shp_#{param_name[0]}".to_sym, param_name[1]]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Rubykassa
|
2
|
+
module SignatureGenerator
|
3
|
+
KIND_ERROR_MESSAGE =
|
4
|
+
'Available kinds are only :payment, :result or :success'.freeze
|
5
|
+
|
6
|
+
def generate_signature_for(kind)
|
7
|
+
unless [:success, :payment, :result].include?(kind)
|
8
|
+
raise ArgumentError, KIND_ERROR_MESSAGE
|
9
|
+
end
|
10
|
+
method(Rubykassa.hash_algorithm).call params_string(kind)
|
11
|
+
end
|
12
|
+
|
13
|
+
def params_string kind
|
14
|
+
result = case kind
|
15
|
+
when :payment
|
16
|
+
[Rubykassa.login, @total, @invoice_id, @receipt, Rubykassa.first_password, custom_params]
|
17
|
+
when :result
|
18
|
+
[@total, @invoice_id, Rubykassa.second_password, custom_params]
|
19
|
+
when :success
|
20
|
+
[@total, @invoice_id, Rubykassa.first_password, custom_params]
|
21
|
+
end
|
22
|
+
result.flatten.join ':'
|
23
|
+
end
|
24
|
+
|
25
|
+
def custom_params
|
26
|
+
@params.sort.inject([]) do |result, element|
|
27
|
+
result << element.join('=') if element[0] =~ /^shp/
|
28
|
+
result
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def md5(data)
|
35
|
+
Digest::MD5.hexdigest data
|
36
|
+
end
|
37
|
+
|
38
|
+
def ripemd160(data)
|
39
|
+
Digest::RMD160.hexdigest data
|
40
|
+
end
|
41
|
+
|
42
|
+
def sha1(data)
|
43
|
+
Digest::SHA1.hexdigest data
|
44
|
+
end
|
45
|
+
|
46
|
+
def sha265(data)
|
47
|
+
Digest::SHA256.hexdigest data
|
48
|
+
end
|
49
|
+
|
50
|
+
def sha384(data)
|
51
|
+
Digest::SHA384.hexdigest data
|
52
|
+
end
|
53
|
+
|
54
|
+
def sha512(data)
|
55
|
+
Digest::SHA512.hexdigest data
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|