Class DefaultShippingCalculator

Default shipping calculator.

Inheritance
System.Object
DefaultShippingCalculator
Implements
Inherited Members
System.Object.ToString()
System.Object.Equals(System.Object)
System.Object.Equals(System.Object, System.Object)
System.Object.ReferenceEquals(System.Object, System.Object)
System.Object.GetHashCode()
System.Object.GetType()
System.Object.MemberwiseClone()
Namespace: EPiServer.Commerce.Order.Calculator
Assembly: EPiServer.Business.Commerce.dll
Version: 10.8.0
Syntax
public class DefaultShippingCalculator : IShippingCalculator
Examples
    /// <summary>
/// Sample implementation of <see cref="IShippingCalculator"/>.
/// </summary>
public class ShippingCalculatorSample : IShippingCalculator
{
private readonly ILineItemCalculator _lineItemCalculator;
private readonly ServiceCollectionAccessor<IShippingPlugin> _shippingPluginsAccessor;
private readonly IReturnLineItemCalculator _returnLineItemCalculator;
private readonly ITaxCalculator _taxCalculator;

public ShippingCalculatorSample(
ILineItemCalculator lineItemCalculator,
IReturnLineItemCalculator returnLineItemCalculator,
ITaxCalculator taxCalculator,
ServiceCollectionAccessor<IShippingPlugin> shippingPluginsAccessor)
{
_lineItemCalculator = lineItemCalculator;
_returnLineItemCalculator = returnLineItemCalculator;
_taxCalculator = taxCalculator;
_shippingPluginsAccessor = shippingPluginsAccessor;
}

[Obsolete("This method is no longer used, use IOrderGroupCalculator.GetShippingSubTotal instead.")]
public Money GetShippingCost(IOrderGroup orderGroup, IMarket market, Currency currency)
{
var orderGroupCalculator = ServiceLocator.Current.GetInstance<IOrderGroupCalculator>();
return orderGroupCalculator.GetShippingSubTotal(orderGroup);
}

[Obsolete("This method is no longer used, use IOrderFormCalculator.GetShippingSubTotal instead.")]
public Money GetShippingCost(IOrderForm orderForm, IMarket market, Currency currency)
{
var orderFormCalculator = ServiceLocator.Current.GetInstance<IOrderFormCalculator>();
return orderFormCalculator.GetShippingSubTotal(orderForm, market, currency);
}

public Money GetShippingCost(IShipment shipment, IMarket market, Currency currency)
{
var zeroMoney = new Money(0m, currency);
var allShippingMethods = ShippingManager.GetShippingMethods(string.Empty);
var row = allShippingMethods.ShippingMethod.FindByShippingMethodId(shipment.ShippingMethodId);

if (row == null)
{
    return zeroMoney;
}

var type = Type.GetType(row.ShippingOptionRow.ClassName);
var provider = _shippingPluginsAccessor().First(s => s.GetType() == type);

var message = string.Empty;
var rate = provider.GetRate(market, row.ShippingMethodId, shipment, ref message);

if (rate == null)
{
    throw new Exception(string.Format("There is no rate configured for the shipping method {0}: {1}",
        row.ShippingOptionRow.ClassName, message));
}

if (!CurrencyFormatter.CanBeConverted(rate.Money, currency))
{
    throw new InvalidOperationException(
        string.Format("Cannot convert selected shipping's currency({0}) to the target currency({1}).",
            rate.Money.Currency.CurrencyCode, currency.CurrencyCode));
}

return CurrencyFormatter.ConvertCurrency(rate.Money, currency);
}

public Money GetDiscountedShippingAmount(IShipment shipment, IMarket market, Currency currency)
{
//It's the shipping cost with all shipping discounts applied on the shipment.
return GetShippingCost(shipment, market, currency) - shipment.GetShipmentDiscountPrice(currency);
}

public Money GetShippingItemsTotal(IShipment shipment, Currency currency)
{
var itemsTotalAmount = shipment.LineItems
    .Where(x => x.Quantity > 0 && !x.IsGift) // Gift items should not be included in the calculation.
    .Sum(lineItem => _lineItemCalculator.GetDiscountedPrice(lineItem, currency).Amount);

return new Money(itemsTotalAmount, currency);
}

public Money GetShippingReturnItemsTotal(IShipment shipment, Currency currency)
{
//NOTE: the shipment must belong to an IReturnOrderForm.
var itemsTotalAmount = shipment.LineItems.OfType<IReturnLineItem>()
    .Where(x => x.ReturnQuantity > 0 && !x.IsGift) // Gift items should be excluded from the calculation.
    .Sum(returnLineItem => _returnLineItemCalculator.GetDiscountedPrice(returnLineItem, currency).Amount);

return new Money(itemsTotalAmount, currency);
}

public Money GetShipmentDiscountPrice(IShipment shipment, Currency currency)
{
return shipment.GetShipmentDiscountPrice(currency);
}

public ShippingTotals GetShippingTotals(IShipment shipment, IMarket market, Currency currency)
{
var shippingSubtotal = GetShippingItemsTotal(shipment, currency);
var shippingCost = GetShippingCost(shipment, market, currency);
var shippingTax = GetShippingTax(shipment, market, currency);
var lineItemPricesDictionary = shipment.LineItems.ToDictionary(item => item, item => _lineItemCalculator.GetLineItemPrices(item, currency));

return new ShippingTotals(shippingSubtotal, shippingCost, shippingTax, lineItemPricesDictionary);
}

public Money GetShippingTax(IShipment shipment, IMarket market, Currency currency)
{
var shipmentSubtotal = GetShippingItemsTotal(shipment, currency);
return CalculateShippingTax(shipment, market, currency, shipmentSubtotal,
    (item, curr) => _lineItemCalculator.GetDiscountedPrice(item, curr),
    item => item.Quantity);
}

public Money GetSalesTax(IShipment shipment, IMarket market, Currency currency)
{
var shippingAddress = shipment.ShippingAddress;
if (shippingAddress == null)
{
    // The tax rate depends on the shipping address - where line items will be shipped to.
    return new Money(0m, currency);
}

var salesTaxAmount = shipment.LineItems
    .Where(x => x.Quantity > 0 && !x.IsGift) // Gift items should be excluded from the calculation.
    .Sum(item => _lineItemCalculator.GetSalesTax(item, market, currency, shippingAddress).Amount);

return new Money(salesTaxAmount, currency);
}

public Money GetReturnShippingTax(IShipment shipment, IMarket market, Currency currency)
{
var shipmentSubtotal = GetShippingReturnItemsTotal(shipment, currency);
return CalculateShippingTax(shipment, market, currency, shipmentSubtotal,
    (item, curr) => _returnLineItemCalculator.GetDiscountedPrice((IReturnLineItem)item, curr),
    item => item.ReturnQuantity);
}

public Money GetReturnSalesTax(IShipment shipment, IMarket market, Currency currency)
{
var shippingAddress = shipment.ShippingAddress;
if (shippingAddress == null)
{
    // The tax rate depends on the shipping address - where line items will be shipped to.
    return new Money(0m, currency);
}

var returnSalesTaxAmount = shipment.LineItems.OfType<IReturnLineItem>()
    .Where(x => x.ReturnQuantity > 0 && !x.IsGift) // Gift items should be excluded from the calculation.
    .Sum(returnItem => _returnLineItemCalculator.GetSalesTax(returnItem, market, currency, shippingAddress).Amount);

return new Money(returnSalesTaxAmount, currency);
}

public ShippingTotals GetReturnShippingTotals(IShipment shipment, Currency currency)
{
var zeroMoney = new Money(0, currency);
var total = GetShippingReturnItemsTotal(shipment, currency);
var lineItemPrices = shipment.LineItems
    .ToDictionary(item => item, item => _returnLineItemCalculator.GetLineItemPrices((IReturnLineItem)item, currency));

// A return shipment doesn't include any shipping cost and shipping tax.
return new ShippingTotals(total, zeroMoney, zeroMoney, lineItemPrices);
}

private Money CalculateShippingTax(
IShipment shipment,
IMarket market,
Currency currency,
Money shipmentSubtotal,
Func<ILineItem, Currency, Money> getDiscountedPriceFunction,
Func<ILineItem, decimal> getQuantityFunction)
{
// The tax rate depends on the shipping address - where line items will be shipped to.
if (shipment.ShippingAddress == null)
{
    return new Money(0m, currency);
}

var shippingTax = 0m;
var shippingSubTotal = GetDiscountedShippingAmount(shipment, market, currency).Amount;
var lineItemsQuantity = shipment.LineItems.Sum(lineItem => getQuantityFunction(lineItem));

foreach (var item in shipment.LineItems)
{
    var quantity = getQuantityFunction(item);
    if (quantity <= 0)
    {
        continue;
    }

    //The base price used to calculate shipping tax for a line item is the discounted price of the line item distributed on every quantity of the line item.
    var itemDiscountedPrice = getDiscountedPriceFunction(item, currency).Amount;
    var itemShippingSubTotalAmount = shippingSubTotal * (shipmentSubtotal.Amount == 0 ? quantity / lineItemsQuantity : itemDiscountedPrice / shipmentSubtotal.Amount);
    var itemShippingSubTotal = new Money(itemShippingSubTotalAmount, currency);

    shippingTax += _taxCalculator.GetShippingTax(item, market, shipment.ShippingAddress, itemShippingSubTotal).Amount;
}

return new Money(shippingTax, currency).Round();
}
}

Constructors

DefaultShippingCalculator(ILineItemCalculator)

Initialize a new instance of the DefaultShippingCalculator class.

Declaration
public DefaultShippingCalculator(ILineItemCalculator lineItemCalculator)
Parameters
Type Name Description
ILineItemCalculator lineItemCalculator

The line item calculator.

Methods

CalculateShipmentCost(IOrderGroup, IMarket, Currency)

Gets shipping cost of the orderGroup

Declaration
[Obsolete("This method is no longer used. Use CalculateShippingCost instead. Will remain at least until September 2017.")]
protected virtual Money CalculateShipmentCost(IOrderGroup orderGroup, IMarket market, Currency currency)
Parameters
Type Name Description
IOrderGroup orderGroup

The order group

IMarket market

The market to be used in the calculation.

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The shipping cost of the order group.

Remarks

Gets the result by looping over all order forms and calling GetShippingCost

Examples

CalculateShipmentCost(IShipment, IMarket, Currency)

Gets the shipment cost for the shipment

Declaration
[Obsolete("This method is no longer used. Use CalculateShippingCost instead. Will remain at least until September 2017.")]
protected virtual Money CalculateShipmentCost(IShipment shipment, IMarket market, Currency currency)
Parameters
Type Name Description
IShipment shipment

The shipment

IMarket market

The market to be used in the calculation.

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The subtotal of the shipment.

Remarks

Gets the result by calling GetRate on selected shipping provider.

Examples
Exceptions
Type Condition
System.InvalidOperationException

The currency returned from the shipping provider cannot be converted to the currency

System.TypeInitializationException

The shipping method points to an unexisting class name.

CalculateShippingCost(IOrderForm, IMarket, Currency)

Gets the shipping cost of the orderForm

Declaration
protected virtual Money CalculateShippingCost(IOrderForm orderForm, IMarket market, Currency currency)
Parameters
Type Name Description
IOrderForm orderForm

The order form

IMarket market

The market to be used in the calculation.

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The shipping cost of the order form.

Remarks

Gets the result by looping over all shipments and calling GetShippingCost

Examples

CalculateShippingCost(IOrderGroup, IMarket, Currency)

Gets shipping cost of the orderGroup

Declaration
protected virtual Money CalculateShippingCost(IOrderGroup orderGroup, IMarket market, Currency currency)
Parameters
Type Name Description
IOrderGroup orderGroup

The order group

IMarket market

The market to be used in the calculation.

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The shipping cost of the order group.

Remarks

Gets the result by looping over all order forms and calling GetShippingCost

Examples

CalculateShippingCost(IShipment, IMarket, Currency)

Gets the shipping cost for the shipment

Declaration
protected virtual Money CalculateShippingCost(IShipment shipment, IMarket market, Currency currency)
Parameters
Type Name Description
IShipment shipment

The shipment

IMarket market

The market to be used in the calculation.

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The subtotal of the shipment.

Remarks

Gets the result by calling GetRate on selected shipping provider.

Examples
Exceptions
Type Condition
System.InvalidOperationException

The currency returned from the shipping provider cannot be converted to the currency

System.TypeInitializationException

The shipping method points to an unexisting class name.

CalculateShippingItemsTotal(IShipment, Currency)

Gets the total of extended prices for all line items in the shipment.

Declaration
protected virtual Money CalculateShippingItemsTotal(IShipment shipment, Currency currency)
Parameters
Type Name Description
IShipment shipment

The shipment

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The subtotal of the shipment

Remarks

Gets the result by looping over all shipments and calling GetExtendedPrice

Examples

CanBeConverted(Money, Currency)

Determines whether the result can be converted to a specific currency

Declaration
protected virtual bool CanBeConverted(Money moneyFrom, Currency currencyTo)
Parameters
Type Name Description
Money moneyFrom

The money from.

Currency currencyTo

The currency to.

Returns
Type Description
System.Boolean

true if the result can be converted; otherwise, false.

GetDiscountedShippingAmount(IShipment, IMarket, Currency)

Gets the discounted shipping amount for the shipment

Declaration
public Money GetDiscountedShippingAmount(IShipment shipment, IMarket market, Currency currency)
Parameters
Type Name Description
IShipment shipment

The shipment

IMarket market

The market to be used in the calculation.

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The subtotal of the shipment.

Remarks

Gets the result by calling GetRate on selected shipping provider.

Examples
Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

GetShipmentDiscountPrice(IShipment, Currency)

Gets the shipment discount.

Declaration
public Money GetShipmentDiscountPrice(IShipment shipment, Currency currency)
Parameters
Type Name Description
IShipment shipment

The shipment.

Currency currency

The currency.

Returns
Type Description
Money

The shipment discount.

GetShippingCost(IOrderForm, IMarket, Currency)

Gets the shipping cost of the orderForm

Declaration
public Money GetShippingCost(IOrderForm orderForm, IMarket market, Currency currency)
Parameters
Type Name Description
IOrderForm orderForm

The order form

IMarket market

The market to be used in the calculation.

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The shipping cost of the order form.

Remarks

Gets the result by looping over all shipments and calling GetShippingCost

Examples
Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

GetShippingCost(IOrderGroup, IMarket, Currency)

Gets the shipping cost of the orderGroup

Declaration
public Money GetShippingCost(IOrderGroup orderGroup, IMarket market, Currency currency)
Parameters
Type Name Description
IOrderGroup orderGroup

The order group

IMarket market

The market to be used in the calculation.

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The shipping cost of the order group.

Remarks

Gets the result by looping over all order forms and calling GetShippingCost

Examples
Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

GetShippingCost(IShipment, IMarket, Currency)

Gets the shipping cost of the shipment

Declaration
public Money GetShippingCost(IShipment shipment, IMarket market, Currency currency)
Parameters
Type Name Description
IShipment shipment

The shipment

IMarket market

The market to be used in the calculation.

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The shipping cost of the shipment.

Remarks

Gets the result by calling GetRate on selected shipping provider.

Examples
Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

GetShippingItemsTotal(IShipment, Currency)

Gets the total of extended prices for all line items in the shipment.

Declaration
public Money GetShippingItemsTotal(IShipment shipment, Currency currency)
Parameters
Type Name Description
IShipment shipment

The shipment

Currency currency

The currency to be used in the calculations

Returns
Type Description
Money

The subtotal of the shipment

Remarks

Gets the result by looping over all shipments and calling GetExtendedPrice

Examples
Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

GetShippingMethods()

Gets all the shipping methods in the system.

Declaration
protected virtual ShippingMethodDto GetShippingMethods()
Returns
Type Description
ShippingMethodDto

ValidateShipmentCostForOrder(Money)

Validates the shipment cost

Declaration
[Obsolete("This method is no longer used. Use ValidateShippingCostForOrder instead. Will remain at least until September 2017.")]
protected virtual void ValidateShipmentCostForOrder(Money money)
Parameters
Type Name Description
Money money

The calculated value

Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

ValidateShipmentCostForOrderForm(Money)

Validates the shipment cost

Declaration
[Obsolete("This method is no longer used. Use ValidateShippingCostForOrderForm instead. Will remain at least until September 2017.")]
protected virtual void ValidateShipmentCostForOrderForm(Money money)
Parameters
Type Name Description
Money money

The calculated value

Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

ValidateShipmentCostForShipment(Money)

Validates the shipment cost

Declaration
[Obsolete("This method is no longer used. Use ValidateShippingCostForShipment instead. Will remain at least until September 2017.")]
protected virtual void ValidateShipmentCostForShipment(Money money)
Parameters
Type Name Description
Money money

The calculated value

Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

ValidateShippingCostForOrder(Money)

Validates the shipping cost

Declaration
protected virtual void ValidateShippingCostForOrder(Money money)
Parameters
Type Name Description
Money money

The calculated value

Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

ValidateShippingCostForOrderForm(Money)

Validates the shipping cost

Declaration
protected virtual void ValidateShippingCostForOrderForm(Money money)
Parameters
Type Name Description
Money money

The calculated value

Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

ValidateShippingCostForShipment(Money)

Validates the shipping cost

Declaration
protected virtual void ValidateShippingCostForShipment(Money money)
Parameters
Type Name Description
Money money

The calculated value

Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

ValidateShippingItemTotal(Money)

Validates the shipping item total

Declaration
protected virtual void ValidateShippingItemTotal(Money money)
Parameters
Type Name Description
Money money

The calculated value

Exceptions
Type Condition
System.ComponentModel.DataAnnotations.ValidationException

If validation fails.

Implements