private void Aquire( Dictionary <int, OverlapppedDiscounts> itemGroupIndexToOverlapppedDiscountsLookup, OverlapppedDiscounts overlapppedDiscountsToAcquire) { using (SimpleProfiler profiler = new SimpleProfiler("OverlappedDiscounts.Aquire", 4)) { this.MixAndMatchAndQuantityDiscounts.AddRange(overlapppedDiscountsToAcquire.MixAndMatchAndQuantityDiscounts); this.CoveredItemGroupIndexSet.AddRange(overlapppedDiscountsToAcquire.CoveredItemGroupIndexSet); foreach (KeyValuePair <string, DiscountBase> pairOfferIdToDiscount in overlapppedDiscountsToAcquire.MixAndMatchAndQuantityDiscounts) { DiscountBase discount = pairOfferIdToDiscount.Value; foreach (KeyValuePair <int, HashSet <decimal> > pair in discount.ItemGroupIndexToDiscountLineNumberSetMap) { int itemGroupIndex = pair.Key; itemGroupIndexToOverlapppedDiscountsLookup[itemGroupIndex] = this; } } } }
/// <summary> /// Splits all discounts into multiple groups of overlapped discounts with each group non-overlapping with each other. /// </summary> /// <param name="possibleDiscounts">Possible discounts.</param> /// <returns>A collection of overlapped discounts.</returns> /// <remarks>By isolating discounts into groups, we can calculate and optimize discounts for each group.</remarks> internal static IEnumerable <OverlapppedDiscounts> BuildOverlappedDiscountsGroup(List <DiscountBase> possibleDiscounts) { // DISCOUNTPERF: add filtering by remaining quantities // Build lookup for mix and match and quantity discounts. Ignore offer discounts for now. Dictionary <int, OverlapppedDiscounts> itemGroupIndexToOverlapppedDiscountsLookup = new Dictionary <int, OverlapppedDiscounts>(); foreach (DiscountBase discount in possibleDiscounts) { if (discount is MixAndMatchDiscount || discount is MultipleBuyDiscount) { OverlapppedDiscounts myOverlapppedDiscounts = null; foreach (KeyValuePair <int, HashSet <decimal> > pair in discount.ItemGroupIndexToDiscountLineNumberSetMap) { int itemGroupIndex = pair.Key; OverlapppedDiscounts overlappedDiscounts = null; if (itemGroupIndexToOverlapppedDiscountsLookup.TryGetValue(itemGroupIndex, out overlappedDiscounts)) { // Item covered in an overlappedDiscounts already. if (myOverlapppedDiscounts == null) { // myOverlapppedDiscounts not set yet, add current discount to it. myOverlapppedDiscounts = overlappedDiscounts; myOverlapppedDiscounts.MixAndMatchAndQuantityDiscounts.Add(discount.OfferId, discount); } else if (myOverlapppedDiscounts.OverlapId != overlappedDiscounts.OverlapId) { // Item covered in a different overlappedDiscounts, myOverlapppedDiscounts acquires it. myOverlapppedDiscounts.Aquire(itemGroupIndexToOverlapppedDiscountsLookup, overlappedDiscounts); itemGroupIndexToOverlapppedDiscountsLookup[itemGroupIndex] = myOverlapppedDiscounts; } } else { // Item not covered yet. if (myOverlapppedDiscounts == null) { // New overlappedDiscounts. myOverlapppedDiscounts = new OverlapppedDiscounts(itemGroupIndex, discount); } else { // Add item to the overlappedDiscounts. myOverlapppedDiscounts.CoveredItemGroupIndexSet.Add(itemGroupIndex); } itemGroupIndexToOverlapppedDiscountsLookup[itemGroupIndex] = myOverlapppedDiscounts; } } } } // Add offer discounts to the lookup. foreach (DiscountBase discount in possibleDiscounts) { if (discount is OfferDiscount) { foreach (KeyValuePair <int, HashSet <decimal> > pair in discount.ItemGroupIndexToDiscountLineNumberSetMap) { int itemGroupIndex = pair.Key; OverlapppedDiscounts overlappedDiscounts = null; if (itemGroupIndexToOverlapppedDiscountsLookup.TryGetValue(itemGroupIndex, out overlappedDiscounts)) { overlappedDiscounts.OfferDiscounts[discount.OfferId] = discount; } } } } // Convert itemGroupIndexToOverlapppedDiscountsLookup to List<OverlapppedDiscounts>. HashSet <Guid> overlappedIdSet = new HashSet <Guid>(); List <OverlapppedDiscounts> overlappedDiscountsList = new List <OverlapppedDiscounts>(); foreach (KeyValuePair <int, OverlapppedDiscounts> pair in itemGroupIndexToOverlapppedDiscountsLookup) { OverlapppedDiscounts overlappedDiscounts = pair.Value; if (!overlappedIdSet.Contains(overlappedDiscounts.OverlapId)) { overlappedIdSet.Add(overlappedDiscounts.OverlapId); overlappedDiscountsList.Add(overlappedDiscounts); } } return(overlappedDiscountsList); }
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); } }