spreedly-core-ruby 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
data/lib/spreedly-core-ruby.rb
CHANGED
@@ -21,9 +21,9 @@ module SpreedlyCore
|
|
21
21
|
}
|
22
22
|
|
23
23
|
class Error < RuntimeError; end
|
24
|
-
|
24
|
+
|
25
25
|
# Custom exception which occurs when a request to SpreedlyCore times out
|
26
|
-
# See SpreedlyCore::Base.default_timeout
|
26
|
+
# See SpreedlyCore::Base.default_timeout
|
27
27
|
class TimeOutError < Error; end
|
28
28
|
class InvalidResponse < Error
|
29
29
|
def initialize(response, message)
|
@@ -37,7 +37,7 @@ module SpreedlyCore
|
|
37
37
|
def initialize(errors)
|
38
38
|
errors = [errors] unless errors.is_a?(Array)
|
39
39
|
@errors = errors
|
40
|
-
|
40
|
+
|
41
41
|
super(errors.join("\n"))
|
42
42
|
end
|
43
43
|
end
|
@@ -75,6 +75,9 @@ module SpreedlyCore
|
|
75
75
|
if login.nil? || secret.nil?
|
76
76
|
raise ArgumentError.new("You must provide a login and a secret. Gem will look for ENV['SPREEDLYCORE_API_LOGIN'] and ENV['SPREEDLYCORE_API_SECRET'], but you may also pass in a hash with :api_login and :api_secret keys.")
|
77
77
|
end
|
78
|
+
|
79
|
+
options[:endpoint] ||= "https://spreedlycore.com/#{SpreedlyCore::API_VERSION}"
|
80
|
+
|
78
81
|
Base.configure(login, secret, options)
|
79
82
|
end
|
80
83
|
|
@@ -93,6 +96,6 @@ module SpreedlyCore
|
|
93
96
|
class Response < Base
|
94
97
|
attr_reader(:success, :message, :avs_code, :avs_message, :cvv_code,
|
95
98
|
:cvv_message, :error_code, :error_detail, :created_at,
|
96
|
-
:updated_at)
|
99
|
+
:updated_at)
|
97
100
|
end
|
98
101
|
end
|
@@ -4,23 +4,22 @@ module SpreedlyCore
|
|
4
4
|
# Base class for all SpreedlyCore API requests
|
5
5
|
class Base
|
6
6
|
include HTTParty
|
7
|
-
|
7
|
+
|
8
8
|
# Net::HTTP::Options is configured to not have a body.
|
9
9
|
# Lets give it the body it's always dreamed of
|
10
10
|
old_verbose, $VERBOSE = $VERBOSE, nil
|
11
11
|
Net::HTTP::Options::RESPONSE_HAS_BODY = true
|
12
12
|
$VERBOSE = old_verbose
|
13
|
-
|
13
|
+
|
14
14
|
format :xml
|
15
15
|
|
16
16
|
# timeout requests after 10 seconds
|
17
17
|
default_timeout 10
|
18
18
|
|
19
|
-
base_uri "https://spreedlycore.com/#{SpreedlyCore::API_VERSION}"
|
20
|
-
|
21
19
|
def self.configure(login, secret, options = {})
|
22
20
|
@@login = login
|
23
21
|
self.basic_auth(@@login, secret)
|
22
|
+
base_uri options[:endpoint]
|
24
23
|
@@gateway_token = options.delete(:gateway_token)
|
25
24
|
end
|
26
25
|
|
@@ -31,7 +30,7 @@ module SpreedlyCore
|
|
31
30
|
# make a post request to path
|
32
31
|
# If the request succeeds, provide the respones to the &block
|
33
32
|
def self.verify_post(path, options={}, &block)
|
34
|
-
verify_request(:post, path, options, 200, 201, 422, &block)
|
33
|
+
verify_request(:post, path, options, 200, 201, 202, 422, &block)
|
35
34
|
end
|
36
35
|
|
37
36
|
# make a put request to path
|
@@ -58,12 +57,12 @@ module SpreedlyCore
|
|
58
57
|
# If *allowed_codes is empty, don't check the response code, but set an instance
|
59
58
|
# variable on the object created in the block containing the response code.
|
60
59
|
def self.verify_request(request_type, path, options, *allowed_codes, &block)
|
61
|
-
begin
|
60
|
+
begin
|
62
61
|
response = self.send(request_type, path, options)
|
63
62
|
rescue Timeout::Error, Errno::ETIMEDOUT => e
|
64
63
|
raise TimeOutError.new("Request to #{path} timed out. Is Spreedly Core down?")
|
65
64
|
end
|
66
|
-
|
65
|
+
|
67
66
|
if allowed_codes.any? && !allowed_codes.include?(response.code)
|
68
67
|
raise InvalidResponse.new(response, "Error retrieving #{path}. Got status of #{response.code}. Expected status to be in #{allowed_codes.join(",")}")
|
69
68
|
end
|
@@ -89,7 +88,7 @@ module SpreedlyCore
|
|
89
88
|
attrs.each do |k, v|
|
90
89
|
instance_variable_set("@#{k}", v)
|
91
90
|
end
|
92
|
-
# errors may be nil, empty, a string, or an array of strings.
|
91
|
+
# errors may be nil, empty, a string, or an array of strings.
|
93
92
|
@errors = if @errors.nil? || @errors["error"].blank?
|
94
93
|
[]
|
95
94
|
elsif @errors["error"].is_a?(String)
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module SpreedlyCore
|
2
2
|
class PaymentMethod < Base
|
3
|
-
attr_reader
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
attr_reader :address1, :address2, :card_type, :city, :country, :created_at,
|
4
|
+
:data, :email, :errors, :first_name, :last_four_digits,
|
5
|
+
:last_name, :month, :number, :payment_method_type, :phone_number,
|
6
|
+
:state, :token, :updated_at, :verification_value, :year, :zip
|
7
7
|
|
8
8
|
# configure additional required fiels. Like :address1, :city, :state
|
9
9
|
def self.additional_required_cc_fields *fields
|
@@ -18,7 +18,7 @@ module SpreedlyCore
|
|
18
18
|
|
19
19
|
# Lookup the PaymentMethod by token
|
20
20
|
def self.find(token)
|
21
|
-
return nil if token.nil?
|
21
|
+
return nil if token.nil?
|
22
22
|
verify_get("/payment_methods/#{token}.xml",
|
23
23
|
:has_key => "payment_method") do |response|
|
24
24
|
new(response.parsed_response["payment_method"])
|
@@ -26,7 +26,7 @@ module SpreedlyCore
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def self.create(credit_card)
|
29
|
-
verify_post("/payment_methods.xml", :body => {:credit_card => credit_card}) do |response|
|
29
|
+
verify_post("/payment_methods.xml", :body => {:payment_method => { :credit_card => credit_card }}) do |response|
|
30
30
|
AddPaymentMethodTransaction.new(response.parsed_response["transaction"])
|
31
31
|
end
|
32
32
|
end
|
@@ -52,13 +52,13 @@ module SpreedlyCore
|
|
52
52
|
end
|
53
53
|
|
54
54
|
# Make a purchase against the payment method
|
55
|
-
def purchase(amount,
|
56
|
-
purchase_or_authorize(:purchase, amount,
|
55
|
+
def purchase(amount, *args)
|
56
|
+
purchase_or_authorize(:purchase, amount, *args)
|
57
57
|
end
|
58
58
|
|
59
59
|
# Make an authorize against payment method. You can then later capture against the authorize
|
60
|
-
def authorize(amount,
|
61
|
-
purchase_or_authorize(:authorize, amount,
|
60
|
+
def authorize(amount, *args)
|
61
|
+
purchase_or_authorize(:authorize, amount, *args)
|
62
62
|
end
|
63
63
|
|
64
64
|
# Update the attributes of a payment method
|
@@ -82,13 +82,7 @@ module SpreedlyCore
|
|
82
82
|
@errors.empty?
|
83
83
|
end
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
protected
|
89
|
-
|
90
|
-
|
91
|
-
|
85
|
+
protected
|
92
86
|
|
93
87
|
# Validate additional cc fields like first_name, last_name, etc when
|
94
88
|
# configured to do so
|
@@ -103,27 +97,39 @@ protected
|
|
103
97
|
else
|
104
98
|
str_field.split("_").join(" ")
|
105
99
|
end
|
106
|
-
|
100
|
+
|
107
101
|
@errors << "#{friendly_name.capitalize} can't be blank"
|
108
102
|
end
|
109
103
|
end
|
110
104
|
@errors = @errors.sort
|
111
105
|
end
|
112
106
|
|
113
|
-
def purchase_or_authorize(tran_type, amount,
|
107
|
+
def purchase_or_authorize(tran_type, amount, *args)
|
108
|
+
options = if(args.size == 1 && args.first.kind_of?(Hash))
|
109
|
+
args.first
|
110
|
+
else
|
111
|
+
{
|
112
|
+
:currency => args[0],
|
113
|
+
:gateway_token => args[1],
|
114
|
+
:ip_address => args[2]
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
114
118
|
transaction_type = tran_type.to_s
|
115
119
|
raise "Unknown transaction type" unless %w{purchase authorize}.include?(transaction_type)
|
116
120
|
|
117
|
-
currency
|
118
|
-
|
119
|
-
path = "/gateways/#{
|
121
|
+
currency = (options[:currency] || "USD")
|
122
|
+
gateway_token = (options[:gateway_token] || self.class.gateway_token)
|
123
|
+
path = "/gateways/#{gateway_token}/#{transaction_type}.xml"
|
120
124
|
data = {
|
121
125
|
:transaction => {
|
122
|
-
:transaction_type => transaction_type,
|
126
|
+
:transaction_type => transaction_type,
|
123
127
|
:payment_method_token => token,
|
124
128
|
:amount => amount,
|
125
129
|
:currency_code => currency,
|
126
|
-
:ip => ip_address
|
130
|
+
:ip => options[:ip_address],
|
131
|
+
:redirect_url => options[:redirect_url],
|
132
|
+
:callback_url => options[:callback_url]
|
127
133
|
}
|
128
134
|
}
|
129
135
|
self.class.verify_post(path, :body => data,
|
@@ -3,7 +3,7 @@ module SpreedlyCore
|
|
3
3
|
class Transaction < Base
|
4
4
|
attr_reader(:amount, :on_test_gateway, :created_at, :updated_at, :currency_code,
|
5
5
|
:succeeded, :token, :message, :transaction_type, :gateway_token,
|
6
|
-
:response)
|
6
|
+
:response, :signed, :state, :checkout_url)
|
7
7
|
alias :succeeded? :succeeded
|
8
8
|
|
9
9
|
# Breaks enacapsulation a bit, but allow subclasses to register the 'transaction_type'
|
@@ -15,35 +15,65 @@ module SpreedlyCore
|
|
15
15
|
|
16
16
|
# Lookup the transaction by its token. Returns the correct subclass
|
17
17
|
def self.find(token)
|
18
|
-
return nil if token.nil?
|
18
|
+
return nil if token.nil?
|
19
19
|
verify_get("/transactions/#{token}.xml", :has_key => "transaction") do |response|
|
20
20
|
attrs = response.parsed_response["transaction"]
|
21
21
|
klass = @@transaction_type_to_class[attrs["transaction_type"]] || self
|
22
|
-
klass.new(attrs)
|
22
|
+
klass.new(attrs).tap do |transaction|
|
23
|
+
transaction.verified!
|
24
|
+
end
|
23
25
|
end
|
24
26
|
end
|
27
|
+
|
28
|
+
def initialize(attrs={})
|
29
|
+
super
|
30
|
+
if(valid_signature?)
|
31
|
+
verified!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def verified!
|
36
|
+
@verified = true
|
37
|
+
end
|
38
|
+
|
39
|
+
def verified?
|
40
|
+
@verified
|
41
|
+
end
|
42
|
+
|
43
|
+
def pending?
|
44
|
+
state == "pending"
|
45
|
+
end
|
46
|
+
|
47
|
+
def valid_signature?
|
48
|
+
return false unless signed
|
49
|
+
fields = signed["fields"]
|
50
|
+
data = fields.collect do |field|
|
51
|
+
self.instance_variable_get("@#{field}")
|
52
|
+
end.join("|")
|
53
|
+
(OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(signed["algorithm"], SpreedlyCore::Base.secret, data)) == signed["signature"])
|
54
|
+
end
|
25
55
|
end
|
26
56
|
|
27
57
|
class RetainTransaction < Transaction
|
28
58
|
handles "RetainPaymentMethod"
|
29
59
|
attr_reader :payment_method
|
30
|
-
|
60
|
+
|
31
61
|
def initialize(attrs={})
|
32
62
|
@payment_method = PaymentMethod.new(attrs.delete("payment_method") || {})
|
33
63
|
super(attrs)
|
34
64
|
end
|
35
65
|
end
|
36
|
-
|
66
|
+
|
37
67
|
class RedactTransaction < Transaction
|
38
68
|
handles "RedactPaymentMethod"
|
39
69
|
attr_reader :payment_method
|
40
|
-
|
70
|
+
|
41
71
|
def initialize(attrs={})
|
42
72
|
@payment_method = PaymentMethod.new(attrs.delete("payment_method") || {})
|
43
73
|
super(attrs)
|
44
74
|
end
|
45
75
|
end
|
46
|
-
|
76
|
+
|
47
77
|
module NullifiableTransaction
|
48
78
|
# Void is used to cancel out authorizations and, with some gateways, to
|
49
79
|
# cancel actual payment transactions within the first 24 hours
|
@@ -52,13 +82,13 @@ module SpreedlyCore
|
|
52
82
|
self.class.verify_post("/transactions/#{token}/void.xml",
|
53
83
|
:body => body, :has_key => "transaction") do |response|
|
54
84
|
VoidedTransaction.new(response.parsed_response["transaction"])
|
55
|
-
end
|
85
|
+
end
|
56
86
|
end
|
57
87
|
|
58
88
|
# Credit amount. If amount is nil, then credit the entire previous purchase
|
59
|
-
# or captured amount
|
89
|
+
# or captured amount
|
60
90
|
def credit(amount=nil, ip_address=nil)
|
61
|
-
body = if amount.nil?
|
91
|
+
body = if amount.nil?
|
62
92
|
{:ip => ip_address}
|
63
93
|
else
|
64
94
|
{:transaction => {:amount => amount, :ip => ip_address}}
|
@@ -76,10 +106,10 @@ module SpreedlyCore
|
|
76
106
|
|
77
107
|
class AuthorizeTransaction < Transaction
|
78
108
|
include HasIpAddress
|
79
|
-
|
109
|
+
|
80
110
|
handles "Authorization"
|
81
111
|
attr_reader :payment_method
|
82
|
-
|
112
|
+
|
83
113
|
def initialize(attrs={})
|
84
114
|
@payment_method = PaymentMethod.new(attrs.delete("payment_method") || {})
|
85
115
|
@response = Response.new(attrs.delete("response") || {})
|
@@ -120,21 +150,21 @@ module SpreedlyCore
|
|
120
150
|
class CaptureTransaction < Transaction
|
121
151
|
include NullifiableTransaction
|
122
152
|
include HasIpAddress
|
123
|
-
|
153
|
+
|
124
154
|
handles "Capture"
|
125
155
|
attr_reader :reference_token
|
126
156
|
end
|
127
157
|
|
128
158
|
class VoidedTransaction < Transaction
|
129
159
|
include HasIpAddress
|
130
|
-
|
160
|
+
|
131
161
|
handles "Void"
|
132
162
|
attr_reader :reference_token
|
133
163
|
end
|
134
164
|
|
135
165
|
class CreditTransaction < Transaction
|
136
166
|
include HasIpAddress
|
137
|
-
|
167
|
+
|
138
168
|
handles "Credit"
|
139
169
|
attr_reader :reference_token
|
140
170
|
end
|
@@ -145,5 +175,5 @@ module SpreedlyCore
|
|
145
175
|
handles "AddPaymentMethod"
|
146
176
|
attr_reader :payment_method
|
147
177
|
end
|
148
|
-
|
178
|
+
|
149
179
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spreedly-core-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-10-19 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: httparty
|
17
|
-
requirement:
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,10 +22,15 @@ dependencies:
|
|
22
22
|
version: '0.0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements:
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0.0'
|
26
31
|
- !ruby/object:Gem::Dependency
|
27
32
|
name: activesupport
|
28
|
-
requirement:
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
29
34
|
none: false
|
30
35
|
requirements:
|
31
36
|
- - ~>
|
@@ -33,10 +38,15 @@ dependencies:
|
|
33
38
|
version: '3.0'
|
34
39
|
type: :runtime
|
35
40
|
prerelease: false
|
36
|
-
version_requirements:
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3.0'
|
37
47
|
- !ruby/object:Gem::Dependency
|
38
48
|
name: builder
|
39
|
-
requirement:
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
40
50
|
none: false
|
41
51
|
requirements:
|
42
52
|
- - ! '>='
|
@@ -44,10 +54,15 @@ dependencies:
|
|
44
54
|
version: '0'
|
45
55
|
type: :runtime
|
46
56
|
prerelease: false
|
47
|
-
version_requirements:
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
48
63
|
- !ruby/object:Gem::Dependency
|
49
64
|
name: ruby-debug19
|
50
|
-
requirement:
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
51
66
|
none: false
|
52
67
|
requirements:
|
53
68
|
- - ! '>='
|
@@ -55,21 +70,31 @@ dependencies:
|
|
55
70
|
version: '0'
|
56
71
|
type: :development
|
57
72
|
prerelease: false
|
58
|
-
version_requirements:
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
59
79
|
- !ruby/object:Gem::Dependency
|
60
80
|
name: rake
|
61
|
-
requirement:
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
62
82
|
none: false
|
63
83
|
requirements:
|
64
|
-
- - =
|
84
|
+
- - '='
|
65
85
|
- !ruby/object:Gem::Version
|
66
86
|
version: 0.8.7
|
67
87
|
type: :development
|
68
88
|
prerelease: false
|
69
|
-
version_requirements:
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - '='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 0.8.7
|
70
95
|
- !ruby/object:Gem::Dependency
|
71
96
|
name: webmock
|
72
|
-
requirement:
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
73
98
|
none: false
|
74
99
|
requirements:
|
75
100
|
- - ~>
|
@@ -77,7 +102,12 @@ dependencies:
|
|
77
102
|
version: 1.6.2
|
78
103
|
type: :development
|
79
104
|
prerelease: false
|
80
|
-
version_requirements:
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.6.2
|
81
111
|
description: Spreedly Core is a cloud service that allows you to store credit cards
|
82
112
|
and run transactions against them, enabling you to accept payments on your website
|
83
113
|
while avoiding all liability and PCI compliance requirements.
|
@@ -117,15 +147,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
147
|
- - ! '>='
|
118
148
|
- !ruby/object:Gem::Version
|
119
149
|
version: '0'
|
150
|
+
segments:
|
151
|
+
- 0
|
152
|
+
hash: -3960261074814685909
|
120
153
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
154
|
none: false
|
122
155
|
requirements:
|
123
156
|
- - ! '>='
|
124
157
|
- !ruby/object:Gem::Version
|
125
158
|
version: '0'
|
159
|
+
segments:
|
160
|
+
- 0
|
161
|
+
hash: -3960261074814685909
|
126
162
|
requirements: []
|
127
163
|
rubyforge_project:
|
128
|
-
rubygems_version: 1.8.
|
164
|
+
rubygems_version: 1.8.24
|
129
165
|
signing_key:
|
130
166
|
specification_version: 3
|
131
167
|
summary: Ruby interface for Spreedly Core
|