/// <summary> /// Overrides OnPreInit method. /// </summary> protected override void OnPreInit(EventArgs e) { base.OnPreInit(e); // Initialize creation of a new variants GlobalObjectsKeyName = ECommerceSettings.ALLOW_GLOBAL_PRODUCTS; // Check if product belongs to current site var product = EditedObject as SKUInfo; if (product != null) { CheckEditedObjectSiteID(product.SKUSiteID); } mAllCategoriesOptions = new List <Tuple <OptionCategoryInfo, List <SKUInfo> > >(); mVariantCategoriesOptions = new List <Tuple <OptionCategoryInfo, List <SKUInfo> > >(); // Get all enabled product option attribute categories plus option categories used in variants DataSet allCategoriesDS = VariantHelper.GetUsedProductOptionCategories(ProductID, OptionCategoryTypeEnum.Attribute); // Get all product options categories which are already in variants DataSet variantCategoriesDS = VariantHelper.GetProductVariantsCategories(ProductID); // Fill categories lists FillCategoriesOptions(mAllCategoriesOptions, allCategoriesDS); FillCategoriesOptions(mVariantCategoriesOptions, variantCategoriesDS); // Pass data to controls VariantFilter.ExternalDataSource = CategorySelector.AllCategoriesOptions = mAllCategoriesOptions.ToDictionary(c => c.Item1, c => c.Item2);; CategorySelector.VariantCategoriesOptions = mVariantCategoriesOptions.ToDictionary(c => c.Item1, c => c.Item2);; }
/// <summary> /// Returns an enumerable collection of all variants of the given product. /// </summary> /// <param name="productId">SKU object identifier of the variant's parent product.</param> /// <returns>Collection of product variants. See <see cref="ProductVariant"/> for detailed information.</returns> public IEnumerable <ProductVariant> GetByProductId(int productId) { var variantSKUs = VariantHelper.GetVariants(productId).OnSite(SiteContext.CurrentSiteID).ToList(); // Create variants with the options return(variantSKUs.Select(sku => new ProductVariant(sku.SKUID))); }
/// <summary> /// Gets the options with names from external data source or database. /// </summary> /// <param name="skuIdOfProductWithCategories">Id of product with categories.</param> /// <param name="categoryId">The category id.</param> private Dictionary <int, string> GetOptionsWithNames(int skuIdOfProductWithCategories, int categoryId) { Dictionary <int, string> optionsWithName = new Dictionary <int, string>(); if ((ExternalDataSource != null) && (ExternalDataSource.Count > 0)) { // External data OptionCategoryInfo categoryInfo = ExternalDataSource.Keys.First(k => k.CategoryID == categoryId); List <SKUInfo> externalOptions = ExternalDataSource[categoryInfo]; foreach (SKUInfo info in externalOptions) { optionsWithName.Add(info.SKUID, info.SKUName); } return(optionsWithName); } else { InfoDataSet <SKUInfo> dsOptions = VariantHelper.GetEnabledOptionsWithVariantOptions(skuIdOfProductWithCategories, categoryId); if (!DataHelper.DataSourceIsEmpty(dsOptions)) { foreach (var option in dsOptions) { optionsWithName.Add(option.SKUID, option.SKUName); } } return(optionsWithName); } }
/// <summary> /// Handles the OnReloadData event of the menuZoneVariants control. /// </summary> protected void menuMoveToZoneVariants_OnReloadData(object sender, EventArgs e) { // Check permissions if (currentUser == null) { return; } if ((DocumentContext.CurrentPageInfo != null) && (DocumentContext.CurrentPageInfo.TemplateInstance != null)) { VariantModeEnum currentVariantMode = VariantModeEnum.None; string targetZoneId = ValidationHelper.GetString(menuMoveToZoneVariants.Parameter, string.Empty); int pageTemplateId = DocumentContext.CurrentPageInfo.UsedPageTemplateInfo.PageTemplateId; // Get selected zone variant mode if ((DocumentContext.CurrentPageInfo != null) && (DocumentContext.CurrentPageInfo.TemplateInstance != null)) { WebPartZoneInstance targetZone = DocumentContext.CurrentPageInfo.TemplateInstance.GetZone(targetZoneId); if (targetZone != null) { currentVariantMode = targetZone.VariantMode; } } SetColumnNames(currentVariantMode); // Get all zone variants of the current web part DataTable resultTable = null; DataSet ds = VariantHelper.GetVariants(currentVariantMode, pageTemplateId, targetZoneId, Guid.Empty, 0); if (!DataHelper.DataSourceIsEmpty(ds)) { DataTable table = ds.Tables[0].Copy(); table.DefaultView.Sort = columnVariantID; // Add the original web part as the first item in the variant list DataRow originalVariant = table.NewRow(); originalVariant[columnVariantID] = 0; originalVariant[columnVariantDisplayName] = ResHelper.GetString("ZoneMenu.OriginalZone", UICulture); originalVariant[columnVariantZoneID] = targetZoneId; originalVariant[columnVariantPageTemplateID] = pageTemplateId; originalVariant[columnVariantInstanceGUID] = Guid.Empty; table.Rows.InsertAt(originalVariant, 0); resultTable = table.DefaultView.ToTable(); if (DataHelper.DataSourceIsEmpty(resultTable)) { pnlNoZoneVariants.Visible = true; ltlNoZoneVariants.Text = ResHelper.GetString("Content.NoPermissions", UICulture); } } repMoveToZoneVariants.DataSource = resultTable; repMoveToZoneVariants.DataBind(); } }
/// <summary> /// Hide/rename columns in uniGrid before loading data. /// </summary> void ugOptions_OnBeforeDataReload() { // Hide price adjustment if category is used in product variants if (VariantHelper.AreCategoriesUsedInVariants(ProductID, new[] { CategoryID })) { ugOptions.NamedColumns["SKUPrice"].Visible = false; } }
/// <summary> /// Returns a collection of option categories used in a product's variants. /// </summary> /// <param name="productId">SKU identifier of the variant's parent product.</param> /// <returns>Collection of option categories used in a product's variants. See <see cref="OptionCategoryInfo"/> for detailed information.</returns> public IEnumerable <OptionCategoryInfo> GetVariantOptionCategories(int productId) { return(repositoryCacheHelper.CacheObjects(() => { // Get a list of option categories return VariantHelper.GetProductVariantsCategories(productId); }, $"{nameof(VariantRepository)}|{nameof(GetVariantOptionCategories)}|{productId}")); }
/// <summary> /// Updates price of variants in asynchronous control. /// </summary> /// <param name="newPrice">New price of variant</param> protected void UpdatePrice(double newPrice) { try { SKUInfo variantInfo = null; // Use special action contexts to turn off unnecessary actions using (ECommerceActionContext eCommerceContext = new ECommerceActionContext()) { eCommerceContext.TouchParent = false; eCommerceContext.SetLowestPriceToParent = false; // Update all variants if ((WhatEnum)ValidationHelper.GetInteger(drpWhat.SelectedIndex, -1) == WhatEnum.AllVariants) { var variants = VariantHelper.GetVariants(ProductID); foreach (var variant in variants) { variantInfo = variant; UpdateVariant(variantInfo, newPrice); } } // Update selected variants else { var variantsToUpdate = ugVariants.SelectedItems; foreach (var variantId in variantsToUpdate) { variantInfo = SKUInfoProvider.GetSKUInfo(ValidationHelper.GetInteger(variantId, 0)); // Do not allow modify variants of other product if ((variantInfo != null) && (variantInfo.SKUParentSKUID != ProductID)) { variantInfo = null; } if (variantInfo != null) { UpdateVariant(variantInfo, newPrice); } } } } // Save variant to update parent SKULastModified a SKUPrice properties if (variantInfo != null) { variantInfo.Generalized.SetObject(); } } catch (Exception ex) { CurrentError = GetString("com.product.updatepriceerror"); EventLogProvider.LogException("Update price bulk action", "UPDATEVARIANT", ex); } }
/// <summary> /// Returns a variant for the given parent product which consists of the specified options. /// If multiple variants use the given subset of options, one of them is returned (based on setting of the database engine). /// </summary> /// <param name="productId">SKU identifier of the variant's parent product.</param> /// <param name="optionIds">Collection of the variant's product options.</param> /// <returns><see cref="ProductVariant"/> object representing a product variant assembled from the specified information. Returns <c>null</c> if such variant does not exist.</returns> public ProductVariant GetByProductIdAndOptions(int productId, IEnumerable <int> optionIds) { var variantSKU = VariantHelper.GetProductVariant(productId, new ProductAttributeSet(optionIds)); if (variantSKU == null) { return(null); } return(new ProductVariant(variantSKU.SKUID)); }
/// <summary> /// Handles the OnReloadData event of the menuWebPartCPVariants control. /// </summary> protected void menuWebPartCPVariants_OnReloadData(object sender, EventArgs e) { // Check permissions if ((MembershipContext.AuthenticatedUser == null) || (!MembershipContext.AuthenticatedUser.IsAuthorizedPerResource("CMS.ContentPersonalization", "Read"))) { return; } string parameters = ValidationHelper.GetString(menuWebPartCPVariants.Parameter, string.Empty); string[] items = parameters.Split(new char[] { ',' }, 7); if ((items == null) || (items.Length < 4)) { return; } string zoneId = ValidationHelper.GetString(items[0], string.Empty); string webpartName = ValidationHelper.GetString(items[1], string.Empty); string aliasPath = ValidationHelper.GetString(items[2], string.Empty); Guid instanceGuid = ValidationHelper.GetGuid(items[3], Guid.Empty); isZone = (instanceGuid == Guid.Empty); if ((DocumentContext.CurrentPageInfo != null) && (DocumentContext.CurrentPageInfo.TemplateInstance != null)) { int templateId = DocumentContext.CurrentPageInfo.UsedPageTemplateInfo.PageTemplateId; DataSet ds = VariantHelper.GetVariants(VariantModeEnum.ContentPersonalization, templateId, zoneId, instanceGuid, 0); DataTable resultTable = null; if (!DataHelper.DataSourceIsEmpty(ds)) { DataTable table = ds.Tables[0].Copy(); table.DefaultView.Sort = columnVariantID; // Add the original web part as the first item in the variant list DataRow originalVariant = table.NewRow(); originalVariant[columnVariantID] = 0; originalVariant[columnVariantDisplayName] = ResHelper.GetString(isZone ? "ZoneMenu.OriginalZone" : "WebPartMenu.OriginalWebPart"); originalVariant[columnVariantZoneID] = zoneId; originalVariant[columnVariantPageTemplateID] = templateId; originalVariant[columnVariantInstanceGUID] = instanceGuid; table.Rows.InsertAt(originalVariant, 0); resultTable = table.DefaultView.ToTable(); } repWebPartCPVariants.DataSource = resultTable; repWebPartCPVariants.DataBind(); } }
/// <summary> /// Handles the OnReloadData event of the menuWebPartVariants control. /// </summary> protected void menuZoneMVTVariants_OnReloadData(object sender, EventArgs e) { // Check permissions if ((currentUser == null) || (!currentUser.IsAuthorizedPerResource("CMS.MVTest", "Read"))) { return; } SetColumnNames(VariantModeEnum.MVT); string zoneId = ValidationHelper.GetString(menuZoneMVTVariants.Parameter, string.Empty); if ((DocumentContext.CurrentPageInfo != null) && (DocumentContext.CurrentPageInfo.TemplateInstance != null)) { int templateId = DocumentContext.CurrentPageInfo.UsedPageTemplateInfo.PageTemplateId; // Get all MVT zone variants of the current web part DataSet ds = VariantHelper.GetVariants(VariantModeEnum.MVT, templateId, zoneId, Guid.Empty, 0); DataTable resultTable = null; if (!DataHelper.DataSourceIsEmpty(ds)) { DataTable table = ds.Tables[0].Copy(); table.DefaultView.Sort = columnVariantID; // Add the original web part as the first item in the variant list DataRow originalVariant = table.NewRow(); originalVariant[columnVariantID] = 0; originalVariant[columnVariantDisplayName] = ResHelper.GetString("WebPartMenu.OriginalWebPart", UICulture); originalVariant[columnVariantZoneID] = zoneId; originalVariant[columnVariantPageTemplateID] = templateId; originalVariant[columnVariantInstanceGUID] = Guid.Empty; table.Rows.InsertAt(originalVariant, 0); resultTable = table.DefaultView.ToTable(); if (DataHelper.DataSourceIsEmpty(resultTable)) { pnlNoZoneMVTVariants.Visible = true; lblNoZoneMVTVariants.Text = ResHelper.GetString("Content.NoPermissions", UICulture); } } else { pnlNoZoneMVTVariants.Visible = true; } repZoneMVTVariants.DataSource = resultTable; repZoneMVTVariants.DataBind(); } }
/// <summary> /// Gets all options used in variant. /// </summary> /// <returns>Collection of option Ids used in variants.</returns> private List <string> GetOptionIdsUsedInVariant() { var optionsInCategory = SKUInfoProvider.GetSKUOptions(optionSKUCategoryInfo.CategoryID, false).Column("SKUID"); var optionsInVariants = VariantOptionInfo.Provider.Get() .WhereIn("VariantSKUID", VariantHelper.GetVariants(ProductID).Column("SKUID")) .Column("OptionSKUID"); // Check if some variant was created from the option return(optionsInCategory.WhereIn("SKUID", optionsInVariants).ToList() .Select(o => o.SKUID.ToString()) .ToList()); }
public IList <ProductAttribute> GetByProductId(int productId, bool onlyVariantSpecific = false) { var q = Repository.Where(x => x.ProductId == productId) .Join <AvailableAttribute>("AvailableAttributeId", "Id", joinType: JoinType.LeftOuter) //.Join<Product>("ProductId", "Id") .Join <ProductAttributeValue>("Id", "ProductAttributeId", SourceColumn.Parent, joinType: JoinType.LeftOuter) .Join <AvailableAttributeValue>("AvailableAttributeValueId", "Id", joinType: JoinType.LeftOuter); //should we restrict to only variant specific attributes if (onlyVariantSpecific) { var allowedInputTypes = VariantHelper.GetVariantSpecificFieldTypes(); Expression <Func <ProductAttribute, bool> > variantWhere = attribute => allowedInputTypes.Contains(attribute.InputFieldType); q.Where(variantWhere); } return(q .Relate(RelationTypes.OneToMany <ProductAttribute, ProductAttributeValue>()) .Relate <AvailableAttributeValue>((productAttribute, availableAttributeValue) => { if (productAttribute.Tag == null) { productAttribute.Tag = new List <AvailableAttributeValue>(); } var attributeList = (List <AvailableAttributeValue>)productAttribute.Tag; if (!attributeList.Contains(availableAttributeValue)) { attributeList.Add(availableAttributeValue); } var pav = productAttribute.ProductAttributeValues.FirstOrDefault( x => x.AvailableAttributeValueId == availableAttributeValue.Id); if (pav != null) { pav.AvailableAttributeValue = availableAttributeValue; } }) .Relate <AvailableAttribute>((productAttribute, availableAttribute) => { availableAttribute.AvailableAttributeValues = (List <AvailableAttributeValue>)productAttribute.Tag; productAttribute.AvailableAttribute = availableAttribute; }) .OrderBy(x => x.DisplayOrder) .SelectNested() .ToList()); }
private IEnumerable <SKUInfo> GetOptions(int skuID, int categoryID, ISKUInfoProvider skuInfoProvider) { // Get all variant's options var variantOptionIDs = VariantOptionInfo.Provider.Get() .WhereIn("VariantSKUID", VariantHelper.GetVariants(skuID).Column("SKUID")) .Column("OptionSKUID"); var variantOptionsList = skuInfoProvider.Get() .WhereIn("SKUID", variantOptionIDs) .OrderBy("SKUOrder") .ToList(); // Create option categories with selectable variant options return(variantOptionsList.Where(o => o.SKUOptionCategoryID == categoryID)); }
/// <summary> /// Gets the categories with names from external data source or database. /// </summary> /// <param name="skuIdOfProductWithCategories">Id of product with categories.</param> private Dictionary <int, string> GetCategoriesWithNames(int skuIdOfProductWithCategories) { Dictionary <int, string> categoriesWithName = new Dictionary <int, string>(); if ((ExternalDataSource != null) && (ExternalDataSource.Count > 0)) { // External data foreach (OptionCategoryInfo info in ExternalDataSource.Keys) { // Use category live site display name in case it is available, otherwise category display name categoriesWithName.Add(info.CategoryID, info.CategoryTitle); } return(categoriesWithName); } // Load data from DB DataSet dsOptionCategories; // If ShowOnlyUsedCategories is true, dataset will contain only already used categories in variants if (ShowOnlyUsedCategories) { dsOptionCategories = VariantHelper.GetProductVariantsCategories(skuIdOfProductWithCategories); } else { dsOptionCategories = OptionCategoryInfoProvider.GetProductOptionCategories(skuIdOfProductWithCategories, true, OptionCategoryTypeEnum.Attribute); } if (DataHelper.DataSourceIsEmpty(dsOptionCategories)) { return(categoriesWithName); } foreach (DataRow catDr in dsOptionCategories.Tables[0].Rows) { int categoryId = ValidationHelper.GetInteger(catDr["CategoryID"], 0); string categoryName = ValidationHelper.GetString(catDr["CategoryLiveSiteDisplayName"], String.Empty); if (string.IsNullOrEmpty(categoryName)) { categoryName = ValidationHelper.GetString(catDr["CategoryDisplayName"], String.Empty); } categoriesWithName.Add(categoryId, categoryName); } return(categoriesWithName); }
/// <summary> /// Gets all options used in variant. /// </summary> /// <returns>Collection of option Ids used in variants.</returns> private List <string> GetOptionIdsUsedInVariant() { var options = SKUInfoProvider.GetSKUOptions(optionSKUCategoryInfo.CategoryID, false); var variantOptions = new List <string>(); // Check if some variant was created from the option foreach (var option in options) { if (VariantHelper.VariantExists(ProductID, new ProductAttributeSet(option.SKUID), false)) { variantOptions.Add(option.SKUID.ToString()); } } return(variantOptions); }
/// <summary> /// Creates category with variant attributes. /// </summary> /// <param name="optionsList">Product options</param> private void SetVariantAttributes(List <SKUInfo> optionsList) { // Get attributes category index - just before representing category var attrPos = editForm.FormInformation.ItemsList.FindIndex(f => (f is FormCategoryInfo) && ((FormCategoryInfo)f).CategoryName.EqualsCSafe("com.sku.representingcategory")); // Create attributes category var attCategory = new FormCategoryInfo() { CategoryName = "Attributes", IsDummy = true, }; attCategory.SetPropertyValue(FormCategoryPropertyEnum.Caption, HTMLHelper.HTMLEncode(GetString("com.variant.attributes"))); editForm.FormInformation.AddFormItem(attCategory, attrPos++); // Get variant categories var variantCategories = VariantHelper.GetProductVariantsCategories(ProductID, false); foreach (var category in variantCategories) { var option = optionsList.FirstOrDefault(o => o.SKUOptionCategoryID == category.CategoryID); if (option != null) { FormFieldInfo ffOption = new FormFieldInfo { Name = category.CategoryName, AllowEmpty = true, Size = 400, FieldType = FormFieldControlTypeEnum.LabelControl, DataType = FieldDataType.Text, IsDummyField = true, }; ffOption.SetPropertyValue(FormFieldPropertyEnum.DefaultValue, HTMLHelper.HTMLEncode(ResHelper.LocalizeString(option.SKUName))); // Show category live site display name instead of category display name in case it is available ffOption.SetPropertyValue(FormFieldPropertyEnum.FieldCaption, HTMLHelper.HTMLEncode(ResHelper.LocalizeString(category.CategoryTitle))); //Insert field to the form on specified position editForm.FormInformation.AddFormItem(ffOption, attrPos++); } } }
/// <summary> /// Sets current layout. /// </summary> protected void SetCurrentLayout(bool saveToWebPartInstance) { if ((webPart != null) && (LayoutCodeName != "|new|")) { if (saveToWebPartInstance) { if (LayoutCodeName == "|default|") { webPart.SetValue("WebPartLayout", ""); } else { webPart.SetValue("WebPartLayout", LayoutCodeName); } bool isWebPartVariant = (variantId > 0) || (zoneVariantId > 0) || isNewVariant; if (!isWebPartVariant) { // Update page template PageTemplateInfoProvider.SetPageTemplateInfo(pti); } else { // Save the variant properties if ((webPart != null) && (webPart.ParentZone != null) && (webPart.ParentZone.ParentTemplateInstance != null) && (webPart.ParentZone.ParentTemplateInstance.ParentPageTemplate != null)) { XmlNode xmlWebParts = (zoneVariantId > 0) ? webPart.ParentZone.GetXmlNode() : webPart.GetXmlNode(); VariantHelper.SetVariantWebParts(webPart.VariantMode, (zoneVariantId > 0) ? zoneVariantId : variantId, xmlWebParts); // The variants are cached -> Reload webPart.ParentZone.ParentTemplateInstance.LoadVariants(true, VariantModeEnum.None); } } } string parameters = aliasPath + "/" + zoneId + "/" + webpartId; string cacheName = "CMSVirtualWebParts|" + parameters.ToLowerCSafe().TrimStart('/'); CacheHelper.Remove(cacheName); } }
// Displaying product variants on MVC sites private object DummyEcommerceMethod4() { int productId = 0; IEnumerable <int> optionIds = new List <int>() { 1, 2, 3 }; //DocSection:VariantFromOptionIds // Retrieves a product variant from a given product ID and a collection of option IDs var variantSKU = VariantHelper.GetProductVariant(productId, new ProductAttributeSet(optionIds)); if (variantSKU == null) { return(null); } return(variantSKU); //EndDocSection:VariantFromOptionIds }
/// <summary> /// Removes category bindings assigned to SKU. /// </summary> /// <param name="categoryIDs">ID of categories which should be removed</param> /// <returns>Returns true if some category binding was removed.</returns> private bool RemoveSKUCategoryBindings(IEnumerable <int> categoryIDs) { var ids = categoryIDs.ToList(); var variantCategoryIDs = VariantHelper.GetProductVariantsCategoryIDs(ProductID); var categoryIDsToRemove = ids.Except(variantCategoryIDs).ToList(); foreach (var id in categoryIDsToRemove) { ProductHelper.RemoveOptionCategory(ProductID, id); } // Categories are already used in variants -> they cannot be removed if (ids.Except(categoryIDsToRemove).Any()) { ShowWarning(GetString("com.optioncategory.remove")); } return(categoryIDsToRemove.Any()); }
//EndDocSection:DisplayProduct //DocSection:DisplayVariant /// <summary> /// Displays product detail page of a product or product variant specified by the GUID of the product's or variant's page. /// </summary> /// <param name="guid">Node GUID of the product's (variant's) page.</param> /// <param name="productAlias">Node alias of the product's (variant's) page.</param> public ActionResult Detail(Guid guid, string productAlias) { // Gets the product from the connected Kentico database SKUTreeNode product = GetProduct(guid); // If the product is not found or if it is not allowed for sale, redirects to error 404 if ((product == null) || !product.SKU.SKUEnabled) { return(HttpNotFound()); } // Redirects if the specified page alias does not match if (!string.IsNullOrEmpty(productAlias) && !product.NodeAlias.Equals(productAlias, StringComparison.InvariantCultureIgnoreCase)) { return(RedirectToActionPermanent("Detail", new { guid = product.NodeGUID, productAlias = product.NodeAlias })); } // Gets all product variants of the product List <ProductVariant> variants = VariantHelper.GetVariants(product.NodeSKUID).OnSite(SiteContext.CurrentSiteID).ToList() .Select(sku => new ProductVariant(sku.SKUID)) .OrderBy(v => v.Variant.SKUPrice).ToList(); // Selects the first product variant ProductVariant selectedVariant = variants.FirstOrDefault(); // Calculates the price of the product or the variant ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart(); SKUInfo selectedProduct = selectedVariant != null ? selectedVariant.Variant : product.SKU; ProductCatalogPrices priceDetail = calculatorFactory .GetCalculator(cart.ShoppingCartSiteID) .GetPrices(selectedProduct, Enumerable.Empty <SKUInfo>(), cart); // Initializes the view model of the product or product variant ProductViewModel viewModel = new ProductViewModel(product, priceDetail, variants, selectedVariant?.Variant?.SKUID ?? 0); // Displays the product detail page return(View(viewModel)); }
/// <summary> /// Hide/rename columns in uniGrid before loading data. /// </summary> private void grid_OnBeforeDataReload() { switch (categoryObj.CategoryType) { case OptionCategoryTypeEnum.Attribute: case OptionCategoryTypeEnum.Text: ugOptions.NamedColumns["SKUName"].HeaderText = GetString("unigrid.productoptions.OptionName"); ugOptions.NamedColumns["SKUNumber"].Visible = false; ugOptions.NamedColumns["SKUDepartment"].Visible = false; ugOptions.NamedColumns["SKUAvailableItems"].Visible = false; break; } // Hide price adjustment if category is used in product variants if (parentProductId > 0) { if (VariantHelper.AreCategoriesUsedInVariants(QueryHelper.GetInteger("productId", 0), new[] { categoryObj.CategoryID })) { ugOptions.NamedColumns["SKUPrice"].Visible = false; } } }
/// <summary> /// Generates variants, builds UniGrid and binds data to it. /// </summary> private void SetupVariants(bool regenerate = true) { // Do not setup variants, when callback is requesting page if (RequestHelper.IsCallback()) { return; } // Limit maximum variants count const int maxVariantsCount = 1000; if (VariantHelper.GetAllPossibleVariantsCount(ProductID, CategorySelector.SelectedCategories.Keys) > maxVariantsCount) { ShowWarning(GetString("com.variants.variantlimit")); return; } if (regenerate) { // Generate Variants mGeneratedVariants = GenerateVariants(); ExistingItems = null; } // Set UniGrid columns and other properties VariantGrid.GridColumns.Columns = mColumnDefinitions; VariantGrid.GridOptions.DisplayFilter = false; VariantGrid.GridOptions.ShowSelection = true; VariantGrid.GridOptions.SelectionColumn = "RowNumber"; var existingItems = ExistingItems; VariantGrid.SelectedItems = ((existingItems != null) && (existingItems.Count > 0)) ? existingItems : VariantGrid.SelectedItems; // Bind data to UniGrid VariantGrid.DataSource = mGeneratedVariants; VariantGrid.ReloadData(); }
/// <summary> /// Returns an enumerable collection of all variants of the given product. /// </summary> /// <param name="productId">SKU object identifier of the variant's parent product.</param> /// <returns>Collection of product variants. See <see cref="Variant"/> for detailed information.</returns> public IEnumerable <Variant> GetByProductId(int productId) { var variantSKUs = VariantHelper.GetVariants(productId).OnSite(SiteID).ToList(); // Get the used option IDs for the variants var variantOptions = VariantOptionInfoProvider.GetVariantOptions() .WhereIn("VariantSKUID", variantSKUs.Select(s => s.SKUID).ToList()) .ToList(); // Pre-load option SKUs for the variants var options = SKUInfoProvider.GetSKUs() .WhereIn("SKUID", variantOptions.Select(v => v.OptionSKUID).ToList()) .ToList(); // Create variants with the options return(variantSKUs.Select(sku => new Variant( sku, new ProductAttributeSet(variantOptions .Where(o => o.VariantSKUID == sku.SKUID) .Select(o => options.First(s => s.SKUID == o.OptionSKUID)) .ToArray()) ))); }
/// <summary> /// Returns a collection of option categories used in a product's variants. /// </summary> /// <param name="productId">SKU identifier of the variant's parent product.</param> /// <returns>Collection of option categories used in a product's variants. See <see cref="ProductOptionCategory"/> for detailed information.</returns> public IEnumerable <ProductOptionCategory> GetVariantOptionCategories(int productId) { // Get a list of option categories var optionCategoriesList = VariantHelper.GetProductVariantsCategories(productId).ToList(); // Get all variant's options var variantOptionIDs = VariantOptionInfoProvider.GetVariantOptions() .WhereIn("VariantSKUID", VariantHelper.GetVariants(productId).Column("SKUID")) .Column("OptionSKUID"); var variantOptionsList = SKUInfoProvider.GetSKUs() .WhereIn("SKUID", variantOptionIDs) .OrderBy("SKUOrder") .ToList(); // Create option categories with selectable variant options return(optionCategoriesList.Select(cat => new ProductOptionCategory( cat, variantOptionsList.Where(o => o.SKUOptionCategoryID == cat.CategoryID) ) )); }
/// <summary> /// Removes category bindings assigned to SKU. /// </summary> /// <param name="categoryIDs">ID of categories which should be removed</param> /// <returns>Returns true if some category binding was removed.</returns> private bool RemoveSKUCategoryBindings(IEnumerable <int> categoryIDs) { var ids = categoryIDs.ToList(); // GetProductVariantsCategories create a complex query with join included -> column must be defined with table name prefix // Convert query to list before calling Select, otherwise there will be ambiguous column CategoryID var variantCategoryIDs = VariantHelper.GetProductVariantsCategories(ProductID, false).Column("COM_OptionCategory.CategoryID").ToList().Select(category => category.CategoryID).ToList(); var categoryIDsToRemove = ids.Except(variantCategoryIDs).ToList(); foreach (var id in categoryIDsToRemove) { ProductHelper.RemoveOptionCategory(ProductID, id); } // Categories are already used in variants -> they cannot be removed if (ids.Except(categoryIDsToRemove).Any()) { ShowWarning(GetString("com.optioncategory.remove")); } return(categoryIDsToRemove.Any()); }
//EndDocSection:DisplayProduct //DocSection:DisplayVariant /// <summary> /// Displays product detail page of a product or product variant. /// </summary> public ActionResult Detail() { // Gets the product from the connected Xperience database SKUTreeNode product = GetProduct(); // If the product is not found or if it is not allowed for sale, redirects to error 404 if ((product == null) || !product.SKU.SKUEnabled) { return(NotFound()); } // Gets all product variants of the product List <ProductVariant> variants = VariantHelper .GetVariants(product.NodeSKUID) .OnSite(siteService.CurrentSite.SiteID).ToList() .Select(sku => new ProductVariant(sku.SKUID)) .OrderBy(v => v.Variant.SKUPrice).ToList(); // Selects the first product variant ProductVariant selectedVariant = variants.FirstOrDefault(); // Calculates the price of the product or the variant ShoppingCartInfo cart = shoppingService.GetCurrentShoppingCart(); SKUInfo selectedProduct = selectedVariant != null ? selectedVariant.Variant : product.SKU; ProductCatalogPrices priceDetail = priceCalculatorFactory .GetCalculator(cart.ShoppingCartSiteID) .GetPrices(selectedProduct, Enumerable.Empty <SKUInfo>(), cart); // Initializes the view model of the product or product variant ProductViewModel viewModel = new ProductViewModel(product, priceDetail, variants, selectedVariant?.Variant?.SKUID ?? 0); // Displays the product detail page return(View(viewModel)); }
/// <summary> /// Saves webpart properties. /// </summary> public bool Save() { // Check MVT/CP security if (VariantID > 0) { // Check OnlineMarketing permissions. if (!CheckPermissions("Manage")) { ShowError(GetString("general.modifynotallowed")); return(false); } } // Save the data if ((pi != null) && (pti != null) && (templateInstance != null) && SaveForm(form)) { if (SynchronizationHelper.IsCheckedOutByOtherUser(pti)) { string userName = null; UserInfo ui = UserInfoProvider.GetUserInfo(pti.Generalized.IsCheckedOutByUserID); if (ui != null) { userName = HTMLHelper.HTMLEncode(ui.GetFormattedUserName(IsLiveSite)); } ShowError(string.Format(GetString("ObjectEditMenu.CheckedOutByAnotherUser"), pti.TypeInfo.ObjectType, pti.DisplayName, userName)); return(false); } // Add web part if new if (IsNewWebPart) { int webpartId = ValidationHelper.GetInteger(WebPartID, 0); // Ensure layout zone flag if (QueryHelper.GetBoolean("layoutzone", false)) { WebPartZoneInstance zone = pti.TemplateInstance.EnsureZone(ZoneID); zone.LayoutZone = true; } webPartInstance = PortalHelper.AddNewWebPart(webpartId, ZoneID, false, ZoneVariantID, Position, templateInstance); // Set default layout if (wpi.WebPartParentID > 0) { WebPartLayoutInfo wpli = WebPartLayoutInfoProvider.GetDefaultLayout(wpi.WebPartID); if (wpli != null) { webPartInstance.SetValue("WebPartLayout", wpli.WebPartLayoutCodeName); } } } webPartInstance.XMLVersion = 1; if (IsNewVariant) { webPartInstance = webPartInstance.Clone(); webPartInstance.VariantMode = VariantModeFunctions.GetVariantModeEnum(QueryHelper.GetString("variantmode", String.Empty).ToLowerInvariant()); } // Get basic form's data row and update web part SaveFormToWebPart(form); // Set new position if set if (PositionLeft > 0) { webPartInstance.SetValue("PositionLeft", PositionLeft); } if (PositionTop > 0) { webPartInstance.SetValue("PositionTop", PositionTop); } bool isWebPartVariant = (VariantID > 0) || (ZoneVariantID > 0) || IsNewVariant; if (!isWebPartVariant) { // Save the changes CMSPortalManager.SaveTemplateChanges(pi, templateInstance, WidgetZoneTypeEnum.None, ViewModeEnum.Design, tree); } else { Hashtable varProperties = WindowHelper.GetItem("variantProperties") as Hashtable; // Save changes to the web part variant VariantHelper.SaveWebPartVariantChanges(webPartInstance, VariantID, ZoneVariantID, VariantMode, varProperties); } // Reload the form (because of macro values set only by JS) form.ReloadData(); // Clear the cached web part CacheHelper.TouchKey("webpartinstance|" + InstanceGUID.ToString().ToLowerInvariant()); ShowChangesSaved(); return(true); } if (webPartInstance?.ParentZone?.ParentTemplateInstance != null) { // Reload the zone/web part variants when saving of the form fails webPartInstance.ParentZone.ParentTemplateInstance.LoadVariants(true, VariantModeEnum.None); } return(false); }
/// <summary> /// Loads the web part form. /// </summary> protected void LoadForm() { // Load settings if (!string.IsNullOrEmpty(Request.Form[hdnIsNewWebPart.UniqueID])) { IsNewWebPart = ValidationHelper.GetBoolean(Request.Form[hdnIsNewWebPart.UniqueID], false); } if (!string.IsNullOrEmpty(Request.Form[hdnInstanceGUID.UniqueID])) { InstanceGUID = ValidationHelper.GetGuid(Request.Form[hdnInstanceGUID.UniqueID], Guid.Empty); } // Indicates whether the new variant should be chosen when closing this dialog selectNewVariant = IsNewVariant; // Try to find the web part variant in the database and set its VariantID if (IsNewVariant) { Hashtable varProperties = WindowHelper.GetItem("variantProperties") as Hashtable; if (varProperties != null) { // Get the variant code name from the WindowHelper string variantName = ValidationHelper.GetString(varProperties["codename"], string.Empty); // Check if the variant exists in the database int variantIdFromDB = VariantHelper.GetVariantID(VariantMode, PageTemplateID, variantName, true); // Set the variant id from the database if (variantIdFromDB > 0) { VariantID = variantIdFromDB; IsNewVariant = false; } } } if (!String.IsNullOrEmpty(WebPartID)) { // Get the page info pi = CMSWebPartPropertiesPage.GetPageInfo(AliasPath, PageTemplateID, CultureCode); if (pi == null) { ShowError(GetString("general.pagenotfound")); pnlExport.Visible = false; return; } // Get template pti = pi.UsedPageTemplateInfo; // Get template instance templateInstance = pti.TemplateInstance; if (!IsNewWebPart) { // Standard zone webPartInstance = templateInstance.GetWebPart(InstanceGUID, WebPartID); // If the web part not found, try to find it among the MVT/CP variants if (webPartInstance == null) { // MVT/CP variant // Clone templateInstance to avoid caching of the temporary template instance loaded with CP/MVT variants var tempTemplateInstance = templateInstance.Clone(); tempTemplateInstance.LoadVariants(false, VariantModeEnum.None); webPartInstance = tempTemplateInstance.GetWebPart(InstanceGUID, -1); // Set the VariantMode according to the selected web part/zone variant if (webPartInstance?.ParentZone != null) { VariantMode = (webPartInstance.VariantMode != VariantModeEnum.None) ? webPartInstance.VariantMode : webPartInstance.ParentZone.VariantMode; } else { VariantMode = VariantModeEnum.None; } } else { // Ensure that the ZoneVariantID is not set when the web part was found in a regular zone ZoneVariantID = 0; } if ((VariantID > 0) && webPartInstance?.PartInstanceVariants != null) { // Check OnlineMarketing permissions. if (CheckPermissions("Read")) { webPartInstance = webPartInstance.FindVariant(VariantID); } else { // Not authorized for OnlineMarketing - Manage. RedirectToInformation(String.Format(GetString("general.permissionresource"), "Read", (VariantMode == VariantModeEnum.ContentPersonalization) ? "CMS.ContentPersonalization" : "CMS.MVTest")); } } if (webPartInstance == null) { UIContext.EditedObject = null; return; } } // Keep xml version if (webPartInstance != null) { xmlVersion = webPartInstance.XMLVersion; } // Get the form info FormInfo fi = GetWebPartFormInfo(); // Get the form definition if (fi != null) { fi.ContextResolver.Settings.RelatedObject = templateInstance; form.AllowMacroEditing = true; // Get data row with required columns DataRow dr = fi.GetDataRow(); if (IsNewWebPart || (xmlVersion > 0)) { fi.LoadDefaultValues(dr); } // Load values from existing web part LoadDataRowFromWebPart(dr, webPartInstance, fi); // Set a unique WebPartControlID for the new variant if (IsNewVariant || IsNewWebPart) { dr["WebPartControlID"] = GetUniqueWebPartId(); } // Init the form InitForm(form, dr, fi); DisplayExportPropertiesButton(); } else { UIContext.EditedObject = null; } } }
protected void uniSelector_OnSelectionChanged(object sender, EventArgs e) { var cu = MembershipContext.AuthenticatedUser; // Check permissions if ((cu == null) || (!cu.IsAuthorizedPerResource(ModuleName.ECOMMERCE, EcommercePermissions.ECOMMERCE_MODIFY) && !cu.IsAuthorizedPerResource(ModuleName.ECOMMERCE, EcommercePermissions.PRODUCTS_MODIFY))) { RedirectToAccessDenied(ModuleName.ECOMMERCE, "EcommerceModify OR ModifyProducts"); } else { string newValues = ValidationHelper.GetString(uniSelector.Value, null); string addItems = DataHelper.GetNewItemsInList(UniSelectorData, newValues); string removeItems = DataHelper.GetNewItemsInList(newValues, UniSelectorData); // Add SKU to Option Category if (!String.IsNullOrEmpty(addItems)) { string[] newItems = addItems.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (string item in newItems) { SKUOptionCategoryInfoProvider.AddOptionCategoryToSKU(categoryId, ValidationHelper.GetInteger(item, 0)); } // Show message ShowChangesSaved(); } // Remove SKU from Option Category if (!String.IsNullOrEmpty(removeItems)) { string[] productIds = removeItems.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); bool displayWarning = false; StringBuilder ids = new StringBuilder(); // Check if category is not used in variants of product foreach (string skuID in productIds) { int productId = ValidationHelper.GetInteger(skuID, 0); // Inform user that removing of product is not possible if (VariantHelper.AreCategoriesUsedInVariants(productId, new int[] { categoryId })) { displayWarning = true; ids.Append(";" + skuID); } else { ProductHelper.RemoveOptionCategory(productId, categoryId); } } if (displayWarning) { // Display items which cannot be removed in the selector uniSelector.Value += ids.ToString(); ShowWarning(GetString("com.optioncategory.removeproduct")); } else { ShowChangesSaved(); } } } PreloadUniSelector(true); }
/// <summary> /// Saves widget properties. /// </summary> public bool Save() { if (VariantID > 0) { // Check MVT/CP security if (!CheckPermissions("Manage")) { DisplayError("general.modifynotallowed"); return(false); } } // Save the data if ((CurrentPageInfo != null) && (mTemplateInstance != null) && SaveForm(formCustom)) { ViewModeEnum viewMode = PortalContext.ViewMode; // Check manage permission for non-livesite version if (!viewMode.IsLiveSite() && viewMode != ViewModeEnum.DashboardWidgets && viewMode != ViewModeEnum.UserWidgets) { if (CurrentUser.IsAuthorizedPerDocument(CurrentPageInfo.NodeID, CurrentPageInfo.ClassName, NodePermissionsEnum.Modify) != AuthorizationResultEnum.Allowed) { DisplayError("general.modifynotallowed"); return(false); } // Check design permissions if (PortalContext.IsDesignMode(viewMode, false) && !PortalContext.CurrentUserIsDesigner) { RedirectToAccessDenied("CMS.Design", "Design"); } } PageTemplateInfo pti = mTemplateInstance.ParentPageTemplate; if (PortalContext.IsDesignMode(viewMode) && SynchronizationHelper.IsCheckedOutByOtherUser(pti)) { string userName = null; UserInfo ui = UserInfoProvider.GetUserInfo(pti.Generalized.IsCheckedOutByUserID); if (ui != null) { userName = HTMLHelper.HTMLEncode(ui.GetFormattedUserName(IsLiveSite)); } DisplayError(string.Format(GetString("ObjectEditMenu.CheckedOutByAnotherUser"), pti.TypeInfo.ObjectType, pti.DisplayName, userName)); return(false); } // Get the zone mWebPartZoneInstance = mTemplateInstance.EnsureZone(ZoneId); if (mWebPartZoneInstance != null) { mWebPartZoneInstance.WidgetZoneType = ZoneType; // Add new widget if (IsNewWidget) { bool isLayoutZone = (QueryHelper.GetBoolean("layoutzone", false)); int widgetID = ValidationHelper.GetInteger(WidgetId, 0); // Create new widget instance mWidgetInstance = PortalHelper.AddNewWidget(widgetID, ZoneId, ZoneType, isLayoutZone, mTemplateInstance); } // Ensure handling of the currently edited object (if not exists -> redirect) UIContext.EditedObject = mWidgetInstance; mWidgetInstance.XMLVersion = 1; if (IsNewVariant) { mWidgetInstance = mWidgetInstance.Clone(); // Check whether the editor widgets have been already customized if (CurrentPageInfo.DocumentTemplateInstance.WebPartZones.Count == 0) { // There are no customized editor widgets yet => copy the default editor widgets from the page template under the document (to enable customization) // Save to the document as editor admin changes TreeNode node = DocumentHelper.GetDocument(CurrentPageInfo.DocumentID, mTreeProvider); // Extract and set the document web parts node.SetValue("DocumentWebParts", mTemplateInstance.GetZonesXML(WidgetZoneTypeEnum.Editor)); // Save the document DocumentHelper.UpdateDocument(node, mTreeProvider); } } bool isLayoutWidget = ((mWebPartInfo != null) && ((WebPartTypeEnum)mWebPartInfo.WebPartType == WebPartTypeEnum.Layout)); // Get basicform's datarow and update widget SaveFormToWidget(formCustom, mTemplateInstance, isLayoutWidget); // Ensure unique id for new widget variant or layout widget if (IsNewVariant || (isLayoutWidget && IsNewWidget)) { string controlId = GetUniqueWidgetId(mWidgetInfo.WidgetName); if (!string.IsNullOrEmpty(controlId)) { mWidgetInstance.ControlID = controlId; } else { DisplayError("Unable to generate unique widget id."); return(false); } } // Allow set dashboard in design mode if ((ZoneType == WidgetZoneTypeEnum.Dashboard) && String.IsNullOrEmpty(PortalContext.DashboardName)) { viewMode = ViewModeEnum.Design; PortalContext.SetViewMode(ViewModeEnum.Design); } bool isWidgetVariant = (VariantID > 0) || IsNewVariant; if (!isWidgetVariant) { // Save the changes if ((viewMode.IsEdit(true) || viewMode.IsEditLive()) && (ZoneType == WidgetZoneTypeEnum.Editor)) { if (DocumentManager.AllowSave) { // Store the editor widgets in the temporary interlayer PortalContext.SaveEditorWidgets(CurrentPageInfo.DocumentID, mTemplateInstance.GetZonesXML(WidgetZoneTypeEnum.Editor)); } } else { // Save the changes CMSPortalManager.SaveTemplateChanges(CurrentPageInfo, mTemplateInstance, ZoneType, viewMode, mTreeProvider); } } else if ((viewMode.IsEdit()) && (ZoneType == WidgetZoneTypeEnum.Editor)) { Hashtable properties = WindowHelper.GetItem("variantProperties") as Hashtable; VariantHelper.SaveWebPartVariantChanges(mWidgetInstance, VariantID, 0, VariantMode, properties); // Log widget variant synchronization TreeNode node = DocumentHelper.GetDocument(CurrentPageInfo.DocumentID, mTreeProvider); DocumentSynchronizationHelper.LogDocumentChange(node, TaskTypeEnum.UpdateDocument, mTreeProvider); } } // Reload the form (because of macro values set only by JS) formCustom.ReloadData(); // Display info message ShowChangesSaved(); // Clear the cached web part CacheHelper.TouchKey("webpartinstance|" + InstanceGUID.ToString().ToLowerCSafe()); return(true); } return(false); }