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.
swap() or swapAndInvoice() and provide a new plan price ID.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.