affirm 0.0.1 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 689c049744aaff6ed260bd43c0bcdf0219e6689a
4
- data.tar.gz: 90142f082b195d4b12b593ba8dbe8f0a9d0a01b1
3
+ metadata.gz: 39c1e3c767578030a0b0d4040f1369a0984537dc
4
+ data.tar.gz: 41fe7e6a858817d7bb521c68dcc3238457e347e3
5
5
  SHA512:
6
- metadata.gz: 6b0c3a679864712c47a0053eff6135b0fc2ba4c6a24cb49f9d66b019c95b1ca3b724f2eff90d0a4a8e07f46a5654c8667b44a9e87edbb3d817995b25eca1369b
7
- data.tar.gz: 0836887d3303dbb09d741b13e8894b5f6ec7c987c8218cc1a744e053b4b99a86fb440a14ecb93ba9aabb80051fab200833c211ff7d0e3071d54c35e6c84110a4
6
+ metadata.gz: d00eda5029a694f08f75cbd2512dbf6acd9ae10cd2a4de39e41b10c004d454623142aa791bb74ce4481ce39689a3d4790cbf4d5213739794c041a69e77060f23
7
+ data.tar.gz: 12f0057579aba7917cb39f3f5e5d12d38662b6c8639090652e2215c40be8c8278ed1dba5157adf93b118a9f5dd232f428f802eacdb8e466681eedd8c14469e38
data/README.md CHANGED
@@ -7,15 +7,16 @@ Requires Ruby 2.1 or greater.
7
7
 
8
8
  ## Install
9
9
  Add to your gemfile:
10
+
10
11
  ```ruby
11
- gem 'affirm-ruby'
12
+ gem 'affirm'
12
13
  ```
13
- and `bundle install`.
14
14
 
15
- *Note*: This gem is not yet registered with Rubygems. In the meantime, you can use the 'git' option in your Gemfile.
15
+ and `bundle install`.
16
16
 
17
17
  ## Initialize
18
18
  Initialize the client with your credentials (if you're using rails, this goes in `config/initializers`).
19
+
19
20
  ```ruby
20
21
  Affirm::API.public_key = "xxx"
21
22
  Affirm::API.secret_key = "xxx"
@@ -23,86 +24,87 @@ Affirm::API.api_url = "https://sandbox.affirm.com/api/v2/"
23
24
  ```
24
25
 
25
26
  ## Charges
26
- The charges resource can be accessed through the api class:
27
- ```ruby
28
- Affirm::API.charges
29
- ```
30
27
 
31
- ### Authorizing a charge
28
+ All API requests raise an `Affirm::Error` or subclass thereof on failure.
29
+
30
+ ### Creating/authorizing a charge
31
+
32
32
  ```ruby
33
- Affirm::API.charges.authorize(checkout_token: "token")
34
- Affirm::API.charges.authorize!(checkout_token: "token") # raises Affirm::Error on failure
33
+ charge = Affirm::Charge.create("checkout_token")
35
34
  ```
36
35
 
37
- ### Reading a charge
36
+ ### Retrieving a charge
37
+
38
38
  ```ruby
39
- Affirm::API.charges.get(charge_id: "abcd")
39
+ charge = Affirm::Charge.retrieve("ABCD-ABCD")
40
+
41
+ charge.id
42
+ charge.amount
43
+ charge.created
44
+ charge.currency
45
+ charge.auth_hold
46
+ charge.payable
47
+ charge.void?
48
+ charge.order_id
49
+ charge.events # array of Affirm::ChargeEvent
50
+ charge.details # hash of order details
40
51
  ```
41
52
 
53
+ Raises an `Affirm::ResourceNotFoundError` if the charge doesn't exist.
54
+
55
+ See https://docs.affirm.com/v2/api/charges/#charge-object for more info on the charge object
56
+
42
57
  ### Capturing a charge
43
58
  Optionally takes an `order_id`, `shipping_carrier`, and `shipping_confirmation`.
59
+
44
60
  ```ruby
45
- Affirm::API.charges.capture(charge_id: "abcd")
46
- Affirm::API.charges.capture(charge_id: "abcd", order_id: "1234", shipping_carrier: "USPS", shipping_confirmation: "ABCD1234")
47
- Affirm::API.charges.capture!(charge_id: "abcd") # raises Affirm::Error on failure
61
+ charge.capture
62
+ charge.capture(order_id: "1234", shipping_carrier: "USPS", shipping_confirmation: "ABCD1234")
48
63
  ```
49
64
 
65
+ Returns an `Affirm::ChargeEvent` object of type `capture`.
66
+
50
67
  ### Voiding a charge
68
+
51
69
  ```ruby
52
- Affirm::API.charges.void(charge_id: "abcd")
53
- Affirm::API.charges.void!(charge_id: "abcd") # raises Affirm::Error on failure
70
+ charge.void
54
71
  ```
55
72
 
73
+ Returns an `Affirm::ChargeEvent` object of type `void`.
74
+
56
75
  ### Refunding a charge
57
76
  Optionally takes an `amount` to refund (in cents).
77
+
58
78
  ```ruby
59
- Affirm::API.charges.refund(charge_id: "abcd")
60
- Affirm::API.charges.refund(charge_id: "abcd", amount: 5000)
61
- Affirm::API.charges.refund!(charge_id: "abcd") # raises Affirm::Error on failure
79
+ charge.refund
80
+ charge.refund(amount: 1000)
62
81
  ```
63
82
 
83
+ Returns an `Affirm::ChargeEvent` object of type `refund`.
84
+
64
85
  ### Updating tracking fields
65
86
  Optionally takes an `order_id`, `shipping_carrier`, and `shipping_confirmation`.
66
- ```ruby
67
- Affirm::API.charges.update(charge_id: "abcd", order_id: "1234", shipping_carrier: "USPS", shipping_confirmation: "ABCD1234")
68
- Affirm::API.charges.update!(charge_id: "abcd", order_id: "1234") # raises Affirm::Error on failure
69
- ```
70
87
 
71
- ## Responses
72
- On successful api calls, the response json is
73
88
  ```ruby
74
- response = Affirm::API.charges.get(charge_id: "abcd")
75
-
76
- response.success? # => true
77
- response.error? # => false
78
-
79
- response.status_code # => 200
80
-
81
- response.body # => hash of values
82
- response.body["id"] # eg "abcd"
83
- response.body["details"]["shipping_amount"] # eg 400
89
+ charge.update(order_id: "1234", shipping_carrier: "USPS", shipping_confirmation: "ABCD1234")
84
90
  ```
85
91
 
86
- ### Error responses
87
- Unsuccessful responses have a few methods built in:
88
- ```ruby
89
- response.code # eg "auth-declined"
90
- response.type # eg "invalid_request"
91
- response.message # eg "Invalid phone number format"
92
- response.field # eg "shipping_address.phone"
93
- ```
94
- See https://docs.affirm.com/v2/api/errors/#error-object.
92
+ Returns an `Affirm::ChargeEvent` object of type `update`.
95
93
 
96
- ### Exceptions
97
- Exceptions are raised for 5xx, 404 and 401 responses, yielding an `Affirm::ServerError`,
94
+ ## Exceptions
95
+ Special exceptions are raised for 5xx, 404 and 401 responses, yielding an `Affirm::ServerError`,
98
96
  `Affirm::ResourceNotFoundError` and `Affirm::AuthenticationError`, respectively. These are subclassed from
99
97
  `Affirm::Error`.
98
+
99
+ All exceptions have the following methods on them:
100
+
100
101
  ```ruby
101
102
  begin
102
- Affirm::API.charges.authorize(checkout_token: "token")
103
- rescue Affirm::ServerError => e
104
- Logger.info e.code
105
- Logger.info e.message
103
+ Affirm::Charge.create("checkout_token")
104
+ rescue Affirm::Error => e
105
+ Logger.info e.http_code # eg 422
106
+ Logger.info e.code # eg "auth-declined"
107
+ Logger.info e.message # eg "Invalid phone number format"
106
108
  end
107
109
  ```
108
110
 
data/affirm.gemspec CHANGED
@@ -2,7 +2,7 @@ Gem::Specification.new do |s|
2
2
  s.name = "affirm"
3
3
  s.summary = "Affirm Ruby Client Library"
4
4
  s.description = "Ruby client library for integrating with Affirm financing payments"
5
- s.version = "0.0.1"
5
+ s.version = "1.0.0"
6
6
  s.license = "Apache License Version 2.0"
7
7
  s.author = "Reverb.com"
8
8
  s.email = "dev@reverb.com"
data/lib/affirm/api.rb CHANGED
@@ -4,10 +4,6 @@ module Affirm
4
4
  attr_accessor :public_key, :secret_key, :api_url
5
5
  @@client = nil
6
6
 
7
- def charges
8
- @@charges ||= Affirm::Charges.new(client)
9
- end
10
-
11
7
  def client
12
8
  @@client ||= Affirm::Client.new(
13
9
  public_key: public_key,
@@ -0,0 +1,115 @@
1
+ module Affirm
2
+ class Charge
3
+ attr_reader :id, :amount, :created, :currency, :auth_hold, :payable, :order_id, :events, :details
4
+
5
+ ##
6
+ # RETRIEVE
7
+ #
8
+ # id - (required) string. The charge id, in format 'XXXX-XXXX'
9
+ def self.retrieve(id, client: Affirm::API.client)
10
+ new(attrs: {"id" => id}, client: client).refresh
11
+ end
12
+
13
+ ##
14
+ # CREATE / AUTHORIZE
15
+ #
16
+ # checkout_token - (required) string. The charge token passed through the confirmation response.
17
+ def self.create(checkout_token, client: Affirm::API.client)
18
+ response = client.make_request!("/charges", :post, checkout_token: checkout_token)
19
+
20
+ new(attrs: response.body, client: client)
21
+ end
22
+
23
+ ##
24
+ # CAPTURE
25
+ #
26
+ # order_id - (optional) string. Your internal order id. This is stored for your own future reference.
27
+ # shipping_carrier - (optional) string. The shipping carrier used to ship the items in the charge.
28
+ # shipping_confirmation - (optional) string. The shipping confirmation for the shipment.
29
+ def capture(order_id: nil, shipping_carrier: nil, shipping_confirmation: nil)
30
+ api_request("/charges/#{id}/capture", :post, {
31
+ order_id: order_id,
32
+ shipping_carrier: shipping_carrier,
33
+ shipping_confirmation: shipping_confirmation
34
+ })
35
+ end
36
+
37
+ ##
38
+ # VOID
39
+ #
40
+ def void
41
+ api_request("/charges/#{id}/void", :post)
42
+ end
43
+
44
+ ##
45
+ # REFUND
46
+ #
47
+ # amount - (optional) integer or null. The amount to refund in cents. The default amount is the remaining balance on the charge.
48
+ def refund(amount: nil)
49
+ api_request("/charges/#{id}/refund", :post, {
50
+ amount: amount
51
+ })
52
+ end
53
+
54
+ ##
55
+ # UPDATE
56
+ #
57
+ # order_id - (optional) string. Your internal order id. This is stored for your own future reference.
58
+ # shipping_carrier - (optional) string. The shipping carrier used to ship the items in the charge.
59
+ # shipping_confirmation - (optional) string. The shipping confirmation for the shipment.
60
+ def update(order_id: nil, shipping_carrier: nil, shipping_confirmation: nil)
61
+ api_request("/charges/#{id}/update", :post, {
62
+ order_id: order_id,
63
+ shipping_carrier: shipping_carrier,
64
+ shipping_confirmation: shipping_confirmation
65
+ })
66
+ end
67
+
68
+ def initialize(attrs: {}, client: Affirm::API.client)
69
+ @client = client
70
+ set_attrs(attrs)
71
+ end
72
+
73
+ def refresh
74
+ response = @client.make_request("/charges/#{id}", :get)
75
+
76
+ set_attrs(response.body)
77
+
78
+ self
79
+ end
80
+
81
+ def void?
82
+ @void
83
+ end
84
+
85
+ private
86
+
87
+ def set_attrs(attrs)
88
+ @id = attrs["id"]
89
+ @amount = attrs["amount"]
90
+ @created = attrs["created"]
91
+ @currency = attrs["currency"]
92
+ @auth_hold = attrs["auth_hold"]
93
+ @payable = attrs["payable"]
94
+ @void = attrs["void"]
95
+ @order_id = attrs["order_id"]
96
+ @details = attrs["details"]
97
+ @events = parse_events(attrs["events"])
98
+ end
99
+
100
+ def parse_events(events_attrs)
101
+ if events_attrs
102
+ events_attrs.map { |event| ChargeEvent.new(event) }
103
+ else
104
+ []
105
+ end
106
+ end
107
+
108
+ def api_request(url, method, params={})
109
+ response = @client.make_request!(url, method, params)
110
+ event = ChargeEvent.new(response.body)
111
+ @events << event
112
+ event
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,20 @@
1
+ module Affirm
2
+ class ChargeEvent
3
+ attr_reader :id, :transaction_id, :type, :created,
4
+ :amount, :fee, :order_id, :shipping_carrier, :shipping_confirmation,
5
+ :fee_refunded
6
+
7
+ def initialize(attrs)
8
+ @id = attrs["id"]
9
+ @transaction_id = attrs["transaction_id"]
10
+ @type = attrs["type"]
11
+ @created = attrs["created"]
12
+ @amount = attrs["amount"]
13
+ @fee = attrs["fee"]
14
+ @order_id = attrs["order_id"]
15
+ @shipping_carrier = attrs["shipping_carrier"]
16
+ @shipping_confirmation = attrs["shipping_confirmation"]
17
+ @fee_refunded = attrs["fee_refunded"]
18
+ end
19
+ end
20
+ end
data/lib/affirm/client.rb CHANGED
@@ -28,6 +28,15 @@ module Affirm
28
28
  handle_errors(affirm_response)
29
29
  end
30
30
 
31
+ # like make_request, but raise error on failure
32
+ def make_request!(path, method, data={})
33
+ response = make_request(path, method, data)
34
+
35
+ raise Affirm::Error.from_response(response) if response.error?
36
+
37
+ response
38
+ end
39
+
31
40
  private
32
41
 
33
42
  def parse_response(response)
@@ -6,7 +6,7 @@ module Affirm
6
6
  new(
7
7
  status_code: response.status_code,
8
8
  code: response.code,
9
- message: response.message
9
+ message: response.message || response.raw_body
10
10
  )
11
11
  end
12
12
 
@@ -17,7 +17,11 @@ module Affirm
17
17
  end
18
18
 
19
19
  def to_s
20
- "#{status_code} #{code}: #{message}"
20
+ if code || message
21
+ "#{status_code} - (#{code}) #{message}"
22
+ else
23
+ status_code.to_s
24
+ end
21
25
  end
22
26
  end
23
27
  end
@@ -1,11 +1,11 @@
1
1
  module Affirm
2
2
  class Response
3
- attr_reader :status_code
3
+ attr_reader :status_code, :raw_body
4
4
 
5
5
  def initialize(success:, status_code:, body:)
6
6
  @success = success
7
7
  @status_code = status_code.to_i
8
- @body = body
8
+ @raw_body = body
9
9
  end
10
10
 
11
11
  def success?
@@ -17,7 +17,9 @@ module Affirm
17
17
  end
18
18
 
19
19
  def body
20
- JSON.parse(@body)
20
+ JSON.parse(@raw_body)
21
+ rescue JSON::ParserError
22
+ {}
21
23
  end
22
24
 
23
25
  def type
data/lib/affirm.rb CHANGED
@@ -3,7 +3,8 @@ require 'json'
3
3
  require 'affirm/api'
4
4
  require 'affirm/client'
5
5
  require 'affirm/response'
6
- require 'affirm/charges'
6
+ require 'affirm/charge_event'
7
+ require 'affirm/charge'
7
8
 
8
9
  require 'affirm/errors/error'
9
10
  require 'affirm/errors/authentication_error'
@@ -0,0 +1,242 @@
1
+ require 'spec_helper'
2
+
3
+ describe Affirm::Charge do
4
+ let(:id) { "ABCD" }
5
+ let!(:request) do
6
+ stub_request(request_method, request_url).to_return(status: response_code, body: response_body)
7
+ end
8
+
9
+ let(:response_code) { 200 }
10
+
11
+ let(:charge) { Affirm::Charge.new(attrs: {"id" => id}) }
12
+
13
+ describe "self.retrieve" do
14
+ let(:request_method) { :get }
15
+ let(:request_url) { "#{TEST_URL}/charges/#{id}" }
16
+ let(:response_body) { load_fixture("charges/retrieve.json") }
17
+
18
+ it "returns a charge" do
19
+ charge = Affirm::Charge.retrieve(id)
20
+
21
+ charge.should be_a Affirm::Charge
22
+ end
23
+
24
+ it "sets attributes" do
25
+ charge = Affirm::Charge.retrieve(id)
26
+
27
+ charge.id.should == id
28
+ charge.created.should == "2014-03-18T19:19:04Z"
29
+ charge.currency.should == "USD"
30
+ charge.amount.should == 6100
31
+ charge.auth_hold.should == 6100
32
+ charge.payable.should == 0
33
+ charge.void?.should == false
34
+ end
35
+
36
+ it "parses events" do
37
+ charge = Affirm::Charge.retrieve(id)
38
+ events = charge.events
39
+
40
+ events.length.should == 1
41
+ events.first.type.should == "auth"
42
+ end
43
+
44
+ context "not found" do
45
+ let(:response_code) { 404 }
46
+
47
+ it "raises an error" do
48
+ expect { Affirm::Charge.retrieve(id) }.to raise_error(Affirm::ResourceNotFoundError)
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "self.create" do
54
+ let(:request_method) { :post }
55
+ let(:request_url) { "#{TEST_URL}/charges" }
56
+ let(:response_body) { load_fixture("charges/create.json") }
57
+
58
+ it "returns a charge" do
59
+ charge = Affirm::Charge.create("token")
60
+
61
+ charge.should be_a Affirm::Charge
62
+ charge.id.should == id
63
+ end
64
+
65
+ it "sends the correct body" do
66
+ charge = Affirm::Charge.create("token")
67
+
68
+ expect(WebMock).to have_requested(request_method, request_url).with(body: {
69
+ checkout_token: "token"
70
+ }.to_json)
71
+ end
72
+
73
+ context "failed response" do
74
+ let(:response_code) { 422 }
75
+ let(:response_body) { load_fixture("charges/invalid_request.json") }
76
+
77
+ it "raises an error" do
78
+ expect { Affirm::Charge.create("token") }.to raise_error(Affirm::Error)
79
+ end
80
+ end
81
+ end
82
+
83
+ describe "capture" do
84
+ let(:request_method) { :post }
85
+ let(:request_url) { "#{TEST_URL}/charges/#{id}/capture" }
86
+ let(:response_body) { load_fixture("charges/capture.json") }
87
+
88
+ it "POSTs to the capture url" do
89
+ charge.capture
90
+
91
+ expect(WebMock).to have_requested(request_method, request_url)
92
+ end
93
+
94
+ it "optionally allows tracking params" do
95
+ params = { order_id: "order_id", shipping_carrier: "carrier", shipping_confirmation: "confirmation" }
96
+ charge.capture(params)
97
+
98
+ expect(WebMock).to have_requested(request_method, request_url).with(body: params.to_json)
99
+ end
100
+
101
+ it "adds the event to the charge" do
102
+ expect { charge.capture }.to change { charge.events.length }.by(1)
103
+
104
+ charge.events.last.type.should == "capture"
105
+ end
106
+
107
+ it "returns an event" do
108
+ charge.capture.should be_a Affirm::ChargeEvent
109
+ end
110
+
111
+ context "failed response" do
112
+ let(:response_code) { 422 }
113
+ let(:response_body) { load_fixture("charges/invalid_request.json") }
114
+
115
+ it "raises an error" do
116
+ expect { charge.capture }.to raise_error(Affirm::Error)
117
+ end
118
+ end
119
+ end
120
+
121
+ describe "void" do
122
+ let(:request_method) { :post }
123
+ let(:request_url) { "#{TEST_URL}/charges/#{id}/void" }
124
+ let(:response_body) { load_fixture("charges/void.json") }
125
+
126
+ it "POSTs to the void url" do
127
+ charge.void
128
+
129
+ expect(WebMock).to have_requested(request_method, request_url)
130
+ end
131
+
132
+ it "adds the event to the charge" do
133
+ expect { charge.void }.to change { charge.events.length }.by(1)
134
+
135
+ charge.events.last.type.should == "void"
136
+ end
137
+
138
+ it "returns an event" do
139
+ charge.void.should be_a Affirm::ChargeEvent
140
+ end
141
+
142
+ context "failed response" do
143
+ let(:response_code) { 422 }
144
+ let(:response_body) { load_fixture("charges/invalid_request.json") }
145
+
146
+ it "raises an error" do
147
+ expect { charge.void }.to raise_error(Affirm::Error)
148
+ end
149
+ end
150
+ end
151
+
152
+ describe "refund" do
153
+ let(:request_method) { :post }
154
+ let(:request_url) { "#{TEST_URL}/charges/#{id}/refund" }
155
+ let(:response_body) { load_fixture("charges/refund.json") }
156
+
157
+ it "POSTs to the refund url" do
158
+ charge.refund
159
+
160
+ expect(WebMock).to have_requested(request_method, request_url)
161
+ end
162
+
163
+ it "adds the event to the charge" do
164
+ expect { charge.refund }.to change { charge.events.length }.by(1)
165
+
166
+ charge.events.last.type.should == "refund"
167
+ end
168
+
169
+ it "returns an event" do
170
+ charge.refund.should be_a Affirm::ChargeEvent
171
+ end
172
+
173
+ context "with amount" do
174
+ it "sends the amount" do
175
+ charge.refund(amount: 100)
176
+
177
+ expect(WebMock).to have_requested(request_method, request_url).with(body: {
178
+ amount: 100
179
+ }.to_json)
180
+ end
181
+ end
182
+
183
+ context "failed response" do
184
+ let(:response_code) { 422 }
185
+ let(:response_body) { load_fixture("charges/invalid_request.json") }
186
+
187
+ it "raises an error" do
188
+ expect { charge.refund }.to raise_error(Affirm::Error)
189
+ end
190
+ end
191
+ end
192
+
193
+ describe "update" do
194
+ let(:request_method) { :post }
195
+ let(:request_url) { "#{TEST_URL}/charges/#{id}/update" }
196
+ let(:response_body) { load_fixture("charges/update.json") }
197
+
198
+ it "POSTs to the update url" do
199
+ charge.update
200
+
201
+ expect(WebMock).to have_requested(request_method, request_url)
202
+ end
203
+
204
+ it "optionally allows params" do
205
+ params = { order_id: "order_id", shipping_carrier: "carrier", shipping_confirmation: "confirmation" }
206
+ charge.update(params)
207
+
208
+ expect(WebMock).to have_requested(request_method, request_url).with(body: params.to_json)
209
+ end
210
+
211
+ it "adds the event to the charge" do
212
+ expect { charge.update }.to change { charge.events.length }.by(1)
213
+
214
+ charge.events.last.type.should == "update"
215
+ end
216
+
217
+ it "returns an event" do
218
+ charge.update.should be_a Affirm::ChargeEvent
219
+ end
220
+
221
+ context "failed response" do
222
+ let(:response_code) { 422 }
223
+ let(:response_body) { load_fixture("charges/invalid_request.json") }
224
+
225
+ it "raises an error" do
226
+ expect { charge.update }.to raise_error(Affirm::Error)
227
+ end
228
+ end
229
+ end
230
+
231
+ context "with specified client" do
232
+ let(:client) { Affirm::Client.new(public_key: "other_public", secret_key: "other_secret") }
233
+
234
+ let(:request_method) { :get }
235
+ let(:response_body) { load_fixture("charges/retrieve.json") }
236
+ let(:request_url) { /.*other_public:other_secret.*/ }
237
+
238
+ it "uses the client's creds" do
239
+ Affirm::Charge.retrieve(id, client: client)
240
+ end
241
+ end
242
+ end
data/spec/client_spec.rb CHANGED
@@ -54,10 +54,6 @@ describe Affirm::Client do
54
54
  end
55
55
  end
56
56
  end
57
-
58
- context "authentication error" do
59
-
60
- end
61
57
  end
62
58
 
63
59
  describe "get" do
@@ -137,5 +133,16 @@ describe Affirm::Client do
137
133
  expect { client.get("testpath") }.to raise_error(Affirm::ResourceNotFoundError)
138
134
  end
139
135
  end
136
+
137
+ context "non-json response" do
138
+ before do
139
+ stub_request(:get, affirm_url).
140
+ to_return(status: 500, body: "the server is down")
141
+ end
142
+
143
+ it "doesn't blow up" do
144
+ expect { client.get("testpath") }.to raise_error(Affirm::ServerError)
145
+ end
146
+ end
140
147
  end
141
148
  end
@@ -1,5 +1,5 @@
1
1
  {
2
- "id":"TEST-ALO4-UVGR",
2
+ "id":"ABCD",
3
3
  "created":"2014-03-18T19:19:04Z",
4
4
  "currency":"USD",
5
5
  "amount":6100,
@@ -1,5 +1,5 @@
1
1
  {
2
- "id":"TEST-ALO4-UVGR",
2
+ "id":"ABCD",
3
3
  "created":"2014-03-18T19:19:04Z",
4
4
  "currency":"USD",
5
5
  "amount":6100,
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "created": "2014-10-08T23:48:04Z",
3
3
  "id": "DCPO5PP6QA9V7T60",
4
+ "type": "update",
4
5
  "order_id": "CUSTOM_ORDER_ID",
5
6
  "shipping_carrier": "USPS",
6
7
  "shipping_confirmation": "1Z23223"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: affirm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reverb.com
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-20 00:00:00.000000000 Z
11
+ date: 2015-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: typhoeus
@@ -90,20 +90,21 @@ files:
90
90
  - affirm.gemspec
91
91
  - lib/affirm.rb
92
92
  - lib/affirm/api.rb
93
- - lib/affirm/charges.rb
93
+ - lib/affirm/charge.rb
94
+ - lib/affirm/charge_event.rb
94
95
  - lib/affirm/client.rb
95
96
  - lib/affirm/errors/authentication_error.rb
96
97
  - lib/affirm/errors/error.rb
97
98
  - lib/affirm/errors/resource_not_found_error.rb
98
99
  - lib/affirm/errors/server_error.rb
99
100
  - lib/affirm/response.rb
100
- - spec/charges_spec.rb
101
+ - spec/charge_spec.rb
101
102
  - spec/client_spec.rb
102
- - spec/fixtures/charges/authorize.json
103
103
  - spec/fixtures/charges/capture.json
104
- - spec/fixtures/charges/get.json
104
+ - spec/fixtures/charges/create.json
105
105
  - spec/fixtures/charges/invalid_request.json
106
106
  - spec/fixtures/charges/refund.json
107
+ - spec/fixtures/charges/retrieve.json
107
108
  - spec/fixtures/charges/update.json
108
109
  - spec/fixtures/charges/void.json
109
110
  - spec/spec_helper.rb
@@ -1,103 +0,0 @@
1
- module Affirm
2
- class Charges
3
- def initialize(client)
4
- @client = client
5
- @namespace = "charges"
6
- end
7
-
8
- ######
9
- # GET
10
- #
11
- def get(charge_id:)
12
- make_request(charge_id, :get)
13
- end
14
-
15
- ######
16
- # AUTHORIZE
17
- #
18
- # checkout_token - (required) string. The charge token passed through the confirmation response.
19
- def authorize(checkout_token:)
20
- make_request("/", :post, checkout_token: checkout_token)
21
- end
22
-
23
- def authorize!(checkout_token:)
24
- response = authorize(checkout_token: checkout_token)
25
- assert_success(response)
26
- end
27
-
28
- ######
29
- # CAPTURE
30
- #
31
- # order_id - (optional) string. Your internal order id. This is stored for your own future reference.
32
- # shipping_carrier - (optional) string. The shipping carrier used to ship the items in the charge.
33
- # shipping_confirmation - (optional) string. The shipping confirmation for the shipment.
34
- def capture(charge_id:, order_id: nil, shipping_carrier: nil, shipping_confirmation: nil)
35
- make_request("#{charge_id}/capture", :post, {
36
- order_id: order_id,
37
- shipping_carrier: shipping_carrier,
38
- shipping_confirmation: shipping_confirmation
39
- })
40
- end
41
-
42
- def capture!(charge_id:, order_id: nil, shipping_carrier: nil, shipping_confirmation: nil)
43
- response = capture(charge_id: charge_id, order_id: order_id, shipping_carrier: shipping_carrier, shipping_confirmation: shipping_confirmation)
44
- assert_success(response)
45
- end
46
-
47
- ######
48
- # VOID
49
- #
50
- def void(charge_id:)
51
- make_request("#{charge_id}/void", :post)
52
- end
53
-
54
- def void!(charge_id:)
55
- response = void(charge_id: charge_id)
56
- assert_success(response)
57
- end
58
-
59
- ######
60
- # REFUND
61
- #
62
- # amount - (optional) integer or null. The amount to refund in cents. The default amount is the remaining balance on the charge.
63
- def refund(charge_id:, amount: nil)
64
- make_request("#{charge_id}/refund", :post, amount: amount)
65
- end
66
-
67
- def refund!(charge_id:, amount: nil)
68
- response = refund(charge_id: charge_id, amount: amount)
69
- assert_success(response)
70
- end
71
-
72
- ######
73
- # UPDATE
74
- #
75
- # order_id - (optional) string. Your internal order id. This is stored for your own future reference.
76
- # shipping_carrier - (optional) string. The shipping carrier used to ship the items in the charge.
77
- # shipping_confirmation - (optional) string. The shipping confirmation for the shipment.
78
- def update(charge_id:, order_id: nil, shipping_carrier: nil, shipping_confirmation: nil)
79
- make_request("#{charge_id}/update", :post, {
80
- order_id: order_id,
81
- shipping_carrier: shipping_carrier,
82
- shipping_confirmation: shipping_confirmation
83
- })
84
- end
85
-
86
- def update!(charge_id:, order_id: nil, shipping_carrier: nil, shipping_confirmation: nil)
87
- response = update(charge_id: charge_id, order_id: order_id, shipping_carrier: shipping_carrier, shipping_confirmation: shipping_confirmation)
88
- assert_success(response)
89
- end
90
-
91
- private
92
-
93
- def make_request(path, method, data={})
94
- @client.make_request(File.join(@namespace, path), method, data)
95
- end
96
-
97
- def assert_success(response)
98
- raise Affirm::Error.from_response(response) if response.error?
99
-
100
- response
101
- end
102
- end
103
- end
data/spec/charges_spec.rb DELETED
@@ -1,170 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Affirm::Charges do
4
- let!(:request) do
5
- stub_request(request_method, request_url).to_return(status: response_code, body: response_body)
6
- end
7
-
8
- let(:response_code) { 200 }
9
-
10
- describe "self.get" do
11
- let(:request_method) { :get }
12
- let(:request_url) { "#{TEST_URL}/charges/ABCD" }
13
- let(:response_body) { load_fixture("charges/get.json") }
14
-
15
- it "is successful" do
16
- response = Affirm::API.charges.get(charge_id: "ABCD")
17
- response.should be_success
18
- response.body["amount"].should == 6100
19
- end
20
- end
21
-
22
- describe "self.authorize" do
23
- let(:request_method) { :post }
24
- let(:request_url) { "#{TEST_URL}/charges/" }
25
- let(:response_body) { load_fixture("charges/authorize.json") }
26
-
27
- it "is successful" do
28
- response = Affirm::API.charges.authorize(checkout_token: "token")
29
- response.should be_success
30
- end
31
-
32
- it "sends the correct body" do
33
- Affirm::API.charges.authorize(checkout_token: "token")
34
-
35
- expect(WebMock).to have_requested(request_method, request_url).with(body: {
36
- checkout_token: "token"
37
- }.to_json)
38
- end
39
-
40
- context "bang method" do
41
- let(:response_code) { 422 }
42
- let(:response_body) { load_fixture("charges/invalid_request.json") }
43
-
44
- it "raises an error on failure" do
45
- expect { Affirm::API.charges.authorize!(checkout_token: "token") }.to raise_error(Affirm::Error)
46
- end
47
- end
48
- end
49
-
50
- describe "self.capture" do
51
- let(:request_method) { :post }
52
- let(:request_url) { "#{TEST_URL}/charges/ABCD/capture" }
53
- let(:response_body) { load_fixture("charges/capture.json") }
54
-
55
- it "is successful" do
56
- response = Affirm::API.charges.capture(charge_id: "ABCD")
57
- response.should be_success
58
- end
59
-
60
- it "optionally allows tracking params" do
61
- params = { order_id: "order_id", shipping_carrier: "carrier", shipping_confirmation: "confirmation" }
62
- Affirm::API.charges.capture({charge_id: "ABCD"}.merge(params))
63
-
64
- expect(WebMock).to have_requested(request_method, request_url).with(body: params.to_json)
65
- end
66
-
67
- context "bang method" do
68
- let(:response_code) { 422 }
69
- let(:response_body) { load_fixture("charges/invalid_request.json") }
70
-
71
- it "raises an error on failure" do
72
- expect { Affirm::API.charges.capture!(charge_id: "ABCD") }.to raise_error(Affirm::Error)
73
- end
74
- end
75
- end
76
-
77
- describe "self.void" do
78
- let(:request_method) { :post }
79
- let(:request_url) { "#{TEST_URL}/charges/ABCD/void" }
80
- let(:response_body) { load_fixture("charges/void.json") }
81
-
82
- it "is successful" do
83
- response = Affirm::API.charges.void(charge_id: "ABCD")
84
- response.should be_success
85
- end
86
-
87
- context "bang method" do
88
- let(:response_code) { 422 }
89
- let(:response_body) { load_fixture("charges/invalid_request.json") }
90
-
91
- it "raises an error on failure" do
92
- expect { Affirm::API.charges.void!(charge_id: "ABCD") }.to raise_error(Affirm::Error)
93
- end
94
- end
95
- end
96
-
97
- describe "self.refund" do
98
- let(:request_method) { :post }
99
- let(:request_url) { "#{TEST_URL}/charges/ABCD/refund" }
100
- let(:response_body) { load_fixture("charges/refund.json") }
101
-
102
- it "is successful" do
103
- response = Affirm::API.charges.refund(charge_id: "ABCD")
104
- response.should be_success
105
- end
106
-
107
- context "with amount" do
108
- it "sends the correct body" do
109
- Affirm::API.charges.refund(charge_id: "ABCD", amount: 100)
110
-
111
- expect(WebMock).to have_requested(request_method, request_url).with(body: {
112
- amount: 100
113
- }.to_json)
114
- end
115
- end
116
-
117
- context "bang method" do
118
- let(:response_code) { 422 }
119
- let(:response_body) { load_fixture("charges/invalid_request.json") }
120
-
121
- it "raises an error on failure" do
122
- expect { Affirm::API.charges.refund!(charge_id: "ABCD") }.to raise_error(Affirm::Error)
123
- end
124
- end
125
- end
126
-
127
- describe "self.update" do
128
- let(:request_method) { :post }
129
- let(:request_url) { "#{TEST_URL}/charges/ABCD/update" }
130
- let(:response_body) { load_fixture("charges/update.json") }
131
-
132
- it "is successful" do
133
- response = Affirm::API.charges.update(charge_id: "ABCD", order_id: "order_id", shipping_carrier: "carrier", shipping_confirmation: "confirmation")
134
- response.should be_success
135
- end
136
-
137
- it "sends the correct body" do
138
- params = { order_id: "order_id", shipping_carrier: "carrier", shipping_confirmation: "confirmation" }
139
- Affirm::API.charges.update({charge_id: "ABCD"}.merge(params))
140
-
141
- expect(WebMock).to have_requested(request_method, request_url).with(body: params.to_json)
142
- end
143
-
144
- it "doesn't require the params" do
145
- response = Affirm::API.charges.update(charge_id: "ABCD")
146
- response.should be_success
147
- end
148
-
149
- context "bang method" do
150
- let(:response_code) { 422 }
151
- let(:response_body) { load_fixture("charges/invalid_request.json") }
152
-
153
- it "raises an error on failure" do
154
- expect { Affirm::API.charges.update!(charge_id: "ABCD") }.to raise_error(Affirm::Error)
155
- end
156
- end
157
- end
158
-
159
- context "with specified client" do
160
- let(:client) { Affirm::Client.new(public_key: "other_public", secret_key: "other_secret") }
161
-
162
- let(:request_method) { :get }
163
- let(:response_body) { load_fixture("charges/get.json") }
164
- let(:request_url) { /.*other_public:other_secret.*/ }
165
-
166
- it "uses the client's creds" do
167
- described_class.new(client).get(charge_id: "ABCD")
168
- end
169
- end
170
- end