bucky 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/CONTRIBUTING.md +32 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +251 -0
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/bucky.gemspec +37 -0
- data/lib/bucky/config.rb +37 -0
- data/lib/bucky/constants.rb +18 -0
- data/lib/bucky/main.rb +37 -0
- data/lib/bucky/payment_response.rb +21 -0
- data/lib/bucky/response.rb +38 -0
- data/lib/bucky/signature.rb +49 -0
- data/lib/bucky/version.rb +3 -0
- data/lib/bucky.rb +11 -0
- data/lib/generators/bucky/install/install_generator.rb +49 -0
- data/lib/generators/bucky/install/templates/buckaroo.rb +5 -0
- data/lib/generators/bucky/install/templates/transactions_controller.rb +32 -0
- metadata +180 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: df1137e34f2215b445b9b31d10cb76096a1a510e
|
4
|
+
data.tar.gz: 4b672b0a49b0f549d97981c866691bb4dd5d9198
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9737e2142380606b2c7fc423b2140c2b2a4f8896538b06bd18347e26cd38366cede9ec5f83b357db8e1be9ccdc77ce62ee4417ee539067c06b58fe09e679a5eb
|
7
|
+
data.tar.gz: 2622be3264891ce0e2c778ec787b485506a4a9e633f607ec8c739c2c6a29762634805adb8541b116ada145d69369a89efdc1f4ab6faa9f82f429bb26e85881df
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
|
4
|
+
|
5
|
+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
|
6
|
+
|
7
|
+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
|
8
|
+
|
9
|
+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
|
10
|
+
|
11
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
|
12
|
+
|
13
|
+
This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
We love pull requests from everyone. By participating in this project, you agree
|
2
|
+
to abide by the [code of conduct]. And also agree to [thoughtbot's code of conduct]
|
3
|
+
|
4
|
+
[code of conduct]: https://githu.com/sajoku/bucky/CODE_OF_CONDUCT.md
|
5
|
+
[thoughtbot's code of conduct]: https://thoughtbot.com/open-source-code-of-conduct
|
6
|
+
|
7
|
+
1. Fork the repo.
|
8
|
+
|
9
|
+
2. Run `./bin/setup`.
|
10
|
+
|
11
|
+
3. Run the tests. We only take pull requests with passing tests, and it's great
|
12
|
+
to know that you have a clean slate: `bundle exec rspec spec`
|
13
|
+
|
14
|
+
4. Add a test for your change. Only refactoring and documentation changes
|
15
|
+
require no new tests. If you are adding functionality or fixing a
|
16
|
+
bug, we need a test!
|
17
|
+
|
18
|
+
5. Make the test pass.
|
19
|
+
|
20
|
+
6. Push to your fork and submit a pull request.
|
21
|
+
|
22
|
+
At this point you're waiting on us. We like to at least comment on, if not
|
23
|
+
accept, pull requests within three business days (and, typically, one business
|
24
|
+
day). We may suggest some changes or improvements or alternatives.
|
25
|
+
|
26
|
+
Some things that will increase the chance that your pull request is accepted,
|
27
|
+
taken straight from the Ruby on Rails guide:
|
28
|
+
|
29
|
+
* Use Rails idioms and helpers
|
30
|
+
* Include tests that fail without your code, and pass with it
|
31
|
+
* Update the documentation, the surrounding one, examples elsewhere, guides,
|
32
|
+
whatever is affected by your contribution
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Sander Kuijper
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,251 @@
|
|
1
|
+
# Bucky
|
2
|
+
|
3
|
+
Bucky is intended to provide some default configuration for your Rails app when using Buckaroo as a Payment Provider. It currently only talks to the [NVP endpoint].
|
4
|
+
|
5
|
+
[NVP endpoint]: http://support.buckaroo.nl/nl/index.php/NVP_Koppeling
|
6
|
+
|
7
|
+
Bucky has opinionated defaults and is intended to be used with explicitness in mind.
|
8
|
+
In stead of doing magic Bucky tries to take care of the hard parts and provide you with a clear API.
|
9
|
+
|
10
|
+
Please use [GitHub Issues] to report bugs.
|
11
|
+
|
12
|
+
[GitHub Issues]: https://github.com/sajoku/bucky/issues
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Bucky is tested against Rails 4.2.1.
|
17
|
+
It has some dependencies which are:
|
18
|
+
* httparty
|
19
|
+
* rails
|
20
|
+
* addressable
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem 'bucky'
|
26
|
+
```
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
$ bundle
|
31
|
+
|
32
|
+
Or install it yourself as:
|
33
|
+
|
34
|
+
$ gem install bucky
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
|
39
|
+
TLDR;
|
40
|
+
|
41
|
+
#### Generate a default setup
|
42
|
+
|
43
|
+
Assuming you are calling your model `Transaction` you can run
|
44
|
+
`rails generate bucky:install` and Bucky will try to generate the needed files and inject the routes.
|
45
|
+
|
46
|
+
### Manual setup
|
47
|
+
|
48
|
+
Create an initializer in app/initializers/ which calls Buckaroo::Config.configure.
|
49
|
+
Websitekey and Secret are two variables that need to be present.
|
50
|
+
You can find these in your Buckaroo dashboard.
|
51
|
+
|
52
|
+
```initializers/buckaroo.rb```
|
53
|
+
|
54
|
+
``` ruby
|
55
|
+
Buckaroo::Config.configure(
|
56
|
+
endpoint: "https://testcheckout.buckaroo.nl/nvp/",
|
57
|
+
secret: "very-secret",
|
58
|
+
websitekey: "very-secure"
|
59
|
+
)
|
60
|
+
```
|
61
|
+
|
62
|
+
You might want to create separate configurations for different environments
|
63
|
+
``` ruby
|
64
|
+
if Rails.env.production?
|
65
|
+
Buckaroo::Config.configure(
|
66
|
+
endpoint: "https://checkout.buckaroo.nl/nvp/",
|
67
|
+
secret: "very-secret-production",
|
68
|
+
websitekey: "very-secure-production"
|
69
|
+
)
|
70
|
+
elsif Rails.env.development?
|
71
|
+
|
72
|
+
Buckaroo::Config.configure(
|
73
|
+
endpoint: "https://testcheckout.buckaroo.nl/nvp/",
|
74
|
+
secret: "very-secret",
|
75
|
+
websitekey: "very-secure"
|
76
|
+
)
|
77
|
+
else
|
78
|
+
Buckaroo::Config.configure(
|
79
|
+
endpoint: "https://testcheckout.buckaroo.nl/nvp/",
|
80
|
+
secret: "very-secret-test",
|
81
|
+
websitekey: "very-secure-test"
|
82
|
+
)
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
### Creating a transaction request
|
87
|
+
|
88
|
+
Your next step is to create a transaction request which will return a raw response. You can either choose to parse the response with Bucky or parse this yourself. examples!
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
def do_it_yourself
|
92
|
+
provider = Buckaroo::Main.new(transaction_request_parameters)
|
93
|
+
raw_response = provider.post_transaction_request
|
94
|
+
end
|
95
|
+
|
96
|
+
# These are the minimal keys and values you need to send.
|
97
|
+
#
|
98
|
+
# You can omit the brq_return, brq_returnreject, brq_returncancel, brq_returnerror if you have configured these in the Buckaroo dashboard.
|
99
|
+
def transaction_request_parameters
|
100
|
+
{
|
101
|
+
brq_amount: 1.0,
|
102
|
+
brq_currency: "EUR",
|
103
|
+
brq_invoicenumber: 46,
|
104
|
+
brq_description: "order 46",
|
105
|
+
brq_return: "http://localhost:3000/transactions/46/callback_success",
|
106
|
+
brq_returnreject: "http://localhost:3000/transactions/46/callback_reject",
|
107
|
+
brq_returncancel: "http://localhost:3000/transactions/46/callback_cancel",
|
108
|
+
brq_returnerror: "http://localhost:3000/transactions/46/callback_error",
|
109
|
+
brq_continue_on_incomplete: "RedirectToHTML" #Or no to redirect to html
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
This returns:
|
114
|
+
```
|
115
|
+
"BRQ_ACTIONREQUIRED=redirect&BRQ_AMOUNT=123.00&BRQ_APIRESULT=ActionRequired&BRQ_CURRENCY=EUR&BRQ_DESCRIPTION=order+46&BRQ_INVOICENUMBER=46&BRQ_MUTATIONTYPE=NotSet&BRQ_REDIRECTURL=https%3a%2f%2ftestcheckout.buckaroo.nl%2fhtml%2fredirect.ashx%3fr%3d82CBA1A6EDC245C0B5D48CD38DF0CF32&BRQ_STATUSCODE=790&BRQ_STATUSMESSAGE=Pending+input&BRQ_TEST=true&BRQ_TIMESTAMP=2015-04-24+11%3a31%3a35&BRQ_TRANSACTIONS=E56EC0D0BC614F958486BC87F97D997A&BRQ_WEBSITEKEY=very-secure&BRQ_SIGNATURE=614e5d6df26e5995e25aa8deb9e0ca9c745e009d"
|
116
|
+
|
117
|
+
Or let Bucky handle the parsing for you:
|
118
|
+
``` ruby
|
119
|
+
def let_bucky_do_it
|
120
|
+
provider = Buckaroo::Main.new(params)
|
121
|
+
raw_response = provider.post_transaction_request
|
122
|
+
parsed_response = Buckaroo::Response.new(raw_response)
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
`Buckaroo::Response` parses the response and adds some convenience methods.
|
127
|
+
`parsed_response.redirect_url`
|
128
|
+
Returns the url which the user (person that's paying) needs to be redirected to.
|
129
|
+
|
130
|
+
`parsed_response.status`
|
131
|
+
Status code of the transaction requests. Find the different statuses in `Constants.rb`.
|
132
|
+
|
133
|
+
`parsed_response.human_readable_status`
|
134
|
+
Just like the regular status except Bucky matched the human readable string from `Constants.rb`.
|
135
|
+
|
136
|
+
|
137
|
+
### Callbacks
|
138
|
+
|
139
|
+
Once the user completes a transaction, Buckaroo will callback your app which can be success, reject, failure or cancel. You need to validate the response and check the status of the payment.
|
140
|
+
Bucky provides `Buckaroo::Signature.valid?(params)` to check if the signature returned by Buckaroo actually matches the one Bucky calculates. Check out `Signature.rb` on how this gets done.
|
141
|
+
|
142
|
+
If the signature is correct your app needs to update/cancel the transaction/payment. Although Buckaroo posts to callback_success it's easy to double check the response for status success.
|
143
|
+
`Buckaroo::PaymentResponse.new(params).successful_payment?`
|
144
|
+
|
145
|
+
|
146
|
+
### Putting it all together
|
147
|
+
|
148
|
+
Your final implementation could look something like this:
|
149
|
+
|
150
|
+
``` ruby
|
151
|
+
class PaymentProvider
|
152
|
+
|
153
|
+
def initialize(transaction)
|
154
|
+
@transaction = transaction
|
155
|
+
end
|
156
|
+
|
157
|
+
def create_transaction_request
|
158
|
+
provider = @Buckaroo::Main.new(params)
|
159
|
+
result = provider.post_transaction_request
|
160
|
+
Buckaroo::Response.new(result)
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
|
165
|
+
attr_reader :transaction
|
166
|
+
|
167
|
+
def transaction_request_parameters
|
168
|
+
{
|
169
|
+
brq_amount: transaction.amount_cents.to_f / 100,
|
170
|
+
brq_currency: transaction.currency,
|
171
|
+
brq_invoicenumber: transaction.id,
|
172
|
+
brq_description: "order #{transaction.id}",
|
173
|
+
brq_return: callback_success_transaction_url(transaction.id),
|
174
|
+
brq_returnreject: callback_reject_transaction_url(transaction),
|
175
|
+
brq_returncancel: callback_cancel_transaction_url(transaction),
|
176
|
+
brq_returnerror: callback_error_transaction_url(transaction),
|
177
|
+
brq_continue_on_incomplete: "RedirectToHTML"
|
178
|
+
}
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
```
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
class TransactionsController < ApplicationController
|
186
|
+
protect_from_forgery with: :null_session
|
187
|
+
before_filter :require_valid_signature
|
188
|
+
|
189
|
+
def callback_success
|
190
|
+
if Buckaroo::PaymentResponse.new(params).successful_payment?
|
191
|
+
transaction = Transaction.find(params[:id])
|
192
|
+
transaction.update_attributes!(accepted_at: DateTime.now)
|
193
|
+
|
194
|
+
redirect_to root_path
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Since the error and cancel response are very similar you can choose to handle these
|
199
|
+
# with a single method. It's easy to just create separate actions for these callbacks.
|
200
|
+
def callback_reject
|
201
|
+
transaction = Transaction.find(params[:id])
|
202
|
+
|
203
|
+
transaction.update_attributes!(rejected_at: DateTime.now)
|
204
|
+
|
205
|
+
redirect_to root_path
|
206
|
+
end
|
207
|
+
alias_method :callback_error, :callback_reject
|
208
|
+
alias_method :callback_cancel, :callback_reject
|
209
|
+
|
210
|
+
private
|
211
|
+
|
212
|
+
# Check the signature before every action
|
213
|
+
def require_valid_signature
|
214
|
+
unless Buckaroo::Signature.valid?(params)
|
215
|
+
render status: 422, nothing: true
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
end
|
220
|
+
```
|
221
|
+
|
222
|
+
``` ruby
|
223
|
+
resources :transactions, only: :none do
|
224
|
+
member do
|
225
|
+
post :callback_success
|
226
|
+
post :callback_reject
|
227
|
+
post :callback_cancel
|
228
|
+
post :callback_error
|
229
|
+
end
|
230
|
+
end
|
231
|
+
```
|
232
|
+
|
233
|
+
## Development
|
234
|
+
|
235
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
|
236
|
+
|
237
|
+
|
238
|
+
## Contributing
|
239
|
+
|
240
|
+
1. Fork it ( https://github.com/[my-github-username]/bucky/fork )
|
241
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
242
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
243
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
244
|
+
5. Create a new Pull Request
|
245
|
+
|
246
|
+
### Thank you
|
247
|
+
|
248
|
+
A big thanks to:
|
249
|
+
* [Daniel Willemse](https://github.com/danielwillemse).For writing the initial implementation.
|
250
|
+
* The [buckaroo-ideal](https://github.com/eet-nu/buckaroo-ideal) gem. I "borrowed" the configuration class. And peeked at some implementation details.
|
251
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "bucky"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/bucky.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bucky/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "bucky"
|
8
|
+
spec.version = Bucky::VERSION
|
9
|
+
spec.authors = ["Sander Kuijper"]
|
10
|
+
spec.email = ["sajoku@me.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Buckaroo payment gem}
|
13
|
+
spec.description = %q{Buckaroo payment gem for the NVP gateway}
|
14
|
+
spec.homepage = "http://github.com/sajoku/bucky"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
if spec.respond_to?(:metadata)
|
18
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
19
|
+
else
|
20
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
21
|
+
end
|
22
|
+
|
23
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
24
|
+
spec.bindir = "exe"
|
25
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
26
|
+
spec.require_paths = ["lib"]
|
27
|
+
|
28
|
+
spec.add_runtime_dependency "httparty"
|
29
|
+
spec.add_runtime_dependency "rails"
|
30
|
+
spec.add_runtime_dependency "addressable"
|
31
|
+
|
32
|
+
spec.add_development_dependency "bundler", "~> 1.9"
|
33
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
34
|
+
spec.add_development_dependency "rspec"
|
35
|
+
spec.add_development_dependency "pry"
|
36
|
+
spec.add_development_dependency "webmock"
|
37
|
+
end
|
data/lib/bucky/config.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Buckaroo
|
2
|
+
class Config
|
3
|
+
class << self
|
4
|
+
|
5
|
+
# The endpoint to which your app will connect.
|
6
|
+
# expects a string which is a valid url
|
7
|
+
attr_accessor :endpoint
|
8
|
+
|
9
|
+
#The secret provided by Buckaroo
|
10
|
+
attr_accessor :secret
|
11
|
+
|
12
|
+
# the website key you generated on the configuration panel
|
13
|
+
# in Buckaroo
|
14
|
+
attr_accessor :websitekey
|
15
|
+
|
16
|
+
#The culture/locale in which the payment occurs
|
17
|
+
# Defaults to nl-NL. Other valid values are en-US, de-DE
|
18
|
+
attr_accessor :culture
|
19
|
+
|
20
|
+
def defaults
|
21
|
+
{
|
22
|
+
endpoint: "https://testcheckout.buckaroo.nl/nvp/",
|
23
|
+
secret: "",
|
24
|
+
websitekey: "",
|
25
|
+
culture: 'nl-NL',
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def configure(settings = {})
|
30
|
+
defaults.merge(settings).each do |key, value|
|
31
|
+
instance_variable_set(:"@#{key}", value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Buckaroo
|
2
|
+
module Constants
|
3
|
+
|
4
|
+
PAYMENT_STATUS_CODES = {
|
5
|
+
"190" => "Payment success",
|
6
|
+
"490" => "Payment failure",
|
7
|
+
"491" => "Validation error",
|
8
|
+
"492" => "Technical error",
|
9
|
+
"690" => "Payment rejected",
|
10
|
+
"790" => "Waiting for user input",
|
11
|
+
"791" => "Waiting for processor",
|
12
|
+
"792" => "Waiting on consumer action (e.g.: initiate money transfer)",
|
13
|
+
"793" => "Payment on hold (e.g. waiting for sufficient balance)",
|
14
|
+
"890" => "Cancelled by consumer",
|
15
|
+
"891" => "Cancelled by merchant"
|
16
|
+
}
|
17
|
+
end
|
18
|
+
end
|
data/lib/bucky/main.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module Buckaroo
|
4
|
+
class Main
|
5
|
+
|
6
|
+
def initialize(params = {})
|
7
|
+
@params = params
|
8
|
+
end
|
9
|
+
|
10
|
+
def post_transaction_request
|
11
|
+
HTTParty.post(Buckaroo::Config.endpoint, body: params_with_signature)
|
12
|
+
end
|
13
|
+
|
14
|
+
def params_with_signature
|
15
|
+
transaction_parameters.merge(brq_signature: signature)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def transaction_parameters
|
21
|
+
{
|
22
|
+
brq_websitekey: Buckaroo::Config.websitekey,
|
23
|
+
brq_culture: Buckaroo::Config.culture
|
24
|
+
}.merge(@params)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
def endpoint
|
29
|
+
Buckaroo::Config.endpoint
|
30
|
+
end
|
31
|
+
|
32
|
+
def signature
|
33
|
+
Buckaroo::Signature.new(transaction_parameters).to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Buckaroo
|
2
|
+
class PaymentResponse
|
3
|
+
|
4
|
+
def initialize(params = {})
|
5
|
+
@params = params
|
6
|
+
end
|
7
|
+
|
8
|
+
def successful_payment?
|
9
|
+
Constants::PAYMENT_STATUS_CODES[status_code] == 'Payment success'
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
attr_reader :params
|
15
|
+
|
16
|
+
def status_code
|
17
|
+
params["BRQ_STATUSCODE"] || params["brq_statuscode"]
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
|
3
|
+
module Buckaroo
|
4
|
+
class Response
|
5
|
+
|
6
|
+
def initialize(raw_response)
|
7
|
+
@raw_response = raw_response
|
8
|
+
end
|
9
|
+
|
10
|
+
def redirect_url
|
11
|
+
converted_response["BRQ_REDIRECTURL"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def status
|
15
|
+
converted_response["BRQ_STATUSCODE"].to_i
|
16
|
+
end
|
17
|
+
|
18
|
+
def human_readable_status
|
19
|
+
Buckaroo::Constants::PAYMENT_STATUS_CODES[status.to_s]
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def converted_response
|
25
|
+
@converted_response ||= Hash[unescape_raw_response]
|
26
|
+
end
|
27
|
+
|
28
|
+
# Using Addressable converts the raw_response into something like:
|
29
|
+
# [
|
30
|
+
# ["BRQ_WEBSITEKEY", "very-secure"],
|
31
|
+
# ["BRQ_SIGNATURE", "b871a4bc3b30c34df70949d3e20903dcd0810fd9"]
|
32
|
+
# ]
|
33
|
+
# Which is much easier to work with
|
34
|
+
def unescape_raw_response
|
35
|
+
Addressable::URI.form_unencode(@raw_response)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'active_support/hash_with_indifferent_access'
|
2
|
+
|
3
|
+
module Buckaroo
|
4
|
+
class Signature
|
5
|
+
attr_accessor :body
|
6
|
+
|
7
|
+
def initialize(hash)
|
8
|
+
@body = hash.dup
|
9
|
+
end
|
10
|
+
|
11
|
+
def to_s
|
12
|
+
Digest::SHA1.hexdigest(body_to_string.split("\n").join("") + secret_key)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.valid?(params)
|
16
|
+
hash = HashWithIndifferentAccess.new(params.select{ |key, value| key.to_s.match(/^brq_|^add_|^cust_/i) })
|
17
|
+
signature = hash.delete(:brq_signature) || hash.delete(:BRQ_SIGNATURE)
|
18
|
+
|
19
|
+
self.new(hash).to_s == signature
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def secret_key
|
25
|
+
Buckaroo::Config.secret
|
26
|
+
end
|
27
|
+
|
28
|
+
# Modifies the given hash according to the Buckaroo API documentation.
|
29
|
+
#
|
30
|
+
#
|
31
|
+
# The calculation is done as follows:
|
32
|
+
# 1. Create a list with all the fields in the params given that start with brq_, add_ or cust_ in the following format: brq_fieldname=Value
|
33
|
+
# 2. Sort this list on alphabetical order based on the field_name (brq_amount should come before brq_websitekey).
|
34
|
+
# Note: Sort should NOT be done case-sensitive. Case should be preserved in the values. Example: BRQ_AMOUNT=1.00brq_currency=EURbrq_websitekey=asdfasdfsecret
|
35
|
+
# 3. Join all these values as a string. Do not use any whitespace.
|
36
|
+
# Example: BRQ_AMOUNT=1.00brq_currency=EURbrq_websitekey=asdfasdfsecretkey
|
37
|
+
# 4. Append the pre-shared secret key to this string. *(Buckaroo::Config.secret).
|
38
|
+
# 5. Calculate the SHA-1 hash of this string in a hexadecimal format and compare it to the signature given in the response.
|
39
|
+
|
40
|
+
def body_to_string
|
41
|
+
sanitized_body.keys.sort_by(&:downcase).map{|key| "#{key}=#{@body[key]}" }.join("")
|
42
|
+
end
|
43
|
+
|
44
|
+
def sanitized_body
|
45
|
+
@body.map{|key, value| @body[key] = value.to_s.gsub("+",' ')}
|
46
|
+
@body
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/bucky.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require "bucky/version"
|
2
|
+
|
3
|
+
module Buckaroo
|
4
|
+
autoload :VERSION, 'bucky/version'
|
5
|
+
autoload :Constants, 'bucky/constants'
|
6
|
+
autoload :Main, 'bucky/main'
|
7
|
+
autoload :Config, 'bucky/config'
|
8
|
+
autoload :Response, 'bucky/response'
|
9
|
+
autoload :Signature, 'bucky/signature'
|
10
|
+
autoload :PaymentResponse, 'bucky/payment_response'
|
11
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Bucky
|
4
|
+
module Generators
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path('../templates', __FILE__)
|
7
|
+
|
8
|
+
def initialize_bucky_configuration_template
|
9
|
+
if yes?("Generate a new Buckaroo::Config template?")
|
10
|
+
if File.exist? "config/initializers/buckaroo.rb"
|
11
|
+
puts "config/initializers/buckaroo.rb already exists. Rename or manually copy the file from templates"
|
12
|
+
else
|
13
|
+
copy_file "buckaroo.rb", "config/initializers/buckaroo.rb"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_transactions_controller
|
19
|
+
if yes?("Generate transactions_controller.rb?")
|
20
|
+
if File.exist? "app/controllers/transactions_controller.rb"
|
21
|
+
puts "TransactionsController already exists. Rename or manually copy te file from templates."
|
22
|
+
else
|
23
|
+
copy_file 'transactions_controller.rb', 'app/controllers/transactions_controller.rb'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def inject_bucky_transactions_into_routes
|
29
|
+
if yes?("Inject transaction callback routes in config/routes.rb?")
|
30
|
+
insert_into_file "config/routes.rb", before: /^end/ do
|
31
|
+
<<-RUBY
|
32
|
+
|
33
|
+
resources :transactions, only: :none do
|
34
|
+
member do
|
35
|
+
post :callback_success
|
36
|
+
post :callback_reject
|
37
|
+
post :callback_cancel
|
38
|
+
post :callback_error
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
RUBY
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class TransactionsController < ApplicationController
|
2
|
+
protect_from_forgery with: :null_session
|
3
|
+
before_filter :require_signed_params
|
4
|
+
|
5
|
+
def callback_success
|
6
|
+
if Buckaroo::PaymentResponse.new(params).successful_payment?
|
7
|
+
#Your code here
|
8
|
+
redirect_to root_path
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
#handle transaction rejection, error, and cancel callbacks.
|
13
|
+
#
|
14
|
+
# ie.
|
15
|
+
# transaction = Transaction.find(params[:id])
|
16
|
+
# transaction.update_attributes(rejected_at: DateTime.now)
|
17
|
+
#
|
18
|
+
def callback_reject
|
19
|
+
#your code here
|
20
|
+
end
|
21
|
+
alias_method :callback_error, :callback_reject
|
22
|
+
alias_method :callback_cancel, :callback_reject
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def require_signed_params
|
27
|
+
unless Buckaroo::Signature.valid?(params)
|
28
|
+
render status: 422, nothing: true
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,180 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bucky
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sander Kuijper
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-04-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: addressable
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.9'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.9'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '10.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '10.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: pry
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: webmock
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
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
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: Buckaroo payment gem for the NVP gateway
|
126
|
+
email:
|
127
|
+
- sajoku@me.com
|
128
|
+
executables: []
|
129
|
+
extensions: []
|
130
|
+
extra_rdoc_files: []
|
131
|
+
files:
|
132
|
+
- ".gitignore"
|
133
|
+
- ".rspec"
|
134
|
+
- ".travis.yml"
|
135
|
+
- CODE_OF_CONDUCT.md
|
136
|
+
- CONTRIBUTING.md
|
137
|
+
- Gemfile
|
138
|
+
- LICENSE.txt
|
139
|
+
- README.md
|
140
|
+
- Rakefile
|
141
|
+
- bin/console
|
142
|
+
- bin/setup
|
143
|
+
- bucky.gemspec
|
144
|
+
- lib/bucky.rb
|
145
|
+
- lib/bucky/config.rb
|
146
|
+
- lib/bucky/constants.rb
|
147
|
+
- lib/bucky/main.rb
|
148
|
+
- lib/bucky/payment_response.rb
|
149
|
+
- lib/bucky/response.rb
|
150
|
+
- lib/bucky/signature.rb
|
151
|
+
- lib/bucky/version.rb
|
152
|
+
- lib/generators/bucky/install/install_generator.rb
|
153
|
+
- lib/generators/bucky/install/templates/buckaroo.rb
|
154
|
+
- lib/generators/bucky/install/templates/transactions_controller.rb
|
155
|
+
homepage: http://github.com/sajoku/bucky
|
156
|
+
licenses:
|
157
|
+
- MIT
|
158
|
+
metadata:
|
159
|
+
allowed_push_host: https://rubygems.org
|
160
|
+
post_install_message:
|
161
|
+
rdoc_options: []
|
162
|
+
require_paths:
|
163
|
+
- lib
|
164
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
requirements: []
|
175
|
+
rubyforge_project:
|
176
|
+
rubygems_version: 2.4.6
|
177
|
+
signing_key:
|
178
|
+
specification_version: 4
|
179
|
+
summary: Buckaroo payment gem
|
180
|
+
test_files: []
|