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.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/.travis.yml +20 -0
  4. data/CHANGELOG.md +71 -0
  5. data/Gemfile +28 -0
  6. data/Guardfile +5 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +121 -0
  9. data/Rakefile +7 -0
  10. data/app/controllers/robokassa_controller.rb +33 -0
  11. data/config/routes.rb +12 -0
  12. data/lib/generators/rubykassa/install_generator.rb +11 -0
  13. data/lib/generators/rubykassa/templates/rubykassa.rb +22 -0
  14. data/lib/rubykassa/action_view_extension.rb +16 -0
  15. data/lib/rubykassa/client.rb +36 -0
  16. data/lib/rubykassa/configuration.rb +43 -0
  17. data/lib/rubykassa/engine.rb +9 -0
  18. data/lib/rubykassa/notification.rb +27 -0
  19. data/lib/rubykassa/payment_interface.rb +66 -0
  20. data/lib/rubykassa/signature_generator.rb +58 -0
  21. data/lib/rubykassa/version.rb +3 -0
  22. data/lib/rubykassa/xml_interface.rb +88 -0
  23. data/lib/rubykassa.rb +27 -0
  24. data/rubykassa-fixed.gemspec +28 -0
  25. data/spec/dummy/README.rdoc +261 -0
  26. data/spec/dummy/Rakefile +7 -0
  27. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  28. data/spec/dummy/app/controllers/welcome_controller.rb +4 -0
  29. data/spec/dummy/app/views/layouts/application.html.erb +12 -0
  30. data/spec/dummy/app/views/welcome/index.html.erb +24 -0
  31. data/spec/dummy/config/application.rb +62 -0
  32. data/spec/dummy/config/boot.rb +10 -0
  33. data/spec/dummy/config/database.yml +25 -0
  34. data/spec/dummy/config/environment.rb +5 -0
  35. data/spec/dummy/config/environments/development.rb +39 -0
  36. data/spec/dummy/config/environments/production.rb +69 -0
  37. data/spec/dummy/config/environments/test.rb +39 -0
  38. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  39. data/spec/dummy/config/initializers/inflections.rb +15 -0
  40. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  41. data/spec/dummy/config/initializers/rubykassa.rb +8 -0
  42. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  43. data/spec/dummy/config/initializers/session_store.rb +8 -0
  44. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  45. data/spec/dummy/config/locales/en.yml +5 -0
  46. data/spec/dummy/config/routes.rb +5 -0
  47. data/spec/dummy/config.ru +4 -0
  48. data/spec/dummy/db/development.sqlite3 +0 -0
  49. data/spec/dummy/db/test.sqlite3 +0 -0
  50. data/spec/dummy/public/404.html +26 -0
  51. data/spec/dummy/public/422.html +26 -0
  52. data/spec/dummy/public/500.html +25 -0
  53. data/spec/dummy/public/favicon.ico +0 -0
  54. data/spec/dummy/script/rails +6 -0
  55. data/spec/rubykassa/client_configuration_spec.rb +81 -0
  56. data/spec/rubykassa/notification_spec.rb +39 -0
  57. data/spec/rubykassa/payment_interface_spec.rb +37 -0
  58. data/spec/rubykassa/xml_interface_spec.rb +60 -0
  59. data/spec/spec_helper.rb +11 -0
  60. 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
@@ -0,0 +1,5 @@
1
+ guard 'rspec', version: 2, cli: "--color --format nested" do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ end
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
+ [![Gem Version](https://badge.fury.io/rb/rubykassa.png)](http://badge.fury.io/rb/rubykassa)
4
+ [![Build Status](https://secure.travis-ci.org/ZeroOneStudio/rubykassa.png)](http://travis-ci.org/ZeroOneStudio/rubykassa)
5
+ [![Coverage Status](https://coveralls.io/repos/ZeroOneStudio/rubykassa/badge.png)](https://coveralls.io/r/ZeroOneStudio/rubykassa)
6
+ [![Code Climate](https://codeclimate.com/github/ZeroOneStudio/rubykassa.png)](https://codeclimate.com/github/ZeroOneStudio/rubykassa)
7
+ [![Dependency Status](https://gemnasium.com/ZeroOneStudio/rubykassa.png)](https://gemnasium.com/ZeroOneStudio/rubykassa)
8
+ [![Inline docs](http://inch-ci.org/github/ZeroOneStudio/rubykassa.svg?branch=master)](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
+ [![Gitter chat](https://badges.gitter.im/ZeroOneStudio/rubykassa.png)](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 [![Build Status](https://secure.travis-ci.org/ZeroOneStudio/rubykassa.png)](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
+ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/ZeroOneStudio/rubykassa/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ task :default => :spec
@@ -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,12 @@
1
+ Rails.application.routes.draw do
2
+ if Rubykassa::Client.configuration
3
+ scope :robokassa do
4
+ %w(result success fail).map do |route|
5
+ match route,
6
+ controller: :robokassa,
7
+ action: route,
8
+ via: Rubykassa.http_method
9
+ end
10
+ end
11
+ end
12
+ end
@@ -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,9 @@
1
+ require 'rubykassa/action_view_extension'
2
+
3
+ module Rubykassa
4
+ class Engine < ::Rails::Engine
5
+ initializer 'rubykassa.action_view_extension' do
6
+ ActionView::Base.send :include, Rubykassa::ActionViewExtension
7
+ end
8
+ end
9
+ 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
@@ -0,0 +1,3 @@
1
+ module Rubykassa
2
+ VERSION = '0.4.2'
3
+ end