Skip to content

Commit 9c07aa1

Browse files
s2t2alexmamonchik
authored andcommitted
Support for latest API version
1 parent cfc8846 commit 9c07aa1

29 files changed

+901
-537
lines changed

.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ stripe-mock-server.pid
55
Gemfile.lock
66
stripe-mock-server.log
77
.idea
8-
.ruby-version
8+
.ruby-version

.travis.yml

+4-5
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ group: deprecated-2017Q2
33
sudo: required
44
language: ruby
55
rvm:
6-
- 2.0.0
7-
- 2.1.10
8-
- 2.2.7
9-
- 2.3.4
6+
- 2.4.6
7+
- 2.5.5
8+
- 2.6.3
109
before_install:
1110
- rvm 2.1.10 do gem install mime-types -v 2.6.2
1211
- gem install bundler -v '< 2'
@@ -17,7 +16,7 @@ script: "bundle exec rspec && bundle exec rspec -t live"
1716

1817
env:
1918
global:
20-
- IS_TRAVIS=true STRIPE_TEST_SECRET_KEY_A=sk_test_Ut2MSlZANdT3iDALdGhyLymy STRIPE_TEST_SECRET_KEY_B=sk_test_JXtzss9tHOG1ofIyEZgoUP4Q STRIPE_TEST_SECRET_KEY_C=sk_test_ZR5nVz9p3ivsqVa7mYB0sFep STRIPE_TEST_SECRET_KEY_D=sk_test_ZR5nVz9p3ivsqVa7mYB0sFep
19+
- IS_TRAVIS=true STRIPE_TEST_SECRET_KEY_A=sk_test_BsztzqQjzd7lqkgo1LjEG5DF00KzH7tWKF STRIPE_TEST_SECRET_KEY_B=sk_test_rKCEu0x8jzg6cKPqoey8kUPQ00usQO3KYE STRIPE_TEST_SECRET_KEY_C=sk_test_qeaB7R6Ywp8sC9pzd1ZIABH700YLC7nhmZ
2120

2221
notifications:
2322
webhooks:

lib/stripe_mock/api/webhooks.rb

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ def self.event_list
7575
'plan.created',
7676
'plan.updated',
7777
'plan.deleted',
78+
'product.created',
79+
'product.updated',
80+
'product.deleted',
7881
'coupon.created',
7982
'coupon.deleted',
8083
'transfer.created',

lib/stripe_mock/data.rb

+29-11
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,7 @@ def self.mock_invoice(lines, params={})
358358
created: 1349738950,
359359
period_end: 1349738950,
360360
period_start: 1349738950,
361+
due_date: nil,
361362
lines: {
362363
object: "list",
363364
total_count: lines.count,
@@ -385,7 +386,7 @@ def self.mock_invoice(lines, params={})
385386
amount_paid: 0,
386387
currency: currency,
387388
starting_balance: 0,
388-
ending_balance: nil,
389+
ending_balance: 0,
389390
next_payment_attempt: 1349825350,
390391
charge: nil,
391392
discount: nil,
@@ -399,6 +400,7 @@ def self.mock_invoice(lines, params={})
399400
end
400401
due = invoice[:total] + invoice[:starting_balance]
401402
invoice[:amount_due] = due < 0 ? 0 : due
403+
invoice[:ending_balance] = invoice[:starting_balance] + invoice[:total] if invoice[:amount_due] == 0
402404
invoice
403405
end
404406

@@ -521,33 +523,49 @@ def self.mock_order_item(params={})
521523
def self.mock_plan(params={})
522524
currency = params[:currency] || StripeMock.default_currency
523525
{
524-
id: "2",
526+
id: "mock_plan_123",
525527
object: "plan",
528+
active: true,
529+
aggregate_usage: nil,
526530
amount: 2300,
531+
billing_scheme: "per_unit",
527532
created: 1466698898,
528533
currency: currency,
529534
interval: "month",
530535
interval_count: 1,
531536
livemode: false,
532537
metadata: {},
533-
name: "The Basic Plan",
534-
statement_descriptor: nil,
535-
trial_period_days: nil
538+
nickname: "My Mock Plan",
539+
product: "mock_prod_NONEXIST", # override this with your own existing product id
540+
tiers: nil,
541+
tiers_mode: nil,
542+
transform_usage: nil,
543+
trial_period_days: nil,
544+
usage_type: "licensed"
536545
}.merge(params)
537546
end
538547

539-
def self.mock_product(params = {})
548+
def self.mock_product(params={})
540549
{
541-
id: "default_test_prod",
550+
id: "mock_prod_abc123",
542551
object: "product",
543552
active: true,
544-
created: 1556896214,
553+
attributes:[],
554+
caption: nil,
555+
created: 1466698000,
556+
deactivate_on: [],
557+
description: nil,
558+
images: [],
545559
livemode: false,
546560
metadata: {},
547-
name: "Default Test Product",
548-
statement_descriptor: "PRODUCT",
561+
name: "The Mock Product",
562+
package_dimensions: nil,
563+
shippable: nil,
564+
statement_descriptor: nil,
549565
type: "service",
550-
updated: 1556918200,
566+
unit_label: "my_unit",
567+
updated: 1537939442,
568+
url: nil
551569
}.merge(params)
552570
end
553571

lib/stripe_mock/request_handlers/helpers/token_helpers.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ def get_card_by_token(token)
3636

3737
def get_card_or_bank_by_token(token)
3838
token_id = token['id'] || token
39-
@card_tokens[token_id] || @bank_tokens[token_id] || raise(Stripe::InvalidRequestError.new("Invalid token id: #{token_id}", 'tok', http_status: 404))
39+
@card_tokens[token_id] || @bank_tokens[token_id] || raise(Stripe::InvalidRequestError.new("Invalid token id: #{token_id}", 'tok', http_status: 404))
4040
end
4141

4242
end

lib/stripe_mock/request_handlers/invoices.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,12 @@ def upcoming_invoice(route, method_url, params, headers)
9999
invoice_lines = []
100100

101101
if prorating
102-
unused_amount = subscription[:plan][:amount] * subscription[:quantity] * (subscription[:current_period_end] - subscription_proration_date.to_i) / (subscription[:current_period_end] - subscription[:current_period_start])
102+
unused_amount = (
103+
subscription[:plan][:amount].to_f *
104+
subscription[:quantity] *
105+
(subscription[:current_period_end] - subscription_proration_date.to_i) / (subscription[:current_period_end] - subscription[:current_period_start])
106+
).ceil
107+
103108
invoice_lines << Data.mock_line_item(
104109
id: new_id('ii'),
105110
amount: -unused_amount,

lib/stripe_mock/request_handlers/products.rb

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ def self.included(base)
1111

1212
def create_product(_route, _method_url, params, _headers)
1313
params[:id] ||= new_id('prod')
14+
validate_create_product_params(params)
1415
products[params[:id]] = Data.mock_product(params)
1516
end
1617

lib/stripe_mock/request_handlers/subscriptions.rb

+16-4
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ def create_subscription(route, method_url, params, headers)
102102
customer[:default_source] = new_card[:id]
103103
end
104104

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)
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 enable_incomplete_payments cancel_at_period_end)
106106
unknown_params = params.keys - allowed_params.map(&:to_sym)
107107
if unknown_params.length > 0
108108
raise Stripe::InvalidRequestError.new("Received unknown parameter: #{unknown_params.join}", unknown_params.first.to_s, http_status: 400)
@@ -133,6 +133,11 @@ def create_subscription(route, method_url, params, headers)
133133
end
134134
end
135135

136+
if params[:cancel_at_period_end]
137+
subscription[:cancel_at_period_end] = true
138+
subscription[:canceled_at] = Time.now.utc.to_i
139+
end
140+
136141
subscriptions[subscription[:id]] = subscription
137142
add_subscription_to_customer(customer, subscription)
138143

@@ -191,17 +196,24 @@ def update_subscription(route, method_url, params, headers)
191196
raise Stripe::InvalidRequestError.new("No such coupon: #{coupon_id}", 'coupon', http_status: 400)
192197
end
193198
end
194-
verify_card_present(customer, subscription_plans.first, subscription)
195199

196-
if subscription[:cancel_at_period_end]
200+
if params[:cancel_at_period_end]
201+
subscription[:cancel_at_period_end] = true
202+
subscription[:canceled_at] = Time.now.utc.to_i
203+
elsif params.has_key?(:cancel_at_period_end)
197204
subscription[:cancel_at_period_end] = false
198205
subscription[:canceled_at] = nil
199206
end
200207

201208
params[:current_period_start] = subscription[:current_period_start]
202209
params[:trial_end] = params[:trial_end] || subscription[:trial_end]
210+
211+
plan_amount_was = subscription.dig(:plan, :amount)
212+
203213
subscription = resolve_subscription_changes(subscription, subscription_plans, customer, params)
204214

215+
verify_card_present(customer, subscription_plans.first, subscription, params) if plan_amount_was == 0 && subscription.dig(:plan, :amount) && subscription.dig(:plan, :amount) > 0
216+
205217
# delete the old subscription, replace with the new subscription
206218
customer[:subscriptions][:data].reject! { |sub| sub[:id] == subscription[:id] }
207219
customer[:subscriptions][:data] << subscription
@@ -281,7 +293,7 @@ def verify_card_present(customer, plan, subscription, params={})
281293

282294
return if params[:billing] == 'send_invoice'
283295

284-
raise Stripe::InvalidRequestError.new('You must supply a valid card xoxo', nil, http_status: 400)
296+
raise Stripe::InvalidRequestError.new('This customer has no attached payment source', nil, http_status: 400)
285297
end
286298

287299
def verify_active_status(subscription)

lib/stripe_mock/request_handlers/validators/param_validators.rb

+97-10
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,28 @@ module StripeMock
22
module RequestHandlers
33
module ParamValidators
44

5-
def validate_create_plan_params(params)
5+
def already_exists_message(obj_class)
6+
"#{obj_class.to_s.split("::").last} already exists."
7+
end
8+
9+
def not_found_message(obj_class, obj_id)
10+
"No such #{obj_class.to_s.split("::").last.downcase}: #{obj_id}"
11+
end
12+
13+
def missing_param_message(attr_name)
14+
"Missing required param: #{attr_name}."
15+
end
16+
17+
def invalid_integer_message(my_val)
18+
"Invalid integer: #{my_val}"
19+
end
20+
21+
#
22+
# ProductValidator
23+
#
24+
25+
26+
def validate_create_product_params(params)
627
params[:id] = params[:id].to_s
728
required_product_fields = @base_strategy.create_plan_params[:product].keys
829

@@ -14,25 +35,91 @@ def validate_create_plan_params(params)
1435
raise Stripe::InvalidRequestError.new(message, name) if params[:product][name].nil?
1536
end
1637

17-
@base_strategy.create_plan_params.keys.each do |name|
38+
@base_strategy.create_product_params.keys.reject{ |k,_| k == :id }.each do |k|
39+
raise Stripe::InvalidRequestError.new(missing_param_message(k), k) if params[k].nil?
40+
end
41+
42+
if !%w[good service].include?(params[:type])
43+
raise Stripe::InvalidRequestError.new("Invalid type: must be one of good or service", :type)
44+
end
45+
46+
if products[ params[:id] ]
47+
raise Stripe::InvalidRequestError.new(already_exists_message(Stripe::Product), :id)
48+
end
49+
end
50+
51+
#
52+
# PlanValidator
53+
#
54+
55+
def missing_plan_amount_message
56+
"Plans require an `amount` parameter to be set."
57+
end
58+
59+
SUPPORTED_PLAN_INTERVALS = ["month", "year", "week", "day"]
60+
61+
def invalid_plan_interval_message
62+
"Invalid interval: must be one of month, year, week, or day"
63+
end
64+
65+
SUPPORTED_CURRENCIES = [
66+
"usd", "aed", "afn", "all", "amd", "ang", "aoa", "ars", "aud", "awg", "azn", "bam", "bbd", "bdt", "bgn",
67+
"bif", "bmd", "bnd", "bob", "brl", "bsd", "bwp", "bzd", "cad", "cdf", "chf", "clp", "cny", "cop", "crc",
68+
"cve", "czk", "djf", "dkk", "dop", "dzd", "egp", "etb", "eur", "fjd", "fkp", "gbp", "gel", "gip", "gmd",
69+
"gnf", "gtq", "gyd", "hkd", "hnl", "hrk", "htg", "huf", "idr", "ils", "inr", "isk", "jmd", "jpy", "kes",
70+
"kgs", "khr", "kmf", "krw", "kyd", "kzt", "lak", "lbp", "lkr", "lrd", "lsl", "mad", "mdl", "mga", "mkd",
71+
"mmk", "mnt", "mop", "mro", "mur", "mvr", "mwk", "mxn", "myr", "mzn", "nad", "ngn", "nio", "nok", "npr",
72+
"nzd", "pab", "pen", "pgk", "php", "pkr", "pln", "pyg", "qar", "ron", "rsd", "rub", "rwf", "sar", "sbd",
73+
"scr", "sek", "sgd", "shp", "sll", "sos", "srd", "std", "szl", "thb", "tjs", "top", "try", "ttd", "twd",
74+
"tzs", "uah", "ugx", "uyu", "uzs", "vnd", "vuv", "wst", "xaf", "xcd", "xof", "xpf", "yer", "zar", "zmw",
75+
"eek", "lvl", "svc", "vef"
76+
]
77+
78+
def invalid_currency_message(my_val)
79+
"Invalid currency: #{my_val.downcase}. Stripe currently supports these currencies: #{SUPPORTED_CURRENCIES.join(", ")}"
80+
end
81+
82+
def validate_create_plan_params(params)
83+
plan_id = params[:id].to_s
84+
product_id = params[:product]
85+
86+
@base_strategy.create_plan_params.keys.each do |attr_name|
1887
message =
19-
if name == :amount
20-
"Plans require an `#{name}` parameter to be set."
21-
elsif name == :product
88+
if attr_name == :amount
89+
"Plans require an `#{attr_name}` parameter to be set."
90+
elsif attr_name == :product
2291
"Missing required param: name."
2392
else
24-
"Missing required param: #{name}."
93+
"Missing required param: #{attr_name}."
2594
end
26-
raise Stripe::InvalidRequestError.new(message, name) if params[name].nil?
95+
raise Stripe::InvalidRequestError.new(message, attr_name) if params[attr_name].nil?
2796
end
2897

29-
if plans[ params[:id] ]
30-
raise Stripe::InvalidRequestError.new("Plan already exists.", :id)
98+
if plans[plan_id]
99+
message = already_exists_message(Stripe::Plan)
100+
raise Stripe::InvalidRequestError.new(message, :id)
101+
end
102+
103+
unless products[product_id]
104+
message = not_found_message(Stripe::Product, product_id)
105+
raise Stripe::InvalidRequestError.new(message, :product)
106+
end
107+
108+
unless SUPPORTED_PLAN_INTERVALS.include?(params[:interval])
109+
message = invalid_plan_interval_message
110+
raise Stripe::InvalidRequestError.new(message, :interval)
111+
end
112+
113+
unless SUPPORTED_CURRENCIES.include?(params[:currency])
114+
message = invalid_currency_message(params[:currency])
115+
raise Stripe::InvalidRequestError.new(message, :currency)
31116
end
32117

33118
unless params[:amount].integer?
34-
raise Stripe::InvalidRequestError.new("Invalid integer: #{params[:amount]}", :amount)
119+
message = invalid_integer_message(params[:amount])
120+
raise Stripe::InvalidRequestError.new(message, :amount)
35121
end
122+
36123
end
37124

38125
def require_param(param_name)

0 commit comments

Comments
 (0)