stripe 1.31.0 → 1.58.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE.md +5 -0
  3. data/.travis.yml +2 -12
  4. data/Gemfile +29 -4
  5. data/History.txt +168 -0
  6. data/README.md +134 -0
  7. data/Rakefile +10 -0
  8. data/VERSION +1 -1
  9. data/bin/stripe-console +12 -5
  10. data/lib/data/ca-certificates.crt +3868 -5114
  11. data/lib/stripe/account.rb +41 -21
  12. data/lib/stripe/alipay_account.rb +20 -0
  13. data/lib/stripe/api_operations/create.rb +1 -1
  14. data/lib/stripe/api_operations/delete.rb +1 -1
  15. data/lib/stripe/api_operations/list.rb +1 -2
  16. data/lib/stripe/api_operations/save.rb +87 -0
  17. data/lib/stripe/api_resource.rb +37 -4
  18. data/lib/stripe/apple_pay_domain.rb +12 -0
  19. data/lib/stripe/application_fee.rb +8 -8
  20. data/lib/stripe/application_fee_refund.rb +7 -3
  21. data/lib/stripe/balance_transaction.rb +1 -1
  22. data/lib/stripe/bank_account.rb +9 -5
  23. data/lib/stripe/bitcoin_receiver.rb +6 -6
  24. data/lib/stripe/bitcoin_transaction.rb +1 -1
  25. data/lib/stripe/card.rb +9 -5
  26. data/lib/stripe/charge.rb +30 -12
  27. data/lib/stripe/country_spec.rb +9 -0
  28. data/lib/stripe/coupon.rb +1 -1
  29. data/lib/stripe/customer.rb +6 -4
  30. data/lib/stripe/dispute.rb +2 -2
  31. data/lib/stripe/errors.rb +82 -0
  32. data/lib/stripe/file_upload.rb +1 -1
  33. data/lib/stripe/invoice.rb +3 -3
  34. data/lib/stripe/invoice_item.rb +1 -1
  35. data/lib/stripe/list_object.rb +7 -6
  36. data/lib/stripe/order.rb +10 -2
  37. data/lib/stripe/order_return.rb +9 -0
  38. data/lib/stripe/plan.rb +1 -1
  39. data/lib/stripe/product.rb +2 -10
  40. data/lib/stripe/recipient.rb +1 -1
  41. data/lib/stripe/refund.rb +1 -1
  42. data/lib/stripe/reversal.rb +7 -3
  43. data/lib/stripe/singleton_api_resource.rb +3 -3
  44. data/lib/stripe/sku.rb +2 -2
  45. data/lib/stripe/source.rb +11 -0
  46. data/lib/stripe/stripe_object.rb +167 -91
  47. data/lib/stripe/subscription.rb +15 -9
  48. data/lib/stripe/subscription_item.rb +12 -0
  49. data/lib/stripe/three_d_secure.rb +9 -0
  50. data/lib/stripe/transfer.rb +3 -4
  51. data/lib/stripe/util.rb +100 -28
  52. data/lib/stripe/version.rb +1 -1
  53. data/lib/stripe.rb +283 -140
  54. data/stripe.gemspec +5 -18
  55. data/test/stripe/account_test.rb +55 -9
  56. data/test/stripe/alipay_account_test.rb +11 -0
  57. data/test/stripe/api_operations_test.rb +31 -0
  58. data/test/stripe/api_resource_test.rb +204 -10
  59. data/test/stripe/apple_pay_domain_test.rb +34 -0
  60. data/test/stripe/application_fee_test.rb +8 -5
  61. data/test/stripe/bitcoin_receiver_test.rb +2 -2
  62. data/test/stripe/charge_refund_test.rb +12 -0
  63. data/test/stripe/charge_test.rb +32 -4
  64. data/test/stripe/country_spec_test.rb +43 -0
  65. data/test/stripe/coupon_test.rb +9 -1
  66. data/test/stripe/customer_card_test.rb +2 -2
  67. data/test/stripe/customer_test.rb +24 -1
  68. data/test/stripe/dispute_test.rb +8 -0
  69. data/test/stripe/errors_test.rb +18 -0
  70. data/test/stripe/invoice_item_test.rb +19 -0
  71. data/test/stripe/invoice_test.rb +27 -1
  72. data/test/stripe/list_object_test.rb +36 -15
  73. data/test/stripe/order_return_test.rb +25 -0
  74. data/test/stripe/order_test.rb +21 -1
  75. data/test/stripe/plan_test.rb +31 -0
  76. data/test/stripe/product_test.rb +17 -7
  77. data/test/stripe/recipient_card_test.rb +2 -2
  78. data/test/stripe/recipient_test.rb +21 -0
  79. data/test/stripe/refund_test.rb +10 -1
  80. data/test/stripe/sku_test.rb +15 -6
  81. data/test/stripe/source_test.rb +83 -0
  82. data/test/stripe/stripe_object_test.rb +180 -11
  83. data/test/stripe/subscription_item_test.rb +76 -0
  84. data/test/stripe/subscription_test.rb +161 -37
  85. data/test/stripe/three_d_secure_test.rb +22 -0
  86. data/test/stripe/transfer_test.rb +8 -0
  87. data/test/stripe/util_test.rb +48 -16
  88. data/test/stripe_test.rb +58 -0
  89. data/test/test_data.rb +337 -27
  90. data/test/test_helper.rb +7 -3
  91. metadata +47 -133
  92. data/README.rdoc +0 -68
  93. data/gemfiles/default-with-activesupport.gemfile +0 -10
  94. data/gemfiles/json.gemfile +0 -12
  95. data/gemfiles/yajl.gemfile +0 -12
  96. data/lib/stripe/api_operations/update.rb +0 -58
  97. data/lib/stripe/errors/api_connection_error.rb +0 -4
  98. data/lib/stripe/errors/api_error.rb +0 -4
  99. data/lib/stripe/errors/authentication_error.rb +0 -4
  100. data/lib/stripe/errors/card_error.rb +0 -12
  101. data/lib/stripe/errors/invalid_request_error.rb +0 -11
  102. data/lib/stripe/errors/rate_limit_error.rb +0 -4
  103. data/lib/stripe/errors/stripe_error.rb +0 -26
@@ -1,25 +1,31 @@
1
1
  module Stripe
2
2
  class Subscription < APIResource
3
- include Stripe::APIOperations::Update
3
+ extend Stripe::APIOperations::List
4
+ extend Stripe::APIOperations::Create
5
+ include Stripe::APIOperations::Save
4
6
  include Stripe::APIOperations::Delete
5
7
 
6
- def url
7
- "#{Customer.url}/#{CGI.escape(customer)}/subscriptions/#{CGI.escape(id)}"
8
+ save_nested_resource :source
9
+
10
+ def delete_discount
11
+ _, opts = request(:delete, discount_url)
12
+ initialize_from({ :discount => nil }, opts, true)
8
13
  end
9
14
 
10
- def self.retrieve(id, opts=nil)
11
- raise NotImplementedError.new("Subscriptions cannot be retrieved without a customer ID. Retrieve a subscription using customer.subscriptions.retrieve('subscription_id')")
15
+ def self.update(id, params={}, opts={})
16
+ params[:items] = Util.array_to_hash(params[:items]) if params[:items]
17
+ super(id, params, opts)
12
18
  end
13
19
 
14
- def delete_discount
15
- response, opts = request(:delete, discount_url)
16
- initialize_from({ :discount => nil }, opts, true)
20
+ def self.create(params={}, opts={})
21
+ params[:items] = Util.array_to_hash(params[:items]) if params[:items]
22
+ super(params, opts)
17
23
  end
18
24
 
19
25
  private
20
26
 
21
27
  def discount_url
22
- url + '/discount'
28
+ resource_url + '/discount'
23
29
  end
24
30
  end
25
31
  end
@@ -0,0 +1,12 @@
1
+ module Stripe
2
+ class SubscriptionItem < APIResource
3
+ extend Stripe::APIOperations::Create
4
+ include Stripe::APIOperations::Delete
5
+ extend Stripe::APIOperations::List
6
+ include Stripe::APIOperations::Save
7
+
8
+ def self.resource_url
9
+ '/v1/subscription_items'
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module Stripe
2
+ class ThreeDSecure < APIResource
3
+ extend Stripe::APIOperations::Create
4
+
5
+ def self.resource_url
6
+ "/v1/3d_secure"
7
+ end
8
+ end
9
+ end
@@ -2,16 +2,15 @@ module Stripe
2
2
  class Transfer < APIResource
3
3
  extend Stripe::APIOperations::List
4
4
  extend Stripe::APIOperations::Create
5
- include Stripe::APIOperations::Update
5
+ include Stripe::APIOperations::Save
6
6
 
7
7
  def cancel
8
- response, api_key = Stripe.request(:post, cancel_url, @api_key)
8
+ response, api_key = self.request(:post, cancel_url)
9
9
  initialize_from(response, api_key)
10
10
  end
11
11
 
12
12
  def cancel_url
13
- url + '/cancel'
13
+ resource_url + '/cancel'
14
14
  end
15
-
16
15
  end
17
16
  end
data/lib/stripe/util.rb CHANGED
@@ -23,36 +23,54 @@ module Stripe
23
23
  'list' => ListObject,
24
24
 
25
25
  # business objects
26
- 'account' => Account,
27
- 'application_fee' => ApplicationFee,
28
- 'balance' => Balance,
29
- 'balance_transaction' => BalanceTransaction,
30
- 'bank_account' => BankAccount,
31
- 'card' => Card,
32
- 'charge' => Charge,
33
- 'coupon' => Coupon,
34
- 'customer' => Customer,
35
- 'event' => Event,
36
- 'fee_refund' => ApplicationFeeRefund,
37
- 'invoiceitem' => InvoiceItem,
38
- 'invoice' => Invoice,
39
- 'plan' => Plan,
40
- 'recipient' => Recipient,
41
- 'refund' => Refund,
42
- 'subscription' => Subscription,
43
- 'file_upload' => FileUpload,
44
- 'token' => Token,
45
- 'transfer' => Transfer,
46
- 'transfer_reversal' => Reversal,
47
- 'bitcoin_receiver' => BitcoinReceiver,
48
- 'bitcoin_transaction' => BitcoinTransaction,
49
- 'dispute' => Dispute,
50
- 'product' => Product,
51
- 'sku' => SKU,
52
- 'order' => Order,
26
+ 'account' => Account,
27
+ 'alipay_account' => AlipayAccount,
28
+ 'apple_pay_domain' => ApplePayDomain,
29
+ 'application_fee' => ApplicationFee,
30
+ 'balance' => Balance,
31
+ 'balance_transaction' => BalanceTransaction,
32
+ 'bank_account' => BankAccount,
33
+ 'bitcoin_receiver' => BitcoinReceiver,
34
+ 'bitcoin_transaction' => BitcoinTransaction,
35
+ 'card' => Card,
36
+ 'charge' => Charge,
37
+ 'country_spec' => CountrySpec,
38
+ 'coupon' => Coupon,
39
+ 'customer' => Customer,
40
+ 'dispute' => Dispute,
41
+ 'event' => Event,
42
+ 'fee_refund' => ApplicationFeeRefund,
43
+ 'file_upload' => FileUpload,
44
+ 'invoice' => Invoice,
45
+ 'invoiceitem' => InvoiceItem,
46
+ 'order' => Order,
47
+ 'order_return' => OrderReturn,
48
+ 'plan' => Plan,
49
+ 'product' => Product,
50
+ 'recipient' => Recipient,
51
+ 'refund' => Refund,
52
+ 'sku' => SKU,
53
+ 'subscription' => Subscription,
54
+ 'subscription_item' => SubscriptionItem,
55
+ 'three_d_secure' => ThreeDSecure,
56
+ 'token' => Token,
57
+ 'transfer' => Transfer,
58
+ 'transfer_reversal' => Reversal,
53
59
  }
54
60
  end
55
61
 
62
+ # Converts a hash of fields or an array of hashes into a +StripeObject+ or
63
+ # array of +StripeObject+s. These new objects will be created as a concrete
64
+ # type as dictated by their `object` field (e.g. an `object` value of
65
+ # `charge` would create an instance of +Charge+), but if `object` is not
66
+ # present or of an unknown type, the newly created instance will fall back
67
+ # to being a +StripeObject+.
68
+ #
69
+ # ==== Attributes
70
+ #
71
+ # * +resp+ - Hash of fields and values to be converted into a StripeObject.
72
+ # * +opts+ - Options for +StripeObject+ like an API key that will be reused
73
+ # on subsequent API calls.
56
74
  def self.convert_to_stripe_object(resp, opts)
57
75
  case resp
58
76
  when Array
@@ -103,6 +121,20 @@ module Stripe
103
121
  map { |k,v| "#{url_encode(k)}=#{url_encode(v)}" }.join('&')
104
122
  end
105
123
 
124
+ # Transforms an array into a hash with integer keys. Used for a small
125
+ # number of API endpoints. If the argument is not an Array, return it
126
+ # unchanged. Example: [{foo: 'bar'}] => {"0" => {foo: "bar"}}
127
+ def self.array_to_hash(array)
128
+ case array
129
+ when Array
130
+ hash = {}
131
+ array.each_with_index { |v,i| hash[i.to_s] = v }
132
+ hash
133
+ else
134
+ array
135
+ end
136
+ end
137
+
106
138
  # Encodes a string in a way that makes it suitable for use in a set of
107
139
  # query parameters in a URI or in a set of form parameters in a request
108
140
  # body.
@@ -119,11 +151,12 @@ module Stripe
119
151
 
120
152
  # do not sort the final output because arrays (and arrays of hashes
121
153
  # especially) can be order sensitive, but do sort incoming parameters
122
- params.sort_by { |(k, v)| k.to_s }.each do |key, value|
154
+ params.each do |key, value|
123
155
  calculated_key = parent_key ? "#{parent_key}[#{key}]" : "#{key}"
124
156
  if value.is_a?(Hash)
125
157
  result += flatten_params(value, calculated_key)
126
158
  elsif value.is_a?(Array)
159
+ check_array_of_maps_start_keys!(value)
127
160
  result += flatten_params_array(value, calculated_key)
128
161
  else
129
162
  result << [calculated_key, value]
@@ -180,5 +213,44 @@ module Stripe
180
213
  raise TypeError.new("api_key must be a string") unless key.is_a?(String)
181
214
  key
182
215
  end
216
+
217
+ private
218
+
219
+ # We use a pretty janky version of form encoding (Rack's) that supports
220
+ # more complex data structures like maps and arrays through the use of
221
+ # specialized syntax. To encode an array of maps like:
222
+ #
223
+ # [{a: 1, b: 2}, {a: 3, b: 4}]
224
+ #
225
+ # We have to produce something that looks like this:
226
+ #
227
+ # arr[][a]=1&arr[][b]=2&arr[][a]=3&arr[][b]=4
228
+ #
229
+ # The only way for the server to recognize that this is a two item array is
230
+ # that it notices the repetition of element "a", so it's key that these
231
+ # repeated elements are encoded first.
232
+ #
233
+ # This method is invoked for any arrays being encoded and checks that if
234
+ # the array contains all non-empty maps, that each of those maps must start
235
+ # with the same key so that their boundaries can be properly encoded.
236
+ def self.check_array_of_maps_start_keys!(arr)
237
+ expected_key = nil
238
+ arr.each do |item|
239
+ return if !item.is_a?(Hash)
240
+ return if item.count == 0
241
+
242
+ first_key = item.first[0]
243
+
244
+ if expected_key
245
+ if expected_key != first_key
246
+ raise ArgumentError,
247
+ "All maps nested in an array should start with the same key " +
248
+ "(expected starting key '#{expected_key}', got '#{first_key}')"
249
+ end
250
+ else
251
+ expected_key = first_key
252
+ end
253
+ end
254
+ end
183
255
  end
184
256
  end
@@ -1,3 +1,3 @@
1
1
  module Stripe
2
- VERSION = '1.31.0'
2
+ VERSION = '1.58.0'
3
3
  end