From c7c6125cfb5607d7b4425deda812744e83006271 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Sun, 23 Apr 2023 18:21:57 +0200 Subject: [PATCH 1/6] Refactor Checkouts to API calls --- README.md | 3 +- config/lemon-squeezy.php | 19 ++++- resources/views/components/button.blade.php | 4 +- src/Checkout.php | 78 ++++++++++++++------- src/Concerns/ManagesCheckouts.php | 3 +- src/Concerns/ManagesCustomer.php | 8 --- tests/Feature/BillableTest.php | 22 ++++-- tests/Feature/CheckoutButtonTest.php | 48 +++---------- tests/Feature/CheckoutTest.php | 60 ++++++++++++---- 9 files changed, 147 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index a4dee85..909911f 100644 --- a/README.md +++ b/README.md @@ -191,7 +191,6 @@ You can easily prefill user data for checkouts by overwriting the following meth public function lemonSqueezyName(): ?string; // name public function lemonSqueezyEmail(): ?string; // email public function lemonSqueezyCountry(): ?string; // country -public function lemonSqueezyState(): ?string; // state public function lemonSqueezyZip(): ?string; // zip public function lemonSqueezyTaxNumber(): ?string; // tax_number ``` @@ -208,7 +207,7 @@ Route::get('/buy', function (Request $request) { $request->user()->checkout('your-product-uuid') ->withName('John Doe') ->withEmail('john@example.com') - ->withBillingAddress('US', 'NY', '10038') + ->withBillingAddress('US', '10038') ->withTaxNumber('123456679') ->withDiscountCode('PROMO') ); diff --git a/config/lemon-squeezy.php b/config/lemon-squeezy.php index fa96ecb..5d60a81 100644 --- a/config/lemon-squeezy.php +++ b/config/lemon-squeezy.php @@ -46,14 +46,27 @@ | Lemon Squeezy Store |-------------------------------------------------------------------------- | - | This is the URL to your Lemon Squeezy store. You can find your store - | URL in the Lemon Squeezy dashboard. The entered value should be the - | subdomain of your store URL right before the .lemonsqueezy.com part. + | This is the ID of your Lemon Squeezy store. You can find your store + | ID in the Lemon Squeezy dashboard. The entered value should be the + | part after the # sign. | */ 'store' => env('LEMON_SQUEEZY_STORE'), + /* + |-------------------------------------------------------------------------- + | Default Redirect URL + |-------------------------------------------------------------------------- + | + | This is the default redirect URL that will be used when a customer + | is redirected back to your application after completing a purchase + | from a checkout session in your Lemon Squeezy store. + | + */ + + 'redirect_url' => env('LEMON_SQUEEZY_REDIRECT_URL'), + /* |-------------------------------------------------------------------------- | Lemon Squeezy Products diff --git a/resources/views/components/button.blade.php b/resources/views/components/button.blade.php index 9921bff..8edd625 100644 --- a/resources/views/components/button.blade.php +++ b/resources/views/components/button.blade.php @@ -1,9 +1,9 @@ -@props(['href', 'dark' => false]) +@props(['href']) @php($href = $href instanceof LemonSqueezy\Laravel\Checkout ? $href->url() : $href) merge(['class' => 'lemonsqueezy-button']) }} > {{ $slot }} diff --git a/src/Checkout.php b/src/Checkout.php index fa0441a..b416d72 100644 --- a/src/Checkout.php +++ b/src/Checkout.php @@ -15,12 +15,14 @@ class Checkout implements Responsable private bool $desc = true; - private bool $code = true; + private bool $discount = true; - private array $fields = []; + private array $checkoutData = []; private array $custom = []; + private ?string $redirectUrl; + public function __construct(private string $store, private string $variant) { } @@ -51,32 +53,31 @@ public function withoutDescription(): self return $this; } - public function withoutCode(): self + public function withoutDiscountField(): self { - $this->code = false; + $this->discount = false; return $this; } public function withName(string $name): self { - $this->fields['name'] = $name; + $this->checkoutData['name'] = $name; return $this; } public function withEmail(string $email): self { - $this->fields['email'] = $email; + $this->checkoutData['email'] = $email; return $this; } - public function withBillingAddress(string $country, string $state = null, string $zip = null): self + public function withBillingAddress(string $country, string $zip = null): self { - $this->fields['billing_address'] = array_filter([ + $this->checkoutData['billing_address'] = array_filter([ 'country' => $country, - 'state' => $state, 'zip' => $zip, ]); @@ -85,14 +86,14 @@ public function withBillingAddress(string $country, string $state = null, string public function withTaxNumber(string $taxNumber): self { - $this->fields['tax_number'] = $taxNumber; + $this->checkoutData['tax_number'] = $taxNumber; return $this; } public function withDiscountCode(string $discountCode): self { - $this->fields['discount_code'] = $discountCode; + $this->checkoutData['discount_code'] = $discountCode; return $this; } @@ -115,24 +116,51 @@ public function withCustomData(array $custom): self return $this; } - public function url(): string + public function redirectTo(string $url): self { - $params = collect(['logo', 'media', 'desc', 'code']) - ->filter(fn ($toggle) => ! $this->{$toggle}) - ->mapWithKeys(fn ($toggle) => [$toggle => 0]) - ->all(); + $this->redirectUrl = $url; - if ($this->fields) { - $params['checkout'] = array_filter($this->fields); - } - - if ($this->custom) { - $params['checkout']['custom'] = $this->custom; - } + return $this; + } - $params = ! empty($params) ? '?'.http_build_query($params) : ''; + public function url(): string + { + $response = LemonSqueezy::api('POST', 'checkouts', [ + 'data' => [ + 'type' => 'checkouts', + 'attributes' => [ + 'checkout_data' => array_merge( + array_filter($this->checkoutData, fn ($value) => $value !== ''), + ['custom' => $this->custom] + ), + 'checkout_options' => [ + 'logo' => $this->logo, + 'media' => $this->media, + 'desc' => $this->desc, + 'discount' => $this->discount, + ], + 'product_options' => [ + 'redirect_url' => $this->redirectUrl ?? config('lemon-squeezy.redirect_url'), + ], + ], + 'relationships' => [ + 'store' => [ + 'data' => [ + 'type' => 'stores', + 'id' => $this->store, + ], + ], + 'variant' => [ + 'data' => [ + 'type' => 'variants', + 'id' => $this->variant, + ], + ], + ], + ], + ]); - return "https://{$this->store}.lemonsqueezy.com/checkout/buy/{$this->variant}".$params; + return $response['data']['attributes']['url']; } public function redirect(): RedirectResponse diff --git a/src/Concerns/ManagesCheckouts.php b/src/Concerns/ManagesCheckouts.php index c769cfc..63a5bbf 100644 --- a/src/Concerns/ManagesCheckouts.php +++ b/src/Concerns/ManagesCheckouts.php @@ -16,7 +16,7 @@ public function checkout(string $variant, array $options = [], array $custom = [ // we make an API request we'll attach the authentication identifier to this // checkout so we can match it back to a user when handling Lemon Squeezy webhooks. $custom = array_merge($custom, [ - 'billable_id' => $this->getKey(), + 'billable_id' => (string) $this->getKey(), 'billable_type' => $this->getMorphClass(), ]); @@ -25,7 +25,6 @@ public function checkout(string $variant, array $options = [], array $custom = [ ->withEmail($options['email'] ?? (string) $this->lemonSqueezyEmail()) ->withBillingAddress( $options['country'] ?? (string) $this->lemonSqueezyCountry(), - $options['state'] ?? (string) $this->lemonSqueezyState(), $options['zip'] ?? (string) $this->lemonSqueezyZip(), ) ->withTaxNumber($options['tax_number'] ?? (string) $this->lemonSqueezyTaxNumber()) diff --git a/src/Concerns/ManagesCustomer.php b/src/Concerns/ManagesCustomer.php index 4ccb3b1..4fe17bd 100644 --- a/src/Concerns/ManagesCustomer.php +++ b/src/Concerns/ManagesCustomer.php @@ -49,14 +49,6 @@ public function lemonSqueezyCountry(): ?string return $this->country ?? null; // 'US' } - /** - * Get the billable model's state to associate with Lemon Squeezy. - */ - public function lemonSqueezyState(): ?string - { - return $this->state ?? null; // 'NY' - } - /** * Get the billable model's zip code to associate with Lemon Squeezy. */ diff --git a/tests/Feature/BillableTest.php b/tests/Feature/BillableTest.php index 0a15ac3..2b25625 100644 --- a/tests/Feature/BillableTest.php +++ b/tests/Feature/BillableTest.php @@ -3,26 +3,38 @@ use Tests\Fixtures\User; it('can generate a checkout for a billable', function () { - config()->set('lemon-squeezy.store', 'lemon'); + config()->set('lemon-squeezy.store', 'store_23432'); + + Http::fake([ + 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + ]), + ]); $checkout = (new User)->checkout('variant_123'); expect($checkout->url()) - ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123?checkout%5Bcustom%5D%5Bbillable_id%5D=user_123&checkout%5Bcustom%5D%5Bbillable_type%5D=users'); + ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123'); }); it('can generate a checkout for a billable with custom data', function () { - config()->set('lemon-squeezy.store', 'lemon'); + config()->set('lemon-squeezy.store', 'store_23432'); + + Http::fake([ + 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + ]), + ]); $checkout = (new User)->checkout('variant_123') ->withCustomData(['batch_id' => '789']); expect($checkout->url()) - ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123?checkout%5Bcustom%5D%5Bbillable_id%5D=user_123&checkout%5Bcustom%5D%5Bbillable_type%5D=users&checkout%5Bcustom%5D%5Bbatch_id%5D=789'); + ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123'); }); it('cannnot overwrite the customer id and type or subscription id for a billable', function () { - config()->set('lemon-squeezy.store', 'lemon'); + config()->set('lemon-squeezy.store', 'store_23432'); $this->expectExceptionMessage( 'You cannot use "billable_id", "billable_type" or "subscription_type" as custom data keys because these are reserved keywords.' diff --git a/tests/Feature/CheckoutButtonTest.php b/tests/Feature/CheckoutButtonTest.php index 80895f2..7792f29 100644 --- a/tests/Feature/CheckoutButtonTest.php +++ b/tests/Feature/CheckoutButtonTest.php @@ -13,43 +13,7 @@ $expect = <<<'HTML' - Buy Now - - HTML; - - $view->assertSee($expect, false); -}); - -it('can render an overlay with a dark background', function () { - $view = $this->blade( - 'Buy Now', - ['href' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123'] - ); - - $expect = <<<'HTML' - - Buy Now - - HTML; - - $view->assertSee($expect, false); -}); - -it('can render a button with disabled toggles', function () { - $view = $this->blade( - 'Buy Now', - ['href' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123?logo=0&media=0'] - ); - - $expect = <<<'HTML' - Buy Now @@ -60,14 +24,20 @@ class="lemonsqueezy-button" }); it('can render a checkout instance', function () { + Http::fake([ + 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + ]), + ]); + $view = $this->blade( 'Buy Now', - ['checkout' => Checkout::make('lemon', 'variant_123')->withoutLogo()] + ['checkout' => Checkout::make('store_24398', 'variant_123')] ); $expect = <<<'HTML' Buy Now diff --git a/tests/Feature/CheckoutTest.php b/tests/Feature/CheckoutTest.php index 4372b7a..2f80f02 100644 --- a/tests/Feature/CheckoutTest.php +++ b/tests/Feature/CheckoutTest.php @@ -4,7 +4,13 @@ use LemonSqueezy\Laravel\Checkout; it('can initiate a new checkout', function () { - $checkout = new Checkout('lemon', 'variant_123'); + $checkout = new Checkout('store_24398', 'variant_123'); + + Http::fake([ + 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + ]), + ]); expect($checkout)->toBeInstanceOf(Checkout::class); expect($checkout->url()) @@ -12,7 +18,13 @@ }); it('can be redirected', function () { - $checkout = new Checkout('lemon', 'variant_123'); + $checkout = new Checkout('store_24398', 'variant_123'); + + Http::fake([ + 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + ]), + ]); expect($checkout->redirect())->toBeInstanceOf(RedirectResponse::class); expect($checkout->redirect()->getTargetUrl()) @@ -20,45 +32,69 @@ }); it('can turn off toggles', function () { - $checkout = Checkout::make('lemon', 'variant_123') + $checkout = Checkout::make('store_24398', 'variant_123') ->withoutLogo() ->withoutMedia() ->withoutDescription() - ->withoutCode(); + ->withoutDiscountField(); + + Http::fake([ + 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + ]), + ]); expect($checkout->url()) - ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123?logo=0&media=0&desc=0&code=0'); + ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123'); }); it('can set prefilled fields with dedicated methods', function () { - $checkout = Checkout::make('lemon', 'variant_123') + $checkout = Checkout::make('store_24398', 'variant_123') ->withName('John Doe') ->withEmail('john@example.com') - ->withBillingAddress('US', 'NY', '10038') + ->withBillingAddress('US', '10038') ->withTaxNumber('GB123456789') ->withDiscountCode('10PERCENTOFF'); + Http::fake([ + 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + ]), + ]); + expect($checkout->url()) - ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123?checkout%5Bname%5D=John+Doe&checkout%5Bemail%5D=john%40example.com&checkout%5Bbilling_address%5D%5Bcountry%5D=US&checkout%5Bbilling_address%5D%5Bstate%5D=NY&checkout%5Bbilling_address%5D%5Bzip%5D=10038&checkout%5Btax_number%5D=GB123456789&checkout%5Bdiscount_code%5D=10PERCENTOFF'); + ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123'); }); it('can include custom data', function () { - $checkout = Checkout::make('lemon', 'variant_123') + $checkout = Checkout::make('store_24398', 'variant_123') ->withCustomData([ 'order_id' => '789', ]); + Http::fake([ + 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + ]), + ]); + expect($checkout->url()) - ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123?checkout%5Bcustom%5D%5Border_id%5D=789'); + ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123'); }); it('can include prefilled fields and custom data', function () { - $checkout = Checkout::make('lemon', 'variant_123') + $checkout = Checkout::make('store_24398', 'variant_123') ->withName('John Doe') ->withCustomData([ 'order_id' => '789', ]); + Http::fake([ + 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + ]), + ]); + expect($checkout->url()) - ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123?checkout%5Bname%5D=John+Doe&checkout%5Bcustom%5D%5Border_id%5D=789'); + ->toBe('https://lemon.lemonsqueezy.com/checkout/buy/variant_123'); }); From 6f5a095acfcfd94a9b88d1d8bf04e5c3f3f80a14 Mon Sep 17 00:00:00 2001 From: driesvints Date: Sun, 23 Apr 2023 16:24:13 +0000 Subject: [PATCH 2/6] Fix code styling --- tests/Feature/BillableTest.php | 4 ++-- tests/Feature/CheckoutButtonTest.php | 2 +- tests/Feature/CheckoutTest.php | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/Feature/BillableTest.php b/tests/Feature/BillableTest.php index 2b25625..52f2a50 100644 --- a/tests/Feature/BillableTest.php +++ b/tests/Feature/BillableTest.php @@ -7,7 +7,7 @@ Http::fake([ 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ - 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']], ]), ]); @@ -22,7 +22,7 @@ Http::fake([ 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ - 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']], ]), ]); diff --git a/tests/Feature/CheckoutButtonTest.php b/tests/Feature/CheckoutButtonTest.php index 7792f29..3ae5040 100644 --- a/tests/Feature/CheckoutButtonTest.php +++ b/tests/Feature/CheckoutButtonTest.php @@ -26,7 +26,7 @@ class="lemonsqueezy-button" it('can render a checkout instance', function () { Http::fake([ 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ - 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']], ]), ]); diff --git a/tests/Feature/CheckoutTest.php b/tests/Feature/CheckoutTest.php index 2f80f02..239a449 100644 --- a/tests/Feature/CheckoutTest.php +++ b/tests/Feature/CheckoutTest.php @@ -8,7 +8,7 @@ Http::fake([ 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ - 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']], ]), ]); @@ -22,7 +22,7 @@ Http::fake([ 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ - 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']], ]), ]); @@ -40,7 +40,7 @@ Http::fake([ 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ - 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']], ]), ]); @@ -58,7 +58,7 @@ Http::fake([ 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ - 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']], ]), ]); @@ -74,7 +74,7 @@ Http::fake([ 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ - 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']], ]), ]); @@ -91,7 +91,7 @@ Http::fake([ 'api.lemonsqueezy.com/v1/checkouts' => Http::response([ - 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']] + 'data' => ['attributes' => ['url' => 'https://lemon.lemonsqueezy.com/checkout/buy/variant_123']], ]), ]); From 172ea4cfa67e7077b6aa052a2da2df90bd4f6662 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Sun, 23 Apr 2023 18:38:59 +0200 Subject: [PATCH 3/6] wip --- README.md | 48 ++++++++++++++++++++-------------------- config/lemon-squeezy.php | 2 +- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 909911f..8408da6 100644 --- a/README.md +++ b/README.md @@ -61,12 +61,12 @@ LEMON_SQUEEZY_API_KEY=your-lemon-squeezy-api-key When you're deploying your app to production, you'll have to create a new key in production mode to work with live data. -### Store URL +### Store Identifier -Your store url will be used when creating checkouts for your products. Go to [your Lemon Squeezy general settings](https://app.lemonsqueezy.com/settings/general) and copy the Store URL subdomain (the part before `.lemonsqueezy.com`) into the env value below: +Your store identifier will be used when creating checkouts for your products. Go to [your Lemon Squeezy general settings](https://app.lemonsqueezy.com/settings/general) and copy the Store ID (the part before `#` sign) into the env value below: ```ini -LEMON_SQUEEZY_STORE=your-lemon-squeezy-subdomain +LEMON_SQUEEZY_STORE=your-lemon-squeezy-store-id ``` ### Billable Model @@ -136,22 +136,19 @@ With this package, you can easily create checkouts for your customers. ### Single Payments -For example, to create a checkout for a single-payment, click the "share" button of the product you want to share, copy its UUID from the share url and create a checkout using the snippet below: +For example, to create a checkout for a single-payment, use a variant ID of a product variant you want to sell and create a checkout using the snippet below: ```php use Illuminate\Http\Request; Route::get('/buy', function (Request $request) { return response()->redirect( - $request->user()->checkout('your-product-uuid') + $request->user()->checkout('variant-id') ); }); ``` -This will automatically redirect your customer to a Lemon Squeezy checkout where the customer can buy your product. - -> **Note** -> Please note that the product UUID is not the same as the variant ID. +This will automatically redirect your customer to a Lemon Squeezy checkout where the customer can buy your product. ### Overlay Widget @@ -161,7 +158,7 @@ Instead of redirecting your customer to a checkout screen, you can also create a use Illuminate\Http\Request; Route::get('/buy', function (Request $request) { - $checkout = $request->user()->checkout('your-product-uuid'); + $checkout = $request->user()->checkout('variant-id'); return view('billing', ['checkout' => $checkout]); }); @@ -175,14 +172,6 @@ Now, create the button using the shipped Laravel Blade component from the packag ``` -When a user clicks this button, it'll trigger the Lemon Squeezy checkout overlay. You can also, optionally request it to be rendered in dark mode: - -```blade - - Buy Product - -``` - ### Prefill User Data You can easily prefill user data for checkouts by overwriting the following methods on your billable model: @@ -204,10 +193,10 @@ use Illuminate\Http\Request; Route::get('/buy', function (Request $request) { return response()->redirect( - $request->user()->checkout('your-product-uuid') + $request->user()->checkout('variant-id') ->withName('John Doe') ->withEmail('john@example.com') - ->withBillingAddress('US', '10038') + ->withBillingAddress('US', '10038') // Country & Zip Code ->withTaxNumber('123456679') ->withDiscountCode('PROMO') ); @@ -216,7 +205,18 @@ Route::get('/buy', function (Request $request) { ### Redirects After Purchase -After a purchase the customer will be redirected to your Lemon Squeezy's store. If you want them to be redirected back to your app, you'll have to configure the url in your settings in your Lemon Squeezy dashboard for each individual product. +To redirect customers back to your app after purchase, you may use the `redirectTo` method: + +```php +$request->user()->checkout('variant-id') + ->redirectTo(url('/')); +``` + +You may also set a default url for this by configuring the `lemon-squeezy.redirect_url` in your config file: + +```php +'redirect_url' => 'https://my-app.com/dashboard', +``` ### Custom Data @@ -227,7 +227,7 @@ use Illuminate\Http\Request; Route::get('/buy', function (Request $request) { return response()->redirect( - $request->user()->checkout('your-product-uuid', custom: ['foo' => 'bar']) + $request->user()->checkout('variant-id', custom: ['foo' => 'bar']) ); }); ``` @@ -256,14 +256,14 @@ This gives you the advantage later on to make use of the `hasProduct` method on ### Creating Subscriptions -Starting subscriptions is easy. For this, we need the UUID from our product. Click the "share" button of the subscription product you want to share, copy its UUID from the share url and initiate a new subscription checkout from your billable model: +Starting subscriptions is easy. For this, we need the variant id from our product. Copy the variant id and initiate a new subscription checkout from your billable model: ```php use Illuminate\Http\Request; Route::get('/buy', function (Request $request) { return response()->redirect( - $request->user()->subscribe('your-product-uuid') + $request->user()->subscribe('variant-id') ); }); ``` diff --git a/config/lemon-squeezy.php b/config/lemon-squeezy.php index 5d60a81..7d2d648 100644 --- a/config/lemon-squeezy.php +++ b/config/lemon-squeezy.php @@ -65,7 +65,7 @@ | */ - 'redirect_url' => env('LEMON_SQUEEZY_REDIRECT_URL'), + 'redirect_url' => null, /* |-------------------------------------------------------------------------- From e23e740e988b2078bf5734d273dc3505281da4d7 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Sun, 23 Apr 2023 18:45:57 +0200 Subject: [PATCH 4/6] wip --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 8408da6..76adcc8 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,9 @@ Route::get('/buy', function (Request $request) { This will automatically redirect your customer to a Lemon Squeezy checkout where the customer can buy your product. +> **Note** +> When creating a checkout for your store, each time you redirect a checkout object or call `url` on the checkout object, an API call to Lemon Squeezy will be made. These calls are expensive and can be time and resource consuming for your app. If you are creating the same session over and over again you may want to cache these urls. + ### Overlay Widget Instead of redirecting your customer to a checkout screen, you can also create a checkout button which will render a checkout overlay on your page. To do this, pass the `$checkout` object to a view: From 328eb760c6296440f71bc435e68ee3dc154ae5ab Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Sun, 23 Apr 2023 18:47:48 +0200 Subject: [PATCH 5/6] wip --- phpunit.xml.dist | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 5ecece2..ec45ca6 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -18,5 +18,7 @@ + + From 3a4b72ec55e4280aae218dbb280ff57b4c001d84 Mon Sep 17 00:00:00 2001 From: Dries Vints Date: Sun, 23 Apr 2023 18:49:46 +0200 Subject: [PATCH 6/6] wip --- tests/Feature/BillableTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Feature/BillableTest.php b/tests/Feature/BillableTest.php index 52f2a50..79e2104 100644 --- a/tests/Feature/BillableTest.php +++ b/tests/Feature/BillableTest.php @@ -48,6 +48,8 @@ }); it('needs a configured store to generate checkouts', function () { + config()->set('lemon-squeezy.store', null); + $this->expectExceptionMessage('The Lemon Squeezy store was not configured.'); (new User)->checkout('variant_123');