Skip to content

Commit

Permalink
Fix cart id hanging around in the session when not cleared (#1854)
Browse files Browse the repository at this point in the history
Currently if a cart has a completed order but wasn't cleared from the
session it will seize up and cause problems when users try to interact
with it. This also causes data issues as the cart no longer maps to the
completed order correctly.

---------

Co-authored-by: alecritson <[email protected]>
Co-authored-by: Glenn Jacobs <[email protected]>
  • Loading branch information
3 people committed Jul 8, 2024
1 parent 5a9569d commit fca6cca
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 55 deletions.
10 changes: 8 additions & 2 deletions docs/core/reference/carts.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,17 @@ Configuration for your cart is handled in `lunar/cart.php`

| Field | Description | Default |
|:--------------|:---------------------------------------------------------------------------------------|:-------------|
| `session_key` | What key to use when storing the cart id in the session | `lunar_cart` |
| `auto_create` | If no current basket exists, should we create one in the database? | `false` |
| `auth_policy` | When a user logs in, how should we handle merging of the basket? | `merge` |
| `eager_load` | Which relationships should be eager loaded by default when calculating the cart totals |

There is additional, separate, config specifically for when using the `CartSession` located in `lunar/cart_session.php`.

| Field | Description | Default |
|:---------------------------------|:-------------------------------------------------------------------|:-------------|
| `session_key` | What key to use when storing the cart id in the session | `lunar_cart` |
| `auto_create` | If no current basket exists, should we create one in the database? | `false` |
| `allow_multiple_orders_per_cart` | Whether carts can have multiple orders associated to them. | `false` |

### Getting the cart session instance

You can either use the facade or inject the `CartSession` into your code.
Expand Down
13 changes: 13 additions & 0 deletions docs/core/upgrading.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@ php artisan migrate

Lunar currently provides bug fixes and security updates for only the latest minor release, e.g. `0.8`.

## 1.0.0-alpha.31

### High Impact

Certain parts of `config/cart.php` which are more specific to when you are interacting with carts via the session have been relocated to a new `config/cart_session.php` file.

```php
// Move to config/cart_session.php
'session_key' => 'lunar_cart',
'auto_create' => false,
```

You should also check this file for any new config values you may need to add.

## 1.0.0-alpha.29

Expand Down
23 changes: 0 additions & 23 deletions packages/core/config/cart.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,6 @@
use Lunar\Actions\Carts\GenerateFingerprint;

return [

/*
|--------------------------------------------------------------------------
| Session Key
|--------------------------------------------------------------------------
|
| Specify the session key used when fetching the cart.
|
*/
'session_key' => 'lunar_cart',

/*
|--------------------------------------------------------------------------
| Fingerprint Generator
Expand All @@ -24,18 +13,6 @@
*/
'fingerprint_generator' => GenerateFingerprint::class,

/*
|--------------------------------------------------------------------------
| Auto create a cart when none exists for user.
|--------------------------------------------------------------------------
|
| Determines whether you want to automatically create a cart for a user if
| they do not currently have one in the session. By default this is false
| to minimise the amount of cart lines added to the database.
|
*/
'auto_create' => false,

/*
|--------------------------------------------------------------------------
| Authentication policy
Expand Down
38 changes: 38 additions & 0 deletions packages/core/config/cart_session.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

return [
/*
|--------------------------------------------------------------------------
| Session Key
|--------------------------------------------------------------------------
|
| Specify the session key used when fetching the cart.
|
*/
'session_key' => 'lunar_cart',

/*
|--------------------------------------------------------------------------
| Auto create a cart when none exists for user.
|--------------------------------------------------------------------------
|
| Determines whether you want to automatically create a cart for a user if
| they do not currently have one in the session. By default, this is false
| to minimise the amount of carts added to the database.
|
*/
'auto_create' => false,

/*
|--------------------------------------------------------------------------
| Allow Carts to have multiple orders associated.
|--------------------------------------------------------------------------
|
| Determines whether the same cart instance will be returned if there is already
| a completed order associated to the cart which is retrieved in the session.
| When set to false, if a cart has a completed order, then a new instance
| of a cart will be returned, even if auto_create is set to false
|
*/
'allow_multiple_orders_per_cart' => false,
];
1 change: 1 addition & 0 deletions packages/core/src/LunarServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class LunarServiceProvider extends ServiceProvider
{
protected $configFiles = [
'cart',
'cart_session',
'database',
'media',
'orders',
Expand Down
25 changes: 16 additions & 9 deletions packages/core/src/Managers/CartSessionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@ public function __construct(
//
}

public function allowsMultipleOrdersPerCart(): bool
{
return config('lunar.cart_session.allow_multiple_per_order', false);
}

/**
* {@inheritDoc}
*/
public function current(bool $estimateShipping = false, bool $calculate = true): ?Cart
{
return $this->fetchOrCreate(
config('lunar.cart.auto_create', false),
config('lunar.cart_session.auto_create', false),
estimateShipping: $estimateShipping,
calculate: $calculate,
);
Expand Down Expand Up @@ -135,6 +140,10 @@ private function fetchOrCreate(bool $create = false, bool $estimateShipping = fa
config('lunar.cart.eager_load', [])
)->find($cartId);

if ($cart->hasCompletedOrders() && ! $this->allowsMultipleOrdersPerCart()) {
return $this->createNewCart();
}

if (! $cart) {
return $create ? $this->createNewCart() : null;
}
Expand Down Expand Up @@ -173,7 +182,7 @@ public function estimateShipping(): void
*/
public function getSessionKey(): string
{
return config('lunar.cart.session_key');
return config('lunar.cart_session.session_key');
}

/**
Expand Down Expand Up @@ -232,12 +241,12 @@ public function getShippingOptions(): Collection

/**
* Create an order from a cart instance.
*
* @param bool $forget
*/
public function createOrder($forget = true): Order
public function createOrder(bool $forget = true): Order
{
$order = $this->manager()->createOrder();
$order = $this->manager()->createOrder(
allowMultipleOrders: $this->allowsMultipleOrdersPerCart()
);

if ($forget) {
$this->forget();
Expand All @@ -248,10 +257,8 @@ public function createOrder($forget = true): Order

/**
* Create a new cart instance.
*
* @return \Lunar\Models\Cart
*/
protected function createNewCart()
protected function createNewCart(): Cart
{
$user = $this->authManager->user();

Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/Models/Cart.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
use Lunar\Pipelines\Cart\Calculate;
use Lunar\Validation\Cart\ValidateCartForOrderCreation;
use Lunar\Validation\CartLine\CartLineStock;
use Throwable;

/**
* @property int $id
Expand Down Expand Up @@ -465,6 +466,8 @@ public function clear(): Cart

/**
* Associate a user to the cart
*
* @throws Exception
*/
public function associate(User $user, string $policy = 'merge', bool $refresh = true): Cart
{
Expand Down Expand Up @@ -643,7 +646,7 @@ public function fingerprint(): string
/**
* Check whether a given fingerprint matches the one being generated for the cart.
*
* @throws FingerprintMismatchException
* @throws FingerprintMismatchException|Throwable
*/
public function checkFingerprint(string $fingerprint): bool
{
Expand Down
Loading

0 comments on commit fca6cca

Please sign in to comment.