Skip to main content
Carts manage the collection of items a customer intends to purchase, with dynamic price calculation.

Overview

Carts hold a collection of purchasable items (typically product variants) that a customer intends to order. They belong to users (which relate to customers) and support a single currency each.
Cart prices are dynamically calculated and are not stored in the database. Once a cart is converted to an order, the prices are persisted on the order instead.

Cart Model

Creating a Cart

Relationships

The draftOrder and completedOrder relationships accept an optional order ID parameter to filter to a specific order:

Scopes

Setting the Tax Zone Added in 1.5

A cart can be assigned an explicit tax zone, which lets line totals be calculated tax-inclusive before a shipping address is captured. This is typically wired up in middleware that infers the customer’s tax zone from their IP address.
setTaxZone triggers a recalculation by default. Pass false as the second argument to defer the recalculation.
When setShippingAddress is called on a cart that already has an explicit tax zone, the zone is cleared so that address-based resolution can take over. Pass clearTaxZone: false to keep the explicit zone in place.

Cart Lines

Each item in a cart is represented by a CartLine. Lines link to a purchasable model (usually a ProductVariant) and track the desired quantity.

Relationships

Adding Lines

Use the add method to add a purchasable item to the cart. If the item already exists in the cart, its quantity is updated instead.
Multiple lines can be added at once using addLines:
Lines can also be created directly via the relationship:

Updating Lines

Removing Lines

Line Validation

When adding, updating, or removing items, a series of validation actions are run (defined in config/lunar/cart.php). These throw a CartException on failure.

Exceptions

Lunar throws specific exceptions during cart operations to help identify what went wrong. All cart exceptions extend Lunar\Exceptions\LunarException.

CartException

The primary exception for cart validation failures. It is thrown by the validation pipeline when adding, updating, or removing cart lines, or when creating an order. It wraps a MessageBag containing one or more error messages.
When creating an order, the ValidateCartForOrderCreation validator may throw a CartException with one of the following messages:

InvalidCartLineQuantityException

Thrown when attempting to add a purchasable to the cart with a quantity of zero or less.

NonPurchasableItemException

Thrown when creating or updating a cart line with a model that does not implement the Lunar\Base\Purchasable interface. This is checked automatically by the CartLineObserver.

CartLineIdMismatchException

Thrown when attempting to remove a cart line that does not belong to the specified cart.

DisallowMultipleCartOrdersException

Thrown when calling createOrder() on a cart that already has a completed order, unless allowMultipleOrders: true is passed.

FingerprintMismatchException

Thrown when the fingerprint passed to checkFingerprint() does not match the cart’s current fingerprint. See Detecting Cart Changes for usage details.

Calculating Totals

Call calculate() to hydrate the cart with computed prices and tax breakdowns.
All monetary values return a Lunar\DataTypes\Price object, providing access to value, formatted, and decimal properties.
To force recalculation (bypassing the cached result), use recalculate:
To check whether a cart has already been calculated:

Cart-Level Properties

Line-Level Properties

After calculation, each cart line is also hydrated with its own totals:

Breakdowns

The cart also provides detailed breakdowns for tax, discounts, and shipping:

Extending Cart Calculations

To programmatically change cart values (e.g. custom discounts or prices), see Cart Extending.

Cart Addresses

Each cart can have a shipping and billing address, represented by the CartAddress model. These addresses are used when calculating tax breakdowns and shipping costs.

Relationships

Cached Properties

After the cart is calculated, shipping addresses are hydrated with shipping-related totals:

Setting Addresses

Shipping and billing addresses can be set on the cart, which are used when calculating tax breakdowns.
An Address model or a CartAddress model can also be passed:
Retrieve addresses via the properties:
During a cart’s early lifetime, address information may not yet be available. Some countries don’t display tax until checkout. The address-based tax calculation is designed to handle this: the addresses can be set when they become available.

Shipping Options

A shipping option can be set on the cart after an address has been provided. The available options are determined by the shipping manifest.
To retrieve the currently selected shipping option:
To check whether the cart contains any shippable items:

Shipping Estimates

It may be useful to show an estimated shipping cost before a full address is provided. The getEstimatedShipping method returns the cheapest available shipping option based on partial address data.
By default, this estimate is not used in cart total calculations. To include it, pass setOverride: true:
When setOverride is enabled, the returned shipping option bypasses other shipping logic in the cart pipelines, but only for that single request.
The override can also be set manually:

Creating Orders

Once a cart has been calculated and all required information (addresses, shipping, etc.) has been provided, an order can be created from the cart.
By default, a cart can only have one order. To allow multiple orders from the same cart (e.g. for split shipments), pass allowMultipleOrders:
To update an existing order instead of creating a new one, pass the order ID:

Checking Order Readiness

Before attempting to create an order, check whether the cart has sufficient information:
To check whether the cart already has completed (placed) orders:
To retrieve the current draft order (matching the cart’s fingerprint and total):

Stock Validation

Stock levels can be validated before order creation. This checks each cart line against the available stock for its purchasable item.

Associating Users and Customers

A user can be associated directly on the cart model. The policy parameter controls how the association behaves when the user already has an existing cart: merge combines the carts, while override replaces the existing one.
A customer can also be associated:

Cart Session Manager

The cart session manager is useful when building a traditional Laravel storefront that uses sessions.
The session manager provides a convenient API for managing carts tied to the current user’s session.

Configuration

Cart configuration lives in config/lunar/cart.php: The default eager_load relationships are:
Additional session-specific config is in config/lunar/cart_session.php:

Getting the Session Instance

Use the facade or inject the interface:
When current() is called, the behavior depends on the auto_create config. With auto_create set to false (default), null is returned if no cart exists, preventing unnecessary database records.

Managing Lines

Using a Specific Cart

Associating a User

Associating a Customer

A customer can be associated directly on the cart model:

Forgetting the Cart

Forgetting a cart removes it from the session and soft-deletes it from the database:
To remove it from the session without deleting:

Shipping Estimates

When using the CartSession manager, shipping estimation parameters can be persisted so they do not need to be passed each time:
See Shipping Estimates above for more on how the underlying estimation works.

Handling User Login

When a user logs in, Lunar automatically listens to authentication events and handles cart association. If the user had a guest cart, it will be merged with (or override) any existing cart on their account, depending on the auth_policy config.

Detecting Cart Changes

Carts are dynamic: items, quantities, and prices can change at any moment. To detect whether a cart has been modified (e.g. on a different browser tab during checkout), use the fingerprint system:
The fingerprint generator class can be customized in config/lunar/cart.php:

Pruning Old Carts

Over time, unused carts accumulate in the database. Lunar can automatically prune carts that have no associated order. Enable pruning in config/lunar/cart.php:

Activity Logging

The Cart model uses Spatie Activity Log to automatically record changes. All attribute changes are logged except for updated_at.

Macros

The Cart model supports macros, allowing custom methods to be added at runtime: