/// <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); }
/// <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); }