/// <summary> /// Given a list of promotion prices, crunch them down into a single discounted amount /// </summary> /// <param name="promoPrices">Prices to crunch</param> /// <param name="price">Tentative item price before promotions</param> /// <returns></returns> private static Decimal CombinePromotionPrices(IEnumerable <PromoPrice> promoPrices, Decimal price) { Decimal totalAmount = 0; // only first non-compoundable promotion will be applied if (promoPrices.Any(p => !p.IsCompoundable)) { PromoPrice nonCompoundable = promoPrices.Where(p => !p.IsCompoundable).First(); totalAmount = Math.Max(nonCompoundable.AmountOff, nonCompoundable.PercentOff * price / 100); } // apply compoundable promotions in order of offer Id foreach (var promo in promoPrices.Where(p => p.IsCompoundable).OrderBy(p => p.PromoId)) { // otherwise add the amount or percent to the total amount discounted if (promo.AmountOff != 0) { totalAmount += promo.AmountOff; } else if (promo.PercentOff != 0) { totalAmount += (price - totalAmount) * promo.PercentOff / 100; } } // don't discount more than the price if (totalAmount > price) { totalAmount = price; } return(totalAmount); }
/// <summary> /// Given a set of promotion lines, tentative item price, and item, calculate the price after promotions are applied /// </summary> /// <param name="promotionLines">List of promotion configurations active for this item</param> /// <param name="price">Price of the item before the promotion, derived from trade agreement or base item price</param> /// <param name="saleItem">The sale item whose price is being determined</param> /// <returns>Unrounded price after applying all promotions</returns> public static decimal CalculatePromotionPrice(IEnumerable <PromotionInfo> promotionLines, decimal price, BaseSaleItem saleItem) { if (saleItem == null) { NetTracer.Warning("saleItem parameter is null"); throw new ArgumentNullException("saleItem"); } if (promotionLines == null || promotionLines.Count() == 0) { return(price); } decimal promoPrice = price; IList <PromoPrice> promoPrices = new List <PromoPrice>(); foreach (PromotionInfo promo in promotionLines) { PromoPrice promoLine = new PromoPrice(); promoLine.PromoId = promo.PromoId; promoLine.Concurrency = promo.Concurrency; promoLine.IsCompoundable = false; switch (promo.DiscountMethod) { case DiscountMethod.DiscountPercent: promoLine.PercentOff = promo.MaxDiscPct; promoLine.IsCompoundable = true; promoPrices.Add(promoLine); break; case DiscountMethod.OfferPrice: if (!saleItem.Transaction.TaxIncludedInPrice) { promoLine.AmountOff = price - promo.Price; promoPrices.Add(promoLine); } break; case DiscountMethod.OfferPriceInclTax: if (saleItem.Transaction.TaxIncludedInPrice) { promoLine.AmountOff = price - promo.PriceInclTax; promoPrices.Add(promoLine); } break; case DiscountMethod.DiscountAmount: promoLine.AmountOff = promo.MaxDiscAmount; promoLine.IsCompoundable = true; promoPrices.Add(promoLine); break; } } promoPrice = price - FindConcurrentPromoAmount(promoPrices, price); return(promoPrice); }
/// <summary> /// Given a set of promotion lines, tentative item price, and item, calculate the price after promotions are applied. /// </summary> /// <param name="priceLines">List of possible adjustments and methods active for this item.</param> /// <param name="price">Price of the item before the promotion, derived from trade agreement or base item price.</param> /// <returns> /// Unrounded price after applying all promotions. /// </returns> internal static decimal CalculatePromotionPrice(IEnumerable <PriceAdjustmentPriceLine> priceLines, decimal price) { if (priceLines == null || !priceLines.Any()) { return(price); } decimal promoPrice = price; IList <PromoPrice> promoPrices = new List <PromoPrice>(); foreach (var promo in priceLines) { PromoPrice promoLine = new PromoPrice(); promoLine.PromoId = promo.OriginId; promoLine.Concurrency = promo.Concurrency; promoLine.IsCompoundable = false; switch (promo.PriceMethod) { case PriceMethod.PercentOff: promoLine.PercentOff = promo.Value; promoLine.IsCompoundable = true; break; case PriceMethod.Fixed: promoLine.AmountOff = Math.Max(0m, price - promo.Value); break; case PriceMethod.AmountOff: promoLine.AmountOff = promo.Value; promoLine.IsCompoundable = true; break; default: throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Behavior not defined for price method: {0}", promo.PriceMethod)); } promoPrices.Add(promoLine); } promoPrice = price - FindConcurrentPromoAmount(promoPrices, price); return(promoPrice); }