public static VolumeDiscount Load(Int32 volumeDiscountId, bool useCache)
        {
            if (volumeDiscountId == 0)
            {
                return(null);
            }
            VolumeDiscount volumeDiscount = null;
            string         key            = "VolumeDiscount_" + volumeDiscountId.ToString();

            if (useCache)
            {
                volumeDiscount = ContextCache.GetObject(key) as VolumeDiscount;
                if (volumeDiscount != null)
                {
                    return(volumeDiscount);
                }
            }
            volumeDiscount = new VolumeDiscount();
            if (volumeDiscount.Load(volumeDiscountId))
            {
                if (useCache)
                {
                    ContextCache.SetObject(key, volumeDiscount);
                }
                return(volumeDiscount);
            }
            return(null);
        }
Beispiel #2
0
        /// <summary>
        /// Creates a copy of a volume discount
        /// </summary>
        /// <param name="volumeDiscountId">Id of the volume discount of which to create a copy</param>
        /// <param name="deepCopy">If <b>true</b> all child references are also copied</param>
        /// <returns>Copy of the given volume discount</returns>
        public static VolumeDiscount Copy(int volumeDiscountId, bool deepCopy)
        {
            //LOAD COPY (NO CACHE)
            VolumeDiscount source = new VolumeDiscount();

            if (source.Load(volumeDiscountId))
            {
                //IF DEEP COPY, RESET ALL CHILD REFERENCES
                if (deepCopy)
                {
                    foreach (VolumeDiscountLevel child in source.Levels)
                    {
                        child.VolumeDiscountLevelId = 0;
                        child.VolumeDiscountId      = 0;
                    }
                    foreach (VolumeDiscountGroup child in source.VolumeDiscountGroups)
                    {
                        child.VolumeDiscountId = 0;
                    }
                    foreach (CategoryVolumeDiscount child in source.CategoryVolumeDiscounts)
                    {
                        child.VolumeDiscountId = 0;
                    }
                    foreach (ProductVolumeDiscount child in source.ProductVolumeDiscounts)
                    {
                        child.VolumeDiscountId = 0;
                    }
                }
                source.VolumeDiscountId = 0;
                source.Save();
                return(source);
            }
            return(null);
        }
        public static bool Delete(Int32 volumeDiscountId)
        {
            VolumeDiscount volumeDiscount = new VolumeDiscount();

            if (volumeDiscount.Load(volumeDiscountId))
            {
                return(volumeDiscount.Delete());
            }
            return(false);
        }
 /// <summary>
 /// Loads the given VolumeDiscount object from the given database data reader.
 /// </summary>
 /// <param name="volumeDiscount">The VolumeDiscount object to load.</param>
 /// <param name="dr">The database data reader to read data from.</param>
 public static void LoadDataReader(VolumeDiscount volumeDiscount, IDataReader dr)
 {
     //SET FIELDS FROM ROW DATA
     volumeDiscount.VolumeDiscountId = dr.GetInt32(0);
     volumeDiscount.StoreId          = dr.GetInt32(1);
     volumeDiscount.Name             = dr.GetString(2);
     volumeDiscount.IsValueBased     = dr.GetBoolean(3);
     volumeDiscount.IsGlobal         = dr.GetBoolean(4);
     volumeDiscount.IsDirty          = false;
 }
        public static VolumeDiscountCollection LoadForGroup(Int32 groupId, int maximumRows, int startRowIndex, string sortExpression)
        {
            //CREATE THE DYNAMIC SQL TO LOAD OBJECT
            StringBuilder selectQuery = new StringBuilder();

            selectQuery.Append("SELECT");
            if (maximumRows > 0)
            {
                selectQuery.Append(" TOP " + (startRowIndex + maximumRows).ToString());
            }
            selectQuery.Append(" " + VolumeDiscount.GetColumnNames("ac_VolumeDiscounts"));
            selectQuery.Append(" FROM ac_VolumeDiscounts, ac_VolumeDiscountGroups");
            selectQuery.Append(" WHERE ac_VolumeDiscounts.VolumeDiscountId = ac_VolumeDiscountGroups.VolumeDiscountId");
            selectQuery.Append(" AND ac_VolumeDiscountGroups.GroupId = @groupId");
            selectQuery.Append(" AND StoreId = @storeId");
            if (!string.IsNullOrEmpty(sortExpression))
            {
                selectQuery.Append(" ORDER BY " + sortExpression);
            }
            Database  database      = Token.Instance.Database;
            DbCommand selectCommand = database.GetSqlStringCommand(selectQuery.ToString());

            database.AddInParameter(selectCommand, "@groupId", System.Data.DbType.Int32, groupId);
            database.AddInParameter(selectCommand, "@storeId", System.Data.DbType.Int32, Token.Instance.StoreId);
            //EXECUTE THE COMMAND
            VolumeDiscountCollection results = new VolumeDiscountCollection();
            int thisIndex = 0;
            int rowCount  = 0;

            using (IDataReader dr = database.ExecuteReader(selectCommand))
            {
                while (dr.Read() && ((maximumRows < 1) || (rowCount < maximumRows)))
                {
                    if (thisIndex >= startRowIndex)
                    {
                        VolumeDiscount volumeDiscount = new VolumeDiscount();
                        VolumeDiscount.LoadDataReader(volumeDiscount, dr);
                        results.Add(volumeDiscount);
                        rowCount++;
                    }
                    thisIndex++;
                }
                dr.Close();
            }
            return(results);
        }
        public static VolumeDiscountCollection  LoadForCriteria(string sqlCriteria, int maximumRows, int startRowIndex, string sortExpression)
        {
            //CREATE THE DYNAMIC SQL TO LOAD OBJECT
            StringBuilder selectQuery = new StringBuilder();

            selectQuery.Append("SELECT");
            if (maximumRows > 0)
            {
                selectQuery.Append(" TOP " + (startRowIndex + maximumRows).ToString());
            }
            selectQuery.Append(" " + VolumeDiscount.GetColumnNames(string.Empty));
            selectQuery.Append(" FROM ac_VolumeDiscounts");
            string whereClause = string.IsNullOrEmpty(sqlCriteria) ? string.Empty : " WHERE " + sqlCriteria;

            selectQuery.Append(whereClause);
            if (!string.IsNullOrEmpty(sortExpression))
            {
                selectQuery.Append(" ORDER BY " + sortExpression);
            }
            Database  database      = Token.Instance.Database;
            DbCommand selectCommand = database.GetSqlStringCommand(selectQuery.ToString());
            //EXECUTE THE COMMAND
            VolumeDiscountCollection results = new VolumeDiscountCollection();
            int thisIndex = 0;
            int rowCount  = 0;

            using (IDataReader dr = database.ExecuteReader(selectCommand))
            {
                while (dr.Read() && ((maximumRows < 1) || (rowCount < maximumRows)))
                {
                    if (thisIndex >= startRowIndex)
                    {
                        VolumeDiscount volumeDiscount = new VolumeDiscount();
                        VolumeDiscount.LoadDataReader(volumeDiscount, dr);
                        results.Add(volumeDiscount);
                        rowCount++;
                    }
                    thisIndex++;
                }
                dr.Close();
            }
            return(results);
        }
        /// <summary>
        /// Gets a dictionary of potential discounts for the basket.
        /// </summary>
        /// <param name="basket">Basket to check for potential discounts</param>
        /// <param name="productsToExclude">Products that should not be considered for discounts.</param>
        /// <param name="groupingMode">Grouping mode in use</param>
        /// <returns>A dictionary of potential discounts for the order.</returns>
        private static Dictionary <int, List <PotentialDiscount> > GetPotentialDiscounts(Basket basket, List <int> productsToExclude, GroupingMode groupingMode)
        {
            //INITIALIZE THE RETURN VALUE
            Dictionary <int, List <PotentialDiscount> > potentialDiscounts = new Dictionary <int, List <PotentialDiscount> >();

            //KEEP TRACK OF PRODUCTS TO EXCLUDE FROM GLOBAL DISCOUNTS
            List <int> excludeGlobal = new List <int>();

            //BUILD CRITERIA FOR PRODUCTS TO EXCLUDE FROM QUERY
            string excludedProducts = string.Empty;

            if (productsToExclude.Count > 0)
            {
                if (productsToExclude.Count == 1)
                {
                    excludedProducts = " AND ProductId <> " + productsToExclude[0].ToString();
                }
                else
                {
                    excludedProducts = " AND ProductId NOT IN (" + AlwaysConvert.ToList(",", productsToExclude.ToArray()) + ")";
                }
                //ALSO EXCLUDE THESE PRODUCTS FROM GLOBAL DISCOUNTS
                excludeGlobal.AddRange(productsToExclude);
            }

            //FIND ALL DISCOUNTS THAT ARE ASSOCIATED WITH PRODUCTS IN THE BASKET
            StringBuilder categorySql = new StringBuilder();

            categorySql.Append("SELECT DISTINCT CP.ParentId, CP.ParentLevel, CVD.VolumeDiscountId");
            if (groupingMode == GroupingMode.Product)
            {
                categorySql.Append(", CN.CatalogNodeId");
            }
            categorySql.Append(" FROM (ac_BasketItems BI INNER JOIN ac_CatalogNodes CN ON BI.ProductId = CN.CatalogNodeId");
            categorySql.Append(" INNER JOIN ac_CategoryParents CP ON CN.CategoryId = CP.CategoryId");
            categorySql.Append(" INNER JOIN ac_CategoryVolumeDiscounts CVD ON CP.ParentId = CVD.CategoryId)");
            categorySql.Append(" WHERE BI.BasketId = @basketId ");
            categorySql.Append(" AND CN.CatalogNodeTypeId = 1");
            categorySql.Append(excludedProducts);
            //ORDER FROM THE MOST SPECIFIC CATEGORY TO THE LEAST (PARENTLEVEL)
            categorySql.Append(" ORDER BY CP.ParentLevel DESC");
            if (groupingMode == GroupingMode.Product)
            {
                categorySql.Append(", CN.CatalogNodeId ASC");
            }

            //CREATE THE COMMAND
            Database  database = Token.Instance.Database;
            DbCommand command  = database.GetSqlStringCommand(categorySql.ToString());

            database.AddInParameter(command, "@basketId", System.Data.DbType.Int32, basket.BasketId);
            DataSet allDiscounts = database.ExecuteDataSet(command);

            //LOOP ALL DISCOUNTS, BUILD LIST OF POTENTIAL DISCOUNTS THAT COULD APPLY TO USER
            User user = basket.User;

            foreach (DataRow row in allDiscounts.Tables[0].Rows)
            {
                //GET THE DISCOUNTED OBJECT (EITHER PRODUCT OR CATEGORY LEVEL)
                int key;
                if (groupingMode == GroupingMode.Product)
                {
                    key = (int)row[3];
                }
                else
                {
                    key = Convert.ToInt32((byte)row[1]);
                }

                //GET THE LEVEL OF THE CATEGORY (DETERMINES PRECEDENCE)
                int categoryLevel = Convert.ToInt32((byte)row[1]);

                //FIND THE LIST OF POTENTIAL DISCOUNTS FOR THIS KEY
                if (!potentialDiscounts.ContainsKey(key))
                {
                    potentialDiscounts[key] = new List <PotentialDiscount>();
                }
                List <PotentialDiscount> discountGroup = potentialDiscounts[key];

                //DECIDE WHETHER THIS DISCOUNT HAS ENOUGH PRECDENCE TO CHECK
                bool checkDiscount = true;
                if (discountGroup.Count > 0)
                {
                    //THE CURRENT ROW COULD HAVE THE SAME LEVEL AS THE DISCOUNTS ALREADY FOUND
                    if (categoryLevel < discountGroup[0].CategoryLevel)
                    {
                        checkDiscount = false;
                    }
                    //WE DO NOT HAVE TO CHECK FOR LEVEL BEING GREATER, BECAUSE
                    //THE QUERY INCLUDES PARENT LEVEL IN THE ORDERBY CLAUSE
                }

                if (checkDiscount)
                {
                    //THIS COULD BE A VALID DISCOUNT
                    int volumeDiscountId = (int)row[2];
                    //CHECK FOR USER EXCLUSIONS
                    VolumeDiscount v = VolumeDiscountDataSource.Load(volumeDiscountId);
                    if ((v != null) && (v.IsValidForUser(user)))
                    {
                        //THE DISCOUNT IS VALID FOR THIS USER
                        //ADD TO THE LIST OF POTENTIALS
                        PotentialDiscount pd = new PotentialDiscount();
                        pd.CategoryId       = (int)row[0];
                        pd.CategoryLevel    = categoryLevel;
                        pd.VolumeDiscountId = volumeDiscountId;
                        if (groupingMode == GroupingMode.Product)
                        {
                            pd.ProductId = key;
                            //SINCE THERE IS A CATEGORY DISCOUNT, WE DO
                            //NOT WANT TO USE ANY GLOBAL DISCOUNTS FOR THIS PRODUCT
                            excludeGlobal.Add(key);
                        }
                        discountGroup.Add(pd);
                    }
                }
            }

            List <int> globalDiscountProducts = new List <int>();

            if (groupingMode == GroupingMode.Product)
            {
                //CHECK WHETHER ANY PRODUCTS REMAIN IN ORDER THAT ARE ELIGIBLE
                //FOR GLOBAL DISCOUNTS
                foreach (BasketItem item in basket.Items)
                {
                    //MAKE SURE THIS IS A PRODUCT AND IS NOT EXCLUDED FROM GLOBAL DISCOUNT
                    if ((item.ProductId > 0) && (excludeGlobal.IndexOf(item.ProductId) < 0))
                    {
                        //ADD THIS PRODUCT TO THE GLOBAL DISCOUNT LIST (IF NOT ALREADY THERE)
                        if (globalDiscountProducts.IndexOf(item.ProductId) < 0)
                        {
                            globalDiscountProducts.Add(item.ProductId);
                        }
                    }
                }
            }

            //ARE WE CALCULATING DISCOUNTS USING CATEGORY GROUPING MODE?
            //OR ARE THERE ANY PRODUCTS THAT COULD HAVE GLOBAL DISCOUNTS?
            if (groupingMode == GroupingMode.Category || globalDiscountProducts.Count > 0)
            {
                //FIND ANY GLOBAL DISCOUNTS
                VolumeDiscountCollection globalDiscounts = VolumeDiscountDataSource.LoadGlobal();
                if (globalDiscounts.Count > 0)
                {
                    if (groupingMode == GroupingMode.Product)
                    {
                        foreach (int productId in globalDiscountProducts)
                        {
                            potentialDiscounts[productId] = new List <PotentialDiscount>();
                            List <PotentialDiscount> discountGroup = potentialDiscounts[productId];
                            foreach (VolumeDiscount v in globalDiscounts)
                            {
                                //VERIFY USER RESTRICTION ON GLOBAL DISCOUNT
                                if (v.IsValidForUser(user))
                                {
                                    PotentialDiscount pd = new PotentialDiscount();
                                    pd.CategoryId       = 0;
                                    pd.CategoryLevel    = 0;
                                    pd.VolumeDiscountId = v.VolumeDiscountId;
                                    pd.ProductId        = productId;
                                    discountGroup.Add(pd);
                                }
                            }
                        }
                    }
                    else
                    {
                        potentialDiscounts[0] = new List <PotentialDiscount>();
                        List <PotentialDiscount> discountGroup = potentialDiscounts[0];
                        foreach (VolumeDiscount v in globalDiscounts)
                        {
                            //VERIFY USER RESTRICTION ON GLOBAL DISCOUNT
                            if (v.IsValidForUser(user))
                            {
                                PotentialDiscount pd = new PotentialDiscount();
                                pd.CategoryId       = 0;
                                pd.CategoryLevel    = 0;
                                pd.VolumeDiscountId = v.VolumeDiscountId;
                                pd.ProductId        = 0;
                                discountGroup.Add(pd);
                            }
                        }
                    }
                }
            }

            //REMOVE ANY ENTRIES FROM THE LIST THAT HAVE NO DISCOUNTS
            List <int> emptyKeys = new List <int>();

            foreach (int key in potentialDiscounts.Keys)
            {
                if (potentialDiscounts[key].Count == 0)
                {
                    emptyKeys.Add(key);
                }
            }
            foreach (int key in emptyKeys)
            {
                potentialDiscounts.Remove(key);
            }

            //RETURN POTENTIAL DISCOUNTS FOR BASKET
            return(potentialDiscounts);
        }
        private static LSDecimal Calculate_LineItemMode(Basket basket)
        {
            //KEEP TRACK OF TOTAL DISCOUNT APPLIED
            LSDecimal totalDiscount = 0;

            //CLEAR EXISTING DISCOUNTS FROM THE BASKET
            ClearExistingDiscounts(basket);

            //BUILD A LIST OF PRODUCTS THAT HAVE DISCOUNTS SPECIFICALLY APPLIED
            //THESE PRODUCTS CANNOT RECEIVE ANY FURTHER DISCOUNTS
            List <int> productsToExclude = new List <int>();

            //INITIALLY POPULATE THE LIST WITH ANY GIFT CERTIFICATE PRODUCT IS AS THESE
            //PRODUCTS ARE NOT ALLOWED TO BE DISCOUNTED
            productsToExclude.AddRange(DiscountCalculator.GetGiftCertificateProductIds(basket.BasketId));

            //CALCULATE THE PRODUCT LEVEL DISCOUNTS
            totalDiscount += CalculateProductDiscounts(basket, productsToExclude);

            //GET POTENTIAL PRODUCT DISCOUNTS
            Dictionary <int, List <PotentialDiscount> > potentialDiscounts = DiscountCalculator.GetPotentialDiscounts(basket, productsToExclude, GroupingMode.Product);

            //BUILD A QUANTITY AND VALUE LOOKUP TABLE, IF NEEDED TO COMBINE OPTIONS
            Dictionary <int, int>       productQuantityLookup = null;
            Dictionary <int, LSDecimal> productValueLookup    = null;
            bool combineVariantsInLineItemDiscountMode        = Store.GetCachedSettings().CombineVariantsInLineItemDiscountMode;

            if (combineVariantsInLineItemDiscountMode)
            {
                productQuantityLookup = new Dictionary <int, int>();
                productValueLookup    = new Dictionary <int, LSDecimal>();
                foreach (BasketItem bi in basket.Items)
                {
                    if (productQuantityLookup.ContainsKey(bi.ProductId))
                    {
                        productQuantityLookup[bi.ProductId] += bi.Quantity;
                        productValueLookup[bi.ProductId]    += bi.ExtendedPrice;
                    }
                    else
                    {
                        productQuantityLookup[bi.ProductId] = bi.Quantity;
                        productValueLookup[bi.ProductId]    = bi.ExtendedPrice;
                    }
                }
            }

            //LOOP BASKET ITEMS
            List <BasketItem> newItems = new List <BasketItem>();

            foreach (BasketItem bi in basket.Items)
            {
                //SEE WHETHER THIS PRODUCT HAS ANY POTENTIAL DISCOUNTS
                if (potentialDiscounts.ContainsKey(bi.ProductId))
                {
                    //GET THE POTENTIAL DISCOUNTS FOR THIS PRODUCT
                    List <PotentialDiscount> productDiscounts = potentialDiscounts[bi.ProductId];
                    //FIND THE BEST DISCOUNT
                    VolumeDiscount appliedDiscount = null;
                    LSDecimal      discountAmount  = -1;
                    for (int i = 0; i < productDiscounts.Count; i++)
                    {
                        VolumeDiscount tempDiscount = VolumeDiscountDataSource.Load(productDiscounts[i].VolumeDiscountId);
                        //DETERMINE THE QUANTITY USED TO CALCULATE DISCOUNT
                        int       totalProductQuantity;
                        LSDecimal totalProductValue;
                        if (combineVariantsInLineItemDiscountMode)
                        {
                            totalProductQuantity = productQuantityLookup[bi.ProductId];
                            totalProductValue    = productValueLookup[bi.ProductId];
                        }
                        else
                        {
                            totalProductQuantity = bi.Quantity;
                            totalProductValue    = bi.ExtendedPrice;
                        }
                        //CHECK THIS DISCOUNT AMOUNT
                        LSDecimal tempDiscountAmount = tempDiscount.CalculateDiscount(bi.Quantity, totalProductQuantity, bi.ExtendedPrice, totalProductValue);
                        //SEE WHETHER THIS CALCULATED DISCOUNT IS THE GREATEST VALUE
                        if (tempDiscountAmount > discountAmount)
                        {
                            //THIS DISCOUNT HAS A HIGHER VALUE THAN THE LAST TESTED
                            //MAKE THIS THE APPLIED DISCOUNT
                            discountAmount  = tempDiscountAmount;
                            appliedDiscount = tempDiscount;
                        }
                    }

                    //CREATE THE DISCOUNT ITEM IF REQUIRED
                    if (discountAmount > 0)
                    {
                        //DISCOUNT AMOUNT SHOULD NOT BE GREATER THEN PARENT ITEM TOTAL
                        if (discountAmount > bi.ExtendedPrice)
                        {
                            discountAmount = bi.ExtendedPrice;
                        }

                        BasketItem discountLineItem = new BasketItem();
                        discountLineItem.BasketId         = basket.BasketId;
                        discountLineItem.OrderItemType    = OrderItemType.Discount;
                        discountLineItem.ParentItemId     = bi.BasketItemId;
                        discountLineItem.BasketShipmentId = bi.BasketShipmentId;
                        discountLineItem.Name             = appliedDiscount.Name;
                        discountLineItem.Sku       = appliedDiscount.VolumeDiscountId.ToString();
                        discountLineItem.Price     = (-1 * discountAmount);
                        discountLineItem.Quantity  = 1; //bi.Quantity;
                        discountLineItem.TaxCodeId = bi.TaxCodeId;
                        discountLineItem.Shippable = bi.Shippable;
                        newItems.Add(discountLineItem);
                        totalDiscount += discountAmount;
                    }
                }
            }

            //ADD DISCOUNT ITEMS TO BASKET
            foreach (BasketItem bi in newItems)
            {
                basket.Items.Add(bi);
                bi.Save();
            }

            //RETURN THE TOTAL DISCOUNT APPLIED
            return(totalDiscount);
        }
        /// <summary>
        /// Calculates any product specific discounts for the basket
        /// </summary>
        /// <param name="basket">Basket to calculate discounts for</param>
        /// <param name="productsToExclude">Any products to exclude from discounting</param>
        /// <returns>The total discount applied to the basket</returns>
        private static LSDecimal CalculateProductDiscounts(Basket basket, List <int> productsToExclude)
        {
            LSDecimal totalDiscount = 0;

            //GET ALL PRODUCTS FROM THE BASKET THAT HAVE DISCOUNTS DIRECTLY ASSOCIATED
            //TODO: UPDATE THE METHOD BELOW TO FACTOR IN THE COMBINE VARIANTS IN LINE ITEM DISCOUNT MODE SETTING
            DiscountedBasketProduct[] discountedItems = DiscountCalculator.GetDiscountedBasketProducts(basket.BasketId, productsToExclude);
            if (discountedItems != null && discountedItems.Length > 0)
            {
                //EVALUATE EACH ITEM TO SEE WHETHER THE PRODUCT DISCOUNT APPLIES
                foreach (DiscountedBasketProduct discountedProduct in discountedItems)
                {
                    VolumeDiscount appliedDiscount = null;
                    LSDecimal      discountAmount  = -1;
                    //LOOP ALL AVAILABLE DISCOUNTS AND FIND THE BEST ONE
                    VolumeDiscountCollection availableDiscounts = VolumeDiscountDataSource.LoadForProduct(discountedProduct.ProductId);
                    foreach (VolumeDiscount testDiscount in availableDiscounts)
                    {
                        if (testDiscount.IsValidForUser(basket.User))
                        {
                            LSDecimal tempDiscountAmount = testDiscount.CalculateDiscount(discountedProduct.Quantity, discountedProduct.Quantity, discountedProduct.ExtendedPrice, discountedProduct.ExtendedPrice);
                            if (tempDiscountAmount > discountAmount)
                            {
                                discountAmount  = tempDiscountAmount;
                                appliedDiscount = testDiscount;
                            }
                        }
                    }

                    //CHECK WHETHER A DISCOUNT APPLIES TO THIS PRODUCT FOR THIS USER
                    if (appliedDiscount != null)
                    {
                        //productsToExclude.Add(discountedProduct.ProductId);
                        List <BasketItem> newItems = new List <BasketItem>();
                        //LOOP ALL ITEMS IN BASKET, CALCULATE DISCOUNT FOR MATCHING PRODUCTS
                        foreach (BasketItem basketItem in basket.Items)
                        {
                            if (basketItem.ProductId == discountedProduct.ProductId)
                            {
                                //THIS IS A DISCOUNTED PRODUCT, CREATE THE DISCOUNT LINE ITEM
                                discountAmount = appliedDiscount.CalculateDiscount(basketItem.Quantity, discountedProduct.Quantity, basketItem.ExtendedPrice, discountedProduct.ExtendedPrice);
                                if (discountAmount > 0)
                                {
                                    //DISCOUNT AMOUNT SHOULD NOT BE GREATER THEN PARENT ITEM TOTAL
                                    if (discountAmount > basketItem.ExtendedPrice)
                                    {
                                        discountAmount = basketItem.ExtendedPrice;
                                    }

                                    //DISCOUNT MUST BE ADJUSTED FOR OPTIONS THAT ARE GROUPED
                                    BasketItem discountLineItem = new BasketItem();
                                    discountLineItem.BasketId         = basket.BasketId;
                                    discountLineItem.OrderItemType    = OrderItemType.Discount;
                                    discountLineItem.ParentItemId     = basketItem.BasketItemId;
                                    discountLineItem.BasketShipmentId = basketItem.BasketShipmentId;
                                    discountLineItem.Name             = appliedDiscount.Name;
                                    discountLineItem.Sku       = appliedDiscount.VolumeDiscountId.ToString();
                                    discountLineItem.Price     = (-1 * discountAmount);
                                    discountLineItem.Quantity  = 1; // basketItem.Quantity;
                                    discountLineItem.TaxCodeId = basketItem.TaxCodeId;
                                    discountLineItem.Shippable = basketItem.Shippable;
                                    discountLineItem.Save();
                                    newItems.Add(discountLineItem);
                                    totalDiscount += discountAmount;
                                }
                            }
                        }
                        //ADD ANY NEW ITEMS TO THE BASKET COLLECTION
                        foreach (BasketItem basketItem in newItems)
                        {
                            basket.Items.Add(basketItem);
                        }

                        //AT LEAST ONE DISCOUNT WAS APPLICABLE TO THIS USER
                        //ADD THIS PRODUCT TO EXCLUDE LIST
                        if (productsToExclude.IndexOf(discountedProduct.ProductId) < 0)
                        {
                            productsToExclude.Add(discountedProduct.ProductId);
                        }
                    }
                }
            }
            return(totalDiscount);
        }
        private static LSDecimal Calculate_GroupingMode(Basket basket)
        {
            //KEEP TRACK OF TOTAL DISCOUNT APPLIED
            LSDecimal totalDiscount = 0;

            //CLEAR EXISTING DISCOUNTS FROM THE BASKET
            ClearExistingDiscounts(basket);

            //BUILD A LIST OF PRODUCTS THAT HAVE DISCOUNTS SPECIFICALLY APPLIED
            //THESE PRODUCTS CANNOT RECEIVE ANY FURTHER DISCOUNTS
            List <int> productsToExclude = new List <int>();

            //INITIALLY POPULATE THE LIST WITH ANY GIFT CERTIFICATE PRODUCT IS AS THESE
            //PRODUCTS ARE NOT ALLOWED TO BE DISCOUNTED
            productsToExclude.AddRange(DiscountCalculator.GetGiftCertificateProductIds(basket.BasketId));

            //CALCULATE THE PRODUCT LEVEL DISCOUNTS
            totalDiscount += CalculateProductDiscounts(basket, productsToExclude);

            //GET POTENTIAL CATEGORY DISCOUNTS
            //THE DICTIONARY KEY WILL BE CATEGORY LEVEL
            //POTENTIAL DISCOUNTS ARE THOSE THAT COULD APPLY AT THE SAME SPECIFICITY
            //THE POTENTIAL DISCOUNTS ARE ORDERED FROM MOST SPECIFIC CATEGORY LEVEL TO LEAST
            Dictionary <int, List <PotentialDiscount> > potentialDiscounts = DiscountCalculator.GetPotentialDiscounts(basket, productsToExclude, GroupingMode.Category);

            //LOOP THE DISCOUNTED CATEGORIES
            //WE HAVE TO CHECK ALL POTENTIAL DISCOUNTS AT EACH CATEGORY LEVEL
            //TO DETERMINE WHICH ONE TO APPLY
            List <BasketItem> newItems = new List <BasketItem>();

            foreach (int categoryLevel in potentialDiscounts.Keys)
            {
                //IF WE FIND A DISCOUNT AT THIS LEVEL, IT SHOULD BE APPLIED, THEN WE
                //SHOULD RECHECK DISCOUNTS AT THIS LEVEL TO SEE IF ANY OTHERS APPLY
                bool       recheckThisLevel  = false;
                List <int> appliedCategories = new List <int>();
                do
                {
                    LSDecimal                appliedDiscountAmount = -1;
                    VolumeDiscount           appliedDiscount       = null;
                    int                      appliedCategoryId     = 0;
                    List <PotentialDiscount> discountGroup         = potentialDiscounts[categoryLevel];
                    foreach (PotentialDiscount pd in discountGroup)
                    {
                        if (appliedCategories.IndexOf(pd.CategoryId) < 0)
                        {
                            //GET ALL BASKET ITEMS ELIGIBLE FOR DISCOUNT IN THIS CATEGORY
                            BasketItemCollection eligibleItems = DiscountCalculator.GetCategoryItems(pd.CategoryId, basket, productsToExclude);
                            //TOTAL UP ITEMS FOR GROUPING MODE
                            int totalQuantity = eligibleItems.TotalQuantity();
                            if (totalQuantity > 0)
                            {
                                LSDecimal      totalPrice   = eligibleItems.TotalPrice();
                                VolumeDiscount tempDiscount = VolumeDiscountDataSource.Load(pd.VolumeDiscountId);
                                //JUST USE TOTALS TO DETERMINE OVERALL DISCOUNT
                                LSDecimal tempDiscountAmount = tempDiscount.CalculateDiscount(totalQuantity, totalQuantity, totalPrice, totalPrice);
                                if (tempDiscountAmount > appliedDiscountAmount)
                                {
                                    appliedDiscountAmount = tempDiscountAmount;
                                    appliedDiscount       = tempDiscount;
                                    appliedCategoryId     = pd.CategoryId;
                                }
                            }
                        }
                    }

                    //SEE WHETHER WE FOUND A DISCOUNT AT THIS LEVEL
                    if (appliedDiscount != null)
                    {
                        //GET ALL BASKET ITEMS ELIGIBLE FOR DISCOUNT IN THIS CATEGORY
                        BasketItemCollection eligibleItems = DiscountCalculator.GetCategoryItems(appliedCategoryId, basket, productsToExclude);
                        //TOTAL UP ITEMS FOR GROUPING MODE
                        int       totalQuantity = eligibleItems.TotalQuantity();
                        LSDecimal totalPrice    = eligibleItems.TotalPrice();
                        //LOOP ALL BASKET ITEMS TO ADD DISCOUNTS TO BASKET
                        foreach (BasketItem bi in eligibleItems)
                        {
                            LSDecimal discountAmount = appliedDiscount.CalculateDiscount(bi.Quantity, totalQuantity, bi.ExtendedPrice, totalPrice);
                            if (discountAmount > 0)
                            {
                                //DISCOUNT AMOUNT SHOULD NOT BE GREATER THEN PARENT ITEM TOTAL
                                if (discountAmount > bi.ExtendedPrice)
                                {
                                    discountAmount = bi.ExtendedPrice;
                                }

                                //DISCOUNT MUST BE ADJUSTED FOR OPTIONS THAT ARE GROUPED
                                BasketItem discountLineItem = new BasketItem();
                                discountLineItem.BasketId         = basket.BasketId;
                                discountLineItem.OrderItemType    = OrderItemType.Discount;
                                discountLineItem.ParentItemId     = bi.BasketItemId;
                                discountLineItem.BasketShipmentId = bi.BasketShipmentId;
                                discountLineItem.Name             = appliedDiscount.Name;
                                discountLineItem.Sku       = appliedDiscount.VolumeDiscountId.ToString();
                                discountLineItem.Price     = (-1 * discountAmount);
                                discountLineItem.Quantity  = 1; //bi.Quantity;
                                discountLineItem.TaxCodeId = bi.TaxCodeId;
                                discountLineItem.Shippable = bi.Shippable;
                                basket.Items.Add(discountLineItem);
                                discountLineItem.Save();
                                totalDiscount += discountAmount;
                            }
                            if (productsToExclude.IndexOf(bi.ProductId) < 0)
                            {
                                productsToExclude.Add(bi.ProductId);
                            }
                        }
                    }
                    //IF A CATEGORY DISCOUNT WAS APPLIED
                    //AND THERE IS MORE THAN ONE DISCOUNT AT THIS LEVEL,
                    //WE MUST RECHECK THIS LEVEL
                    recheckThisLevel = ((appliedCategoryId > 0) && (potentialDiscounts[categoryLevel].Count > 1));
                } while (recheckThisLevel);
            }

            //ADD DISCOUNT ITEMS TO BASKET
            foreach (BasketItem bi in newItems)
            {
                basket.Items.Add(bi);
                bi.Save();
            }

            //RETURN THE CALCULATED DISCOUNT
            return(totalDiscount);
        }
 public static SaveResult Update(VolumeDiscount volumeDiscount)
 {
     return(volumeDiscount.Save());
 }
 public static SaveResult Insert(VolumeDiscount volumeDiscount)
 {
     return(volumeDiscount.Save());
 }
 public static bool Delete(VolumeDiscount volumeDiscount)
 {
     return(volumeDiscount.Delete());
 }
Beispiel #14
0
        /// <summary>
        /// Get discounts that apply to a product by virtue of category assignment.
        /// </summary>
        /// <param name="productId">The product to check for category discounts</param>
        /// <returns>The discounts that apply to a product</returns>
        private static VolumeDiscountCollection GetCategoryDiscountsForProduct(int productId)
        {
            //FIND ALL PRODUCTS THAT ARE A DESCENDANT OF THE CATEGORY
            StringBuilder categorySql = new StringBuilder();

            categorySql.Append("SELECT DISTINCT CP.ParentLevel,CVD.VolumeDiscountId");
            categorySql.Append(" FROM ((ac_CatalogNodes CN INNER JOIN ac_CategoryParents CP ON CN.CategoryId = CP.CategoryId)");
            categorySql.Append(" INNER JOIN ac_CategoryVolumeDiscounts CVD ON CP.ParentId = CVD.CategoryId)");
            categorySql.Append(" WHERE CN.CatalogNodeId = @productId");
            categorySql.Append(" AND CN.CatalogNodeTypeId = 1");
            categorySql.Append(" ORDER BY CP.ParentLevel DESC");

            //EXECUTE THE QUERY
            Database  database = Token.Instance.Database;
            DbCommand command  = database.GetSqlStringCommand(categorySql.ToString());

            database.AddInParameter(command, "@productId", System.Data.DbType.Int32, productId);

            //BUILD LIST OF VOLUME DISCOUNT IDS APPLICABLE FOR THE USER
            User       user = Token.Instance.User;
            List <int> volumeDiscountIds = new List <int>();
            int        lastLevel         = -1;
            bool       levelChanged      = false;

            using (IDataReader dr = database.ExecuteReader(command))
            {
                while (dr.Read() && !levelChanged)
                {
                    int            thisLevel        = (int)dr.GetByte(0);
                    int            volumeDiscountId = dr.GetInt32(1);
                    VolumeDiscount v = VolumeDiscountDataSource.Load(volumeDiscountId);
                    if (v.IsValidForUser(user))
                    {
                        if ((lastLevel > -1) && (lastLevel != thisLevel))
                        {
                            levelChanged = true;
                        }
                        else
                        {
                            volumeDiscountIds.Add(dr.GetInt32(1));
                            lastLevel = thisLevel;
                        }
                    }
                }
                dr.Close();
            }

            //INITIALIZE THE RETURN SET
            VolumeDiscountCollection discounts = new VolumeDiscountCollection();

            //DID WE FIND DISCOUNTS ON A CATEGORY?
            if (volumeDiscountIds.Count > 0)
            {
                //BUILD THE COLLECTION OF DISCOUNTS
                foreach (int id in volumeDiscountIds)
                {
                    VolumeDiscount v = VolumeDiscountDataSource.Load(id);
                    if (v != null)
                    {
                        discounts.Add(v);
                    }
                }
            }
            else
            {
                //NO DISCOUNT FOUND ON A CATEGORY, RETURN ANY GLOBAL DISCOUNTS
                VolumeDiscountCollection globalDiscounts = VolumeDiscountDataSource.LoadGlobal();
                foreach (VolumeDiscount v in globalDiscounts)
                {
                    if (v.IsValidForUser(user))
                    {
                        discounts.Add(v);
                    }
                }
            }
            //RETURN ANY CATEGORY DISCOUNTS FOUND
            return(discounts);
        }