stripe-ruby-mock 2.5.0 → 2.5.1

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/stripe_mock.rb +3 -0
  4. data/lib/stripe_mock/api/account_balance.rb +14 -0
  5. data/lib/stripe_mock/api/webhooks.rb +2 -0
  6. data/lib/stripe_mock/client.rb +4 -0
  7. data/lib/stripe_mock/data.rb +78 -3
  8. data/lib/stripe_mock/instance.rb +21 -4
  9. data/lib/stripe_mock/request_handlers/accounts.rb +18 -2
  10. data/lib/stripe_mock/request_handlers/balance.rb +17 -0
  11. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +27 -6
  12. data/lib/stripe_mock/request_handlers/invoices.rb +20 -4
  13. data/lib/stripe_mock/request_handlers/payouts.rb +32 -0
  14. data/lib/stripe_mock/request_handlers/subscriptions.rb +65 -9
  15. data/lib/stripe_mock/request_handlers/tokens.rb +6 -0
  16. data/lib/stripe_mock/request_handlers/validators/param_validators.rb +7 -1
  17. data/lib/stripe_mock/server.rb +4 -0
  18. data/lib/stripe_mock/util.rb +8 -2
  19. data/lib/stripe_mock/version.rb +1 -1
  20. data/lib/stripe_mock/webhook_fixtures/account.updated.json +1 -1
  21. data/lib/stripe_mock/webhook_fixtures/charge.updated.json +58 -0
  22. data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +40 -10
  23. data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +39 -10
  24. data/lib/stripe_mock/webhook_fixtures/customer.subscription.trial_will_end.json +39 -10
  25. data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +39 -10
  26. data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +92 -85
  27. data/spec/shared_stripe_examples/account_examples.rb +8 -0
  28. data/spec/shared_stripe_examples/balance_examples.rb +11 -0
  29. data/spec/shared_stripe_examples/bank_examples.rb +27 -0
  30. data/spec/shared_stripe_examples/dispute_examples.rb +10 -0
  31. data/spec/shared_stripe_examples/invoice_examples.rb +68 -6
  32. data/spec/shared_stripe_examples/payout_examples.rb +68 -0
  33. data/spec/shared_stripe_examples/plan_examples.rb +7 -1
  34. data/spec/shared_stripe_examples/subscription_examples.rb +132 -2
  35. data/spec/shared_stripe_examples/webhook_event_examples.rb +69 -0
  36. data/spec/support/stripe_examples.rb +2 -0
  37. data/spec/util_spec.rb +35 -1
  38. metadata +10 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ce6d1ae38721fc9f43fa69e3d82217593b0789d9
4
- data.tar.gz: abbbfb0dd70438e23ac276215602a3d3a77705b1
3
+ metadata.gz: 27d9481d4fc8140fc2d42f733fc529fbb7a121cf
4
+ data.tar.gz: a8eeabea5e8b7d9181f597b9968e6e98b8fba4ed
5
5
  SHA512:
6
- metadata.gz: 49d92a3efee46c78cd157fd84de5e8eb456b6686b06c00a23262648395b0dd2cb647620304de703e52e5919102ce6c782a4947b50c39aef90428a02af9cfe9b0
7
- data.tar.gz: c87d09dd495bdca773e0ea39169f04900e7467f315f220ca556d907e9c0f294ddad399a73c2765e27e9ebe319b42f1b68b9ef825a02707c4877096777154a8c4
6
+ metadata.gz: b089c35e1b06284105b79baa151a5c61ebf54ec1e405406e3d0f827964c9e30f6e33b02a92dfc11ee83ec4a0e71a8a7fa35448c9a859476481bbbff2f60d15a1
7
+ data.tar.gz: e913cc264d89d765911c9de0066cc57a819f5235b3a2fb4d6266f7dd5561669e3ebe45e12faa5be8e12a74cc4a67ed51ca6adc2064bdcc02b1394dc5cf298899
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.0', :require => 'stripe_mock'
15
+ gem 'stripe-ruby-mock', '~> 2.5.1', :require => 'stripe_mock'
16
16
 
17
17
  ## Features
18
18
 
@@ -26,6 +26,7 @@ require 'stripe_mock/api/client'
26
26
  require 'stripe_mock/api/server'
27
27
 
28
28
  require 'stripe_mock/api/bank_tokens'
29
+ require 'stripe_mock/api/account_balance'
29
30
  require 'stripe_mock/api/conversion_rate'
30
31
  require 'stripe_mock/api/card_tokens'
31
32
  require 'stripe_mock/api/debug'
@@ -45,6 +46,7 @@ require 'stripe_mock/request_handlers/helpers/token_helpers.rb'
45
46
  require 'stripe_mock/request_handlers/validators/param_validators.rb'
46
47
 
47
48
  require 'stripe_mock/request_handlers/accounts.rb'
49
+ require 'stripe_mock/request_handlers/balance.rb'
48
50
  require 'stripe_mock/request_handlers/balance_transactions.rb'
49
51
  require 'stripe_mock/request_handlers/charges.rb'
50
52
  require 'stripe_mock/request_handlers/cards.rb'
@@ -60,6 +62,7 @@ require 'stripe_mock/request_handlers/plans.rb'
60
62
  require 'stripe_mock/request_handlers/recipients.rb'
61
63
  require 'stripe_mock/request_handlers/refunds.rb'
62
64
  require 'stripe_mock/request_handlers/transfers.rb'
65
+ require 'stripe_mock/request_handlers/payouts.rb'
63
66
  require 'stripe_mock/request_handlers/subscriptions.rb'
64
67
  require 'stripe_mock/request_handlers/tokens.rb'
65
68
  require 'stripe_mock/request_handlers/country_spec.rb'
@@ -0,0 +1,14 @@
1
+ module StripeMock
2
+
3
+ def self.set_account_balance(value)
4
+ case @state
5
+ when 'local'
6
+ instance.account_balance = value
7
+ when 'remote'
8
+ client.set_account_balance(value)
9
+ else
10
+ raise UnstartedStateError
11
+ end
12
+ end
13
+
14
+ end
@@ -18,6 +18,7 @@ module StripeMock
18
18
  json[:account] = params.delete(:account) if params.key?(:account)
19
19
  json[:data][:object] = Util.rmerge(json[:data][:object], params)
20
20
  json.delete(:id)
21
+ json[:created] = params[:created] || Time.now.to_i
21
22
 
22
23
  if @state == 'local'
23
24
  event_data = instance.generate_webhook_event(json)
@@ -43,6 +44,7 @@ module StripeMock
43
44
  'account.external_account.deleted',
44
45
  'balance.available',
45
46
  'charge.succeeded',
47
+ 'charge.updated',
46
48
  'charge.failed',
47
49
  'charge.refunded',
48
50
  'charge.dispute.created',
@@ -73,6 +73,10 @@ module StripeMock
73
73
  timeout_wrap { @pipe.set_conversion_rate(value) }
74
74
  end
75
75
 
76
+ def set_account_balance(value)
77
+ timeout_wrap { @pipe.set_account_balance(value) }
78
+ end
79
+
76
80
  def destroy_resource(type, id)
77
81
  timeout_wrap { @pipe.destroy_resource(type, id) }
78
82
  end
@@ -12,7 +12,7 @@ module StripeMock
12
12
  timezone: "US/Pacific",
13
13
  details_submitted: false,
14
14
  charges_enabled: false,
15
- transfers_enabled: false,
15
+ payouts_enabled: false,
16
16
  currencies_supported: [
17
17
  "usd"
18
18
  ],
@@ -103,7 +103,7 @@ module StripeMock
103
103
 
104
104
  def self.mock_customer(sources, params)
105
105
  cus_id = params[:id] || "test_cus_default"
106
- currency = params[:currency] || nil
106
+ currency = params[:currency] || 'usd'
107
107
  sources.each {|source| source[:customer] = cus_id}
108
108
  {
109
109
  email: 'stripe_mock@example.com',
@@ -207,7 +207,8 @@ module StripeMock
207
207
  metadata: {},
208
208
  charge: "ch_4fWhYjzQ23UFWT",
209
209
  receipt_number: nil,
210
- status: "succeeded"
210
+ status: "succeeded",
211
+ reason: "requested_by_customer"
211
212
  }.merge(params)
212
213
  end
213
214
 
@@ -284,6 +285,7 @@ module StripeMock
284
285
  def self.mock_subscription(params={})
285
286
  StripeMock::Util.rmerge({
286
287
  created: 1478204116,
288
+ billing: 'charge_automatically',
287
289
  current_period_start: 1308595038,
288
290
  current_period_end: 1308681468,
289
291
  status: 'trialing',
@@ -620,6 +622,21 @@ module StripeMock
620
622
  }.merge(params)
621
623
  end
622
624
 
625
+ def self.mock_payout(params={})
626
+ currency = params[:currency] || 'usd'
627
+ id = params[:id] || 'po_test_payout'
628
+ {
629
+ :amount => 100,
630
+ :id => id,
631
+ :livemode => false,
632
+ :metadata => {},
633
+ :currency => currency,
634
+ :object => "payout",
635
+ :date => 1304114826,
636
+ :description => "Payout description",
637
+ }.merge(params)
638
+ end
639
+
623
640
  def self.mock_disputes(ids=[])
624
641
  disputes = {}
625
642
  ids.each do |id|
@@ -909,6 +926,38 @@ module StripeMock
909
926
  }
910
927
  end
911
928
 
929
+ def self.mock_balance(usd_balance = 10000)
930
+ {
931
+ object: "balance",
932
+ available: [
933
+ {
934
+ currency: "usd",
935
+ amount: usd_balance,
936
+ source_types: {
937
+ card: 25907032203,
938
+ bank_account: 108476658,
939
+ bitcoin_receiver: 1545182
940
+ }
941
+ }],
942
+ connect_reserved: [
943
+ {
944
+ currency: "usd",
945
+ amount: 4700
946
+ }],
947
+ livemode: false,
948
+ pending: [
949
+ {
950
+ currency: "usd",
951
+ amount: 22738833554,
952
+ source_types: {
953
+ card: 22738826610,
954
+ bank_account: 0,
955
+ bitcoin_receiver: 6944
956
+ }
957
+ }]
958
+ }
959
+ end
960
+
912
961
  def self.mock_balance_transactions(ids=[])
913
962
  bts = {}
914
963
  ids.each do |id|
@@ -952,5 +1001,31 @@ module StripeMock
952
1001
  type: "charge"
953
1002
  }.merge(params)
954
1003
  end
1004
+
1005
+ def self.mock_subscription_item(params = {})
1006
+ iid = params[:id] || 'test_txn_default'
1007
+ {
1008
+ id: iid,
1009
+ object: 'subscription_item',
1010
+ created: 1504716183,
1011
+ metadata: {
1012
+ },
1013
+ plan: {
1014
+ id: 'PER_USER_PLAN1',
1015
+ object: 'plan',
1016
+ amount: 1337,
1017
+ created: 1504716177,
1018
+ currency: 'usd',
1019
+ interval: 'month',
1020
+ interval_count: 1,
1021
+ livemode: false,
1022
+ metadata: {},
1023
+ name: 'StripeMock Default Plan ID',
1024
+ statement_descriptor: nil,
1025
+ trial_period_days: nil
1026
+ },
1027
+ quantity: 2
1028
+ }.merge(params)
1029
+ end
955
1030
  end
956
1031
  end
@@ -21,6 +21,7 @@ module StripeMock
21
21
  end
22
22
 
23
23
  include StripeMock::RequestHandlers::Accounts
24
+ include StripeMock::RequestHandlers::Balance
24
25
  include StripeMock::RequestHandlers::BalanceTransactions
25
26
  include StripeMock::RequestHandlers::Charges
26
27
  include StripeMock::RequestHandlers::Cards
@@ -39,16 +40,17 @@ module StripeMock
39
40
  include StripeMock::RequestHandlers::Transfers
40
41
  include StripeMock::RequestHandlers::Tokens
41
42
  include StripeMock::RequestHandlers::CountrySpec
43
+ include StripeMock::RequestHandlers::Payouts
42
44
 
43
-
44
- attr_reader :accounts, :balance_transactions, :bank_tokens, :charges, :coupons, :customers,
45
+ attr_reader :accounts, :balance, :balance_transactions, :bank_tokens, :charges, :coupons, :customers,
45
46
  :disputes, :events, :invoices, :invoice_items, :orders, :plans, :recipients,
46
- :refunds, :transfers, :subscriptions, :country_spec
47
+ :refunds, :transfers, :payouts, :subscriptions, :country_spec, :subscriptions_items
47
48
 
48
- attr_accessor :error_queue, :debug, :conversion_rate
49
+ attr_accessor :error_queue, :debug, :conversion_rate, :account_balance
49
50
 
50
51
  def initialize
51
52
  @accounts = {}
53
+ @balance = Data.mock_balance
52
54
  @balance_transactions = Data.mock_balance_transactions(['txn_05RsQX2eZvKYlo2C0FRTGSSA','txn_15RsQX2eZvKYlo2C0ERTYUIA', 'txn_25RsQX2eZvKYlo2C0ZXCVBNM', 'txn_35RsQX2eZvKYlo2C0QAZXSWE', 'txn_45RsQX2eZvKYlo2C0EDCVFRT', 'txn_55RsQX2eZvKYlo2C0OIKLJUY', 'txn_65RsQX2eZvKYlo2C0ASDFGHJ', 'txn_75RsQX2eZvKYlo2C0EDCXSWQ', 'txn_85RsQX2eZvKYlo2C0UJMCDET', 'txn_95RsQX2eZvKYlo2C0EDFRYUI'])
53
55
  @bank_tokens = {}
54
56
  @card_tokens = {}
@@ -64,14 +66,18 @@ module StripeMock
64
66
  @recipients = {}
65
67
  @refunds = {}
66
68
  @transfers = {}
69
+ @payouts = {}
67
70
  @subscriptions = {}
71
+ @subscriptions_items = []
68
72
  @country_spec = {}
69
73
 
70
74
  @debug = false
71
75
  @error_queue = ErrorQueue.new
72
76
  @id_counter = 0
73
77
  @balance_transaction_counter = 0
78
+ @dispute_counter = 0
74
79
  @conversion_rate = 1.0
80
+ @account_balance = 10000
75
81
 
76
82
  # This is basically a cache for ParamValidators
77
83
  @base_strategy = TestStrategies::Base.new
@@ -125,6 +131,8 @@ module StripeMock
125
131
  case object
126
132
  when :balance_transaction
127
133
  id = new_balance_transaction('txn', attributes)
134
+ when :dispute
135
+ id = new_dispute('dp', attributes)
128
136
  else
129
137
  raise UnsupportedRequestError.new "Unsupported stripe object `#{object}`"
130
138
  end
@@ -134,6 +142,9 @@ module StripeMock
134
142
  when :balance_transaction
135
143
  btxn = assert_existence :balance_transaction, id, @balance_transactions[id]
136
144
  btxn.merge!(attributes)
145
+ when :dispute
146
+ dispute = assert_existence :dispute, id, @disputes[id]
147
+ dispute.merge!(attributes)
137
148
  else
138
149
  raise UnsupportedRequestError.new "Unsupported stripe object `#{object}`"
139
150
  end
@@ -169,6 +180,12 @@ module StripeMock
169
180
  id
170
181
  end
171
182
 
183
+ def new_dispute(prefix, params = {})
184
+ id = "#{StripeMock.global_id_prefix}#{prefix}_#{@dispute_counter += 1}"
185
+ @disputes[id] = Data.mock_dispute(params.merge(id: id))
186
+ id
187
+ end
188
+
172
189
  def symbolize_names(hash)
173
190
  Stripe::Util.symbolize_names(hash)
174
191
  end
@@ -26,8 +26,12 @@ module StripeMock
26
26
 
27
27
  def update_account(route, method_url, params, headers)
28
28
  route =~ method_url
29
- assert_existence :account, $1, accounts[$1]
30
- accounts[$1].merge!(params)
29
+ account = assert_existence :account, $1, accounts[$1]
30
+ account.merge!(params)
31
+ if blank_value?(params[:tos_acceptance], :date)
32
+ raise Stripe::InvalidRequestError.new("Invalid integer: ", "tos_acceptance[date]", http_status: 400)
33
+ end
34
+ account
31
35
  end
32
36
 
33
37
  def list_accounts(route, method_url, params, headers)
@@ -49,6 +53,18 @@ module StripeMock
49
53
  accounts[acc[:id]] = acc
50
54
  end
51
55
  end
56
+
57
+ # Checks if setting a blank value
58
+ #
59
+ # returns true if the key is included in the hash
60
+ # and its value is empty or nil
61
+ def blank_value?(hash, key)
62
+ if hash.key?(key)
63
+ value = hash[key]
64
+ return true if value.nil? || "" == value
65
+ end
66
+ false
67
+ end
52
68
  end
53
69
  end
54
70
  end
@@ -0,0 +1,17 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module Balance
4
+
5
+ def Balance.included(klass)
6
+ klass.add_handler 'get /v1/balance', :get_balance
7
+ end
8
+
9
+ def get_balance(route, method_url, params, headers)
10
+ route =~ method_url
11
+
12
+ return_balance = Data.mock_balance(account_balance)
13
+ return_balance
14
+ end
15
+ end
16
+ end
17
+ end
@@ -9,12 +9,14 @@ module StripeMock
9
9
  def custom_subscription_params(plan, cus, options = {})
10
10
  verify_trial_end(options[:trial_end]) if options[:trial_end]
11
11
 
12
- start_time = options[:current_period_start] || Time.now.utc.to_i
13
- params = { plan: plan, customer: cus[:id], current_period_start: start_time }
12
+ now = Time.now.utc.to_i
13
+ created_time = options[:created] || now
14
+ start_time = options[:current_period_start] || now
15
+ params = { plan: plan, customer: cus[:id], current_period_start: start_time, created: created_time }
14
16
  params.merge! options.select {|k,v| k =~ /application_fee_percent|quantity|metadata|tax_percent/}
15
17
  # TODO: Implement coupon logic
16
18
 
17
- if ((plan[:trial_period_days]||0) == 0 && options[:trial_end].nil?) || options[:trial_end] == "now"
19
+ if (((plan && plan[:trial_period_days]) || 0) == 0 && options[:trial_end].nil?) || options[:trial_end] == "now"
18
20
  end_time = get_ending_time(start_time, plan)
19
21
  params.merge!({status: 'active', current_period_end: end_time, trial_start: nil, trial_end: nil})
20
22
  else
@@ -28,12 +30,16 @@ module StripeMock
28
30
  def add_subscription_to_customer(cus, sub)
29
31
  if sub[:trial_end].nil? || sub[:trial_end] == "now"
30
32
  id = new_id('ch')
31
- charges[id] = Data.mock_charge(:id => id, :customer => cus[:id], :amount => sub[:plan][:amount])
33
+ charges[id] = Data.mock_charge(
34
+ :id => id,
35
+ :customer => cus[:id],
36
+ :amount => (sub[:plan] ? sub[:plan][:amount] : total_items_amount(sub[:items][:data]))
37
+ )
32
38
  end
33
39
 
34
40
  if cus[:currency].nil?
35
- cus[:currency] = sub[:plan][:currency]
36
- elsif cus[:currency] != sub[:plan][:currency]
41
+ cus[:currency] = sub[:items][:data][0][:plan][:currency]
42
+ elsif cus[:currency] != sub[:items][:data][0][:plan][:currency]
37
43
  raise Stripe::InvalidRequestError.new( "Can't combine currencies on a single customer. This customer has had a subscription, coupon, or invoice item with currency #{cus[:currency]}", 'currency', http_status: 400)
38
44
  end
39
45
  cus[:subscriptions][:total_count] = (cus[:subscriptions][:total_count] || 0) + 1
@@ -50,6 +56,8 @@ module StripeMock
50
56
  # `intervals` is set to 1 when calculating current_period_end from current_period_start & plan
51
57
  # `intervals` is set to 2 when calculating Stripe::Invoice.upcoming end from current_period_start & plan
52
58
  def get_ending_time(start_time, plan, intervals = 1)
59
+ return start_time unless plan
60
+
53
61
  case plan[:interval]
54
62
  when "week"
55
63
  start_time + (604800 * (plan[:interval_count] || 1) * intervals)
@@ -74,6 +82,19 @@ module StripeMock
74
82
  end
75
83
  end
76
84
 
85
+ def total_items_amount(items)
86
+ total = 0
87
+ items.each { |i| total += (i[:quantity] || 1) * i[:plan][:amount] }
88
+ total
89
+ end
90
+
91
+ def mock_subscription_items(items = [])
92
+ data = []
93
+ items.each do |i|
94
+ data << Data.mock_subscription_item(i.merge(plan: plans[i[:plan].to_s]))
95
+ end
96
+ data
97
+ end
77
98
  end
78
99
  end
79
100
  end
@@ -73,7 +73,7 @@ module StripeMock
73
73
  else
74
74
  customer[:subscriptions][:data].min_by { |sub| sub[:current_period_end] }
75
75
  end
76
-
76
+
77
77
  if params[:subscription_proration_date] && !((subscription[:current_period_start]..subscription[:current_period_end]) === params[:subscription_proration_date])
78
78
  raise Stripe::InvalidRequestError.new('Cannot specify proration date outside of current subscription period', nil, http_status: 400)
79
79
  end
@@ -112,14 +112,30 @@ module StripeMock
112
112
  quantity: subscription[:quantity],
113
113
  proration: true
114
114
  )
115
+
116
+ preview_plan = assert_existence :plan, params[:subscription_plan], plans[params[:subscription_plan]]
117
+ if preview_plan[:interval] == subscription[:plan][:interval] && preview_plan[:interval_count] == subscription[:plan][:interval_count] && params[:subscription_trial_end].nil?
118
+ remaining_amount = preview_plan[:amount] * subscription_quantity * (subscription[:current_period_end] - subscription_proration_date.to_i) / (subscription[:current_period_end] - subscription[:current_period_start])
119
+ invoice_lines << Data.mock_line_item(
120
+ id: new_id('ii'),
121
+ amount: remaining_amount,
122
+ description: 'Remaining time',
123
+ plan: preview_plan,
124
+ period: {
125
+ start: subscription_proration_date.to_i,
126
+ end: subscription[:current_period_end]
127
+ },
128
+ quantity: subscription_quantity,
129
+ proration: true
130
+ )
131
+ end
115
132
  end
116
133
 
117
134
  subscription_line = get_mock_subscription_line_item(preview_subscription)
118
135
  invoice_lines << subscription_line
119
136
 
120
- id = new_id('in')
121
- invoices[id] = Data.mock_invoice(invoice_lines,
122
- id: id,
137
+ Data.mock_invoice(invoice_lines,
138
+ id: new_id('in'),
123
139
  customer: customer[:id],
124
140
  discount: customer[:discount],
125
141
  date: invoice_date,