Table of Contents

Shopping Cart

Render cart content, handle the checkout flow, and show a receipt to customers.

The Shopping Cart app is a paragraph app that turns a page into a checkout flow. On every request it:

  • Loads the current cart and keeps a record of the products added to it
  • Saves whatever the customer just posted (address, payment & shipping selection, custom fields, voucher/gift card codes …) onto the cart
  • Recalculates prices, discounts and taxes
  • Validates the input and decides which step to render
  • At the checkout step, converts the cart into a real order (or a quote), hands it to a payment gateway, sends notification e-mails, and finally shows a receipt

This article explains how the app works at runtime and then documents every setting in the app editor. Two companion articles cover the rest of the implementation surface:

  • Cart commands – manipulate cart content (add/remove/update lines, set quantities …) from any template
  • Submitting to cart – the form fields and conventions used to move the customer through the flow
Note

The shopping cart does not currently expose a ViewModel, so its templates use template tags, not Razor view models.

How it works

The cart is rendered by the eCom_CartV2 content module. Each time the cart page is requested, the module runs the same pipeline. Understanding this pipeline is the key to implementing the cart correctly, because almost every setting in the editor simply tweaks one step of it.

flowchart TD
    start((" ")) --> ctx["Resolve cart & context<br/>(channel / order context)"]
    ctx --> empty{"Is the cart<br/>empty?"}
    empty -- yes --> emptyaction["Run the configured<br/>empty-cart action"]
    empty -- no --> clean["Remove products that<br/>no longer exist"]
    clean --> post["Apply posted values<br/>(address, method, fields,<br/>vouchers, gift cards …)"]
    post --> calc["Recalculate prices,<br/>discounts & taxes"]
    calc --> resolve["Resolve next step<br/>(GotoStepN / re-enter rule)"]
    resolve --> validate{"Is the step<br/>valid & fields OK?"}
    validate -- no --> rerender["Re-render previous step<br/>with validation errors"]
    validate -- yes --> ischeckout{"Is the next step<br/>the checkout step?"}
    ischeckout -- no --> render["Render the step template"]
    ischeckout -- yes --> convert["Convert cart → order / quote<br/>send mails · pass to gateway"]
    convert --> receipt["Show receipt<br/>(post-checkout step)"]

    classDef decision fill:#5ba85b,stroke:#3d8b3d,color:#fff
    class empty,validate,ischeckout decision
    style start fill:#888,stroke:#888,color:#888
    style convert fill:#1a6fb5,stroke:#145a93,color:#fff

Steps are a state machine

The flow is driven by an ordered list of steps. The cart remembers which step it is on (the step index is stored on the order), and the customer moves between steps by submitting a form button named CartV2.GotoStepN, where N is the target step index. The app then:

  1. Works out the requested next step (from the GotoStepN button, or — if the customer simply returned to the page — from the re-enter rule).
  2. Checks the move is legal. You can move forward and backward through the pre-checkout steps, but you cannot reach a post-checkout step (the receipt) unless the order has actually completed. Likewise, once an order is complete only the receipt steps are reachable.
  3. Validates the fields posted on the step (and, on the checkout step, the order as a whole). If validation fails, the previous step is re-rendered with the errors so the customer can correct them.

The checkout step is the pivot

Exactly one step must be marked as the checkout step. Reaching it is what turns a cart into something permanent:

  • For a normal cart it generates an order number, hands the order to the relevant payment gateway / checkout handler, and (on success) marks the order complete, rewards loyalty points, redeems gift cards and sends the notification e-mails.
  • For a quote cart it converts the cart to a quote and sends the mails immediately, without a gateway.

The checkout step itself does not need its own template — when configured without one, the customer moves straight from the previous step to the next step (typically the receipt).

Things the app does automatically

Several behaviours are not settings — the app always handles them when the corresponding fields are posted. Knowing the field names is what lets you build the templates:

Behaviour Triggered by See
Voucher / discount codes EcomOrderVoucherCode Vouchers
Gift cards EcomOrderGiftCardCode Gift cards
Loyalty points payment EcomOrderPointsToUse Loyalty points
Subscription / recurring orders EcomRecurringOrderCreate (+ interval fields) Submitting to cart
Create a user during checkout EcomUserCreateNew / EcomUserCreateNewOrUpdate User management
Newsletter opt-in EcomOrderSubscribeToNewsletter Newsletter

Throughout the pipeline the app raises a large number of notifications (before/after payment method set, country changed, order validation, checkout done …), which is the supported way to hook in custom logic without modifying the cart.

Note

The cart page is always served with no-cache response headers, because its content is request- and session-specific. Don't rely on output caching for cart pages.

Settings

The rest of this article documents the app editor. When you add the app to a paragraph you get the settings below, grouped into sections. The Steps are the most important because they define the flow; most other sections refine behaviour around it.

The Settings section sets the channel/context and turns the cart into a quote cart: Shopping cart – Settings section

Setting Use Notes
Channel Select a channel Overrides the value set on the website Ecommerce settings. If left empty, the website's channel is used.
Context cart Select an order context Lets this cart use a separate order context (e.g. a secondary basket).
Checkout to quote Make this a quote cart The checkout step converts the cart to a quote and sends mails instead of passing it to a gateway.

Steps

The Steps section defines the steps in the checkout flow – e.g. Show Cart, Checkout and Receipt. Each step consists of a label and a template that renders what happens on that step. Shopping cart – Steps list Click a step to edit it. Exactly one step must be designated the checkout step – this is the step that converts a cart into an order (see The checkout step is the pivot). Shopping cart – marking a step as the checkout step The checkout step doesn't need a template; when it has none, the customer moves directly from the previous step to the next step (typically Receipt).

Notification e-mails

The Notification e-mails section creates e-mail notifications for customers and staff – most commonly an order confirmation. They are sent when the checkout step completes. Shopping cart – Notification e-mails section To create a notification:

  1. Click Add
  2. Specify recipients – in one or more of these ways:
    • Check send to billing email and/or send to shipping email
    • Check send to custom email field and select the custom field holding the address
    • Manually specify an address in the Recipient field
  3. Fill in the e-mail details:
    • Specify a Subject. The token {OrderID} is replaced with the order id (case-insensitive), so Order {OrderID} confirmed becomes e.g. Order ORDER42 confirmed.
    • Select mail contentPage or Template – and select the relevant page or template (see below)
    • Specify a sender name and sender email (the sender e-mail must be a valid address or the mail is skipped)
    • Select an encoding (default is UTF-8)
    • Optionally select an attachment

The body is always sent as HTML. The difference between the two content sources is what context they get:

  • Template – an order e-mail template, rendered with the full set of order template tags (Ecom:Order.*, the OrderLines loop, gift card and voucher loops, …) – the same tags you use on the receipt step.
  • Page – an internal page, rendered with the order made available as context values Order and OrderID, so an item on the page can render order details.

A single notification can resolve to several recipients (billing + shipping + every address in a custom field); each unique address receives its own copy. {OrderID} and the body are evaluated per send.

Note

Notification e-mails are sent when the checkout step completes – for a normal cart after the gateway confirms the order, and for a quote cart immediately on conversion. Sending is wrapped so that a mail failure is logged but does not break the customer's checkout.

Field validation

The Field validation settings apply validation during checkout: Shopping cart – Field validation section Using these settings you can:

  • Check customer acceptance to require Terms & Conditions acceptance, and customize the error message rendered when the check fails
  • Check stock status to require that products are in stock, and customize its error message
  • Select a custom validation group to apply during checkout

Newsletter

The Newsletter setting lets the customer update the standard user e-mail permission field during checkout (via the EcomOrderSubscribeToNewsletter field). It is enabled by default. Shopping cart – Newsletter section

Empty cart

The Empty cart settings control what happens when the customer views an empty cart: Shopping cart – Empty cart section

  • Redirect to an internal page – redirect the customer to a specific page
  • Show template – render a chosen template instead of the cart
  • Take no special action (default) – render the first step of the flow as normal

User management

The User management section does two things: Shopping cart – User management section

  • Apply user details to order controls whether a logged-in user's details are applied to the cart on first load. This is on by default.
  • Create user in checkout lets an anonymous customer be registered during checkout. When enabled you can:
    • Select a group for new users to place them in
    • Check Update existing users based on email match to update a matching user instead of failing
    • Customize the validation error messages (empty username/password, passwords don't match, password length, username taken, illegal characters)

There is also an option to include delivery addresses from users with the same customer number, so that addresses belonging to other users in the same company/customer account become selectable during checkout.

Payment & delivery

The Payment & delivery section controls which payment methods and shipping methods are available on this cart. Shopping cart – Payment & delivery section

  • For each of payment and delivery you can either make all methods available (the default) or select a specific list of methods.
  • You can set a default payment method and a default shipping method, which are pre-selected for the customer (see SetDefaultPaymentAndShipping behaviour). If no default is set and only one method is available, that method is used.

Additional settings

The Additional settings section tweaks a few behaviours of the flow: Shopping cart – Additional settings section

  • When re-entering cart controls which step to show when a customer leaves the flow and returns to the cart:
    • Show first step (default)
    • Show last visited step
  • Country for shipping method controls which address is used to fetch shipping methods:
    • Always use billing country
    • Always use shipping country
    • Use delivery/shipping country if a shipping address is set, otherwise billing (default)
  • Country for payment method controls which address is used to fetch payment methods. Same three options, but the default is Always use billing country.
  • Unavailable products controls what happens when a product becomes unavailable during checkout:
    • Remove – silently remove it from the cart (the removed product names are passed to the template so you can inform the customer)
    • Ignore – leave it in the cart

Appendix A: two example flows

The same app supports very different checkouts depending purely on how you configure the steps and the surrounding settings. The two flows below are common starting points. They differ in configuration, not in code – the pipeline in How it works runs identically for both.

A1: Anonymous B2C checkout

A typical webshop checkout where the visitor is not logged in and enters their details as they go.

Step Label Checkout step? Template renders
0 Cart No Order lines, quantities, voucher/gift card field, Continue button
1 Information No Billing + delivery address fields, shipping & payment selection, terms opt-in
2 Checkout Yes (no template – hands off to the gateway)
3 Receipt No Order confirmation (see Appendix B)

Relevant settings:

  • User management → Apply user details to order: irrelevant (no user), but Create user in checkout is often enabled with Update existing users based on email match so a returning customer isn't duplicated.
  • Field validation → customer acceptance: on, to force a Terms & Conditions tick.
  • Country for payment/shipping method: the visitor's typed billing country drives method availability, so the address step submits the cart on country change.

Technically, this flow leans on the billing/delivery fields being typed into the form on step 1. The cart carries the values; no user record exists unless create user in checkout fires at the checkout step.

A2: Authenticated B2B checkout

A logged-in business buyer who orders on behalf of a company, picking from saved addresses and paying on account.

Step Label Checkout step? Template renders
0 Cart No Order lines, requisition/reference fields, Continue button
1 Delivery & payment No Address picker (saved addresses), shipping & payment (e.g. Invoice)
2 Checkout Yes (no template)
3 Receipt No Order confirmation + "your reference"

Relevant settings & techniques:

  • User management → Apply user details to order: on, so the logged-in user's details populate the order on first load.
  • Include delivery addresses from users with the same customer number: on, so the buyer can ship to any address belonging to their company, not just their own.
  • Instead of typing an address, the template submits a selected address idEcomOrderCustomerSelectedAddressId (billing) and EcomOrderDeliverySelectedAddressId (delivery) – and the cart copies that address onto the order. A delivery address is only accepted if it belongs to the user or to a user with the same customer number.
  • B2B-oriented order fields such as EcomCartRequisition and EcomOrderReference are commonly collected and shown again on the receipt and in the order confirmation e-mail.
  • Payment is typically an Invoice method that needs no gateway interaction, so the checkout step completes the order directly.
Tip

The step count and labels are entirely up to you – a one-page checkout is just step 0 = checkout, and a multi-page wizard is more pre-checkout steps. What must be true in every flow is that exactly one step is the checkout step, and that price/method-affecting fields submit the cart when they change.

Appendix B: a minimal receipt template

A receipt step renders a completed order, so all Ecom:Order.* tags and the OrderLines loop are populated. The smallest useful receipt looks like this:

<h1>Thank you for your order</h1>

<p>Order number: <strong>@GetString("Ecom:Order.ID")</strong></p>

<table>
    <thead>
        <tr><th>Product</th><th>Qty</th><th>Total</th></tr>
    </thead>
    <tbody>
        @foreach (var line in GetLoop("OrderLines"))
        {
            <tr>
                <td>@line.GetString("Ecom:Order:OrderLine.ProductName")</td>
                <td>@line.GetString("Ecom:Order:OrderLine.Quantity")</td>
                <td>@line.GetString("Ecom:Order:OrderLine.TotalPrice")</td>
            </tr>
        }
    </tbody>
</table>

<p>Total: <strong>@GetString("Ecom:Order.Price.PriceWithVATFormatted")</strong></p>

@if (GetString("Ecom:Order.HasUsedGiftCards") == "true")
{
    <p>Paid partly with gift card(s):</p>
    <ul>
        @foreach (var card in GetLoop("UsedGiftCards"))
        {
            <li>@card.GetString("Ecom:Order.UsedGiftCard.Code") – @card.GetString("Ecom:Order.UsedGiftCard.UsedAmountForTheOrder")</li>
        }
    </ul>
}

The same markup works as a Template-type notification e-mail body, which is why an order confirmation mail and the on-screen receipt usually share one template. For the full set of tags available on the order and order lines, see Submitting to cart.

To top