public void Calculate(Order order)
        {
            foreach (var item in order.OrderItems)
            {
                // For each base charge that this charge should be calculated on top of (item, duty, vat etc.)
                foreach (var baseChargeName in _baseCharges)
                {
                    // All of the charges that we need to calculate on top of
                    // e.g if applying on top of item and vat, and vat was applied on item, the charges we need to calculate on are:
                    // item, vatOnItem
                    var baseCharges = item.Charges.Where(c => c.BaseChargeName == baseChargeName);

                    foreach (var charge in baseCharges.ToList())
                    {
                        if (charge.ChargeAmount.Value == 0)
                        {
                            continue;
                        }

                        var chargeAmount = charge.ChargeAmount * _getRate(item).AsDecimal;

                        var chargeName = ChargeName.FromBaseChargeName(_chargeName, charge.ChargeName);

                        item.AddCharge(new OrderCharge(chargeName, chargeAmount, _chargeName));
                    }
                }
            }
        }
 public FixedRateChargeConfiguration(
     ChargeName chargeName,
     Price deminimisThreshold,
     Price fixedChargeAmount) : base(chargeName, CalculationType.Fixed, deminimisThreshold, true, null, null)
 {
     FixedChargeAmount = fixedChargeAmount;
 }
Example #3
0
 public ReversePriceCalculator(
     ChargeName chargeName,
     ChargeName inputChargeName)
 {
     _chargeName      = chargeName;
     _inputChargeName = inputChargeName;
 }
        /// <summary>
        /// Get the requested order charge.
        /// </summary>
        /// <param name="chargeName">The charge name being requested.</param>
        /// <param name="includeSubCharges">A <see cref="bool"/> value indicating whether all sub charges (e.g: VatOnDuty, VatOnFee) should be included when requesting a charge (e.g Vat)</param>
        /// <returns></returns>
        public Price GetChargeAmount(ChargeName chargeName, Currency currency)
        {
            var chargeAmount = Charges
                               .Where(c => c.BaseChargeName == chargeName || c.ChargeName == chargeName)
                               .Select(x => x.ChargeAmount)
                               .Sum(currency);

            return(chargeAmount);
        }
Example #5
0
 /// <summary>
 /// Create a new <see cref="ReverseRateCalculator"/>.
 /// </summary>
 /// <param name="chargeName">The charge name that the reverse rate is being calculated for.</param>
 /// <param name="getRate">A func used to determine the rate for each item.</param>
 /// <param name="baseCharges">A collection of <see cref="ChargeName"/>, used to determine which charges this charge should be applied on top of.</param>
 public ReverseRateCalculator(
     ChargeName chargeName,
     Func <OrderItem, Rate> getRate,
     IEnumerable <ChargeName> baseCharges)
 {
     _getRate     = getRate;
     _baseCharges = baseCharges;
     _chargeName  = chargeName;
 }
Example #6
0
 public MinimumPayableConstraint(
     IChargeCalculator chargeCalculator,
     ChargeName chargeName,
     Price minimumPayable)
 {
     _chargeCalculator = chargeCalculator;
     _chargeName       = chargeName;
     _minimumPayable   = minimumPayable;
 }
 public WeightBasedChargeConfiguration(
     ChargeName chargeName,
     Price deminimisThreshold,
     Rate rate,
     Price?minimumPayable,
     Price?minimumCollectible) : base(chargeName, CalculationType.WeightBased, deminimisThreshold, true, minimumPayable, minimumCollectible)
 {
     Rate = rate;
 }
Example #8
0
 public RateBasedChargeConfiguration(
     ChargeName chargeName,
     Price deminimisThreshold,
     IEnumerable <ChargeName> baseChargeNames,
     Rate?rate                = default,
     Price?minimumPayable     = default,
     Price?minimumCollectible = default) : base(chargeName, CalculationType.RateBased, deminimisThreshold, false, minimumPayable, minimumCollectible)
 {
     Rate             = rate;
     _baseChargeNames = baseChargeNames.ToList();
 }
        public void Calculate(Order order)
        {
            foreach (var item in order.OrderItems)
            {
                var chargeAmount = _amount * order.RelativeOrderItemValue(item);

                var chargeName = ChargeName.FromBaseChargeName(_chargeName, ChargeNames.Item);

                item.AddCharge(new OrderCharge(chargeName, chargeAmount, _chargeName));
            }
        }
 protected ChargeConfiguration(
     ChargeName chargeName,
     CalculationType calculationType,
     Price deminimisThreshold,
     bool knownCharge,
     Price?minimumPayable,
     Price?minimumCollectible)
 {
     ChargeName         = chargeName;
     CalculationType    = calculationType;
     DeminimisThreshold = deminimisThreshold;
     MinimumPayable     = minimumPayable;
     MinimumCollectible = minimumCollectible;
     KnownCharge        = knownCharge;
 }
        public void Calculate_SingleOrderItem_ShouldAddCorrectCharge()
        {
            // Arrange
            var orderItem = _orderItemBuilder.Build();
            var order     = _orderBuilder.WithOrderItems(new List <OrderItem> {
                orderItem
            }).Build();
            var expectedChargeName = ChargeName.FromBaseChargeName(_chargeName, ChargeNames.Item);

            var sut = new FixedChargeCalculator(_chargeName, new Price(CurrencyFakes.EUR, 10));

            // Act
            sut.Calculate(order);

            // Assert
            orderItem.Charges.Should()
            .HaveCount(3).And
            .ContainSingle(c => c.ChargeName.Value == expectedChargeName && c.ChargeAmount.Value == 10);
        }
Example #12
0
        public void Calculate(Order order)
        {
            foreach (var item in order.OrderItems)
            {
                // Loop through each of the charges that this charge type is to be calculated on top of.
                foreach (var baseChargeName in _baseCharges)
                {
                    var baseChargeAmount = item.GetChargeAmount(baseChargeName, order.Currency);

                    // Check to see if a charge has been calculated for this charge type.
                    // If so, do a forward calculation - the calculated charges can be removed from the
                    // inclusive price before applying the reverse rate as they are known.
                    if (baseChargeAmount.Value != 0)
                    {
                        var chargeAmount = baseChargeAmount * _getRate(item).AsDecimal;

                        var chargeName = ChargeName.FromBaseChargeName(_chargeName, baseChargeName);

                        item.AddCharge(new OrderCharge(chargeName, chargeAmount, _chargeName));
                    }

                    // If the charge that we need to calculate on top of has not already been calculated,
                    // and is therefore unknown - we need to calculate the reverse rate.
                    else
                    {
                        // If the base charge is item or delivery (not a calculated rate), just add the rate
                        // for this item to the calculation rates collection. There might be a better way of
                        // identifying these 'non calculated' rates types of charges that would be more flexible.
                        if (baseChargeName.Value == "Item" || baseChargeName.Value == "Delivery")
                        {
                            item.AddReverseRate(new ReverseRate(
                                                    name: ChargeName.FromBaseChargeName(_chargeName, baseChargeName),
                                                    parentChargeName: _chargeName,
                                                    rate: _getRate(item)));
                        }

                        // If the base charge is a calculated rate, we need to calculate a new rate and add it
                        // to the calculated rates collection. All of these rates combined will be used to reverse
                        // back to the item price.
                        else
                        {
                            // Get the current list of rates
                            var reverseRates = item.ReverseRates.ToList();

                            // Get all of the reverse rates related to the current base charge. For example, if we're
                            // calculating a fee, which was calculated on top of duty and vat, we'll need the base
                            // fee rate, the fee on duty rate and the fee on vat rate. This is done by querying the
                            // rates collection by 'parent' charge. In this example, all rates would have a parent charge
                            // of fee.
                            foreach (var reverseRate in reverseRates.Where(x => x.BaseChargeName == baseChargeName))
                            {
                                var rate = _getRate(item).AsDecimal *reverseRate.Rate.AsDecimal * 100;

                                var calculatedRate = new ReverseRate(
                                    name: ChargeName.FromBaseChargeName(_chargeName, reverseRate.ChargeName),
                                    parentChargeName: _chargeName,
                                    rate: new Rate(rate));

                                item.AddReverseRate(calculatedRate);
                            }
                        }
                    }
                }
            }
        }
Example #13
0
 /// <summary>
 /// Removes the charge from all order items on the order.
 /// </summary>
 /// <param name="chargeName">Name of the charge.</param>
 public void RemoveCharge(ChargeName chargeName)
 {
     _orderItems.ForEach(oi => oi.RemoveCharge(chargeName));
 }
Example #14
0
 /// <summary>
 /// Get the requested order charge, if the charge name is a base charge it will return the total
 /// charge amount including sub charges (Vat, Vat On Duty etc.)
 /// </summary>
 public Price GetChargeAmount(ChargeName chargeName, Currency currency)
 {
     return(_orderItems.Select(oi => oi.GetChargeAmount(chargeName, currency)).Sum(currency));
 }
 public void RemoveCharge(ChargeName chargeName)
 {
     _charges.RemoveAll(x => x.ChargeName == chargeName || x.BaseChargeName == chargeName);
 }
 public WeightBasedChargeCalculator(ChargeName chargeName, Func <OrderItem, Rate> getRate)
 {
     _chargeName = chargeName;
     _getRate    = getRate;
 }
 public FixedChargeCalculator(ChargeName chargeName, Price amount)
 {
     _chargeName = chargeName;
     _amount     = amount;
 }