stripe 1.18.0 → 1.19.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.
@@ -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