Table of Contents

Submitting to cart

How to submit things to cart

During the checkout flow, the customer is often asked to provide information and select e.g. a payment and shipping method before being allowed to submit the cart and convert it to an order.

In this section we will go though all the different things you can do when submitting to the cart, e.g.

  • Billing & Delivery details
  • User creation during checkout
  • Payment & shipping method selection
  • Applying vouchers
  • Paying with loyalty points
  • Using gift cards
  • Creating subscription orders
  • Paying with a saved card - and saving a card
  • Opt-ins
  • Using custom fields

To submit something to the cart you post a form with the id ordersubmit containing input fields that represent the features you want to implement:

<form name="ordersubmit" id="ordersubmit" method="post" role="form">

    <!--Insert form content here-->

    <button type="submit" name='@GetValue("CartV2.CurrentStepButtonName")' id='@GetValue("CartV2.CurrentStepButtonName")'>@Translate("Update_order", "Update order")</button>
    <button type="submit" name='@GetValue("CartV2.NextStepButtonName")' id='@GetValue("CartV2.NextStepButtonName")'>@Translate("Create_order", "Create order")</button>
</form>

In order for the cart to receive this information, the input fields being submitted must have specific names & values (the id only matters when you need to target an element from JavaScript or a <label>). You can read more about each feature below.

How the form drives the flow

Every post to the cart does two things: it saves the submitted fields onto the cart, and it requests a step to render. Which step is requested comes from the name of the button that submitted the form:

  • CartV2.CurrentStepButtonName resolves to CartV2.GotoStep{current} – it stays on the current step. Use it for an Update order button that recalculates the cart (e.g. after the customer changes country or quantity) without advancing.
  • CartV2.NextStepButtonName resolves to CartV2.GotoStep{current+1} – it advances to the next step. Use it for the Continue / Create order button.
  • You can target any step directly by submitting a button named CartV2.GotoStep{N} (for example a "back to cart" link that posts CartV2.GotoStep0). The cart still validates that the jump is allowed – see How it works.

The renderer also exposes ready-made button names so you rarely have to build the GotoStep{N} string yourself: CartV2.PreviousStepButtonName, CartV2.CheckoutButtonName, and a per-step Step.ButtonName inside the steps loop (handy for a clickable progress indicator).

A field is only saved when it is present in the post. This is why selecting a country or shipping method is usually wired to submit the form (an onchange="updateCart();" helper that clicks the update button), so the new value reaches the cart and prices/methods refresh immediately.

Tip

Because the cart recalculates on every post, fields that influence price or method availability – country, shipping method, voucher/gift card, loyalty points – should trigger a submit when they change, rather than waiting for the customer to press Continue.

Billing details

To add billing address details to an order, use input fields with the IDs listed below. Most map directly to standard user fields, but a few are for billing-specific information like an EAN-number or a VAT-number.

Field name & id Notes
EcomOrderCustomerCompany
EcomOrderCustomerName
EcomOrderCustomerTitle
EcomOrderCustomerFirstName
EcomOrderCustomerSurname
EcomOrderCustomerMiddleName
EcomOrderCustomerHouseNumber
EcomOrderCustomerInitials
EcomOrderCustomerPrefix
EcomOrderCustomerAddress
EcomOrderCustomerAddress2
EcomOrderCustomerZip
EcomOrderCustomerCity
EcomOrderCustomerCountry This field influences which payment methods & shipping methods can be selected.
EcomOrderCustomerRegion
EcomOrderCustomerPhone
EcomOrderCustomerFax
EcomOrderCustomerCell
EcomOrderCustomerEmail
EcomOrderCustomerVatRegNumber
EcomOrderCustomerEAN
EcomOrderCustomerRefId
EcomOrderCustomerComment Maps to the customer comment order field.

Since the billing country is important for determining which payment & shipping methods should be shown, you should make sure to preselect any default option and also find a way to update the cart when the user selects one of the commerce countries on the solution:

<!--Billing Address Fields-->
<div>
    <!--Personal Fields-->
    <div>
        <input type="text" name="EcomOrderCustomerTitle" id="Title" value='' />
        <input type="text" name="EcomOrderCustomerFirstName" id="EcomOrderCustomerFirstName" value='' />
        <input type="text" name="EcomOrderCustomerSurname" id="EcomOrderCustomerSurname" value='' />
        <input type="text" name="EcomOrderCustomerEmail" id="EcomOrderCustomerEmail" value='' />
        <input type="text" name="EcomOrderCustomerPhone" id="EcomOrderCustomerPhone" value='' />
    </div>

    <!--Address Fields-->
    <div>
        <input type="text" name="EcomOrderCustomerAddress" id="EcomOrderCustomerAddress" value='' />
        <input type="text" name="EcomOrderCustomerAddress2" id="EcomOrderCustomerAddress2" value='' />
        <input type="text" name="EcomOrderCustomerHouseNumber" id="EcomOrderCustomerHouseNumber" value='' />
        <input type="text" name="EcomOrderCustomerZip" id="EcomOrderCustomerZip" value='' />
        <input type="text" name="EcomOrderCustomerCity" id="EcomOrderCustomerCity" value='' />
        <input type="text" name="EcomOrderCustomerRegion" id="EcomOrderCustomerRegion" value='' />
        <select name="EcomOrderCustomerCountry" id="EcomOrderCustomerCountry" onchange="updateCart();">
            @foreach (var country in GetLoop("Countries"))
            {
                if (country.GetString("Ecom:Country.IsCustomerCountryOrDefault") == "true")
                {
                    <option value='@country.GetValue("Ecom:Country.Code2")' selected>@country.GetValue("Ecom:Country.Name")</option>
                }
                else
                {
                    <option value='@country.GetValue("Ecom:Country.Code2")'>@country.GetValue("Ecom:Country.Name")</option>
                }
            }
        </select>
    </div>
</div>

Delivery details

Delivery address details are submitted to cart in the same way as billing details – and are in fact almost identical to billing details.

The 'Copy customer info to delivery info fields if empty'-checkbox allows you to copy billing address field values to the delivery address fields if no part of the delivery address has been filled out.

Field name & id Notes
EcomOrderDeliveryCompany
EcomOrderDeliveryName
EcomOrderDeliveryFirstName
EcomOrderDeliveryTitle
EcomOrderDeliverySurname
EcomOrderDeliveryHouseNumber
EcomOrderDeliveryMiddleName
EcomOrderDeliveryInitials
EcomOrderDeliveryPrefix
EcomOrderDeliveryAddress
EcomOrderDeliveryAddress2
EcomOrderDeliveryZip
EcomOrderDeliveryCity
EcomOrderDeliveryCountry
EcomOrderDeliveryRegion
EcomOrderDeliveryPhone
EcomOrderDeliveryFax
EcomOrderDeliveryCell
EcomOrderDeliveryEmail

Creating a user during checkout

To create a user or update an existing user during checkout, submit a field with the name and ID EcomUserCreateNewOrUpdate alongside fields specifying the username and password.

Field name & Id Notes
EcomUserCreateNewOrUpdate Older implementations used EcomUserCreateNew
EcomUserCreateUserName
EcomUserCreatePassword
EcomUserCreateConfirmPassword

Payment methods

Payment methods are submitted to cart using input elements with the name EcomCartPaymethodID and an id of the type EcomCartPaymethodID_{PaymentMethodID}, with PaymentMethodID replaced by a valid id.

Some payment methods support rendering a payment form inline directly in the cart template, others require you to progress in the checkout flow. This part is payment-method specific, and the content of the payment form typically comes from a template selected on the payment method.

<!--Payment Methods-->
@foreach (var paymentmethod in GetLoop("Paymethods")) //Loop through payment methods
{
    <div class="radio">
        <label >
            @if (@paymentmethod.GetString("Ecom:Cart.Paymethod.IsSelected") == "true") // check if payment method is selected
            {
                <input type="radio" name="EcomCartPaymethodID" id='EcomCartPaymethodID_@paymentmethod.GetValue("Ecom:Cart.Paymethod.ID")' value='@paymentmethod.GetValue("Ecom:Cart.Paymethod.ID")' checked='checked' />
            }
            else
            {
                <input type="radio" name="EcomCartPaymethodID" id='EcomCartPaymethodID_@paymentmethod.GetValue("Ecom:Cart.Paymethod.ID")' value='@paymentmethod.GetValue("Ecom:Cart.Paymethod.ID")' />
            }
            @paymentmethod.GetValue("Ecom:Cart.Paymethod.Name")

        </label>
    </div>
}

<!--Inline Payment Forms-->
@if (!string.IsNullOrWhiteSpace(GetString("Ecom:Cart.PaymentInlineForm")))
{
     @GetString("Ecom:Cart.PaymentInlineForm")
}

Shipping methods

Shipping methods are submitted to cart using input elements with the name EcomCartShippingMethodId and an id of the type EcomCartShippingMethodId_{ShippingMethodID} with ShippingMethodID being replaced by a valid id.

Some shipping methods will ask the customer to select e.g. a parcel shop and a parcel type and so on - that's shipping method specific, and is handled in a template selectdd on the shipping method.

<!--Shipping methods-->
@foreach (var shippingmethod in GetLoop("Shippingmethods"))
{
    <div class="radio">
        <label>
            @if (shippingmethod.GetString("Ecom:Cart.Shippingmethod.IsSelected") == "true")
            {
                <input type="radio" name="EcomCartShippingmethodID" onclick="updateCart();" id='EcomCartShippingmethodID_@shippingmethod.GetValue("Ecom:Cart.Shippingmethod.ID")' value='@shippingmethod.GetValue("Ecom:Cart.Shippingmethod.ID")' checked="checked" />
            }
            else
            {
                <input type="radio" name="EcomCartShippingmethodID" onclick="updateCart();" id='EcomCartShippingmethodID_@shippingmethod.GetValue("Ecom:Cart.Shippingmethod.ID")' value='@shippingmethod.GetValue("Ecom:Cart.Shippingmethod.ID")' />
            }
            @shippingmethod.GetValue("Ecom:Cart.Shippingmethod.Name")
        </label>
    </div>

    <!--Shippingmethod Content - e.g. Parcel shops or Parcel types-->
    if (!string.IsNullOrWhiteSpace(shippingmethod.GetString("Ecom:ShippingProvider.Content")))
    {
        @shippingmethod.GetString("Ecom:ShippingProvider.Content")
    }
}

Vouchers

Vouchers are applied to an order by submitting one or more voucher codes in a field named EcomOrderVoucherCode.

<!--Vouchers-->
<input type="text" name="EcomOrderVoucherCode" id="EcomOrderVoucherCode" value='@GetString("Ecom:Order.Customer.VoucherCode")' />

Submitting more than one code

The value of EcomOrderVoucherCode may contain several codes separated by a comma, semicolon or space (e.g. SUMMER10, WELCOME5). On submit, the cart:

  1. Splits the value into individual codes.
  2. Validates each code on its own and silently discards the invalid ones.
  3. Stores the surviving codes back on the order as a single comma-separated string.

Because the field is replaced on every submit (it is not additive), the value you post is the complete set of codes the order should have. This has two consequences:

  • Submitting the same code twice has no extra effect – duplicates collapse to a single applied code.
  • To add a code while keeping the existing ones, post the existing codes plus the new one. To remove one code but keep the others, post the remaining codes and leave the unwanted one out. Posting an empty value removes them all.

Rendering the applied codes

Two things come back to the template:

  • Ecom:Order.Customer.VoucherCode – the raw, comma-separated value, suitable for re-populating the input field above (it falls back to the value just posted so the field survives a failed validation).
  • A VoucherCodes loop that yields one row per applied code via Ecom:Order.VoucherCode – use this to render a removable "chip" per code.
<!--Show the applied codes as removable chips-->
<ul class="voucher-list">
    @foreach (var voucher in GetLoop("VoucherCodes"))
    {
        <li>@voucher.GetString("Ecom:Order.VoucherCode")</li>
    }
</ul>

To make a single chip removable, render a button that re-posts EcomOrderVoucherCode with that one code stripped out – typically by building the new value in JavaScript from the remaining chips, then submitting the cart.

Note

A voucher only does something if it is tied to a discount (or, on the adjustments engine, a voucher condition). A code can be a perfectly valid, unused voucher and still not change the price if no active discount targets it. The discount it triggers shows up as a discount order line, where Ecom:Order:OrderLine.DiscountVoucher holds the code that produced it.

Loyalty points

To apply loyalty points to an order, you submit a field with the id EcomOrderPointsToUse and a value in loyalty points. In this example we first check if the current user is logged in - if she is, we retrieve her points balance and check if it's possible to use points on an order.

@{
    var isLoggedIn = Dynamicweb.Security.UserManagement.User.IsExtranetUserLoggedIn();
    var currentUser = Dynamicweb.Security.UserManagement.User.GetCurrentExtranetUser();

    double pointsbalance = 0;
}

<!--Pay with points-->
@if (isLoggedIn)
{
    pointsbalance = Dynamicweb.Ecommerce.Services.Loyalty.GetPointsBalance(currentUser.ID);

    <div>Your points: @pointsbalance</div>

    @if (pointsbalance > 0)
    {
        <input type="text" name="EcomOrderPointsToUse" id="EcomOrderPointsToUse" value='@GetValue("Ecom:Order.PointsToUse")' />
    }
    else
    {
        <input type="text" name="EcomOrderPointsToUse" id="EcomOrderPointsToUse" value='' disabled title='No loyalty points available' />
    }
}

Gift Cards

Gift cards are applied to an order by submitting one or more gift card codes in a field named EcomOrderGiftCardCode.

<input type="text" name="EcomOrderGiftCardCode" id="EcomOrderGiftCardCode" value="" />

Submitting more than one code

Like vouchers, the field can hold several codes separated by a comma, semicolon or space, and the field is treated as the complete set of cards on the order rather than an addition to it. On each submit the cart:

  1. Compares the posted codes with the gift cards already applied to the cart.
  2. Keeps the cards whose code is still present, removes the cards whose code is no longer posted, and applies any new codes.

So the removal pattern is the same as for vouchers: to remove one gift card but keep the others, re-post the field with that code left out; posting an empty value removes them all. Applying a card adds a discount order line carrying the gift card code, which is how the redeemed amount is reflected in the cart total.

Rendering applied gift cards

How a redeemed gift card surfaces depends on the stage of the flow:

  • In the active cart, each applied card is a discount order line – iterate the order lines and use Ecom:Order:OrderLine.GiftCardCode to identify them.
  • On the receipt (a completed order), two ready-made loops are available:
    • Ecom:Order.HasUsedGiftCards is true when at least one card was redeemed, and the UsedGiftCards loop exposes per-card details: Ecom:Order.UsedGiftCard.Name, .Code, .ExpiryDate, .InitialAmount, .UsedAmountForTheOrder and .RemainingBalance (each amount also has the usual price-formatting sub-tags).
    • Ecom:Order.HasGiftCards is true when the order bought gift card products, and the GiftCards loop exposes the issued cards via Ecom:Order.GiftCard.Name, .Code, .ExpiryDate and .Amount.
@if (GetString("Ecom:Order.HasUsedGiftCards") == "true")
{
    <ul>
        @foreach (var card in GetLoop("UsedGiftCards"))
        {
            <li>
                @card.GetString("Ecom:Order.UsedGiftCard.Code")
                – used @card.GetString("Ecom:Order.UsedGiftCard.UsedAmountForTheOrder")
                (balance @card.GetString("Ecom:Order.UsedGiftCard.RemainingBalance"))
            </li>
        }
    </ul>
}

Subscription orders

To create a subscription order you must first check if the payment method supports subscription orders. If it does, submit a boolean field with the id & name EcomRecurringOrderCreate alongside an interval. an interval unit, a start date and an end date.

Field Name & ID Value Notes
EcomRecurringOrderCreate
EcomOrderRecurringInterval -
EcomOrderRecurringIntervalUnit 0 = days, 1 = weeks, 2 = months
EcomOrderRecurringEndDate
EcomOrderRecurringEndDate_year
EcomOrderRecurringEndDate_month
EcomOrderRecurringEndDate_day
EcomOrderRecurringStartDate
@if (@GetBoolean("Ecom:Order.PaymentMethod.RecurringSupport") == true)
{
    <!--Checkbox to create recurring orders-->
    <input type="checkbox" name="EcomRecurringOrderCreate" id="EcomRecurringOrderCreate" checked='@GetBoolean("Ecom:User.CreateNew")' />

    <!--Interval-->
    <input type="text" name="EcomOrderRecurringInterval" id="EcomOrderRecurringInterval" value='1' />
    <select name="EcomOrderRecurringIntervalUnit" id="EcomOrderRecurringIntervalUnit" value="0">
        <option value="0">Days</option>
        <option value="1" selected>Weeks</option>
        <option value="2">Months</option>
    </select>

    <!--Start Date-->
    <input type="date" name="EcomOrderRecurringStartDate" id="EcomOrderRecurringStartDate" min='@DateTime.Today.ToString("yyyy-MM-dd")' value='@DateTime.Today.ToString("yyyy-MM-dd")' />

    <!--End Date-->
    <input type="date" name="EcomOrderRecurringEndDate" id="EcomOrderRecurringEndDate" min='@DateTime.Today.AddDays(7).ToString("yyyy-MM-dd")' value='@DateTime.Today.AddDays(7).ToString("yyyy-MM-dd")' />
}

Saved cards

Saved cards - or more properly saved payment methods - are saved by submitting a field named EcomOrderSavedCardCreate with the value true, alongside a field named EcomOrderSavedCardName specifying the name to store the card under. You should ensure that the payment method supports saved cards - at the time of writing this is supported by Stripe, ChargeLogic and QuickPay Payment Window.

Note

The cart reads the name EcomOrderSavedCardCreate (the value must be the string true or false). The _{PaymethodID} suffix you will see on the id attribute in the example below is only there to keep the element ids unique while looping the payment methods – it is not part of the submitted name. Submitting the value false clears a previously requested save.

To use a saved card submit a field named EcomCartSavedCardID whose value is the id of the saved card (the id attribute is suffixed _{SavedCardId} to stay unique in the loop). Selecting a saved card also sets the payment method from the stored card, so you do not need to submit a separate EcomCartPaymethodID.

<!--Saving a card -->
@foreach (var paymentmethod in GetLoop("Paymethods")) //Loop through payment methods
{
    if (paymentmethod.GetString("Ecom:Cart.Paymethod.SupportSavedCard") == "true" && @paymentmethod.GetString("Ecom:Cart.Paymethod.IsSelected") == "true") // Check if this method supports saved cards & is selected
    {
        <input type="checkbox" name="EcomOrderSavedCardCreate" id="EcomOrderSavedCardCreate_@paymentmethod.GetString("Ecom:Cart.Paymethod.ID")" value="true" />
        <input type="text" name="EcomOrderSavedCardName" id="MySavedCardName" value='My @paymentmethod.GetValue("Ecom:Cart.Paymethod.Name") Card' />
    }
}
<!-- Using a card -->
@{
    var savedcards = GetLoop("SavedCards");
}
@if (savedcards.Any()) //Checks if this user has any saved cards
{
    foreach (var savedcard in savedcards)
    {
        <div class="radio">
            <label>
                @if (@savedcard.GetString("Ecom:SavedCard.IsSelected") == "true") //Checks if the saved card is selected
                {
                    <input type="radio" name="EcomCartSavedCardID" id="EcomCartSavedCardID_@savedcard.GetString("Ecom:SavedCard.ID")" value="@savedcard.GetString("Ecom:SavedCard.ID")" checked="checked" />
                }
                else
                {
                    <input type="radio" name="EcomCartSavedCardID" id="EcomCartSavedCardID_@savedcard.GetString("Ecom:SavedCard.ID")" value="@savedcard.GetString("Ecom:SavedCard.ID")" />
                }
                @savedcard.GetString("Ecom:SavedCard.Name")

            </label>
        </div>
    }
}

To allow the customer to see/edit/remove a saved card use a customer center app.

Opt-ins

From the cart you can change the value of the Email permission field on the logged in user, and the user can be asked to accept the Terms & Conditions.

A setting on the cart - Use email subscription - can be used in templates.

<!--Email permission-->
@if (GetString("Ecom:Cart.UseNewsletterSubscription") == "True")
{
    <input type="checkbox" name="EcomOrderSubscribeToNewsletter" id="EcomOrderSubscribeToNewsletter" checked='@GetBoolean("Ecom:Order.Customer.NewsletterSubscribe")' />
    <label for="EcomOrderSubscribeToNewsletter">Subscribe to newsletter</label>
}

<!--Terms & Conditions-->
<input type="checkbox" name="EcomOrderCustomerAccepted" id="EcomOrderCustomerAccepted" />
<label for="EcomOrderCustomerAccepted">Accept terms & conditions</label>

When the cart's customer acceptance validation is enabled, leaving EcomOrderCustomerAccepted unchecked fails the submit and the configured error message is surfaced through the validation tags.

Rendering validation and errors

When a submit fails validation – a required field is empty, a validation group rule fails, terms aren't accepted, stock is insufficient, and so on – the cart re-renders the step the customer came from and exposes the errors to the template so you can show them. Nothing is lost: the posted values are kept on the cart, so the fields you re-render with value='@GetString(...)' come back populated.

Errors are available in two shapes:

  • A ValidationErrors loop, with one row per error: Ecom:Cart.ValidationError.FieldSystemName, Ecom:Cart.ValidationError.FieldName (the friendly name) and Ecom:Cart.ValidationError.ErrorMessage. Use this for a summary list at the top of the form.
  • A per-field tag Ecom:Cart.ValidationError.{FieldSystemName}.ErrorMessage, which is set to the message when that field failed and to an empty string otherwise. Use this to print the message next to the relevant input.
<!--Error summary-->
@if (GetLoop("ValidationErrors").Any())
{
    <div class="alert alert-danger">
        <ul>
            @foreach (var error in GetLoop("ValidationErrors"))
            {
                <li>@error.GetString("Ecom:Cart.ValidationError.FieldName"): @error.GetString("Ecom:Cart.ValidationError.ErrorMessage")</li>
            }
        </ul>
    </div>
}

<!--Inline error next to a field-->
<input type="text" name="EcomOrderCustomerEmail" value='@GetString("Ecom:Order.Customer.Email")' />
<span class="field-error">@GetString("Ecom:Cart.ValidationError.EcomOrderCustomerEmail.ErrorMessage")</span>

Two related signals are worth handling:

  • Removed products – if a product was removed because it no longer exists, its name is passed to the step template so you can tell the customer what happened.
  • Method errors – a shipping provider can reject the current selection; Ecom:Cart.Shippingmethod.Error carries any provider error message for the method.

Custom field

Custom fields – such as order fields or a coupon field – are posted to the cart using input elements which take the system name as the field name. No ID is necessary.

<div>
    <label for="Coupons">Coupon</label>
    <input  type="text" name="Coupons" value='' />
</div>
<div>
    <label for="TrackingURLFromERP">TrackingURLFromERP</label>
    <input type="text" name="TrackingURLFromERP" value='' />
</div>

Other fields

Finally, a small set of standard order fields can be submitted to the cart. They map directly to properties on the order and are used primarily on B2B and integrated solutions. Although you can submit values to them from frontend this is not the typical case.

Field Name & ID Maps to order property Notes
EcomCartRequisition Requisition A free-text purchase requisition / PO number the buyer wants on the order. Common on B2B checkouts where the customer must reference their own internal purchase order.
EcomOrderReference Reference A free-text order reference – e.g. "your reference", the name of the person placing the order, or any reference the customer or sales rep wants to carry on the order.
EcomOrderShippingDate ShippingDate A requested shipping/delivery date. The value is parsed as a date; an empty or unparseable value clears it. Use it when the customer can ask for a specific delivery day.
EcomOrderIntegrationId IntegrationOrderId The order id in an external system (e.g. an ERP). Normally written by an integration rather than entered by the customer, which is why it is rarely on a checkout form.
Note

These are standard fields with dedicated order properties – they are not custom fields, so you submit them under the fixed field names above, not under an order field system name.

To top