Esempio n. 1
0
            /// <summary>
            /// Compare two estimates.
            /// </summary>
            /// <param name="x">First estimate.</param>
            /// <param name="y">Second estimate.</param>
            /// <returns>Comparison result.</returns>
            internal static int Compare(DiscountDealEstimate x, DiscountDealEstimate y)
            {
                if (x != null && y != null)
                {
                    return(x.MarginalDiscountAmountPerOverlappedQuantity.CompareTo(y.MarginalDiscountAmountPerOverlappedQuantity));
                }
                else if (y == null)
                {
                    return(1);
                }

                return(-1);
            }
            private static DiscountDealEstimate BuildEstimates(
                Dictionary <string, DiscountDealEstimate> offerIdToEstimateNonCompoundedLookupHolder,
                List <DiscountBase> compoundedDiscountsHolder,
                DiscountDealEstimate existingCombinedEstimatesForCompounded,
                Dictionary <string, DiscountBase> discounts,
                DiscountableItemGroup[] discountableItemGroups,
                decimal[] remainingQuantities,
                decimal[] remainingQuantitiesForCompound,
                HashSet <int> itemsWithOverlappingDiscounts,
                HashSet <int> itemsWithOverlappingDiscountsCompoundedOnly)
            {
                using (SimpleProfiler profiler = new SimpleProfiler("OverlappedDiscounts.BuildEstimates", 2))
                {
                    DiscountDealEstimate combinedEstimateForCompounded = existingCombinedEstimatesForCompounded;
                    foreach (KeyValuePair <string, DiscountBase> pair in discounts)
                    {
                        DiscountBase         discount = pair.Value;
                        DiscountDealEstimate estimate = discount.GetDiscountDealEstimate(
                            discountableItemGroups,
                            discount.CanCompound ? remainingQuantitiesForCompound : remainingQuantities,
                            itemsWithOverlappingDiscounts,
                            itemsWithOverlappingDiscountsCompoundedOnly);

                        if (discount.CanCompound)
                        {
                            if (combinedEstimateForCompounded == null)
                            {
                                combinedEstimateForCompounded = estimate;
                            }
                            else
                            {
                                combinedEstimateForCompounded = DiscountDealEstimate.Combine(combinedEstimateForCompounded, estimate);
                            }

                            compoundedDiscountsHolder.Add(discount);
                        }
                        else
                        {
                            offerIdToEstimateNonCompoundedLookupHolder[discount.OfferId] = estimate;
                        }
                    }

                    // returns combined estimate for compounded
                    return(combinedEstimateForCompounded);
                }
            }
Esempio n. 3
0
            internal static DiscountDealEstimate Combine(DiscountDealEstimate x, DiscountDealEstimate y)
            {
                if (!x.CanCompound || !y.CanCompound)
                {
                    return(x);
                }

                Dictionary <int, decimal> combinedLookup = new Dictionary <int, decimal>(x.ItemGroupIndexToQuantityNeededFromOverlappedLookup);

                foreach (KeyValuePair <int, decimal> pair in y.ItemGroupIndexToQuantityNeededFromOverlappedLookup)
                {
                    int     itemGroupIndex = pair.Key;
                    decimal quantity       = pair.Value;

                    decimal existingQuantity = decimal.Zero;

                    // Takes the max quantity of the two.
                    if (combinedLookup.TryGetValue(itemGroupIndex, out existingQuantity))
                    {
                        combinedLookup[itemGroupIndex] = Math.Max(quantity, existingQuantity);
                    }
                    else
                    {
                        combinedLookup[itemGroupIndex] = quantity;
                    }
                }

                return(new DiscountDealEstimate(
                           true,
                           string.Empty,
                           x.TotalApplicableQuantityWithOverlapped + y.TotalApplicableQuantityWithOverlapped,
                           x.TotalDiscountAmountWithOverlapped + y.TotalDiscountAmountWithOverlapped,
                           x.TotalApplicableQuantityWithoutOverlapped + y.TotalApplicableQuantityWithoutOverlapped,
                           x.TotalDiscountAmountWithoutOverlapped + y.TotalDiscountAmountWithoutOverlapped,
                           combinedLookup));
            }
            internal DiscountBase[] GetSortedDiscountsToApplyInFastMode(
                DiscountableItemGroup[] discountableItemGroups,
                decimal[] remainingQuantities,
                decimal[] remainingQuantitiesForCompound,
                HashSet <int> itemsWithOverlappingDiscounts,
                HashSet <int> itemsWithOverlappingDiscountsCompoundedOnly)
            {
                using (SimpleProfiler profiler = new SimpleProfiler("OverlappedDiscounts.GetDiscountsToApplyInFastMode", 2))
                {
                    Dictionary <string, DiscountDealEstimate> offerIdToEstimateNonCompoundedLookup = new Dictionary <string, DiscountDealEstimate>(StringComparer.OrdinalIgnoreCase);

                    // Consolidate all compounded discounts into one estimate, to be sorted with the rest later.
                    List <DiscountBase>  compoundedDiscounts           = new List <DiscountBase>();
                    DiscountDealEstimate combinedEstimateForCompounded = null;

                    // Build estimates for offer discounts.
                    combinedEstimateForCompounded = OverlapppedDiscounts.BuildEstimates(
                        offerIdToEstimateNonCompoundedLookup,
                        compoundedDiscounts,
                        combinedEstimateForCompounded,
                        this.OfferDiscounts,
                        discountableItemGroups,
                        remainingQuantities,
                        remainingQuantitiesForCompound,
                        itemsWithOverlappingDiscounts,
                        itemsWithOverlappingDiscountsCompoundedOnly);

                    // Build estimates for mix and match and quantity discounts.
                    combinedEstimateForCompounded = OverlapppedDiscounts.BuildEstimates(
                        offerIdToEstimateNonCompoundedLookup,
                        compoundedDiscounts,
                        combinedEstimateForCompounded,
                        this.MixAndMatchAndQuantityDiscounts,
                        discountableItemGroups,
                        remainingQuantities,
                        remainingQuantitiesForCompound,
                        itemsWithOverlappingDiscounts,
                        itemsWithOverlappingDiscountsCompoundedOnly);

                    List <DiscountDealEstimate> estimatedSorted = new List <DiscountDealEstimate>(offerIdToEstimateNonCompoundedLookup.Values);
                    if (combinedEstimateForCompounded != null)
                    {
                        estimatedSorted.Add(combinedEstimateForCompounded);
                    }

                    estimatedSorted.Sort(DiscountDealEstimate.GetComparison());

    #if DEBUG
                    foreach (DiscountDealEstimate estimate in estimatedSorted)
                    {
                        estimate.DebugDisplay();
                    }
    #endif

                    DiscountBase[] discountsSorted = new DiscountBase[this.MixAndMatchAndQuantityDiscounts.Count + this.OfferDiscounts.Count];
                    int            discountIndex   = 0;
                    for (int i = estimatedSorted.Count - 1; i >= 0; i--)
                    {
                        DiscountDealEstimate estimate = estimatedSorted[i];

                        if (estimate.CanCompound)
                        {
                            for (int compoundedIndex = 0; compoundedIndex < compoundedDiscounts.Count; compoundedIndex++)
                            {
                                discountsSorted[discountIndex] = compoundedDiscounts[compoundedIndex];
                                discountIndex++;
                            }
                        }
                        else
                        {
                            DiscountBase discount = null;

                            if (this.MixAndMatchAndQuantityDiscounts.TryGetValue(estimate.OfferId, out discount))
                            {
                                discountsSorted[discountIndex] = discount;
                                discountIndex++;
                            }
                            else if (this.OfferDiscounts.TryGetValue(estimate.OfferId, out discount))
                            {
                                discountsSorted[discountIndex] = discount;
                                discountIndex++;
                            }
                        }
                    }

                    return(discountsSorted);
                }
            }
Esempio n. 5
0
            /// <summary>
            /// Gets the discount deal estimate.
            /// </summary>
            /// <param name="discountableItemGroups">The valid sales line items on the transaction to consider.</param>
            /// <param name="remainingQuantities">The remaining quantities of each of the sales lines to consider.</param>
            /// <param name="itemsWithOverlappingDiscounts">Items with overlapping discounts.</param>
            /// <param name="itemsWithOverlappingDiscountsCompoundedOnly">Hast set of overlapped item group indices, compounded only.</param>
            /// <returns>Discount deal estimate.</returns>
            protected internal override DiscountDealEstimate GetDiscountDealEstimate(
                DiscountableItemGroup[] discountableItemGroups,
                decimal[] remainingQuantities,
                HashSet <int> itemsWithOverlappingDiscounts,
                HashSet <int> itemsWithOverlappingDiscountsCompoundedOnly)
            {
                if (discountableItemGroups == null)
                {
                    throw new ArgumentNullException("discountableItemGroups");
                }

                if (remainingQuantities == null)
                {
                    throw new ArgumentNullException("remainingQuantities");
                }

                if (itemsWithOverlappingDiscounts == null)
                {
                    throw new ArgumentNullException("itemsWithOverlappingDiscounts");
                }

                if (itemsWithOverlappingDiscountsCompoundedOnly == null)
                {
                    throw new ArgumentNullException("itemsWithOverlappingDiscounts");
                }

                decimal totalApplicableQuantityWithOverlapped    = decimal.Zero;
                decimal totalDiscountAmountWithOverlapped        = decimal.Zero;
                decimal totalApplicableQuantityWithoutOverlapped = decimal.Zero;
                decimal totalDiscountAmountWithoutOverlapped     = decimal.Zero;
                Dictionary <int, decimal> itemGroupIndexToQuantityNeededFromOverlappedLookup = new Dictionary <int, decimal>();

                foreach (KeyValuePair <int, HashSet <decimal> > pair in this.ItemGroupIndexToDiscountLineNumberSetMap)
                {
                    int itemGroupIndex = pair.Key;
                    HashSet <decimal> discountLineNumberSet = pair.Value;
                    decimal           quantity = remainingQuantities[itemGroupIndex];
                    if (quantity > decimal.Zero)
                    {
                        decimal price = discountableItemGroups[itemGroupIndex].Price;
                        decimal unitDiscountAmount = decimal.Zero;

                        if (discountLineNumberSet.Any())
                        {
                            unitDiscountAmount = GetUnitDiscountAmount(this.DiscountLines[discountLineNumberSet.First()], price);
                        }

                        decimal effectiveDiscountAmount = unitDiscountAmount * quantity;
                        totalApplicableQuantityWithOverlapped += quantity;
                        totalDiscountAmountWithOverlapped     += effectiveDiscountAmount;

                        if (this.IsItemIndexGroupOverlappedWithNonCompoundedDiscounts(itemGroupIndex, itemsWithOverlappingDiscounts, itemsWithOverlappingDiscountsCompoundedOnly))
                        {
                            itemGroupIndexToQuantityNeededFromOverlappedLookup[itemGroupIndex] = quantity;
                        }
                        else
                        {
                            totalApplicableQuantityWithoutOverlapped += quantity;
                            totalDiscountAmountWithoutOverlapped     += effectiveDiscountAmount;
                        }
                    }
                }

                DiscountDealEstimate estimate = new DiscountDealEstimate(
                    this.CanCompound,
                    this.OfferId,
                    totalApplicableQuantityWithOverlapped,
                    totalDiscountAmountWithOverlapped,
                    totalApplicableQuantityWithoutOverlapped,
                    totalDiscountAmountWithoutOverlapped,
                    itemGroupIndexToQuantityNeededFromOverlappedLookup);

                return(estimate);
            }