Exemple #1
0
        /// <summary>
        /// Adds the discount to line item.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <param name="itemRecord">The item record.</param>
        /// <param name="entryCode">The entry code.</param>
        /// <param name="itemDiscount">The item discount.</param>
        /// <param name="orderLevelDiscount">The order level discount.</param>
        private void AddDiscountToLineItem(OrderGroup order, PromotionItemRecord itemRecord, PromotionEntry promotionEntry,
                                           decimal itemDiscount, decimal orderLevelDiscount)
        {
            LineItem item = FindLineItemByPromotionEntry(order, promotionEntry);

            if (item != null)
            {
                // Add line item properties
                item.LineItemDiscountAmount   += itemDiscount;
                item.OrderLevelDiscountAmount += orderLevelDiscount;
                item.ExtendedPrice             = item.ListPrice * item.Quantity - item.LineItemDiscountAmount - item.OrderLevelDiscountAmount;

                if (itemRecord.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Entry).Key, StringComparison.OrdinalIgnoreCase))
                {
                    LineItemDiscount discount = FindLineItemDiscountById(order, itemRecord.PromotionItem.DataRow.PromotionId, item.LineItemId);

                    if (discount == null)
                    {
                        discount = new LineItemDiscount();
                    }

                    discount.DiscountAmount = itemRecord.PromotionItem.DataRow.OfferAmount;
                    discount.DiscountCode   = itemRecord.PromotionItem.DataRow.CouponCode;
                    discount.DiscountName   = itemRecord.PromotionItem.DataRow.Name;
                    discount.DiscountValue  = itemRecord.PromotionItem.DataRow.OfferAmount;
                    discount.DisplayMessage = GetDisplayName(itemRecord.PromotionItem.DataRow, Thread.CurrentThread.CurrentCulture.Name);
                    discount.LineItemId     = item.LineItemId;
                    discount.DiscountId     = itemRecord.PromotionItem.DataRow.PromotionId;
                    item.Discounts.Add(discount);
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Pre processes item record adding additional LineItems if needed.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <param name="record">The record.</param>
        private void PreProcessItemRecord(OrderGroup order, PromotionItemRecord record)
        {
            // We do special logic for the gift promotion reward
            if (record.PromotionReward is GiftPromotionReward)
            {
                // Check if item already in the cart, if not add
                if (((GiftPromotionReward)record.PromotionReward).AddStrategy == GiftPromotionReward.Strategy.AddWhenNeeded)
                {
                    // We assume that all affected entries are the gifts that need to be added to the cart
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        LineItem item = FindLineItemByCatalogEntryId(order, entry.CatalogEntryCode);

                        // Didn't find, add it
                        if (item == null)
                        {
                            // we should some kind of delegate or common implementation here so we can use the same function in both discount and front end
                            Entry    catEntry = CatalogContext.Current.GetCatalogEntry(entry.CatalogEntryCode);
                            LineItem lineItem = CreateLineItem(catEntry, entry.Quantity);

                            // Need to determine which order form the entry belongs to (which should be the same as the target entry)

                            // hack: add to the first
                            order.OrderForms[0].LineItems.Add(lineItem);
                        }
                    }
                }
            }
        }
Exemple #3
0
 /// <summary>
 /// Adds the promotion item record.
 /// </summary>
 /// <param name="reward">The reward.</param>
 /// <param name="entriesCollection">The entries collection.</param>
 /// <returns></returns>
 public void AddPromotionItemRecord(PromotionReward reward, params PromotionEntriesSet[] entrySetsCollection)
 {
     foreach (PromotionEntriesSet entrySet in entrySetsCollection)
     {
         PromotionItemRecord record = new PromotionItemRecord(this.PromotionContext.TargetEntriesSet, entrySet, reward);
         record.PromotionItem = PromotionContext.CurrentPromotion;
         PromotionContext.PromotionResult.PromotionRecords.Add(record);
     }
 }
Exemple #4
0
        /// <summary>
        /// Pre processes item record adding additional LineItems if needed.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <param name="record">The record.</param>
        private void PreProcessItemRecord(OrderGroup order, PromotionItemRecord record)
        {
            // We do special logic for the gift promotion reward
            if (record.PromotionReward is GiftPromotionReward)
            {
                // Check if item already in the cart, if not add
                if (((GiftPromotionReward)record.PromotionReward).AddStrategy == GiftPromotionReward.Strategy.AddWhenNeeded)
                {
                    // We assume that all affected entries are the gifts that need to be added to the cart
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        LineItem giftLineItem = FindGiftLineItemInOrder(order, entry.CatalogEntryCode, record);

                        if (!IsOrderHaveSpecifiedGiftPromotion(order, record))
                        {
                            // Didn't find, add it
                            if (giftLineItem == null)
                            {
                                // we should some kind of delegate or common implementation here so we can use the same function in both discount and front end
                                CatalogEntryResponseGroup responseGroup = new CatalogEntryResponseGroup(CatalogEntryResponseGroup.ResponseGroup.Variations);
                                Entry catEntry = CatalogContext.Current.GetCatalogEntry(entry.CatalogEntryCode, responseGroup);
                                giftLineItem = AddNewGiftLineItemToOrder(order, catEntry, entry.Quantity);
                                AddGiftItemToAShipment(giftLineItem, giftLineItem.Parent.LineItems.Count - 1);
                                CatalogEntryDto entryDto = CatalogContext.Current.GetCatalogEntryDto(giftLineItem.Code, responseGroup);
                                CatalogEntryDto.CatalogEntryRow entryRow = entryDto.CatalogEntry[0];
                                Money?price = GetItemPrice(entryRow, giftLineItem, CustomerContext.Current.CurrentContact);
                                giftLineItem.ListPrice   = price.HasValue ? price.Value.Amount : 0m;
                                giftLineItem.PlacedPrice = giftLineItem.ListPrice;
                                // populate inventory information for giftLineItem
                                var aggregateInventory = ServiceLocator.Current.GetInstance <IInventoryService>().QueryByEntry(new [] { entryRow.Code });
                                foreach (var inventoryRecord in aggregateInventory)
                                {
                                    PopulateInventoryInfo(inventoryRecord, giftLineItem);
                                }
                            }
                            else
                            {
                                giftLineItem.Quantity = Math.Max(entry.Quantity, giftLineItem.Quantity);

                                var index = giftLineItem.Parent.LineItems.IndexOf(giftLineItem);

                                if (!giftLineItem.Parent.Shipments.SelectMany(x => x.LineItemIndexes).Contains(index.ToString()))
                                {
                                    AddGiftItemToAShipment(giftLineItem, index);
                                }
                            }
                        }
                        else
                        {
                            entry.Quantity = giftLineItem != null?Math.Min(entry.Quantity, giftLineItem.Quantity) : entry.Quantity;
                        }
                        entry.Owner        = giftLineItem;
                        entry.CostPerEntry = giftLineItem != null ? giftLineItem.ListPrice : 0m;
                    }
                }
            }
        }
Exemple #5
0
        private bool IsOrderHaveSpecifiedGiftPromotion(OrderGroup order, PromotionItemRecord promoRecord)
        {
            bool retVal = false;

            foreach (OrderFormDiscount discount in order.OrderForms[0].Discounts)
            {
                if (GetGiftPromotionName(promoRecord) == discount.DiscountName)
                {
                    retVal = true;
                    break;
                }
            }
            return(retVal);
        }
        /// <summary>
        /// Gets the discount amount for one entry only.
        /// </summary>
        /// <param name="record">The record.</param>
        /// <param name="reward">The reward.</param>
        /// <returns></returns>
        private static decimal GetDiscountAmount(PromotionItemRecord record, PromotionReward reward)
        {
            decimal discountAmount = 0;

            if (reward.RewardType == PromotionRewardType.EachAffectedEntry || reward.RewardType == PromotionRewardType.AllAffectedEntries)
            {
                if (reward.AmountType == PromotionRewardAmountType.Percentage)
                {
                    discountAmount = record.AffectedEntriesSet.TotalCost * reward.AmountOff / 100;
                }
                else // need to split discount between all items
                {
                    discountAmount += reward.AmountOff; // since we assume only one entry in affected items
                }
            }
            return(Math.Round(discountAmount, 2));
        }
        private decimal GetDiscountAmount(PromotionItemRecord record, PromotionReward reward)
        {
            decimal discountAmount = 0;

            if (reward.RewardType != PromotionRewardType.EachAffectedEntry && reward.RewardType != PromotionRewardType.AllAffectedEntries)
            {
                return(Math.Round(discountAmount, 2));
            }
            if (reward.AmountType == PromotionRewardAmountType.Percentage)
            {
                discountAmount = record.AffectedEntriesSet.TotalCost * reward.AmountOff / 100;
            }
            else
            {
                discountAmount += reward.AmountOff;
            }
            return(Math.Round(discountAmount, 2));
        }
 private bool IsOrderHaveSpecifiedGiftPromotion(OrderGroup order, PromotionItemRecord promoRecord)
 {
     bool retVal = false;
     foreach (OrderFormDiscount discount in order.OrderForms[0].Discounts)
     {
         if (GetGiftPromotionName(promoRecord) == discount.DiscountName)
         {
             retVal = true;
             break;
         }
     }
     return retVal;
 }
 private LineItem FindGiftLineItemInOrder(OrderGroup order, string catalogEntryId, PromotionItemRecord promoRecord)
 {
     var lineItems = order.OrderForms[0].LineItems.ToArray().Where(x => x.Code == catalogEntryId);
     foreach (var lineitem in lineItems)
     {
         foreach (LineItemDiscount discount in lineitem.Discounts)
         {
             if (discount.DiscountName == GetGiftPromotionName(promoRecord))
             {
                 return lineitem;
             }
         }
     }
     return null;
 }
        private void AddDiscountToLineItem(OrderGroup order, PromotionItemRecord itemRecord, PromotionEntry promotionEntry,
                                          decimal itemDiscount, decimal orderLevelDiscount)
        {
            orderLevelDiscount = Math.Floor(orderLevelDiscount * 100) * 0.01m;
            LineItem item = FindLineItemByPromotionEntry(order, promotionEntry);
            if (item != null)
            {
                //reset gift line item discount
                if (IsGiftLineItem(item))
                {
                    item.PlacedPrice = promotionEntry.CostPerEntry;
                    item.LineItemDiscountAmount = itemDiscount;
                    item.OrderLevelDiscountAmount = 0;
                    item.ExtendedPrice = item.PlacedPrice;
                }
                else
                {
                    // Add line item properties
                    item.LineItemDiscountAmount += itemDiscount;
                    item.OrderLevelDiscountAmount += orderLevelDiscount;
                    item.ExtendedPrice = item.PlacedPrice * item.Quantity - item.LineItemDiscountAmount - item.OrderLevelDiscountAmount;
                }

                if (itemRecord.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Entry).Key, StringComparison.OrdinalIgnoreCase)
                    || itemRecord.PromotionReward is GiftPromotionReward
                    || (itemRecord.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Order).Key,
                        StringComparison.OrdinalIgnoreCase) && itemRecord.PromotionReward.RewardType == PromotionRewardType.EachAffectedEntry))
                {
                    LineItemDiscount discount = FindLineItemDiscountById(order, itemRecord.PromotionItem.DataRow.PromotionId, item.LineItemId);

                    if (discount == null)
                    {
                        discount = new LineItemDiscount();
                        item.Discounts.Add(discount);
                    }

                    var discountName = itemRecord.PromotionItem.DataRow.Name;
                    if (itemRecord.PromotionReward is GiftPromotionReward)
                    {
                        discount.DiscountName = GetGiftPromotionName(itemRecord);
                    }
                    else
                    {
                        discount.DiscountName = String.Format("{0}{1}", itemRecord.PromotionItem.DataRow.Name,
                            itemRecord.PromotionItem.DataRow.OfferType == 1 ? ":PercentageBased" : ":ValueBased");
                    }

                    discount.DiscountAmount = itemRecord.PromotionReward.AmountOff;
                    discount.DiscountCode = itemRecord.PromotionItem.DataRow.CouponCode;

                    discount.DiscountValue = itemDiscount;
                    // use the promotion name if the localized display message is null or empty
                    discount.DisplayMessage = GetDisplayName(itemRecord.PromotionItem.DataRow, Thread.CurrentThread.CurrentCulture.Name);
                    if (string.IsNullOrEmpty(discount.DisplayMessage))
                        discount.DisplayMessage = itemRecord.PromotionItem.DataRow.Name;
                    discount.LineItemId = item.LineItemId;
                    discount.DiscountId = itemRecord.PromotionItem.DataRow.PromotionId;
                }
            }
        }
        /// <summary>
        /// Applies the item discount.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <param name="record">The record.</param>
        /// <param name="totalAmount">The total amount.</param>
        /// <returns></returns>
        private decimal ApplyItemDiscount(OrderGroup order, PromotionItemRecord record, decimal totalAmount)
        {

            decimal discountAmount = 0;
            if (record.PromotionReward.RewardType == PromotionRewardType.AllAffectedEntries)
            {
                if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                {
                    discountAmount = record.AffectedEntriesSet.TotalCost * record.PromotionReward.AmountOff / 100;
                    decimal averageDiscountAmount = discountAmount / record.AffectedEntriesSet.TotalQuantity;
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        // Sasha: changed back, CostPerEntry does not change dynamically, while total cost does
                        // AddDiscountToLineItem(order, record, entry, entry.CostPerEntry * entry.Quantity * record.PromotionReward.AmountOff / 100m, 0);
                        // AddDiscountToLineItem(order, record, entry.CatalogEntryCode, averageDiscountAmount * entry.Quantity, 0);
                        AddDiscountToLineItem(order, record, entry, averageDiscountAmount * entry.Quantity, 0);
                    }
                }
                else // need to split discount between all items
                {
                    discountAmount = record.PromotionReward.AmountOff;
                    decimal averageDiscountAmount = record.PromotionReward.AmountOff / record.AffectedEntriesSet.TotalQuantity;
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        AddDiscountToLineItem(order, record, entry, averageDiscountAmount * entry.Quantity, 0);
                    }
                }
            }
            else if (record.PromotionReward.RewardType == PromotionRewardType.EachAffectedEntry)
            {
                if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                {
                    discountAmount = record.AffectedEntriesSet.TotalCost * record.PromotionReward.AmountOff / 100;
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        AddDiscountToLineItem(order, record, entry, entry.CostPerEntry * entry.Quantity * record.PromotionReward.AmountOff / 100, 0);
                    }
                }
                else
                {
                    discountAmount = record.AffectedEntriesSet.TotalQuantity * record.PromotionReward.AmountOff;
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        AddDiscountToLineItem(order, record, entry, record.PromotionReward.AmountOff * entry.Quantity, 0);
                    }
                }
            }
            else if (record.PromotionReward.RewardType == PromotionRewardType.WholeOrder)
            {
                decimal percentageOffTotal = 0;
                if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                {
                    decimal extendedCost = 0;
                    foreach (OrderForm orderForm in order.OrderForms)
                    {
                        extendedCost += orderForm.LineItems.ToArray().Sum(x => x.ExtendedPrice);
                    }
                    // calculate percentage adjusted by the running amount, so it will be a little less if running amount is less than total
                    percentageOffTotal = (record.PromotionReward.AmountOff / 100) * (totalAmount / extendedCost);
                    //percentageOffTotal = PromotionReward.AmountOff / 100;
                    discountAmount = totalAmount * record.PromotionReward.AmountOff / 100;
                }
                else
                {
                    // Calculate percentage off discount price
                    if (totalAmount > 0)
                    {
                        percentageOffTotal = record.PromotionReward.AmountOff / totalAmount;
                        // but since CostPerEntry is not an adjusted price, we need to take into account additional discounts already applied
                        percentageOffTotal = percentageOffTotal * (totalAmount / record.AffectedEntriesSet.TotalCost);
                    }
                    else
                    {
                        percentageOffTotal = 100m;
                    }

                    discountAmount = record.PromotionReward.AmountOff;
                }

                // Now distribute discount amount evenly over all entries taking into account running total
                // Special case for shipments, we consider WholeOrder to be a shipment
                if (!record.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Shipping).Key, StringComparison.OrdinalIgnoreCase))
                {
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        LineItem item = FindLineItemByPromotionEntry(order, entry);
                        AddDiscountToLineItem(order, record, entry, 0, item.ExtendedPrice * percentageOffTotal);
                    }
                }
            }

            // Save discounts
            if (record.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Order).Key, StringComparison.OrdinalIgnoreCase)
                || record.PromotionReward is GiftPromotionReward)
            {
                if (record.PromotionReward.RewardType == PromotionRewardType.WholeOrder)
                {
                    OrderFormDiscount discount = FindOrderFormDiscountById(order, record.PromotionItem.DataRow.PromotionId, Int32.Parse(record.AffectedEntriesSet.OrderFormId));
                    bool hasOrderFormDiscount = true;
                    if (discount == null)
                    {
                        discount = new OrderFormDiscount();
                        hasOrderFormDiscount = false;
                    }

                    var discountName = record.PromotionItem.DataRow.Name;
                    if (record.PromotionReward is GiftPromotionReward)
                    {
                        discountName = GetGiftPromotionName(record);
                    }
                    discount.DiscountName = discountName;

                    discount.DiscountAmount = record.PromotionReward.AmountOff;
                    discount.DiscountCode = record.PromotionItem.DataRow.CouponCode;
                    discount.DiscountValue = hasOrderFormDiscount ? discountAmount + discount.DiscountValue : discountAmount;
                    discount.DisplayMessage = GetDisplayName(record.PromotionItem.DataRow, Thread.CurrentThread.CurrentCulture.Name);
                    discount.OrderFormId = Int32.Parse(record.AffectedEntriesSet.OrderFormId);
                    discount.DiscountId = record.PromotionItem.DataRow.PromotionId;

                    foreach (OrderForm form in order.OrderForms)
                    {
                        if (form.OrderFormId == discount.OrderFormId && !hasOrderFormDiscount)
                            form.Discounts.Add(discount);
                    }
                }
            }
            else if (record.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Shipping).Key, StringComparison.OrdinalIgnoreCase))
            {
                ShipmentDiscount discount = FindShipmentDiscountById(order, record.PromotionItem.DataRow.PromotionId, Int32.Parse(record.AffectedEntriesSet.ShipmentId));

                if (discount == null)
                    discount = new ShipmentDiscount();

                discount.DiscountAmount = record.PromotionReward.AmountOff;
                discount.DiscountCode = record.PromotionItem.DataRow.CouponCode;
                discount.DiscountName = record.PromotionItem.DataRow.Name;
                discount.DisplayMessage = GetDisplayName(record.PromotionItem.DataRow, Thread.CurrentThread.CurrentCulture.Name);
                discount.ShipmentId = Int32.Parse(record.AffectedEntriesSet.ShipmentId);
                discount.DiscountId = record.PromotionItem.DataRow.PromotionId;

                foreach (OrderForm form in order.OrderForms)
                {
                    foreach (Shipment shipment in form.Shipments)
                    {
                        if (shipment.ShipmentId == discount.ShipmentId)
                        {
                            shipment.Discounts.Add(discount);

                            if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                            {
                                discountAmount = shipment.ShippingSubTotal * record.PromotionReward.AmountOff / 100;
                            }
                            else
                            {
                                discountAmount = Math.Min(record.PromotionReward.AmountOff, shipment.ShippingSubTotal);
                            }

                            shipment.ShippingDiscountAmount = Math.Min(shipment.ShippingDiscountAmount + discountAmount, shipment.ShippingSubTotal);
                            // ShippingDiscountAmount will not be subtracted from the ShipmentTotal per discussions on 2/22/2012.
                            break;
                        }
                    }
                }
                discount.DiscountValue = discountAmount;
            }
            return discountAmount;
        }
        /// <summary>
        /// Pre processes item record adding additional LineItems if needed.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <param name="record">The record.</param>
        private void PreProcessItemRecord(OrderGroup order, PromotionItemRecord record)
        {
            // We do special logic for the gift promotion reward
            if (record.PromotionReward is GiftPromotionReward)
            {
                // Check if item already in the cart, if not add
                if (((GiftPromotionReward)record.PromotionReward).AddStrategy == GiftPromotionReward.Strategy.AddWhenNeeded)
                {
                    // We assume that all affected entries are the gifts that need to be added to the cart
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        LineItem giftLineItem = FindGiftLineItemInOrder(order, entry.CatalogEntryCode, record);

                        if (!IsOrderHaveSpecifiedGiftPromotion(order, record))
                        {
                            // Didn't find, add it
                            if (giftLineItem == null)
                            {
                                // we should some kind of delegate or common implementation here so we can use the same function in both discount and front end
                                CatalogEntryResponseGroup responseGroup = new CatalogEntryResponseGroup(CatalogEntryResponseGroup.ResponseGroup.Variations);
                                Entry catEntry = CatalogContext.Current.GetCatalogEntry(entry.CatalogEntryCode, responseGroup);
                                giftLineItem = AddNewGiftLineItemToOrder(order, catEntry, entry.Quantity);
                                AddGiftItemToAShipment(giftLineItem);
                                CatalogEntryDto entryDto = CatalogContext.Current.GetCatalogEntryDto(giftLineItem.Code, responseGroup);
                                CatalogEntryDto.CatalogEntryRow entryRow = entryDto.CatalogEntry[0];
                                Money? price = GetItemPrice(entryRow, giftLineItem, CustomerContext.Current.CurrentContact);
                                giftLineItem.ListPrice = price.HasValue ? price.Value.Amount : 0m;
                                giftLineItem.PlacedPrice = giftLineItem.ListPrice;
                                // populate inventory information for giftLineItem
                                IWarehouseInventory aggregateInventory = ServiceLocator.Current.GetInstance<IWarehouseInventoryService>().GetTotal(new CatalogKey(entryRow));
                                PopulateInventoryInfo(aggregateInventory, giftLineItem);
                            }
                            else
                            {
                                giftLineItem.Quantity = Math.Max(entry.Quantity, giftLineItem.Quantity);
                            }
                        }
                        else
                        {
                            entry.Quantity = giftLineItem != null ? Math.Min(entry.Quantity, giftLineItem.Quantity) : entry.Quantity;
                        }
                        entry.Owner = giftLineItem;
                        entry.CostPerEntry = giftLineItem != null ? giftLineItem.ListPrice : 0m;
                    }
                }
            }
        }
Exemple #13
0
 /// <summary>
 /// Adds the promotion item record.
 /// </summary>
 /// <param name="record">The record.</param>
 /// <returns></returns>
 public PromotionItemRecord AddPromotionItemRecord(PromotionItemRecord record)
 {
     PromotionContext.PromotionResult.PromotionRecords.Add(record);
     return(record);
 }
Exemple #14
0
        private LineItem FindGiftLineItemInOrder(OrderGroup order, string catalogEntryId, PromotionItemRecord promoRecord)
        {
            var lineItems = order.OrderForms[0].LineItems.ToArray().Where(x => x.Code == catalogEntryId);

            foreach (var lineitem in lineItems)
            {
                foreach (LineItemDiscount discount in lineitem.Discounts)
                {
                    if (discount.DiscountName == GetGiftPromotionName(promoRecord))
                    {
                        return(lineitem);
                    }
                }
            }
            return(null);
        }
Exemple #15
0
        private void AddDiscountToLineItem(OrderGroup order, PromotionItemRecord itemRecord, PromotionEntry promotionEntry,
                                           decimal itemDiscount, decimal orderLevelDiscount)
        {
            itemDiscount       = _currency.Round(itemDiscount);
            orderLevelDiscount = _currency.Round(orderLevelDiscount);
            LineItem item = FindLineItemByPromotionEntry(order, promotionEntry);

            if (item != null)
            {
                //reset gift line item discount
                if (IsGiftLineItem(item))
                {
                    item.PlacedPrice              = promotionEntry.CostPerEntry;
                    item.LineItemDiscountAmount   = itemDiscount;
                    item.OrderLevelDiscountAmount = 0;
                    item.ExtendedPrice            = item.PlacedPrice;
                }
                else
                {
                    // Add line item properties
                    item.LineItemDiscountAmount   += itemDiscount;
                    item.OrderLevelDiscountAmount += orderLevelDiscount;
                    item.ExtendedPrice             = item.PlacedPrice * item.Quantity - item.LineItemDiscountAmount - item.OrderLevelDiscountAmount;
                }

                if (itemRecord.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Entry).Key, StringComparison.OrdinalIgnoreCase) ||
                    itemRecord.PromotionReward is GiftPromotionReward ||
                    (itemRecord.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Order).Key,
                                                                            StringComparison.OrdinalIgnoreCase) && itemRecord.PromotionReward.RewardType == PromotionRewardType.EachAffectedEntry))
                {
                    LineItemDiscount discount = FindLineItemDiscountById(order, itemRecord.PromotionItem.DataRow.PromotionId, item.LineItemId);

                    if (discount == null)
                    {
                        discount = new LineItemDiscount();
                        item.Discounts.Add(discount);
                    }

                    var discountName = itemRecord.PromotionItem.DataRow.Name;
                    if (itemRecord.PromotionReward is GiftPromotionReward)
                    {
                        discount.DiscountName = GetGiftPromotionName(itemRecord);
                    }
                    else
                    {
                        discount.DiscountName = String.Format("{0}{1}", itemRecord.PromotionItem.DataRow.Name,
                                                              itemRecord.PromotionItem.DataRow.OfferType == 1 ? ":PercentageBased" : ":ValueBased");
                    }

                    discount.DiscountAmount = itemRecord.PromotionReward.AmountOff;
                    discount.DiscountCode   = itemRecord.PromotionItem.DataRow.CouponCode;

                    discount.DiscountValue = itemDiscount;
                    // use the promotion name if the localized display message is null or empty
                    discount.DisplayMessage = GetDisplayName(itemRecord.PromotionItem.DataRow, Thread.CurrentThread.CurrentCulture.Name);
                    if (string.IsNullOrEmpty(discount.DisplayMessage))
                    {
                        discount.DisplayMessage = itemRecord.PromotionItem.DataRow.Name;
                    }
                    discount.LineItemId = item.LineItemId;
                    discount.DiscountId = itemRecord.PromotionItem.DataRow.PromotionId;
                }
            }
        }
Exemple #16
0
        /// <summary>
        /// Applies the item discount.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <param name="record">The record.</param>
        /// <param name="totalAmount">The total amount.</param>
        /// <returns></returns>
        private decimal ApplyItemDiscount(OrderGroup order, PromotionItemRecord record, decimal totalAmount)
        {
            decimal discountAmount = 0;

            if (record.PromotionReward.RewardType == PromotionRewardType.AllAffectedEntries)
            {
                decimal averageDiscountAmount;
                if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                {
                    discountAmount        = _currency.Percentage(record.AffectedEntriesSet.TotalCost, record.PromotionReward.AmountOff);
                    averageDiscountAmount = discountAmount / record.AffectedEntriesSet.TotalQuantity;
                }
                else // need to split discount between all items
                {
                    discountAmount        = record.PromotionReward.AmountOff;
                    averageDiscountAmount = record.PromotionReward.AmountOff / record.AffectedEntriesSet.TotalQuantity;
                }

                foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                {
                    AddDiscountToLineItem(order, record, entry, averageDiscountAmount * entry.Quantity, 0);
                }
            }
            else if (record.PromotionReward.RewardType == PromotionRewardType.EachAffectedEntry)
            {
                if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                {
                    discountAmount = _currency.Percentage(record.AffectedEntriesSet.TotalCost, record.PromotionReward.AmountOff);
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        AddDiscountToLineItem(order, record, entry, entry.CostPerEntry * entry.Quantity * record.PromotionReward.AmountOff / 100, 0);
                    }
                }
                else
                {
                    discountAmount = record.AffectedEntriesSet.TotalQuantity * record.PromotionReward.AmountOff;
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        AddDiscountToLineItem(order, record, entry, record.PromotionReward.AmountOff * entry.Quantity, 0);
                    }
                }
            }
            else if (record.PromotionReward.RewardType == PromotionRewardType.WholeOrder)
            {
                decimal percentageOffTotal = 0;
                if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                {
                    decimal extendedCost = 0;
                    foreach (OrderForm orderForm in order.OrderForms)
                    {
                        extendedCost += orderForm.LineItems.ToArray().Sum(x => x.ExtendedPrice);
                    }
                    // calculate percentage adjusted by the running amount, so it will be a little less if running amount is less than total
                    percentageOffTotal = (record.PromotionReward.AmountOff / 100) * (totalAmount / extendedCost);
                    discountAmount     = _currency.Percentage(totalAmount, record.PromotionReward.AmountOff);
                }
                else
                {
                    // Calculate percentage off discount price
                    if (totalAmount > 0)
                    {
                        percentageOffTotal = record.PromotionReward.AmountOff / totalAmount;
                        // but since CostPerEntry is not an adjusted price, we need to take into account additional discounts already applied
                        percentageOffTotal = percentageOffTotal * (totalAmount / record.AffectedEntriesSet.TotalCost);
                        discountAmount     = record.PromotionReward.AmountOff;
                    }
                    else
                    {
                        percentageOffTotal = 100m;
                        discountAmount     = 0;
                    }
                }

                // Now distribute discount amount evenly over all entries taking into account running total
                // Special case for shipments, we consider WholeOrder to be a shipment
                if (!record.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Shipping).Key, StringComparison.OrdinalIgnoreCase))
                {
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        LineItem item = FindLineItemByPromotionEntry(order, entry);
                        var      orderLevelDiscount = _currency.Round(item.ExtendedPrice * percentageOffTotal);
                        AddDiscountToLineItem(order, record, entry, 0, orderLevelDiscount);
                    }
                }
            }

            // Save discounts
            if (record.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Order).Key, StringComparison.OrdinalIgnoreCase) ||
                record.PromotionReward is GiftPromotionReward)
            {
                if (record.PromotionReward.RewardType == PromotionRewardType.WholeOrder && discountAmount > 0)
                {
                    OrderFormDiscount discount = FindOrderFormDiscountById(order, record.PromotionItem.DataRow.PromotionId, Int32.Parse(record.AffectedEntriesSet.OrderFormId));
                    bool hasOrderFormDiscount  = true;
                    if (discount == null)
                    {
                        discount             = new OrderFormDiscount();
                        hasOrderFormDiscount = false;
                    }

                    var discountName = record.PromotionItem.DataRow.Name;
                    if (record.PromotionReward is GiftPromotionReward)
                    {
                        discountName = GetGiftPromotionName(record);
                    }
                    discount.DiscountName = discountName;

                    discount.DiscountAmount = record.PromotionReward.AmountOff;
                    discount.DiscountCode   = record.PromotionItem.DataRow.CouponCode;
                    discount.DiscountValue  = hasOrderFormDiscount ? discountAmount + discount.DiscountValue : discountAmount;
                    discount.DisplayMessage = GetDisplayName(record.PromotionItem.DataRow, Thread.CurrentThread.CurrentCulture.Name);
                    discount.OrderFormId    = Int32.Parse(record.AffectedEntriesSet.OrderFormId);
                    discount.DiscountId     = record.PromotionItem.DataRow.PromotionId;

                    foreach (OrderForm form in order.OrderForms)
                    {
                        if (form.OrderFormId == discount.OrderFormId && !hasOrderFormDiscount)
                        {
                            form.Discounts.Add(discount);
                        }
                    }
                }
            }
            else if (record.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Shipping).Key, StringComparison.OrdinalIgnoreCase))
            {
                ShipmentDiscount discount = FindShipmentDiscountById(order, record.PromotionItem.DataRow.PromotionId, Int32.Parse(record.AffectedEntriesSet.ShipmentId));

                if (discount == null)
                {
                    discount = new ShipmentDiscount();
                }

                discount.DiscountAmount = record.PromotionReward.AmountOff;
                discount.DiscountCode   = record.PromotionItem.DataRow.CouponCode;
                discount.DiscountName   = record.PromotionItem.DataRow.Name;
                discount.DisplayMessage = GetDisplayName(record.PromotionItem.DataRow, Thread.CurrentThread.CurrentCulture.Name);
                discount.ShipmentId     = Int32.Parse(record.AffectedEntriesSet.ShipmentId);
                discount.DiscountId     = record.PromotionItem.DataRow.PromotionId;

                var shipment = order.OrderForms.SelectMany(o => o.Shipments).FirstOrDefault(s => s.ShipmentId == discount.ShipmentId);
                if (shipment != null)
                {
                    shipment.Discounts.Add(discount);

                    if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                    {
                        discountAmount = _currency.Percentage(shipment.ShippingSubTotal, record.PromotionReward.AmountOff);
                    }
                    else
                    {
                        // PromotionReward.AmountOff was calculated in Promotion context, it's not be rounded.
                        discountAmount = _currency.Round(Math.Min(record.PromotionReward.AmountOff, shipment.ShippingSubTotal));
                    }

                    shipment.ShippingDiscountAmount = Math.Min(shipment.ShippingDiscountAmount + discountAmount, shipment.ShippingSubTotal);
                    // ShippingDiscountAmount will not be subtracted from the ShipmentTotal per discussions on 2/22/2012.
                }
                discount.DiscountValue = discountAmount;
            }
            return(discountAmount);
        }
Exemple #17
0
 /// <summary>
 /// Gets the name of the gift promotion.
 /// </summary>
 /// <param name="promoRecord">The promo record.</param>
 /// <returns></returns>
 public string GetGiftPromotionName(PromotionItemRecord promoRecord)
 {
     return("@" + promoRecord.PromotionItem.DataRow.Name + ":Gift");
 }
Exemple #18
0
 /// <summary>
 /// Adds the promotion item record.
 /// </summary>
 /// <param name="record">The record.</param>
 public void AddPromotionItemRecord(PromotionItemRecord record)
 {
     PromotionResult.PromotionRecords.Add(record);
 }
Exemple #19
0
        /// <summary>
        /// Evaluates the promotions.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="promotions">The promotions.</param>
        /// <param name="filter">The filter.</param>
        /// <returns>Collection of promotions that were applied. Look inside PromotionContext for actual rewards and for items
        /// that have been affected by these promotions.</returns>
        public PromotionItemCollection EvaluatePromotions(PromotionContext context, PromotionItemCollection promotions, PromotionFilter filter)
        {
            // Start checking discounts
            List <int> rowIndexes = new List <int>();

            // Retrieve all the coupons customer entered
            List <string> coupons = context.Coupons;

            // Retrieve customer segments, it should be initialized beforehand
            List <int> segments = context.Segments;

            // Retrieve customer id, it should be initialized beforehand
            Guid customerId = context.CustomerId;

            foreach (PromotionItem item in promotions)
            {
                // Set currently executed promotion
                context.CurrentPromotion = item;

                // If discount is global and other discount has been applied already, skip it
                if (item.DataRow.ExclusivityType.Equals(ExclusionType.GlobalLevel) && rowIndexes.Count != 0)
                {
                    continue;
                }

                // Check if it belongs to a group specified
                if (!String.IsNullOrEmpty(context.TargetGroup) && !context.TargetGroup.Equals(item.DataRow.PromotionGroup, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                // Check group exclusivity
                if (context.ExclusiveGroups.Contains(item.DataRow.PromotionGroup))
                {
                    continue;
                }

                // Check limits here
                int currentOrderPromotionCount = context.PromotionResult.GetCount(item.DataRow.PromotionId);

                // Start with per order limit
                if (item.DataRow.PerOrderLimit > 0 && currentOrderPromotionCount >= item.DataRow.PerOrderLimit)
                {
                    continue;
                }

                // Check application limit limit, only check when limit is set
                if (item.DataRow.ApplicationLimit > 0 && item.TotalUsedCount - context.ReservedCount + currentOrderPromotionCount >= item.DataRow.ApplicationLimit)
                {
                    continue;
                }

                // Check customer limit, only check when limit is set and customer id is set
                if ((item.DataRow.CustomerLimit > 0 && customerId == Guid.Empty) || item.DataRow.CustomerLimit > 0 && item.GetCustomerUsageCount(customerId) - context.ReservedCount + currentOrderPromotionCount >= item.DataRow.CustomerLimit)
                {
                    continue;
                }

                // First do simply checks that will take little time and save us from wasting processor time
                // -----------------------------------------------------------------------------------------
                if (!filter.IncludeInactive)
                {
                    // Skip if start date is past now
                    if (!item.Campaign.IsActive)
                    {
                        continue;
                    }

                    if (item.Campaign.StartDate > FrameworkContext.Current.CurrentDateTime)
                    {
                        continue;
                    }

                    // Skip if end date is in the past
                    if (item.Campaign.EndDate < FrameworkContext.Current.CurrentDateTime)
                    {
                        continue;
                    }

                    // Skip if start date is past now
                    if (item.DataRow.StartDate > FrameworkContext.Current.CurrentDateTime)
                    {
                        continue;
                    }

                    // Skip if end date is in the past
                    if (item.DataRow.EndDate < FrameworkContext.Current.CurrentDateTime)
                    {
                        continue;
                    }

                    // Check promotion status
                    if (!item.DataRow.Status.Equals(PromotionStatus.Active))
                    {
                        continue;
                    }
                }

                if (!filter.IncludeCoupons)
                {
                    // Check coupons
                    string couponCode = item.DataRow.CouponCode;
                    if (!String.IsNullOrEmpty(couponCode))
                    {
                        if (coupons == null)
                        {
                            continue;
                        }

                        bool foundCoupon = false;
                        foreach (string coupon in coupons)
                        {
                            if (couponCode.Equals(coupon, StringComparison.OrdinalIgnoreCase))
                            {
                                foundCoupon = true;
                            }
                        }

                        if (!foundCoupon)
                        {
                            continue;
                        }
                    }
                }

                // Check catalog / node / entry filtering
                if (context.TargetEntriesSet.Entries.Count > 0)
                {
                    bool isValid = true;
                    foreach (PromotionEntry entry in context.TargetEntriesSet.Entries)
                    {
                        string catalogEntryId = entry.CatalogEntryCode;
                        string catalogNodeId  = entry.CatalogNodeCode;
                        string catalogName    = entry.CatalogName;

                        if (!String.IsNullOrEmpty(catalogEntryId) || !String.IsNullOrEmpty(catalogNodeId) || !String.IsNullOrEmpty(catalogName))
                        {
                            PromotionDto.PromotionConditionRow[] conditions = item.DataRow.GetPromotionConditionRows();
                            if (conditions != null && conditions.Length > 0)
                            {
                                foreach (PromotionDto.PromotionConditionRow condition in conditions)
                                {
                                    if (!String.IsNullOrEmpty(catalogEntryId) && !condition.IsCatalogEntryIdNull() && !condition.CatalogEntryId.Equals(catalogEntryId))
                                    {
                                        isValid = false;
                                        break;
                                    }
                                    else if (!String.IsNullOrEmpty(catalogNodeId) && !condition.IsCatalogNodeIdNull() && !condition.CatalogNodeId.Equals(catalogNodeId))
                                    {
                                        isValid = false;
                                        break;
                                    }
                                    else if (!String.IsNullOrEmpty(catalogName) && !condition.IsCatalogNameNull() && !condition.CatalogName.Equals(catalogName))
                                    {
                                        isValid = false;
                                        break;
                                    }
                                }

                                if (!isValid)
                                {
                                    continue;
                                }
                            }
                        }
                    }
                    if (!isValid)
                    {
                        continue;
                    }
                }


                // Start doing more expensive checks here
                // -----------------------------------------------------------------------------------------
                if (!filter.IgnoreSegments)
                {
                    // Check customer segments, customer should belong to a segment for promotion to apply
                    CampaignDto.CampaignSegmentRow[] segmentRows = item.Campaign.GetCampaignSegmentRows();

                    // if there are no segments defined assume it applies to everyone
                    if (segmentRows != null && segmentRows.Length > 0)
                    {
                        // customer is not within any segment, so promotion does not apply
                        if (segments == null || segments.Count == 0)
                        {
                            continue;
                        }

                        // start checking segments
                        bool apply = false;
                        foreach (CampaignDto.CampaignSegmentRow row in segmentRows)
                        {
                            if (segments.Contains(row.SegmentId))
                            {
                                // mark promotion as apply and leave loop
                                apply = true;
                                break;
                            }
                        }

                        // if does not apply continue with a next promotion
                        if (!apply)
                        {
                            continue;
                        }
                    }
                }

                if (!filter.IgnoreConditions)
                {
                    // Validate expressions
                    if (item.Expressions.Count > 0)
                    {
                        bool isValid = true;
                        foreach (ExpressionDto.ExpressionRow expression in item.Expressions)
                        {
                            if (!String.IsNullOrEmpty(expression.ExpressionXml))
                            {
                                ValidationResult result = ValidateExpression(expression.ApplicationId.ToString() + "-" + expression.Category + "-" + expression.ExpressionId.ToString(), expression.ExpressionXml, context);
                                if (!result.IsValid)
                                {
                                    isValid = false;
                                    break;
                                }
                            }
                        }

                        if (!isValid)
                        {
                            continue;
                        }
                    }
                }
                else
                {
                    // Create Award manually based on default settings
                    PromotionReward     reward = new PromotionReward(PromotionRewardType.EachAffectedEntry, item.DataRow.OfferAmount, item.DataRow.OfferType == 0 ? PromotionRewardAmountType.Percentage : PromotionRewardAmountType.Value);
                    PromotionItemRecord record = new PromotionItemRecord(context.TargetEntriesSet, context.TargetEntriesSet, reward);
                    record.PromotionItem = context.CurrentPromotion;
                    context.PromotionResult.PromotionRecords.Add(record);
                }

                if (!filter.IgnorePolicy)
                {
                    // Validate store policies
                    if (item.PolicyExpressions.Count > 0)
                    {
                        bool isValid = true;
                        foreach (ExpressionDto.ExpressionRow expression in item.PolicyExpressions)
                        {
                            if (!String.IsNullOrEmpty(expression.ExpressionXml))
                            {
                                ValidationResult result = ValidateExpression(expression.ApplicationId.ToString() + "-" + expression.Category + "-" + expression.ExpressionId.ToString(), expression.ExpressionXml, context);
                                if (!result.IsValid)
                                {
                                    isValid = false;
                                    break;
                                }
                            }
                        }

                        if (!isValid)
                        {
                            // Invalidates all records added during this evaluation sequence
                            context.RejectRecords();
                            continue;
                        }
                    }
                }

                // Commits all records added during this evaluation sequence
                context.CommitRecords();

                // Apply item
                rowIndexes.Add(item.RowIndex);

                // Add item to a group if it is applied
                if (item.DataRow.ExclusivityType.Equals(ExclusionType.GroupLevel))
                {
                    context.ExclusiveGroups.Add(item.DataRow.PromotionGroup);
                }

                // Finish processing if global level item has been added
                if (item.DataRow.ExclusivityType.Equals(ExclusionType.GlobalLevel))
                {
                    break;
                }
            }

            // Assign curren promotion to null
            context.CurrentPromotion = null;

            return(new PromotionItemCollection(promotions, rowIndexes.ToArray()));
        }
 /// <summary>
 /// Gets the name of the gift promotion.
 /// </summary>
 /// <param name="promoRecord">The promo record.</param>
 /// <returns></returns>
 public string GetGiftPromotionName(PromotionItemRecord promoRecord)
 {
     return "@" + promoRecord.PromotionItem.DataRow.Name + ":Gift";
 }
 private decimal GetDiscountAmount(PromotionItemRecord record, PromotionReward reward)
 {
     decimal discountAmount = 0;
     if (reward.RewardType != PromotionRewardType.EachAffectedEntry && reward.RewardType != PromotionRewardType.AllAffectedEntries)
     {
         return Math.Round(discountAmount, 2);
     }
     if (reward.AmountType == PromotionRewardAmountType.Percentage)
     {
         discountAmount = record.AffectedEntriesSet.TotalCost * reward.AmountOff / 100;
     }
     else
     {
         discountAmount += reward.AmountOff;
     }
     return Math.Round(discountAmount, 2);
 }
Exemple #22
0
        /// <summary>
        /// Applies the item discount.
        /// </summary>
        /// <param name="order">The order.</param>
        /// <param name="record">The record.</param>
        /// <param name="totalAmount">The total amount.</param>
        /// <returns></returns>
        private decimal ApplyItemDiscount(OrderGroup order, PromotionItemRecord record, decimal totalAmount)
        {
            decimal discountAmount = 0;

            if (record.PromotionReward.RewardType == PromotionRewardType.AllAffectedEntries)
            {
                if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                {
                    discountAmount = record.AffectedEntriesSet.TotalCost * record.PromotionReward.AmountOff / 100;
                    decimal averageDiscountAmount = discountAmount / record.AffectedEntriesSet.TotalQuantity;
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        // Sasha: changed back, CostPerEntry does not change dynamically, while total cost does
                        // AddDiscountToLineItem(order, record, entry, entry.CostPerEntry * entry.Quantity * record.PromotionReward.AmountOff / 100m, 0);
                        // AddDiscountToLineItem(order, record, entry.CatalogEntryCode, averageDiscountAmount * entry.Quantity, 0);
                        AddDiscountToLineItem(order, record, entry, averageDiscountAmount * entry.Quantity, 0);
                    }
                }
                else // need to split discount between all items
                {
                    discountAmount = record.PromotionReward.AmountOff;
                    decimal averageDiscountAmount = record.PromotionReward.AmountOff / record.AffectedEntriesSet.TotalQuantity;
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        AddDiscountToLineItem(order, record, entry, averageDiscountAmount * entry.Quantity, 0);
                    }
                }
            }
            else if (record.PromotionReward.RewardType == PromotionRewardType.EachAffectedEntry)
            {
                if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                {
                    discountAmount = record.AffectedEntriesSet.TotalCost * record.PromotionReward.AmountOff / 100;
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        AddDiscountToLineItem(order, record, entry, entry.CostPerEntry * entry.Quantity * record.PromotionReward.AmountOff / 100, 0);
                    }
                }
                else
                {
                    discountAmount = record.AffectedEntriesSet.TotalQuantity * record.PromotionReward.AmountOff;
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        AddDiscountToLineItem(order, record, entry, record.PromotionReward.AmountOff * entry.Quantity, 0);
                    }
                }
            }
            else if (record.PromotionReward.RewardType == PromotionRewardType.WholeOrder)
            {
                decimal percentageOffTotal = 0;
                if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                {
                    // calculate percentage adjusted by the running amount, so it will be a little less if running amount is less than total
                    percentageOffTotal = (record.PromotionReward.AmountOff / 100) * (totalAmount / record.AffectedEntriesSet.TotalCost);
                    //percentageOffTotal = PromotionReward.AmountOff / 100;
                    discountAmount = totalAmount * record.PromotionReward.AmountOff / 100;
                }
                else
                {
                    // Calculate percentage off discount price
                    percentageOffTotal = record.PromotionReward.AmountOff / totalAmount;

                    // but since CostPerEntry is not an adjusted price, we need to take into account additional discounts already applied
                    percentageOffTotal = percentageOffTotal * (totalAmount / record.AffectedEntriesSet.TotalCost);

                    discountAmount = record.PromotionReward.AmountOff;
                }

                // Now distribute discount amount evenly over all entries taking into account running total
                // Special case for shipments, we consider WholeOrder to be a shipment
                if (!record.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Shipping).Key, StringComparison.OrdinalIgnoreCase))
                {
                    foreach (PromotionEntry entry in record.AffectedEntriesSet.Entries)
                    {
                        AddDiscountToLineItem(order, record, entry, 0, (((entry.CostPerEntry * entry.Quantity) /* - entry.Discount*/)) * percentageOffTotal);
                    }
                }
            }

            // Save discounts
            if (record.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Order).Key, StringComparison.OrdinalIgnoreCase) ||
                record.PromotionReward is GiftPromotionReward)
            {
                if (record.PromotionReward.RewardType == PromotionRewardType.WholeOrder)
                {
                    OrderFormDiscount discount = FindOrderFormDiscountById(order, record.PromotionItem.DataRow.PromotionId, Int32.Parse(record.AffectedEntriesSet.OrderFormId));
                    bool hasOrderFormDiscount  = true;
                    if (discount == null)
                    {
                        discount             = new OrderFormDiscount();
                        hasOrderFormDiscount = false;
                    }

                    var discountName = record.PromotionItem.DataRow.Name;
                    if (record.PromotionReward is GiftPromotionReward)
                    {
                        discountName = GetGiftPromotionName(record);
                    }
                    discount.DiscountName = discountName;

                    discount.DiscountAmount = record.PromotionReward.AmountOff;
                    discount.DiscountCode   = record.PromotionItem.DataRow.CouponCode;
                    discount.DiscountValue  = hasOrderFormDiscount ? discountAmount + discount.DiscountValue : discountAmount;
                    discount.DisplayMessage = GetDisplayName(record.PromotionItem.DataRow, Thread.CurrentThread.CurrentCulture.Name);
                    discount.OrderFormId    = Int32.Parse(record.AffectedEntriesSet.OrderFormId);
                    discount.DiscountId     = record.PromotionItem.DataRow.PromotionId;

                    foreach (OrderForm form in order.OrderForms)
                    {
                        if (form.OrderFormId == discount.OrderFormId && !hasOrderFormDiscount)
                        {
                            form.Discounts.Add(discount);
                        }
                    }
                }
            }
            else if (record.PromotionItem.DataRow.PromotionGroup.Equals(PromotionGroup.GetPromotionGroup(PromotionGroup.PromotionGroupKey.Shipping).Key, StringComparison.OrdinalIgnoreCase))
            {
                ShipmentDiscount discount = FindShipmentDiscountById(order, record.PromotionItem.DataRow.PromotionId, Int32.Parse(record.AffectedEntriesSet.ShipmentId));

                if (discount == null)
                {
                    discount = new ShipmentDiscount();
                }

                discount.DiscountAmount = record.PromotionReward.AmountOff;
                discount.DiscountCode   = record.PromotionItem.DataRow.CouponCode;
                discount.DiscountName   = record.PromotionItem.DataRow.Name;
                discount.DisplayMessage = GetDisplayName(record.PromotionItem.DataRow, Thread.CurrentThread.CurrentCulture.Name);
                discount.ShipmentId     = Int32.Parse(record.AffectedEntriesSet.ShipmentId);
                discount.DiscountId     = record.PromotionItem.DataRow.PromotionId;

                foreach (OrderForm form in order.OrderForms)
                {
                    foreach (Shipment shipment in form.Shipments)
                    {
                        if (shipment.ShipmentId == discount.ShipmentId)
                        {
                            shipment.Discounts.Add(discount);

                            if (record.PromotionReward.AmountType == PromotionRewardAmountType.Percentage)
                            {
                                discountAmount = shipment.ShipmentTotal * record.PromotionReward.AmountOff / 100;
                            }
                            else
                            {
                                discountAmount = Math.Min(record.PromotionReward.AmountOff, shipment.ShipmentTotal);
                            }

                            shipment.ShippingDiscountAmount += discountAmount;
                            // ShippingDiscountAmount will not be subtracted from the ShipmentTotal per discussions on 2/22/2012.
                            break;
                        }
                    }
                }
                discount.DiscountValue = discountAmount;
            }
            return(discountAmount);
        }