How to fetch and display discounted shipping price before the shipping method has been selected?

Vote:
 

Hello,

We're currently listing available shipping methods on our checkout page with their base prices next to them, for instance 49 SEK for home delivery.

Now say that we have a promotion with free shipping for carts with a value of 2000 SEK or above. If a customer comes to the checkout page with such a cart we want to show the price 0 SEK instead of the base price 49 next to the option. However I can't figure out a way to get this discounted price this since the home delivery shipping method hasn't been selected yet and therefore the promotion is not valid at that point in time, I guess.

I've looked at Promotions connected to the cart and IPromotionEngine and a couple of other classes in Episerver but can't figure out how to do this. Is there maybe a way to fake that the shipping method has been selected and that way get the discounted price or how do I go about solving this?

Any input is appreciated :-)

/Martin

#182284
Sep 14, 2017 13:20
Vote:
 

That's an interesting question, I don't really have an answer for you, but I will see if we can resolve it at Framework level - i.e. having it as a builtin feature. 

#182288
Sep 14, 2017 15:30
Vote:
 

I don't know the specifics of your project, but I assume you loop through the available shipping methods and display them?

In that case you might try something like this. Haven't tested it though

Assuming you have already apllied the discounts:

public decimal GetSavedAmountForShippingMethod(IEnumerable<RewardDescription> rewards, Guid shippingMethodId)
        {
            IEnumerable<RewardDescription> shippingRewards = rewards.Where(r => r.Promotion is ShippingPromotion);
            RewardDescription rewardDescription = shippingRewards.Where(r => ((ShippingPromotion)r.Promotion).ShippingMethods.Contains(shippingMethodId)).OrderByDescending( r => r.SavedAmount).FirstOrDefault();
            return rewardDescription?.SavedAmount ?? 0;
        }

If you havent applied any discounts yet, you could just evaluate them, without applying them, like this

public IEnumerable<RewardDescription> GetPromotionsForCart(ICart cart)
        {
            IEnumerable<RewardDescription> rewards = _promotionEngine.Run(
                cart,
                new PromotionEngineSettings()
                    {
                        ApplyReward = false,
                        RequestedStatuses = RequestFulfillmentStatus.Fulfilled
                    });

            return rewards;
        }

When looping through the shipping methods get the saved amount for the shipping method base on the applied discounts and subtract it from the amount of the shippingrate you are probably displaying.

#182303
Sep 14, 2017 18:43
Vote:
 

Tried your two approaches Jeroen but can't seem to get the correct price, they only give me the saved amount after the home delivery shipping option, which is connected to the promotion, has been selected, not before that happens which is what we're trying to achieve. 

BTW, forgot to mention that we're currently running Commerce 10.0.2 if that makes any difference. 

#182340
Sep 15, 2017 14:08
Vote:
 

I tried it in Quicksilver and I get the saved amount back from the method. which with free shipping is the same as the shipping costs. I tried it with the get free shipping when you spend above a certain amount. In that case the promotion conditions are already fulfilled when you get to the checkout page.

So maybe the conditions for your promotion have not been met at the point of checking?

#182385
Sep 17, 2017 21:04
Vote:
 

Sorry about late reply to this thread. I've now also tried this in Quicksilver and kind of get it to work but not in a fully functional way. First of all I still only get it to work when a shipment has a shippingmethod id connected to it, otherwise I get no rewards back as fulfilled. If you've managed to get this to work without having a shipping method selected I'd really appreciate if you can send me a hint to how and where you've changed the code in Quicksilver.

Also, if you have three shipping methods available, like in Quicksilver, costing 20, 10 and 5 USD and you have a promotion saying 10 USD of when you buy certain items. When the 20 and 10 USD shipping methods are selected the SavedAmount states 10 USD but when selecting the 5 USD choice the SavedAmount says 5 USD. UnitDiscount says 10 USD so I guess I have to take it from there and make some sort of calculation based on UnitDiscount and Percentage depending on the type of promotion of my own, if not Quan makes it a part of the framework any time soon :-) 

#182662
Sep 27, 2017 13:51
Vote:
 

Late update to this forum thread but since I just saw a similar question in another thread I thought I'd add our solution to this problem as of now at least. This is how we solved it when fetching information about all available ShippingMethods:

private IEnumerable<ShippingMethodViewModel> GetShippingMethods(IEnumerable<ShippingRate> shippingRates, ICart cart)
    {
      var shippingMethods = shippingRates.Select(r => new ShippingMethodViewModel
      {
        Id = r.Id,
        DisplayName = r.Name,
        Description = r.ShippingMethodDescription,
        ShippingMethodName = r.ShippingMethodName,
        IconClass = GetShippingIconString(r.ShippingMethodName),
        Price = r.Money,
        ReducedPrice = GetReducedShippingMethodPrice(r.Id, cart, r.Money)
      });
      return shippingMethods;
    }

private Money? GetReducedShippingMethodPrice(Guid shippingMethodId, ICart cart, Money basePrice)
    {
      if (_shippingPromotions == null)
      {
        _shippingPromotions = new List<ShippingPromotion>();
        //Check if promotion has been added for current shipping method and apply promotion price
        var campaigns = _contentLoader.GetChildren<SalesCampaign>(SalesCampaignFolder.CampaignRoot).ToList();

        foreach (var salesCampaign in campaigns)
        {
          if (!salesCampaign.IsActive)
          {
            continue;
          }
          var promotions = _contentLoader.GetChildren<ShippingPromotion>(salesCampaign.ContentLink);
          _shippingPromotions.AddRange(promotions.Where(promotion => promotion.IsActive && promotion.DiscountType == DiscountType.Shipping));
        }
      }

      if (!_shippingPromotions.Any())
      {
        return null;
      }

      var shippingMethodInPromotions = _shippingPromotions.Where(sh => sh.ShippingMethods.Contains(shippingMethodId));
      if (!shippingMethodInPromotions.Any())
      {
        return null;
      }

      var originalShippingMethodId = cart.GetFirstShipment().ShippingMethodId;
      cart.GetFirstShipment().ShippingMethodId = shippingMethodId;

      var rewards = _promotionEngine.Run(cart, new PromotionEngineSettings
      {
        ApplyReward = false
      }).ToList();

      cart.GetFirstShipment().ShippingMethodId = originalShippingMethodId;
      var shippingRewards = rewards.Where(r => r.Promotion.DiscountType == DiscountType.Shipping).ToList();
      if (shippingRewards.Any())
      {
        return new Money(basePrice.Amount - shippingRewards.First().SavedAmount, cart.Currency);
      }
      return null;
    }

The "magic" happens in the function GetReducedShippingMethodPrice where we first check if there are any active Shipping promotions. Then we check if the active shipping promotion is connected to the current shipping method. After that we temporarily set the current shipping method as the selected one for the cart and do PromotionEngine.Run, that way we get the reduced price before the customer actually selects any shipping methods. 

#188229
Feb 15, 2018 9:56
Vote:
 

Thank you for that final post Martin - I was in a similar position to you, and had to display shipping costs prior to selection so this definitely helped. 

One thing to note for anyone using the example above, is that if you are setting the shipping method ID back to the original ID, be sure to evaluate the promotions again against the cart (_promotionEngine.Run(cart)) that way the cart totals will then reflect the correct ID.  

#194899
Jul 05, 2018 18:47
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.