paynl 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +51 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/paynl/api/api.rb +71 -0
- data/lib/paynl/api/transaction/get_service.rb +21 -0
- data/lib/paynl/api/transaction/info.rb +33 -0
- data/lib/paynl/api/transaction/refund.rb +45 -0
- data/lib/paynl/api/transaction/start_transaction.rb +245 -0
- data/lib/paynl/api/validate/get_pay_server_ips.rb +16 -0
- data/lib/paynl/api/validate/is_pay_server_ip.rb +25 -0
- data/lib/paynl/config.rb +47 -0
- data/lib/paynl/error/required/apitokenerror.rb +8 -0
- data/lib/paynl/error/required/serviceiderror.rb +8 -0
- data/lib/paynl/error/requirederror.rb +7 -0
- data/lib/paynl/helper.rb +70 -0
- data/lib/paynl/paymentmethods.rb +69 -0
- data/lib/paynl/transaction.rb +143 -0
- data/lib/paynl/version.rb +3 -0
- data/lib/paynl.rb +21 -0
- data/paynl.gemspec +37 -0
- metadata +127 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 597bdb4dd6e58b7935e11868bb68fe0cc4d4d270
|
4
|
+
data.tar.gz: 157694b909a3c50486203eebe04362906fe8e904
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1827605f64419ce0c155a09c2405f97bd5276f96e5d2bb1ab6ad14dc0ac3964f814051f19470699718055f611413442b6ef0e2d203fed9408f4c99784ae2c575
|
7
|
+
data.tar.gz: be136dfc0bf3af14525a17f86ae1ce0679ca626b69a79459cc134aefbfa7a0981bd4739c6a21cd90709446546aac7741bc981980cb4f94e2ea511ea7b6e8a3fe
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Sebastian Berm <sebastian@sebsoft.nl>
|
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,51 @@
|
|
1
|
+
# Pay.nl SDK in Ruby
|
2
|
+
|
3
|
+
---
|
4
|
+
|
5
|
+
- [Installation](#installation)
|
6
|
+
- [Requirements](#requirements)
|
7
|
+
- [Quick start and examples](#quick-start-and-examples)
|
8
|
+
|
9
|
+
---
|
10
|
+
|
11
|
+
This SDK is available as Ruby gem.
|
12
|
+
|
13
|
+
With this SDK you will be able to start transactions and retrieve transactions with their status for the Pay.nl payment service provider.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'paynl'
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
|
25
|
+
$ bundle
|
26
|
+
|
27
|
+
Or install it yourself as:
|
28
|
+
|
29
|
+
$ gem install paynl
|
30
|
+
|
31
|
+
## Requirements
|
32
|
+
This gem requires Ruby 1.9.2+.
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
TODO: Write usage instructions here
|
37
|
+
|
38
|
+
## Development
|
39
|
+
|
40
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
41
|
+
|
42
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
43
|
+
|
44
|
+
## Contributing
|
45
|
+
|
46
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/paynl/sdk-ruby.
|
47
|
+
|
48
|
+
|
49
|
+
## License
|
50
|
+
|
51
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "paynl"
|
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
@@ -0,0 +1,71 @@
|
|
1
|
+
module Paynl
|
2
|
+
module Api
|
3
|
+
class Api
|
4
|
+
@version = 1;
|
5
|
+
@@data = Hash.new
|
6
|
+
|
7
|
+
@apiTokenRequired = false;
|
8
|
+
@serviceIdRequired = false;
|
9
|
+
|
10
|
+
def isApiTokenRequired
|
11
|
+
return @apiTokenRequired
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def isServiceIdRequired
|
16
|
+
return @serviceIdRequired
|
17
|
+
end
|
18
|
+
|
19
|
+
def getData
|
20
|
+
if self.isApiTokenRequired
|
21
|
+
Paynl::Helper::requireApiToken
|
22
|
+
|
23
|
+
@@data['token'] = Paynl::Config::getApiToken
|
24
|
+
end
|
25
|
+
|
26
|
+
if self.isServiceIdRequired
|
27
|
+
Paynl::Helper::requireServiceId
|
28
|
+
|
29
|
+
@@data['serviceId'] = Paynl::Config::getServiceId
|
30
|
+
end
|
31
|
+
|
32
|
+
return @@data
|
33
|
+
end
|
34
|
+
|
35
|
+
def processResult(result)
|
36
|
+
if result['request']['result'] != '1' and result['request']['result'] != 'TRUE'
|
37
|
+
raise result['request']['errorId'] + ' - ' + result['request']['errorMessage']
|
38
|
+
end
|
39
|
+
|
40
|
+
return result
|
41
|
+
end
|
42
|
+
|
43
|
+
def doRequest(endpoint, version = nil)
|
44
|
+
|
45
|
+
data = self.getData
|
46
|
+
uri = Paynl::Config::getApiUrl(endpoint, version)
|
47
|
+
# puts uri
|
48
|
+
# puts data
|
49
|
+
# Code to actually do the CURL request
|
50
|
+
response = Typhoeus::Request.post(
|
51
|
+
uri,
|
52
|
+
:params => data
|
53
|
+
)
|
54
|
+
|
55
|
+
# if response.code != 200
|
56
|
+
# raise 'API error'
|
57
|
+
# end
|
58
|
+
|
59
|
+
# puts response.code # http status code
|
60
|
+
# puts response.time # time in seconds the request took
|
61
|
+
# puts response.headers # the http headers
|
62
|
+
# puts response.headers_hash # http headers put into a hash
|
63
|
+
# puts response.body # the response body
|
64
|
+
|
65
|
+
output = self.processResult(JSON.parse(response.body))
|
66
|
+
return output
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Paynl
|
2
|
+
module Api
|
3
|
+
class GetService < Api
|
4
|
+
|
5
|
+
def getData
|
6
|
+
Paynl::Helper::requireServiceId
|
7
|
+
@@data['serviceId'] = Paynl::Config::getServiceId
|
8
|
+
|
9
|
+
Paynl::Helper::requireApiToken
|
10
|
+
@@data['token'] = Paynl::Config::getApiToken
|
11
|
+
|
12
|
+
return super;
|
13
|
+
end
|
14
|
+
|
15
|
+
def doRequest
|
16
|
+
# TODO: add caching to this
|
17
|
+
return super('transaction/getService', nil)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Paynl
|
2
|
+
module Api
|
3
|
+
class TransactionInfo < Api
|
4
|
+
|
5
|
+
@transactionId = '';
|
6
|
+
|
7
|
+
def getData
|
8
|
+
Paynl::Helper::requireApiToken
|
9
|
+
@@data['token'] = Paynl::Config::getApiToken
|
10
|
+
|
11
|
+
if (@transactionId.nil?)
|
12
|
+
raise('TransactionId not set, please use setTransactionId first.')
|
13
|
+
end
|
14
|
+
|
15
|
+
@@data['transactionId'] = @transactionId
|
16
|
+
|
17
|
+
return super;
|
18
|
+
end
|
19
|
+
|
20
|
+
def setTransactionId(transactionId)
|
21
|
+
if (transactionId.nil?)
|
22
|
+
raise('TransactionId cannot be nil. Please set valid transactionId');
|
23
|
+
end
|
24
|
+
|
25
|
+
@transactionId = transactionId
|
26
|
+
end
|
27
|
+
|
28
|
+
def doRequest
|
29
|
+
return super('transaction/info', nil)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Paynl
|
2
|
+
module Api
|
3
|
+
class TransactionRefund < Api
|
4
|
+
@transactionId = ''
|
5
|
+
@amount = ''
|
6
|
+
@description = ''
|
7
|
+
|
8
|
+
def setTransactionId(transactionId)
|
9
|
+
if (transactionId.nil?)
|
10
|
+
raise('TransactionId cannot be nil. Please set valid transactionId');
|
11
|
+
end
|
12
|
+
@transactionId = transactionId
|
13
|
+
end
|
14
|
+
|
15
|
+
def setAmount(amount)
|
16
|
+
@amount = amount
|
17
|
+
end
|
18
|
+
|
19
|
+
def setDescription(description)
|
20
|
+
@description = description
|
21
|
+
end
|
22
|
+
|
23
|
+
def getData
|
24
|
+
Paynl::Helper::requireApiToken
|
25
|
+
@@data['token'] = Paynl::Config::getApiToken
|
26
|
+
|
27
|
+
if (@transactionId.nil?)
|
28
|
+
raise('TransactionId not set, please use setTransactionId first.')
|
29
|
+
end
|
30
|
+
|
31
|
+
unless (@amount.nil?)
|
32
|
+
@@data['amount'] = @amount
|
33
|
+
end
|
34
|
+
|
35
|
+
@@data['transactionId'] = @transactionId
|
36
|
+
|
37
|
+
return super;
|
38
|
+
end
|
39
|
+
|
40
|
+
def doRequest
|
41
|
+
return super('transaction/refund', nil)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
module Paynl
|
2
|
+
module Api
|
3
|
+
class StartTransaction < Api
|
4
|
+
@amount = nil
|
5
|
+
@paymentOptionId = nil
|
6
|
+
@paymentOptionSubId = nil
|
7
|
+
@finishUrl = nil
|
8
|
+
@currency = nil
|
9
|
+
@exchangeUrl = nil
|
10
|
+
@description = nil
|
11
|
+
@enduser = Hash.new
|
12
|
+
@extra1 = nil
|
13
|
+
@extra2 = nil
|
14
|
+
@extra3 = nil
|
15
|
+
@testMode = false
|
16
|
+
@promotorId = nil
|
17
|
+
@info = nil
|
18
|
+
@tool = nil
|
19
|
+
@object = nil
|
20
|
+
@domainId = nil
|
21
|
+
@transferData = nil
|
22
|
+
@ipaddress = nil
|
23
|
+
@products = Hash.new
|
24
|
+
|
25
|
+
def setIpAddress(ipAddress)
|
26
|
+
@ipaddress = ipAddress;
|
27
|
+
end
|
28
|
+
def setPromotorId(promotorId)
|
29
|
+
@promotorId = promotorId
|
30
|
+
end
|
31
|
+
def setCurrency(currency)
|
32
|
+
@currency = currency
|
33
|
+
end
|
34
|
+
def setInfo(info)
|
35
|
+
@info = info
|
36
|
+
end
|
37
|
+
def setTool(tool)
|
38
|
+
@tool = tool;
|
39
|
+
end
|
40
|
+
def setObject(object)
|
41
|
+
@object = object
|
42
|
+
end
|
43
|
+
def setTransferData(transferData)
|
44
|
+
@transferData = transferData
|
45
|
+
end
|
46
|
+
|
47
|
+
def addProduct(id, description, price, quantity, vatPercentage)
|
48
|
+
unless price.is_a? Numeric
|
49
|
+
raise('Price has to be numerical')
|
50
|
+
end
|
51
|
+
|
52
|
+
unless quantity.is_a? Numeric
|
53
|
+
raise('Quantity has to be numerical')
|
54
|
+
end
|
55
|
+
|
56
|
+
if (@products.nil?)
|
57
|
+
@products = Hash.new
|
58
|
+
end
|
59
|
+
|
60
|
+
# copying code from PHP version... this has no use.
|
61
|
+
quantity = quantity * 1
|
62
|
+
|
63
|
+
# Description can only be 45 chars long
|
64
|
+
description = description[0,45];
|
65
|
+
|
66
|
+
product = Hash.new
|
67
|
+
product.store('productId', id)
|
68
|
+
product.store('description', description)
|
69
|
+
product.store('price', price)
|
70
|
+
product.store('quantity', quantity)
|
71
|
+
product.store('vatCode', vatPercentage)
|
72
|
+
|
73
|
+
@products.store(@products.length + 1,product);
|
74
|
+
end
|
75
|
+
|
76
|
+
def setEnduser(enduser)
|
77
|
+
unless enduser.is_a? Hash
|
78
|
+
raise('Please supply Hash with correct data')
|
79
|
+
end
|
80
|
+
@enduser = enduser
|
81
|
+
end
|
82
|
+
|
83
|
+
# Set amount (in cents) of the transaction
|
84
|
+
def setAmount(amount)
|
85
|
+
unless amount.is_a? Numeric
|
86
|
+
raise('The amount has to be numeric (and in cents)')
|
87
|
+
end
|
88
|
+
|
89
|
+
@amount = amount
|
90
|
+
end
|
91
|
+
|
92
|
+
def setPaymentOptionId(paymentOptionId)
|
93
|
+
unless paymentOptionId.is_a? Numeric
|
94
|
+
raise('The paymentOptionId has to be numeric')
|
95
|
+
end
|
96
|
+
|
97
|
+
@paymentOptionId = paymentOptionId;
|
98
|
+
end
|
99
|
+
|
100
|
+
def setPaymentOptionSubId(paymentOptionSubId)
|
101
|
+
unless paymentOptionSubId.is_a? Numeric
|
102
|
+
raise('The paymentOptionSubId has to be numberic')
|
103
|
+
end
|
104
|
+
|
105
|
+
@paymentOptionSubId = paymentOptionSubId
|
106
|
+
end
|
107
|
+
|
108
|
+
# Set the url where the user will be redirected to after payment.
|
109
|
+
def setFinishUrl(finishUrl)
|
110
|
+
@finishUrl = finishUrl
|
111
|
+
end
|
112
|
+
|
113
|
+
# Set the communication url, the pay.nl server will call this url when the status of the transaction changes
|
114
|
+
def setExchangeUrl(exchangeUrl)
|
115
|
+
@exchangeUrl = exchangeUrl
|
116
|
+
end
|
117
|
+
|
118
|
+
def setTestMode(testMode = false)
|
119
|
+
@testMode = testMode
|
120
|
+
end
|
121
|
+
|
122
|
+
def setExtra1(extra1)
|
123
|
+
@extra1 = extra1
|
124
|
+
end
|
125
|
+
def setExtra2(extra2)
|
126
|
+
@extra2 = extra2
|
127
|
+
end
|
128
|
+
def setExtra3(extra3)
|
129
|
+
@extra3 = extra3
|
130
|
+
end
|
131
|
+
|
132
|
+
def setDomainId(domainId)
|
133
|
+
@domainId = domainId
|
134
|
+
end
|
135
|
+
|
136
|
+
def setDescription(description)
|
137
|
+
@description = description
|
138
|
+
end
|
139
|
+
|
140
|
+
def getData()
|
141
|
+
Paynl::Helper::requireServiceId
|
142
|
+
@@data['serviceId'] = Paynl::Config::getServiceId
|
143
|
+
|
144
|
+
Paynl::Helper::requireApiToken
|
145
|
+
@@data['token'] = Paynl::Config::getApiToken
|
146
|
+
|
147
|
+
if @testMode.equal? true
|
148
|
+
@@data['testMode'] = 1
|
149
|
+
else
|
150
|
+
@@data['testMode'] = 0
|
151
|
+
end
|
152
|
+
|
153
|
+
if @amount.nil?
|
154
|
+
raise('Amount has to be set and in cents')
|
155
|
+
else
|
156
|
+
@@data['amount'] = @amount.round(0);
|
157
|
+
end
|
158
|
+
|
159
|
+
unless @paymentOptionId.nil?
|
160
|
+
@@data['paymentOptionsId'] = @paymentOptionId
|
161
|
+
end
|
162
|
+
|
163
|
+
if @finishUrl.nil?
|
164
|
+
raise('finishUrl is not set, which is required')
|
165
|
+
else
|
166
|
+
@@data['finishUrl'] = @finishUrl
|
167
|
+
end
|
168
|
+
|
169
|
+
# Crappy PHP associative array's are fcking my codestyle
|
170
|
+
unless @@data['transaction'].is_a? Hash
|
171
|
+
@@data['transaction'] = Hash.new
|
172
|
+
end
|
173
|
+
unless @@data['saleData'].is_a? Hash
|
174
|
+
@@data['saleData'] = Hash.new
|
175
|
+
end
|
176
|
+
unless @@data['statsData'].is_a? Hash
|
177
|
+
@@data['statsData'] = Hash.new
|
178
|
+
end
|
179
|
+
|
180
|
+
unless @exchangeUrl.nil?
|
181
|
+
@@data['transaction'].store('orderExchangeUrl',@exchangeUrl)
|
182
|
+
end
|
183
|
+
|
184
|
+
unless @description.nil?
|
185
|
+
@@data['transaction'].store('description', @description)
|
186
|
+
end
|
187
|
+
|
188
|
+
unless @currency.nil?
|
189
|
+
@@data['transaction'].store('currency', @currency)
|
190
|
+
end
|
191
|
+
|
192
|
+
if @ipaddress.nil?
|
193
|
+
#TODO: This is pure Ruby, no rails crap, so I can't abuse rails to get the IP
|
194
|
+
raise("IP addresses are required for payments")
|
195
|
+
else
|
196
|
+
@@data['ipAddress'] = @ipaddress
|
197
|
+
end
|
198
|
+
|
199
|
+
unless @products.nil?
|
200
|
+
@@data['saleData'].store('orderData',@products)
|
201
|
+
end
|
202
|
+
|
203
|
+
unless @enduser.nil?
|
204
|
+
@@data['enduser'] = @enduser
|
205
|
+
end
|
206
|
+
|
207
|
+
unless @extra1.nil?
|
208
|
+
@@data['statsData'].store('extra1',@extra1)
|
209
|
+
end
|
210
|
+
unless @extra2.nil?
|
211
|
+
@@data['statsData'].store('extra2',@extra2)
|
212
|
+
end
|
213
|
+
unless @extra3.nil?
|
214
|
+
@@data['statsData'].store('extra3',@extra3)
|
215
|
+
end
|
216
|
+
|
217
|
+
unless @promotorId.nil?
|
218
|
+
@@data['statsData'].store('promotorId',@promotorId)
|
219
|
+
end
|
220
|
+
unless @info.nil?
|
221
|
+
@@data['statsData'].store('info',@info)
|
222
|
+
end
|
223
|
+
unless @tool.nil?
|
224
|
+
@@data['statsData'].store('tool',@tool)
|
225
|
+
end
|
226
|
+
unless @object.nil?
|
227
|
+
@@data['statsData'].store('object',@object)
|
228
|
+
end
|
229
|
+
unless @domainId.nil?
|
230
|
+
@@data['statsData'].store('domainId',@domainId)
|
231
|
+
end
|
232
|
+
unless @transferData.nil?
|
233
|
+
@@data['statsData'].store('transferData',@transferData)
|
234
|
+
end
|
235
|
+
|
236
|
+
return super
|
237
|
+
end
|
238
|
+
|
239
|
+
def doRequest()
|
240
|
+
return super('transaction/start', 5)
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Paynl
|
2
|
+
module Api
|
3
|
+
class GetPayServerIps < Api
|
4
|
+
@@version = 1;
|
5
|
+
|
6
|
+
def doRequest ()
|
7
|
+
return super('validate/getPayServerIps',@@version)
|
8
|
+
end
|
9
|
+
|
10
|
+
def processResult(result)
|
11
|
+
# Nothing to do here
|
12
|
+
return result
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Paynl
|
2
|
+
module Api
|
3
|
+
class IsPayServerIp < Api
|
4
|
+
def getData
|
5
|
+
if @@data['ipAddress'].nil?
|
6
|
+
raise Paynl::Error::RequiredError('ipAddress is required')
|
7
|
+
end
|
8
|
+
|
9
|
+
return @@data
|
10
|
+
end
|
11
|
+
|
12
|
+
def setIpAddress(ipAddress)
|
13
|
+
@@data['ipAddress'] = ipAddress
|
14
|
+
end
|
15
|
+
|
16
|
+
def processResult(result)
|
17
|
+
return !result['result'].to_i.zero?
|
18
|
+
end
|
19
|
+
|
20
|
+
def doRequest()
|
21
|
+
return super('validate/isPayServerIp', 1)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/paynl/config.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Paynl
|
2
|
+
class Config
|
3
|
+
@@apiToken=''
|
4
|
+
@@serviceId=''
|
5
|
+
@@apiBase='https://rest-api.pay.nl'
|
6
|
+
@@apiVersion=5
|
7
|
+
|
8
|
+
# getApiToken - Retrieves Pay.nl api token
|
9
|
+
def self.getApiToken
|
10
|
+
return @@apiToken
|
11
|
+
end
|
12
|
+
|
13
|
+
# setApiToken - Sets Pay.nl api token
|
14
|
+
def self.setApiToken(apiToken)
|
15
|
+
@@apiToken = apiToken
|
16
|
+
end
|
17
|
+
|
18
|
+
# getServiceId - Retrieves Pay.nl Service Id
|
19
|
+
def self.getServiceId
|
20
|
+
return @@serviceId
|
21
|
+
end
|
22
|
+
|
23
|
+
# setServiceId - Set the Pay.nl Service Id
|
24
|
+
def self.setServiceId(serviceId)
|
25
|
+
@@serviceId = serviceId
|
26
|
+
end
|
27
|
+
|
28
|
+
# getApiVersion - Retrieves Pay.nl Api version
|
29
|
+
def self.getApiVersion
|
30
|
+
return @@apiVersion
|
31
|
+
end
|
32
|
+
|
33
|
+
# setApiVersion - Set the Pay.nl Api version
|
34
|
+
def self.setApiVersion(apiVersion)
|
35
|
+
@@apiVersion = apiVersion
|
36
|
+
end
|
37
|
+
|
38
|
+
# getApiUrl - Get constructed API Url for the given endpoint
|
39
|
+
def self.getApiUrl(endpoint, version = nil)
|
40
|
+
unless !version.nil?
|
41
|
+
version = @@apiVersion
|
42
|
+
end
|
43
|
+
|
44
|
+
return @@apiBase + '/v' + version.to_s + '/' + endpoint + '/json'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/paynl/helper.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
module Paynl
|
2
|
+
class Helper
|
3
|
+
def self.requireApiToken
|
4
|
+
apiToken = Paynl::Config::getApiToken
|
5
|
+
|
6
|
+
# Hmm, porting PHP to Ruby is crap if you want to keep the structure
|
7
|
+
if apiToken == nil? or apiToken == ''
|
8
|
+
raise Paynl::Error::Required::ApiTokenError, 'Api token is required'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.requireServiceId
|
13
|
+
serviceId = Paynl::Config::getServiceId
|
14
|
+
if serviceId == nil? or serviceId == ''
|
15
|
+
raise Paynl::Error::Required::ServiceIdError, 'No Service Id is set'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.nearest(number, numbers)
|
20
|
+
if (numbers.is_a? Hash)
|
21
|
+
# numbers is a, I suppose, hash, not an array, for this piece of magick I need an array
|
22
|
+
numbers = numbers.to_a
|
23
|
+
end
|
24
|
+
# And this is the reason why Ruby is more interesting than PHP, we can do this in 1 line of code
|
25
|
+
return numbers.min_by{ |x| (x.first.to_f - number).abs }
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.calculateTaxClass(amountInclTax, taxAmount)
|
29
|
+
# Setup basic taxClasses (like in the PHP SDK)
|
30
|
+
taxClasses = Hash.new
|
31
|
+
taxClasses.store(0, 'N')
|
32
|
+
taxClasses.store(6, 'L')
|
33
|
+
taxClasses.store(21, 'H')
|
34
|
+
|
35
|
+
if (taxAmount == 0 || amountInclTax == 0)
|
36
|
+
return taxClasses[0]
|
37
|
+
end
|
38
|
+
|
39
|
+
amountExclTax = amountInclTax - taxAmount
|
40
|
+
taxRate = (taxAmount / amountExclTax) * 100
|
41
|
+
nearestTaxRate = self.nearest(taxRate, taxClasses)
|
42
|
+
return nearestTaxRate
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.transactionIsPaid(transaction)
|
46
|
+
unless transaction.is_a? Hash
|
47
|
+
raise("Please give me the output of the Paynl::Transaction::getTransaction function")
|
48
|
+
end
|
49
|
+
|
50
|
+
if result['paymentDetails']['stateName'] == 'PAID'
|
51
|
+
return true
|
52
|
+
end
|
53
|
+
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.transactionIsPending(transaction)
|
58
|
+
unless transaction.is_a? Hash
|
59
|
+
raise("Please give me the output of the Paynl::Transaction::getTransaction function")
|
60
|
+
end
|
61
|
+
|
62
|
+
if result['paymentDetails']['stateName'] == 'PENDING'
|
63
|
+
return true
|
64
|
+
end
|
65
|
+
|
66
|
+
return false
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Paynl
|
2
|
+
class Paymentmethods
|
3
|
+
|
4
|
+
def filterCountry(paymentMethods, country)
|
5
|
+
output = Hash.new
|
6
|
+
paymentMethods.each do |key, paymentMethod|
|
7
|
+
paymentMethod['countries'].each_with_index do |countryFromList, index|
|
8
|
+
if countryFromList[1]['id'] == country or countryFromList[1]['id'] == 'ALL'
|
9
|
+
output.store(output.length + 1, paymentMethod)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
return output
|
14
|
+
end
|
15
|
+
|
16
|
+
def reorderOutput(input)
|
17
|
+
paymentMethods = Hash.new
|
18
|
+
input['countryOptionList'].each do |key, country|
|
19
|
+
country['paymentOptionList'].each_with_index do |paymentOption, index|
|
20
|
+
|
21
|
+
if !paymentMethods[paymentOption[1]['id']].nil?
|
22
|
+
|
23
|
+
paymentMethods[paymentOption[1]['id']]['countries'].store(
|
24
|
+
paymentMethods[paymentOption[1]['id']]['countries'].length + 1, country['id'])
|
25
|
+
else
|
26
|
+
banks = Hash.new
|
27
|
+
unless paymentOption[1]['paymentOptionSubList'] != nil?
|
28
|
+
paymentOption[1]['paymentOptionSubList'].each do |optionSub, index|
|
29
|
+
bank = Hash.new
|
30
|
+
bank['id'] = optionSub['id']
|
31
|
+
bank['name'] = optionSub['name']
|
32
|
+
bank['visibleName'] = optionSub['visibleName']
|
33
|
+
banks[banks.length + 1] = bank
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
paymentMethod = Hash.new
|
38
|
+
paymentMethod['id'] = paymentOption[1]['id']
|
39
|
+
paymentMethod['name'] = paymentOption[1]['name']
|
40
|
+
paymentMethod['visibleName'] = paymentOption[1]['visibleName']
|
41
|
+
countryList = Hash.new
|
42
|
+
countryList.store(1,country)
|
43
|
+
paymentMethod['countries'] = countryList
|
44
|
+
paymentMethod['banks'] = banks
|
45
|
+
paymentMethods.store(paymentOption[1]['id'],paymentMethod)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
return paymentMethods
|
51
|
+
end
|
52
|
+
|
53
|
+
def getList(options)
|
54
|
+
api = Paynl::Api::GetService.new
|
55
|
+
result = api.doRequest()
|
56
|
+
|
57
|
+
paymentMethods = self.reorderOutput(result)
|
58
|
+
|
59
|
+
# TODO: this is not the best way to do this...
|
60
|
+
if options.class.to_s == 'Hash'
|
61
|
+
if !options['country'].nil?
|
62
|
+
paymentMethods = self.filterCountry(paymentMethods, options['country'])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
return paymentMethods
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
module Paynl
|
2
|
+
class Transaction
|
3
|
+
def start(options)
|
4
|
+
enduser = Hash.new
|
5
|
+
|
6
|
+
api = Paynl::Api::StartTransaction.new
|
7
|
+
unless (options['amount'].nil?)
|
8
|
+
api.setAmount(options['amount'].round(2) * 100)
|
9
|
+
end
|
10
|
+
|
11
|
+
unless (options['currency'].nil?)
|
12
|
+
api.setCurrency(options['currency'])
|
13
|
+
end
|
14
|
+
|
15
|
+
unless (options['returnUrl'].nil?)
|
16
|
+
api.setFinishUrl(options['returnUrl'])
|
17
|
+
end
|
18
|
+
|
19
|
+
unless (options['exchangeUrl'].nil?)
|
20
|
+
api.setExchangeUrl(options['exchangeUrl'])
|
21
|
+
end
|
22
|
+
|
23
|
+
unless (options['paymentMethod'].nil?)
|
24
|
+
api.setPaymentOptionId(options['paymentMethod'])
|
25
|
+
end
|
26
|
+
|
27
|
+
unless (options['bank'].nil?)
|
28
|
+
api.setPaymentOptionSubId(options['bank'])
|
29
|
+
end
|
30
|
+
|
31
|
+
unless (options['description'].nil?)
|
32
|
+
api.setDescription(options['description'])
|
33
|
+
end
|
34
|
+
|
35
|
+
unless (options['testMode'].nil?)
|
36
|
+
if options['testMode'] == true or options['testMode'] == 'true'
|
37
|
+
api.setTestMode(true)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
unless (options['ipaddress'].nil?)
|
42
|
+
api.setIpAddress(options['ipaddress'])
|
43
|
+
end
|
44
|
+
|
45
|
+
unless (options['extra1']).nil?
|
46
|
+
api.setExtra1(options['extra1'])
|
47
|
+
end
|
48
|
+
|
49
|
+
unless (options['extra2'].nil?)
|
50
|
+
api.setExtra2(options['extra2'])
|
51
|
+
end
|
52
|
+
|
53
|
+
unless (options['extra3'].nil?)
|
54
|
+
api.setExtra3(options['extra3'])
|
55
|
+
end
|
56
|
+
|
57
|
+
unless (options['products'].nil?)
|
58
|
+
options['products'].each_with_index {
|
59
|
+
|product, index|
|
60
|
+
taxClass = Paynl::Helper::calculateTaxClass(product[1]['price'], product[1]['tax'])
|
61
|
+
api.addProduct(product[1]['id'], product[1]['name'], (product[1]['price'].round * 100), product[1]['qty'], taxClass)
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
unless (options['enduser'].nil?)
|
66
|
+
enduser = options['enduser'].to_hash
|
67
|
+
end
|
68
|
+
|
69
|
+
unless (options['language'].nil?)
|
70
|
+
enduser['language'] = options['language']
|
71
|
+
end
|
72
|
+
|
73
|
+
unless (options['address'].nil?)
|
74
|
+
address = Hash.new
|
75
|
+
unless (options['address']['streetName'].nil?)
|
76
|
+
address.store('streetName', options['address']['streetName'])
|
77
|
+
end
|
78
|
+
unless (options['address']['houseNumber'].nil?)
|
79
|
+
address.store('houseNumber', options['address']['houseNumber'])
|
80
|
+
end
|
81
|
+
unless (options['address']['zipCode'].nil?)
|
82
|
+
address.store('zipCode', options['address']['zipCode'])
|
83
|
+
end
|
84
|
+
unless (options['address']['city'].nil?)
|
85
|
+
address.store('city', options['address']['city'])
|
86
|
+
end
|
87
|
+
unless (options['address']['country'].nil?)
|
88
|
+
address.store('country', options['address']['country'])
|
89
|
+
end
|
90
|
+
enduser.store('address', address)
|
91
|
+
end
|
92
|
+
|
93
|
+
unless (options['invoiceAddress'].nil?)
|
94
|
+
invoiceAddress = Hash.new
|
95
|
+
|
96
|
+
unless (options['invoiceAddress']['initials'].nil?)
|
97
|
+
invoiceAddress.store('initials', options['invoiceAddress']['initials'])
|
98
|
+
end
|
99
|
+
unless (options['invoiceAddress']['lastName'].nil?)
|
100
|
+
invoiceAddress.store('lastName', options['invoiceAddress']['lastName'])
|
101
|
+
end
|
102
|
+
|
103
|
+
unless (options['invoiceAddress']['streetName'].nil?)
|
104
|
+
invoiceAddress.store('streetName', options['invoiceAddress']['streetName'])
|
105
|
+
end
|
106
|
+
unless (options['invoiceAddress']['houseNumber'].nil?)
|
107
|
+
invoiceAddress.store('houseNumber', options['invoiceAddress']['houseNumber'])
|
108
|
+
end
|
109
|
+
unless (options['invoiceAddress']['zipCode'].nil?)
|
110
|
+
invoiceAddress.store('zipCode', options['invoiceAddress']['zipCode'])
|
111
|
+
end
|
112
|
+
unless (options['invoiceAddress']['city'].nil?)
|
113
|
+
invoiceAddress.store('city', options['invoiceAddress']['city'])
|
114
|
+
end
|
115
|
+
unless (options['invoiceAddress']['country'].nil?)
|
116
|
+
invoiceAddress.store('country', options['invoiceAddress']['country'])
|
117
|
+
end
|
118
|
+
enduser.store('invoiceAddress', invoiceAddress)
|
119
|
+
end
|
120
|
+
|
121
|
+
api.setEnduser(enduser)
|
122
|
+
return api.doRequest
|
123
|
+
end
|
124
|
+
|
125
|
+
def getTransaction(transactionId)
|
126
|
+
api = Paynl::Api::TransactionInfo.new
|
127
|
+
api.setTransactionId(transactionId)
|
128
|
+
return api.doRequest
|
129
|
+
end
|
130
|
+
|
131
|
+
def refund(transactionId, amount = nil, description = nil)
|
132
|
+
api = Paynl::Api::TransactionRefund.new
|
133
|
+
api.setTransactionId(transactionId)
|
134
|
+
unless amount.nil?
|
135
|
+
api.setAmount(amount)
|
136
|
+
end
|
137
|
+
unless description.nil?
|
138
|
+
api.setDescription(description)
|
139
|
+
end
|
140
|
+
return api.doRequest
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
data/lib/paynl.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'typhoeus'
|
3
|
+
require 'json'
|
4
|
+
require 'paynl/api/api'
|
5
|
+
require 'paynl/error/required/serviceiderror'
|
6
|
+
require 'paynl/error/required/apitokenerror'
|
7
|
+
require 'paynl/error/requirederror'
|
8
|
+
require 'paynl/helper'
|
9
|
+
require 'paynl/version'
|
10
|
+
require 'paynl/api/validate/is_pay_server_ip'
|
11
|
+
require 'paynl/api/validate/get_pay_server_ips'
|
12
|
+
require 'paynl/api/transaction/get_service'
|
13
|
+
require 'paynl/api/transaction/start_transaction'
|
14
|
+
require 'paynl/api/transaction/info'
|
15
|
+
require 'paynl/api/transaction/refund'
|
16
|
+
require 'paynl/api/api'
|
17
|
+
require 'paynl/config'
|
18
|
+
require 'paynl/transaction'
|
19
|
+
require 'paynl/paymentmethods'
|
20
|
+
require 'paynl'
|
21
|
+
|
data/paynl.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 'paynl/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "paynl"
|
8
|
+
spec.version = Paynl::VERSION
|
9
|
+
spec.authors = ["Sebastian Berm"]
|
10
|
+
spec.email = ["sebastian@sebsoft.nl"]
|
11
|
+
|
12
|
+
spec.summary = %q{Simple interface to create transactions for the Pay.nl PSP}
|
13
|
+
spec.description = %q{Simple SDK interface to create transactions for the Pay.nl payment service provider.}
|
14
|
+
spec.homepage = "https://github.com/paynl/sdk-ruby"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
|
+
# delete this section to allow pushing this gem to any host.
|
19
|
+
# if spec.respond_to?(:metadata)
|
20
|
+
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
|
21
|
+
# else
|
22
|
+
# raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
23
|
+
# end
|
24
|
+
|
25
|
+
# Had to comment the next line to get this working correctly on Windows 10 in RubyMine
|
26
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
27
|
+
spec.bindir = "exe"
|
28
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
31
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
33
|
+
# spec.add_development_dependency "spec"
|
34
|
+
# spec.add_development_dependency "spectask"
|
35
|
+
|
36
|
+
spec.add_runtime_dependency "typhoeus"
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: paynl
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sebastian Berm
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: typhoeus
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Simple SDK interface to create transactions for the Pay.nl payment service
|
70
|
+
provider.
|
71
|
+
email:
|
72
|
+
- sebastian@sebsoft.nl
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- ".gitignore"
|
78
|
+
- ".rspec"
|
79
|
+
- ".travis.yml"
|
80
|
+
- Gemfile
|
81
|
+
- LICENSE.txt
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- bin/console
|
85
|
+
- bin/setup
|
86
|
+
- lib/paynl.rb
|
87
|
+
- lib/paynl/api/api.rb
|
88
|
+
- lib/paynl/api/transaction/get_service.rb
|
89
|
+
- lib/paynl/api/transaction/info.rb
|
90
|
+
- lib/paynl/api/transaction/refund.rb
|
91
|
+
- lib/paynl/api/transaction/start_transaction.rb
|
92
|
+
- lib/paynl/api/validate/get_pay_server_ips.rb
|
93
|
+
- lib/paynl/api/validate/is_pay_server_ip.rb
|
94
|
+
- lib/paynl/config.rb
|
95
|
+
- lib/paynl/error/required/apitokenerror.rb
|
96
|
+
- lib/paynl/error/required/serviceiderror.rb
|
97
|
+
- lib/paynl/error/requirederror.rb
|
98
|
+
- lib/paynl/helper.rb
|
99
|
+
- lib/paynl/paymentmethods.rb
|
100
|
+
- lib/paynl/transaction.rb
|
101
|
+
- lib/paynl/version.rb
|
102
|
+
- paynl.gemspec
|
103
|
+
homepage: https://github.com/paynl/sdk-ruby
|
104
|
+
licenses:
|
105
|
+
- MIT
|
106
|
+
metadata: {}
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
requirements:
|
118
|
+
- - ">="
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
requirements: []
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 2.4.6
|
124
|
+
signing_key:
|
125
|
+
specification_version: 4
|
126
|
+
summary: Simple interface to create transactions for the Pay.nl PSP
|
127
|
+
test_files: []
|