vbarbarosh
vbarbarosh

Reputation: 3702

Using Stripe Upcoming Invoice to preview changes in subscription

I want to use Stripe Upcoming Invoices to display how much a user will be billed when he makes changes to his subscriptions. But it seems that I miss something...

Why do I get 29 instead of 0?

dump($plans['basic_monthly']->price);
29.0
dump($plans['premium_monthly']->price);
49.0
$stripe_customer = step1_create_customer();
$stripe_subscription = step2_create_subscription($stripe_customer, $plans['basic_monthly']->stripe_price_id);

dump([
    'reason' => 'Nohting was changed (price_id and quantity are the same), so 0 is expected. Why 29 is here?',
    'expected' => 0,
    'actual' => upcoming($stripe_subscription, $plans['basic_monthly']->stripe_price_id)->amount_due/100,
]);
array:3 [▼
    "reason" => "Nohting was changed (price_id and quantity are the same), so 0 is expected. Why 29 is here?"
    "expected" => 0
    "actual" => 29
]
dump([
    'reason' => 'Transition to more expensive plan was made. 49 - 29 = 20 is expected',
    'expected' => 20,
    'actual' => upcoming($stripe_subscription, $plans['premium_monthly']->stripe_price_id)->amount_due/100,
]);
array:3 [▼
    "reason" => "Transition to more expensive plan was made. 49 - 29 = 20 is expected"
    "expected" => 20
    "actual" => 20
]
function step1_create_customer()
{
    $stripe = new \Stripe\StripeClient(env('STRIPE_SECRET_KEY'));

    $test_clock = $stripe->testHelpers->testClocks->create([
        'frozen_time' => time(),
        'name' => sprintf('Testing Upcoming Invoices'),
    ]);

    $stripe_customer = $stripe->customers->create([
        'test_clock' => $test_clock->id,
        'payment_method' => 'pm_card_visa',
        'invoice_settings' => ['default_payment_method' => 'pm_card_visa'],
        'metadata' => [
            'testing_upcoming_invoices' => 1,
        ],
        'expand' => [
            'test_clock',
            'invoice_settings.default_payment_method',
        ],
    ]);

    return $stripe_customer;
}

function step2_create_subscription($stripe_customer, $stripe_price_id)
{
    $stripe = new \Stripe\StripeClient(env('STRIPE_SECRET_KEY'));

    $stripe_subscription = $stripe->subscriptions->create([
        'customer' => $stripe_customer->id,
        'items' => [
            [
                'price' => $stripe_price_id,
                'quantity' => 1,
            ],
        ],
        'metadata' => [
            'testing_upcoming_invoices' => 1,
        ],
    ]);

    return $stripe_subscription;
}

function upcoming($stripe_subscription, $stripe_price_id)
{
    $stripe = new \Stripe\StripeClient(env('STRIPE_SECRET_KEY'));

    $stripe_invoice = $stripe->invoices->upcoming([
        'subscription' => $stripe_subscription->id,
        'subscription_items' => [
            [
                'id' => $stripe_subscription->items->data[0]->id,
                'price' => $stripe_price_id,
                'quantity' => 1,
            ],
        ],
        'subscription_cancel_at_period_end' => false,
        'subscription_proration_behavior' => 'always_invoice',
        //'subscription_proration_date' => $now,
    ]);

    return $stripe_invoice;
}

Upvotes: 0

Views: 1784

Answers (1)

koopajah
koopajah

Reputation: 25582

What your code is doing here is upgrading a Subscription from Price A ($29/month) to Price B ($49/month) immediately after creation. You're also passing subscription_proration_behavior: 'always_invoice'.

When you upgrade or downgrade a subscription, Stripe calculates the proration for you automatically. This is something Stripe documents in details here and here.

In a nutshell, since you move from $29/month to $49/month immediately after creation, what happens is that Stripe calculates that:

  • You owe your customer credit for the time they paid on $29/month that they won't use. Since it's immediately after creation, you owe them $29.
  • The customer owes you for the remaining time for the new Price. Since it's the start of the month they owe you the full price of $49.

In a default integration, the proration is created as 2 separate InvoiceItems that are pending until the next cycle. In your case you pass proration_behavior: 'always_invoice' so an Invoice is created immediately with only those 2 line items. -$29 + $49 = $20 which is where the amount comes from.

Upvotes: 1

Related Questions