Developer forum

Forum » Development » Adding product to the cart programmatically

Adding product to the cart programmatically

Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Hi there,

I have the following code to add a product to the cart:

private static void CreateOrderLine(Product product, double quantity, double price)
{
var order = Context.Cart;
  if (product == null)
  { return; }

  var ol = new OrderLine
  {
    Product = product,
    ProductID = product.ID,
    ProductName = product.Name,
    ProductNumber = product.Number,
    ProductVariantID = string.IsNullOrEmpty(product.VariantID) ? product.VirtualVariantID : product.VariantID,
    Quantity = quantity,
    Type = ((int)OrderLine.OrderLineType.Product).ToString(),
    Modified = DateTime.Now,
    Order = order,
    AllowOverridePrices = true
  };

  ol.SetUnitPrice(new PriceInfo { PriceWithVAT = price }, true);
  order.OrderLines.Add(ol);
  order.ClearCachedPrices();
  Context.SetCart(order);
}

The product is added to the cart successfully and the price I am assinging shows up as the line item price.

However, the total of the order remains zero. Is there something I need to do to force the cart to recalculate itself?

 

Thanks,

Imar


Replies

 
Morten Bengtson
Reply

I'm not sure if it works, but have you tried order.ForcePriceRecalculation() ? ;-)

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Yep, tried that too.

It seems the issue is on the line, not the order, as the Unit Price for the line has a value, but the line total does not....

Thanks!

Imar

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply

I believe, this is caused by you setting AllowOverridePrices to true. You don't really need it in this case, and since you don't specify the total price explicitly, the price will be incorrect.

- Jeppe

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

That didn't seem to make a difference. My code now looks like this:

private static void CreateOrderLine(Product product, double quantity, double price)
{
  var order = Context.Cart ?? new Order();

  if (product == null)
  {
    return;
  }

  var ol = new OrderLine
  {
    Product = product,
    ProductID = product.ID,
    ProductName = product.Name,
    ProductNumber = product.Number,
    Quantity = quantity,
    Type = ((int) OrderLine.OrderLineType.Product).ToString(),
  };

  ol.SetUnitPrice(price);
  order.OrderLines.Add(ol);
  order.ClearCachedPrices();
  Context.SetCart(order);
}

When it rus and I then look at the cart, I see something like this:

 

Unit price: 250

Quanity: 1

Total price: 0

Order total price: 0

 

When I increase the quantity through a cart command of incOrderLine, the numbers are correct:

Unit price: 250

Quanity: 2

Total price: 500

Order total price: 500

 

Any other ideas?

Imar

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

BTW: do I always need to call Context.SetCart(order)? Or should that only be done when a new Order instance is created?
 

Imar

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply

You do not need to call Context.SetCart every time, only when you create a new order object and want to set it in the context.

Can you try using the helper method Order.CreateOrderLine() and see if that does the trick? This method adds the OrderLine to the Order object on which the method was invoked as well as return the OrderLine object to you.

- Jeppe

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Same thing. I know have this code:

private void CreateOrderLine(Product product, double quantity, double price)
{
  Order order;
  if (Context.Cart != null)
  {
    order = Context.Cart;
  }
  else
  {
    order = new Order();
    Context.SetCart(order);
  }

  if (product == null)
  {
    return;
  }

  var ol = order.CreateOrderLine(product, quantity);
  product.Price.PriceWithoutVAT = price;  // Tried it with and without this line

  ol.Order = order;
  order.ClearCachedPrices();
}

 

The result is the same: the Unit price is update, the line total is not.

Can I do what I try to do? That is, is this an official way to programmatically add products to the cart?

Thanks!

Imar

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

I added some logging:

 private void CreateOrderLine(Product product, double quantity, double price)
    {
      if (product == null)
      {
        return;
      }

      var order = Context.Cart;

      if (order == null)
      {
        order = new Order();
        Context.SetCart(order);
      }

      var ol = order.CreateOrderLine(product, quantity);
      ol.SetUnitPrice(price);

      Logger.Trace(String.Format("In CreateOrderLine ol.Price.Price: {0}", ol.Price.Price));
      Logger.Trace(String.Format("In CreateOrderLine ol.UnitPrice.Price: {0}", ol.UnitPrice.Price));

      ol.Order = order;

      order.ClearCachedPrices();

      Logger.Trace(String.Format("In CreateOrderLine after clear ol.Price.Price: {0}", ol.Price.Price));
      Logger.Trace(String.Format("In CreateOrderLine after clear ol.UnitPrice.Price: {0}", ol.UnitPrice.Price));

    }

which gives me this:

In CreateOrderLine ol.Price.Price: 0
In CreateOrderLine ol.UnitPrice.Price: 350
In CreateOrderLine after clear ol.Price.Price: 0
In CreateOrderLine after clear ol.UnitPrice.Price: 350

Shouldn't the price be updated here?

Imar

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

With the following code:

var ol = order.CreateOrderLine(product, quantity);
var priceInfo = new PriceInfo();
priceInfo.PriceWithVAT = price;
priceInfo.PriceWithoutVAT = price;
priceInfo.VAT = 0;
ol.SetUnitPrice(priceInfo, true);

I can make it somewhat work. The unit price and total price now get a value. However, the order total is still zero. Additionally, when I increase the quantity of the product using a cart command, the price for the product defaults back to the price specified in the backend. Isn't the order line price supposed to stick?

Imar

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply

A few points. You do not need to set OrderLine.Order explicitly, that is handled by CreateOrderLine. Also, setting the price of the Product after CreateOrderLine is not going to work. The method will set the unit price so you need to either pass in the unit price as a PriceInfo or change the product price before invoking CreateOrderLine.

Here is a minor alteration to the last four lines of code that gives you better control over the price:

var p = new PriceInfo();
p.PriceWithoutVAT = price;
p.PriceWithVAT = price * 1.25; //Or whatever VAT percent you need
p.VAT = p.PriceWithVAT - p.PriceWithoutVAT;

var ol = order.CreateOrderLine(product, quantity, null, p);

This is an official way to add product orderlines to a given order through the API, and it is used internally as well.

I've just made a test where I ran your code from a cart notification subscriber, and it worked as expected. The only thing I can think of is that your code is invoked at some point in the process where the change is not picked up in it's entirety, though I cannot think of where that might be. Where is your code executed from?

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply

You could also call OrderLine.ClearCachedPrices() to see if that has an effect, though it shouldn't be necessary.

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Hi Jeppe,

I tried your code, and it still gives me the same result.

I am calling it from the GetContent method of a custom module.However, I don't *have* to. I need to call this whenever I detect an external ID in the query string. An external site redirects the user to a page on my site that then needs to add a product to the cart based on some info in the query string. What's the best way to do this?

Thanks!

Imar

 

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply
This post has been marked as an answer

Just in case other interested parties discover this thread, I just wanted to provide the root of the issue. After an offline talk, Imar and I have discovered that the issue was caused by the Order.IsCart property being set to false. This made Order.Calculate be false, which in turn caused the prices to be incorrect.

Votes for this answer: 1
 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply
This post has been marked as an answer

Yes, the issue was indeed that IsCart was false.

We had code like this:

Context.SetCart(new Order());

incorrectly assuming that an order would default to being a cart. However, it's not, so our calculations didn't stick. Changing the code to something like this:

Context.SetCart(new Order { IsCart = true, LanguageID = Context.LanguageID });

I don't think we need the LanguageID as it defaults to the context's language, but we definitely needed the IsCart property set to true. That change made everything work.

We could then also simplify our code and use the built-in CreateOrderLine method like this:

var ol = cart.CreateOrderLine(product, quantity);
ol.SetUnitPrice(price);

Thanks a lot Jeppe!

Imar

Votes for this answer: 1
 
Remi Muller
Reply

I had a similar problem and used this in the past:

cart.Save();
//this refreshes the cart see topic: http://developer.dynamicweb-cms.com/forum.aspx?PID=48&ThreadID=27975
CartCatch.SaveCart();

Not sure if it applies to your issue.

 

 
Lars Larsen
Reply

Hi,

I am trying almost the same thing, adding a new orderline to an existing order. My code looks like this:

            order.IsCart = true;
            order.Save(); 
            
            Context.SetCart(order);
            var orderline = order.CreateOrderLine(Product.GetProductByID(shippingMethod.NAVProductId), 1);

            var priceinfo = new PriceInfo();
            priceinfo.Currency = Context.Currency;

            var pricecalculated = new PriceCalculated
                                  {
                                      IgnoreRounding = true,
                                      PriceRaw = new PriceRaw(Convert.ToDouble(123), Context.Currency)
                                  };
            orderline.Type = Base.ChkString(Base.ChkNumber(OrderLine.OrderLineType.Fixed))
            orderline.SetUnitPrice(priceinfo.Add(pricecalculated));
            order.ForcePriceRecalculation();
            
            order.IsCart = false;
            order.Save();

The problem is that the orderline unitprice is the only price on my new orderline. I miss the orderline price and orderline total price. What should I do to get those prices on my orderline?

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply

Hi Lars,

If I read your code correctly, you take an Order object that is already upgraded from a cart to an order, and then you add a new orderline to that cart. This is a use-case that we don't guarantee will work, besides, it feel a bit dodgy editing an order that has been approved by the customer.

Also, based on the property containing the product you add, I guess that this is a solution that has live integration. It's very difficult to determine what happens to the order in this scenario.

I'd really recommend you consider doing something where you don't have to manipulate an Order object that has been upgraded to an order state.

I might misunderstand the code, but if you could provider a context for the code, I'd have a better chance of helping you solve the issue.

- Jeppe

 
Lars Larsen
Reply

Hi Jeppe

Yes, I am trying to add an orderline to an existing order, but trying to change the state with the property IsCart=false. The case is that I want to convert the shipping fee to an orderline because the customer wants to have the shipping fee as an orderline in NAV. You're right about the problem having live integration and changing an order in DW when that order is already sent to NAV. I had not thought about that!! What is your recommandation when shipping should be an orderline in NAV? Is that to handle this entirely in NAV?

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply
This post has been marked as an answer

I'd recommend that you put the shipping as an orderline before you go to checkout. That way everything is correct (Dynamicweb and NAV) before the order is approved by the customer and sent to NAV.

If that's not an option, then let NAV handle it.

- Jeppe

Votes for this answer: 1
 
Lars Larsen
Reply

Hi Jeppe 

Thanks for your input :-)

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Wouldn't this be more of a NAV concern? It should be fairly staight forward to convert the shipping fee to an order line in NAV instead of bending Dynamicweb to support that there.

Cheers,

Imar

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply

It would still change the order after the customer approved it. It won't change the price, but I still feel that it's a bit sketchy. While I definitely see your point, I think that it's better to have it be consistant where shipping is an orderline through the whole cart process.

Keep in mind though, this is completely subjective and my personal opinion and not a technical issue.

- Jeppe

 

You must be logged in to post in the forum