robokassa 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +8 -0
- data/Gemfile +24 -0
- data/README.md +189 -0
- data/Rakefile +26 -0
- data/VERSION +1 -0
- data/app/assets/images/robokassa/AlfaBank.gif +0 -0
- data/app/assets/images/robokassa/HandyBank.gif +0 -0
- data/app/assets/images/robokassa/Mastercard.gif +0 -0
- data/app/assets/images/robokassa/MoneyMail.gif +0 -0
- data/app/assets/images/robokassa/RBKMoney.gif +0 -0
- data/app/assets/images/robokassa/TeleMoney.gif +0 -0
- data/app/assets/images/robokassa/TerminalsAbsolutplat.gif +0 -0
- data/app/assets/images/robokassa/TerminalsElecsnet.gif +0 -0
- data/app/assets/images/robokassa/TerminalsPinpay.gif +0 -0
- data/app/assets/images/robokassa/TerminalsQiwi.gif +0 -0
- data/app/assets/images/robokassa/TerminalsUnikassa.gif +0 -0
- data/app/assets/images/robokassa/TerminalsmobilElement.gif +0 -0
- data/app/assets/images/robokassa/VKontakte.gif +0 -0
- data/app/assets/images/robokassa/VTB24.gif +0 -0
- data/app/assets/images/robokassa/Visa.gif +0 -0
- data/app/assets/images/robokassa/WMTrustID.gif +0 -0
- data/app/assets/images/robokassa/WebmoneyR.gif +0 -0
- data/app/assets/images/robokassa/YandexMoney.gif +0 -0
- data/app/assets/images/robokassa/iRobo.gif +0 -0
- data/app/assets/images/robokassa/logo.gif +0 -0
- data/app/controllers/robokassa_controller.rb +3 -0
- data/app/helpers/robokassa_helper.rb +130 -0
- data/app/views/payment_method/robokassa/_init.html.erb +32 -0
- data/autotest/discover.rb +1 -0
- data/config/locales/en.yml +3 -0
- data/config/locales/ru.yml +3 -0
- data/config/routes.rb +8 -0
- data/lib/robokassa.rb +20 -0
- data/lib/robokassa/controller.rb +19 -0
- data/lib/robokassa/interface.rb +378 -0
- data/robokassa.gemspec +35 -0
- data/spec/lib/interface_spec.rb +39 -0
- data/spec/routing/routes_spec.rb +23 -0
- data/spec/spec_helper.rb +14 -0
- metadata +199 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in robokassa.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'nokogiri'
|
7
|
+
|
8
|
+
group :test do
|
9
|
+
gem 'ZenTest'
|
10
|
+
gem 'rspec'
|
11
|
+
gem 'rspec-rails', '>= 2.5.0'
|
12
|
+
gem 'factory_girl', '>= 1.3.3'
|
13
|
+
gem 'factory_girl_rails', '>= 1.0.1'
|
14
|
+
# gem 'rcov'
|
15
|
+
gem 'shoulda'
|
16
|
+
gem 'faker'
|
17
|
+
# gem 'celerity'
|
18
|
+
# gem 'culerity'
|
19
|
+
if RUBY_VERSION < "1.9"
|
20
|
+
gem "ruby-debug"
|
21
|
+
else
|
22
|
+
gem "ruby-debug19"
|
23
|
+
end
|
24
|
+
end
|
data/README.md
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
SUMMARY
|
2
|
+
-------
|
3
|
+
|
4
|
+
This gem adds robokassa support to your app.
|
5
|
+
|
6
|
+
Robokassa is payment system, that provides a single simple interface for payment systems popular in Russia.
|
7
|
+
If you have customers in Russia you can use the gem.
|
8
|
+
|
9
|
+
The first thing about this gem, is that it was oribinally desgned for spree commerce. So keep it im mind.
|
10
|
+
|
11
|
+
Данный джем является форком джема: https://github.com/shaggyone/robokassa
|
12
|
+
|
13
|
+
Using the Gem
|
14
|
+
-------------
|
15
|
+
|
16
|
+
Add the following line to your app Gemfile
|
17
|
+
|
18
|
+
gem 'robokassa'
|
19
|
+
|
20
|
+
Update your bundle
|
21
|
+
|
22
|
+
bundle install
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
config/initializers/robokassa.rb:
|
26
|
+
|
27
|
+
ROBOKASSA_SETTINGS = {
|
28
|
+
:test_mode => true,
|
29
|
+
:login => 'LOGIN',
|
30
|
+
:password1 => 'PASSWORD1',
|
31
|
+
:password2 => 'PASSWORD2'
|
32
|
+
}
|
33
|
+
|
34
|
+
$robokassa = Robokassa::Interface.new(ROBOKASSA_SETTINGS)
|
35
|
+
|
36
|
+
module Robokassa
|
37
|
+
class Interface
|
38
|
+
def notify_implementation(invoice_id, *args); end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
def get_options_by_notification_key(key)
|
42
|
+
ROBOKASSA_SETTINGS
|
43
|
+
end
|
44
|
+
|
45
|
+
def success_implementation(invoice_id, *args)
|
46
|
+
payment = Payment.find_by_id(invoice_id)
|
47
|
+
payment.to_success!
|
48
|
+
end
|
49
|
+
|
50
|
+
def fail_implementation(invoice_id, *args)
|
51
|
+
payment = Payment.find_by_id(invoice_id)
|
52
|
+
payment.to_fail!
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
routes.rb:
|
59
|
+
|
60
|
+
...
|
61
|
+
controller :robokassa do
|
62
|
+
get "robokassa/:notification_key/notify" => :notify, :as => :robokassa_notification
|
63
|
+
get "robokassa/success" => :success, :as => :robokassa_on_success
|
64
|
+
get "robokassa/fail" => :fail, :as => :robokassa_on_fail
|
65
|
+
end
|
66
|
+
...
|
67
|
+
|
68
|
+
class Dashboard::PaymentsController < Dashboard::ApplicationController
|
69
|
+
...
|
70
|
+
def create
|
71
|
+
@payment = current_user.payments.create!(:amount => params[:payment][:amount])
|
72
|
+
pay_url = $robokassa.init_payment_url(
|
73
|
+
@payment.id, @payment.amount, "Платеж № #{@payment.id}",
|
74
|
+
'', 'ru', current_user.email, {}
|
75
|
+
)
|
76
|
+
redirect_to pay_url
|
77
|
+
end
|
78
|
+
...
|
79
|
+
|
80
|
+
class Payment < ActiveRecord::Base
|
81
|
+
include AASM
|
82
|
+
|
83
|
+
validates_presence_of :user_id, :amount
|
84
|
+
attr_accessible :amount
|
85
|
+
belongs_to :user
|
86
|
+
|
87
|
+
default_scope order("id desc")
|
88
|
+
|
89
|
+
aasm do
|
90
|
+
state :new, :initial => true
|
91
|
+
state :success
|
92
|
+
state :fail
|
93
|
+
|
94
|
+
event :to_success, :after => :give_money! do
|
95
|
+
transitions :to => :success
|
96
|
+
end
|
97
|
+
|
98
|
+
event :to_fail do
|
99
|
+
transitions :to => :fail
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def state
|
104
|
+
self.aasm_state
|
105
|
+
end
|
106
|
+
|
107
|
+
def give_money!
|
108
|
+
self.user.give_money!(self.amount)
|
109
|
+
end
|
110
|
+
|
111
|
+
def printable_amount
|
112
|
+
"#{self.amount.to_s} руб."
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
class User < ActiveRecord::Base
|
117
|
+
...
|
118
|
+
def give_money!(amount)
|
119
|
+
sql = "update users set balance='#{self.balance + amount.to_f}' where id='#{self.id}'"
|
120
|
+
connection.update(sql)
|
121
|
+
end
|
122
|
+
...
|
123
|
+
|
124
|
+
dashboarb/payments/_form.html.erb:
|
125
|
+
|
126
|
+
<%= semantic_form_for [:dashboard, @payment] do |f| %>
|
127
|
+
<%= f.error_messages %>
|
128
|
+
<%= f.input :amount %>
|
129
|
+
<%= actions_for f, "Пополнить" %>
|
130
|
+
<% end %>
|
131
|
+
|
132
|
+
app/controllers/robokassa.rb:
|
133
|
+
|
134
|
+
# coding: utf-8
|
135
|
+
class RobokassaController < Robokassa::Controller
|
136
|
+
def success
|
137
|
+
super
|
138
|
+
@payment = Payment.find_by_id(params[:InvId])
|
139
|
+
if @payment
|
140
|
+
redirect_to dashboard_payment_path(@payment),
|
141
|
+
:notice => "Ваш платеж на сумму #{@payment.amount.to_s} руб. успешно принят. Спасибо!"
|
142
|
+
else
|
143
|
+
redirect_to new_dashboard_payment_path,
|
144
|
+
:error => "Не могу найти платеж по данному идентификатору"
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def fail
|
149
|
+
super
|
150
|
+
redirect_to dashboard_payments_path,
|
151
|
+
:error => "Во время принятия платежа возникла ошибка. Мы скоро разберемся!"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
```
|
156
|
+
|
157
|
+
In Robokassa account settings set:
|
158
|
+
|
159
|
+
Result URL: http://example.com/robokassa/default/notify
|
160
|
+
Success URL: http://example.com/robokassa/success
|
161
|
+
Fail URL: http://example.com/robokassa/fail
|
162
|
+
|
163
|
+
Testing
|
164
|
+
-----
|
165
|
+
In console:
|
166
|
+
|
167
|
+
Clone gem
|
168
|
+
```bash
|
169
|
+
git clone git://github.com/shaggyone/robokassa.git
|
170
|
+
```
|
171
|
+
|
172
|
+
Install gems and generate a dummy application (It'll be ignored by git):
|
173
|
+
```bash
|
174
|
+
cd robokassa
|
175
|
+
bundle install
|
176
|
+
bundle exec combust
|
177
|
+
```
|
178
|
+
|
179
|
+
Run specs:
|
180
|
+
```bash
|
181
|
+
rake spec
|
182
|
+
```
|
183
|
+
|
184
|
+
Generate a dummy test application
|
185
|
+
|
186
|
+
Plans
|
187
|
+
-----
|
188
|
+
|
189
|
+
I plan to add generators for views
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/packagetask'
|
5
|
+
require 'rubygems/package_task'
|
6
|
+
require 'bundler'
|
7
|
+
require 'rspec'
|
8
|
+
require "rspec/core/rake_task"
|
9
|
+
|
10
|
+
Bundler.setup
|
11
|
+
Bundler::GemHelper.install_tasks
|
12
|
+
|
13
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
14
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
15
|
+
spec.rspec_opts = ['--backtrace']
|
16
|
+
end
|
17
|
+
|
18
|
+
require 'rdoc/task'
|
19
|
+
Rake::RDocTask.new do |rdoc|
|
20
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
21
|
+
|
22
|
+
rdoc.rdoc_dir = 'rdoc'
|
23
|
+
rdoc.title = "constantations #{version}"
|
24
|
+
rdoc.rdoc_files.include('README*')
|
25
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
26
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.2
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module RobokassaHelper
|
2
|
+
include ActionView::Helpers::TagHelper
|
3
|
+
include ActionView::Helpers::CaptureHelper
|
4
|
+
include ActionView::Helpers::FormTagHelper
|
5
|
+
|
6
|
+
PAYMENT_SYSTEMS = {
|
7
|
+
:bank_card => 'BANKOCEANMR', # Банковской картой
|
8
|
+
:platezh_ru => 'OceanBankOceanR', # Банковской картой через Platezh.ru
|
9
|
+
:qiwi => 'QiwiR', # QIWI Кошелек
|
10
|
+
:yandex => 'PCR', # Яндекс.Деньги
|
11
|
+
:wmr => 'WMRM', # WMR
|
12
|
+
:wmz => 'WMZM', # WMZ
|
13
|
+
:wme => 'WMEM', # WME
|
14
|
+
:wmu => 'WMUM', # WMU
|
15
|
+
:wmb => 'WMBM', # WMB
|
16
|
+
:wmg => 'WMGM', # WMG
|
17
|
+
:money_mail_ru => 'MoneyMailR', # RUR MoneyMail
|
18
|
+
:rur_rbk_money => 'RuPayR', # RUR RBK Money
|
19
|
+
:w1r => 'W1R', # RUR Единый Кошелек
|
20
|
+
:easy_pay => 'EasyPayB', # EasyPay
|
21
|
+
:liq_pay_usd => 'LiqPayZ', # USD LiqPay
|
22
|
+
:money_mail_ru => 'MailRuR', # Деньги@Mail.Ru
|
23
|
+
:z_payment => 'ZPaymentR', # RUR Z-Payment
|
24
|
+
:tele_money => 'TeleMoneyR', # RUR TeleMoney
|
25
|
+
:alfabank => 'AlfaBankR', # Альфа-Клик
|
26
|
+
:pskbr => 'PSKBR', # Промсвязьбанк
|
27
|
+
:handy_bank => 'HandyBankMerchantR', # HandyBank
|
28
|
+
:innivation => 'BSSFederalBankForInnovationAndDevelopmentR', # АК ФБ Инноваций и Развития (ЗАО)
|
29
|
+
:energobank => 'BSSMezhtopenergobankR', # Межтопэнергобанк
|
30
|
+
:svyaznoy => 'RapidaOceanSvyaznoyR', # Через Связной
|
31
|
+
:euroset => 'RapidaOceanEurosetR', # Через Евросеть
|
32
|
+
:elecsnet_r => 'ElecsnetR', # Элекснет
|
33
|
+
:kassira_net => 'TerminalsUnikassaR', # Кассира.нет
|
34
|
+
:mobil_element => 'TerminalsMElementR', # Мобил Элемент
|
35
|
+
:baltika => 'TerminalsNovoplatR', # Банк Балтика
|
36
|
+
:absolut_plat => 'TerminalsAbsolutplatR', # Absolutplat
|
37
|
+
:pinpay => 'TerminalsPinpayR', # Pinpay
|
38
|
+
:money_money => 'TerminalsMoneyMoneyR', # Money-Money
|
39
|
+
:petrocommerce => 'TerminalsPkbR', # Петрокоммерц
|
40
|
+
:vtb24 => 'VTB24R', # ВТБ24
|
41
|
+
:mts => 'MtsR', # МТС
|
42
|
+
:megafon => 'MegafonR', # Мегафон
|
43
|
+
:iphone => 'BANKOCEANCHECKR', # Через iPhone
|
44
|
+
:contact => 'ContactR', # Переводом по системе Контакт
|
45
|
+
:online_credit => 'OnlineCreditR'
|
46
|
+
}
|
47
|
+
|
48
|
+
def payment_form(interface, invoice_id, amount, description, custom_options = {})
|
49
|
+
payment_base_url = interface.init_payment_base_url
|
50
|
+
payment_options = interface.init_payment_options(invoice_id, amount, description, custom_options)
|
51
|
+
|
52
|
+
@__robokassa_vars = {
|
53
|
+
:interface => interface,
|
54
|
+
:invoice_id => invoice_id,
|
55
|
+
:amount => amount,
|
56
|
+
:description => description,
|
57
|
+
:custom_options => custom_options,
|
58
|
+
:payment_base_url => payment_base_url,
|
59
|
+
:payment_options => payment_options
|
60
|
+
}
|
61
|
+
|
62
|
+
if block_given?
|
63
|
+
yield payment_base_url, payment_options
|
64
|
+
else
|
65
|
+
render 'payment_method/robokassa/init',
|
66
|
+
:interface => interface,
|
67
|
+
:invoice_id => invoice_id,
|
68
|
+
:amount => amount,
|
69
|
+
:description => description,
|
70
|
+
:custom_options => custom_options,
|
71
|
+
:payment_base_url => payment_base_url,
|
72
|
+
:payment_options => payment_options
|
73
|
+
end
|
74
|
+
|
75
|
+
@__robokassa_vars = nil
|
76
|
+
end
|
77
|
+
|
78
|
+
def robokassa_rates_hash
|
79
|
+
raise "rates_hash helper should be called inside of payment_form." if @__robokassa_vars.blank?
|
80
|
+
@__robokassa_vars[:rates_hash] ||= robokassa_interface.rates_linear(robokassa_amount)
|
81
|
+
end
|
82
|
+
|
83
|
+
def robokassa_payment_block currency
|
84
|
+
raise "payment_block should be called inside of payment_form." if @__robokassa_vars.blank?
|
85
|
+
|
86
|
+
currency = RobokassaHelper::PAYMENT_SYSTEMS[currency]
|
87
|
+
raise "wrong currency" unless currency
|
88
|
+
kept_rate = @__robokassa_vars[:currency_rate]
|
89
|
+
currency_rate = robokassa_rates_hash[currency]
|
90
|
+
return "" unless currency_rate
|
91
|
+
@__robokassa_vars[:currency_rate] = currency_rate
|
92
|
+
|
93
|
+
yield currency_rate
|
94
|
+
|
95
|
+
@__robokassa_vars[:currency_rate] = kept_rate
|
96
|
+
end
|
97
|
+
|
98
|
+
def robokassa_payment_link *args
|
99
|
+
raise "payment_link should be called inside of payment_form." if @__robokassa_vars.blank?
|
100
|
+
options = args.extract_options!
|
101
|
+
currency = options.delete(:currency)
|
102
|
+
if currency
|
103
|
+
return robokassa_currency currency do
|
104
|
+
payment_link args
|
105
|
+
end
|
106
|
+
end
|
107
|
+
payment_url = "#{ robokassa_payment_base_url }?#{ robokassa_payment_options.merge('IncCurrLabel' => robokassa_currency_rate[:name]).to_query}"
|
108
|
+
|
109
|
+
if block_given?
|
110
|
+
link_to payment_url, *args, options do
|
111
|
+
yield robokassa_currency_rate
|
112
|
+
end
|
113
|
+
else
|
114
|
+
title = args.shift
|
115
|
+
link_to title, payment_url, *args, options
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
[:interface, :invoice_id, :amount, :description, :custom_options, :payment_base_url, :payment_options].each do |method_name|
|
120
|
+
define_method "robokassa_#{method_name}".to_sym do
|
121
|
+
raise "robokassa_#{method_name} helper should be called inside of payment_form." if @__robokassa_vars.blank?
|
122
|
+
@__robokassa_vars[method_name]
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def robokassa_currency_rate
|
127
|
+
raise "robokassa_currency_rate helper should be called inside of robokassa_payment_block." if @__robokassa_vars.blank? || @__robokassa_vars[:currency_rate].blank?
|
128
|
+
@__robokassa_vars[:currency_rate]
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<div class='robokassa'>
|
2
|
+
<form action="<%=interface.init_payment_base_url %>" method="get">
|
3
|
+
<%
|
4
|
+
options = interface.init_payment_options(invoice_id, amount, description, custom_options)
|
5
|
+
options.delete 'IncCurrLabel'
|
6
|
+
%>
|
7
|
+
<% options.each do |name, value| %>
|
8
|
+
<%= hidden_field_tag name, value %>
|
9
|
+
<% end %>
|
10
|
+
<ul class='robokassa-groups'>
|
11
|
+
<% interface.rates(amount).each_with_index do |group, i| %>
|
12
|
+
<% group_name, group = group %>
|
13
|
+
<li class='robokassa-group robokassa-<%= group_name.underscore %>'>
|
14
|
+
<p class='robokassa-group-description'><%= group[:description] %></p>
|
15
|
+
<ul>
|
16
|
+
<% group[:currencies].each_with_index do |currency, j| %>
|
17
|
+
<% currency_name, currency = currency %>
|
18
|
+
<li class='robokassa-group-currency <%= "#{group_name.underscore}_#{currency_name.underscore}" %>'>
|
19
|
+
<%= label_tag "inc_curr_label_#{group_name.underscore}_#{currency_name.underscore}" do %>
|
20
|
+
<%= radio_button_tag "IncCurrLabel", currency_name, false, :id => "inc_curr_label_#{group_name.underscore}_#{currency_name.underscore}" %>
|
21
|
+
<span class="description"><%= currency[:currency_description] %></span>
|
22
|
+
<span class="amount"><%= number_to_currency currency[:amount], :delimiter => " ", :format=>'%n' %></span>
|
23
|
+
<% end %>
|
24
|
+
</li>
|
25
|
+
<% end %>
|
26
|
+
</ul>
|
27
|
+
</li>
|
28
|
+
<% end %>
|
29
|
+
</ul>
|
30
|
+
<input type="submit" class="continue button primary" value="<%=t("robokassa.proceed_to_payment") %>" />
|
31
|
+
</form>
|
32
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
Autotest.add_discovery { "rspec2" }
|
data/config/routes.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
Rails.application.routes.draw do
|
2
|
+
controller :robokassa do
|
3
|
+
get "robokassa/:notification_key/notify" => :notify, :as => :robokassa_notification
|
4
|
+
|
5
|
+
get "robokassa/success" => :success, :as => :robokassa_on_success
|
6
|
+
get "robokassa/fail" => :fail, :as => :robokassa_on_fail
|
7
|
+
end
|
8
|
+
end
|
data/lib/robokassa.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Robokassa
|
2
|
+
mattr_accessor :interface_class
|
3
|
+
|
4
|
+
# this allow use custom class for handeling api responces
|
5
|
+
# === Example
|
6
|
+
# Robokassa.interface_class = MyCustomInterface
|
7
|
+
# Robokassa.interface_class.new(options)
|
8
|
+
def self.interface_class
|
9
|
+
@@interface_class || ::Robokassa::Interface
|
10
|
+
end
|
11
|
+
|
12
|
+
class Engine < Rails::Engine #:nodoc:
|
13
|
+
config.autoload_paths += %W(#{config.root}/lib)
|
14
|
+
|
15
|
+
def self.activate
|
16
|
+
end
|
17
|
+
|
18
|
+
config.to_prepare &method(:activate).to_proc
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Robokassa::Controller < ActionController::Base
|
2
|
+
protect_from_forgery :only => []
|
3
|
+
|
4
|
+
def notify
|
5
|
+
interface = Robokassa.interface_class.create_by_notification_key params[:notification_key]
|
6
|
+
params.delete :notification_key
|
7
|
+
render :text => interface.notify(params, self)
|
8
|
+
end
|
9
|
+
|
10
|
+
def success
|
11
|
+
retval = Robokassa.interface_class.success(params, self)
|
12
|
+
redirect_to retval if retval.is_a? String
|
13
|
+
end
|
14
|
+
|
15
|
+
def fail
|
16
|
+
retval = Robokassa.interface_class.fail(params, self)
|
17
|
+
redirect_to retval if retval.is_a? String
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,378 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'net/http'
|
3
|
+
require 'net/https'
|
4
|
+
require 'open-uri'
|
5
|
+
require 'rexml/document'
|
6
|
+
|
7
|
+
class Robokassa::Interface
|
8
|
+
include ActionDispatch::Routing::UrlFor
|
9
|
+
include Rails.application.routes.url_helpers
|
10
|
+
|
11
|
+
cattr_accessor :config
|
12
|
+
|
13
|
+
@@default_options = {
|
14
|
+
:language => "ru"
|
15
|
+
}
|
16
|
+
@cache = {}
|
17
|
+
|
18
|
+
# Indicate if calling api in test mode
|
19
|
+
# === Returns
|
20
|
+
# true or false
|
21
|
+
def test_mode?
|
22
|
+
@options[:test_mode] || false
|
23
|
+
end
|
24
|
+
|
25
|
+
def owner
|
26
|
+
@options[:owner]
|
27
|
+
end
|
28
|
+
|
29
|
+
# Takes options to access Robokassa API
|
30
|
+
#
|
31
|
+
# === Example
|
32
|
+
# Robokassa::Interface.new test_mode: true, login: 'demo', password1: '12345', password2: 'qweqwe123'
|
33
|
+
#
|
34
|
+
def initialize(options)
|
35
|
+
@options = @@default_options.merge(options.symbolize_keys)
|
36
|
+
@cache = {}
|
37
|
+
end
|
38
|
+
|
39
|
+
# This method verificates request params recived from robocassa server
|
40
|
+
def notify(params, controller)
|
41
|
+
parsed_params = map_params(params, @@notification_params_map)
|
42
|
+
notify_implementation(
|
43
|
+
parsed_params[:invoice_id],
|
44
|
+
parsed_params[:amount],
|
45
|
+
parsed_params[:custom_options],
|
46
|
+
controller)
|
47
|
+
"OK#{parsed_params[:invoice_id]}"
|
48
|
+
end
|
49
|
+
|
50
|
+
# Handler for success api callback
|
51
|
+
# this method calls from RobokassaController
|
52
|
+
# It requires Robokassa::Interface.success_implementation to be inmplemented by user
|
53
|
+
def self.success(params, controller)
|
54
|
+
parsed_params = map_params(params, @@notification_params_map)
|
55
|
+
success_implementation(
|
56
|
+
parsed_params[:invoice_id],
|
57
|
+
parsed_params[:amount],
|
58
|
+
parsed_params[:language],
|
59
|
+
parsed_params[:custom_options],
|
60
|
+
controller)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Fail callback requiest handler
|
64
|
+
# It requires Robokassa::Interface.fail_implementation to be inmplemented by user
|
65
|
+
def self.fail(params, controller)
|
66
|
+
parsed_params = map_params(params, @@notification_params_map)
|
67
|
+
fail_implementation(
|
68
|
+
parsed_params[:invoice_id],
|
69
|
+
parsed_params[:amount],
|
70
|
+
parsed_params[:language],
|
71
|
+
parsed_params[:custom_options],
|
72
|
+
controller)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# Generates url for payment page
|
77
|
+
#
|
78
|
+
# === Example
|
79
|
+
# <%= link_to "Pay with Robokassa", interface.init_payment_url(order.id, order.amount, "Order #{order.id}", '', 'ru', order.user.email) %>
|
80
|
+
#
|
81
|
+
def init_payment_url(invoice_id, amount, description, currency='', language='ru', email='', custom_options={})
|
82
|
+
url_options = init_payment_options(invoice_id, amount, description, custom_options, currency, language, email)
|
83
|
+
"#{init_payment_base_url}?" + url_options.map do |k, v| "#{CGI::escape(k.to_s)}=#{CGI::escape(v.to_s)}" end.join('&')
|
84
|
+
end
|
85
|
+
|
86
|
+
def payment_methods # :nodoc:
|
87
|
+
return @cache[:payment_methods] if @cache[:payment_methods]
|
88
|
+
xml = get_remote_xml(payment_methods_url)
|
89
|
+
if xml.elements['PaymentMethodsList/Result/Code'].text != '0'
|
90
|
+
raise (a=xml.elements['PaymentMethodsList/Result/Description']) ? a.text : "Unknown error"
|
91
|
+
end
|
92
|
+
|
93
|
+
@cache[:payment_methods] ||= Hash[xml.elements.each('PaymentMethodsList/Methods/Method'){}.map do|g|
|
94
|
+
[g.attributes['Code'], g.attributes['Description']]
|
95
|
+
end]
|
96
|
+
end
|
97
|
+
|
98
|
+
def rates_long(amount, currency='')
|
99
|
+
cache_key = "rates_long_#{currency}_#{amount}"
|
100
|
+
return @cache[cache_key] if @cache[cache_key]
|
101
|
+
xml = get_remote_xml(rates_url(amount, currency))
|
102
|
+
if xml.elements['RatesList/Result/Code'].text != '0'
|
103
|
+
raise (a=xml.elements['RatesList/Result/Description']) ? a.text : "Unknown error"
|
104
|
+
end
|
105
|
+
|
106
|
+
@cache[cache_key] = Hash[xml.elements.each('RatesList/Groups/Group'){}.map do|g|
|
107
|
+
code = g.attributes['Code']
|
108
|
+
description = g.attributes['Description']
|
109
|
+
[
|
110
|
+
code,
|
111
|
+
{
|
112
|
+
:code => code,
|
113
|
+
:description => description,
|
114
|
+
:currencies => Hash[g.elements.each('Items/Currency'){}.map do|c|
|
115
|
+
label = c.attributes['Label']
|
116
|
+
name = c.attributes['Name']
|
117
|
+
[label, {
|
118
|
+
:currency => label,
|
119
|
+
:currency_description => name,
|
120
|
+
:group => code,
|
121
|
+
:group_description => description,
|
122
|
+
:amount => BigDecimal.new(c.elements['Rate'].attributes['IncSum'])
|
123
|
+
}]
|
124
|
+
end]
|
125
|
+
}
|
126
|
+
]
|
127
|
+
end]
|
128
|
+
end
|
129
|
+
|
130
|
+
def rates(amount, currency='')
|
131
|
+
cache_key = "rates_#{currency}_#{amount}"
|
132
|
+
@cache[cache_key] ||= Hash[rates_long(amount, currency).map do |key, value|
|
133
|
+
[key, {
|
134
|
+
:description => value[:description],
|
135
|
+
:currencies => Hash[(value[:currencies] || []).map do |k, v|
|
136
|
+
[k, v]
|
137
|
+
end]
|
138
|
+
}]
|
139
|
+
end]
|
140
|
+
end
|
141
|
+
|
142
|
+
def rates_linear(amount, currency='')
|
143
|
+
cache_key = "rates_linear#{currency}_#{amount}"
|
144
|
+
@cache[cache_key] ||= begin
|
145
|
+
retval = rates(amount, currency).map do |group|
|
146
|
+
group_name, group = group
|
147
|
+
group[:currencies].map do |currency|
|
148
|
+
currency_name, currency = currency
|
149
|
+
{
|
150
|
+
:name => currency_name,
|
151
|
+
:desc => currency[:currency_description],
|
152
|
+
:group_name => group[:name],
|
153
|
+
:group_desc => group[:description],
|
154
|
+
:amount => currency[:amount]
|
155
|
+
}
|
156
|
+
end
|
157
|
+
end
|
158
|
+
Hash[retval.flatten.map { |v| [v[:name], v] }]
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def currencies_long
|
163
|
+
return @cache[:currencies_long] if @cache[:currencies_long]
|
164
|
+
xml = get_remote_xml(currencies_url)
|
165
|
+
if xml.elements['CurrenciesList/Result/Code'].text != '0'
|
166
|
+
raise (a=xml.elements['CurrenciesList/Result/Description']) ? a.text : "Unknown error"
|
167
|
+
end
|
168
|
+
@cache[:currencies_long] = Hash[xml.elements.each('CurrenciesList/Groups/Group'){}.map do|g|
|
169
|
+
code = g.attributes['Code']
|
170
|
+
description = g.attributes['Description']
|
171
|
+
[
|
172
|
+
code,
|
173
|
+
{
|
174
|
+
:code => code,
|
175
|
+
:description => description,
|
176
|
+
:currencies => Hash[g.elements.each('Items/Currency'){}.map do|c|
|
177
|
+
label = c.attributes['Label']
|
178
|
+
name = c.attributes['Name']
|
179
|
+
[label, {
|
180
|
+
:currency => label,
|
181
|
+
:currency_description => name,
|
182
|
+
:group => code,
|
183
|
+
:group_description => description
|
184
|
+
}]
|
185
|
+
end]
|
186
|
+
}
|
187
|
+
]
|
188
|
+
end]
|
189
|
+
end
|
190
|
+
|
191
|
+
def currencies
|
192
|
+
@cache[:currencies] ||= Hash[currencies_long.map do |key, value|
|
193
|
+
[key, {
|
194
|
+
:description => value[:description],
|
195
|
+
:currencies => value[:currencies]
|
196
|
+
}]
|
197
|
+
end]
|
198
|
+
end
|
199
|
+
|
200
|
+
# for testing
|
201
|
+
# === Example
|
202
|
+
# i.default_url_options = { :host => '127.0.0.1', :port => 3000 }
|
203
|
+
# i.notification_url # => 'http://127.0.0.1:3000/robokassa/asfadsf/notify'
|
204
|
+
def notification_url
|
205
|
+
robokassa_notification_url :notification_key => @options[:notification_key]
|
206
|
+
end
|
207
|
+
|
208
|
+
# for testing
|
209
|
+
def on_success_url
|
210
|
+
robokassa_on_success_url
|
211
|
+
end
|
212
|
+
|
213
|
+
# for testing
|
214
|
+
def on_fail_url
|
215
|
+
robokassa_on_fail_url
|
216
|
+
end
|
217
|
+
|
218
|
+
def parse_response_params(params)
|
219
|
+
parsed_params = map_params(params, @@notification_params_map)
|
220
|
+
parsed_params[:custom_options] = Hash[args.select do |k,v| o.starts_with?('shp') end.sort.map do|k, v| [k[3, k.size], v] end]
|
221
|
+
if response_signature(parsed_params)!=parsed_params[:signature].downcase
|
222
|
+
raise "Invalid signature"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def rates_url(amount, currency)
|
227
|
+
"#{xml_services_base_url}/GetRates?#{query_string(rates_options(amount, currency))}"
|
228
|
+
end
|
229
|
+
|
230
|
+
def rates_options(amount, currency)
|
231
|
+
map_params(subhash(@options.merge(:amount=>amount, :currency=>currency), %w{login language amount currency}), @@service_params_map)
|
232
|
+
end
|
233
|
+
|
234
|
+
def payment_methods_url
|
235
|
+
@cache[:get_currencies_url] ||= "#{xml_services_base_url}/GetPaymentMethods?#{query_string(payment_methods_options)}"
|
236
|
+
end
|
237
|
+
|
238
|
+
def payment_methods_options
|
239
|
+
map_params(subhash(@options, %w{login language}), @@service_params_map)
|
240
|
+
end
|
241
|
+
|
242
|
+
def currencies_url
|
243
|
+
@cache[:get_currencies_url] ||= "#{xml_services_base_url}/GetCurrencies?#{query_string(currencies_options)}"
|
244
|
+
end
|
245
|
+
|
246
|
+
def currencies_options
|
247
|
+
map_params(subhash(@options, %w{login language}), @@service_params_map)
|
248
|
+
end
|
249
|
+
|
250
|
+
# make hash of options for init_payment_url
|
251
|
+
def init_payment_options(invoice_id, amount, description, custom_options = {}, currency='', language='ru', email='')
|
252
|
+
options = {
|
253
|
+
:login => @options[:login],
|
254
|
+
:amount => amount.to_s,
|
255
|
+
:invoice_id => invoice_id,
|
256
|
+
:description => description[0, 100],
|
257
|
+
:signature => init_payment_signature(invoice_id, amount, description, custom_options),
|
258
|
+
:currency => currency,
|
259
|
+
:email => email,
|
260
|
+
:language => language
|
261
|
+
}.merge(Hash[custom_options.sort.map{|x| ["shp#{x[0]}", x[1]]}])
|
262
|
+
map_params(options, @@params_map)
|
263
|
+
end
|
264
|
+
|
265
|
+
# calculates signature to check params from Robokassa
|
266
|
+
def response_signature(parsed_params)
|
267
|
+
md5 response_signature_string(parsed_params)
|
268
|
+
end
|
269
|
+
|
270
|
+
# build signature string
|
271
|
+
def response_signature_string(parsed_params)
|
272
|
+
custom_options_fmt = custom_options.sort.map{|x|"shp#{x[0]}=x[1]]"}.join(":")
|
273
|
+
"#{parsed_params[:amount]}:#{parsed_params[:invoice_id]}:#{@options[:password2]}#{unless custom_options_fmt.blank? then ":" + custom_options_fmt else "" end}"
|
274
|
+
end
|
275
|
+
|
276
|
+
# calculates md5 from result of :init_payment_signature_string
|
277
|
+
def init_payment_signature(invoice_id, amount, description, custom_options={})
|
278
|
+
md5 init_payment_signature_string(invoice_id, amount, description, custom_options)
|
279
|
+
end
|
280
|
+
|
281
|
+
# generates signature string to calculate 'SignatureValue' url parameter
|
282
|
+
def init_payment_signature_string(invoice_id, amount, description, custom_options={})
|
283
|
+
custom_options_fmt = custom_options.sort.map{|x|"shp#{x[0]}=#{x[1]}"}.join(":")
|
284
|
+
"#{@options[:login]}:#{amount}:#{invoice_id}:#{@options[:password1]}#{unless custom_options_fmt.blank? then ":" + custom_options_fmt else "" end}"
|
285
|
+
end
|
286
|
+
|
287
|
+
# returns http://test.robokassa.ru or https://merchant.roboxchange.com in order to current mode
|
288
|
+
def base_url
|
289
|
+
test_mode? ? 'http://test.robokassa.ru' : 'https://merchant.roboxchange.com'
|
290
|
+
end
|
291
|
+
|
292
|
+
# returns url to redirect user to payment page
|
293
|
+
def init_payment_base_url
|
294
|
+
"#{base_url}/Index.aspx"
|
295
|
+
end
|
296
|
+
|
297
|
+
# returns base url for API access
|
298
|
+
def xml_services_base_url
|
299
|
+
"#{base_url}/WebService/Service.asmx"
|
300
|
+
end
|
301
|
+
|
302
|
+
@@notification_params_map = {
|
303
|
+
'OutSum' => :amount,
|
304
|
+
'InvId' => :invoice_id,
|
305
|
+
'SignatureValue' => :signature,
|
306
|
+
'Culture' => :language
|
307
|
+
}
|
308
|
+
|
309
|
+
@@params_map = {
|
310
|
+
'MrchLogin' => :login,
|
311
|
+
'OutSum' => :amount,
|
312
|
+
'InvId' => :invoice_id,
|
313
|
+
'Desc' => :description,
|
314
|
+
'Email' => :email,
|
315
|
+
'IncCurrLabel' => :currency,
|
316
|
+
'Culture' => :language,
|
317
|
+
'SignatureValue' => :signature
|
318
|
+
}.invert
|
319
|
+
|
320
|
+
@@service_params_map = {
|
321
|
+
'MerchantLogin' => :login,
|
322
|
+
'Language' => :language,
|
323
|
+
'IncCurrLabel' => :currency,
|
324
|
+
'OutSum' => :amount
|
325
|
+
}.invert
|
326
|
+
|
327
|
+
def md5(str) #:nodoc:
|
328
|
+
Digest::MD5.hexdigest(str).downcase
|
329
|
+
end
|
330
|
+
|
331
|
+
def subhash(hash, keys) #:nodoc:
|
332
|
+
Hash[keys.map do |key|
|
333
|
+
[key.to_sym, hash[key.to_sym]]
|
334
|
+
end]
|
335
|
+
end
|
336
|
+
|
337
|
+
# Maps gem parameter names, to robokassa names
|
338
|
+
def self.map_params(params, map)
|
339
|
+
Hash[params.map do|key, value| [(map[key] || map[key.to_sym] || key), value] end]
|
340
|
+
end
|
341
|
+
|
342
|
+
def map_params(params, map) #:nodoc:
|
343
|
+
self.class.map_params params, map
|
344
|
+
end
|
345
|
+
|
346
|
+
def query_string(params) #:nodoc:
|
347
|
+
params.map do |name, value|
|
348
|
+
"#{CGI::escape(name.to_s)}=#{CGI::escape(value.to_s)}"
|
349
|
+
end.join("&")
|
350
|
+
end
|
351
|
+
|
352
|
+
# make request and parse XML from specified url
|
353
|
+
def get_remote_xml(url)
|
354
|
+
# xml_data = Net::HTTP.get_response(URI.parse(url)).body
|
355
|
+
begin
|
356
|
+
xml_data = URI.parse(url).read
|
357
|
+
doc = REXML::Document.new(xml_data)
|
358
|
+
rescue REXML::ParseException => e
|
359
|
+
sleep 1
|
360
|
+
get_remote_xml(url)
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
|
365
|
+
class << self
|
366
|
+
# This method creates new instance of Interface for specified key (for multi-account support)
|
367
|
+
# it calls then Robokassa call ResultURL callback
|
368
|
+
def create_by_notification_key(key)
|
369
|
+
self.new get_options_by_notification_key(key)
|
370
|
+
end
|
371
|
+
|
372
|
+
%w{success fail notify}.map{|m| m + '_implementation'} + ['get_options_by_notification_key'].each do |m|
|
373
|
+
define_method m.to_sym do |*args|
|
374
|
+
raise NoMethodError, "Robokassa::Interface.#{m} should be defined by app developer"
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
data/robokassa.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
version = File.read(File.expand_path("../VERSION",__FILE__)).strip
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "robokassa"
|
7
|
+
s.version = version
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Victor Zagorski aka shaggyone"]
|
10
|
+
s.email = ["victor@zagorski.ru"]
|
11
|
+
s.homepage = "http://github.com/shaggyone/robokassa"
|
12
|
+
s.summary = %q{This gem adds robokassa support to your app.}
|
13
|
+
s.description = %q{
|
14
|
+
Robokassa is payment system, that provides a single simple interface for payment systems popular in Russia.
|
15
|
+
If you have customers in Russia you can use the gem.
|
16
|
+
|
17
|
+
The first thing about this gem, is that it was oribinally designed for spree commerce. So keep it in mind.
|
18
|
+
}
|
19
|
+
|
20
|
+
s.rubyforge_project = "robokassa"
|
21
|
+
|
22
|
+
s.files = `git ls-files`.split("\n")
|
23
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
25
|
+
s.require_paths = ["lib"]
|
26
|
+
|
27
|
+
s.add_dependency "rails", ">= 3.2.0"
|
28
|
+
|
29
|
+
s.add_development_dependency "rake"
|
30
|
+
s.add_development_dependency "thor"
|
31
|
+
s.add_development_dependency "shoulda"
|
32
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
33
|
+
s.add_development_dependency 'combustion', '~> 0.3.1'
|
34
|
+
s.add_development_dependency 'sqlite3'
|
35
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
require 'robokassa/interface'
|
3
|
+
describe "Interface should work correct" do
|
4
|
+
before :each do
|
5
|
+
end
|
6
|
+
|
7
|
+
it "Should correctly use test server" do
|
8
|
+
i = Robokassa::Interface.new :test_mode => true
|
9
|
+
i.should be_test_mode
|
10
|
+
i.base_url.should == "http://test.robokassa.ru"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should compute correct signature string" do
|
14
|
+
i = Robokassa::Interface.new :test_mode => true, :login => 'demo', 'password1' => '12345'
|
15
|
+
i.init_payment_signature_string(15, 185.0, "Order #125").should == "demo:185.0:15:12345"
|
16
|
+
i.init_payment_signature_string(15, 185.0, "Order #125", {:a => 15, :c => 30, :b => 20}).should == "demo:185.0:15:12345:shpa=15:shpb=20:shpc=30"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should create correct init payment url" do
|
20
|
+
i = Robokassa::Interface.new :test_mode => true, :login => 'demo', 'password1' => '12345'
|
21
|
+
i = Robokassa::Interface.new :test_mode => true, :login => 'shaggyone239', 'password1' => '12345asdf'
|
22
|
+
i.init_payment_signature_string(15, 185.11, "Order #125").should == "shaggyone239:185.11:15:12345asdf"
|
23
|
+
i.init_payment_signature(15, 185.11, "Order #125").should == "55f2aee20767cde28e7fc49919cec969"
|
24
|
+
i.init_payment_url(15, 185.11, "Order 125", '', 'ru', 'demo@robokassa.ru', {}).should ==
|
25
|
+
"http://test.robokassa.ru/Index.aspx?MrchLogin=shaggyone239&OutSum=185.11&InvId=15&Desc=Order+125&SignatureValue=55f2aee20767cde28e7fc49919cec969&IncCurrLabel=&Email=demo%40robokassa.ru&Culture=ru"
|
26
|
+
i.init_payment_signature(196, 2180.0, "R602412577").should == "adeedf2afbac5eca09b44898da3ef51a"
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should return correct notification, success and fail urls" do
|
30
|
+
i = Robokassa::Interface.new :test_mode => true, :login => 'demo', 'password1' => '12345', :notification_key => "asfadsf"
|
31
|
+
i.default_url_options = {
|
32
|
+
:host => '127.0.0.1',
|
33
|
+
:port => 3000
|
34
|
+
}
|
35
|
+
i.notification_url.should == 'http://127.0.0.1:3000/robokassa/asfadsf/notify'
|
36
|
+
i.on_success_url.should == 'http://127.0.0.1:3000/robokassa/success'
|
37
|
+
i.on_fail_url.should == 'http://127.0.0.1:3000/robokassa/fail'
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe 'routes' do
|
5
|
+
context "robokassa" do
|
6
|
+
specify { get('/robokassa/some-secure-notification-key/notify').should route_to(
|
7
|
+
controller: 'robokassa',
|
8
|
+
action: 'notify',
|
9
|
+
notification_key: 'some-secure-notification-key'
|
10
|
+
)}
|
11
|
+
|
12
|
+
specify { get('/robokassa/success').should route_to(
|
13
|
+
controller: 'robokassa',
|
14
|
+
action: 'success'
|
15
|
+
)}
|
16
|
+
|
17
|
+
specify { get('/robokassa/fail').should route_to(
|
18
|
+
controller: 'robokassa',
|
19
|
+
action: 'fail'
|
20
|
+
)}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
require 'rails'
|
5
|
+
|
6
|
+
Bundler.require :default, :development
|
7
|
+
|
8
|
+
Combustion.initialize! :active_record, :action_controller
|
9
|
+
|
10
|
+
require 'rspec/rails'
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.use_transactional_fixtures = true
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,199 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: robokassa
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Victor Zagorski aka shaggyone
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-03-31 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 3.2.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 3.2.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: thor
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: shoulda
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: bundler
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.0.0
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.0.0
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: combustion
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 0.3.1
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 0.3.1
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: sqlite3
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
description: ! "\n Robokassa is payment system, that provides a single simple interface
|
127
|
+
for payment systems popular in Russia.\n If you have customers in Russia you
|
128
|
+
can use the gem.\n\n The first thing about this gem, is that it was oribinally
|
129
|
+
designed for spree commerce. So keep it in mind.\n "
|
130
|
+
email:
|
131
|
+
- victor@zagorski.ru
|
132
|
+
executables: []
|
133
|
+
extensions: []
|
134
|
+
extra_rdoc_files: []
|
135
|
+
files:
|
136
|
+
- .gitignore
|
137
|
+
- Gemfile
|
138
|
+
- README.md
|
139
|
+
- Rakefile
|
140
|
+
- VERSION
|
141
|
+
- app/assets/images/robokassa/AlfaBank.gif
|
142
|
+
- app/assets/images/robokassa/HandyBank.gif
|
143
|
+
- app/assets/images/robokassa/Mastercard.gif
|
144
|
+
- app/assets/images/robokassa/MoneyMail.gif
|
145
|
+
- app/assets/images/robokassa/RBKMoney.gif
|
146
|
+
- app/assets/images/robokassa/TeleMoney.gif
|
147
|
+
- app/assets/images/robokassa/TerminalsAbsolutplat.gif
|
148
|
+
- app/assets/images/robokassa/TerminalsElecsnet.gif
|
149
|
+
- app/assets/images/robokassa/TerminalsPinpay.gif
|
150
|
+
- app/assets/images/robokassa/TerminalsQiwi.gif
|
151
|
+
- app/assets/images/robokassa/TerminalsUnikassa.gif
|
152
|
+
- app/assets/images/robokassa/TerminalsmobilElement.gif
|
153
|
+
- app/assets/images/robokassa/VKontakte.gif
|
154
|
+
- app/assets/images/robokassa/VTB24.gif
|
155
|
+
- app/assets/images/robokassa/Visa.gif
|
156
|
+
- app/assets/images/robokassa/WMTrustID.gif
|
157
|
+
- app/assets/images/robokassa/WebmoneyR.gif
|
158
|
+
- app/assets/images/robokassa/YandexMoney.gif
|
159
|
+
- app/assets/images/robokassa/iRobo.gif
|
160
|
+
- app/assets/images/robokassa/logo.gif
|
161
|
+
- app/controllers/robokassa_controller.rb
|
162
|
+
- app/helpers/robokassa_helper.rb
|
163
|
+
- app/views/payment_method/robokassa/_init.html.erb
|
164
|
+
- autotest/discover.rb
|
165
|
+
- config/locales/en.yml
|
166
|
+
- config/locales/ru.yml
|
167
|
+
- config/routes.rb
|
168
|
+
- lib/robokassa.rb
|
169
|
+
- lib/robokassa/controller.rb
|
170
|
+
- lib/robokassa/interface.rb
|
171
|
+
- robokassa.gemspec
|
172
|
+
- spec/lib/interface_spec.rb
|
173
|
+
- spec/routing/routes_spec.rb
|
174
|
+
- spec/spec_helper.rb
|
175
|
+
homepage: http://github.com/shaggyone/robokassa
|
176
|
+
licenses: []
|
177
|
+
post_install_message:
|
178
|
+
rdoc_options: []
|
179
|
+
require_paths:
|
180
|
+
- lib
|
181
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
182
|
+
none: false
|
183
|
+
requirements:
|
184
|
+
- - ! '>='
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
188
|
+
none: false
|
189
|
+
requirements:
|
190
|
+
- - ! '>='
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0'
|
193
|
+
requirements: []
|
194
|
+
rubyforge_project: robokassa
|
195
|
+
rubygems_version: 1.8.19
|
196
|
+
signing_key:
|
197
|
+
specification_version: 3
|
198
|
+
summary: This gem adds robokassa support to your app.
|
199
|
+
test_files: []
|