London Dev Meetup Rescheduled! Due to unavoidable reasons, the event has been moved to 21st May. Speakers remain the same—any changes will be communicated. Seats are limited—register here to secure your spot!

Son Do
Dec 27, 2016
  4056
(8 votes)

[No-workflow] Generating cart using Commerce abstraction

Why

- Sometime I need a cart for testing new business logic.

- Sometime I need to create some cart for verify listing.

- And sometime I need to create a lot of cart for checking performance.

- In general, I need sample cart data.

Those’re the reason I create and share this, maybe someone need to data cart like me :)

There are 2 sections in this post:

- Creating a simple cart.

- Creating a tool to generate a bundle of carts.

Refer to http://world.episerver.com/documentation/developer-guides/commerce/orders/order-processing/ for more detail.

Creating a simple cart

We could create a simple cart with short code and pass through all validator. Creating cart is quite simple like code below:


var orderRepository = ServiceLocator.Current.GetInstance();
var customerId = Guid.NewGuid();
var cart = orderRepository.LoadOrCreateCart(customerId, "DefaultName");

var lineItem = cart.CreateLineItem("entry code you want to add (SKU-24064191 for example)");
lineItem.Quantity = 1;
lineItem.PlacedPrice = 100;

cart.AddLineItem(lineItem);
var cartLink = orderRepository.Save(cart);

Verify on DB or Commerce Manager, we’ll found a cart was created with that code. 

Note that those APIs were in Commerce 10.2.0 and below - this version includes new cart feature, that helps us creating cart more simple than before, with shorter and easier to understanding.

Validate cart

Adding line below to your existing code:


cart.ValidateOrRemoveLineItems(null); // Validates the line items and removes from the cart if they are invalid.
cart.UpdatePlacedPriceOrRemoveLineItems(null); // Updates all of the line item placed prices for the specified cart or removes the line item if their is no valid price.
cart.UpdateInventoryOrRemoveLineItems(null); // Updates the inventory for var or removes the line item if no available inventory
var orderRepository = ServiceLocator.Current.GetInstance();
var customerId = Guid.NewGuid();
var cart = orderRepository.LoadOrCreateCart(customerId, "DefaultName");

var lineItem = cart.CreateLineItem("entry code you want to add (SKU-24064191 for example)");
lineItem.Quantity = 1;
lineItem.PlacedPrice = 100;

cart.AddLineItem(lineItem);

cart.ValidateOrRemoveLineItems(null); // Validates the line items and removes from the cart if they are invalid.
cart.UpdatePlacedPriceOrRemoveLineItems(null); // Updates all of the line item placed prices for the specified cart or removes the line item if their is no valid price.
cart.UpdateInventoryOrRemoveLineItems(null); // Updates the inventory for var or removes the line item if no available inventory

var cartLink = orderRepository.Save(cart);

This is no-workflow process and could be used for replacing Cart validate workflow.

Cart Prepare - applying promotion

We could apply promotion discount - those discount were defined in new promotion system.


// Apply promotion
var promotionEngine = ServiceLocator.Current.GetInstance();
var rewardDescriptions = cart.ApplyDiscounts(promotionEngine, new PromotionEngineSettings());
var orderRepository = ServiceLocator.Current.GetInstance();
var orderRepository = ServiceLocator.Current.GetInstance();
var customerId = Guid.NewGuid();
var cart = orderRepository.LoadOrCreateCart(customerId, "DefaultName");

var lineItem = cart.CreateLineItem("entry code you want to add (SKU-24064191 for example)");
lineItem.Quantity = 1;
lineItem.PlacedPrice = 100;

cart.AddLineItem(lineItem);

cart.ValidateOrRemoveLineItems(null); 
cart.UpdatePlacedPriceOrRemoveLineItems(null); 
cart.UpdateInventoryOrRemoveLineItems(null);

// Apply promotion
var promotionEngine = ServiceLocator.Current.GetInstance();
var rewardDescriptions = cart.ApplyDiscounts(promotionEngine, new PromotionEngineSettings());

var cartLink = orderRepository.Save(cart);

After those code, the promotions will apply cart and cart will be re-calculated. This could be used for replacing CartPrepare workflow.

So creating cart task was finished after applying promotion.

In this sample, we’re using abstraction to create a cart, we don’t use any workflow to validate lineitem or calculate discount like old way. You could read more information in document I mention before or you could see this on latest Quicksilver sample site.

Creating a bundle of carts

Next, we focus on creating more than 1 cart -  just simple cart – and make an UI to define how many carts, how many shipments for each cart and how many lineitem for each shipment like this:

creating cart UI

 

Step 1: we use Quicksilver sample site for this example. So first of all, clone or download Quicksilver from: https://github.com/episerver/Quicksilver

Step 2: Creating simple page type and adding controller, UI for this page:

- Creating page type: in Features folder, create a folder Generator. Then adding a class, we name it as GeneratorPage.cs

[ContentType(DisplayName = "Generator page", GUID = "43000bdf-731c-47d2-ae46-001df01dd678", Description = "", AvailableInEditMode = true)]
public class GeneratorPage : PageData
{
    [CultureSpecific]
    [Display(
            Name = "Generator title",
            Description = "Title for the Generator page",
            GroupName = SystemTabNames.Content,
            Order = 1)]
    public virtual string Title { get; set; }
}

- Adding controller for this page type, name it as GeneratorController.cs

public class GeneratorController : PageController<GeneratorPage>
{
    private IOrderRepository _orderRepository;        
    const string _defaultName = "Default";
    // Those variation codes were generated from our variation content.
    private IList<string> _listOfEntryCodes = new List<string> { "SKU-40797394", "SKU-40797396", "SKU-40797399", "SKU-40797402", "SKU-40797405", "SKU-40797409", "SKU-40797413", "SKU-40797417", "SKU-40797420", "SKU-40797423","SKU-40797426","SKU-40707713","SKU-40707735","SKU-40707740","SKU-40707746","SKU-40800952","SKU-40707751","SKU-40707717","SKU-40707721","SKU-40707730","SKU-40801260","SKU-40707703","SKU-41136685","SKU-41136683","SKU-41136682",
"SKU-41136681","SKU-41136684","SKU-41136726","SKU-41136690","SKU-41136688","SKU-41136687","SKU-41136686","SKU-41136689","SKU-42313640","SKU-42313641","SKU-42313642","SKU-42313643","SKU-42313644","SKU-42313635","SKU-42313636","SKU-42313637","SKU-42313638","SKU-42313639","SKU-42313650","SKU-43093280","SKU-43093282","SKU-43093281","SKU-43093283","SKU-43093284","SKU-40835688","SKU-42340084","SKU-42340065","SKU-42340072","SKU-42340074","SKU-42340076",
"SKU-42340078","SKU-42340080","SKU-42340066","SKU-42340067","SKU-42340069","SKU-42340070","SKU-38424528","SKU-38424545","SKU-38424534","SKU-38424537","SKU-38424552","SKU-40707729","SKU-40707701","SKU-40707709","SKU-40707712","SKU-40707716","SKU-40707722","SKU-40707749","SKU-40707754","SKU-40707758","SKU-40707763","SKU-40707768","SKU-40707883","SKU-40707863","SKU-40707865","SKU-40707868","SKU-40707872","SKU-40707876","SKU-40707823","SKU-40707827" }; 

    public GeneratorController(IOrderRepository orderRepository)
    {
        _orderRepository = orderRepository;
    }

    public ViewResult Index()
    { 

        return View();
    }

    [HttpPost]
    public ViewResult Index(FormCollection collection)
    {
        var numberOfCart = string.IsNullOrEmpty(collection["numberOfCart"]) ? 1 : int.Parse(collection["numberOfCart"]);
        var numberOfShipment = string.IsNullOrEmpty(collection["numberOfShipment"]) ? 1 : int.Parse(collection["numberOfShipment"]);
        var numberOfItem = string.IsNullOrEmpty(collection["numberOfItem"]) ? 1 : int.Parse(collection["numberOfItem"]);

        CreateCart(numberOfCart, numberOfShipment, numberOfItem);
        ViewBag.Message = $"{numberOfCart} carts were created!";
        return View();
    }

    private void CreateCart(int numberOfCart, int numberOfShipment, int numberOfItem)
    {
        for (var k = 1; k <= numberOfCart; k++)
        {
            var cart = _orderRepository.LoadOrCreateCart<ICart>(Guid.NewGuid(), _defaultName);

            for (var j = 1; j <= numberOfShipment; j++)
            {
                var shipment = cart.GetFirstShipment();
                if (j > 1)
                {
                    shipment = cart.CreateShipment();
                    cart.AddShipment(shipment);
                }                

                for (var i = 1; i <= numberOfItem; i++)
                {
                    // Adding random entry to cart
                    var entryCode = _listOfEntryCodes.OrderBy(s => Guid.NewGuid()).First();
                    do
                    {
                        entryCode = _listOfEntryCodes.OrderBy(s => Guid.NewGuid()).First();
                    } while (cart.GetAllLineItems().Any(l => l.Code == entryCode));

                    var lineItem = cart.CreateLineItem(entryCode);
                    lineItem.Quantity = 1;
                    lineItem.PlacedPrice = 100;
                    shipment.LineItems.Add(lineItem);
                }
            }

            _orderRepository.Save(cart);
        }
    }
}

- Adding view to this controller (Index.cshtml):

<h1 class="text-center">Cart generator</h1>
@using (Html.BeginForm(null, null, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    <div class="form-group">
        <label for="numberOfCart" class="col-sm-3 control-label">Number of cart:</label>
        <div class="col-sm-9">
            <input type="text" class="form-control text-right" id="numberOfCart" name="numberOfCart" placeholder="Number of cart" value="1">
        </div>
    </div>
    <div class="form-group">
        <label for="numberOfShipment" class="col-sm-3 control-label">Number of shipment (each cart)</label>
        <div class="col-sm-3">
            <input type="text" class="form-control text-right" id="numberOfShipment" name="numberOfShipment" placeholder="Number of shipment for each cart" value="1">
        </div>
        <label for="numberOfItem" class="col-sm-3 control-label">Number of lineitem (each shipment)</label>
        <div class="col-sm-3">
            <input type="text" class="form-control text-right" id="numberOfItem" name="numberOfItem" placeholder="Number of lineitem for each shipment" value="2">
        </div>
    </div>  
    <div class="form-group">
        <div class="col-sm-12">
            <button type="submit" class="btn btn-primary btn-lg btn-block">Generate</button>
        </div>
    </div>
}
@if (ViewBag.Message != null)
{ 
<div class="alert alert-success alert-dismissible" role="alert">
    <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
    @ViewBag.Message
</div>
}

Step 3: Adding this page to our site

new page

generate cart UI

Step 4: we need to make sure that our variants have enough in stock quality  then we ready to generate a lot of carts :)

generate cart UI

DONE :)

This sample will help us creating cart data for testing, you could do step by step in this post or get it from my github.

 

Hope this could help your task.

/Son Do

Dec 27, 2016

Comments

Dec 27, 2016 10:28 AM

Well done Son, i'll try :)

Please login to comment.
Latest blogs
Optimizely Frontend Hosting Beta – Early Thoughts and Key Questions

Optimizely has opened the waitlist for its new Frontend Hosting capability. I’m part of the beta programme, but my invite isn’t due until May, whil...

Minesh Shah (Netcel) | Apr 23, 2025

Developer Meetup - London, 21st May 2025

The London Dev Meetup has been rescheduled for Wednesday, 21st May and will be Candyspace 's first Optimizely Developer Meetup, and the first one...

Gavin_M | Apr 22, 2025

Frontend hosting for PaaS & SaaS CMS

Just announced on the DXP, we FINALLY have a front end hosting solution coming as part of the DXP for modern decoupled solutions in both the PaaS a...

Scott Reed | Apr 22, 2025

Routing to a page in SaaS CMS

More early findings from using a SaaS CMS instance; setting up Graph queries that works for both visitor pageviews and editor previews.

Johan Kronberg | Apr 14, 2025 |

Developer Meetup - London, 24th April 2025

Next Thursday, 24th April will be Candyspace 's first Optimizely Developer Meetup, and the first one held in London this year! We've have some...

Gavin_M | Apr 14, 2025

Successful Digitalization for SMEs: How Optimizely One can Revolutionize Your Business Processes

"Achieve digital excellence with Optimizely One: Boost efficiency, delight customers, secure growth." In today's digital world, it's crucial for...

Frank Hohmeyer | Apr 11, 2025