Cashier-stripe: Swapping Price Plans Sets Quantity to 1

Created on 5 Sep 2020  路  11Comments  路  Source: laravel/cashier-stripe

  • Cashier Version: 12.3.0
  • Laravel Version: 7.22.4
  • PHP Version: 7.4.8

Description:

In the Laravel docs, changing plans notes that:

if a "quantity" exists for the subscription, that quantity will also be maintained.

However, calling swap() or swapAndInvoice() on a subscription with a quantity greater than 1 results in the quantity being set to 1. The Stripe docs do show that the quantity is optional, but I spoke with their support and it is only optional if you want to use the default, which is 1.

This is the POST request body sent to Stripe via Cashier:

{
  "items": {
    "0": {
      "plan": "price_1HLCZtLgaSkaqMsc4Qie4D5x",
    },
    "1": {
      "deleted": "true",
      "id": "si_Hxz9LvF447Vq9s"
    }
  },
  ...
}

It should have items.0.quantity like this:

{
  "items": {
    "0": {
      "plan": "price_1HLCZtLgaSkaqMsc4Qie4D5x",
      "quantity": 55,
    },
    "1": {
      "deleted": "true",
      "id": "si_Hxz9LvF447Vq9s"
    }
  },
  ...
}

It looks like the quantity should be set in the parseSwapPlans() method of Subscription.php. When I include the subscription quantity with the merged return array, then the request to Stripe is correct and the subscription quantity remains the same after the price plan is swapped.

I don't think that is the actual solution though as it would only work when a single subscription item is present (which is my scenario). I believe if you have multiple subscription items, you would need the quantity of the subscription item you are replacing, not the quantity from the subscription itself.

Steps To Reproduce:

  • Create a subscription with a quantity greater than 1.
  • Call swap() or swapAndInvoice() and provide a new plan price ID.
  • The subscription quantity will now be 1.
bug

All 11 comments

I second that, just found out the same bug. Changing the plan/price of a subscriptions resets the quantity to 1.

I'm looking into this atm

continued testing and i'm not sure anymore this is a cashier thing, it may be a stripe thing!

use Stripe\{ Subscription as StripeSubscription};
public function test_change_plan_stripe_direct_no_cashier(){
        $user = $this->init(); // creates user and subscription with quantity 10
        $subscription = Subscription::whereUserId( $user->id )->first();
        $subscriptionItem = SubscriptionItem::whereSubscriptionId(  $subscription->id )->first();

        $planYearly = env('ANOTHER_PLAN);

        $itemsArray = [];
        $itemsArray[] = [
            "id"=>$subscriptionItem->stripe_id,
            "price" => $planYearly
        ];

        $response = StripeSubscription::update($subscription->stripe_id, [ "items" => $itemsArray ]);
        dump($response); // --> $response.quantity = 1 !!

    } 

It's definitely a Cashier thing. We always remove the existing subscription item and create a new one. We need to explicitly pass the quantity when creating a new one for a single plan subscription.

but? my test above goes direct to stripe without cashier ?

You're not passing the quantity in your new items so it'll get a default of 1. The Stripe behavior is correct in your above example.

I've sent in the PR for this here: https://github.com/laravel/cashier-stripe/pull/999

Hi @driesvints when are the update to cashier package published now that the MR has been approved? we would love to have the fix available :-)

Today somewhere. I'm gonna do the releases in a bit.

@driesvints actually there is the same bug on multiplan subscription.

@AnthonyHexium can you please open up a new issue for your specific use case? Add specific steps to reproduce, thanks.

Was this page helpful?
0 / 5 - 0 ratings