stripe 1.18.0 → 1.19.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,9 @@
1
+ === 1.19.0 2015-02-15
2
+
3
+ * Support for new Transfers /reversals endpoint
4
+ * Account retrieval now optionally accepts an account ID
5
+ * Better support for passing custom headers, like Stripe-Account, through requests
6
+
1
7
  === 1.18.0 2015-01-21
2
8
 
3
9
  * 1 major enhancement:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.18.0
1
+ 1.19.0
@@ -14,6 +14,7 @@ require 'stripe/api_operations/create'
14
14
  require 'stripe/api_operations/update'
15
15
  require 'stripe/api_operations/delete'
16
16
  require 'stripe/api_operations/list'
17
+ require 'stripe/api_operations/request'
17
18
 
18
19
  # Resources
19
20
  require 'stripe/util'
@@ -40,6 +41,7 @@ require 'stripe/card'
40
41
  require 'stripe/subscription'
41
42
  require 'stripe/application_fee'
42
43
  require 'stripe/refund'
44
+ require 'stripe/reversal'
43
45
  require 'stripe/application_fee_refund'
44
46
  require 'stripe/bitcoin_receiver'
45
47
  require 'stripe/bitcoin_transaction'
@@ -56,6 +58,7 @@ module Stripe
56
58
  DEFAULT_CA_BUNDLE_PATH = File.dirname(__FILE__) + '/data/ca-certificates.crt'
57
59
  @api_base = 'https://api.stripe.com'
58
60
  @connect_base = 'https://connect.stripe.com'
61
+ @uploads_base = 'https://uploads.stripe.com'
59
62
 
60
63
  @ssl_bundle_path = DEFAULT_CA_BUNDLE_PATH
61
64
  @verify_ssl_certs = true
@@ -63,7 +66,7 @@ module Stripe
63
66
 
64
67
 
65
68
  class << self
66
- attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version, :connect_base
69
+ attr_accessor :api_key, :api_base, :verify_ssl_certs, :api_version, :connect_base, :uploads_base
67
70
  end
68
71
 
69
72
  def self.api_url(url='', api_base_url=nil)
@@ -74,17 +77,17 @@ module Stripe
74
77
  api_base_url = api_base_url || @api_base
75
78
 
76
79
  unless api_key ||= @api_key
77
- raise AuthenticationError.new('No API key provided. ' +
78
- 'Set your API key using "Stripe.api_key = <API-KEY>". ' +
79
- 'You can generate API keys from the Stripe web interface. ' +
80
- 'See https://stripe.com/api for details, or email support@stripe.com ' +
80
+ raise AuthenticationError.new('No API key provided. ' \
81
+ 'Set your API key using "Stripe.api_key = <API-KEY>". ' \
82
+ 'You can generate API keys from the Stripe web interface. ' \
83
+ 'See https://stripe.com/api for details, or email support@stripe.com ' \
81
84
  'if you have any questions.')
82
85
  end
83
86
 
84
87
  if api_key =~ /\s/
85
- raise AuthenticationError.new('Your API key is invalid, as it contains ' +
86
- 'whitespace. (HINT: You can double-check your API key from the ' +
87
- 'Stripe web interface. See https://stripe.com/api for details, or ' +
88
+ raise AuthenticationError.new('Your API key is invalid, as it contains ' \
89
+ 'whitespace. (HINT: You can double-check your API key from the ' \
90
+ 'Stripe web interface. See https://stripe.com/api for details, or ' \
88
91
  'email support@stripe.com if you have any questions.)')
89
92
  end
90
93
 
@@ -148,13 +151,13 @@ module Stripe
148
151
 
149
152
  def self.ssl_preflight_passed?
150
153
  if !verify_ssl_certs && !@no_verify
151
- $stderr.puts "WARNING: Running without SSL cert verification. " +
154
+ $stderr.puts "WARNING: Running without SSL cert verification. " \
152
155
  "Execute 'Stripe.verify_ssl_certs = true' to enable verification."
153
156
 
154
157
  @no_verify = true
155
158
 
156
159
  elsif !Util.file_readable(@ssl_bundle_path) && !@no_bundle
157
- $stderr.puts "WARNING: Running without SSL cert verification " +
160
+ $stderr.puts "WARNING: Running without SSL cert verification " \
158
161
  "because #{@ssl_bundle_path} isn't readable"
159
162
 
160
163
  @no_bundle = true
@@ -1,9 +1,35 @@
1
1
  module Stripe
2
- class Account < SingletonAPIResource
2
+ class Account < APIResource
3
+ include Stripe::APIOperations::Create
4
+ include Stripe::APIOperations::List
5
+ include Stripe::APIOperations::Update
6
+
7
+ def url
8
+ if self['id']
9
+ super
10
+ else
11
+ "/v1/account"
12
+ end
13
+ end
14
+
15
+ # @override To make id optional
16
+ def self.retrieve(id=nil, opts={})
17
+ # Account used to be a singleton, where this method's signature was `(opts={})`.
18
+ # For the sake of not breaking folks who pass in an OAuth key in opts, let's lurkily
19
+ # string match for it.
20
+ if opts == {} && id.is_a?(String) && id.start_with?('sk_')
21
+ # `super` properly assumes a String opts is the apiKey and normalizes as expected.
22
+ opts = id
23
+ id = nil
24
+ end
25
+ super(id, opts)
26
+ end
27
+
3
28
  def deauthorize(client_id, opts={})
4
- api_key, headers = Util.parse_opts(opts)
5
- response, api_key = Stripe.request(:post, '/oauth/deauthorize', api_key, { 'client_id' => client_id, 'stripe_user_id' => self.id }, headers, Stripe.connect_base)
6
- Util.convert_to_stripe_object(response, api_key)
29
+ opts = {:api_base => Stripe.connect_base}.merge(Util.normalize_opts(opts))
30
+ response, opts = request(:post, '/oauth/deauthorize', { 'client_id' => client_id, 'stripe_user_id' => self.id }, opts)
31
+ opts.delete(:api_base) # the api_base here is a one-off, don't persist it
32
+ Util.convert_to_stripe_object(response, opts)
7
33
  end
8
34
  end
9
35
  end
@@ -3,9 +3,8 @@ module Stripe
3
3
  module Create
4
4
  module ClassMethods
5
5
  def create(params={}, opts={})
6
- api_key, headers = Util.parse_opts(opts)
7
- response, api_key = Stripe.request(:post, self.url, api_key, params, headers)
8
- Util.convert_to_stripe_object(response, api_key)
6
+ response, opts = request(:post, url, params, opts)
7
+ Util.convert_to_stripe_object(response, opts)
9
8
  end
10
9
  end
11
10
 
@@ -1,10 +1,10 @@
1
1
  module Stripe
2
2
  module APIOperations
3
3
  module Delete
4
- def delete(params = {}, opts={})
5
- api_key, headers = Util.parse_opts(opts)
6
- response, api_key = Stripe.request(:delete, url, api_key || @api_key, params, headers)
7
- refresh_from(response, api_key)
4
+ def delete(params={}, opts={})
5
+ opts = Util.normalize_opts(opts)
6
+ response, opts = request(:delete, url, params, opts)
7
+ refresh_from(response, opts)
8
8
  end
9
9
  end
10
10
  end
@@ -3,9 +3,9 @@ module Stripe
3
3
  module List
4
4
  module ClassMethods
5
5
  def all(filters={}, opts={})
6
- api_key, headers = Util.parse_opts(opts)
7
- response, api_key = Stripe.request(:get, url, api_key, filters, headers)
8
- Util.convert_to_stripe_object(response, api_key)
6
+ opts = Util.normalize_opts(opts)
7
+ response, opts = request(:get, url, filters, opts)
8
+ Util.convert_to_stripe_object(response, opts)
9
9
  end
10
10
  end
11
11
 
@@ -0,0 +1,41 @@
1
+ module Stripe
2
+ module APIOperations
3
+ module Request
4
+ module ClassMethods
5
+ OPTS_KEYS_TO_PERSIST = Set[:api_key, :api_base, :stripe_account, :stripe_version]
6
+
7
+ def request(method, url, params={}, opts={})
8
+ opts = Util.normalize_opts(opts)
9
+
10
+ headers = opts.clone
11
+ api_key = headers.delete(:api_key)
12
+ api_base = headers.delete(:api_base)
13
+ # Assume all remaining opts must be headers
14
+
15
+ response, opts[:api_key] = Stripe.request(method, url, api_key, params, headers, api_base)
16
+
17
+ # Hash#select returns an array before 1.9
18
+ opts_to_persist = {}
19
+ opts.each do |k, v|
20
+ if OPTS_KEYS_TO_PERSIST.include?(k)
21
+ opts_to_persist[k] = v
22
+ end
23
+ end
24
+
25
+ [response, opts_to_persist]
26
+ end
27
+ end
28
+
29
+ def self.included(base)
30
+ base.extend(ClassMethods)
31
+ end
32
+
33
+ protected
34
+
35
+ def request(method, url, params={}, opts={})
36
+ opts = @opts.merge(Util.normalize_opts(opts))
37
+ self.class.request(method, url, params, opts)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,8 +1,8 @@
1
1
  module Stripe
2
2
  module APIOperations
3
3
  module Update
4
- def save(opts={})
5
- values = serialize_params(self).merge(opts)
4
+ def save(params={})
5
+ values = serialize_params(self).merge(params)
6
6
 
7
7
  if @values[:metadata]
8
8
  values[:metadata] = serialize_metadata
@@ -11,8 +11,8 @@ module Stripe
11
11
  if values.length > 0
12
12
  values.delete(:id)
13
13
 
14
- response, api_key = Stripe.request(:post, url, @api_key, values)
15
- refresh_from(response, api_key)
14
+ response, opts = request(:post, url, values)
15
+ refresh_from(response, opts)
16
16
  end
17
17
  self
18
18
  end
@@ -1,5 +1,7 @@
1
1
  module Stripe
2
2
  class APIResource < StripeObject
3
+ include Stripe::APIOperations::Request
4
+
3
5
  def self.class_name
4
6
  self.name.split('::')[-1]
5
7
  end
@@ -19,12 +21,13 @@ module Stripe
19
21
  end
20
22
 
21
23
  def refresh
22
- response, api_key = Stripe.request(:get, url, @api_key, @retrieve_options)
23
- refresh_from(response, api_key)
24
+ response, opts = request(:get, url, @retrieve_params)
25
+ refresh_from(response, opts)
24
26
  end
25
27
 
26
- def self.retrieve(id, api_key=nil)
27
- instance = self.new(id, api_key)
28
+ def self.retrieve(id, opts=nil)
29
+ opts = Util.normalize_opts(opts)
30
+ instance = self.new(id, opts)
28
31
  instance.refresh
29
32
  instance
30
33
  end
@@ -7,9 +7,8 @@ module Stripe
7
7
  end
8
8
 
9
9
  def refund(params={}, opts={})
10
- api_key, headers = Util.parse_opts(opts)
11
- response, api_key = Stripe.request(:post, refund_url, api_key || @api_key, params, headers)
12
- refresh_from(response, api_key)
10
+ response, opts = request(:post, refund_url, params, opts)
11
+ refresh_from(response, opts)
13
12
  end
14
13
 
15
14
  private
@@ -12,7 +12,7 @@ module Stripe
12
12
  end
13
13
  end
14
14
 
15
- def self.retrieve(id, api_key=nil)
15
+ def self.retrieve(id, opts=nil)
16
16
  raise NotImplementedError.new("Cards cannot be retrieved without a customer ID. Retrieve a card using customer.cards.retrieve('card_id')")
17
17
  end
18
18
  end
@@ -39,9 +39,9 @@ module Stripe
39
39
  if blacklisted_certs = BLACKLIST[uri.host]
40
40
  if blacklisted_certs.include?(fingerprint)
41
41
  raise APIConnectionError.new(
42
- "Invalid server certificate. You tried to connect to a server that" +
43
- "has a revoked SSL certificate, which means we cannot securely send" +
44
- "data to that server. Please email support@stripe.com if you need" +
42
+ "Invalid server certificate. You tried to connect to a server that" \
43
+ "has a revoked SSL certificate, which means we cannot securely send" \
44
+ "data to that server. Please email support@stripe.com if you need" \
45
45
  "help connecting to the correct API server."
46
46
  )
47
47
  end
@@ -5,48 +5,40 @@ module Stripe
5
5
  include Stripe::APIOperations::Update
6
6
 
7
7
  def refund(params={}, opts={})
8
- api_key, headers = Util.parse_opts(opts)
9
- response, api_key = Stripe.request(
10
- :post, refund_url, api_key || @api_key, params, headers)
11
- refresh_from(response, api_key)
8
+ response, opts = request(:post, refund_url, params, opts)
9
+ refresh_from(response, opts)
12
10
  end
13
11
 
14
12
  def capture(params={}, opts={})
15
- api_key, headers = Util.parse_opts(opts)
16
- response, api_key = Stripe.request(
17
- :post, capture_url, api_key || @api_key, params, headers)
18
- refresh_from(response, api_key)
13
+ response, opts = request(:post, capture_url, params, opts)
14
+ refresh_from(response, opts)
19
15
  end
20
16
 
21
17
  def update_dispute(params={}, opts={})
22
- api_key, headers = Util.parse_opts(opts)
23
- response, api_key = Stripe.request(
24
- :post, dispute_url, api_key || @api_key, params, headers)
25
- refresh_from({ :dispute => response }, api_key, true)
18
+ response, opts = request(:post, dispute_url, params, opts)
19
+ refresh_from({ :dispute => response }, opts, true)
26
20
  dispute
27
21
  end
28
22
 
29
23
  def close_dispute(params={}, opts={})
30
- api_key, headers = Util.parse_opts(opts)
31
- response, api_key = Stripe.request(
32
- :post, close_dispute_url, api_key || @api_key, params, headers)
33
- refresh_from(response, api_key)
24
+ response, opts = request(:post, close_dispute_url, params, opts)
25
+ refresh_from(response, opts)
34
26
  end
35
27
 
36
28
  def mark_as_fraudulent
37
29
  params = {
38
30
  :fraud_details => { :user_report => 'fraudulent' }
39
31
  }
40
- response, api_key = Stripe.request(:post, url, @api_key, params)
41
- refresh_from(response, api_key)
32
+ response, opts = request(:post, url, params)
33
+ refresh_from(response, opts)
42
34
  end
43
35
 
44
36
  def mark_as_safe
45
37
  params = {
46
38
  :fraud_details => { :user_report => 'safe' }
47
39
  }
48
- response, api_key = Stripe.request(:post, url, @api_key, params)
49
- refresh_from(response, api_key)
40
+ response, opts = request(:post, url, params)
41
+ refresh_from(response, opts)
50
42
  end
51
43
 
52
44
  private
@@ -6,58 +6,52 @@ module Stripe
6
6
  include Stripe::APIOperations::List
7
7
 
8
8
  def add_invoice_item(params, opts={})
9
- opts[:api_key] = @api_key
9
+ opts = @opts.merge(Util.normalize_opts(opts))
10
10
  InvoiceItem.create(params.merge(:customer => id), opts)
11
11
  end
12
12
 
13
13
  def invoices
14
- Invoice.all({ :customer => id }, @api_key)
14
+ Invoice.all({ :customer => id }, @opts)
15
15
  end
16
16
 
17
17
  def invoice_items
18
- InvoiceItem.all({ :customer => id }, @api_key)
18
+ InvoiceItem.all({ :customer => id }, @opts)
19
19
  end
20
20
 
21
21
  def upcoming_invoice
22
- Invoice.upcoming({ :customer => id }, @api_key)
22
+ Invoice.upcoming({ :customer => id }, @opts)
23
23
  end
24
24
 
25
25
  def charges
26
- Charge.all({ :customer => id }, @api_key)
26
+ Charge.all({ :customer => id }, @opts)
27
27
  end
28
28
 
29
29
  def create_upcoming_invoice(params={}, opts={})
30
- opts[:api_key] = @api_key
30
+ opts = @opts.merge(Util.normalize_opts(opts))
31
31
  Invoice.create(params.merge(:customer => id), opts)
32
32
  end
33
33
 
34
34
  def cancel_subscription(params={}, opts={})
35
- api_key, headers = Util.parse_opts(opts)
36
- response, api_key = Stripe.request(
37
- :delete, subscription_url, api_key || @api_key, params, headers)
38
- refresh_from({ :subscription => response }, api_key, true)
35
+ response, opts = request(:delete, subscription_url, params, opts)
36
+ refresh_from({ :subscription => response }, opts, true)
39
37
  subscription
40
38
  end
41
39
 
42
40
  def update_subscription(params={}, opts={})
43
- api_key, headers = Util.parse_opts(opts)
44
- response, api_key = Stripe.request(
45
- :post, subscription_url, api_key || @api_key, params, headers)
46
- refresh_from({ :subscription => response }, api_key, true)
41
+ response, opts = request(:post, subscription_url, params, opts)
42
+ refresh_from({ :subscription => response }, opts, true)
47
43
  subscription
48
44
  end
49
45
 
50
46
  def create_subscription(params={}, opts={})
51
- api_key, headers = Util.parse_opts(opts)
52
- response, api_key = Stripe.request(
53
- :post, subscriptions_url, api_key || @api_key, params, headers)
54
- refresh_from({ :subscription => response }, api_key, true)
47
+ response, opts = request(:post, subscriptions_url, params, opts)
48
+ refresh_from({ :subscription => response }, opts, true)
55
49
  subscription
56
50
  end
57
51
 
58
52
  def delete_discount
59
- Stripe.request(:delete, discount_url, @api_key)
60
- refresh_from({ :discount => nil }, api_key, true)
53
+ _, opts = request(:delete, discount_url)
54
+ refresh_from({ :discount => nil }, opts, true)
61
55
  end
62
56
 
63
57
  private
@@ -1,34 +1,22 @@
1
1
  module Stripe
2
2
  class FileUpload < APIResource
3
- UPLOADS_API_BASE = "https://uploads.stripe.com"
4
-
5
3
  def self.url
6
4
  "/v1/files"
7
5
  end
8
6
 
9
- def self.request_headers
10
- {
7
+ def self.create(params={}, opts={})
8
+ opts = {
11
9
  :content_type => 'multipart/form-data',
12
- }
13
- end
14
-
15
- def self.create(params={}, api_key=nil)
16
- response, api_key = Stripe.request(
17
- :post, self.url, api_key, params, self.request_headers, UPLOADS_API_BASE)
18
- Util.convert_to_stripe_object(response, api_key)
10
+ :api_base => Stripe::uploads_base
11
+ }.merge(opts)
12
+ response, opts = request(:post, url, params, opts)
13
+ Util.convert_to_stripe_object(response, opts)
19
14
  end
20
15
 
21
16
  def self.all(filters={}, opts={})
22
- api_key, headers = Util.parse_opts(opts)
23
- response, api_key = Stripe.request(
24
- :get, self.url, api_key, filters, headers, UPLOADS_API_BASE)
25
- Util.convert_to_stripe_object(response, api_key)
26
- end
27
-
28
- def refresh
29
- response, api_key = Stripe.request(
30
- :get, url, @api_key, @retrieve_options, self.class.request_headers, UPLOADS_API_BASE)
31
- refresh_from(response, api_key)
17
+ opts = {:api_base => Stripe::uploads_base}.merge(opts)
18
+ response, opts = request(:get, url, filters, opts)
19
+ Util.convert_to_stripe_object(response, opts)
32
20
  end
33
21
  end
34
22
  end
@@ -4,14 +4,15 @@ module Stripe
4
4
  include Stripe::APIOperations::Update
5
5
  include Stripe::APIOperations::Create
6
6
 
7
- def self.upcoming(params, api_key = nil)
8
- response, api_key = Stripe.request(:get, upcoming_url, api_key, params)
9
- Util.convert_to_stripe_object(response, api_key)
7
+ def self.upcoming(params, opts={})
8
+ opts = Util.normalize_opts(opts)
9
+ response, api_key = Stripe.request(:get, upcoming_url, opts, params)
10
+ Util.convert_to_stripe_object(response, opts)
10
11
  end
11
12
 
12
13
  def pay
13
- response, api_key = Stripe.request(:post, pay_url, @api_key)
14
- refresh_from(response, api_key)
14
+ response, opts = Stripe.request(:post, pay_url, @opts, {})
15
+ refresh_from(response, opts)
15
16
  end
16
17
 
17
18
  private
@@ -1,5 +1,6 @@
1
1
  module Stripe
2
2
  class ListObject < StripeObject
3
+ include Stripe::APIOperations::Request
3
4
 
4
5
  def [](k)
5
6
  case k
@@ -14,24 +15,19 @@ module Stripe
14
15
  self.data.each(&blk)
15
16
  end
16
17
 
17
- def retrieve(id, api_key=nil)
18
- api_key ||= @api_key
19
- response, api_key = Stripe.request(:get,"#{url}/#{CGI.escape(id)}", api_key)
20
- Util.convert_to_stripe_object(response, api_key)
18
+ def retrieve(id, opts={})
19
+ response, opts = request(:get,"#{url}/#{CGI.escape(id)}", {}, opts)
20
+ Util.convert_to_stripe_object(response, opts)
21
21
  end
22
22
 
23
23
  def create(params={}, opts={})
24
- api_key, headers = Util.parse_opts(opts)
25
- api_key ||= @api_key
26
- response, api_key = Stripe.request(:post, url, api_key, params, headers)
27
- Util.convert_to_stripe_object(response, api_key)
24
+ response, opts = request(:post, url, params, opts)
25
+ Util.convert_to_stripe_object(response, opts)
28
26
  end
29
27
 
30
28
  def all(params={}, opts={})
31
- api_key, headers = Util.parse_opts(opts)
32
- api_key ||= @api_key
33
- response, api_key = Stripe.request(:get, url, api_key, params, headers)
34
- Util.convert_to_stripe_object(response, api_key)
29
+ response, opts = request(:get, url, params, opts)
30
+ Util.convert_to_stripe_object(response, opts)
35
31
  end
36
32
  end
37
33
  end
@@ -0,0 +1,14 @@
1
+ module Stripe
2
+ class Reversal < APIResource
3
+ include Stripe::APIOperations::Update
4
+ include Stripe::APIOperations::List
5
+
6
+ def url
7
+ "#{Transfer.url}/#{CGI.escape(transfer)}/reversals/#{CGI.escape(id)}"
8
+ end
9
+
10
+ def self.retrieve(id, opts={})
11
+ raise NotImplementedError.new("Reversals cannot be retrieved without a transfer ID. Retrieve a reversal using transfer.reversals.retrieve('reversal_id')")
12
+ end
13
+ end
14
+ end
@@ -2,25 +2,24 @@ module Stripe
2
2
  class StripeObject
3
3
  include Enumerable
4
4
 
5
- attr_accessor :api_key
6
- @@permanent_attributes = Set.new([:api_key, :id])
5
+ @@permanent_attributes = Set.new([:id])
7
6
 
8
7
  # The default :id method is deprecated and isn't useful to us
9
8
  if method_defined?(:id)
10
9
  undef :id
11
10
  end
12
11
 
13
- def initialize(id=nil, api_key=nil)
12
+ def initialize(id=nil, opts={})
14
13
  # parameter overloading!
15
14
  if id.kind_of?(Hash)
16
- @retrieve_options = id.dup
17
- @retrieve_options.delete(:id)
15
+ @retrieve_params = id.dup
16
+ @retrieve_params.delete(:id)
18
17
  id = id[:id]
19
18
  else
20
- @retrieve_options = {}
19
+ @retrieve_params = {}
21
20
  end
22
21
 
23
- @api_key = api_key
22
+ @opts = opts
24
23
  @values = {}
25
24
  # This really belongs in APIResource, but not putting it there allows us
26
25
  # to have a unified inspect method
@@ -29,8 +28,8 @@ module Stripe
29
28
  @values[:id] = id if id
30
29
  end
31
30
 
32
- def self.construct_from(values, api_key=nil)
33
- self.new(values[:id], api_key).refresh_from(values, api_key)
31
+ def self.construct_from(values, opts={})
32
+ self.new(values[:id]).refresh_from(values, opts)
34
33
  end
35
34
 
36
35
  def to_s(*args)
@@ -42,9 +41,8 @@ module Stripe
42
41
  "#<#{self.class}:0x#{self.object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values)
43
42
  end
44
43
 
45
- def refresh_from(values, api_key, partial=false)
46
- @api_key = api_key
47
-
44
+ def refresh_from(values, opts, partial=false)
45
+ @opts = opts
48
46
  @previous_metadata = values[:metadata]
49
47
  removed = partial ? Set.new : Set.new(@values.keys - values.keys)
50
48
  added = Set.new(values.keys - @values.keys)
@@ -62,7 +60,7 @@ module Stripe
62
60
  @unsaved_values.delete(k)
63
61
  end
64
62
  values.each do |k, v|
65
- @values[k] = Util.convert_to_stripe_object(v, api_key)
63
+ @values[k] = Util.convert_to_stripe_object(v, @opts)
66
64
  @transient_values.delete(k)
67
65
  @unsaved_values.delete(k)
68
66
  end
@@ -106,12 +104,12 @@ module Stripe
106
104
  end
107
105
 
108
106
  def _dump(level)
109
- Marshal.dump([@values, @api_key])
107
+ Marshal.dump([@values, @opts])
110
108
  end
111
109
 
112
110
  def self._load(args)
113
- values, api_key = Marshal.load(args)
114
- construct_from(values, api_key)
111
+ values, opts = Marshal.load(args)
112
+ construct_from(values, opts)
115
113
  end
116
114
 
117
115
  if RUBY_VERSION < '1.9.2'
@@ -146,8 +144,8 @@ module Stripe
146
144
  define_method(k_eq) do |v|
147
145
  if v == ""
148
146
  raise ArgumentError.new(
149
- "You cannot set #{k} to an empty string." +
150
- "We interpret empty strings as nil in requests." +
147
+ "You cannot set #{k} to an empty string." \
148
+ "We interpret empty strings as nil in requests." \
151
149
  "You may set #{self}.#{k} = nil to delete the property.")
152
150
  end
153
151
  @values[k] = v
@@ -7,13 +7,13 @@ module Stripe
7
7
  "#{Customer.url}/#{CGI.escape(customer)}/subscriptions/#{CGI.escape(id)}"
8
8
  end
9
9
 
10
- def self.retrieve(id, api_key=nil)
10
+ def self.retrieve(id, opts=nil)
11
11
  raise NotImplementedError.new("Subscriptions cannot be retrieved without a customer ID. Retrieve a subscription using customer.subscriptions.retrieve('subscription_id')")
12
12
  end
13
13
 
14
14
  def delete_discount
15
- Stripe.request(:delete, discount_url, @api_key)
16
- refresh_from({ :discount => nil }, api_key, true)
15
+ response, opts = request(:delete, discount_url)
16
+ refresh_from({ :discount => nil }, opts, true)
17
17
  end
18
18
 
19
19
  private
@@ -21,6 +21,7 @@ module Stripe
21
21
  'list' => ListObject,
22
22
 
23
23
  # business objects
24
+ 'account' => Account,
24
25
  'application_fee' => ApplicationFee,
25
26
  'balance' => Balance,
26
27
  'balance_transaction' => BalanceTransaction,
@@ -38,18 +39,19 @@ module Stripe
38
39
  'subscription' => Subscription,
39
40
  'file_upload' => FileUpload,
40
41
  'transfer' => Transfer,
42
+ 'transfer_reversal' => Reversal,
41
43
  'bitcoin_receiver' => BitcoinReceiver,
42
44
  'bitcoin_transaction' => BitcoinTransaction
43
45
  }
44
46
  end
45
47
 
46
- def self.convert_to_stripe_object(resp, api_key)
48
+ def self.convert_to_stripe_object(resp, opts)
47
49
  case resp
48
50
  when Array
49
- resp.map { |i| convert_to_stripe_object(i, api_key) }
51
+ resp.map { |i| convert_to_stripe_object(i, opts) }
50
52
  when Hash
51
53
  # Try converting to a known object class. If none available, fall back to generic StripeObject
52
- object_classes.fetch(resp[:object], StripeObject).construct_from(resp, api_key)
54
+ object_classes.fetch(resp[:object], StripeObject).construct_from(resp, opts)
53
55
  else
54
56
  resp
55
57
  end
@@ -119,23 +121,16 @@ module Stripe
119
121
 
120
122
  # The secondary opts argument can either be a string or hash
121
123
  # Turn this value into an api_key and a set of headers
122
- def self.parse_opts(opts)
124
+ def self.normalize_opts(opts)
123
125
  case opts
124
126
  when NilClass
125
- return nil, {}
127
+ {}
126
128
  when String
127
- return opts, {}
129
+ {:api_key => opts}
128
130
  when Hash
129
- headers = {}
130
- if opts[:idempotency_key]
131
- headers[:idempotency_key] = opts[:idempotency_key]
132
- end
133
- if opts[:stripe_account]
134
- headers[:stripe_account] = opts[:stripe_account]
135
- end
136
- return opts[:api_key], headers
131
+ opts.clone
137
132
  else
138
- raise TypeError.new("parse_opts expects a string or a hash")
133
+ raise TypeError.new('normalize_opts expects a string or a hash')
139
134
  end
140
135
  end
141
136
  end
@@ -1,3 +1,3 @@
1
1
  module Stripe
2
- VERSION = '1.18.0'
2
+ VERSION = '1.19.0'
3
3
  end
@@ -20,7 +20,6 @@ spec = Gem::Specification.new do |s|
20
20
  s.add_development_dependency('shoulda', '~> 3.4.0')
21
21
  s.add_development_dependency('test-unit')
22
22
  s.add_development_dependency('rake')
23
- s.add_development_dependency('pry')
24
23
 
25
24
  s.files = `git ls-files`.split("\n")
26
25
  s.test_files = `git ls-files -- test/*`.split("\n")
@@ -4,13 +4,28 @@ module Stripe
4
4
  class AccountTest < Test::Unit::TestCase
5
5
  should "account should be retrievable" do
6
6
  resp = {:email => "test+bindings@stripe.com", :charge_enabled => false, :details_submitted => false}
7
- @mock.expects(:get).once.returns(test_response(resp))
7
+ @mock.expects(:get).
8
+ once.
9
+ with('https://api.stripe.com/v1/account', nil, nil).
10
+ returns(test_response(resp))
8
11
  a = Stripe::Account.retrieve
9
12
  assert_equal "test+bindings@stripe.com", a.email
10
13
  assert !a.charge_enabled
11
14
  assert !a.details_submitted
12
15
  end
13
16
 
17
+ should "account should be retrievable via plural endpoint" do
18
+ resp = {:email => "test+bindings@stripe.com", :charge_enabled => false, :details_submitted => false}
19
+ @mock.expects(:get).
20
+ once.
21
+ with('https://api.stripe.com/v1/accounts/acct_foo', nil, nil).
22
+ returns(test_response(resp))
23
+ a = Stripe::Account.retrieve('acct_foo')
24
+ assert_equal "test+bindings@stripe.com", a.email
25
+ assert !a.charge_enabled
26
+ assert !a.details_submitted
27
+ end
28
+
14
29
  should "be able to deauthorize an account" do
15
30
  resp = {:id => 'acct_1234', :email => "test+bindings@stripe.com", :charge_enabled => false, :details_submitted => false}
16
31
  @mock.expects(:get).once.returns(test_response(resp))
@@ -67,6 +67,23 @@ module Stripe
67
67
  end
68
68
  end
69
69
 
70
+ should "send expand on fetch properly" do
71
+ @mock.expects(:get).once.
72
+ with("#{Stripe.api_base}/v1/charges/ch_test_charge?expand[]=customer", nil, nil).
73
+ returns(test_response(test_charge))
74
+
75
+ Stripe::Charge.retrieve({:id => 'ch_test_charge', :expand => [:customer]})
76
+ end
77
+
78
+ should "preserve expand across refreshes" do
79
+ @mock.expects(:get).twice.
80
+ with("#{Stripe.api_base}/v1/charges/ch_test_charge?expand[]=customer", nil, nil).
81
+ returns(test_response(test_charge))
82
+
83
+ ch = Stripe::Charge.retrieve({:id => 'ch_test_charge', :expand => [:customer]})
84
+ ch.refresh
85
+ end
86
+
70
87
  should "send stripe account as header when set" do
71
88
  stripe_account = "acct_0000"
72
89
  Stripe.expects(:execute_request).with do |opts|
@@ -294,7 +311,6 @@ module Stripe
294
311
  @mock.expects(:get).never
295
312
  @mock.expects(:post).never
296
313
  @mock.expects(:delete).with("#{Stripe.api_base}/v1/customers/c_test_customer", nil, nil).once.returns(test_response({ "id" => "test_customer", "deleted" => true }))
297
-
298
314
  c = Stripe::Customer.construct_from(test_customer)
299
315
  c.delete
300
316
  assert_equal true, c.deleted
@@ -318,6 +334,33 @@ module Stripe
318
334
  assert c[0].card.kind_of?(Stripe::StripeObject) && c[0].card.object == 'card'
319
335
  end
320
336
 
337
+ should "passing in a stripe_account header should pass it through on call" do
338
+ Stripe.expects(:execute_request).with do |opts|
339
+ opts[:method] == :get &&
340
+ opts[:url] == "#{Stripe.api_base}/v1/customers/c_test_customer" &&
341
+ opts[:headers][:stripe_account] == 'acct_abc'
342
+ end.once.returns(test_response(test_customer))
343
+ c = Stripe::Customer.retrieve("c_test_customer", {:stripe_account => 'acct_abc'})
344
+ end
345
+
346
+ should "passing in a stripe_account header should pass it through on save" do
347
+ Stripe.expects(:execute_request).with do |opts|
348
+ opts[:method] == :get &&
349
+ opts[:url] == "#{Stripe.api_base}/v1/customers/c_test_customer" &&
350
+ opts[:headers][:stripe_account] == 'acct_abc'
351
+ end.once.returns(test_response(test_customer))
352
+ c = Stripe::Customer.retrieve("c_test_customer", {:stripe_account => 'acct_abc'})
353
+
354
+ Stripe.expects(:execute_request).with do |opts|
355
+ opts[:method] == :post &&
356
+ opts[:url] == "#{Stripe.api_base}/v1/customers/c_test_customer" &&
357
+ opts[:headers][:stripe_account] == 'acct_abc' &&
358
+ opts[:payload] == 'description=FOO'
359
+ end.once.returns(test_response(test_customer))
360
+ c.description = 'FOO'
361
+ c.save
362
+ end
363
+
321
364
  context "error checking" do
322
365
 
323
366
  should "404s should raise an InvalidRequestError" do
@@ -0,0 +1,47 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ module Stripe
4
+ class ReversalTest < Test::Unit::TestCase
5
+ should "reversals should be listable" do
6
+ @mock.expects(:get).once.returns(test_response(test_transfer))
7
+
8
+ transfer = Stripe::Transfer.retrieve('test_transfer')
9
+
10
+ assert transfer.reversals.first.kind_of?(Stripe::Reversal)
11
+ end
12
+
13
+ should "reversals should be refreshable" do
14
+ @mock.expects(:get).twice.returns(test_response(test_transfer), test_response(test_reversal(:id => 'refreshed_reversal')))
15
+
16
+ transfer = Stripe::Transfer.retrieve('test_transfer')
17
+ reversal = transfer.reversals.first
18
+ reversal.refresh
19
+
20
+ assert_equal 'refreshed_reversal', reversal.id
21
+ end
22
+
23
+ should "reversals should be updateable" do
24
+ @mock.expects(:get).once.returns(test_response(test_transfer))
25
+ @mock.expects(:post).once.returns(test_response(test_reversal(:metadata => {'key' => 'value'})))
26
+
27
+ transfer = Stripe::Transfer.retrieve('test_transfer')
28
+ reversal = transfer.reversals.first
29
+
30
+ assert_equal nil, reversal.metadata['key']
31
+
32
+ reversal.metadata['key'] = 'value'
33
+ reversal.save
34
+
35
+ assert_equal 'value', reversal.metadata['key']
36
+ end
37
+
38
+ should "create should return a new reversal" do
39
+ @mock.expects(:get).once.returns(test_response(test_transfer))
40
+ @mock.expects(:post).once.returns(test_response(test_reversal(:id => 'test_new_reversal')))
41
+
42
+ transfer = Stripe::Transfer.retrieve('test_transfer')
43
+ reversals = transfer.reversals.create(:amount => 20)
44
+ assert_equal 'test_new_reversal', reversals.id
45
+ end
46
+ end
47
+ end
@@ -10,11 +10,12 @@ module Stripe
10
10
  end
11
11
 
12
12
  should "marshal a stripe object correctly" do
13
- obj = Stripe::StripeObject.construct_from({ :id => 1, :name => 'Stripe' }, 'apikey')
13
+ obj = Stripe::StripeObject.construct_from({ :id => 1, :name => 'Stripe' }, {:api_key => 'apikey'})
14
14
  m = Marshal.load(Marshal.dump(obj))
15
15
  assert_equal 1, m.id
16
16
  assert_equal 'Stripe', m.name
17
- assert_equal 'apikey', m.api_key
17
+ expected_hash = {:api_key => 'apikey'}
18
+ assert_equal expected_hash, m.instance_variable_get('@opts')
18
19
  end
19
20
 
20
21
  should "recursively call to_hash on its values" do
@@ -25,35 +25,5 @@ module Stripe
25
25
  symbolized = Stripe::Util.symbolize_names(start)
26
26
  assert_equal(finish, symbolized)
27
27
  end
28
-
29
- should "parse a nil opts argument" do
30
- api_key, headers = Stripe::Util.parse_opts(nil)
31
- assert_equal({}, headers)
32
- assert_equal(nil, api_key)
33
- end
34
-
35
- should "parse a string opts argument" do
36
- api_key, headers = Stripe::Util.parse_opts('foo')
37
- assert_equal({}, headers)
38
- assert_equal('foo', api_key)
39
- end
40
-
41
- should "parse a hash opts argument with just api_key" do
42
- api_key, headers = Stripe::Util.parse_opts({:api_key => 'foo'})
43
- assert_equal({}, headers)
44
- assert_equal('foo', api_key)
45
- end
46
-
47
- should "parse a hash opts argument with just idempotency_key" do
48
- api_key, headers = Stripe::Util.parse_opts({:idempotency_key => 'foo'})
49
- assert_equal({:idempotency_key => 'foo'}, headers)
50
- assert_equal(nil, api_key)
51
- end
52
-
53
- should "parse a hash opts argument both idempotency_key and api_key" do
54
- api_key, headers = Stripe::Util.parse_opts({:api_key => 'bar', :idempotency_key => 'foo'})
55
- assert_equal({:idempotency_key => 'foo'}, headers)
56
- assert_equal('bar', api_key)
57
- end
58
28
  end
59
29
  end
@@ -254,6 +254,13 @@ module Stripe
254
254
  }
255
255
  end
256
256
 
257
+ def test_reversal_array(transfer_id)
258
+ {
259
+ :data => [test_reversal, test_reversal, test_reversal],
260
+ :object => 'list',
261
+ :url => '/v1/transfers/' + transfer_id + '/reversals'
262
+ }
263
+ end
257
264
 
258
265
  def test_invoice
259
266
  {
@@ -359,6 +366,7 @@ module Stripe
359
366
  :fee => 0,
360
367
  :fee_details => [],
361
368
  :id => "tr_test_transfer",
369
+ :reversals => test_reversal_array('tr_test_transfer'),
362
370
  :livemode => false,
363
371
  :currency => "usd",
364
372
  :object => "transfer",
@@ -381,6 +389,18 @@ module Stripe
381
389
  })
382
390
  end
383
391
 
392
+ def test_reversal(params={})
393
+ {
394
+ :object => 'transfer_reversal',
395
+ :amount => 30,
396
+ :currency => "usd",
397
+ :created => 1308595038,
398
+ :id => "ref_test_reversal",
399
+ :transfer => "tr_test_transfer",
400
+ :metadata => {}
401
+ }.merge(params)
402
+ end
403
+
384
404
  def test_bitcoin_receiver(params={})
385
405
  {
386
406
  :id => 'btcrcv_test_receiver',
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stripe
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.18.0
4
+ version: 1.19.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-01-22 00:00:00.000000000 Z
13
+ date: 2015-02-16 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rest-client
@@ -130,22 +130,6 @@ dependencies:
130
130
  - - ! '>='
131
131
  - !ruby/object:Gem::Version
132
132
  version: '0'
133
- - !ruby/object:Gem::Dependency
134
- name: pry
135
- requirement: !ruby/object:Gem::Requirement
136
- none: false
137
- requirements:
138
- - - ! '>='
139
- - !ruby/object:Gem::Version
140
- version: '0'
141
- type: :development
142
- prerelease: false
143
- version_requirements: !ruby/object:Gem::Requirement
144
- none: false
145
- requirements:
146
- - - ! '>='
147
- - !ruby/object:Gem::Version
148
- version: '0'
149
133
  description: Stripe is the easiest way to accept payments online. See https://stripe.com
150
134
  for details.
151
135
  email:
@@ -175,6 +159,7 @@ files:
175
159
  - lib/stripe/api_operations/create.rb
176
160
  - lib/stripe/api_operations/delete.rb
177
161
  - lib/stripe/api_operations/list.rb
162
+ - lib/stripe/api_operations/request.rb
178
163
  - lib/stripe/api_operations/update.rb
179
164
  - lib/stripe/api_resource.rb
180
165
  - lib/stripe/application_fee.rb
@@ -202,6 +187,7 @@ files:
202
187
  - lib/stripe/plan.rb
203
188
  - lib/stripe/recipient.rb
204
189
  - lib/stripe/refund.rb
190
+ - lib/stripe/reversal.rb
205
191
  - lib/stripe/singleton_api_resource.rb
206
192
  - lib/stripe/stripe_object.rb
207
193
  - lib/stripe/subscription.rb
@@ -226,6 +212,7 @@ files:
226
212
  - test/stripe/metadata_test.rb
227
213
  - test/stripe/recipient_card_test.rb
228
214
  - test/stripe/refund_test.rb
215
+ - test/stripe/reversal_test.rb
229
216
  - test/stripe/stripe_object_test.rb
230
217
  - test/stripe/subscription_test.rb
231
218
  - test/stripe/transfer_test.rb
@@ -274,6 +261,7 @@ test_files:
274
261
  - test/stripe/metadata_test.rb
275
262
  - test/stripe/recipient_card_test.rb
276
263
  - test/stripe/refund_test.rb
264
+ - test/stripe/reversal_test.rb
277
265
  - test/stripe/stripe_object_test.rb
278
266
  - test/stripe/subscription_test.rb
279
267
  - test/stripe/transfer_test.rb