Developer forum

Forum » Development » Custom Shipping provider not firing

Custom Shipping provider not firing

Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Hi there,

I have the following ShippingProvider:

  [AddInName("Fee Provider"), AddInDescription("Calls in the ERP to get the fee.")]
  public class ServiceShippingFeeProvider : ShippingProvider, IDropDownOptions
  { 
   public ServiceShippingFeeProvider()
    {
      Logger.Trace("Constructed new instance of ServiceShippingFeeProvider.");
    }

    public override PriceRaw CalculateShippingFee(Order order)
    {
      Logger.Trace("Calling CalculateShippingFee.");
      ... Implementation here
    }
  }

When I run this, my log file shows this:

2015-02-05 13:34:05.0296 Web.Providers.ServiceShippingFeeProvider..ctor Trace Constructed new instance of ServiceShippingFeeProvider.
2015-02-05 13:34:05.0296 Web.Providers.ServiceShippingFeeProvider..ctor Trace Constructed new instance of ServiceShippingFeeProvider.
2015-02-05 13:34:05.0296 Web.Providers.ServiceShippingFeeProvider..ctor Trace Constructed new instance of ServiceShippingFeeProvider.
2015-02-05 13:34:05.0426 Web.Providers.ServiceShippingFeeProvider..ctor Trace Constructed new instance of ServiceShippingFeeProvider.


To summarize: my provider is instantiated and I can see it in the frontend along with other providers for the selected country.

However, CalculateShippingFee is never called and I see zero as the price.

Did something change again in Dynamicweb? Something in the MC I need to turn on or off? Running on 8.5.1.14.

Imar


Replies

 
Nicolai Høeg Pedersen
Reply

Just to clarify, is it a provider that used to work, but does not anymore?

 

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Yes, correct. It runs in production on 8.4.1.19 but I can't get it to work on my local machine with a later version.

Downgrading to the same version now locally to see if that makes a differnece.

Imar

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Just downgraded to 8.4.1.19 and now it works locally as well.

Imar

 
Nicolai Høeg Pedersen
Reply

Hm, I have asked QA to test (and fix) this.

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Bump. Any news on why the shipping provider isn't being called?

Imar

 
Dmitry Nikolenko
Reply

Hi Imar,

I have checked on my 8.5.1 solution and all works fine. Do you enable your provider for your country of the site (tab "Country fees")?

Also check settings in Management Center -> Ecommerce -> Internationalization -> Countries -> Default methods

 

[AddInName("MySuperShipping Provider"), AddInDescription("Yiiiii")]
    public class MySuperShipping : ShippingProvider, IDropDownOptions
    {
        [AddInParameter("Param1"), AddInParameterEditor(typeof(TextParameterEditor), "size=80")]
        public string Param1 { get; set; }

        public MySuperShipping()
        {
            Param1 = string.Empty;
        }

        public override Prices.PriceRaw CalculateShippingFee(Dynamicweb.eCommerce.Orders.Order order)
        {
            return new Prices.PriceRaw(24, new eCommerce.International.Currency("USD"));
        }

        public System.Collections.Hashtable GetOptions(string Name)
        {
            throw new NotImplementedException();
        }
    }

 

 
Imar Spaanjaars Dynamicweb Employee
Imar Spaanjaars
Reply

Hi Dmitry,

I checked it again on 8.6 today and it works. Must have been a glitch in the 8.5.x version I tried it on.

Thanks,

Imar

 
Unnsteinn Garðarsson
Unnsteinn Garðarsson
Reply

I realize that this is an old post but is there any documentation about how one creates a custom shipping provider?

 
Nicolai Pedersen
Reply

Hi Unnsteinn

It is not super documented - you need to inherit this class: https://doc.dynamicweb.com/api/html/c4a97b73-c382-6e80-e88a-2d2afea35c64.htm

Please find attached all our shipping provider projects to see how they work.

BR Nicolai

 
Unnsteinn Garðarsson
Unnsteinn Garðarsson
Reply

Thank you for the quick answer, I had already begun decompiling the Shipping providers but the original classes are a way better reference.

However I have one question, what I want is to create a Shipping Provider that will fetch a list of parcel lockers through an API and I want to be able to loop through these parcel lockers in my cart information step and display them to the user. I have tried to implement the RenderFrontend and ProcessOrder methods but they are never executed in my case.

Can you point me in the right direction on how to tackle this?

Unnsteinn

 
Nicolai Pedersen
Reply

That is what our own GLS and other shipping providers do.

You need to set up a shipping method with your provider on it. Then you have to have cart where your shipping method is chosen. Then it should show up in a loop.

If that is not it, we need to see some screendumps and some code.

BR Nicolai

 
Unnsteinn Garðarsson
Unnsteinn Garðarsson
Reply

Just to clarify, are you referring to the Shippingmethods loop? If so, then I have access to the name and description of the shipping method there but what I need is data fetched by the provider.

Here is the code I have with explanation about what I want from it. I am not sure which method I need to implement in order to achieve this.

 

using System.Collections.Generic;
using Dynamicweb.Ecommerce.Cart;
using Dynamicweb.Ecommerce.Orders;
using Dynamicweb.Extensibility.AddIns;
using Dynamicweb.Extensibility.Editors;

namespace Dynamicweb.eCommerce.LiveIntegration
{
    [AddInName("Posturinn Postboxes")]
    [AddInDescription("All postboxes provided by Posturinn")]
    public class PostboxesShippingProvider : ShippingProvider
    {
        public PostboxesShippingProvider() 
        { 
            List <Postbox> postboxes = new List<Postbox>();
            postboxes = getPostboxesFromExternalAPI();
            // I want to have access to these postboxes in the cart information template tags somehow
        }

        private class Postbox
        {
            public string postboxId;
            public string name;
            public string address;
            public string postcode;
            public string town;

            public Postbox(string postboxId, string name, string address, string postcode, string town)
            {
                this.postboxId = postboxId;
                this.name = name;
                this.address = address;
                this.postcode = postcode;
                this.town = town;
            }

            public string Latitude { get; set; }
            
            public string Longitude { get; set; }
        }
    }
}
 
Nicolai Pedersen
Reply

If you have a look in the GLS provider.

Then make an override of the RenderFrontend:

 public override string RenderFrontend(Order order)

In the GLS provider, it loads a template and fill that up with data of dropboxes (A list of your Postbox'es) and then return template.output which is the rendered shipping methods.

That string is coming out in your cart templates in the tag for that (cannot remember its name :-))

BR Nicolai

 
Unnsteinn Garðarsson
Unnsteinn Garðarsson
Reply

I did try to create a shipping method using the GLS provider to see if I could access the values in the frontend but that was not successfull either. What I did was.

1. Create the shipping method (see image GLS-shipping-provider)
2. Add it to the shipping methods of my cart app (see image selected-shipping-methods)
3. Access it in the front end, the loop renders the name of the shipping method but there is no content, and when I read the documentation this is the correct tag 
https://doc.dynamicweb.com/documentation-9/how-tos/shipping-providers/gls-shopdelivery

What I do notice is that when I implement the RenderFrontend method in my custom shipping provider and place a breakpoint there, it is never executed.

Also I cannot output the Template Tags because as soon as I try to do it I get the following stack trace.

System.NullReferenceException: Object reference not set to an instance of an object. at Dynamicweb.Ecommerce.Products.ProductService.ReFactorProductList(ICollection`1 products, Currency currency, Country country, StockLocation stockLocation, User user, Boolean useAssortments) at Dynamicweb.Ecommerce.Products.ProductService.GetRelatedCountFrontend(Product product, Currency currency, Country country, StockLocation stockLocation, User user) at Dynamicweb.Ecommerce.Frontend.Renderer.GetRelatedCount(Product product, Boolean isFrontend, RenderingContext renderingContext) at Dynamicweb.Ecommerce.Frontend.Renderer.RenderProduct(Product product, Boolean extendedProperties, Template template, Int32 loopCounter, Boolean renderRelated, String productUrl, Int32 quantity, Int32 wishListId, Boolean renderPublicList, Boolean isRecursiveCall, Lazy`1 categoryFieldSorting, Int32 orderLineOfProductCount, RenderingContext renderingContext, String unitId) at Dynamicweb.Ecommerce.Frontend.Renderer.RenderProducts(ProductCollection products, Template parentTemplate, String loopName, Int32 loopCounter, Boolean renderRelatedProducts, Boolean renderRelatedLists, Boolean isRecursive, RenderingContext renderingContext) at Dynamicweb.Ecommerce.Frontend.Renderer.RenderRelatedProductLists(Template template, RelatedProductListProviderEventArgs relatedParams, Boolean isCalledInsideRecursion, ExecutionTable currentExecutionTable) at Dynamicweb.Ecommerce.Frontend.Renderer.RenderProduct(Product product, Boolean extendedProperties, Template template, Int32 loopCounter, Boolean renderRelated, String productUrl, Int32 quantity, Int32 wishListId, Boolean renderPublicList, Boolean isRecursiveCall, Lazy`1 categoryFieldSorting, Int32 orderLineOfProductCount, RenderingContext renderingContext, String unitId) at Dynamicweb.Ecommerce.Frontend.Renderer.RenderOrderLine(OrderLine orderLine, Template template) at Dynamicweb.Ecommerce.Frontend.Renderer.RenderOrderLines(OrderLineCollection orderLines, Template parentTemplate, String loopName) at Dynamicweb.Ecommerce.Frontend.Renderer.RenderOrderDetails(Template template, Order order, Boolean extendedProperties, OrderTemplateExtenderContext orderContext) at Dynamicweb.Ecommerce.Cart.Renderer.RenderStep(Order order, PageView pageView, IEnumerable`1 validationErrors, IEnumerable`1 removedProductNames, Boolean useNewsletterSubscription, String imagePatternProductCatalog, Boolean selectAllPayments, IEnumerable`1 payments, Boolean selectAllDeliveries, IEnumerable`1 deliveries, Template template) at Dynamicweb.Ecommerce.Cart.Renderer.RenderStep(Order order, ModuleSettings settings, Int32 stepIndex, PageView pageView, IEnumerable`1 validationErrors, IEnumerable`1 removedProductNames) at Dynamicweb.Ecommerce.Cart.Frontend.RenderStep(Order order, Int32 stepIndex, IEnumerable`1 removedProductNames, IEnumerable`1 errors) at Dynamicweb.Ecommerce.Cart.Frontend.GetContent()

 

The Foreach loop in the cart information template

    @foreach (LoopItem item in GetLoop("Shippingmethods"))
    {
        <span>@item.GetString("Ecom:Cart.Shippingmethod.Name")</span>
        <span>@item.GetString("Ecom:ShippingProvider.Content")</span> <br/>
    }

GLS-shipping-provider.PNG selected-shipping-methods.PNG
 
Nicolai Pedersen
Reply
This post has been marked as an answer

In the cart template you will have a tag called Ecom:ShippingProvider.Content - it is not a loop.

It will contain the output from the shipping provider - the provider will load its own template file.

As an alternative you can override the Render method instead of RenderFrontend method. The Render method takes a template instance and an order as arguments. You can then add the loop to that template instance and that will give you a loop of droppoints in the cart template instead of the shipping provider template...

Votes for this answer: 1
 
Unnsteinn Garðarsson
Unnsteinn Garðarsson
Reply

This is exactly what I wanted! Thank you for the answer smiley As you notice I am kind of new here so explicit explanations are a bit necessary 

 

You must be logged in to post in the forum