epopia-stripe-ruby-mock 2.5.8

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 (171) hide show
  1. checksums.yaml +7 -0
  2. data/.env +2 -0
  3. data/.gitignore +8 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +28 -0
  6. data/Gemfile +12 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +413 -0
  9. data/Rakefile +14 -0
  10. data/bin/stripe-mock-server +19 -0
  11. data/lib/stripe_mock.rb +95 -0
  12. data/lib/stripe_mock/api/account_balance.rb +14 -0
  13. data/lib/stripe_mock/api/bank_tokens.rb +13 -0
  14. data/lib/stripe_mock/api/card_tokens.rb +13 -0
  15. data/lib/stripe_mock/api/client.rb +41 -0
  16. data/lib/stripe_mock/api/conversion_rate.rb +14 -0
  17. data/lib/stripe_mock/api/debug.rb +11 -0
  18. data/lib/stripe_mock/api/errors.rb +65 -0
  19. data/lib/stripe_mock/api/global_id_prefix.rb +22 -0
  20. data/lib/stripe_mock/api/instance.rb +38 -0
  21. data/lib/stripe_mock/api/live.rb +15 -0
  22. data/lib/stripe_mock/api/server.rb +39 -0
  23. data/lib/stripe_mock/api/test_helpers.rb +24 -0
  24. data/lib/stripe_mock/api/webhooks.rb +88 -0
  25. data/lib/stripe_mock/client.rb +127 -0
  26. data/lib/stripe_mock/data.rb +1193 -0
  27. data/lib/stripe_mock/data/list.rb +73 -0
  28. data/lib/stripe_mock/error_queue.rb +27 -0
  29. data/lib/stripe_mock/errors/closed_client_connection_error.rb +9 -0
  30. data/lib/stripe_mock/errors/server_timeout_error.rb +12 -0
  31. data/lib/stripe_mock/errors/stripe_mock_error.rb +15 -0
  32. data/lib/stripe_mock/errors/uninitialized_instance_error.rb +9 -0
  33. data/lib/stripe_mock/errors/unstarted_state_error.rb +9 -0
  34. data/lib/stripe_mock/errors/unsupported_request_error.rb +4 -0
  35. data/lib/stripe_mock/instance.rb +237 -0
  36. data/lib/stripe_mock/request_handlers/accounts.rb +86 -0
  37. data/lib/stripe_mock/request_handlers/balance.rb +17 -0
  38. data/lib/stripe_mock/request_handlers/balance_transactions.rb +37 -0
  39. data/lib/stripe_mock/request_handlers/cards.rb +35 -0
  40. data/lib/stripe_mock/request_handlers/charges.rb +177 -0
  41. data/lib/stripe_mock/request_handlers/country_spec.rb +22 -0
  42. data/lib/stripe_mock/request_handlers/coupons.rb +35 -0
  43. data/lib/stripe_mock/request_handlers/customers.rb +137 -0
  44. data/lib/stripe_mock/request_handlers/disputes.rb +35 -0
  45. data/lib/stripe_mock/request_handlers/ephemeral_key.rb +13 -0
  46. data/lib/stripe_mock/request_handlers/events.rb +21 -0
  47. data/lib/stripe_mock/request_handlers/external_accounts.rb +55 -0
  48. data/lib/stripe_mock/request_handlers/helpers/bank_account_helpers.rb +14 -0
  49. data/lib/stripe_mock/request_handlers/helpers/card_helpers.rb +127 -0
  50. data/lib/stripe_mock/request_handlers/helpers/charge_helpers.rb +16 -0
  51. data/lib/stripe_mock/request_handlers/helpers/coupon_helpers.rb +17 -0
  52. data/lib/stripe_mock/request_handlers/helpers/external_account_helpers.rb +49 -0
  53. data/lib/stripe_mock/request_handlers/helpers/subscription_helpers.rb +119 -0
  54. data/lib/stripe_mock/request_handlers/helpers/token_helpers.rb +44 -0
  55. data/lib/stripe_mock/request_handlers/invoice_items.rb +45 -0
  56. data/lib/stripe_mock/request_handlers/invoices.rb +177 -0
  57. data/lib/stripe_mock/request_handlers/orders.rb +80 -0
  58. data/lib/stripe_mock/request_handlers/payment_intents.rb +203 -0
  59. data/lib/stripe_mock/request_handlers/payment_methods.rb +112 -0
  60. data/lib/stripe_mock/request_handlers/payouts.rb +32 -0
  61. data/lib/stripe_mock/request_handlers/plans.rb +42 -0
  62. data/lib/stripe_mock/request_handlers/products.rb +43 -0
  63. data/lib/stripe_mock/request_handlers/recipients.rb +60 -0
  64. data/lib/stripe_mock/request_handlers/refunds.rb +91 -0
  65. data/lib/stripe_mock/request_handlers/sources.rb +55 -0
  66. data/lib/stripe_mock/request_handlers/subscription_items.rb +36 -0
  67. data/lib/stripe_mock/request_handlers/subscriptions.rb +296 -0
  68. data/lib/stripe_mock/request_handlers/tax_rates.rb +36 -0
  69. data/lib/stripe_mock/request_handlers/tokens.rb +75 -0
  70. data/lib/stripe_mock/request_handlers/transfers.rb +65 -0
  71. data/lib/stripe_mock/request_handlers/validators/param_validators.rb +32 -0
  72. data/lib/stripe_mock/server.rb +93 -0
  73. data/lib/stripe_mock/test_strategies/base.rb +81 -0
  74. data/lib/stripe_mock/test_strategies/live.rb +40 -0
  75. data/lib/stripe_mock/test_strategies/mock.rb +27 -0
  76. data/lib/stripe_mock/util.rb +44 -0
  77. data/lib/stripe_mock/version.rb +4 -0
  78. data/lib/stripe_mock/webhook_fixtures/account.application.deauthorized.json +12 -0
  79. data/lib/stripe_mock/webhook_fixtures/account.external_account.created.json +27 -0
  80. data/lib/stripe_mock/webhook_fixtures/account.external_account.deleted.json +27 -0
  81. data/lib/stripe_mock/webhook_fixtures/account.external_account.updated.json +27 -0
  82. data/lib/stripe_mock/webhook_fixtures/account.updated.json +26 -0
  83. data/lib/stripe_mock/webhook_fixtures/balance.available.json +25 -0
  84. data/lib/stripe_mock/webhook_fixtures/charge.dispute.closed.json +22 -0
  85. data/lib/stripe_mock/webhook_fixtures/charge.dispute.created.json +22 -0
  86. data/lib/stripe_mock/webhook_fixtures/charge.dispute.funds_reinstated.json +88 -0
  87. data/lib/stripe_mock/webhook_fixtures/charge.dispute.funds_withdrawn.json +88 -0
  88. data/lib/stripe_mock/webhook_fixtures/charge.dispute.updated.json +25 -0
  89. data/lib/stripe_mock/webhook_fixtures/charge.failed.json +56 -0
  90. data/lib/stripe_mock/webhook_fixtures/charge.refunded.json +69 -0
  91. data/lib/stripe_mock/webhook_fixtures/charge.succeeded.json +55 -0
  92. data/lib/stripe_mock/webhook_fixtures/charge.updated.json +58 -0
  93. data/lib/stripe_mock/webhook_fixtures/coupon.created.json +23 -0
  94. data/lib/stripe_mock/webhook_fixtures/coupon.deleted.json +23 -0
  95. data/lib/stripe_mock/webhook_fixtures/customer.created.json +54 -0
  96. data/lib/stripe_mock/webhook_fixtures/customer.deleted.json +42 -0
  97. data/lib/stripe_mock/webhook_fixtures/customer.discount.created.json +28 -0
  98. data/lib/stripe_mock/webhook_fixtures/customer.discount.deleted.json +28 -0
  99. data/lib/stripe_mock/webhook_fixtures/customer.discount.updated.json +43 -0
  100. data/lib/stripe_mock/webhook_fixtures/customer.source.created.json +32 -0
  101. data/lib/stripe_mock/webhook_fixtures/customer.source.deleted.json +32 -0
  102. data/lib/stripe_mock/webhook_fixtures/customer.source.updated.json +36 -0
  103. data/lib/stripe_mock/webhook_fixtures/customer.subscription.created.json +66 -0
  104. data/lib/stripe_mock/webhook_fixtures/customer.subscription.deleted.json +65 -0
  105. data/lib/stripe_mock/webhook_fixtures/customer.subscription.trial_will_end.json +65 -0
  106. data/lib/stripe_mock/webhook_fixtures/customer.subscription.updated.json +78 -0
  107. data/lib/stripe_mock/webhook_fixtures/customer.updated.json +57 -0
  108. data/lib/stripe_mock/webhook_fixtures/invoice.created.json +71 -0
  109. data/lib/stripe_mock/webhook_fixtures/invoice.payment_failed.json +105 -0
  110. data/lib/stripe_mock/webhook_fixtures/invoice.payment_succeeded.json +112 -0
  111. data/lib/stripe_mock/webhook_fixtures/invoice.updated.json +74 -0
  112. data/lib/stripe_mock/webhook_fixtures/invoiceitem.created.json +21 -0
  113. data/lib/stripe_mock/webhook_fixtures/invoiceitem.deleted.json +21 -0
  114. data/lib/stripe_mock/webhook_fixtures/invoiceitem.updated.json +24 -0
  115. data/lib/stripe_mock/webhook_fixtures/plan.created.json +20 -0
  116. data/lib/stripe_mock/webhook_fixtures/plan.deleted.json +20 -0
  117. data/lib/stripe_mock/webhook_fixtures/plan.updated.json +23 -0
  118. data/lib/stripe_mock/webhook_fixtures/transfer.created.json +89 -0
  119. data/lib/stripe_mock/webhook_fixtures/transfer.failed.json +89 -0
  120. data/lib/stripe_mock/webhook_fixtures/transfer.paid.json +89 -0
  121. data/lib/stripe_mock/webhook_fixtures/transfer.updated.json +92 -0
  122. data/lib/trollop.rb +782 -0
  123. data/spec/_dummy/webhooks/dummy.event.json +6 -0
  124. data/spec/api/instance_spec.rb +30 -0
  125. data/spec/fixtures/create_refund.yml +126 -0
  126. data/spec/fixtures/stripe_webhooks/account.updated.json +7 -0
  127. data/spec/fixtures/stripe_webhooks/custom.account.updated.json +5 -0
  128. data/spec/instance_spec.rb +100 -0
  129. data/spec/integration_examples/charge_token_examples.rb +51 -0
  130. data/spec/integration_examples/customer_card_examples.rb +42 -0
  131. data/spec/integration_examples/prepare_error_examples.rb +38 -0
  132. data/spec/list_spec.rb +140 -0
  133. data/spec/readme_spec.rb +75 -0
  134. data/spec/server_spec.rb +139 -0
  135. data/spec/shared_stripe_examples/account_examples.rb +96 -0
  136. data/spec/shared_stripe_examples/balance_examples.rb +11 -0
  137. data/spec/shared_stripe_examples/balance_transaction_examples.rb +63 -0
  138. data/spec/shared_stripe_examples/bank_examples.rb +229 -0
  139. data/spec/shared_stripe_examples/bank_token_examples.rb +59 -0
  140. data/spec/shared_stripe_examples/card_examples.rb +307 -0
  141. data/spec/shared_stripe_examples/card_token_examples.rb +185 -0
  142. data/spec/shared_stripe_examples/charge_examples.rb +510 -0
  143. data/spec/shared_stripe_examples/country_specs_examples.rb +18 -0
  144. data/spec/shared_stripe_examples/coupon_examples.rb +85 -0
  145. data/spec/shared_stripe_examples/customer_examples.rb +453 -0
  146. data/spec/shared_stripe_examples/dispute_examples.rb +98 -0
  147. data/spec/shared_stripe_examples/ephemeral_key_examples.rb +17 -0
  148. data/spec/shared_stripe_examples/error_mock_examples.rb +162 -0
  149. data/spec/shared_stripe_examples/external_account_examples.rb +170 -0
  150. data/spec/shared_stripe_examples/extra_features_examples.rb +36 -0
  151. data/spec/shared_stripe_examples/invoice_examples.rb +524 -0
  152. data/spec/shared_stripe_examples/invoice_item_examples.rb +69 -0
  153. data/spec/shared_stripe_examples/payment_intent_examples.rb +131 -0
  154. data/spec/shared_stripe_examples/payment_method_examples.rb +175 -0
  155. data/spec/shared_stripe_examples/payout_examples.rb +68 -0
  156. data/spec/shared_stripe_examples/plan_examples.rb +194 -0
  157. data/spec/shared_stripe_examples/product_example.rb +65 -0
  158. data/spec/shared_stripe_examples/recipient_examples.rb +118 -0
  159. data/spec/shared_stripe_examples/refund_examples.rb +472 -0
  160. data/spec/shared_stripe_examples/subscription_examples.rb +1148 -0
  161. data/spec/shared_stripe_examples/subscription_items_examples.rb +75 -0
  162. data/spec/shared_stripe_examples/tax_rate_examples.rb +42 -0
  163. data/spec/shared_stripe_examples/transfer_examples.rb +130 -0
  164. data/spec/shared_stripe_examples/validation_examples.rb +19 -0
  165. data/spec/shared_stripe_examples/webhook_event_examples.rb +261 -0
  166. data/spec/spec_helper.rb +58 -0
  167. data/spec/stripe_mock_spec.rb +123 -0
  168. data/spec/support/stripe_examples.rb +42 -0
  169. data/spec/util_spec.rb +121 -0
  170. data/stripe-ruby-mock.gemspec +27 -0
  171. metadata +344 -0
@@ -0,0 +1,73 @@
1
+ module StripeMock
2
+ module Data
3
+ class List
4
+ attr_reader :data, :limit, :offset, :starting_after, :ending_before
5
+
6
+ def initialize(data, options = {})
7
+ @data = Array(data.clone)
8
+ @limit = [[options[:limit] || 10, 100].min, 1].max # restrict @limit to 1..100
9
+ @starting_after = options[:starting_after]
10
+ @ending_before = options[:ending_before]
11
+ if @data.first.is_a?(Hash) && @data.first[:created]
12
+ @data.sort_by! { |x| x[:created] }
13
+ @data.reverse!
14
+ elsif @data.first.respond_to?(:created)
15
+ @data.sort_by { |x| x.created }
16
+ @data.reverse!
17
+ end
18
+ end
19
+
20
+ def url
21
+ "/v1/#{object_types}"
22
+ end
23
+
24
+ def to_hash
25
+ { object: "list", data: data_page, url: url, has_more: has_more? }
26
+ end
27
+ alias_method :to_h, :to_hash
28
+
29
+ def has_more?
30
+ (offset + limit) < data.size
31
+ end
32
+
33
+ def method_missing(method_name, *args, &block)
34
+ hash = to_hash
35
+
36
+ if hash.keys.include?(method_name)
37
+ hash[method_name]
38
+ else
39
+ super
40
+ end
41
+ end
42
+
43
+ def respond_to?(method_name, priv = false)
44
+ to_hash.keys.include?(method_name) || super
45
+ end
46
+
47
+ private
48
+
49
+ def offset
50
+ case
51
+ when starting_after
52
+ index = data.index { |datum| datum[:id] == starting_after }
53
+ (index || raise("No such object id: #{starting_after}")) + 1
54
+ when ending_before
55
+ index = data.index { |datum| datum[:id] == ending_before }
56
+ (index || raise("No such object id: #{ending_before}")) - 1
57
+ else
58
+ 0
59
+ end
60
+ end
61
+
62
+ def data_page
63
+ data[offset, limit]
64
+ end
65
+
66
+ def object_types
67
+ if first_object = data[0]
68
+ "#{first_object.class.to_s.split('::')[-1].downcase}s"
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,27 @@
1
+ require 'drb/drb'
2
+
3
+ module StripeMock
4
+ class ErrorQueue
5
+ include DRb::DRbUndumped
6
+ extend DRb::DRbUndumped
7
+
8
+ def initialize
9
+ @queue = []
10
+ end
11
+
12
+ def queue(error, handler_names)
13
+ @queue << handler_names.map {|n| [n, error]}
14
+ end
15
+
16
+ def error_for_handler_name(handler_name)
17
+ return nil if @queue.count == 0
18
+ triggers = @queue.first
19
+ (triggers.assoc(:all) || triggers.assoc(handler_name) || [])[1]
20
+ end
21
+
22
+ def dequeue
23
+ @queue.shift
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ module StripeMock
2
+ class ClosedClientConnectionError < StripeMockError
3
+
4
+ def initialize
5
+ super("This StripeMock client has already been closed.")
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module StripeMock
2
+ class ServerTimeoutError < StripeMockError
3
+
4
+ attr_reader :associated_error
5
+
6
+ def initialize(associated_error)
7
+ @associated_error = associated_error
8
+ super("Unable to connect to stripe mock server (did you forget to run `$ stripe-mock-server`?)")
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ module StripeMock
2
+ class StripeMockError < StandardError
3
+
4
+ attr_reader :message
5
+
6
+ def initialize(message)
7
+ @message = message
8
+ end
9
+
10
+ def to_s
11
+ @message
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ module StripeMock
2
+ class UninitializedInstanceError < StripeMockError
3
+
4
+ def initialize
5
+ super("StripeMock instance is nil (did you forget to call `StripeMock.start`?)")
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module StripeMock
2
+ class UnstartedStateError < StripeMockError
3
+
4
+ def initialize
5
+ super("StripeMock has not been started. Please call StripeMock.start or StripeMock.start_client")
6
+ end
7
+
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ module StripeMock
2
+ class UnsupportedRequestError < StripeMockError
3
+ end
4
+ end
@@ -0,0 +1,237 @@
1
+ module StripeMock
2
+ class Instance
3
+
4
+ include StripeMock::RequestHandlers::Helpers
5
+ include StripeMock::RequestHandlers::ParamValidators
6
+
7
+ DUMMY_API_KEY = (0...32).map { (65 + rand(26)).chr }.join.downcase
8
+
9
+ # Handlers are ordered by priority
10
+ @@handlers = []
11
+
12
+ def self.add_handler(route, name)
13
+ @@handlers << {
14
+ :route => %r{^#{route}$},
15
+ :name => name
16
+ }
17
+ end
18
+
19
+ def self.handler_for_method_url(method_url)
20
+ @@handlers.find {|h| method_url =~ h[:route] }
21
+ end
22
+
23
+ include StripeMock::RequestHandlers::PaymentIntents
24
+ include StripeMock::RequestHandlers::PaymentMethods
25
+ include StripeMock::RequestHandlers::ExternalAccounts
26
+ include StripeMock::RequestHandlers::Accounts
27
+ include StripeMock::RequestHandlers::Balance
28
+ include StripeMock::RequestHandlers::BalanceTransactions
29
+ include StripeMock::RequestHandlers::Charges
30
+ include StripeMock::RequestHandlers::Cards
31
+ include StripeMock::RequestHandlers::Sources
32
+ include StripeMock::RequestHandlers::Subscriptions # must be before Customers
33
+ include StripeMock::RequestHandlers::SubscriptionItems
34
+ include StripeMock::RequestHandlers::Customers
35
+ include StripeMock::RequestHandlers::Coupons
36
+ include StripeMock::RequestHandlers::Disputes
37
+ include StripeMock::RequestHandlers::Events
38
+ include StripeMock::RequestHandlers::Invoices
39
+ include StripeMock::RequestHandlers::InvoiceItems
40
+ include StripeMock::RequestHandlers::Orders
41
+ include StripeMock::RequestHandlers::Plans
42
+ include StripeMock::RequestHandlers::Products
43
+ include StripeMock::RequestHandlers::Refunds
44
+ include StripeMock::RequestHandlers::Recipients
45
+ include StripeMock::RequestHandlers::Transfers
46
+ include StripeMock::RequestHandlers::Tokens
47
+ include StripeMock::RequestHandlers::CountrySpec
48
+ include StripeMock::RequestHandlers::Payouts
49
+ include StripeMock::RequestHandlers::EphemeralKey
50
+ include StripeMock::RequestHandlers::TaxRates
51
+
52
+ attr_reader :accounts, :balance, :balance_transactions, :bank_tokens, :charges, :coupons, :customers,
53
+ :disputes, :events, :invoices, :invoice_items, :orders, :payment_intents, :payment_methods,
54
+ :plans, :recipients, :refunds, :transfers, :payouts, :subscriptions, :country_spec,
55
+ :subscriptions_items, :products, :tax_rates
56
+
57
+ attr_accessor :error_queue, :debug, :conversion_rate, :account_balance
58
+
59
+ def initialize
60
+ @accounts = {}
61
+ @balance = Data.mock_balance
62
+ @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'])
63
+ @bank_tokens = {}
64
+ @card_tokens = {}
65
+ @customers = {}
66
+ @charges = {}
67
+ @payment_intents = {}
68
+ @coupons = {}
69
+ @disputes = Data.mock_disputes(['dp_05RsQX2eZvKYlo2C0FRTGSSA','dp_15RsQX2eZvKYlo2C0ERTYUIA', 'dp_25RsQX2eZvKYlo2C0ZXCVBNM', 'dp_35RsQX2eZvKYlo2C0QAZXSWE', 'dp_45RsQX2eZvKYlo2C0EDCVFRT', 'dp_55RsQX2eZvKYlo2C0OIKLJUY', 'dp_65RsQX2eZvKYlo2C0ASDFGHJ', 'dp_75RsQX2eZvKYlo2C0EDCXSWQ', 'dp_85RsQX2eZvKYlo2C0UJMCDET', 'dp_95RsQX2eZvKYlo2C0EDFRYUI'])
70
+ @events = {}
71
+ @invoices = {}
72
+ @invoice_items = {}
73
+ @orders = {}
74
+ @payment_methods = {}
75
+ @plans = {}
76
+ @products = {}
77
+ @recipients = {}
78
+ @refunds = {}
79
+ @transfers = {}
80
+ @payouts = {}
81
+ @subscriptions = {}
82
+ @subscriptions_items = {}
83
+ @country_spec = {}
84
+ @tax_rates = {}
85
+
86
+ @debug = false
87
+ @error_queue = ErrorQueue.new
88
+ @id_counter = 0
89
+ @balance_transaction_counter = 0
90
+ @dispute_counter = 0
91
+ @conversion_rate = 1.0
92
+ @account_balance = 10000
93
+
94
+ # This is basically a cache for ParamValidators
95
+ @base_strategy = TestStrategies::Base.new
96
+ end
97
+
98
+ def mock_request(method, url, api_key: nil, api_base: nil, params: {}, headers: {})
99
+ return {} if method == :xtest
100
+
101
+ api_key ||= (Stripe.api_key || DUMMY_API_KEY)
102
+
103
+ # Ensure params hash has symbols as keys
104
+ params = Stripe::Util.symbolize_names(params)
105
+
106
+ method_url = "#{method} #{url}"
107
+
108
+ if handler = Instance.handler_for_method_url(method_url)
109
+ if @debug == true
110
+ puts "- - - - " * 8
111
+ puts "[StripeMock req]::#{handler[:name]} #{method} #{url}"
112
+ puts " #{params}"
113
+ end
114
+
115
+ if mock_error = @error_queue.error_for_handler_name(handler[:name])
116
+ @error_queue.dequeue
117
+ raise mock_error
118
+ else
119
+ res = self.send(handler[:name], handler[:route], method_url, params, headers)
120
+ puts " [res] #{res}" if @debug == true
121
+ [to_faraday_hash(res), api_key]
122
+ end
123
+ else
124
+ puts "[StripeMock] Warning : Unrecognized endpoint + method : [#{method} #{url}]"
125
+ puts "[StripeMock] params: #{params}" unless params.empty?
126
+ [{}, api_key]
127
+ end
128
+ end
129
+
130
+ def generate_webhook_event(event_data)
131
+ event_data[:id] ||= new_id 'evt'
132
+ @events[ event_data[:id] ] = symbolize_names(event_data)
133
+ end
134
+
135
+ def upsert_stripe_object(object, attributes)
136
+ # Most Stripe entities can be created via the API. However, some entities are created when other Stripe entities are
137
+ # created - such as when BalanceTransactions are created when Charges are created. This method provides the ability
138
+ # to create these internal entities.
139
+ # It also provides the ability to modify existing Stripe entities.
140
+ id = attributes[:id]
141
+ if id.nil? || id == ""
142
+ # Insert new Stripe object
143
+ case object
144
+ when :balance_transaction
145
+ id = new_balance_transaction('txn', attributes)
146
+ when :dispute
147
+ id = new_dispute('dp', attributes)
148
+ else
149
+ raise UnsupportedRequestError.new "Unsupported stripe object `#{object}`"
150
+ end
151
+ else
152
+ # Update existing Stripe object
153
+ case object
154
+ when :balance_transaction
155
+ btxn = assert_existence :balance_transaction, id, @balance_transactions[id]
156
+ btxn.merge!(attributes)
157
+ when :dispute
158
+ dispute = assert_existence :dispute, id, @disputes[id]
159
+ dispute.merge!(attributes)
160
+ else
161
+ raise UnsupportedRequestError.new "Unsupported stripe object `#{object}`"
162
+ end
163
+ end
164
+ id
165
+ end
166
+
167
+ private
168
+
169
+ def assert_existence(type, id, obj, message=nil)
170
+ if obj.nil?
171
+ msg = message || "No such #{type}: #{id}"
172
+ raise Stripe::InvalidRequestError.new(msg, type.to_s, http_status: 404)
173
+ end
174
+ obj
175
+ end
176
+
177
+ def new_id(prefix)
178
+ # Stripe ids must be strings
179
+ "#{StripeMock.global_id_prefix}#{prefix}_#{@id_counter += 1}"
180
+ end
181
+
182
+ def new_balance_transaction(prefix, params = {})
183
+ # balance transaction ids must be strings
184
+ id = "#{StripeMock.global_id_prefix}#{prefix}_#{@balance_transaction_counter += 1}"
185
+ amount = params[:amount]
186
+ unless amount.nil?
187
+ # Fee calculation
188
+ calculate_fees(params) unless params[:fee]
189
+ params[:net] = amount - params[:fee]
190
+ params[:amount] = amount * @conversion_rate
191
+ end
192
+ @balance_transactions[id] = Data.mock_balance_transaction(params.merge(id: id))
193
+ id
194
+ end
195
+
196
+ def new_dispute(prefix, params = {})
197
+ id = "#{StripeMock.global_id_prefix}#{prefix}_#{@dispute_counter += 1}"
198
+ @disputes[id] = Data.mock_dispute(params.merge(id: id))
199
+ id
200
+ end
201
+
202
+ def symbolize_names(hash)
203
+ Stripe::Util.symbolize_names(hash)
204
+ end
205
+
206
+ def to_faraday_hash(hash)
207
+ response = Struct.new(:data)
208
+ response.new(hash)
209
+ end
210
+
211
+ def calculate_fees(params)
212
+ application_fee = params[:application_fee] || 0
213
+ params[:fee] = processing_fee(params[:amount]) + application_fee
214
+ params[:fee_details] = [
215
+ {
216
+ amount: processing_fee(params[:amount]),
217
+ application: nil,
218
+ currency: params[:currency] || StripeMock.default_currency,
219
+ description: "Stripe processing fees",
220
+ type: "stripe_fee"
221
+ }
222
+ ]
223
+ if application_fee
224
+ params[:fee_details] << {
225
+ amount: application_fee,
226
+ currency: params[:currency] || StripeMock.default_currency,
227
+ description: "Application fee",
228
+ type: "application_fee"
229
+ }
230
+ end
231
+ end
232
+
233
+ def processing_fee(amount)
234
+ (30 + (amount.abs * 0.029).ceil) * (amount > 0 ? 1 : -1)
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,86 @@
1
+ module StripeMock
2
+ module RequestHandlers
3
+ module Accounts
4
+ VALID_START_YEAR = 2009
5
+
6
+ def Accounts.included(klass)
7
+ klass.add_handler 'post /v1/accounts', :new_account
8
+ klass.add_handler 'get /v1/account', :get_account
9
+ klass.add_handler 'get /v1/accounts/(.*)', :get_account
10
+ klass.add_handler 'post /v1/accounts/(.*)', :update_account
11
+ klass.add_handler 'get /v1/accounts', :list_accounts
12
+ klass.add_handler 'post /oauth/deauthorize',:deauthorize
13
+ end
14
+
15
+ def new_account(route, method_url, params, headers)
16
+ params[:id] ||= new_id('acct')
17
+ route =~ method_url
18
+ accounts[params[:id]] ||= Data.mock_account(params)
19
+ end
20
+
21
+ def get_account(route, method_url, params, headers)
22
+ route =~ method_url
23
+ init_account
24
+ id = $1 || accounts.keys[0]
25
+ assert_existence :account, id, accounts[id]
26
+ end
27
+
28
+ def update_account(route, method_url, params, headers)
29
+ route =~ method_url
30
+ account = assert_existence :account, $1, accounts[$1]
31
+ account.merge!(params)
32
+ if blank_value?(params[:tos_acceptance], :date)
33
+ raise Stripe::InvalidRequestError.new("Invalid integer: ", "tos_acceptance[date]", http_status: 400)
34
+ elsif params[:tos_acceptance] && params[:tos_acceptance][:date]
35
+ validate_acceptance_date(params[:tos_acceptance][:date])
36
+ end
37
+ account
38
+ end
39
+
40
+ def list_accounts(route, method_url, params, headers)
41
+ init_account
42
+ Data.mock_list_object(accounts.values, params)
43
+ end
44
+
45
+ def deauthorize(route, method_url, params, headers)
46
+ init_account
47
+ route =~ method_url
48
+ Stripe::StripeObject.construct_from(:stripe_user_id => params[:stripe_user_id])
49
+ end
50
+
51
+ private
52
+
53
+ def init_account
54
+ if accounts == {}
55
+ acc = Data.mock_account
56
+ accounts[acc[:id]] = acc
57
+ end
58
+ end
59
+
60
+ # Checks if setting a blank value
61
+ #
62
+ # returns true if the key is included in the hash
63
+ # and its value is empty or nil
64
+ def blank_value?(hash, key)
65
+ if hash.key?(key)
66
+ value = hash[key]
67
+ return true if value.nil? || "" == value
68
+ end
69
+ false
70
+ end
71
+
72
+ def validate_acceptance_date(unix_date)
73
+ unix_now = Time.now.strftime("%s").to_i
74
+ formatted_date = Time.at(unix_date)
75
+
76
+ return if formatted_date.year >= VALID_START_YEAR && unix_now >= unix_date
77
+
78
+ raise Stripe::InvalidRequestError.new(
79
+ "ToS acceptance date is not valid. Dates are expected to be integers, measured in seconds, not in the future, and after 2009",
80
+ "tos_acceptance[date]",
81
+ http_status: 400
82
+ )
83
+ end
84
+ end
85
+ end
86
+ end