A Warning About Shipping Costs after Item Changes - Checkout API

Call estimateShipping asynchronously. It queries all the major shippers (UPS, FedEx, USPS, etc) live. That takes time!

Important: Any update/insert/delete of items in a cart will cause the cart to retain the cart.shippingMethod, but zero out cart.shippingHandling, cart.shippingHandlingDiscount, cart.shippingHandlingWithDiscount.

Ouch. It's a fright to see a shipping method of "International" with a cost of $0.00.
However, this is a security precaution. The shipping costs are re-calcuated at checkout to prevent any fraud or mischief. So the zeroing out does NOT affect the final transaction. However, if you display shipping in your checkout summary using cart.shippingHandlingWithDiscount, it could display incorrectly after any of the aforementioned cart item changes.

Don't use cart.shippingHandlingWithDiscount.

Here's the steps you should take to show a summary of cart costs:
1. Look at the cart.shippingMethod. If it's populated, that's the selected shipping method.
2. Then, once you get the shippingMethods back (hopefully asynchronously), update your cart summary html by looping through
the shipping methods, looking for a match. When a match is found, use the shippingMethod.cost as your shipping cost.

Here's a javascript method that updates a summary div. It uses the checkoutapi-2.X, so a convenience method getShippingChoice is called to find the selected ShippingMethod object.

Also, be aware that some states charge tax on shipping. Yes, that's crazy, but it happens. So be sure to check the shippingMethod to see if there's shipping tax. If so, add that to your tax total.

Below is an example from the Online Cart Demo located in the Integration Center of the Merchant Portal.

Given the following html:

  <div id="summaryContainer">
    <div id='summaryHeader' class='colorSubHeader'>SUMMARY</div>
    <div id='summarySubtotal'></div>
    <div id='summaryTax'></div>
    <div id='summaryShipping'></div>
    <div id='summaryTotal'></div>
  </div>

Here's the javascript (checkout v2.X) that updates it.

/**
 * updates the summary block showing subtotal, tax, shipping, and total
 */
function renderSummary(){
  var c = ultraCart.getCart();
  if(c.items.length == 0){
    jQuery('#summaryContainer').hide();
    return;
  } else {
    jQuery('#summaryContainer').show();
  }

  // shipping must be dealt with specially.  to prevent customers from gaming the system, there are several instances
  // where the price of shipping is reset.  So, when rendering, always lookup the shipping method and calculate the cost
  // from that rather than using the cart.shippingHandlingWithDiscount, although the latter would be simpler

  var totalTax = c.tax;
  var shippingTotal = '&nbsp;'; // don't display anything if there's no choice
  var total = c.subtotalWithDiscount + c.tax;

  var shippingChoice = ultraCart.getShippingChoice();
  if(shippingChoice){
    totalTax += shippingChoice.tax;
    if(shippingChoice.cost == 0){
      shippingTotal = '<strong>FREE Shipping!</strong>';
    } else {
      shippingTotal = nf.toCurrency(shippingChoice.cost);
    }
    total += shippingChoice.cost;
    total += shippingChoice.tax;
  }



  jQuery('#summarySubtotal').html("<div class='summaryLabel'>Subtotal:<\/div><div class='summaryField'>" + nf.toCurrency(c.subtotalWithDiscount) + "<\/div>");
  jQuery('#summaryTax').html("<div class='summaryLabel'>Tax:<\/div><div class='summaryField'>" + (totalTax == 0 ? "<span class='tax'>No Sales Tax!</span>" : nf.toCurrency(totalTax)) + "<\/div>");
  jQuery('#summaryShipping').html("<div class='summaryLabel'>Shipping:<\/div><div class='summaryField'>" + shippingTotal + "<\/div>");
  jQuery('#summaryTotal').html("<div class='summaryLabel'>Total:<\/div><div class='summaryField'>" + nf.toCurrency(total) + "<\/div>");
}