stripe-ruby-mock 2.5.6 → 2.5.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/stripe_mock.rb +1 -0
  4. data/lib/stripe_mock/data.rb +17 -2
  5. data/lib/stripe_mock/instance.rb +32 -2
  6. data/lib/stripe_mock/request_handlers/charges.rb +7 -4
  7. data/lib/stripe_mock/request_handlers/customers.rb +2 -2
  8. data/lib/stripe_mock/request_handlers/helpers/coupon_helpers.rb +10 -11
  9. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +9 -1
  10. data/lib/stripe_mock/request_handlers/invoices.rb +1 -1
  11. data/lib/stripe_mock/request_handlers/products.rb +43 -0
  12. data/lib/stripe_mock/request_handlers/refunds.rb +6 -3
  13. data/lib/stripe_mock/request_handlers/subscriptions.rb +40 -22
  14. data/lib/stripe_mock/request_handlers/tokens.rb +2 -2
  15. data/lib/stripe_mock/version.rb +1 -1
  16. data/lib/stripe_mock/webhook_fixtures/invoice.created.json +1 -1
  17. data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +1 -1
  18. data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +1 -1
  19. data/spec/shared_stripe_examples/charge_examples.rb +23 -14
  20. data/spec/shared_stripe_examples/customer_examples.rb +1 -1
  21. data/spec/shared_stripe_examples/invoice_examples.rb +1 -1
  22. data/spec/shared_stripe_examples/plan_examples.rb +1 -1
  23. data/spec/shared_stripe_examples/product_example.rb +65 -0
  24. data/spec/shared_stripe_examples/refund_examples.rb +16 -10
  25. data/spec/shared_stripe_examples/subscription_examples.rb +128 -2
  26. data/spec/shared_stripe_examples/transfer_examples.rb +5 -5
  27. data/spec/support/stripe_examples.rb +1 -1
  28. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b5d9cbcf4490a6413cf153d1c2a1a21acf38929
4
- data.tar.gz: cb9f625fc17632de27cfeef7ec97f429fa79804d
3
+ metadata.gz: 2c1a6cfda90439e30a5198b5e83135070138179b
4
+ data.tar.gz: d1a78b4802fe6b7d37c11b104eec9a0c08f06b40
5
5
  SHA512:
6
- metadata.gz: bde32906b3e0c262da53cbea9263250a497736e81c824a08c6c668546317f8209ed3bd5e6c4ef34df5414af3d753d6a6fdcaedf956e7e4f9a31a50f327e4174b
7
- data.tar.gz: 182a87b8a9f5cc078ecb5c8a3afbcfd6d51d14d72518928aad1e2e85effb1bb3667888fee21a658dc428c4fd1e7c6a1303ea09599e9b2d7791801576fc6b5029
6
+ metadata.gz: 9bd40fd514426cb1a58c52bd2b1c3841bff41a5c8a2a73e8a3dbfb43fc98422b3c51f8b7761e7e7f2a010afd0bb260db5778e2796dd501ce0c28d63e53dca783
7
+ data.tar.gz: bedeb87ade1eeba6a46e9573628187bb66f1bd886233cf21f60383668350f95a9562b53f16f4d7068169393782e54d62e5f9ea680ea8b7a6849c2fe225ace4ea
data/README.md CHANGED
@@ -12,7 +12,7 @@ This gem has unexpectedly grown in popularity and I've gotten pretty busy, so I'
12
12
 
13
13
  In your gemfile:
14
14
 
15
- gem 'stripe-ruby-mock', '~> 2.5.6', :require => 'stripe_mock'
15
+ gem 'stripe-ruby-mock', '~> 2.5.7', :require => 'stripe_mock'
16
16
 
17
17
  ## Features
18
18
 
@@ -70,6 +70,7 @@ require 'stripe_mock/request_handlers/subscriptions.rb'
70
70
  require 'stripe_mock/request_handlers/tokens.rb'
71
71
  require 'stripe_mock/request_handlers/country_spec.rb'
72
72
  require 'stripe_mock/request_handlers/ephemeral_key.rb'
73
+ require 'stripe_mock/request_handlers/products.rb'
73
74
  require 'stripe_mock/instance'
74
75
 
75
76
  require 'stripe_mock/test_strategies/base.rb'
@@ -335,7 +335,7 @@ module StripeMock
335
335
  lines << Data.mock_line_item() if lines.empty?
336
336
  invoice = {
337
337
  id: 'in_test_invoice',
338
- date: 1349738950,
338
+ created: 1349738950,
339
339
  period_end: 1349738950,
340
340
  period_start: 1349738950,
341
341
  lines: {
@@ -409,7 +409,7 @@ module StripeMock
409
409
  {
410
410
  id: "test_ii",
411
411
  object: "invoiceitem",
412
- date: 1349738920,
412
+ created: 1349738920,
413
413
  amount: 1099,
414
414
  livemode: false,
415
415
  proration: false,
@@ -510,6 +510,21 @@ module StripeMock
510
510
  }.merge(params)
511
511
  end
512
512
 
513
+ def self.mock_product(params = {})
514
+ {
515
+ id: "default_test_prod",
516
+ object: "product",
517
+ active: true,
518
+ created: 1556896214,
519
+ livemode: false,
520
+ metadata: {},
521
+ name: "Default Test Product",
522
+ statement_descriptor: "PRODUCT",
523
+ type: "service",
524
+ updated: 1556918200,
525
+ }.merge(params)
526
+ end
527
+
513
528
  def self.mock_recipient(cards, params={})
514
529
  rp_id = params[:id] || "test_rp_default"
515
530
  cards.each {|card| card[:recipient] = rp_id}
@@ -36,6 +36,7 @@ module StripeMock
36
36
  include StripeMock::RequestHandlers::InvoiceItems
37
37
  include StripeMock::RequestHandlers::Orders
38
38
  include StripeMock::RequestHandlers::Plans
39
+ include StripeMock::RequestHandlers::Products
39
40
  include StripeMock::RequestHandlers::Refunds
40
41
  include StripeMock::RequestHandlers::Recipients
41
42
  include StripeMock::RequestHandlers::Transfers
@@ -46,7 +47,8 @@ module StripeMock
46
47
 
47
48
  attr_reader :accounts, :balance, :balance_transactions, :bank_tokens, :charges, :coupons, :customers,
48
49
  :disputes, :events, :invoices, :invoice_items, :orders, :plans, :recipients,
49
- :refunds, :transfers, :payouts, :subscriptions, :country_spec, :subscriptions_items
50
+ :refunds, :transfers, :payouts, :subscriptions, :country_spec, :subscriptions_items,
51
+ :products
50
52
 
51
53
  attr_accessor :error_queue, :debug, :conversion_rate, :account_balance
52
54
 
@@ -65,6 +67,7 @@ module StripeMock
65
67
  @invoice_items = {}
66
68
  @orders = {}
67
69
  @plans = {}
70
+ @products = {}
68
71
  @recipients = {}
69
72
  @refunds = {}
70
73
  @transfers = {}
@@ -175,7 +178,8 @@ module StripeMock
175
178
  amount = params[:amount]
176
179
  unless amount.nil?
177
180
  # Fee calculation
178
- params[:fee] ||= (30 + (amount.abs * 0.029).ceil) * (amount > 0 ? 1 : -1)
181
+ calculate_fees(params) unless params[:fee]
182
+ params[:net] = amount - params[:fee]
179
183
  params[:amount] = amount * @conversion_rate
180
184
  end
181
185
  @balance_transactions[id] = Data.mock_balance_transaction(params.merge(id: id))
@@ -196,5 +200,31 @@ module StripeMock
196
200
  response = Struct.new(:data)
197
201
  response.new(hash)
198
202
  end
203
+
204
+ def calculate_fees(params)
205
+ application_fee = params[:application_fee] || 0
206
+ params[:fee] = processing_fee(params[:amount]) + application_fee
207
+ params[:fee_details] = [
208
+ {
209
+ amount: processing_fee(params[:amount]),
210
+ application: nil,
211
+ currency: params[:currency] || StripeMock.default_currency,
212
+ description: "Stripe processing fees",
213
+ type: "stripe_fee"
214
+ }
215
+ ]
216
+ if application_fee
217
+ params[:fee_details] << {
218
+ amount: application_fee,
219
+ currency: params[:currency] || StripeMock.default_currency,
220
+ description: "Application fee",
221
+ type: "application_fee"
222
+ }
223
+ end
224
+ end
225
+
226
+ def processing_fee(amount)
227
+ (30 + (amount.abs * 0.029).ceil) * (amount > 0 ? 1 : -1)
228
+ end
199
229
  end
200
230
  end
@@ -13,9 +13,12 @@ module StripeMock
13
13
  end
14
14
 
15
15
  def new_charge(route, method_url, params, headers)
16
- if params[:idempotency_key] && charges.any?
17
- original_charge = charges.values.find { |c| c[:idempotency_key] == params[:idempotency_key]}
18
- return charges[original_charge[:id]] if original_charge
16
+ if headers && headers[:idempotency_key]
17
+ params[:idempotency_key] = headers[:idempotency_key]
18
+ if charges.any?
19
+ original_charge = charges.values.find { |c| c[:idempotency_key] == headers[:idempotency_key]}
20
+ return charges[original_charge[:id]] if original_charge
21
+ end
19
22
  end
20
23
 
21
24
  id = new_id('ch')
@@ -41,7 +44,7 @@ module StripeMock
41
44
  end
42
45
 
43
46
  ensure_required_params(params)
44
- bal_trans_params = { amount: params[:amount], source: id }
47
+ bal_trans_params = { amount: params[:amount], source: id, application_fee: params[:application_fee] }
45
48
 
46
49
  balance_transaction_id = new_balance_transaction('txn', bal_trans_params)
47
50
 
@@ -51,7 +51,7 @@ module StripeMock
51
51
  coupon = coupons[ params[:coupon] ]
52
52
  assert_existence :coupon, params[:coupon], coupon
53
53
 
54
- add_coupon_to_customer(customers[params[:id]], coupon)
54
+ add_coupon_to_object(customers[params[:id]], coupon)
55
55
  end
56
56
 
57
57
  customers[ params[:id] ]
@@ -90,7 +90,7 @@ module StripeMock
90
90
  coupon = coupons[ params[:coupon] ]
91
91
  assert_existence :coupon, params[:coupon], coupon
92
92
 
93
- add_coupon_to_customer(cus, coupon)
93
+ add_coupon_to_object(cus, coupon)
94
94
  end
95
95
 
96
96
  cus
@@ -1,18 +1,17 @@
1
1
  module StripeMock
2
2
  module RequestHandlers
3
3
  module Helpers
4
+ def add_coupon_to_object(object, coupon)
5
+ discount_attrs = {}.tap do |attrs|
6
+ attrs[object[:object]] = object[:id]
7
+ attrs[:coupon] = coupon
8
+ attrs[:start] = Time.now.to_i
9
+ attrs[:end] = (DateTime.now >> coupon[:duration_in_months].to_i).to_time.to_i if coupon[:duration] == 'repeating'
10
+ end
4
11
 
5
- def add_coupon_to_customer(customer, coupon)
6
- customer[:discount] = {
7
- coupon: coupon,
8
- customer: customer[:id],
9
- start: Time.now.to_i,
10
- }
11
- customer[:discount][:end] = (DateTime.now >> coupon[:duration_in_months]).to_time.to_i if coupon[:duration].to_sym == :repeating && coupon[:duration_in_months]
12
-
13
- customer
12
+ object[:discount] = Stripe::Discount.construct_from(discount_attrs)
13
+ object
14
14
  end
15
-
16
15
  end
17
16
  end
18
- end
17
+ end
@@ -30,7 +30,15 @@ module StripeMock
30
30
  start_time = options[:current_period_start] || now
31
31
  params = { customer: cus[:id], current_period_start: start_time, created: created_time }
32
32
  params.merge!({ :plan => (plans.size == 1 ? plans.first : nil) })
33
- params.merge! options.select {|k,v| k =~ /application_fee_percent|quantity|metadata|tax_percent/}
33
+ keys_to_merge = /application_fee_percent|quantity|metadata|tax_percent|billing|days_until_due/
34
+ params.merge! options.select {|k,v| k =~ keys_to_merge}
35
+
36
+ if options[:cancel_at_period_end] == true
37
+ params.merge!(cancel_at_period_end: true, canceled_at: now)
38
+ elsif options[:cancel_at_period_end] == false
39
+ params.merge!(cancel_at_period_end: false, canceled_at: nil)
40
+ end
41
+
34
42
  # TODO: Implement coupon logic
35
43
 
36
44
  if (((plan && plan[:trial_period_days]) || 0) == 0 && options[:trial_end].nil?) || options[:trial_end] == "now"
@@ -138,7 +138,7 @@ module StripeMock
138
138
  id: new_id('in'),
139
139
  customer: customer[:id],
140
140
  discount: customer[:discount],
141
- date: invoice_date,
141
+ created: invoice_date,
142
142
  starting_balance: customer[:account_balance],
143
143
  subscription: preview_subscription[:id],
144
144
  period_start: prorating ? invoice_date : preview_subscription[:current_period_start],
@@ -0,0 +1,43 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module Products
4
+ def self.included(base)
5
+ base.add_handler 'post /v1/products', :create_product
6
+ base.add_handler 'get /v1/products/(.*)', :retrieve_product
7
+ base.add_handler 'post /v1/products/(.*)', :update_product
8
+ base.add_handler 'get /v1/products', :list_products
9
+ base.add_handler 'delete /v1/products/(.*)', :destroy_product
10
+ end
11
+
12
+ def create_product(_route, _method_url, params, _headers)
13
+ params[:id] ||= new_id('prod')
14
+ products[params[:id]] = Data.mock_product(params)
15
+ end
16
+
17
+ def retrieve_product(route, method_url, _params, _headers)
18
+ id = method_url.match(route).captures.first
19
+ assert_existence :product, id, products[id]
20
+ end
21
+
22
+ def update_product(route, method_url, params, _headers)
23
+ id = method_url.match(route).captures.first
24
+ product = assert_existence :product, id, products[id]
25
+
26
+ product.merge!(params)
27
+ end
28
+
29
+ def list_products(_route, _method_url, params, _headers)
30
+ limit = params[:limit] || 10
31
+ Data.mock_list_object(products.values.take(limit), params)
32
+ end
33
+
34
+ def destroy_product(route, method_url, _params, _headers)
35
+ id = method_url.match(route).captures.first
36
+ assert_existence :product, id, products[id]
37
+
38
+ products.delete(id)
39
+ { id: id, object: 'product', deleted: true }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -10,9 +10,12 @@ module StripeMock
10
10
  end
11
11
 
12
12
  def new_refund(route, method_url, params, headers)
13
- if params[:idempotency_key] && refunds.any?
14
- original_refund = refunds.values.find { |c| c[:idempotency_key] == params[:idempotency_key]}
15
- return refunds[original_refund[:id]] if original_refund
13
+ if headers && headers[:idempotency_key]
14
+ params[:idempotency_key] = headers[:idempotency_key]
15
+ if refunds.any?
16
+ original_refund = refunds.values.find { |c| c[:idempotency_key] == headers[:idempotency_key]}
17
+ return refunds[original_refund[:id]] if original_refund
18
+ end
16
19
  end
17
20
 
18
21
  charge = assert_existence :charge, params[:charge], charges[params[:charge]]
@@ -60,7 +60,7 @@ module StripeMock
60
60
  coupon = coupons[coupon_id]
61
61
 
62
62
  if coupon
63
- subscription[:discount] = Stripe::Util.convert_to_stripe_object({ coupon: coupon }, {})
63
+ add_coupon_to_object(subscription, coupon)
64
64
  else
65
65
  raise Stripe::InvalidRequestError.new("No such coupon: #{coupon_id}", 'coupon', http_status: 400)
66
66
  end
@@ -73,6 +73,13 @@ module StripeMock
73
73
  end
74
74
 
75
75
  def create_subscription(route, method_url, params, headers)
76
+ if headers && headers[:idempotency_key]
77
+ if subscriptions.any?
78
+ original_subscription = subscriptions.values.find { |c| c[:idempotency_key] == headers[:idempotency_key]}
79
+ puts original_subscription
80
+ return subscriptions[original_subscription[:id]] if original_subscription
81
+ end
82
+ end
76
83
  route =~ method_url
77
84
 
78
85
  subscription_plans = get_subscription_plans_from_params(params)
@@ -95,7 +102,7 @@ module StripeMock
95
102
  customer[:default_source] = new_card[:id]
96
103
  end
97
104
 
98
- allowed_params = %w(customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days current_period_start created prorate billing_cycle_anchor)
105
+ allowed_params = %w(customer application_fee_percent coupon items metadata plan quantity source tax_percent trial_end trial_period_days current_period_start created prorate billing_cycle_anchor billing days_until_due idempotency_key)
99
106
  unknown_params = params.keys - allowed_params.map(&:to_sym)
100
107
  if unknown_params.length > 0
101
108
  raise Stripe::InvalidRequestError.new("Received unknown parameter: #{unknown_params.join}", unknown_params.first.to_s, http_status: 400)
@@ -103,6 +110,9 @@ module StripeMock
103
110
 
104
111
  subscription = Data.mock_subscription({ id: (params[:id] || new_id('su')) })
105
112
  subscription = resolve_subscription_changes(subscription, subscription_plans, customer, params)
113
+ if headers[:idempotency_key]
114
+ subscription[:idempotency_key] = headers[:idempotency_key]
115
+ end
106
116
 
107
117
  # Ensure customer has card to charge if plan has no trial and is not free
108
118
  # Note: needs updating for subscriptions with multiple plans
@@ -117,7 +127,7 @@ module StripeMock
117
127
  coupon = coupons[coupon_id]
118
128
 
119
129
  if coupon
120
- subscription[:discount] = Stripe::Util.convert_to_stripe_object({ coupon: coupon }, {})
130
+ add_coupon_to_object(subscription, coupon)
121
131
  else
122
132
  raise Stripe::InvalidRequestError.new("No such coupon: #{coupon_id}", 'coupon', http_status: 400)
123
133
  end
@@ -174,9 +184,9 @@ module StripeMock
174
184
 
175
185
  coupon = coupons[coupon_id]
176
186
  if coupon
177
- subscription[:discount] = Stripe::Util.convert_to_stripe_object({ coupon: coupon }, {})
187
+ add_coupon_to_object(subscription, coupon)
178
188
  elsif coupon_id == ""
179
- subscription[:discount] = Stripe::Util.convert_to_stripe_object(nil, {})
189
+ subscription[:discount] = nil
180
190
  else
181
191
  raise Stripe::InvalidRequestError.new("No such coupon: #{coupon_id}", 'coupon', http_status: 400)
182
192
  end
@@ -189,6 +199,7 @@ module StripeMock
189
199
  end
190
200
 
191
201
  params[:current_period_start] = subscription[:current_period_start]
202
+ params[:trial_end] = params[:trial_end] || subscription[:trial_end]
192
203
  subscription = resolve_subscription_changes(subscription, subscription_plans, customer, params)
193
204
 
194
205
  # delete the old subscription, replace with the new subscription
@@ -244,26 +255,33 @@ module StripeMock
244
255
  plan_ids.map { |plan_id| plans[plan_id] }
245
256
  end
246
257
 
258
+ # Ensure customer has card to charge unless one of the following criterias is met:
259
+ # 1) is in trial
260
+ # 2) is free
261
+ # 3) has billing set to send invoice
247
262
  def verify_card_present(customer, plan, subscription, params={})
248
- if customer[:default_source].nil? && customer[:trial_end].nil? &&
249
- (plan.nil? ||
250
- ((plan[:trial_period_days] || 0) == 0 &&
251
- plan[:amount] != 0 &&
252
- plan[:trial_end].nil?)) &&
253
- params[:trial_end].nil? &&
254
- (subscription.nil? || subscription[:trial_end].nil? || subscription[:trial_end] == 'now')
255
-
256
- if subscription[:items]
257
- trial = subscription[:items][:data].none? do |item|
258
- plan = item[:plan]
259
- (plan[:trial_period_days].nil? || plan[:trial_period_days] == 0) &&
260
- (plan[:trial_end].nil? || plan[:trial_end] == 'now')
261
- end
262
- return if trial
263
- end
263
+ return if customer[:default_source]
264
+ return if customer[:trial_end]
265
+ return if params[:trial_end]
264
266
 
265
- raise Stripe::InvalidRequestError.new('You must supply a valid card xoxo', nil, http_status: 400)
267
+ plan_trial_period_days = plan[:trial_period_days] || 0
268
+ plan_has_trial = plan_trial_period_days != 0 || plan[:amount] == 0 || plan[:trial_end]
269
+ return if plan && plan_has_trial
270
+
271
+ return if subscription && subscription[:trial_end] && subscription[:trial_end] != 'now'
272
+
273
+ if subscription[:items]
274
+ trial = subscription[:items][:data].none? do |item|
275
+ plan = item[:plan]
276
+ (plan[:trial_period_days].nil? || plan[:trial_period_days] == 0) &&
277
+ (plan[:trial_end].nil? || plan[:trial_end] == 'now')
278
+ end
279
+ return if trial
266
280
  end
281
+
282
+ return if params[:billing] == 'send_invoice'
283
+
284
+ raise Stripe::InvalidRequestError.new('You must supply a valid card xoxo', nil, http_status: 400)
267
285
  end
268
286
 
269
287
  def verify_active_status(subscription)
@@ -46,12 +46,12 @@ module StripeMock
46
46
  end
47
47
 
48
48
  if bank_account
49
- token_id = generate_bank_token(bank_account)
49
+ token_id = generate_bank_token(bank_account.dup)
50
50
  bank_account = @bank_tokens[token_id]
51
51
 
52
52
  Data.mock_bank_account_token(params.merge :id => token_id, :bank_account => bank_account)
53
53
  else
54
- token_id = generate_card_token(customer_card)
54
+ token_id = generate_card_token(customer_card.dup)
55
55
  card = @card_tokens[token_id]
56
56
 
57
57
  Data.mock_card_token(params.merge :id => token_id, :card => card)
@@ -1,4 +1,4 @@
1
1
  module StripeMock
2
2
  # stripe-ruby-mock version
3
- VERSION = "2.5.6"
3
+ VERSION = "2.5.7"
4
4
  end
@@ -6,7 +6,7 @@
6
6
  "object": "event",
7
7
  "data": {
8
8
  "object": {
9
- "date": 1380674206,
9
+ "created": 1380674206,
10
10
  "id": "in_00000000000000",
11
11
  "period_start": 1378082075,
12
12
  "period_end": 1380674075,
@@ -16,7 +16,7 @@
16
16
  "closed": true,
17
17
  "currency": "eur",
18
18
  "customer": "cus_00000000000000",
19
- "date": 1464084258,
19
+ "created": 1464084258,
20
20
  "description": null,
21
21
  "discount": null,
22
22
  "ending_balance": 0,
@@ -6,7 +6,7 @@
6
6
  "object": "event",
7
7
  "data": {
8
8
  "object": {
9
- "date": 1380674206,
9
+ "created": 1380674206,
10
10
  "id": "in_00000000000000",
11
11
  "period_start": 1378082075,
12
12
  "period_end": 1380674075,
@@ -163,15 +163,19 @@ shared_examples 'Charge API' do
163
163
  end
164
164
 
165
165
  it "creates a balance transaction" do
166
+ amount = 300
167
+ fee = 10
166
168
  charge = Stripe::Charge.create({
167
- amount: 300,
169
+ amount: amount,
168
170
  currency: 'USD',
169
- source: stripe_helper.generate_card_token
171
+ source: stripe_helper.generate_card_token,
172
+ application_fee: fee,
170
173
  })
171
174
  bal_trans = Stripe::BalanceTransaction.retrieve(charge.balance_transaction)
172
- expect(bal_trans.amount).to eq(charge.amount)
173
- expect(bal_trans.fee).to eq(39)
175
+ expect(bal_trans.amount).to eq(amount)
176
+ expect(bal_trans.fee).to eq(39 + fee)
174
177
  expect(bal_trans.source).to eq(charge.id)
178
+ expect(bal_trans.net).to eq(amount - bal_trans.fee)
175
179
  end
176
180
 
177
181
  context 'when conversion rate is set' do
@@ -472,29 +476,34 @@ shared_examples 'Charge API' do
472
476
 
473
477
  describe "idempotency" do
474
478
  let(:customer) { Stripe::Customer.create(email: 'johnny@appleseed.com') }
475
- let(:idempotent_charge_params) {{
479
+ let(:charge_params) {{
476
480
  amount: 777,
477
481
  currency: 'USD',
478
482
  customer: customer.id,
479
- capture: true,
483
+ capture: true
484
+ }}
485
+ let(:charge_headers) {{
480
486
  idempotency_key: 'onceisenough'
481
487
  }}
482
488
 
483
489
  it "returns the original charge if the same idempotency_key is passed in" do
484
- charge1 = Stripe::Charge.create(idempotent_charge_params)
485
- charge2 = Stripe::Charge.create(idempotent_charge_params)
490
+ charge1 = Stripe::Charge.create(charge_params, charge_headers)
491
+ charge2 = Stripe::Charge.create(charge_params, charge_headers)
486
492
 
487
493
  expect(charge1).to eq(charge2)
488
494
  end
489
495
 
490
- it "returns different charges if different idempotency_keys are used for each charge" do
491
- idempotent_charge_params2 = idempotent_charge_params.clone
492
- idempotent_charge_params2[:idempotency_key] = 'thisoneisdifferent'
496
+ context 'different key' do
497
+ let(:different_charge_headers) {{
498
+ idempotency_key: 'thisoneisdifferent'
499
+ }}
493
500
 
494
- charge1 = Stripe::Charge.create(idempotent_charge_params)
495
- charge2 = Stripe::Charge.create(idempotent_charge_params2)
501
+ it "returns different charges if different idempotency_keys are used for each charge" do
502
+ charge1 = Stripe::Charge.create(charge_params, charge_headers)
503
+ charge2 = Stripe::Charge.create(charge_params, different_charge_headers)
496
504
 
497
- expect(charge1).not_to eq(charge2)
505
+ expect(charge1).not_to eq(charge2)
506
+ end
498
507
  end
499
508
  end
500
509
 
@@ -226,7 +226,7 @@ shared_examples 'Customer API' do
226
226
  discount = Stripe::Customer.retrieve(customer.id).discount
227
227
  expect(discount).to_not be_nil
228
228
  expect(discount.coupon).to_not be_nil
229
- expect(discount.end).to be_within(1).of (Time.now + 365 * 24 * 3600).to_i
229
+ expect(discount.end).to be_within(1).of (Time.now.to_datetime >> 12).to_time.to_i
230
230
  end
231
231
  after { Stripe::Coupon.retrieve(coupon.id).delete }
232
232
  after { Stripe::Customer.retrieve(customer.id).delete }
@@ -351,7 +351,7 @@ shared_examples 'Invoice API' do
351
351
  it 'generates a preview without performing an actual proration', live: true do
352
352
  expect(preview.subtotal).to eq 150_00
353
353
  # this is a future invoice (generted at the end of the current subscription cycle), rather than a proration invoice
354
- expect(preview.date).to be_within(1).of subscription.current_period_end
354
+ expect(preview.created).to be_within(1).of subscription.current_period_end
355
355
  expect(preview.period_start).to eq subscription.current_period_start
356
356
  expect(preview.period_end).to eq subscription.current_period_end
357
357
  expect(preview.lines.count).to eq 1
@@ -157,7 +157,7 @@ shared_examples 'Plan API' do
157
157
  expect { subject }.to raise_error(Stripe::InvalidRequestError, message)
158
158
  end
159
159
 
160
- it("requires a name") { @name = :name }
160
+ it("requires a product") { @name = :product }
161
161
  it("requires an amount") { @name = :amount }
162
162
  it("requires a currency") { @name = :currency }
163
163
  it("requires an interval") { @name = :interval }
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples 'Product API' do
4
+ it 'creates a product' do
5
+ product = Stripe::Product.create(
6
+ name: 'my awesome product',
7
+ type: 'service'
8
+ )
9
+
10
+ expect(product.name).to eq 'my awesome product'
11
+ expect(product.type).to eq 'service'
12
+ end
13
+
14
+ it 'retrieves a product' do
15
+ Stripe::Product.create(
16
+ id: 'test_prod_1',
17
+ name: 'my awesome product',
18
+ type: 'service'
19
+ )
20
+
21
+ product = Stripe::Product.retrieve('test_prod_1')
22
+
23
+ expect(product.name).to eq 'my awesome product'
24
+ expect(product.type).to eq 'service'
25
+ end
26
+
27
+ it 'updates a product' do
28
+ Stripe::Product.create(
29
+ id: 'test_prod_1',
30
+ name: 'my awesome product',
31
+ type: 'service'
32
+ )
33
+
34
+ Stripe::Product.update('test_prod_1', name: 'my lame product')
35
+
36
+ product = Stripe::Product.retrieve('test_prod_1')
37
+
38
+ expect(product.name).to eq 'my lame product'
39
+ end
40
+
41
+ it 'lists all products' do
42
+ 2.times do |n|
43
+ Stripe::Product.create(
44
+ name: "product #{n}",
45
+ type: 'service'
46
+ )
47
+ end
48
+
49
+ products = Stripe::Product.list
50
+
51
+ expect(products.map(&:name)).to match_array ['product 0', 'product 1']
52
+ end
53
+
54
+ it 'destroys a product', live: true do
55
+ Stripe::Product.create(
56
+ id: 'test_prod_1',
57
+ name: 'my awesome product',
58
+ type: 'service'
59
+ )
60
+
61
+ Stripe::Product.delete('test_prod_1')
62
+
63
+ expect { Stripe::Product.retrieve('test_prod_1') }. to raise_error(Stripe::InvalidRequestError)
64
+ end
65
+ end
@@ -337,26 +337,32 @@ shared_examples 'Refund API' do
337
337
  capture: true
338
338
  )
339
339
  end
340
- let(:idempotent_refund_params) {{
341
- charge: charge.id,
340
+ let(:refund_params) {{
341
+ charge: charge.id
342
+ }}
343
+
344
+ let(:refund_headers) {{
342
345
  idempotency_key: 'onceisenough'
343
346
  }}
344
347
 
345
348
  it "returns the original refund if the same idempotency_key is passed in" do
346
- refund1 = Stripe::Refund.create(idempotent_refund_params)
347
- refund2 = Stripe::Refund.create(idempotent_refund_params)
349
+ refund1 = Stripe::Refund.create(refund_params, refund_headers)
350
+ refund2 = Stripe::Refund.create(refund_params, refund_headers)
348
351
 
349
352
  expect(refund1).to eq(refund2)
350
353
  end
351
354
 
352
- it "returns different charges if different idempotency_keys are used for each charge" do
353
- idempotent_refund_params2 = idempotent_refund_params.clone
354
- idempotent_refund_params2[:idempotency_key] = 'thisoneisdifferent'
355
+ context 'different key' do
356
+ let(:different_refund_headers) {{
357
+ idempotency_key: 'thisoneisdifferent'
358
+ }}
355
359
 
356
- refund1 = Stripe::Refund.create(idempotent_refund_params)
357
- refund2 = Stripe::Refund.create(idempotent_refund_params2)
360
+ it "returns different charges if different idempotency_keys are used for each charge" do
361
+ refund1 = Stripe::Refund.create(refund_params, refund_headers)
362
+ refund2 = Stripe::Refund.create(refund_params, different_refund_headers)
358
363
 
359
- expect(refund1).not_to eq(refund2)
364
+ expect(refund1).not_to eq(refund2)
365
+ end
360
366
  end
361
367
  end
362
368
  end
@@ -140,7 +140,7 @@ shared_examples 'Customer Subscriptions' do
140
140
  expect(customer.subscriptions.data).to be_a(Array)
141
141
  expect(customer.subscriptions.data.count).to eq(1)
142
142
  expect(customer.subscriptions.data.first.discount).not_to be_nil
143
- expect(customer.subscriptions.data.first.discount).to be_a(Stripe::StripeObject)
143
+ expect(customer.subscriptions.data.first.discount).to be_a(Stripe::Discount)
144
144
  expect(customer.subscriptions.data.first.discount.coupon.id).to eq(coupon.id)
145
145
  end
146
146
 
@@ -362,6 +362,30 @@ shared_examples 'Customer Subscriptions' do
362
362
  expect(sub.trial_end).to eq(trial_end)
363
363
  end
364
364
 
365
+ it "does not override trial end when trial end is not set" do
366
+ plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14)
367
+ customer = Stripe::Customer.create(id: 'short_trial')
368
+ trial_end = Time.now.utc.to_i + 3600
369
+ metadata = {description: 'original description'}
370
+
371
+ sub = Stripe::Subscription.create({ plan: 'trial', customer: customer.id, trial_end: trial_end, metadata: metadata })
372
+
373
+ expect(sub.object).to eq('subscription')
374
+ expect(sub.plan.to_hash).to eq(plan.to_hash)
375
+ expect(sub.current_period_end).to eq(trial_end)
376
+ expect(sub.trial_end).to eq(trial_end)
377
+ expect(sub.metadata.description).to eq(metadata[:description])
378
+
379
+ metadata = {description: 'updated description'}
380
+ sub = Stripe::Subscription.update(sub.id, { metadata: metadata })
381
+
382
+ expect(sub.object).to eq('subscription')
383
+ expect(sub.plan.to_hash).to eq(plan.to_hash)
384
+ expect(sub.current_period_end).to eq(trial_end)
385
+ expect(sub.trial_end).to eq(trial_end) # check that the trial_end has NOT changed
386
+ expect(sub.metadata.description).to eq(metadata[:description]) # check that the description has changed
387
+ end
388
+
365
389
  it "returns without a trial when trial_end is set to 'now'" do
366
390
  plan = stripe_helper.create_plan(id: 'trial', amount: 999, trial_period_days: 14)
367
391
  customer = Stripe::Customer.create(id: 'no_trial', source: gen_card_tk)
@@ -472,6 +496,62 @@ shared_examples 'Customer Subscriptions' do
472
496
  expect(subscription.items.data[0].plan.id).to eq plan.id
473
497
  expect(subscription.items.data[1].plan.id).to eq plan2.id
474
498
  end
499
+
500
+ it 'add a new subscription to bill via an invoice' do
501
+ plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' },
502
+ amount: 4999, currency: 'usd')
503
+ customer = Stripe::Customer.create(id: 'cardless')
504
+
505
+ expect(customer.subscriptions.data).to be_empty
506
+ expect(customer.subscriptions.count).to eq(0)
507
+
508
+ sub = Stripe::Subscription.create({
509
+ plan: 'silver',
510
+ customer: customer.id,
511
+ metadata: { foo: 'bar', example: 'yes' },
512
+ billing: 'send_invoice',
513
+ days_until_due: 30,
514
+ })
515
+
516
+ expect(sub.object).to eq('subscription')
517
+ expect(sub.plan.to_hash).to eq(plan.to_hash)
518
+ expect(sub.billing).to eq 'send_invoice'
519
+ expect(sub.days_until_due).to eq 30
520
+ end
521
+
522
+ let(:subscription_header) {{
523
+ :idempotency_key => 'a_idempotency_key'
524
+ }}
525
+
526
+ it "adds a new subscription to customer with identical idempotency key" do
527
+ plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' },
528
+ amount: 4999, currency: 'usd')
529
+ customer = Stripe::Customer.create(source: gen_card_tk)
530
+
531
+ expect(customer.subscriptions.data).to be_empty
532
+ expect(customer.subscriptions.count).to eq(0)
533
+
534
+ sub1 = Stripe::Subscription.create({ items: [{ plan: 'silver' }], customer: customer.id }, subscription_header)
535
+ sub2 = Stripe::Subscription.create({ items: [{ plan: 'silver' }], customer: customer.id }, subscription_header)
536
+ expect(sub1).to eq(sub2)
537
+ end
538
+
539
+ it "adds a new subscription to customer with different idempotency key", :live => true do
540
+ plan = stripe_helper.create_plan(id: 'silver', product: { name: 'Silver Plan' },
541
+ amount: 4999, currency: 'usd')
542
+ customer = Stripe::Customer.create(source: gen_card_tk)
543
+
544
+ expect(customer.subscriptions.data).to be_empty
545
+ expect(customer.subscriptions.count).to eq(0)
546
+
547
+ another_subscription_header = {
548
+ :idempotency_key => 'another_idempotency_key'
549
+ }
550
+
551
+ sub1 = Stripe::Subscription.create({ items: [{ plan: 'silver' }], customer: customer.id }, subscription_header)
552
+ sub2 = Stripe::Subscription.create({ items: [{ plan: 'silver' }], customer: customer.id }, another_subscription_header)
553
+ expect(sub1).not_to eq(sub2)
554
+ end
475
555
  end
476
556
 
477
557
  context "updating a subscription" do
@@ -592,7 +672,7 @@ shared_examples 'Customer Subscriptions' do
592
672
  subscription.save
593
673
 
594
674
  expect(subscription.discount).not_to be_nil
595
- expect(subscription.discount).to be_an_instance_of(Stripe::StripeObject)
675
+ expect(subscription.discount).to be_a(Stripe::Discount)
596
676
  expect(subscription.discount.coupon.id).to eq(coupon.id)
597
677
  end
598
678
 
@@ -891,6 +971,52 @@ shared_examples 'Customer Subscriptions' do
891
971
  end
892
972
  end
893
973
 
974
+ it "supports 'cancelling' by updating cancel_at_period_end" do
975
+ truth = stripe_helper.create_plan(id: 'the_truth')
976
+ customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: "the_truth")
977
+
978
+ sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id)
979
+ result = Stripe::Subscription.update(sub.id, cancel_at_period_end: true)
980
+
981
+ expect(result.status).to eq('active')
982
+ expect(result.cancel_at_period_end).to eq(true)
983
+ expect(result.id).to eq(sub.id)
984
+
985
+ customer = Stripe::Customer.retrieve('test_customer_sub')
986
+ expect(customer.subscriptions.data).to_not be_empty
987
+ expect(customer.subscriptions.count).to eq(1)
988
+ expect(customer.subscriptions.data.length).to eq(1)
989
+
990
+ expect(customer.subscriptions.data.first.status).to eq('active')
991
+ expect(customer.subscriptions.data.first.cancel_at_period_end).to eq(true)
992
+ expect(customer.subscriptions.data.first.ended_at).to be_nil
993
+ expect(customer.subscriptions.data.first.canceled_at).to_not be_nil
994
+ end
995
+
996
+ it "resumes a subscription cancelled by updating cancel_at_period_end" do
997
+ truth = stripe_helper.create_plan(id: 'the_truth')
998
+ customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: "the_truth")
999
+
1000
+ sub = Stripe::Subscription.retrieve(customer.subscriptions.data.first.id)
1001
+ Stripe::Subscription.update(sub.id, cancel_at_period_end: true)
1002
+
1003
+ result = Stripe::Subscription.update(sub.id, cancel_at_period_end: false)
1004
+
1005
+ expect(result.status).to eq('active')
1006
+ expect(result.cancel_at_period_end).to eq(false)
1007
+ expect(result.id).to eq(sub.id)
1008
+
1009
+ customer = Stripe::Customer.retrieve('test_customer_sub')
1010
+ expect(customer.subscriptions.data).to_not be_empty
1011
+ expect(customer.subscriptions.count).to eq(1)
1012
+ expect(customer.subscriptions.data.length).to eq(1)
1013
+
1014
+ expect(customer.subscriptions.data.first.status).to eq('active')
1015
+ expect(customer.subscriptions.data.first.cancel_at_period_end).to eq(false)
1016
+ expect(customer.subscriptions.data.first.ended_at).to be_nil
1017
+ expect(customer.subscriptions.data.first.canceled_at).to be_nil
1018
+ end
1019
+
894
1020
  it "doesn't change status of subscription when cancelling at period end" do
895
1021
  trial = stripe_helper.create_plan(id: 'trial', trial_period_days: 14)
896
1022
  customer = Stripe::Customer.create(id: 'test_customer_sub', source: gen_card_tk, plan: "trial")
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  shared_examples 'Transfer API' do
4
4
 
5
5
  it "creates a stripe transfer" do
6
- destination = Stripe::Account.create(email: "#{SecureRandom.uuid}@example.com", id: "acct_12345")
6
+ destination = Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", id: "acct_12345")
7
7
  transfer = Stripe::Transfer.create(amount: 100, currency: "usd", destination: destination.id)
8
8
 
9
9
  expect(transfer.id).to match /^test_tr/
@@ -31,7 +31,7 @@ shared_examples 'Transfer API' do
31
31
  end
32
32
 
33
33
  describe "listing transfers" do
34
- let(:destination) { Stripe::Account.create(email: "#{SecureRandom.uuid}@example.com", business_name: "MyCo") }
34
+ let(:destination) { Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", business_name: "MyCo") }
35
35
 
36
36
  before do
37
37
  3.times do
@@ -48,7 +48,7 @@ shared_examples 'Transfer API' do
48
48
  end
49
49
 
50
50
  it "filters the search to a specific destination" do
51
- d2 = Stripe::Account.create(email: "#{SecureRandom.uuid}@example.com", business_name: "MyCo")
51
+ d2 = Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", business_name: "MyCo")
52
52
  Stripe::Transfer.create(amount: "100", currency: "usd", destination: d2.id)
53
53
 
54
54
  expect(Stripe::Transfer.all(destination: d2.id).count).to eq(1)
@@ -104,7 +104,7 @@ shared_examples 'Transfer API' do
104
104
  end
105
105
 
106
106
  it "when amount is not integer", live: true do
107
- dest = Stripe::Account.create(type: "standard", email: "#{SecureRandom.uuid}@example.com", business_name: "Alex Smith")
107
+ dest = Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", business_name: "Alex Smith")
108
108
  expect { Stripe::Transfer.create(amount: '400.2',
109
109
  currency: 'usd',
110
110
  destination: dest.id,
@@ -116,7 +116,7 @@ shared_examples 'Transfer API' do
116
116
  end
117
117
 
118
118
  it "when amount is negative", live: true do
119
- dest = Stripe::Account.create(type: "standard", email: "#{SecureRandom.uuid}@example.com", business_name: "Alex Smith")
119
+ dest = Stripe::Account.create(type: "custom", email: "#{SecureRandom.uuid}@example.com", business_name: "Alex Smith")
120
120
  expect { Stripe::Transfer.create(amount: '-400',
121
121
  currency: 'usd',
122
122
  destination: dest.id,
@@ -1,4 +1,3 @@
1
-
2
1
  def require_stripe_examples
3
2
  Dir["./spec/shared_stripe_examples/**/*.rb"].each {|f| require f}
4
3
  Dir["./spec/integration_examples/**/*.rb"].each {|f| require f}
@@ -21,6 +20,7 @@ def it_behaves_like_stripe(&block)
21
20
  it_behaves_like 'Invoice API', &block
22
21
  it_behaves_like 'Invoice Item API', &block
23
22
  it_behaves_like 'Plan API', &block
23
+ it_behaves_like 'Product API', &block
24
24
  it_behaves_like 'Recipient API', &block
25
25
  it_behaves_like 'Refund API', &block
26
26
  it_behaves_like 'Transfer API', &block
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stripe-ruby-mock
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.6
4
+ version: 2.5.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gilbert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-29 00:00:00.000000000 Z
11
+ date: 2019-05-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: stripe
@@ -159,6 +159,7 @@ files:
159
159
  - lib/stripe_mock/request_handlers/orders.rb
160
160
  - lib/stripe_mock/request_handlers/payouts.rb
161
161
  - lib/stripe_mock/request_handlers/plans.rb
162
+ - lib/stripe_mock/request_handlers/products.rb
162
163
  - lib/stripe_mock/request_handlers/recipients.rb
163
164
  - lib/stripe_mock/request_handlers/refunds.rb
164
165
  - lib/stripe_mock/request_handlers/sources.rb
@@ -247,6 +248,7 @@ files:
247
248
  - spec/shared_stripe_examples/invoice_item_examples.rb
248
249
  - spec/shared_stripe_examples/payout_examples.rb
249
250
  - spec/shared_stripe_examples/plan_examples.rb
251
+ - spec/shared_stripe_examples/product_example.rb
250
252
  - spec/shared_stripe_examples/recipient_examples.rb
251
253
  - spec/shared_stripe_examples/refund_examples.rb
252
254
  - spec/shared_stripe_examples/subscription_examples.rb
@@ -315,6 +317,7 @@ test_files:
315
317
  - spec/shared_stripe_examples/invoice_item_examples.rb
316
318
  - spec/shared_stripe_examples/payout_examples.rb
317
319
  - spec/shared_stripe_examples/plan_examples.rb
320
+ - spec/shared_stripe_examples/product_example.rb
318
321
  - spec/shared_stripe_examples/recipient_examples.rb
319
322
  - spec/shared_stripe_examples/refund_examples.rb
320
323
  - spec/shared_stripe_examples/subscription_examples.rb