Hudson
Hudson

Reputation: 15

Swapping subscription plan gives error "Call to a member function asStripeCustomer() on null" [Laravel Cashier]

While trying to swap plans on a subscription, Laravel returns this error:

Call to a member function asStripeCustomer() on null

This is the code it references in the stack trace:

$tenant->subscription('main')->swap('plan_xxxxxxxxx');

The only implementation difference between my code and the Laravel docs is I use my own tenant model, rather than the default user model. I made sure to add the Billable model to my tenant model, as well as change user_id to tenant_id in the subscriptions table.

The complete stack trace is as follows:

[2018-12-16 22:21:27] local.ERROR: Call to a member function asStripeCustomer() on null {"exception":"[object] (Symfony\\Component\\Debug\\Exception\\FatalThrowableError(code: 0): Call to a member function asStripeCustomer() on null at /var/www/html/project/vendor/laravel/cashier/src/Subscription.php:407)
[stacktrace]
#0 /var/www/html/project/vendor/laravel/cashier/src/Subscription.php(251): Laravel\\Cashier\\Subscription->asStripeSubscription()
#1 /var/www/html/project/app/Http/Controllers/BillingController.php(103): Laravel\\Cashier\\Subscription->swap('plan_xxxxxxxx...')
#2 [internal function]: App\\Http\\Controllers\\BillingController->UpdatePlan(Object(Illuminate\\Http\\Request))
#3 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Controller.php(54): call_user_func_array(Array, Array)
#4 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/ControllerDispatcher.php(45): Illuminate\\Routing\\Controller->callAction('UpdatePlan', Array)
#5 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Route.php(212): Illuminate\\Routing\\ControllerDispatcher->dispatch(Object(Illuminate\\Routing\\Route), Object(App\\Http\\Controllers\\BillingController), 'UpdatePlan')
#6 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Route.php(169): Illuminate\\Routing\\Route->runController()
#7 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Router.php(679): Illuminate\\Routing\\Route->run()
#8 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(30): Illuminate\\Routing\\Router->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#9 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Middleware/SubstituteBindings.php(41): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#10 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Routing\\Middleware\\SubstituteBindings->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#11 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#12 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php(75): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#13 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Foundation\\Http\\Middleware\\VerifyCsrfToken->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#14 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#15 /var/www/html/project/vendor/laravel/framework/src/Illuminate/View/Middleware/ShareErrorsFromSession.php(49): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#16 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\View\\Middleware\\ShareErrorsFromSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#17 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#18 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Session/Middleware/StartSession.php(63): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#19 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Session\\Middleware\\StartSession->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#20 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#21 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/AddQueuedCookiesToResponse.php(37): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#22 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Cookie\\Middleware\\AddQueuedCookiesToResponse->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#23 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#24 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Cookie/Middleware/EncryptCookies.php(66): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#25 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Cookie\\Middleware\\EncryptCookies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#26 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#27 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(104): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#28 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Router.php(681): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#29 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Router.php(656): Illuminate\\Routing\\Router->runRouteWithinStack(Object(Illuminate\\Routing\\Route), Object(Illuminate\\Http\\Request))
#30 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Router.php(622): Illuminate\\Routing\\Router->runRoute(Object(Illuminate\\Http\\Request), Object(Illuminate\\Routing\\Route))
#31 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Router.php(611): Illuminate\\Routing\\Router->dispatchToRoute(Object(Illuminate\\Http\\Request))
#32 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(176): Illuminate\\Routing\\Router->dispatch(Object(Illuminate\\Http\\Request))
#33 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(30): Illuminate\\Foundation\\Http\\Kernel->Illuminate\\Foundation\\Http\\{closure}(Object(Illuminate\\Http\\Request))
#34 /var/www/html/project/vendor/fideloper/proxy/src/TrustProxies.php(57): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#35 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Fideloper\\Proxy\\TrustProxies->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#36 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#37 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(31): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#38 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#39 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#40 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/TransformsRequest.php(31): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#41 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Foundation\\Http\\Middleware\\TransformsRequest->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#42 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#43 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/ValidatePostSize.php(27): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#44 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Foundation\\Http\\Middleware\\ValidatePostSize->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#45 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#46 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/CheckForMaintenanceMode.php(62): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#47 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(151): Illuminate\\Foundation\\Http\\Middleware\\CheckForMaintenanceMode->handle(Object(Illuminate\\Http\\Request), Object(Closure))
#48 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Routing/Pipeline.php(53): Illuminate\\Pipeline\\Pipeline->Illuminate\\Pipeline\\{closure}(Object(Illuminate\\Http\\Request))
#49 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(104): Illuminate\\Routing\\Pipeline->Illuminate\\Routing\\{closure}(Object(Illuminate\\Http\\Request))
#50 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(151): Illuminate\\Pipeline\\Pipeline->then(Object(Closure))
#51 /var/www/html/project/vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php(116): Illuminate\\Foundation\\Http\\Kernel->sendRequestThroughRouter(Object(Illuminate\\Http\\Request))
#52 /var/www/html/project/public/index.php(55): Illuminate\\Foundation\\Http\\Kernel->handle(Object(Illuminate\\Http\\Request))
#53 {main}

Any help would be welcome. Thanks.

Edit

As requested, here is the relevant methods from Laravel Cashier.

public function swap($plan)
{
    $subscription = $this->asStripeSubscription();

    $subscription->plan = $plan;

    $subscription->prorate = $this->prorate;

    $subscription->cancel_at_period_end = false;

    if (! is_null($this->billingCycleAnchor)) {
        $subscription->billing_cycle_anchor = $this->billingCycleAnchor;
    }

    // If no specific trial end date has been set, the default behavior should be
    // to maintain the current trial state, whether that is "active" or to run
    // the swap out with the exact number of days left on this current plan.
    if ($this->onTrial()) {
        $subscription->trial_end = $this->trial_ends_at->getTimestamp();
    } else {
        $subscription->trial_end = 'now';
    }

    // Again, if no explicit quantity was set, the default behaviors should be to
    // maintain the current quantity onto the new plan. This is a sensible one
    // that should be the expected behavior for most developers with Stripe.
    if ($this->quantity) {
        $subscription->quantity = $this->quantity;
    }

    $subscription->save();

    $this->user->invoice();

    $this->fill([
        'stripe_plan' => $plan,
        'ends_at' => null,
    ])->save();

    return $this;
}

public function asStripeSubscription()
{                         
    $subscriptions = $this->user->asStripeCustomer()->subscriptions;

    if (! $subscriptions) {
        throw new LogicException('The Stripe customer does not have any subscriptions.');
    }

    return $subscriptions->retrieve($this->stripe_id);
}

Edit 2

It looks like the user attribute is returning null in the asStripeSubscription function.

Upvotes: 0

Views: 1211

Answers (2)

OlaJ
OlaJ

Reputation: 698

This solution worked for me: - modify Sunscription.php line 391 from this;

$this->fill([

'stripe_plan' => $plan,

'ends_at' => null,

])->save();

To this:

$this->fill([

'name' => $plan,

'stripe_plan' => $plan,

'ends_at' => null,

])->save();

and that should update your plans accordingly.

Upvotes: 0

patricus
patricus

Reputation: 62228

From the code you posted, $this->user is returning null. You mentioned you changed the default user to tenant, including the database field. These changes alone would cause the default user relationship on the Subscription model to not work anymore.

A quick look at the code shows that you also need to either set the services.stripe.model configuration value to your Tenant model, or set the STRIPE_MODEL environment variable in your .env to your Tenant model.

Upvotes: 2

Related Questions