Last active
September 6, 2019 00:19
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'test_helper' | |
class StripeTest < ActiveSupport::TestCase | |
test 'should bill customer who wants to upgrade and apply upgrade once invoice is paid' do | |
proration_date = Time.now.to_i | |
customer = Stripe::Customer.retrieve(User.first.stripe_customer_id) | |
subscription = customer.subscriptions.data.first | |
current_period_end_date = subscription.current_period_end | |
# Do this to ensure the user is actually on the cheap plan (Plan.first). | |
# Otherwise, you won't be able to run this test multiple times. | |
Stripe::Subscription.update( | |
subscription.id, | |
cancel_at_period_end: false, | |
prorate: false, | |
items: [ | |
{ | |
id: subscription.items.data[0].id, | |
plan: Plan.first.stripe_plan_id | |
} | |
] | |
) | |
# Making sure they're on the cheap plan. | |
assert_equal Plan.first.stripe_plan_id, Stripe::Customer.retrieve(User.first.stripe_customer_id).subscriptions.data[0].items.data[0].plan.id | |
# To get the proration amount, simulate what happens if this user upgraded now. | |
invoice_items = [{ | |
id: subscription.items.data[0].id, # This returns the subscription item id, which is different from the subscription id. | |
plan: Plan.second.stripe_plan_id | |
}] | |
invoice = Stripe::Invoice.upcoming( | |
customer: customer.id, | |
subscription: subscription.id, | |
subscription_items: invoice_items, | |
subscription_proration_date: proration_date | |
) | |
# invoice.lines.data.count returns 3. | |
# First item is '-100' - i.e. the amount for the days on cheap plan that wasn't used. | |
# Second item is '999' - i.e. the amount that needs to be paid for the remainder of the month for the upgraded plan. | |
# Third item is '1000' - i.e. the normal amount for the next billing cycle. | |
# Get all items with proration date as the start date. | |
# (Excluding the third item, whose start date is the beginning of the next billing cycle.) | |
current_prorations = invoice.lines.data.select { |ii| ii.period.start == proration_date } | |
proration_amount = current_prorations.each.pluck(:amount).inject(:+) | |
# Proration amount should be within this range because the cheap plan is JPY 100, the upgraded plan is JPY 1000. | |
assert_operator proration_amount, :<=, 900 | |
assert_operator proration_amount, :>=, 0 | |
# Create an one-off invoice item, and then an actual invoice. | |
Stripe::InvoiceItem.create( | |
customer: customer.id, | |
amount: proration_amount, | |
currency: 'jpy', | |
description: 'proration cost' | |
) | |
proration_invoice = Stripe::Invoice.create( | |
customer: customer.id, | |
auto_advance: false # If set to 'true', this draft is auto-finalized after ~1 hour. | |
) | |
# Finalization just means the invoice is ready to be paid (not actually paid yet). | |
Stripe::Invoice.finalize_invoice(proration_invoice.id) | |
assert Stripe::Invoice.pay(proration_invoice.id).paid? | |
# If the invoice was paid successfully, upgrade the user with proration disabled. | |
Stripe::Subscription.update( | |
subscription.id, | |
cancel_at_period_end: false, | |
prorate: false, | |
items: [ | |
{ | |
id: subscription.items.data[0].id, | |
plan: Plan.second.stripe_plan_id | |
} | |
] | |
) | |
# Plan.second is the upgraded plan - we're making sure the customer was upgraded. | |
assert_equal Plan.second.stripe_plan_id, Stripe::Customer.retrieve(User.first.stripe_customer_id).subscriptions.data[0].items.data[0].plan.id | |
# Check that the billing cycle hasn't changed. | |
# Note: This doesn't work if the subscription period changed, e.g. if a monthly sub was changed to an annual one. | |
assert_equal current_period_end_date, customer.subscriptions.data.first.current_period_end | |
# Check that the next invoice just charges for the upcoming month (no proration). | |
assert_equal 1000, Stripe::Invoice.upcoming(customer: customer).amount_due | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment