stripe-ruby-mock 2.5.6 → 2.5.7

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.
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