Try your search with a different keyword or use * as a wildcard.
using System.ComponentModel;
using System.Net;
using System.Text;
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.Rendering;
using Newtonsoft.Json;
using Nop.Core;
using Nop.Core.Domain.Catalog;
using Nop.Core.Domain.Common;
using Nop.Core.Domain.Directory;
using Nop.Core.Domain.Discounts;
using Nop.Core.Domain.Orders;
using Nop.Core.Domain.Tax;
using Nop.Core.Domain.Vendors;
using Nop.Services.Catalog;
using Nop.Services.Common;
using Nop.Services.Configuration;
using Nop.Services.Customers;
using Nop.Services.Directory;
using Nop.Services.Discounts;
using Nop.Services.Helpers;
using Nop.Services.Localization;
using Nop.Services.Media;
using Nop.Services.Orders;
using Nop.Services.Seo;
using Nop.Services.Shipping;
using Nop.Services.Stores;
using Nop.Web.Areas.Admin.Infrastructure.Mapper.Extensions;
using Nop.Web.Areas.Admin.Models.Catalog;
using Nop.Web.Areas.Admin.Models.Common;
using Nop.Web.Areas.Admin.Models.Orders;
using Nop.Web.Framework.Extensions;
using Nop.Web.Framework.Factories;
using Nop.Web.Framework.Models.Extensions;
namespace Nop.Web.Areas.Admin.Factories;
///
/// Represents the product model factory implementation
///
public partial class ProductModelFactory : IProductModelFactory
{
#region Fields
protected readonly CatalogSettings _catalogSettings;
protected readonly CurrencySettings _currencySettings;
protected readonly IAclSupportedModelFactory _aclSupportedModelFactory;
protected readonly IAddressService _addressService;
protected readonly IBaseAdminModelFactory _baseAdminModelFactory;
protected readonly ICategoryService _categoryService;
protected readonly ICurrencyService _currencyService;
protected readonly ICustomerService _customerService;
protected readonly IDateTimeHelper _dateTimeHelper;
protected readonly IDiscountService _discountService;
protected readonly IDiscountSupportedModelFactory _discountSupportedModelFactory;
protected readonly ILocalizationService _localizationService;
protected readonly ILocalizedModelFactory _localizedModelFactory;
protected readonly IManufacturerService _manufacturerService;
protected readonly IMeasureService _measureService;
protected readonly IOrderService _orderService;
protected readonly IPictureService _pictureService;
protected readonly IProductAttributeFormatter _productAttributeFormatter;
protected readonly IProductAttributeParser _productAttributeParser;
protected readonly IProductAttributeService _productAttributeService;
protected readonly IProductService _productService;
protected readonly IProductTagService _productTagService;
protected readonly IProductTemplateService _productTemplateService;
protected readonly ISettingModelFactory _settingModelFactory;
protected readonly ISettingService _settingService;
protected readonly IShipmentService _shipmentService;
protected readonly IShippingService _shippingService;
protected readonly IShoppingCartService _shoppingCartService;
protected readonly ISpecificationAttributeService _specificationAttributeService;
protected readonly IStoreMappingSupportedModelFactory _storeMappingSupportedModelFactory;
protected readonly IStoreContext _storeContext;
protected readonly IStoreService _storeService;
protected readonly IUrlRecordService _urlRecordService;
protected readonly IVideoService _videoService;
protected readonly IWorkContext _workContext;
protected readonly MeasureSettings _measureSettings;
protected readonly NopHttpClient _nopHttpClient;
protected readonly TaxSettings _taxSettings;
protected readonly VendorSettings _vendorSettings;
#endregion
#region Ctor
public ProductModelFactory(CatalogSettings catalogSettings,
CurrencySettings currencySettings,
IAclSupportedModelFactory aclSupportedModelFactory,
IAddressService addressService,
IBaseAdminModelFactory baseAdminModelFactory,
ICategoryService categoryService,
ICurrencyService currencyService,
ICustomerService customerService,
IDateTimeHelper dateTimeHelper,
IDiscountService discountService,
IDiscountSupportedModelFactory discountSupportedModelFactory,
ILocalizationService localizationService,
ILocalizedModelFactory localizedModelFactory,
IManufacturerService manufacturerService,
IMeasureService measureService,
IOrderService orderService,
IPictureService pictureService,
IProductAttributeFormatter productAttributeFormatter,
IProductAttributeParser productAttributeParser,
IProductAttributeService productAttributeService,
IProductService productService,
IProductTagService productTagService,
IProductTemplateService productTemplateService,
ISettingModelFactory settingModelFactory,
ISettingService settingService,
IShipmentService shipmentService,
IShippingService shippingService,
IShoppingCartService shoppingCartService,
ISpecificationAttributeService specificationAttributeService,
IStoreMappingSupportedModelFactory storeMappingSupportedModelFactory,
IStoreContext storeContext,
IStoreService storeService,
IUrlRecordService urlRecordService,
IVideoService videoService,
IWorkContext workContext,
MeasureSettings measureSettings,
NopHttpClient nopHttpClient,
TaxSettings taxSettings,
VendorSettings vendorSettings)
{
_catalogSettings = catalogSettings;
_currencySettings = currencySettings;
_aclSupportedModelFactory = aclSupportedModelFactory;
_addressService = addressService;
_baseAdminModelFactory = baseAdminModelFactory;
_categoryService = categoryService;
_currencyService = currencyService;
_customerService = customerService;
_dateTimeHelper = dateTimeHelper;
_discountService = discountService;
_discountSupportedModelFactory = discountSupportedModelFactory;
_localizationService = localizationService;
_localizedModelFactory = localizedModelFactory;
_manufacturerService = manufacturerService;
_measureService = measureService;
_orderService = orderService;
_pictureService = pictureService;
_productAttributeFormatter = productAttributeFormatter;
_productAttributeParser = productAttributeParser;
_productAttributeService = productAttributeService;
_productService = productService;
_productTagService = productTagService;
_productTemplateService = productTemplateService;
_settingModelFactory = settingModelFactory;
_settingService = settingService;
_shipmentService = shipmentService;
_shippingService = shippingService;
_shoppingCartService = shoppingCartService;
_specificationAttributeService = specificationAttributeService;
_storeMappingSupportedModelFactory = storeMappingSupportedModelFactory;
_storeContext = storeContext;
_storeService = storeService;
_urlRecordService = urlRecordService;
_videoService = videoService;
_workContext = workContext;
_measureSettings = measureSettings;
_nopHttpClient = nopHttpClient;
_taxSettings = taxSettings;
_vendorSettings = vendorSettings;
}
#endregion
#region Utilities
/// A task that represents the asynchronous operation
protected virtual async Task GetSpecificationAttributeNameAsync(SpecificationAttribute specificationAttribute)
{
var name = specificationAttribute.Name;
if (specificationAttribute.SpecificationAttributeGroupId.HasValue)
{
var group = await _specificationAttributeService.GetSpecificationAttributeGroupByIdAsync(specificationAttribute.SpecificationAttributeGroupId.Value);
if (group != null)
name = string.Format(await _localizationService.GetResourceAsync("Admin.Catalog.Products.SpecificationAttributes.NameFormat"), group.Name, name);
}
return name;
}
///
/// Prepare copy product model
///
/// Copy product model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the copy product model
///
protected virtual async Task PrepareCopyProductModelAsync(CopyProductModel model, Product product)
{
ArgumentNullException.ThrowIfNull(model);
model.Id = product.Id;
model.Name = string.Format(await _localizationService.GetResourceAsync("Admin.Catalog.Products.Copy.Name.New"), product.Name);
model.Published = true;
model.CopyMultimedia = true;
return model;
}
///
/// Prepare product warehouse inventory models
///
/// List of product warehouse inventory models
/// Product
/// A task that represents the asynchronous operation
protected virtual async Task PrepareProductWarehouseInventoryModelsAsync(IList models, Product product)
{
ArgumentNullException.ThrowIfNull(models);
foreach (var warehouse in await _shippingService.GetAllWarehousesAsync())
{
var model = new ProductWarehouseInventoryModel
{
WarehouseId = warehouse.Id,
WarehouseName = warehouse.Name
};
if (product != null)
{
var productWarehouseInventory = (await _productService.GetAllProductWarehouseInventoryRecordsAsync(product.Id))?.FirstOrDefault(inventory => inventory.WarehouseId == warehouse.Id);
if (productWarehouseInventory != null)
{
model.WarehouseUsed = true;
model.StockQuantity = productWarehouseInventory.StockQuantity;
model.ReservedQuantity = productWarehouseInventory.ReservedQuantity;
model.PlannedQuantity = await _shipmentService.GetQuantityInShipmentsAsync(product, productWarehouseInventory.WarehouseId, true, true);
}
}
models.Add(model);
}
}
///
/// Prepare product attribute mapping validation rules string
///
/// Product attribute mapping
///
/// A task that represents the asynchronous operation
/// The task result contains the validation rules string
///
protected virtual async Task PrepareProductAttributeMappingValidationRulesStringAsync(ProductAttributeMapping attributeMapping)
{
if (!attributeMapping.ValidationRulesAllowed())
return string.Empty;
var validationRules = new StringBuilder(string.Empty);
if (attributeMapping.ValidationMinLength.HasValue)
{
validationRules.AppendFormat("{0}: {1}
",
await _localizationService.GetResourceAsync("Admin.Catalog.Products.ProductAttributes.Attributes.ValidationRules.MinLength"),
attributeMapping.ValidationMinLength);
}
if (attributeMapping.ValidationMaxLength.HasValue)
{
validationRules.AppendFormat("{0}: {1}
",
await _localizationService.GetResourceAsync("Admin.Catalog.Products.ProductAttributes.Attributes.ValidationRules.MaxLength"),
attributeMapping.ValidationMaxLength);
}
if (!string.IsNullOrEmpty(attributeMapping.ValidationFileAllowedExtensions))
{
validationRules.AppendFormat("{0}: {1}
",
await _localizationService.GetResourceAsync("Admin.Catalog.Products.ProductAttributes.Attributes.ValidationRules.FileAllowedExtensions"),
WebUtility.HtmlEncode(attributeMapping.ValidationFileAllowedExtensions));
}
if (attributeMapping.ValidationFileMaximumSize.HasValue)
{
validationRules.AppendFormat("{0}: {1}
",
await _localizationService.GetResourceAsync("Admin.Catalog.Products.ProductAttributes.Attributes.ValidationRules.FileMaximumSize"),
attributeMapping.ValidationFileMaximumSize);
}
if (!string.IsNullOrEmpty(attributeMapping.DefaultValue))
{
validationRules.AppendFormat("{0}: {1}
",
await _localizationService.GetResourceAsync("Admin.Catalog.Products.ProductAttributes.Attributes.ValidationRules.DefaultValue"),
WebUtility.HtmlEncode(attributeMapping.DefaultValue));
}
return validationRules.ToString();
}
///
/// Prepare product attribute condition model
///
/// Product attribute condition model
/// Product attribute mapping
/// A task that represents the asynchronous operation
protected virtual async Task PrepareProductAttributeConditionModelAsync(ProductAttributeConditionModel model,
ProductAttributeMapping productAttributeMapping)
{
ArgumentNullException.ThrowIfNull(model);
ArgumentNullException.ThrowIfNull(productAttributeMapping);
model.ProductAttributeMappingId = productAttributeMapping.Id;
model.EnableCondition = !string.IsNullOrEmpty(productAttributeMapping.ConditionAttributeXml);
//pre-select attribute and values
var selectedPva = (await _productAttributeParser
.ParseProductAttributeMappingsAsync(productAttributeMapping.ConditionAttributeXml))
.FirstOrDefault();
var attributes = (await _productAttributeService.GetProductAttributeMappingsByProductIdAsync(productAttributeMapping.ProductId))
//ignore non-combinable attributes (should have selectable values)
.Where(x => x.CanBeUsedAsCondition())
//ignore this attribute (it cannot depend on itself)
.Where(x => x.Id != productAttributeMapping.Id)
.ToList();
foreach (var attribute in attributes)
{
var attributeModel = new ProductAttributeConditionModel.ProductAttributeModel
{
Id = attribute.Id,
ProductAttributeId = attribute.ProductAttributeId,
Name = (await _productAttributeService.GetProductAttributeByIdAsync(attribute.ProductAttributeId)).Name,
TextPrompt = attribute.TextPrompt,
IsRequired = attribute.IsRequired,
AttributeControlType = attribute.AttributeControlType
};
if (attribute.ShouldHaveValues())
{
//values
var attributeValues = await _productAttributeService.GetProductAttributeValuesAsync(attribute.Id);
foreach (var attributeValue in attributeValues)
{
var attributeValueModel = new ProductAttributeConditionModel.ProductAttributeValueModel
{
Id = attributeValue.Id,
Name = attributeValue.Name,
IsPreSelected = attributeValue.IsPreSelected
};
attributeModel.Values.Add(attributeValueModel);
}
//pre-select attribute and value
if (selectedPva != null && attribute.Id == selectedPva.Id)
{
//attribute
model.SelectedProductAttributeId = selectedPva.Id;
//values
switch (attribute.AttributeControlType)
{
case AttributeControlType.DropdownList:
case AttributeControlType.RadioList:
case AttributeControlType.Checkboxes:
case AttributeControlType.ColorSquares:
case AttributeControlType.ImageSquares:
if (!string.IsNullOrEmpty(productAttributeMapping.ConditionAttributeXml))
{
//clear default selection
foreach (var item in attributeModel.Values)
item.IsPreSelected = false;
//select new values
var selectedValues =
await _productAttributeParser.ParseProductAttributeValuesAsync(productAttributeMapping
.ConditionAttributeXml);
foreach (var attributeValue in selectedValues)
foreach (var item in attributeModel.Values)
if (attributeValue.Id == item.Id)
item.IsPreSelected = true;
}
break;
case AttributeControlType.ReadonlyCheckboxes:
case AttributeControlType.TextBox:
case AttributeControlType.MultilineTextbox:
case AttributeControlType.Datepicker:
case AttributeControlType.FileUpload:
default:
//these attribute types are supported as conditions
break;
}
}
}
model.ProductAttributes.Add(attributeModel);
}
}
///
/// Prepare related product search model
///
/// Related product search model
/// Product
/// Related product search model
protected virtual RelatedProductSearchModel PrepareRelatedProductSearchModel(RelatedProductSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare cross-sell product search model
///
/// Cross-sell product search model
/// Product
/// Cross-sell product search model
protected virtual CrossSellProductSearchModel PrepareCrossSellProductSearchModel(CrossSellProductSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare associated product search model
///
/// Associated product search model
/// Product
/// Associated product search model
protected virtual AssociatedProductSearchModel PrepareAssociatedProductSearchModel(AssociatedProductSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare product picture search model
///
/// Product picture search model
/// Product
/// Product picture search model
protected virtual ProductPictureSearchModel PrepareProductPictureSearchModel(ProductPictureSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare product video search model
///
/// Product video search model
/// Product
/// Product video search model
protected virtual ProductVideoSearchModel PrepareProductVideoSearchModel(ProductVideoSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare product order search model
///
/// Product order search model
/// Product
/// Product order search model
protected virtual ProductOrderSearchModel PrepareProductOrderSearchModel(ProductOrderSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare tier price search model
///
/// Tier price search model
/// Product
/// Tier price search model
protected virtual TierPriceSearchModel PrepareTierPriceSearchModel(TierPriceSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare stock quantity history search model
///
/// Stock quantity history search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the stock quantity history search model
///
protected virtual async Task PrepareStockQuantityHistorySearchModelAsync(StockQuantityHistorySearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare available warehouses
await _baseAdminModelFactory.PrepareWarehousesAsync(searchModel.AvailableWarehouses);
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare product attribute mapping search model
///
/// Product attribute mapping search model
/// Product
/// Product attribute mapping search model
protected virtual ProductAttributeMappingSearchModel PrepareProductAttributeMappingSearchModel(ProductAttributeMappingSearchModel searchModel,
Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare product attribute value search model
///
/// Product attribute value search model
/// Product attribute mapping
/// Product attribute value search model
protected virtual ProductAttributeValueSearchModel PrepareProductAttributeValueSearchModel(ProductAttributeValueSearchModel searchModel,
ProductAttributeMapping productAttributeMapping)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(productAttributeMapping);
searchModel.ProductAttributeMappingId = productAttributeMapping.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare product attribute combination search model
///
/// Product attribute combination search model
/// Product
/// Product attribute combination search model
protected virtual ProductAttributeCombinationSearchModel PrepareProductAttributeCombinationSearchModel(
ProductAttributeCombinationSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare product specification attribute search model
///
/// Product specification attribute search model
/// Product
/// Product specification attribute search model
protected virtual ProductSpecificationAttributeSearchModel PrepareProductSpecificationAttributeSearchModel(
ProductSpecificationAttributeSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
searchModel.ProductId = product.Id;
//prepare page parameters
searchModel.SetGridPageSize();
return searchModel;
}
#endregion
#region Methods
///
/// Prepare product search model
///
/// Product search model
///
/// A task that represents the asynchronous operation
/// The task result contains the product search model
///
public virtual async Task PrepareProductSearchModelAsync(ProductSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
//a vendor should have access only to his products
searchModel.IsLoggedInAsVendor = await _workContext.GetCurrentVendorAsync() != null;
searchModel.AllowVendorsToImportProducts = _vendorSettings.AllowVendorsToImportProducts;
var licenseCheckModel = new LicenseCheckModel();
try
{
var result = await _nopHttpClient.GetLicenseCheckDetailsAsync();
if (!string.IsNullOrEmpty(result))
{
licenseCheckModel = JsonConvert.DeserializeObject(result);
if (licenseCheckModel.DisplayWarning == false && licenseCheckModel.BlockPages == false)
await _settingService.SetSettingAsync($"{nameof(AdminAreaSettings)}.{nameof(AdminAreaSettings.CheckLicense)}", false);
}
}
catch { }
searchModel.LicenseCheckModel = licenseCheckModel;
//prepare available categories
await _baseAdminModelFactory.PrepareCategoriesAsync(searchModel.AvailableCategories);
//prepare available manufacturers
await _baseAdminModelFactory.PrepareManufacturersAsync(searchModel.AvailableManufacturers);
//prepare available stores
await _baseAdminModelFactory.PrepareStoresAsync(searchModel.AvailableStores);
//prepare available vendors
await _baseAdminModelFactory.PrepareVendorsAsync(searchModel.AvailableVendors);
//prepare available product types
await _baseAdminModelFactory.PrepareProductTypesAsync(searchModel.AvailableProductTypes);
//prepare available warehouses
await _baseAdminModelFactory.PrepareWarehousesAsync(searchModel.AvailableWarehouses);
searchModel.HideStoresList = _catalogSettings.IgnoreStoreLimitations || searchModel.AvailableStores.SelectionIsNotPossible();
//prepare "published" filter (0 - all; 1 - published only; 2 - unpublished only)
searchModel.AvailablePublishedOptions.Add(new SelectListItem
{
Value = "0",
Text = await _localizationService.GetResourceAsync("Admin.Catalog.Products.List.SearchPublished.All")
});
searchModel.AvailablePublishedOptions.Add(new SelectListItem
{
Value = "1",
Text = await _localizationService.GetResourceAsync("Admin.Catalog.Products.List.SearchPublished.PublishedOnly")
});
searchModel.AvailablePublishedOptions.Add(new SelectListItem
{
Value = "2",
Text = await _localizationService.GetResourceAsync("Admin.Catalog.Products.List.SearchPublished.UnpublishedOnly")
});
//prepare grid
searchModel.SetGridPageSize();
return searchModel;
}
///
/// Prepare paged product list model
///
/// Product search model
///
/// A task that represents the asynchronous operation
/// The task result contains the product list model
///
public virtual async Task PrepareProductListModelAsync(ProductSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
//get parameters to filter comments
var overridePublished = searchModel.SearchPublishedId == 0 ? null : (bool?)(searchModel.SearchPublishedId == 1);
var currentVendor = await _workContext.GetCurrentVendorAsync();
if (currentVendor != null)
searchModel.SearchVendorId = currentVendor.Id;
var categoryIds = new List { searchModel.SearchCategoryId };
if (searchModel.SearchIncludeSubCategories && searchModel.SearchCategoryId > 0)
{
var childCategoryIds = await _categoryService.GetChildCategoryIdsAsync(parentCategoryId: searchModel.SearchCategoryId, showHidden: true);
categoryIds.AddRange(childCategoryIds);
}
//get products
var products = await _productService.SearchProductsAsync(showHidden: true,
categoryIds: categoryIds,
manufacturerIds: new List { searchModel.SearchManufacturerId },
storeId: searchModel.SearchStoreId,
vendorId: searchModel.SearchVendorId,
warehouseId: searchModel.SearchWarehouseId,
productType: searchModel.SearchProductTypeId > 0 ? (ProductType?)searchModel.SearchProductTypeId : null,
keywords: searchModel.SearchProductName,
pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize,
overridePublished: overridePublished);
//prepare list model
var model = await new ProductListModel().PrepareToGridAsync(searchModel, products, () =>
{
return products.SelectAwait(async product =>
{
//fill in model values from the entity
var productModel = product.ToModel();
//little performance optimization: ensure that "FullDescription" is not returned
productModel.FullDescription = string.Empty;
//fill in additional values (not existing in the entity)
productModel.SeName = await _urlRecordService.GetSeNameAsync(product, 0, true, false);
var defaultProductPicture = (await _pictureService.GetPicturesByProductIdAsync(product.Id, 1)).FirstOrDefault();
(productModel.PictureThumbnailUrl, _) = await _pictureService.GetPictureUrlAsync(defaultProductPicture, 75);
productModel.ProductTypeName = await _localizationService.GetLocalizedEnumAsync(product.ProductType);
if (product.ProductType == ProductType.SimpleProduct && product.ManageInventoryMethod == ManageInventoryMethod.ManageStock)
productModel.StockQuantityStr = (await _productService.GetTotalStockQuantityAsync(product)).ToString();
return productModel;
});
});
return model;
}
///
/// Prepare product model
///
/// Product model
/// Product
/// Whether to exclude populating of some properties of model
///
/// A task that represents the asynchronous operation
/// The task result contains the product model
///
public virtual async Task PrepareProductModelAsync(ProductModel model, Product product, bool excludeProperties = false)
{
Func localizedModelConfiguration = null;
if (product != null)
{
//fill in model values from the entity
if (model == null)
{
model = product.ToModel();
model.SeName = await _urlRecordService.GetSeNameAsync(product, 0, true, false);
}
var parentGroupedProduct = await _productService.GetProductByIdAsync(product.ParentGroupedProductId);
if (parentGroupedProduct != null)
{
model.AssociatedToProductId = product.ParentGroupedProductId;
model.AssociatedToProductName = parentGroupedProduct.Name;
}
model.LastStockQuantity = product.StockQuantity;
model.SelectedProductTags = (await _productTagService.GetAllProductTagsByProductIdAsync(product.Id)).Select(tag => tag.Name).ToList();
model.AvailableProductTags = (await _productTagService.GetAllProductTagsAsync())
.Select(pt => new SelectListItem { Text = pt.Name, Value = pt.Name }).ToList();
model.ProductAttributesExist = (await _productAttributeService.GetAllProductAttributesAsync()).Any();
model.CanCreateCombinations = await (await _productAttributeService
.GetProductAttributeMappingsByProductIdAsync(product.Id)).AnyAwaitAsync(async pam => (await _productAttributeService.GetProductAttributeValuesAsync(pam.Id)).Any());
if (!excludeProperties)
{
model.SelectedCategoryIds = (await _categoryService.GetProductCategoriesByProductIdAsync(product.Id, true))
.Select(productCategory => productCategory.CategoryId).ToList();
model.SelectedManufacturerIds = (await _manufacturerService.GetProductManufacturersByProductIdAsync(product.Id, true))
.Select(productManufacturer => productManufacturer.ManufacturerId).ToList();
}
//prepare copy product model
await PrepareCopyProductModelAsync(model.CopyProductModel, product);
//prepare nested search model
PrepareRelatedProductSearchModel(model.RelatedProductSearchModel, product);
PrepareCrossSellProductSearchModel(model.CrossSellProductSearchModel, product);
PrepareAssociatedProductSearchModel(model.AssociatedProductSearchModel, product);
PrepareProductPictureSearchModel(model.ProductPictureSearchModel, product);
PrepareProductVideoSearchModel(model.ProductVideoSearchModel, product);
PrepareProductSpecificationAttributeSearchModel(model.ProductSpecificationAttributeSearchModel, product);
PrepareProductOrderSearchModel(model.ProductOrderSearchModel, product);
PrepareTierPriceSearchModel(model.TierPriceSearchModel, product);
await PrepareStockQuantityHistorySearchModelAsync(model.StockQuantityHistorySearchModel, product);
PrepareProductAttributeMappingSearchModel(model.ProductAttributeMappingSearchModel, product);
PrepareProductAttributeCombinationSearchModel(model.ProductAttributeCombinationSearchModel, product);
//define localized model configuration action
localizedModelConfiguration = async (locale, languageId) =>
{
locale.Name = await _localizationService.GetLocalizedAsync(product, entity => entity.Name, languageId, false, false);
locale.FullDescription = await _localizationService.GetLocalizedAsync(product, entity => entity.FullDescription, languageId, false, false);
locale.ShortDescription = await _localizationService.GetLocalizedAsync(product, entity => entity.ShortDescription, languageId, false, false);
locale.MetaKeywords = await _localizationService.GetLocalizedAsync(product, entity => entity.MetaKeywords, languageId, false, false);
locale.MetaDescription = await _localizationService.GetLocalizedAsync(product, entity => entity.MetaDescription, languageId, false, false);
locale.MetaTitle = await _localizationService.GetLocalizedAsync(product, entity => entity.MetaTitle, languageId, false, false);
locale.SeName = await _urlRecordService.GetSeNameAsync(product, languageId, false, false);
};
}
//set default values for the new model
if (product == null)
{
model.MaximumCustomerEnteredPrice = 1000;
model.MaxNumberOfDownloads = 10;
model.RecurringCycleLength = 100;
model.RecurringTotalCycles = 10;
model.RentalPriceLength = 1;
model.StockQuantity = 10000;
model.NotifyAdminForQuantityBelow = 1;
model.OrderMinimumQuantity = 1;
model.OrderMaximumQuantity = 10000;
model.TaxCategoryId = _taxSettings.DefaultTaxCategoryId;
model.UnlimitedDownloads = true;
model.IsShipEnabled = true;
model.AllowCustomerReviews = true;
model.Published = true;
model.VisibleIndividually = true;
}
model.PrimaryStoreCurrencyCode = (await _currencyService.GetCurrencyByIdAsync(_currencySettings.PrimaryStoreCurrencyId)).CurrencyCode;
model.BaseWeightIn = (await _measureService.GetMeasureWeightByIdAsync(_measureSettings.BaseWeightId)).Name;
model.BaseDimensionIn = (await _measureService.GetMeasureDimensionByIdAsync(_measureSettings.BaseDimensionId)).Name;
model.IsLoggedInAsVendor = await _workContext.GetCurrentVendorAsync() != null;
model.HasAvailableSpecificationAttributes =
(await _specificationAttributeService.GetSpecificationAttributesWithOptionsAsync()).Any();
//prepare localized models
if (!excludeProperties)
model.Locales = await _localizedModelFactory.PrepareLocalizedModelsAsync(localizedModelConfiguration);
//prepare editor settings
model.ProductEditorSettingsModel = await _settingModelFactory.PrepareProductEditorSettingsModelAsync();
//prepare available product templates
await _baseAdminModelFactory.PrepareProductTemplatesAsync(model.AvailableProductTemplates, false);
//prepare available product types
var productTemplates = await _productTemplateService.GetAllProductTemplatesAsync();
foreach (var productType in Enum.GetValues(typeof(ProductType)).OfType())
{
model.ProductsTypesSupportedByProductTemplates.Add((int)productType, new List());
foreach (var template in productTemplates)
{
var list = (IList)TypeDescriptor.GetConverter(typeof(List)).ConvertFrom(template.IgnoredProductTypes) ?? new List();
if (string.IsNullOrEmpty(template.IgnoredProductTypes) || !list.Contains((int)productType))
{
model.ProductsTypesSupportedByProductTemplates[(int)productType].Add(new SelectListItem
{
Text = template.Name,
Value = template.Id.ToString()
});
}
}
}
//prepare available delivery dates
await _baseAdminModelFactory.PrepareDeliveryDatesAsync(model.AvailableDeliveryDates,
defaultItemText: await _localizationService.GetResourceAsync("Admin.Catalog.Products.Fields.DeliveryDate.None"));
//prepare available product availability ranges
await _baseAdminModelFactory.PrepareProductAvailabilityRangesAsync(model.AvailableProductAvailabilityRanges,
defaultItemText: await _localizationService.GetResourceAsync("Admin.Catalog.Products.Fields.ProductAvailabilityRange.None"));
//prepare available vendors
await _baseAdminModelFactory.PrepareVendorsAsync(model.AvailableVendors,
defaultItemText: await _localizationService.GetResourceAsync("Admin.Catalog.Products.Fields.Vendor.None"));
//prepare available tax categories
await _baseAdminModelFactory.PrepareTaxCategoriesAsync(model.AvailableTaxCategories);
//prepare available warehouses
await _baseAdminModelFactory.PrepareWarehousesAsync(model.AvailableWarehouses,
defaultItemText: await _localizationService.GetResourceAsync("Admin.Catalog.Products.Fields.Warehouse.None"));
await PrepareProductWarehouseInventoryModelsAsync(model.ProductWarehouseInventoryModels, product);
//prepare available base price units
var availableMeasureWeights = (await _measureService.GetAllMeasureWeightsAsync())
.Select(weight => new SelectListItem { Text = weight.Name, Value = weight.Id.ToString() }).ToList();
model.AvailableBasepriceUnits = availableMeasureWeights;
model.AvailableBasepriceBaseUnits = availableMeasureWeights;
//prepare model categories
await _baseAdminModelFactory.PrepareCategoriesAsync(model.AvailableCategories, false);
foreach (var categoryItem in model.AvailableCategories)
{
categoryItem.Selected = int.TryParse(categoryItem.Value, out var categoryId)
&& model.SelectedCategoryIds.Contains(categoryId);
}
//prepare model manufacturers
await _baseAdminModelFactory.PrepareManufacturersAsync(model.AvailableManufacturers, false);
foreach (var manufacturerItem in model.AvailableManufacturers)
{
manufacturerItem.Selected = int.TryParse(manufacturerItem.Value, out var manufacturerId)
&& model.SelectedManufacturerIds.Contains(manufacturerId);
}
//prepare model discounts
var availableDiscounts = await _discountService.GetAllDiscountsAsync(DiscountType.AssignedToSkus, showHidden: true, isActive: null);
await _discountSupportedModelFactory.PrepareModelDiscountsAsync(model, product, availableDiscounts, excludeProperties);
//prepare model customer roles
await _aclSupportedModelFactory.PrepareModelCustomerRolesAsync(model, product, excludeProperties);
//prepare model stores
await _storeMappingSupportedModelFactory.PrepareModelStoresAsync(model, product, excludeProperties);
return model;
}
///
/// Prepare required product search model to add to the product
///
/// Required product search model to add to the product
///
/// A task that represents the asynchronous operation
/// The task result contains the required product search model to add to the product
///
public virtual async Task PrepareAddRequiredProductSearchModelAsync(AddRequiredProductSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
searchModel.IsLoggedInAsVendor = await _workContext.GetCurrentVendorAsync() != null;
//prepare available categories
await _baseAdminModelFactory.PrepareCategoriesAsync(searchModel.AvailableCategories);
//prepare available manufacturers
await _baseAdminModelFactory.PrepareManufacturersAsync(searchModel.AvailableManufacturers);
//prepare available stores
await _baseAdminModelFactory.PrepareStoresAsync(searchModel.AvailableStores);
//prepare available vendors
await _baseAdminModelFactory.PrepareVendorsAsync(searchModel.AvailableVendors);
//prepare available product types
await _baseAdminModelFactory.PrepareProductTypesAsync(searchModel.AvailableProductTypes);
//prepare page parameters
searchModel.SetPopupGridPageSize();
return searchModel;
}
///
/// Prepare required product list model to add to the product
///
/// Required product search model to add to the product
///
/// A task that represents the asynchronous operation
/// The task result contains the required product list model to add to the product
///
public virtual async Task PrepareAddRequiredProductListModelAsync(AddRequiredProductSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
//a vendor should have access only to his products
var currentVendor = await _workContext.GetCurrentVendorAsync();
if (currentVendor != null)
searchModel.SearchVendorId = currentVendor.Id;
//get products
var products = await _productService.SearchProductsAsync(showHidden: true,
categoryIds: new List { searchModel.SearchCategoryId },
manufacturerIds: new List { searchModel.SearchManufacturerId },
storeId: searchModel.SearchStoreId,
vendorId: searchModel.SearchVendorId,
productType: searchModel.SearchProductTypeId > 0 ? (ProductType?)searchModel.SearchProductTypeId : null,
keywords: searchModel.SearchProductName,
pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize);
//prepare grid model
var model = await new AddRequiredProductListModel().PrepareToGridAsync(searchModel, products, () =>
{
return products.SelectAwait(async product =>
{
var productModel = product.ToModel();
productModel.SeName = await _urlRecordService.GetSeNameAsync(product, 0, true, false);
return productModel;
});
});
return model;
}
///
/// Prepare paged related product list model
///
/// Related product search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the related product list model
///
public virtual async Task PrepareRelatedProductListModelAsync(RelatedProductSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get related products
var relatedProducts = (await _productService
.GetRelatedProductsByProductId1Async(productId1: product.Id, showHidden: true)).ToPagedList(searchModel);
//prepare grid model
var model = await new RelatedProductListModel().PrepareToGridAsync(searchModel, relatedProducts, () =>
{
return relatedProducts.SelectAwait(async relatedProduct =>
{
//fill in model values from the entity
var relatedProductModel = relatedProduct.ToModel();
//fill in additional values (not existing in the entity)
relatedProductModel.Product2Name = (await _productService.GetProductByIdAsync(relatedProduct.ProductId2))?.Name;
return relatedProductModel;
});
});
return model;
}
///
/// Prepare related product search model to add to the product
///
/// Related product search model to add to the product
///
/// A task that represents the asynchronous operation
/// The task result contains the related product search model to add to the product
///
public virtual async Task PrepareAddRelatedProductSearchModelAsync(AddRelatedProductSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
searchModel.IsLoggedInAsVendor = await _workContext.GetCurrentVendorAsync() != null;
//prepare available categories
await _baseAdminModelFactory.PrepareCategoriesAsync(searchModel.AvailableCategories);
//prepare available manufacturers
await _baseAdminModelFactory.PrepareManufacturersAsync(searchModel.AvailableManufacturers);
//prepare available stores
await _baseAdminModelFactory.PrepareStoresAsync(searchModel.AvailableStores);
//prepare available vendors
await _baseAdminModelFactory.PrepareVendorsAsync(searchModel.AvailableVendors);
//prepare available product types
await _baseAdminModelFactory.PrepareProductTypesAsync(searchModel.AvailableProductTypes);
//prepare page parameters
searchModel.SetPopupGridPageSize();
return searchModel;
}
///
/// Prepare paged related product list model to add to the product
///
/// Related product search model to add to the product
///
/// A task that represents the asynchronous operation
/// The task result contains the related product list model to add to the product
///
public virtual async Task PrepareAddRelatedProductListModelAsync(AddRelatedProductSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
//a vendor should have access only to his products
var currentVendor = await _workContext.GetCurrentVendorAsync();
if (currentVendor != null)
searchModel.SearchVendorId = currentVendor.Id;
//get products
var products = await _productService.SearchProductsAsync(showHidden: true,
categoryIds: new List { searchModel.SearchCategoryId },
manufacturerIds: new List { searchModel.SearchManufacturerId },
storeId: searchModel.SearchStoreId,
vendorId: searchModel.SearchVendorId,
productType: searchModel.SearchProductTypeId > 0 ? (ProductType?)searchModel.SearchProductTypeId : null,
keywords: searchModel.SearchProductName,
pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize);
//prepare grid model
var model = await new AddRelatedProductListModel().PrepareToGridAsync(searchModel, products, () =>
{
return products.SelectAwait(async product =>
{
var productModel = product.ToModel();
productModel.SeName = await _urlRecordService.GetSeNameAsync(product, 0, true, false);
return productModel;
});
});
return model;
}
///
/// Prepare paged cross-sell product list model
///
/// Cross-sell product search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the cross-sell product list model
///
public virtual async Task PrepareCrossSellProductListModelAsync(CrossSellProductSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get cross-sell products
var crossSellProducts = (await _productService
.GetCrossSellProductsByProductId1Async(productId1: product.Id, showHidden: true)).ToPagedList(searchModel);
//prepare grid model
var model = await new CrossSellProductListModel().PrepareToGridAsync(searchModel, crossSellProducts, () =>
{
return crossSellProducts.SelectAwait(async crossSellProduct =>
{
//fill in model values from the entity
var crossSellProductModel = new CrossSellProductModel
{
Id = crossSellProduct.Id,
ProductId2 = crossSellProduct.ProductId2
};
//fill in additional values (not existing in the entity)
crossSellProductModel.Product2Name = (await _productService.GetProductByIdAsync(crossSellProduct.ProductId2))?.Name;
return crossSellProductModel;
});
});
return model;
}
///
/// Prepare cross-sell product search model to add to the product
///
/// Cross-sell product search model to add to the product
///
/// A task that represents the asynchronous operation
/// The task result contains the cross-sell product search model to add to the product
///
public virtual async Task PrepareAddCrossSellProductSearchModelAsync(AddCrossSellProductSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
searchModel.IsLoggedInAsVendor = await _workContext.GetCurrentVendorAsync() != null;
//prepare available categories
await _baseAdminModelFactory.PrepareCategoriesAsync(searchModel.AvailableCategories);
//prepare available manufacturers
await _baseAdminModelFactory.PrepareManufacturersAsync(searchModel.AvailableManufacturers);
//prepare available stores
await _baseAdminModelFactory.PrepareStoresAsync(searchModel.AvailableStores);
//prepare available vendors
await _baseAdminModelFactory.PrepareVendorsAsync(searchModel.AvailableVendors);
//prepare available product types
await _baseAdminModelFactory.PrepareProductTypesAsync(searchModel.AvailableProductTypes);
//prepare page parameters
searchModel.SetPopupGridPageSize();
return searchModel;
}
///
/// Prepare paged crossSell product list model to add to the product
///
/// CrossSell product search model to add to the product
///
/// A task that represents the asynchronous operation
/// The task result contains the crossSell product list model to add to the product
///
public virtual async Task PrepareAddCrossSellProductListModelAsync(AddCrossSellProductSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
//a vendor should have access only to his products
var currentVendor = await _workContext.GetCurrentVendorAsync();
if (currentVendor != null)
searchModel.SearchVendorId = currentVendor.Id;
//get products
var products = await _productService.SearchProductsAsync(showHidden: true,
categoryIds: new List { searchModel.SearchCategoryId },
manufacturerIds: new List { searchModel.SearchManufacturerId },
storeId: searchModel.SearchStoreId,
vendorId: searchModel.SearchVendorId,
productType: searchModel.SearchProductTypeId > 0 ? (ProductType?)searchModel.SearchProductTypeId : null,
keywords: searchModel.SearchProductName,
pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize);
//prepare grid model
var model = await new AddCrossSellProductListModel().PrepareToGridAsync(searchModel, products, () =>
{
return products.SelectAwait(async product =>
{
var productModel = product.ToModel();
productModel.SeName = await _urlRecordService.GetSeNameAsync(product, 0, true, false);
return productModel;
});
});
return model;
}
///
/// Prepare paged associated product list model
///
/// Associated product search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the associated product list model
///
public virtual async Task PrepareAssociatedProductListModelAsync(AssociatedProductSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
var vendor = await _workContext.GetCurrentVendorAsync();
//get associated products
var associatedProducts = (await _productService.GetAssociatedProductsAsync(showHidden: true,
parentGroupedProductId: product.Id,
vendorId: vendor?.Id ?? 0)).ToPagedList(searchModel);
//prepare grid model
var model = new AssociatedProductListModel().PrepareToGrid(searchModel, associatedProducts, () =>
{
return associatedProducts.Select(associatedProduct =>
{
var associatedProductModel = associatedProduct.ToModel();
associatedProductModel.ProductName = associatedProduct.Name;
return associatedProductModel;
});
});
return model;
}
///
/// Prepare associated product search model to add to the product
///
/// Associated product search model to add to the product
///
/// A task that represents the asynchronous operation
/// The task result contains the associated product search model to add to the product
///
public virtual async Task PrepareAddAssociatedProductSearchModelAsync(AddAssociatedProductSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
searchModel.IsLoggedInAsVendor = await _workContext.GetCurrentVendorAsync() != null;
//prepare available categories
await _baseAdminModelFactory.PrepareCategoriesAsync(searchModel.AvailableCategories);
//prepare available manufacturers
await _baseAdminModelFactory.PrepareManufacturersAsync(searchModel.AvailableManufacturers);
//prepare available stores
await _baseAdminModelFactory.PrepareStoresAsync(searchModel.AvailableStores);
//prepare available vendors
await _baseAdminModelFactory.PrepareVendorsAsync(searchModel.AvailableVendors);
//prepare available product types
await _baseAdminModelFactory.PrepareProductTypesAsync(searchModel.AvailableProductTypes);
//prepare page parameters
searchModel.SetPopupGridPageSize();
return searchModel;
}
///
/// Prepare paged associated product list model to add to the product
///
/// Associated product search model to add to the product
///
/// A task that represents the asynchronous operation
/// The task result contains the associated product list model to add to the product
///
public virtual async Task PrepareAddAssociatedProductListModelAsync(AddAssociatedProductSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
//a vendor should have access only to his products
var currentVendor = await _workContext.GetCurrentVendorAsync();
if (currentVendor != null)
searchModel.SearchVendorId = currentVendor.Id;
//get products
var products = await _productService.SearchProductsAsync(showHidden: true,
categoryIds: new List { searchModel.SearchCategoryId },
manufacturerIds: new List { searchModel.SearchManufacturerId },
storeId: searchModel.SearchStoreId,
vendorId: searchModel.SearchVendorId,
productType: searchModel.SearchProductTypeId > 0 ? (ProductType?)searchModel.SearchProductTypeId : null,
keywords: searchModel.SearchProductName,
pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize);
//prepare grid model
var model = await new AddAssociatedProductListModel().PrepareToGridAsync(searchModel, products, () =>
{
return products.SelectAwait(async product =>
{
//fill in model values from the entity
var productModel = product.ToModel();
//fill in additional values (not existing in the entity)
productModel.SeName = await _urlRecordService.GetSeNameAsync(product, 0, true, false);
var parentGroupedProduct = await _productService.GetProductByIdAsync(product.ParentGroupedProductId);
if (parentGroupedProduct == null)
return productModel;
productModel.AssociatedToProductId = product.ParentGroupedProductId;
productModel.AssociatedToProductName = parentGroupedProduct.Name;
return productModel;
});
});
return model;
}
///
/// Prepare paged product picture list model
///
/// Product picture search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the product picture list model
///
public virtual async Task PrepareProductPictureListModelAsync(ProductPictureSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get product pictures
var productPictures = (await _productService.GetProductPicturesByProductIdAsync(product.Id)).ToPagedList(searchModel);
//prepare grid model
var model = await new ProductPictureListModel().PrepareToGridAsync(searchModel, productPictures, () =>
{
return productPictures.SelectAwait(async productPicture =>
{
//fill in model values from the entity
var productPictureModel = productPicture.ToModel();
//fill in additional values (not existing in the entity)
var picture = (await _pictureService.GetPictureByIdAsync(productPicture.PictureId))
?? throw new Exception("Picture cannot be loaded");
productPictureModel.PictureUrl = (await _pictureService.GetPictureUrlAsync(picture)).Url;
productPictureModel.OverrideAltAttribute = picture.AltAttribute;
productPictureModel.OverrideTitleAttribute = picture.TitleAttribute;
return productPictureModel;
});
});
return model;
}
///
/// Prepare paged product video list model
///
/// Product video search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the product video list model
///
public virtual async Task PrepareProductVideoListModelAsync(ProductVideoSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get product videos
var productVideos = (await _productService.GetProductVideosByProductIdAsync(product.Id)).ToPagedList(searchModel);
//prepare grid model
var model = await new ProductVideoListModel().PrepareToGridAsync(searchModel, productVideos, () =>
{
return productVideos.SelectAwait(async productVideo =>
{
//fill in model values from the entity
var productVideoModel = productVideo.ToModel();
//fill in additional values (not existing in the entity)
var video = (await _videoService.GetVideoByIdAsync(productVideo.VideoId))
?? throw new Exception("Video cannot be loaded");
productVideoModel.VideoUrl = video.VideoUrl;
return productVideoModel;
});
});
return model;
}
///
/// Prepare paged product specification attribute list model
///
/// Product specification attribute search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the product specification attribute list model
///
public virtual async Task PrepareProductSpecificationAttributeListModelAsync(
ProductSpecificationAttributeSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get product specification attributes
var productSpecificationAttributes = (await _specificationAttributeService
.GetProductSpecificationAttributesAsync(product.Id)).ToPagedList(searchModel);
//prepare grid model
var model = await new ProductSpecificationAttributeListModel().PrepareToGridAsync(searchModel, productSpecificationAttributes, () =>
{
return productSpecificationAttributes.SelectAwait(async attribute =>
{
//fill in model values from the entity
var productSpecificationAttributeModel = attribute.ToModel();
var specAttributeOption = await _specificationAttributeService
.GetSpecificationAttributeOptionByIdAsync(attribute.SpecificationAttributeOptionId);
var specAttribute = await _specificationAttributeService
.GetSpecificationAttributeByIdAsync(specAttributeOption.SpecificationAttributeId);
//fill in additional values (not existing in the entity)
productSpecificationAttributeModel.AttributeTypeName = await _localizationService.GetLocalizedEnumAsync(attribute.AttributeType);
productSpecificationAttributeModel.AttributeId = specAttribute.Id;
productSpecificationAttributeModel.AttributeName = await GetSpecificationAttributeNameAsync(specAttribute);
var currentLanguage = await _workContext.GetWorkingLanguageAsync();
switch (attribute.AttributeType)
{
case SpecificationAttributeType.Option:
productSpecificationAttributeModel.ValueRaw = WebUtility.HtmlEncode(specAttributeOption.Name);
productSpecificationAttributeModel.SpecificationAttributeOptionId = specAttributeOption.Id;
break;
case SpecificationAttributeType.CustomText:
productSpecificationAttributeModel.ValueRaw = WebUtility.HtmlEncode(await _localizationService.GetLocalizedAsync(attribute, x => x.CustomValue, currentLanguage?.Id));
break;
case SpecificationAttributeType.CustomHtmlText:
productSpecificationAttributeModel.ValueRaw = await _localizationService
.GetLocalizedAsync(attribute, x => x.CustomValue, currentLanguage?.Id);
break;
case SpecificationAttributeType.Hyperlink:
productSpecificationAttributeModel.ValueRaw = attribute.CustomValue;
break;
}
return productSpecificationAttributeModel;
});
});
return model;
}
///
/// Prepare paged product specification attribute model
///
/// Product id
/// Specification attribute id
///
/// A task that represents the asynchronous operation
/// The task result contains the product specification attribute model
///
public virtual async Task PrepareAddSpecificationAttributeModelAsync(int productId, int? specificationId)
{
if (!specificationId.HasValue)
{
return new AddSpecificationAttributeModel
{
AvailableAttributes = await (await _specificationAttributeService.GetSpecificationAttributesWithOptionsAsync())
.SelectAwait(async attributeWithOption =>
{
var attributeName = await GetSpecificationAttributeNameAsync(attributeWithOption);
return new SelectListItem(attributeName, attributeWithOption.Id.ToString());
}).ToListAsync(),
ProductId = productId,
Locales = await _localizedModelFactory.PrepareLocalizedModelsAsync()
};
}
var attribute = await _specificationAttributeService.GetProductSpecificationAttributeByIdAsync(specificationId.Value)
?? throw new ArgumentException("No specification attribute found with the specified id");
//a vendor should have access only to his products
var currentVendor = await _workContext.GetCurrentVendorAsync();
if (currentVendor != null && (await _productService.GetProductByIdAsync(attribute.ProductId)).VendorId != currentVendor.Id)
throw new UnauthorizedAccessException("This is not your product");
var specAttributeOption = await _specificationAttributeService.GetSpecificationAttributeOptionByIdAsync(attribute.SpecificationAttributeOptionId);
var specAttribute = await _specificationAttributeService.GetSpecificationAttributeByIdAsync(specAttributeOption.SpecificationAttributeId);
var model = attribute.ToModel();
model.SpecificationId = attribute.Id;
model.AttributeId = specAttribute.Id;
model.AttributeTypeName = await _localizationService.GetLocalizedEnumAsync(attribute.AttributeType);
model.AttributeName = specAttribute.Name;
model.AvailableAttributes = await (await _specificationAttributeService.GetSpecificationAttributesWithOptionsAsync())
.SelectAwait(async attributeWithOption =>
{
var attributeName = await GetSpecificationAttributeNameAsync(attributeWithOption);
return new SelectListItem(attributeName, attributeWithOption.Id.ToString());
})
.ToListAsync();
model.AvailableOptions = (await _specificationAttributeService
.GetSpecificationAttributeOptionsBySpecificationAttributeAsync(model.AttributeId))
.Select(option => new SelectListItem { Text = option.Name, Value = option.Id.ToString() })
.ToList();
switch (attribute.AttributeType)
{
case SpecificationAttributeType.Option:
model.ValueRaw = WebUtility.HtmlEncode(specAttributeOption.Name);
model.SpecificationAttributeOptionId = specAttributeOption.Id;
break;
case SpecificationAttributeType.CustomText:
model.Value = WebUtility.HtmlDecode(attribute.CustomValue);
break;
case SpecificationAttributeType.CustomHtmlText:
model.ValueRaw = attribute.CustomValue;
break;
case SpecificationAttributeType.Hyperlink:
model.Value = attribute.CustomValue;
break;
default:
throw new ArgumentOutOfRangeException(nameof(attribute.AttributeType));
}
model.Locales = await _localizedModelFactory.PrepareLocalizedModelsAsync(
async (AddSpecificationAttributeLocalizedModel locale, int languageId) =>
{
switch (attribute.AttributeType)
{
case SpecificationAttributeType.CustomHtmlText:
locale.ValueRaw = await _localizationService.GetLocalizedAsync(attribute, entity => entity.CustomValue, languageId, false, false);
break;
case SpecificationAttributeType.CustomText:
locale.Value = await _localizationService.GetLocalizedAsync(attribute, entity => entity.CustomValue, languageId, false, false);
break;
case SpecificationAttributeType.Option:
break;
case SpecificationAttributeType.Hyperlink:
break;
default:
throw new ArgumentOutOfRangeException();
}
});
return model;
}
///
/// Prepare product tag search model
///
/// Product tag search model
///
/// A task that represents the asynchronous operation
/// The task result contains the product tag search model
///
public virtual Task PrepareProductTagSearchModelAsync(ProductTagSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
//prepare page parameters
searchModel.SetGridPageSize();
return Task.FromResult(searchModel);
}
///
/// Prepare paged product tag list model
///
/// Product tag search model
///
/// A task that represents the asynchronous operation
/// The task result contains the product tag list model
///
public virtual async Task PrepareProductTagListModelAsync(ProductTagSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
//get product tags
var productTags = (await (await _productTagService.GetAllProductTagsAsync(tagName: searchModel.SearchTagName))
.OrderByDescendingAwait(async tag => await _productTagService.GetProductCountByProductTagIdAsync(tag.Id, storeId: 0, showHidden: true)).ToListAsync())
.ToPagedList(searchModel);
//prepare list model
var model = await new ProductTagListModel().PrepareToGridAsync(searchModel, productTags, () =>
{
return productTags.SelectAwait(async tag =>
{
//fill in model values from the entity
var productTagModel = tag.ToModel();
//fill in additional values (not existing in the entity)
productTagModel.ProductCount = await _productTagService.GetProductCountByProductTagIdAsync(tag.Id, storeId: 0, showHidden: true);
return productTagModel;
});
});
return model;
}
///
/// Prepare product tag model
///
/// Product tag model
/// Product tag
/// Whether to exclude populating of some properties of model
///
/// A task that represents the asynchronous operation
/// The task result contains the product tag model
///
public virtual async Task PrepareProductTagModelAsync(ProductTagModel model, ProductTag productTag, bool excludeProperties = false)
{
Func localizedModelConfiguration = null;
if (productTag != null)
{
//fill in model values from the entity
if (model == null)
{
model = productTag.ToModel();
}
model.ProductCount = await _productTagService.GetProductCountByProductTagIdAsync(productTag.Id, storeId: 0, showHidden: true);
//define localized model configuration action
localizedModelConfiguration = async (locale, languageId) =>
{
locale.Name = await _localizationService.GetLocalizedAsync(productTag, entity => entity.Name, languageId, false, false);
};
}
//prepare localized models
if (!excludeProperties)
model.Locales = await _localizedModelFactory.PrepareLocalizedModelsAsync(localizedModelConfiguration);
return model;
}
///
/// Prepare paged product order list model
///
/// Product order search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the product order list model
///
public virtual async Task PrepareProductOrderListModelAsync(ProductOrderSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get orders
var orders = await _orderService.SearchOrdersAsync(productId: searchModel.ProductId,
pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize);
//prepare grid model
var model = await new ProductOrderListModel().PrepareToGridAsync(searchModel, orders, () =>
{
return orders.SelectAwait(async order =>
{
var billingAddress = await _addressService.GetAddressByIdAsync(order.BillingAddressId);
//fill in model values from the entity
var orderModel = new OrderModel
{
Id = order.Id,
CustomerEmail = billingAddress.Email,
CustomOrderNumber = order.CustomOrderNumber
};
//convert dates to the user time
orderModel.CreatedOn = await _dateTimeHelper.ConvertToUserTimeAsync(order.CreatedOnUtc, DateTimeKind.Utc);
//fill in additional values (not existing in the entity)
orderModel.StoreName = (await _storeService.GetStoreByIdAsync(order.StoreId))?.Name ?? "Deleted";
orderModel.OrderStatus = await _localizationService.GetLocalizedEnumAsync(order.OrderStatus);
orderModel.PaymentStatus = await _localizationService.GetLocalizedEnumAsync(order.PaymentStatus);
orderModel.ShippingStatus = await _localizationService.GetLocalizedEnumAsync(order.ShippingStatus);
return orderModel;
});
});
return model;
}
///
/// Prepare paged tier price list model
///
/// Tier price search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the ier price list model
///
public virtual async Task PrepareTierPriceListModelAsync(TierPriceSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get tier prices
var tierPrices = (await _productService.GetTierPricesByProductAsync(product.Id))
.OrderBy(price => price.StoreId).ThenBy(price => price.Quantity).ThenBy(price => price.CustomerRoleId)
.ToList().ToPagedList(searchModel);
//prepare grid model
var model = await new TierPriceListModel().PrepareToGridAsync(searchModel, tierPrices, () =>
{
return tierPrices.SelectAwait(async price =>
{
//fill in model values from the entity
var tierPriceModel = price.ToModel();
//fill in additional values (not existing in the entity)
tierPriceModel.Store = price.StoreId > 0
? ((await _storeService.GetStoreByIdAsync(price.StoreId))?.Name ?? "Deleted")
: await _localizationService.GetResourceAsync("Admin.Catalog.Products.TierPrices.Fields.Store.All");
tierPriceModel.CustomerRoleId = price.CustomerRoleId ?? 0;
tierPriceModel.CustomerRole = price.CustomerRoleId.HasValue
? (await _customerService.GetCustomerRoleByIdAsync(price.CustomerRoleId.Value))?.Name
: await _localizationService.GetResourceAsync("Admin.Catalog.Products.TierPrices.Fields.CustomerRole.All");
return tierPriceModel;
});
});
return model;
}
///
/// Prepare tier price model
///
/// Tier price model
/// Product
/// Tier price
/// Whether to exclude populating of some properties of model
///
/// A task that represents the asynchronous operation
/// The task result contains the ier price model
///
public virtual async Task PrepareTierPriceModelAsync(TierPriceModel model,
Product product, TierPrice tierPrice, bool excludeProperties = false)
{
ArgumentNullException.ThrowIfNull(product);
if (tierPrice != null)
{
//fill in model values from the entity
if (model == null)
model = tierPrice.ToModel();
}
//prepare available stores
await _baseAdminModelFactory.PrepareStoresAsync(model.AvailableStores);
//prepare available customer roles
await _baseAdminModelFactory.PrepareCustomerRolesAsync(model.AvailableCustomerRoles);
return model;
}
///
/// Prepare paged stock quantity history list model
///
/// Stock quantity history search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the stock quantity history list model
///
public virtual async Task PrepareStockQuantityHistoryListModelAsync(StockQuantityHistorySearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get stock quantity history
var stockQuantityHistory = await _productService.GetStockQuantityHistoryAsync(product: product,
warehouseId: searchModel.WarehouseId,
pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize);
var currentCustomer = await _workContext.GetCurrentCustomerAsync();
var currentStore = await _storeContext.GetCurrentStoreAsync();
//prepare grid model
var model = await new StockQuantityHistoryListModel().PrepareToGridAsync(searchModel, stockQuantityHistory, () =>
{
return stockQuantityHistory.SelectAwait(async historyEntry =>
{
//fill in model values from the entity
var stockQuantityHistoryModel = historyEntry.ToModel();
//convert dates to the user time
stockQuantityHistoryModel.CreatedOn =
await _dateTimeHelper.ConvertToUserTimeAsync(historyEntry.CreatedOnUtc, DateTimeKind.Utc);
//fill in additional values (not existing in the entity)
var combination = await _productAttributeService.GetProductAttributeCombinationByIdAsync(historyEntry.CombinationId ?? 0);
if (combination != null)
{
stockQuantityHistoryModel.AttributeCombination = await _productAttributeFormatter
.FormatAttributesAsync(product, combination.AttributesXml, currentCustomer, currentStore, renderGiftCardAttributes: false);
}
stockQuantityHistoryModel.WarehouseName = historyEntry.WarehouseId.HasValue
? (await _shippingService.GetWarehouseByIdAsync(historyEntry.WarehouseId.Value))?.Name ?? "Deleted"
: await _localizationService.GetResourceAsync("Admin.Catalog.Products.Fields.Warehouse.None");
return stockQuantityHistoryModel;
});
});
return model;
}
///
/// Prepare paged product attribute mapping list model
///
/// Product attribute mapping search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the product attribute mapping list model
///
public virtual async Task PrepareProductAttributeMappingListModelAsync(ProductAttributeMappingSearchModel searchModel,
Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get product attribute mappings
var productAttributeMappings = (await _productAttributeService
.GetProductAttributeMappingsByProductIdAsync(product.Id)).ToPagedList(searchModel);
//prepare grid model
var model = await new ProductAttributeMappingListModel().PrepareToGridAsync(searchModel, productAttributeMappings, () =>
{
return productAttributeMappings.SelectAwait(async attributeMapping =>
{
//fill in model values from the entity
var productAttributeMappingModel = attributeMapping.ToModel();
//fill in additional values (not existing in the entity)
productAttributeMappingModel.ConditionString = string.Empty;
productAttributeMappingModel.ValidationRulesString = await PrepareProductAttributeMappingValidationRulesStringAsync(attributeMapping);
productAttributeMappingModel.ProductAttribute = (await _productAttributeService.GetProductAttributeByIdAsync(attributeMapping.ProductAttributeId))?.Name;
productAttributeMappingModel.AttributeControlType = await _localizationService.GetLocalizedEnumAsync(attributeMapping.AttributeControlType);
var conditionAttribute = (await _productAttributeParser
.ParseProductAttributeMappingsAsync(attributeMapping.ConditionAttributeXml))
.FirstOrDefault();
if (conditionAttribute == null)
return productAttributeMappingModel;
var conditionValue = (await _productAttributeParser
.ParseProductAttributeValuesAsync(attributeMapping.ConditionAttributeXml))
.FirstOrDefault();
if (conditionValue != null)
{
productAttributeMappingModel.ConditionString =
$"{WebUtility.HtmlEncode((await _productAttributeService.GetProductAttributeByIdAsync(conditionAttribute.ProductAttributeId)).Name)}: {WebUtility.HtmlEncode(conditionValue.Name)}";
}
return productAttributeMappingModel;
});
});
return model;
}
///
/// Prepare product attribute mapping model
///
/// Product attribute mapping model
/// Product
/// Product attribute mapping
/// Whether to exclude populating of some properties of model
///
/// A task that represents the asynchronous operation
/// The task result contains the product attribute mapping model
///
public virtual async Task PrepareProductAttributeMappingModelAsync(ProductAttributeMappingModel model,
Product product, ProductAttributeMapping productAttributeMapping, bool excludeProperties = false)
{
Func localizedModelConfiguration = null;
ArgumentNullException.ThrowIfNull(product);
if (productAttributeMapping != null)
{
//fill in model values from the entity
model ??= new ProductAttributeMappingModel
{
Id = productAttributeMapping.Id
};
model.ProductAttribute = (await _productAttributeService.GetProductAttributeByIdAsync(productAttributeMapping.ProductAttributeId)).Name;
model.AttributeControlType = await _localizationService.GetLocalizedEnumAsync(productAttributeMapping.AttributeControlType);
if (!excludeProperties)
{
model.ProductAttributeId = productAttributeMapping.ProductAttributeId;
model.TextPrompt = productAttributeMapping.TextPrompt;
model.IsRequired = productAttributeMapping.IsRequired;
model.AttributeControlTypeId = productAttributeMapping.AttributeControlTypeId;
model.DisplayOrder = productAttributeMapping.DisplayOrder;
model.ValidationMinLength = productAttributeMapping.ValidationMinLength;
model.ValidationMaxLength = productAttributeMapping.ValidationMaxLength;
model.ValidationFileAllowedExtensions = productAttributeMapping.ValidationFileAllowedExtensions;
model.ValidationFileMaximumSize = productAttributeMapping.ValidationFileMaximumSize;
model.DefaultValue = productAttributeMapping.DefaultValue;
}
//prepare condition attributes model
model.ConditionAllowed = true;
await PrepareProductAttributeConditionModelAsync(model.ConditionModel, productAttributeMapping);
//define localized model configuration action
localizedModelConfiguration = async (locale, languageId) =>
{
locale.TextPrompt = await _localizationService.GetLocalizedAsync(productAttributeMapping, entity => entity.TextPrompt, languageId, false, false);
locale.DefaultValue = await _localizationService.GetLocalizedAsync(productAttributeMapping, entity => entity.DefaultValue, languageId, false, false);
};
//prepare nested search model
PrepareProductAttributeValueSearchModel(model.ProductAttributeValueSearchModel, productAttributeMapping);
}
model.ProductId = product.Id;
//prepare localized models
if (!excludeProperties)
model.Locales = await _localizedModelFactory.PrepareLocalizedModelsAsync(localizedModelConfiguration);
//prepare available product attributes
model.AvailableProductAttributes = (await _productAttributeService.GetAllProductAttributesAsync()).Select(productAttribute => new SelectListItem
{
Text = productAttribute.Name,
Value = productAttribute.Id.ToString()
}).ToList();
return model;
}
///
/// Prepare paged product attribute value list model
///
/// Product attribute value search model
/// Product attribute mapping
///
/// A task that represents the asynchronous operation
/// The task result contains the product attribute value list model
///
public virtual async Task PrepareProductAttributeValueListModelAsync(ProductAttributeValueSearchModel searchModel,
ProductAttributeMapping productAttributeMapping)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(productAttributeMapping);
//get product attribute values
var productAttributeValues = (await _productAttributeService
.GetProductAttributeValuesAsync(productAttributeMapping.Id)).ToPagedList(searchModel);
//prepare list model
var model = await new ProductAttributeValueListModel().PrepareToGridAsync(searchModel, productAttributeValues, () =>
{
return productAttributeValues.SelectAwait(async value =>
{
//fill in model values from the entity
var productAttributeValueModel = value.ToModel();
//fill in additional values (not existing in the entity)
productAttributeValueModel.AttributeValueTypeName = await _localizationService.GetLocalizedEnumAsync(value.AttributeValueType);
productAttributeValueModel.Name = productAttributeMapping.AttributeControlType != AttributeControlType.ColorSquares
? value.Name : $"{value.Name} - {value.ColorSquaresRgb}";
if (value.AttributeValueType == AttributeValueType.Simple)
{
productAttributeValueModel.PriceAdjustmentStr = value.PriceAdjustment.ToString("G29");
if (value.PriceAdjustmentUsePercentage)
productAttributeValueModel.PriceAdjustmentStr += " %";
productAttributeValueModel.WeightAdjustmentStr = value.WeightAdjustment.ToString("G29");
}
if (value.AttributeValueType == AttributeValueType.AssociatedToProduct)
{
productAttributeValueModel.AssociatedProductName = (await _productService.GetProductByIdAsync(value.AssociatedProductId))?.Name ?? string.Empty;
}
var valuePicture = (await _productAttributeService.GetProductAttributeValuePicturesAsync(value.Id)).FirstOrDefault();
var pictureThumbnailUrl = await _pictureService.GetPictureUrlAsync(valuePicture?.PictureId ?? 0, 75, false);
//little hack here. Grid is rendered wrong way with without "src" attribute
if (string.IsNullOrEmpty(pictureThumbnailUrl))
pictureThumbnailUrl = await _pictureService.GetDefaultPictureUrlAsync(targetSize: 1);
productAttributeValueModel.PictureThumbnailUrl = pictureThumbnailUrl;
return productAttributeValueModel;
});
});
return model;
}
///
/// Prepare product attribute value model
///
/// Product attribute value model
/// Product attribute mapping
/// Product attribute value
/// Whether to exclude populating of some properties of model
///
/// A task that represents the asynchronous operation
/// The task result contains the product attribute value model
///
public virtual async Task PrepareProductAttributeValueModelAsync(ProductAttributeValueModel model,
ProductAttributeMapping productAttributeMapping, ProductAttributeValue productAttributeValue, bool excludeProperties = false)
{
ArgumentNullException.ThrowIfNull(productAttributeMapping);
Func localizedModelConfiguration = null;
if (productAttributeValue != null)
{
//fill in model values from the entity
model ??= new ProductAttributeValueModel
{
ProductAttributeMappingId = productAttributeValue.ProductAttributeMappingId,
AttributeValueTypeId = productAttributeValue.AttributeValueTypeId,
AttributeValueTypeName = await _localizationService.GetLocalizedEnumAsync(productAttributeValue.AttributeValueType),
AssociatedProductId = productAttributeValue.AssociatedProductId,
Name = productAttributeValue.Name,
ColorSquaresRgb = productAttributeValue.ColorSquaresRgb,
DisplayColorSquaresRgb = productAttributeMapping.AttributeControlType == AttributeControlType.ColorSquares,
ImageSquaresPictureId = productAttributeValue.ImageSquaresPictureId,
DisplayImageSquaresPicture = productAttributeMapping.AttributeControlType == AttributeControlType.ImageSquares,
PriceAdjustment = productAttributeValue.PriceAdjustment,
PriceAdjustmentUsePercentage = productAttributeValue.PriceAdjustmentUsePercentage,
WeightAdjustment = productAttributeValue.WeightAdjustment,
Cost = productAttributeValue.Cost,
CustomerEntersQty = productAttributeValue.CustomerEntersQty,
Quantity = productAttributeValue.Quantity,
IsPreSelected = productAttributeValue.IsPreSelected,
DisplayOrder = productAttributeValue.DisplayOrder,
PictureIds = (await _productAttributeService.GetProductAttributeValuePicturesAsync(productAttributeValue.Id))
.Select(c => c.PictureId).ToList(),
};
model.AssociatedProductName = (await _productService.GetProductByIdAsync(productAttributeValue.AssociatedProductId))?.Name;
//define localized model configuration action
localizedModelConfiguration = async (locale, languageId) =>
{
locale.Name = await _localizationService.GetLocalizedAsync(productAttributeValue, entity => entity.Name, languageId, false, false);
};
}
model.ProductAttributeMappingId = productAttributeMapping.Id;
model.DisplayColorSquaresRgb = productAttributeMapping.AttributeControlType == AttributeControlType.ColorSquares;
model.DisplayImageSquaresPicture = productAttributeMapping.AttributeControlType == AttributeControlType.ImageSquares;
//set default values for the new model
if (productAttributeValue == null)
model.Quantity = 1;
//prepare localized models
if (!excludeProperties)
model.Locales = await _localizedModelFactory.PrepareLocalizedModelsAsync(localizedModelConfiguration);
//prepare picture models
var productPictures = await _productService.GetProductPicturesByProductIdAsync(productAttributeMapping.ProductId);
model.ProductPictureModels = await productPictures.SelectAwait(async productPicture => new ProductPictureModel
{
Id = productPicture.Id,
ProductId = productPicture.ProductId,
PictureId = productPicture.PictureId,
PictureUrl = await _pictureService.GetPictureUrlAsync(productPicture.PictureId),
DisplayOrder = productPicture.DisplayOrder
}).ToListAsync();
return model;
}
///
/// Prepare product model to associate to the product attribute value
///
/// Product model to associate to the product attribute value
///
/// A task that represents the asynchronous operation
/// The task result contains the product model to associate to the product attribute value
///
public virtual async Task PrepareAssociateProductToAttributeValueSearchModelAsync(
AssociateProductToAttributeValueSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
searchModel.IsLoggedInAsVendor = await _workContext.GetCurrentVendorAsync() != null;
//prepare available categories
await _baseAdminModelFactory.PrepareCategoriesAsync(searchModel.AvailableCategories);
//prepare available manufacturers
await _baseAdminModelFactory.PrepareManufacturersAsync(searchModel.AvailableManufacturers);
//prepare available stores
await _baseAdminModelFactory.PrepareStoresAsync(searchModel.AvailableStores);
//prepare available vendors
await _baseAdminModelFactory.PrepareVendorsAsync(searchModel.AvailableVendors);
//prepare available product types
await _baseAdminModelFactory.PrepareProductTypesAsync(searchModel.AvailableProductTypes);
//prepare page parameters
searchModel.SetPopupGridPageSize();
return searchModel;
}
///
/// Prepare paged product model to associate to the product attribute value
///
/// Product model to associate to the product attribute value
///
/// A task that represents the asynchronous operation
/// The task result contains the product model to associate to the product attribute value
///
public virtual async Task PrepareAssociateProductToAttributeValueListModelAsync(
AssociateProductToAttributeValueSearchModel searchModel)
{
ArgumentNullException.ThrowIfNull(searchModel);
//a vendor should have access only to his products
var currentVendor = await _workContext.GetCurrentVendorAsync();
if (currentVendor != null)
searchModel.SearchVendorId = currentVendor.Id;
//get products
var products = await _productService.SearchProductsAsync(showHidden: true,
categoryIds: new List { searchModel.SearchCategoryId },
manufacturerIds: new List { searchModel.SearchManufacturerId },
storeId: searchModel.SearchStoreId,
vendorId: searchModel.SearchVendorId,
productType: searchModel.SearchProductTypeId > 0 ? (ProductType?)searchModel.SearchProductTypeId : null,
keywords: searchModel.SearchProductName,
pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize);
//prepare grid model
var model = await new AssociateProductToAttributeValueListModel().PrepareToGridAsync(searchModel, products, () =>
{
//fill in model values from the entity
return products.SelectAwait(async product =>
{
var productModel = product.ToModel();
productModel.SeName = await _urlRecordService.GetSeNameAsync(product, 0, true, false);
return productModel;
});
});
return model;
}
///
/// Prepare paged product attribute combination list model
///
/// Product attribute combination search model
/// Product
///
/// A task that represents the asynchronous operation
/// The task result contains the product attribute combination list model
///
public virtual async Task PrepareProductAttributeCombinationListModelAsync(
ProductAttributeCombinationSearchModel searchModel, Product product)
{
ArgumentNullException.ThrowIfNull(searchModel);
ArgumentNullException.ThrowIfNull(product);
//get product attribute combinations
var productAttributeCombinations = (await _productAttributeService
.GetAllProductAttributeCombinationsAsync(product.Id)).ToPagedList(searchModel);
var currentCustomer = await _workContext.GetCurrentCustomerAsync();
var currentStore = await _storeContext.GetCurrentStoreAsync();
//prepare grid model
var model = await new ProductAttributeCombinationListModel().PrepareToGridAsync(searchModel, productAttributeCombinations, () =>
{
return productAttributeCombinations.SelectAwait(async combination =>
{
//fill in model values from the entity
var productAttributeCombinationModel = combination.ToModel();
//fill in additional values (not existing in the entity)
productAttributeCombinationModel.AttributesXml = await _productAttributeFormatter
.FormatAttributesAsync(product, combination.AttributesXml, currentCustomer, currentStore, "
", true, true, true, false);
var combinationPicture = (await _productAttributeService.GetProductAttributeCombinationPicturesAsync(combination.Id)).FirstOrDefault();
var pictureThumbnailUrl = await _pictureService.GetPictureUrlAsync(combinationPicture?.PictureId ?? 0, 75, false);
//little hack here. Grid is rendered wrong way with without "src" attribute
if (string.IsNullOrEmpty(pictureThumbnailUrl))
pictureThumbnailUrl = await _pictureService.GetDefaultPictureUrlAsync(targetSize: 1);
productAttributeCombinationModel.PictureThumbnailUrl = pictureThumbnailUrl;
var warnings = (await _shoppingCartService.GetShoppingCartItemAttributeWarningsAsync(currentCustomer,
ShoppingCartType.ShoppingCart, product,
attributesXml: combination.AttributesXml,
ignoreNonCombinableAttributes: true)
).Aggregate(string.Empty, (message, warning) => $"{message}{warning}
");
productAttributeCombinationModel.Warnings = new List { warnings };
return productAttributeCombinationModel;
});
});
return model;
}
///
/// Prepare product attribute combination model
///
/// Product attribute combination model
/// Product
/// Product attribute combination
/// Whether to exclude populating of some properties of model
///
/// A task that represents the asynchronous operation
/// The task result contains the product attribute combination model
///
public virtual async Task PrepareProductAttributeCombinationModelAsync(ProductAttributeCombinationModel model,
Product product, ProductAttributeCombination productAttributeCombination, bool excludeProperties = false)
{
ArgumentNullException.ThrowIfNull(product);
if (productAttributeCombination != null)
{
//fill in model values from the entity
model ??= new ProductAttributeCombinationModel
{
AllowOutOfStockOrders = productAttributeCombination.AllowOutOfStockOrders,
AttributesXml = productAttributeCombination.AttributesXml,
Gtin = productAttributeCombination.Gtin,
Id = productAttributeCombination.Id,
ManufacturerPartNumber = productAttributeCombination.ManufacturerPartNumber,
NotifyAdminForQuantityBelow = productAttributeCombination.NotifyAdminForQuantityBelow,
OverriddenPrice = productAttributeCombination.OverriddenPrice,
PictureIds = (await _productAttributeService.GetProductAttributeCombinationPicturesAsync(productAttributeCombination.Id))
.Select(c => c.PictureId).ToList(),
ProductId = productAttributeCombination.ProductId,
Sku = productAttributeCombination.Sku,
StockQuantity = productAttributeCombination.StockQuantity,
MinStockQuantity = productAttributeCombination.MinStockQuantity
};
}
model.ProductId = product.Id;
//set default values for the new model
if (productAttributeCombination == null)
{
model.ProductId = product.Id;
model.StockQuantity = 10000;
model.NotifyAdminForQuantityBelow = 1;
}
//prepare picture models
var productPictures = await _productService.GetProductPicturesByProductIdAsync(product.Id);
model.ProductPictureModels = await productPictures.SelectAwait(async productPicture => new ProductPictureModel
{
Id = productPicture.Id,
ProductId = productPicture.ProductId,
PictureId = productPicture.PictureId,
PictureUrl = await _pictureService.GetPictureUrlAsync(productPicture.PictureId),
DisplayOrder = productPicture.DisplayOrder
}).ToListAsync();
//prepare product attribute mappings (exclude non-combinable attributes)
var attributes = (await _productAttributeService.GetProductAttributeMappingsByProductIdAsync(product.Id))
.Where(productAttributeMapping => !productAttributeMapping.IsNonCombinable()).ToList();
foreach (var attribute in attributes)
{
var attributeModel = new ProductAttributeCombinationModel.ProductAttributeModel
{
Id = attribute.Id,
ProductAttributeId = attribute.ProductAttributeId,
Name = (await _productAttributeService.GetProductAttributeByIdAsync(attribute.ProductAttributeId)).Name,
TextPrompt = attribute.TextPrompt,
IsRequired = attribute.IsRequired,
AttributeControlType = attribute.AttributeControlType
};
if (attribute.ShouldHaveValues())
{
//values
var attributeValues = await _productAttributeService.GetProductAttributeValuesAsync(attribute.Id);
var preSelectedValue = _productAttributeParser.ParseValues(model.AttributesXml, attribute.Id);
foreach (var attributeValue in attributeValues)
{
var attributeValueModel = new ProductAttributeCombinationModel.ProductAttributeValueModel
{
Id = attributeValue.Id,
Name = attributeValue.Name,
IsPreSelected = preSelectedValue.Contains(attributeValue.Id.ToString())
};
attributeModel.Values.Add(attributeValueModel);
}
}
model.ProductAttributes.Add(attributeModel);
}
return model;
}
#endregion
}