Пример #1
0
        /// <summary>
        /// Gets available choices for a product for given option
        /// </summary>
        /// <param name="productId">Id of the product</param>
        /// <param name="targetOptionId">Id of the option to check for choices</param>
        /// <param name="selectedChoices">A Dictionary<int, int> of option choices already selected.  The dictionary key is the OptionId and the value is the OptionChoiceId.</param>
        /// <returns>Collection of OptionChoice objects</returns>
        public static OptionChoiceCollection GetAvailableChoices(int productId, int targetOptionId, Dictionary <int, int> selectedChoices)
        {
            OptionChoiceCollection availableOptionChoices = new OptionChoiceCollection();
            Product product = ProductDataSource.Load(productId);

            if (product != null)
            {
                // SEE IF OPTIONS EXIST, NOTE WE ARE LOADING THE OPTIONS ACCORDING TO THE SORT SPECIFIED FOR VARIANT MANAGEMENT
                // THIS WILL NOT BE THE SAME AS THE DEFAULT SORT ORDER THAT IS DETERMINED BY THE MERCHANT
                OptionCollection options = OptionDataSource.LoadForProduct(productId, ProductVariant.VARIANT_SORT_EXPRESSION);
                if (options.Count > 0)
                {
                    //CAST OFF ANY ATTRIBUTES PAST THE MAXIMUM ALLOWED COUNT
                    while (options.Count > ProductVariant.MAXIMUM_ATTRIBUTES)
                    {
                        options.RemoveAt(ProductVariant.MAXIMUM_ATTRIBUTES);
                    }

                    // DETERMINE THE INDEX USED OR VARIANT MANAGEMENT, THIS ROUGHLY CORRESPONDS TO THE COLUMN NAMES IN ac_ProductVariants TABLE
                    // BUT NOTE THIS VARIANT INDEX IS ZERO BASED, WHERE THE TABLE COLUMN NAMES ARE 1 BASED: OPTION1, OPTION2, ETC.
                    int targetOptionVariantIndex = options.IndexOf(targetOptionId);
                    if (targetOptionVariantIndex > -1)
                    {
                        // SET THE TARGET OPTION
                        Option targetOption = options[targetOptionVariantIndex];

                        // BUILD THE LIST OF CHOICES SELECTED SO FAR
                        // SELECTED CHOICES KEY IS OPTION INDEX FOR VARIANT MANAGER
                        // THE VALUE IS THE SELECTED CHOICE FOR THAT OPTION INDEX
                        Dictionary <int, int> validSelectedChoices = new Dictionary <int, int>();
                        for (int i = 0; i < options.Count; i++)
                        {
                            Option option = options[i];
                            // IGNORE ANY SELECTED CHOICE FOR THE TARGET OPTION
                            if (option.OptionId != targetOptionId && selectedChoices.ContainsKey(option.OptionId))
                            {
                                // SEE IF THERE IS A CHOICE INDICATED FOR THIS OPTION IN THE QUERY STRING
                                int choiceId    = selectedChoices[option.OptionId];
                                int choiceIndex = option.Choices.IndexOf(choiceId);
                                if (choiceIndex > -1)
                                {
                                    // THIS IS A VALID SELECTED CHOICE
                                    validSelectedChoices.Add(i, choiceId);
                                }
                            }
                        }

                        // IF INVENTORY IS ENABLED, WE SIMPLY QUERY THE VARIANT GRID
                        if (Token.Instance.Store.EnableInventory &&
                            !product.AllowBackorder &&
                            product.InventoryMode == InventoryMode.Variant)
                        {
                            List <int> probableChoices = OptionChoiceDataSource.GetAvailableChoicesFromInventory(productId, validSelectedChoices, targetOptionVariantIndex);
                            // THIS STEP IS PROBABLY UNNEEDED, BUT LETS CONFIRM THE CHOICES FROM THE DATABASE ARE VALID
                            // (THE VARIANT TABLE CANNOT BENEFIT FROM CONSTRAINTS TO ENFORCE DATA INTEGRITY)
                            foreach (int choiceId in probableChoices)
                            {
                                int choiceIndex = targetOption.Choices.IndexOf(choiceId);
                                if (choiceIndex > -1)
                                {
                                    // THIS IS A VALID OPTION CHOICE ID
                                    availableOptionChoices.Add(targetOption.Choices[choiceIndex]);
                                }
                            }
                        }
                        else
                        {
                            // CALCULATE THE REMAINING POSSIBLE OPTION COMBINATIONS FOR EACH CHOICE
                            int possibleCount = 1;
                            foreach (Option option in options)
                            {
                                // WE SHOULD NOT INCLUDE THE TARGET OPTION IN THIS COUNT
                                if (option.OptionId != targetOptionId)
                                {
                                    // WE SHOULD NOT INCLUDE ANY OPTION THAT HAS ALREADY BEEN SELECTED
                                    int variantIndex = options.IndexOf(option.OptionId);
                                    if (!validSelectedChoices.ContainsKey(variantIndex))
                                    {
                                        // WE HAVE FOUND A CHOICE THAT IS NOT SELECTED AND IS NOT
                                        // THE TARGET CHOICE.  SO WE MUST CONSIDER ALL CHOICES AS POTENTIAL
                                        // AND INCLUDE THEM IN THE COUNT
                                        possibleCount = possibleCount * option.Choices.Count;
                                    }
                                }
                            }

                            // BUILD THE DICTIONARY OF UNAVAILABLE COUNTS
                            // THIS WILL BE GROUPED BY THE CHOICEID FOR THE TARGET OPTION
                            // AND WILL TELL US HOW MANY COMBINATIONS ARE INVALID FOR THAT CHOICE
                            // IF THE NUMBER MATCHES THE POSSIBLE COUNT, THEN ALL COMBINATIONS ARE UNAVAILABLE
                            // AND THIS CHOICE SHOULD NOT BE INCLUDED AS AVAILABLE
                            Dictionary <int, int> unavailableVariantCounts = OptionChoiceDataSource.GetUnavailableVariantCounts(productId, validSelectedChoices, targetOptionVariantIndex);
                            foreach (OptionChoice possibleChoice in targetOption.Choices)
                            {
                                // CHECK IF THERE ARE NO UNAVAILABLE VARIANTS FOR THIS CHOICE
                                // OR THE UNAVAILABLE COUNT IS LESS THAN THE POSSIBLE COMBINATION COUNT
                                if (!unavailableVariantCounts.ContainsKey(possibleChoice.OptionChoiceId) ||
                                    unavailableVariantCounts[possibleChoice.OptionChoiceId] < possibleCount)
                                {
                                    // THIS IS A VALID CHOICE
                                    availableOptionChoices.Add(possibleChoice);
                                }
                            }
                        }
                    }
                }
            }
            return(availableOptionChoices);
        }
Пример #2
0
 /// <summary>
 /// Calculates variant
 /// </summary>
 /// <returns><b>true</b> if calculation successful, <b>false</b> otherwise</returns>
 public bool CalculateVariant()
 {
     _Calculated = false;
     int[] choiceIds = this.GetOptionChoices(OptionCountBehavior.ActualCount);
     if (choiceIds != null && choiceIds.Length > 0)
     {
         //INITIALIZE THE CALCULATED VALUES
         _CalculatedPrice  = 0;
         _CalculatedWeight = 0;
         //BUILD CRITERIA TO LOAD CORRECT OPTIONS
         string criteria;
         if (choiceIds.Length == 1)
         {
             criteria = "OptionChoiceId = " + choiceIds[0].ToString();
         }
         else
         {
             string idList = AlwaysConvert.ToList(",", choiceIds);
             criteria = "OptionChoiceId IN (" + idList + ")";
         }
         //RECALCULATE ALL ITEMS
         OptionChoiceCollection choices = OptionChoiceDataSource.LoadForCriteria(criteria);
         OptionChoice           choice;
         List <string>          names = new List <string>();
         StringBuilder          sku   = new StringBuilder();
         sku.Append(this.Product.Sku);
         //LOOP ALL CHOICES INDICATED FOR THIS VARIANT AND CALCULATE THE MODIFIERS
         foreach (int optionChoiceId in choiceIds)
         {
             int index = choices.IndexOf(optionChoiceId);
             if (index > -1)
             {
                 choice = choices[index];
                 names.Add(choice.Name);
                 _CalculatedPrice  += choice.PriceModifier;
                 _CalculatedWeight += choice.WeightModifier;
                 sku.Append(choice.SkuModifier);
             }
         }
         //SET THE CALCULATED VALUES
         _CalculatedName = String.Join(", ", names.ToArray());
         _CalculatedSku  = sku.ToString();
         if (this.VariantName == string.Empty)
         {
             this.VariantName = _CalculatedName;
         }
         if (this.Price == 0)
         {
             this.Price = _CalculatedPrice;
         }
         if (this.Weight == 0)
         {
             this.Weight = _CalculatedWeight;
         }
         if (this.Sku == string.Empty)
         {
             this.Sku = _CalculatedSku;
         }
         _Calculated = true;
     }
     return(_Calculated);
 }