paysafe 0.6.2 → 0.9.0
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 +4 -4
- data/.env.sample +5 -0
- data/.travis.yml +4 -4
- data/CHANGELOG.md +28 -0
- data/README.md +64 -26
- data/bin/setup +8 -7
- data/lib/paysafe/address.rb +9 -0
- data/lib/paysafe/authorization.rb +14 -0
- data/lib/paysafe/birth_date.rb +7 -0
- data/lib/paysafe/card.rb +13 -0
- data/lib/paysafe/card_expiry.rb +7 -0
- data/lib/paysafe/error.rb +6 -7
- data/lib/paysafe/profile.rb +13 -0
- data/lib/paysafe/refinements/camel_case.rb +40 -0
- data/lib/paysafe/refinements/snake_case.rb +45 -0
- data/lib/paysafe/rest/client.rb +89 -120
- data/lib/paysafe/result.rb +86 -0
- data/lib/paysafe/single_use_token.rb +10 -0
- data/lib/paysafe/verification.rb +13 -0
- data/lib/paysafe/version.rb +1 -1
- data/lib/paysafe.rb +10 -0
- data/paysafe.gemspec +6 -4
- metadata +32 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6bbfa2b88d67e16221b48a7fdc9e2048f3e83e2
|
4
|
+
data.tar.gz: f4e8670f77a2ca5a406b5a52794a446f87f2dabe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd143b165e5467ae27d084c9011ce710d80dd40eff19fbd2896a4514b6a3d1dff4ccefea27ee533aa05b2c37825970a3644bd7cd14111ec313ba4192fdd725f6
|
7
|
+
data.tar.gz: f577618983eaa4dc510f5fa4def95780be2c85c8ec791d35ea8c300018acbc56780f3f58a7fbf6e5c0558e9ce6d8114cc5fc89c7c8b96d34b69ce77b2205eeb0
|
data/.env.sample
CHANGED
@@ -1,3 +1,8 @@
|
|
1
1
|
PAYSAFE_ACCOUNT_NUMBER="YOUR_ACCOUNT_NUMBER"
|
2
2
|
PAYSAFE_API_KEY="YOUR_API_KEY"
|
3
3
|
PAYSAFE_API_SECRET="YOUR_API_SECRET"
|
4
|
+
|
5
|
+
# This is only needed if you want to generate your own Single
|
6
|
+
# Use Tokens which utilize a different API key and secret.
|
7
|
+
PAYSAFE_SUT_API_KEY="YOUR_SINGLE_USE_TOKEN_API_KEY"
|
8
|
+
PAYSAFE_SUT_API_SECRET="YOUR_SINGLE_USE_TOKEN_API_SECRET"
|
data/.travis.yml
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.
|
4
|
-
- 2.
|
5
|
-
before_install: gem install bundler
|
3
|
+
- 2.3.4
|
4
|
+
- 2.4.1
|
5
|
+
before_install: gem install bundler
|
6
6
|
cache: bundler
|
7
7
|
sudo: false
|
8
8
|
fast_finish: true
|
9
9
|
env:
|
10
|
-
-
|
10
|
+
- SKIP_INTEGRATION=true
|
11
11
|
notifications:
|
12
12
|
email:
|
13
13
|
on_success: always
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Changelog
|
2
|
+
=========
|
3
|
+
|
4
|
+
## 0.9.0 (2017-04-19)
|
5
|
+
|
6
|
+
This is a major update with breaking changes so moving the version up quite a bit since I'd also like to move to a 1.0 release soon after.
|
7
|
+
|
8
|
+
* Requires Ruby 2.3 and up.
|
9
|
+
* All API methods now accept params in snake_case and are converted to camelCase.
|
10
|
+
* Responses are now typed with classes using snake_case properties (converted from camelCase) handling nested complex objects and lazily loaded. No more hashes.
|
11
|
+
* Field names match Paysafe API docs except when making requests and working with responses, its all in snake_case.
|
12
|
+
* Renamed config `timeout_options` renamed to `timeouts`.
|
13
|
+
* Removed default value for `timeouts` config.
|
14
|
+
* Added new methods to work with single use tokens:
|
15
|
+
* `create_single_use_token` (requires different API key and secret)
|
16
|
+
* `create_verification_from_token`
|
17
|
+
* `create_profile_from_token`
|
18
|
+
* `create_card_from_token`
|
19
|
+
* Updated `bin/setup` script.
|
20
|
+
* Updated API base domain to paysafe.com.
|
21
|
+
|
22
|
+
## 0.6.2 (2016-04-25)
|
23
|
+
|
24
|
+
* Upgrade http gem to v2.0
|
25
|
+
|
26
|
+
## 0.6.1 (2016-03-02)
|
27
|
+
|
28
|
+
* Add `update_profile` method to client
|
data/README.md
CHANGED
@@ -3,54 +3,88 @@
|
|
3
3
|
[][gem]
|
4
4
|
[][travis]
|
5
5
|
|
6
|
-
[
|
7
|
-
[travis]: https://travis-ci.org/javierjulio/paysafe
|
8
|
-
|
9
|
-
A tested Ruby interface to the Paysafe REST API (formerly Optimal Payments). Note: requires Ruby 2.1 and up. Not all API actions are supported yet.
|
6
|
+
A well tested Ruby interface to the [Paysafe REST API](paysafe_api_reference) (formerly Optimal Payments). Requires Ruby 2.3 and up. Not all API actions are supported yet. Since the Paysafe API uses camelCase, this gem will handle converting to and from snake_case for you.
|
10
7
|
|
11
8
|
## Installation
|
12
9
|
|
13
|
-
Add
|
10
|
+
Add the following to your application's Gemfile:
|
14
11
|
|
15
12
|
```ruby
|
16
13
|
gem 'paysafe'
|
17
14
|
```
|
18
15
|
|
19
|
-
|
16
|
+
Or install directly with `gem install paysafe`.
|
20
17
|
|
21
|
-
|
18
|
+
To try out the gem, just follow the Development section instructions as the built in setup script will direct you on how to provide the necessary API info.
|
22
19
|
|
23
|
-
|
20
|
+
## Usage
|
24
21
|
|
25
|
-
|
22
|
+
### Client Configuration
|
26
23
|
|
27
|
-
|
24
|
+
Create and configure a client with your API authentication.
|
28
25
|
|
29
|
-
|
26
|
+
```ruby
|
27
|
+
client = Paysafe::REST::Client.new do |config|
|
28
|
+
config.account_number = '1234567890'
|
29
|
+
config.api_key = 'api_key'
|
30
|
+
config.api_secret = 'api_secret'
|
31
|
+
# Enable production requests
|
32
|
+
# config.test_mode = false
|
33
|
+
# Provide explicit timeouts
|
34
|
+
# config.timeouts = { connect: 2, read: 5, write: 10 }
|
35
|
+
end
|
36
|
+
```
|
30
37
|
|
31
|
-
|
38
|
+
### Making Requests
|
32
39
|
|
33
|
-
|
40
|
+
Make an API request with a payload in the structure documented by the [Paysafe REST API](paysafe_api_reference) but using snake_case. The request payload will be converted to camelCase for you.
|
34
41
|
|
35
|
-
|
36
|
-
|
42
|
+
```ruby
|
43
|
+
profile = client.create_profile(
|
44
|
+
merchant_customer_id: '123',
|
45
|
+
locale: 'en_US',
|
46
|
+
card: {
|
47
|
+
card_num: '4111111111111111',
|
48
|
+
card_expiry: {
|
49
|
+
month: 12,
|
50
|
+
year: 2020
|
51
|
+
}
|
52
|
+
}
|
53
|
+
)
|
54
|
+
```
|
37
55
|
|
38
|
-
|
39
|
-
gem update
|
40
|
-
gem install bundler --no-rdoc --no-ri
|
56
|
+
### Handling Responses
|
41
57
|
|
42
|
-
|
43
|
-
4. Run `./bin/console` for an interactive prompt with an authenticated client for you to experiment:
|
58
|
+
Response data is in snake_case (converted from camelCase) typed with individual methods and predicates, including nested complex objects and array of objects as shown below:
|
44
59
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
60
|
+
```ruby
|
61
|
+
profile.id?
|
62
|
+
# => true
|
63
|
+
profile.id
|
64
|
+
# => b088ac37...
|
65
|
+
profile.cards.first.card_expiry.year
|
66
|
+
# => 2020
|
67
|
+
```
|
68
|
+
|
69
|
+
Further API methods are provided in the `Paysafe::REST::Client` object.
|
70
|
+
|
71
|
+
## Development
|
72
|
+
|
73
|
+
1. `git clone https://github.com/javierjulio/paysafe.git`
|
74
|
+
2. Run `./bin/setup` to install dependencies and fill out API key info
|
75
|
+
3. Run `./bin/console` for an interactive prompt with an authenticated client for you to experiment:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
profile = client.create_profile(merchant_customer_id: '123', locale: 'en_US')
|
79
|
+
puts profile.id
|
80
|
+
# => b088ac37...
|
81
|
+
```
|
82
|
+
|
83
|
+
All code is written in snake_case since requests and responses are converted to and from camelCase for you.
|
50
84
|
|
51
85
|
### Tests
|
52
86
|
|
53
|
-
Run `bundle exec rake test` or to skip integration tests run with `
|
87
|
+
Run `bundle exec rake test` or to skip integration tests run with `SKIP_INTEGRATION=true`.
|
54
88
|
|
55
89
|
### Releasing
|
56
90
|
|
@@ -63,3 +97,7 @@ Bug reports and pull requests for missing API support are welcome on GitHub at h
|
|
63
97
|
## License
|
64
98
|
|
65
99
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
100
|
+
|
101
|
+
[gem]: https://rubygems.org/gems/paysafe
|
102
|
+
[travis]: https://travis-ci.org/javierjulio/paysafe
|
103
|
+
[paysafe_api_reference]: https://developer.paysafe.com/en/api-reference/
|
data/bin/setup
CHANGED
@@ -4,15 +4,16 @@ IFS=$'\n\t'
|
|
4
4
|
|
5
5
|
bundle install
|
6
6
|
|
7
|
-
read -r -p 'Do you have an
|
7
|
+
read -r -p 'Do you have an Paysafe Developer account? (y/n) ' has_account
|
8
8
|
|
9
9
|
if [[ "$has_account" =~ ^(Yes|yes|Y|y)$ ]]; then
|
10
10
|
echo "Great! You can get your account credentials from:"
|
11
|
-
echo " https://
|
11
|
+
echo " https://login.test.netbanx.com/office/public/preLogin.htm"
|
12
12
|
echo
|
13
13
|
else
|
14
|
-
echo "Then you'll need to create an account first
|
15
|
-
echo "
|
14
|
+
echo "Then you'll need to create an account first."
|
15
|
+
echo "Click the 'Sign Up' button on the following page:"
|
16
|
+
echo " https://developer.paysafe.com/"
|
16
17
|
echo
|
17
18
|
read -s -p "Press Enter key if you're ready to continue..."
|
18
19
|
echo
|
@@ -24,8 +25,8 @@ read -p 'API Key: ' api_key
|
|
24
25
|
read -p 'API Secret: ' api_secret
|
25
26
|
|
26
27
|
cp .env.sample .env
|
27
|
-
sed -i -e s/YOUR_ACCOUNT_NUMBER
|
28
|
-
sed -i -e s/YOUR_API_KEY
|
29
|
-
sed -i -e s/YOUR_API_SECRET
|
28
|
+
sed -i '' -e "s/YOUR_ACCOUNT_NUMBER/$account_number/g" .env
|
29
|
+
sed -i '' -e "s/YOUR_API_KEY/$api_key/g" .env
|
30
|
+
sed -i '' -e "s/YOUR_API_SECRET/$api_secret/g" .env
|
30
31
|
|
31
32
|
echo "Done."
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'paysafe/result'
|
2
|
+
|
3
|
+
module Paysafe
|
4
|
+
class Authorization < Result
|
5
|
+
attributes :id, :merchant_ref_num, :amount, :settle_with_auth,
|
6
|
+
:pre_auth, :available_to_settle, :child_account_num, :auth_code,
|
7
|
+
:recurring, :customer_ip, :dup_check, :description, :txn_time,
|
8
|
+
:currency_code, :avs_response, :cvv_verification, :status, :keywords
|
9
|
+
|
10
|
+
object_attribute :Card, :card
|
11
|
+
object_attribute :Profile, :profile
|
12
|
+
object_attribute :Address, :billing_details
|
13
|
+
end
|
14
|
+
end
|
data/lib/paysafe/card.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'paysafe/result'
|
2
|
+
|
3
|
+
module Paysafe
|
4
|
+
class Card < Result
|
5
|
+
attributes :id, :nick_name, :merchant_ref_num, :holder_name,
|
6
|
+
:card_num, :card_bin, :last_digits, :card_type, :billing_address_id,
|
7
|
+
:default_card_indicator, :payment_token, :single_use_token, :status,
|
8
|
+
:cvv, :track1, :track2, :type
|
9
|
+
|
10
|
+
object_attribute :CardExpiry, :card_expiry
|
11
|
+
object_attribute :Address, :billing_address
|
12
|
+
end
|
13
|
+
end
|
data/lib/paysafe/error.rb
CHANGED
@@ -81,22 +81,21 @@ module Paysafe
|
|
81
81
|
# @param body [String]
|
82
82
|
# @param code [Integer]
|
83
83
|
# @return [Paysafe::Error]
|
84
|
-
def
|
84
|
+
def from_response(body, code)
|
85
85
|
klass = ERRORS[code] || Paysafe::Error
|
86
86
|
message, error_code = parse_error(body)
|
87
87
|
klass.new(message: message, code: error_code, response: body)
|
88
88
|
end
|
89
89
|
|
90
|
-
|
90
|
+
private
|
91
91
|
|
92
92
|
def parse_error(body)
|
93
|
-
if body.
|
94
|
-
[
|
95
|
-
|
96
|
-
[
|
93
|
+
if body.is_a?(Hash)
|
94
|
+
[ body.dig(:error, :message), body.dig(:error, :code) ]
|
95
|
+
else
|
96
|
+
[ '', nil ]
|
97
97
|
end
|
98
98
|
end
|
99
|
-
|
100
99
|
end
|
101
100
|
|
102
101
|
# Initializes a new Error object
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'paysafe/result'
|
2
|
+
|
3
|
+
module Paysafe
|
4
|
+
class Profile < Result
|
5
|
+
attributes :id, :status, :merchant_customer_id, :locale,
|
6
|
+
:ip, :first_name, :middle_name, :last_name, :gender,
|
7
|
+
:nationality, :email, :phone, :cell_phone, :payment_token
|
8
|
+
|
9
|
+
object_attribute :BirthDate, :date_of_birth
|
10
|
+
object_attribute :Card, :cards
|
11
|
+
object_attribute :Address, :addresses
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Paysafe
|
2
|
+
module Refinements
|
3
|
+
module CamelCase
|
4
|
+
refine Hash do
|
5
|
+
|
6
|
+
def to_camel_case(data = self)
|
7
|
+
case data
|
8
|
+
when Array
|
9
|
+
data.map { |value| to_camel_case(value) }
|
10
|
+
when Hash
|
11
|
+
data.map { |key, value| [camel_case_key(key), to_camel_case(value)] }.to_h
|
12
|
+
else
|
13
|
+
data
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def camel_case_key(key)
|
20
|
+
case key
|
21
|
+
when Symbol
|
22
|
+
camel_case(key.to_s).to_sym
|
23
|
+
when String
|
24
|
+
camel_case(key).to_sym
|
25
|
+
else
|
26
|
+
key
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def camel_case(string)
|
31
|
+
@__memoize_camelcase ||= {}
|
32
|
+
return @__memoize_camelcase[string] if @__memoize_camelcase[string]
|
33
|
+
@__memoize_camelcase[string] = string.gsub(/(?:_+)([a-z])/) { $1.upcase }
|
34
|
+
@__memoize_camelcase[string]
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Paysafe
|
2
|
+
module Refinements
|
3
|
+
module SnakeCase
|
4
|
+
refine Hash do
|
5
|
+
|
6
|
+
def to_snake_case(data = self)
|
7
|
+
case data
|
8
|
+
when Array
|
9
|
+
data.map { |value| to_snake_case(value) }
|
10
|
+
when Hash
|
11
|
+
data.map { |key, value| [underscore_key(key), to_snake_case(value)] }.to_h
|
12
|
+
else
|
13
|
+
data
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def underscore_key(key)
|
20
|
+
case key
|
21
|
+
when Symbol
|
22
|
+
underscore(key.to_s).to_sym
|
23
|
+
when String
|
24
|
+
underscore(key).to_sym
|
25
|
+
else
|
26
|
+
key
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def underscore(string)
|
31
|
+
@__memoize_underscore ||= {}
|
32
|
+
return @__memoize_underscore[string] if @__memoize_underscore[string]
|
33
|
+
@__memoize_underscore[string] =
|
34
|
+
string.gsub(/::/, '/')
|
35
|
+
.gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
36
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
37
|
+
.tr('-', '_')
|
38
|
+
.downcase
|
39
|
+
@__memoize_underscore[string]
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/paysafe/rest/client.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'http'
|
2
|
+
require 'json'
|
2
3
|
|
3
4
|
module Paysafe
|
4
5
|
module REST
|
5
6
|
class Client
|
6
7
|
|
7
|
-
API_TEST = 'https://api.test.
|
8
|
-
API_LIVE = 'https://api.
|
8
|
+
API_TEST = 'https://api.test.paysafe.com'
|
9
|
+
API_LIVE = 'https://api.paysafe.com'
|
9
10
|
|
10
11
|
HEADERS = {
|
11
12
|
'Content-Type' => 'application/json',
|
@@ -14,7 +15,10 @@ module Paysafe
|
|
14
15
|
'X-Ruby-Platform' => RUBY_PLATFORM
|
15
16
|
}
|
16
17
|
|
17
|
-
|
18
|
+
using Refinements::CamelCase
|
19
|
+
using Refinements::SnakeCase
|
20
|
+
|
21
|
+
attr_accessor :account_number, :api_key, :api_secret, :test_mode, :timeouts
|
18
22
|
attr_reader :api_base
|
19
23
|
|
20
24
|
# Initializes a new Client object
|
@@ -23,7 +27,6 @@ module Paysafe
|
|
23
27
|
# @return [Paysafe::REST::Client]
|
24
28
|
def initialize(options={})
|
25
29
|
@test_mode = true
|
26
|
-
@timeout_options = { write: 2, connect: 5, read: 10 }
|
27
30
|
|
28
31
|
options.each do |key, value|
|
29
32
|
instance_variable_set("@#{key}", value)
|
@@ -36,11 +39,7 @@ module Paysafe
|
|
36
39
|
|
37
40
|
# @return [Hash]
|
38
41
|
def credentials
|
39
|
-
{
|
40
|
-
account_number: account_number,
|
41
|
-
api_key: api_key,
|
42
|
-
api_secret: api_secret
|
43
|
-
}
|
42
|
+
{ api_key: api_key, api_secret: api_secret }
|
44
43
|
end
|
45
44
|
|
46
45
|
# @return [Boolean]
|
@@ -48,157 +47,132 @@ module Paysafe
|
|
48
47
|
credentials.values.all?
|
49
48
|
end
|
50
49
|
|
51
|
-
def
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
50
|
+
def create_single_use_token(data)
|
51
|
+
response = post(path: "/customervault/v1/singleusetokens", data: data.to_camel_case)
|
52
|
+
process_response(response, SingleUseToken)
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_profile_from_token(data)
|
56
|
+
response = post(path: "/customervault/v1/profiles", data: data.to_camel_case)
|
57
|
+
process_response(response, Profile)
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_profile(merchant_customer_id:, locale:, **args)
|
61
|
+
data = args.merge({
|
62
|
+
merchant_customer_id: merchant_customer_id,
|
63
|
+
locale: locale
|
64
|
+
}).to_camel_case
|
60
65
|
|
61
66
|
response = post(path: "/customervault/v1/profiles", data: data)
|
62
|
-
|
63
|
-
fail_or_return_response_body(response.code, response_body)
|
67
|
+
process_response(response, Profile)
|
64
68
|
end
|
65
69
|
|
66
70
|
def delete_profile(id:)
|
67
71
|
response = delete(path: "/customervault/v1/profiles/#{id}")
|
68
|
-
|
72
|
+
process_response(response)
|
69
73
|
end
|
70
74
|
|
71
75
|
def get_profile(id:, fields: [])
|
72
|
-
fields.keep_if { |field| field == :cards || field == :addresses }
|
73
|
-
|
74
76
|
path = "/customervault/v1/profiles/#{id}"
|
75
|
-
|
76
|
-
if !fields.empty?
|
77
|
-
path += "?fields=#{fields.join(',')}"
|
78
|
-
end
|
77
|
+
path += "?fields=#{fields.join(',')}" if !fields.empty?
|
79
78
|
|
80
79
|
response = get(path: path)
|
81
|
-
|
82
|
-
fail_or_return_response_body(response.code, response_body)
|
80
|
+
process_response(response, Profile)
|
83
81
|
end
|
84
82
|
|
85
|
-
def update_profile(id:,
|
86
|
-
data = {
|
87
|
-
|
88
|
-
locale: locale
|
89
|
-
|
90
|
-
lastName: args[:lastName],
|
91
|
-
email: args[:email]
|
92
|
-
}
|
83
|
+
def update_profile(id:, merchant_customer_id:, locale:, **args)
|
84
|
+
data = args.merge({
|
85
|
+
merchant_customer_id: merchant_customer_id,
|
86
|
+
locale: locale
|
87
|
+
}).to_camel_case
|
93
88
|
|
94
89
|
response = put(path: "/customervault/v1/profiles/#{id}", data: data)
|
95
|
-
|
96
|
-
fail_or_return_response_body(response.code, response_body)
|
90
|
+
process_response(response, Profile)
|
97
91
|
end
|
98
92
|
|
99
93
|
def create_address(profile_id:, country:, zip:, **args)
|
100
|
-
data = {
|
101
|
-
nickName: args[:nickName],
|
102
|
-
street: args[:street],
|
103
|
-
city: args[:city],
|
104
|
-
country: country,
|
105
|
-
state: args[:state],
|
106
|
-
zip: zip
|
107
|
-
}
|
108
|
-
|
94
|
+
data = args.merge({ country: country, zip: zip }).to_camel_case
|
109
95
|
response = post(path: "/customervault/v1/profiles/#{profile_id}/addresses", data: data)
|
110
|
-
|
111
|
-
|
96
|
+
process_response(response, Address)
|
97
|
+
end
|
98
|
+
|
99
|
+
def create_card_from_token(profile_id:, token:)
|
100
|
+
data = { single_use_token: token }.to_camel_case
|
101
|
+
response = post(path: "/customervault/v1/profiles/#{profile_id}/cards", data: data)
|
102
|
+
process_response(response, Card)
|
112
103
|
end
|
113
104
|
|
114
105
|
def create_card(profile_id:, number:, month:, year:, **args)
|
115
|
-
data = {
|
116
|
-
|
117
|
-
|
106
|
+
data = args.merge({
|
107
|
+
card_num: number,
|
108
|
+
card_expiry: {
|
118
109
|
month: month,
|
119
110
|
year: year
|
120
|
-
}
|
121
|
-
|
122
|
-
holderName: args[:holderName],
|
123
|
-
merchantRefNum: args[:merchantRefNum],
|
124
|
-
billingAddressId: args[:billingAddressId],
|
125
|
-
defaultCardIndicator: args[:defaultCardIndicator]
|
126
|
-
}.reject { |key, value| value.nil? }
|
111
|
+
}
|
112
|
+
}).reject { |key, value| value.nil? }.to_camel_case
|
127
113
|
|
128
114
|
response = post(path: "/customervault/v1/profiles/#{profile_id}/cards", data: data)
|
129
|
-
|
130
|
-
fail_or_return_response_body(response.code, response_body)
|
115
|
+
process_response(response, Card)
|
131
116
|
end
|
132
117
|
|
133
118
|
def delete_card(profile_id:, id:)
|
134
119
|
response = delete(path: "/customervault/v1/profiles/#{profile_id}/cards/#{id}")
|
135
|
-
|
136
|
-
fail_or_return_response_body(response.code, response_body)
|
120
|
+
process_response(response)
|
137
121
|
end
|
138
122
|
|
139
123
|
def get_card(profile_id:, id:)
|
140
124
|
response = get(path: "/customervault/v1/profiles/#{profile_id}/cards/#{id}")
|
141
|
-
|
142
|
-
fail_or_return_response_body(response.code, response_body)
|
125
|
+
process_response(response, Card)
|
143
126
|
end
|
144
127
|
|
145
128
|
def update_card(profile_id:, id:, month:, year:, **args)
|
146
|
-
data = {
|
147
|
-
|
129
|
+
data = args.merge({
|
130
|
+
card_expiry: {
|
148
131
|
month: month,
|
149
132
|
year: year
|
150
|
-
}
|
151
|
-
|
152
|
-
holderName: args[:holderName],
|
153
|
-
merchantRefNum: args[:merchantRefNum],
|
154
|
-
billingAddressId: args[:billingAddressId],
|
155
|
-
defaultCardIndicator: args[:defaultCardIndicator]
|
156
|
-
}.reject { |key, value| value.nil? }
|
133
|
+
}
|
134
|
+
}).reject { |key, value| value.nil? }.to_camel_case
|
157
135
|
|
158
136
|
response = put(path: "/customervault/v1/profiles/#{profile_id}/cards/#{id}", data: data)
|
159
|
-
|
160
|
-
fail_or_return_response_body(response.code, response_body)
|
137
|
+
process_response(response, Card)
|
161
138
|
end
|
162
139
|
|
163
|
-
def purchase(amount:, token:,
|
140
|
+
def purchase(amount:, token:, merchant_ref_num:, **args)
|
164
141
|
data = {
|
165
142
|
amount: amount,
|
166
|
-
|
167
|
-
|
143
|
+
merchant_ref_num: merchant_ref_num,
|
144
|
+
settle_with_auth: true,
|
168
145
|
card: {
|
169
|
-
|
146
|
+
payment_token: token
|
170
147
|
}
|
171
|
-
}
|
148
|
+
}.to_camel_case
|
172
149
|
|
173
150
|
response = post(path: "/cardpayments/v1/accounts/#{account_number}/auths", data: data)
|
174
|
-
|
175
|
-
fail_or_return_response_body(response.code, response_body)
|
151
|
+
process_response(response, Authorization)
|
176
152
|
end
|
177
153
|
|
178
|
-
def
|
179
|
-
data = {
|
180
|
-
|
154
|
+
def create_verification_from_token(merchant_ref_num:, token:)
|
155
|
+
data = { merchant_ref_num: merchant_ref_num, card: { payment_token: token } }.to_camel_case
|
156
|
+
response = post(path: "/cardpayments/v1/accounts/#{account_number}/verifications", data: data)
|
157
|
+
process_response(response, Verification)
|
158
|
+
end
|
159
|
+
|
160
|
+
def verify_card(merchant_ref_num:, number:, month:, year:, cvv:, address:, **args)
|
161
|
+
data = args.merge({
|
162
|
+
merchant_ref_num: merchant_ref_num,
|
163
|
+
billing_details: address,
|
181
164
|
card: {
|
182
|
-
|
183
|
-
|
165
|
+
card_num: number,
|
166
|
+
cvv: cvv,
|
167
|
+
card_expiry: {
|
184
168
|
month: month,
|
185
169
|
year: year
|
186
|
-
}
|
187
|
-
|
188
|
-
|
189
|
-
profile: {
|
190
|
-
firstName: args[:firstName],
|
191
|
-
lastName: args[:lastName],
|
192
|
-
email: args[:email]
|
193
|
-
},
|
194
|
-
billingDetails: args[:address],
|
195
|
-
customerIp: args[:customerIp],
|
196
|
-
description: args[:description]
|
197
|
-
}
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}).to_camel_case
|
198
173
|
|
199
174
|
response = post(path: "/cardpayments/v1/accounts/#{account_number}/verifications", data: data)
|
200
|
-
|
201
|
-
fail_or_return_response_body(response.code, response_body)
|
175
|
+
process_response(response, Verification)
|
202
176
|
end
|
203
177
|
|
204
178
|
private
|
@@ -206,7 +180,7 @@ module Paysafe
|
|
206
180
|
def http_client
|
207
181
|
HTTP
|
208
182
|
.headers(HEADERS)
|
209
|
-
.timeout(@
|
183
|
+
.timeout(@timeouts ? @timeouts : :null)
|
210
184
|
.basic_auth(user: @api_key, pass: @api_secret)
|
211
185
|
end
|
212
186
|
|
@@ -226,25 +200,20 @@ module Paysafe
|
|
226
200
|
http_client.put("#{api_base}#{path}", json: data)
|
227
201
|
end
|
228
202
|
|
229
|
-
def
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
object[key.to_sym] = symbolize_keys!(object.delete(key))
|
237
|
-
end
|
203
|
+
def process_response(response, klass=nil)
|
204
|
+
data = parse_response_body(response.to_s)
|
205
|
+
|
206
|
+
if response.status.success?
|
207
|
+
klass&.new(data)
|
208
|
+
else
|
209
|
+
fail Error.from_response(data, response.code)
|
238
210
|
end
|
239
|
-
object
|
240
211
|
end
|
241
212
|
|
242
|
-
def
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
end
|
247
|
-
body
|
213
|
+
def parse_response_body(body)
|
214
|
+
return nil if body.strip.empty?
|
215
|
+
JSON.parse(body, symbolize_names: true)&.to_snake_case
|
216
|
+
rescue JSON::ParserError
|
248
217
|
end
|
249
218
|
|
250
219
|
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Paysafe
|
2
|
+
class Result
|
3
|
+
|
4
|
+
class << self
|
5
|
+
# Define methods that retrieve the value from attributes
|
6
|
+
#
|
7
|
+
# @param attrs [Array, Symbol]
|
8
|
+
def attributes(*attrs)
|
9
|
+
attrs.each do |attr|
|
10
|
+
define_attribute_method(attr)
|
11
|
+
define_predicate_method(attr)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Define object methods from attributes
|
16
|
+
#
|
17
|
+
# @param klass [Symbol]
|
18
|
+
# @param key1 [Symbol]
|
19
|
+
def object_attribute(klass, key1)
|
20
|
+
define_attribute_method(key1, klass)
|
21
|
+
define_predicate_method(key1)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Dynamically define a method for an attribute
|
25
|
+
#
|
26
|
+
# @param key1 [Symbol]
|
27
|
+
# @param klass [Symbol]
|
28
|
+
def define_attribute_method(key1, klass = nil)
|
29
|
+
define_method(key1) do
|
30
|
+
if instance_variable_defined?("@#{key1}")
|
31
|
+
return instance_variable_get("@#{key1}")
|
32
|
+
end
|
33
|
+
instance_variable_set("@#{key1}", get_value_by(key1, klass))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Dynamically define a predicate method for an attribute
|
38
|
+
#
|
39
|
+
# @param key1 [Symbol]
|
40
|
+
# @param key2 [Symbol]
|
41
|
+
def define_predicate_method(key1, key2 = key1)
|
42
|
+
define_method(:"#{key1}?") do
|
43
|
+
!attr_falsey_or_empty?(key2)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Initializes a new object
|
49
|
+
#
|
50
|
+
# @param attributes [Hash]
|
51
|
+
# @return [Paysafe::Result]
|
52
|
+
def initialize(attributes={})
|
53
|
+
@attributes = attributes || {}
|
54
|
+
end
|
55
|
+
|
56
|
+
# @return [Hash]
|
57
|
+
attr_reader :attributes
|
58
|
+
|
59
|
+
# @return [Boolean]
|
60
|
+
def empty?
|
61
|
+
@attributes.empty?
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def attr_falsey_or_empty?(key)
|
67
|
+
!@attributes[key] || @attributes[key].respond_to?(:empty?) && @attributes[key].empty?
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_value_by(key, klass = nil)
|
71
|
+
return @attributes[key] if klass.nil?
|
72
|
+
|
73
|
+
case @attributes[key]
|
74
|
+
when Hash
|
75
|
+
Paysafe.const_get(klass).new(@attributes[key])
|
76
|
+
when Array
|
77
|
+
@attributes[key].map do |value|
|
78
|
+
Paysafe.const_get(klass).new(value)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
@attributes[key]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'paysafe/result'
|
2
|
+
|
3
|
+
module Paysafe
|
4
|
+
class Verification < Result
|
5
|
+
attributes :id, :merchant_ref_num, :child_account_num,
|
6
|
+
:auth_code, :customer_ip, :dup_check, :description, :txn_time,
|
7
|
+
:currency_code, :avs_response, :cvv_verification, :status
|
8
|
+
|
9
|
+
object_attribute :Profile, :profile
|
10
|
+
object_attribute :Card, :card
|
11
|
+
object_attribute :Address, :billing_details
|
12
|
+
end
|
13
|
+
end
|
data/lib/paysafe/version.rb
CHANGED
data/lib/paysafe.rb
CHANGED
@@ -1,3 +1,13 @@
|
|
1
1
|
require "paysafe/version"
|
2
2
|
require "paysafe/error"
|
3
|
+
require "paysafe/single_use_token"
|
4
|
+
require "paysafe/profile"
|
5
|
+
require "paysafe/birth_date"
|
6
|
+
require "paysafe/address"
|
7
|
+
require "paysafe/card"
|
8
|
+
require "paysafe/card_expiry"
|
9
|
+
require "paysafe/verification"
|
10
|
+
require "paysafe/authorization"
|
11
|
+
require "paysafe/refinements/camel_case"
|
12
|
+
require "paysafe/refinements/snake_case"
|
3
13
|
require "paysafe/rest/client"
|
data/paysafe.gemspec
CHANGED
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Javier Julio"]
|
10
10
|
spec.email = ["jjfutbol@gmail.com"]
|
11
11
|
|
12
|
-
spec.summary =
|
13
|
-
spec.description =
|
12
|
+
spec.summary = "A Ruby interface to the Paysafe REST API."
|
13
|
+
spec.description = "A Ruby interface to the Paysafe REST API."
|
14
14
|
spec.homepage = "https://github.com/javierjulio/paysafe"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
@@ -19,6 +19,10 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
+
spec.required_ruby_version = '>= 2.3.0'
|
23
|
+
|
24
|
+
spec.add_dependency "http", '~> 2.0'
|
25
|
+
|
22
26
|
spec.add_development_dependency "bundler", "~> 1.10"
|
23
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
24
28
|
spec.add_development_dependency "dotenv"
|
@@ -27,6 +31,4 @@ Gem::Specification.new do |spec|
|
|
27
31
|
spec.add_development_dependency "vcr"
|
28
32
|
spec.add_development_dependency "webmock"
|
29
33
|
|
30
|
-
spec.add_dependency "http", '~> 2.0'
|
31
|
-
|
32
34
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paysafe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Javier Julio
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: http
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,21 +122,7 @@ dependencies:
|
|
108
122
|
- - ">="
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '0'
|
111
|
-
|
112
|
-
name: http
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
requirements:
|
115
|
-
- - "~>"
|
116
|
-
- !ruby/object:Gem::Version
|
117
|
-
version: '2.0'
|
118
|
-
type: :runtime
|
119
|
-
prerelease: false
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
requirements:
|
122
|
-
- - "~>"
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version: '2.0'
|
125
|
-
description: Gem to wrap Paysafe REST API
|
125
|
+
description: A Ruby interface to the Paysafe REST API.
|
126
126
|
email:
|
127
127
|
- jjfutbol@gmail.com
|
128
128
|
executables: []
|
@@ -132,6 +132,7 @@ files:
|
|
132
132
|
- ".env.sample"
|
133
133
|
- ".gitignore"
|
134
134
|
- ".travis.yml"
|
135
|
+
- CHANGELOG.md
|
135
136
|
- CODE_OF_CONDUCT.md
|
136
137
|
- Gemfile
|
137
138
|
- LICENSE.txt
|
@@ -140,8 +141,19 @@ files:
|
|
140
141
|
- bin/console
|
141
142
|
- bin/setup
|
142
143
|
- lib/paysafe.rb
|
144
|
+
- lib/paysafe/address.rb
|
145
|
+
- lib/paysafe/authorization.rb
|
146
|
+
- lib/paysafe/birth_date.rb
|
147
|
+
- lib/paysafe/card.rb
|
148
|
+
- lib/paysafe/card_expiry.rb
|
143
149
|
- lib/paysafe/error.rb
|
150
|
+
- lib/paysafe/profile.rb
|
151
|
+
- lib/paysafe/refinements/camel_case.rb
|
152
|
+
- lib/paysafe/refinements/snake_case.rb
|
144
153
|
- lib/paysafe/rest/client.rb
|
154
|
+
- lib/paysafe/result.rb
|
155
|
+
- lib/paysafe/single_use_token.rb
|
156
|
+
- lib/paysafe/verification.rb
|
145
157
|
- lib/paysafe/version.rb
|
146
158
|
- paysafe.gemspec
|
147
159
|
homepage: https://github.com/javierjulio/paysafe
|
@@ -156,7 +168,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
156
168
|
requirements:
|
157
169
|
- - ">="
|
158
170
|
- !ruby/object:Gem::Version
|
159
|
-
version:
|
171
|
+
version: 2.3.0
|
160
172
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
161
173
|
requirements:
|
162
174
|
- - ">="
|
@@ -164,8 +176,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
164
176
|
version: '0'
|
165
177
|
requirements: []
|
166
178
|
rubyforge_project:
|
167
|
-
rubygems_version: 2.
|
179
|
+
rubygems_version: 2.6.8
|
168
180
|
signing_key:
|
169
181
|
specification_version: 4
|
170
|
-
summary:
|
182
|
+
summary: A Ruby interface to the Paysafe REST API.
|
171
183
|
test_files: []
|