Customizing the Shopping Cart and Shipping Behavior

The most common thing to change in the Web Store is likely to be the way Shipping is handled in the Store. The default Web Store ships with a Invoice.CalculateShipping() method that simply returns 0.00. This may actually work for you if you sell products electronically only or you include your shipping prices in your products.

But more likely you'll want to customize this behavior. The shipping calculation occurs in the Invoice.CalculateShipping method which is supposed return a total for the current invoice.

Generally this class will run through each of the LineItems of the invoice and figure out the weight and then figure out what it costs to get the item(s) to the customer.

The CalculateShipping method is called from the InvoiceTotal() method. You should understand that at the time this method is called an invoice may not be actually loaded yet! You should always use the ShipInfo object to perform any shipping calculations as shown in the example below.

So let's look at the example of West Wind which is really simple. Here are the rules:

  • Orders that don't include physical shipping return shipping value of 0.
  • Orders that have any items shipped - usually a CD - incur a shipping cost of $10.
  • International order double the shipping cost so usually this will be $20.

The code to do this looks like this:

public override decimal CalculateShipping() 
	// *** for easier reference
	DataRow InvData = this.DataRow;
	DataRow CustData = this.Customer.DataRow;

	// *** Shipping value to calculate
	decimal Shipping = 0.00M;
	// *** Check if we need to load ShipInfo from the current invoice
	if (this.ShipInfo.UseInvoiceFields) 

	// *** No Shipping items
	if (!this.ShipInfo.ShipToCustomer) 
		return 0.00M;

	// *** No LineItems or invoice is 0
	if ( this.LineItemCount < 1)
		return 0.00M;

	// *** US and Canada orders are $10 shipping
	// *** All others are $20

	decimal Weight = 0;
	if (this.ShipInfo.TotalWeight == 0 && this.ShipInfo.ShipToCustomer)
		// *** Always force the weight to at least 1 pound
		// *** so we get a minimum shipping charge
		Weight = 1; 
		Weight = this.ShipInfo.TotalWeight;

	// *** Check for foreign orders
	bool Foreign = false;
	if (this.ShipInfo.CountryId != "US" && this.ShipInfo.CountryId != "CA")
		Foreign = true;
	// ** Free form shipping calc based on weight - 
	// ** basically charge twice the weight
	if (Weight > 5) 
		Shipping = Weight * 2;
	else if (Weight > 0)
		Shipping = 10;

	if (Foreign) 
		Shipping = Shipping *2;

	return Shipping;

Notice the use of the ShipInfo object. This object is used to pass Shipping information to the invoice and can be used when a physical invoice does not exist yet - for example in the online Web Store when the shopping cart is displayed. When you view an item in the shopping cart and this method is called ShipInfo.UseInvoice is false, but if you view the invoice for the order confirmation or on the Invoice display screen ShipInfo.UseInvoice is true and the values are retrieved from the Invoice and stored in the Invoice object.

After that the ShipInfo object is used to figure out how to calculate the shipping rate.

You should not assume that you have an invoice DataRow object when this method is called! You should rely entirely on the values from the ShipInfo object to provide you this info. If you must you can check the ShipInfo.UseInvoiceFields property - if it is true you know that the current invoice object is indeed loaded.

Your turn

Obviously if your store ships many physical items and supports multiple shippers your shipping calculations will be much more complex. Even though the sample above and the sample store don't use several shippers that information is available to you in the ShipInfo object (the ShipBy field).

If you look at the ShoppingCart form that contains the Shipping entry section you'll see that there are a bunch of fields that are actually hidden that if unhidden will fill the appropriate fields of the ShipInfo structure:

You can add any additional fields you may need to perform the shipping tasks you need. Just make sure you databind the retrieved values (or manually assign them) to the ShipInfo object.

© West Wind Technologies, 1996-2018 • Updated: 12/28/03
Comment or report problem with topic