affirm 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +53 -51
- data/affirm.gemspec +1 -1
- data/lib/affirm/api.rb +0 -4
- data/lib/affirm/charge.rb +115 -0
- data/lib/affirm/charge_event.rb +20 -0
- data/lib/affirm/client.rb +9 -0
- data/lib/affirm/errors/error.rb +6 -2
- data/lib/affirm/response.rb +5 -3
- data/lib/affirm.rb +2 -1
- data/spec/charge_spec.rb +242 -0
- data/spec/client_spec.rb +11 -4
- data/spec/fixtures/charges/{authorize.json → create.json} +1 -1
- data/spec/fixtures/charges/{get.json → retrieve.json} +1 -1
- data/spec/fixtures/charges/update.json +1 -0
- metadata +7 -6
- data/lib/affirm/charges.rb +0 -103
- data/spec/charges_spec.rb +0 -170
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39c1e3c767578030a0b0d4040f1369a0984537dc
|
4
|
+
data.tar.gz: 41fe7e6a858817d7bb521c68dcc3238457e347e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
12
|
+
gem 'affirm'
|
12
13
|
```
|
13
|
-
and `bundle install`.
|
14
14
|
|
15
|
-
|
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
|
-
|
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::
|
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
|
-
###
|
36
|
+
### Retrieving a charge
|
37
|
+
|
38
38
|
```ruby
|
39
|
-
Affirm::
|
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
|
-
|
46
|
-
|
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
|
-
|
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
|
-
|
60
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
97
|
-
|
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::
|
103
|
-
rescue Affirm::
|
104
|
-
Logger.info e.
|
105
|
-
Logger.info e.
|
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
|
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
@@ -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)
|
data/lib/affirm/errors/error.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/affirm/response.rb
CHANGED
@@ -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
|
-
@
|
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(@
|
20
|
+
JSON.parse(@raw_body)
|
21
|
+
rescue JSON::ParserError
|
22
|
+
{}
|
21
23
|
end
|
22
24
|
|
23
25
|
def type
|
data/lib/affirm.rb
CHANGED
data/spec/charge_spec.rb
ADDED
@@ -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
|
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
|
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-
|
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/
|
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/
|
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/
|
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
|
data/lib/affirm/charges.rb
DELETED
@@ -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
|