Custom Shipping Provider - Order and Shipping totals do not update

Chris Isom asked on October 29, 2015 17:51

After following the directions here:
https://docs.kentico.com/display/K82/Implementing+custom+shipping+carrier+providers
and reviewing and implementing the source code here:
http://devnet.kentico.com/articles/webinar-recap-adding-real-time-shipping-rates-to-kentico

The order total and shipping total does not update from the returned price from shipping provider's GetPrice(Delivery delivery, string currencyCode) method.

The shipping and payment stage of checkout shows the correct drop down of the 3 UPS service selections. During debug, I can follow the code when it hits the provider below, and it returns 3 prices upon showing the shipping service dropdown and returns a single price after selecting a specific service while proceeding to the next page. All the values returned from the UPS call are above $0.00 yet, the order and shipping totals do not update.

There are no service or carrier configurations in the CMS so we return Guid.Empty.

The site was originally at 8.2 and was updated to 8.2.43 to address this issue, but the problem remains. Any assistance would be appreciated.

UPSRealTimeShippingProvider.cs

using System;
using System.Collections.Generic;
using System.Web;
using System.Linq;
using System.Text;
using CMS;
using CMS.Ecommerce;
using CMS.CustomTables;
using CMS.DataEngine;
using DotNetShipping;
using System.Collections.Specialized;
using System.Configuration;
using CMS.DocumentEngine;

[assembly: RegisterCustomClass("UPSRealTimeShippingProvider", typeof(UPSRealTimeShippingProvider))]
public sealed class UPSRealTimeShippingProvider : ICarrierProvider
{
    private const string NAME = "UPS Shipping";
    private List<KeyValuePair<string, string>> mServices;

    public string CarrierProviderName
    {
        get { return NAME; }
    }

    public List<KeyValuePair<string, string>> GetServices()
    {
        //new KeyValuePair<string, string>("Standard", "UPS Real-Time Calculated"),
        return mServices ?? (mServices = new List<KeyValuePair<string, string>>
        {
            new KeyValuePair<string,string>("UPS Next Day Air", "UPS Next Day Air"),
            new KeyValuePair<string,string>("UPS 2nd Day Air", "UPS 2nd Day Air"),
            new KeyValuePair<string,string>("UPS Ground", "UPS Ground")

        });
    }

    /// <summary>
    /// Calculates the shipping cost of the given delivery.
    /// </summary>
    /// <param name="delivery">The shipped delivery.</param>
    /// <param name="currencyCode">The code of the currency in which the shipping price should be calculated (e.g. USD or EUR).</param>
    /// <returns>The price in the currency specified by currencyCode.</returns>
    public decimal GetPrice(Delivery delivery, string currencyCode)
    {
        decimal deliveryPrice = 0;

        NameValueCollection appSettings = ConfigurationManager.AppSettings;
        string upsLicenseNumber = appSettings["UPSLicenseNumber"];
        string upsLogin = appSettings["UPSUserId"];
        string upsPassword = appSettings["UPSPassword"];
        string upsOriginZipCode = appSettings["UPSOriginZipCode"];

        //Delivery has total weight, but we need it broken up
        //Must add unit weight and boxes for each different item

        CMS.DataEngine.ObjectQuery<CustomTableItem> cti = CustomTableItemProvider.GetItems("CCI.Boxes");
        List<Package> packages = new List<Package>();
        foreach (DeliveryItem item in delivery.Items)
        {
            var prod = DocumentHelper.GetDocuments("CCI.Product")
                                    .WhereLike("SKUNumber", "%" + item.Product.SKUNumber +"%").FirstOrDefault();

            //get box size
            CustomTableItem BoxSize = (from x in cti.AsEnumerable()
                        where x.ItemID == prod.GetIntegerValue("BoxSize",0)
                        select x).FirstOrDefault();


            if (BoxSize != null)
            {
                //box info
                decimal width = Convert.ToDecimal(BoxSize.GetValue<float>("Width",0f));
                decimal height = Convert.ToDecimal(BoxSize.GetValue<float>("Height", 0f));
                decimal length = Convert.ToDecimal(BoxSize.GetValue<float>("Length", 0f));
                decimal boxweight = Convert.ToDecimal(BoxSize.GetValue<float>("Weight", 0f));
                //get DeliveryItem qty
                decimal orderQty = item.Amount;
                //get product weight
                decimal itemWeight = Convert.ToDecimal(prod.GetValue<float>("ItemWeight", 0f));
                //get items per box
                int itemsPerBox = prod.GetIntegerValue("ItemsPerBox", 0);
                //add all packages
                for (int i = Convert.ToInt32(orderQty); i > 0; )
                {
                    int productInBox = itemsPerBox < i ? itemsPerBox : i;
                    //min weight of 2 
                    decimal totalWeight = (productInBox * itemWeight) + boxweight > 2 ?  (productInBox * itemWeight) + boxweight : 2;
                    packages.Add(new Package(length, width, height, totalWeight, 0));
                    i = i - itemsPerBox;
                }
            }
        }
        //pass to service
        if (packages.Count > 0 && delivery.ShippingOption.ShippingOptionCarrierServiceName.Contains("UPS"))
        {
            Address origin = new Address("", "", upsOriginZipCode, "US");
            Address destination = new Address("", "", delivery.DeliveryAddress.AddressZip, "US");
            RateManager rm = new RateManager();
            rm.AddProvider(new DotNetShipping.ShippingProviders.UPSProvider(upsLicenseNumber, upsLogin, upsPassword, delivery.ShippingOption.ShippingOptionCarrierServiceName));
            Shipment shipment = rm.GetRates(origin, destination, packages);
            deliveryPrice = shipment.Rates.FirstOrDefault() != null ? shipment.Rates.First().TotalCharges : 0;
        }

        return deliveryPrice;
    }

    /// <summary>
    /// Checks whether the shipping option is available for the specified shipping address.
    /// The only supported shipping addresses are to USA, Canada or Mexico.
    /// </summary>
    /// <param name="delivery">The shipped delivery.</param>
    public bool CanDeliver(Delivery delivery)
    {
        return true;
    }

    /// <summary>
    /// Returns Guid.Empty. This carrier does not have or need any configuration tab.
    /// </summary>
    public Guid GetConfigurationUIElementGUID()
    {
        return Guid.Empty;
    }

    /// <summary>
    /// Returns Guid.Empty. Service configuration is not required.
    /// </summary>
    /// <param name="serviceName">Service name.</param>
    public Guid GetServiceConfigurationUIElementGUID(string serviceName)
    {
        return Guid.Empty;
    }
}

Correct Answer

Chris Isom answered on November 10, 2015 15:15

Thanks for the help from Kentico support, as they pointed out the code is fine, but the sample e-commerce setup data needs to be updated to remove/disable the special offers of "Free shipping to US and Canada".

0 votesVote for this answer Unmark Correct answer

   Please, sign in to be able to submit a new answer.