Skip to content

Commit 04466f1

Browse files
authored
Support for customer portals (#46)
* Support for customer portals * wip
1 parent b4197d2 commit 04466f1

File tree

4 files changed

+95
-2
lines changed

4 files changed

+95
-2
lines changed

README.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -357,9 +357,25 @@ Attempting to use any of these will result in an exception being thrown.
357357

358358
## Customers
359359

360-
### Updating Customers
360+
### Customer Portal
361361

362-
Right now, it's not possible to update customer objects. Meaning, when they fill out their name, email address, city, region and country initially, there's no possibility of updating it later. To change these fields for a customer in Lemon Squeezy, you'll need to let your customer [contact Lemon Squeezy support](https://www.lemonsqueezy.com/help) so they can do it for you.
362+
Customers may easily manage their personal data like their name, email address, etc by visiting their [customer portal](https://docs.lemonsqueezy.com/guides/developer-guide/customer-portal). Lemon Squeezy for Laravel makes it easy to redirect customers to this by calling `redirectToCustomerPortal` on the billable:
363+
364+
```php
365+
use Illuminate\Http\Request;
366+
367+
Route::get('/customer-portal', function (Request $request) {
368+
return $request->user()->redirectToCustomerPortal();
369+
});
370+
```
371+
372+
In order to call this method your billable already needs to have a subscription or made a purchase through Lemon Squeezy. Also, this method will perform an underlying API call so make sure to place this redirect behind a route which you can link to in your app.
373+
374+
Optionally, you also get the signed customer portal url directly:
375+
376+
```php
377+
$url = $user->customerPortalUrl();
378+
```
363379

364380
## Subscriptions
365381

src/Concerns/ManagesCustomer.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
namespace LemonSqueezy\Laravel\Concerns;
44

55
use Illuminate\Database\Eloquent\Relations\MorphOne;
6+
use Illuminate\Http\RedirectResponse;
67
use LemonSqueezy\Laravel\Customer;
8+
use LemonSqueezy\Laravel\Exceptions\InvalidCustomer;
9+
use LemonSqueezy\Laravel\LemonSqueezy;
710

811
trait ManagesCustomer
912
{
@@ -64,4 +67,44 @@ public function lemonSqueezyTaxNumber(): ?string
6467
{
6568
return $this->tax_number ?? null; // 'GB123456789'
6669
}
70+
71+
/**
72+
* Get the customer portal url for this billable.
73+
*/
74+
public function customerPortalUrl(): string
75+
{
76+
$this->assertCustomerExists();
77+
78+
$response = LemonSqueezy::api('GET', "customers/{$this->lemon_squeezy_id}");
79+
80+
return $response['data']['attributes']['urls']['customer_portal'];
81+
}
82+
83+
/**
84+
* Generate a redirect response to the billable's customer portal.
85+
*/
86+
public function redirectToCustomerPortal(): RedirectResponse
87+
{
88+
return new RedirectResponse($this->customerPortalUrl());
89+
}
90+
91+
/**
92+
* Determine if the billable has a Lemon Squeezy customer ID.
93+
*/
94+
public function hasLemonSqueezyId(): bool
95+
{
96+
return ! is_null($this->lemon_squeezy_id);
97+
}
98+
99+
/**
100+
* Determine if the billable has a Lemon Squeezy customer ID and throw an exception if not.
101+
*
102+
* @throws InvalidCustomer
103+
*/
104+
protected function assertCustomerExists(): void
105+
{
106+
if (! $this->hasLemonSqueezyId()) {
107+
throw InvalidCustomer::notYetCreated($this);
108+
}
109+
}
67110
}

src/Exceptions/InvalidCustomer.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace LemonSqueezy\Laravel\Exceptions;
4+
5+
use Exception;
6+
use Illuminate\Database\Eloquent\Model;
7+
8+
class InvalidCustomer extends Exception
9+
{
10+
public static function notYetCreated(Model $owner): static
11+
{
12+
return new static(class_basename($owner).' is not a Stripe customer yet. See the createAsStripeCustomer method.');
13+
}
14+
}

tests/Feature/BillableTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,23 @@
5454

5555
(new User)->checkout('variant_123');
5656
});
57+
58+
it('can generate a customer portal link for a billable', function () {
59+
config()->set('lemon-squeezy.store', 'store_23432');
60+
61+
Http::fake([
62+
'api.lemonsqueezy.com/v1/customers/1' => Http::response([
63+
'data' => ['attributes' => ['urls' => [
64+
'customer_portal' => 'https://my-store.lemonsqueezy.com/billing?expires=1666869343&signature=xxxxx',
65+
]]],
66+
]),
67+
]);
68+
69+
$user = new User;
70+
$user->lemon_squeezy_id = 1;
71+
72+
$url = $user->customerPortalUrl();
73+
74+
expect($url)
75+
->toBe('https://my-store.lemonsqueezy.com/billing?expires=1666869343&signature=xxxxx');
76+
});

0 commit comments

Comments
 (0)