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; }
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); }
/// <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; }
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; }
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); }
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); } } } } } }
/// <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)); }
/// <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; }