/// <summary> /// Initializes a new instance of the <see cref="GetProductsByIdsProcedure"/> class. /// </summary> /// <param name="request">The data request.</param> public GetProductsByIdsProcedure(GetProductsDataRequest request) { this.request = request; }
/// <summary> /// Executes the workflow to retrieve active product prices for given product ids. /// </summary> /// <param name="request">The request.</param> /// <returns>The response.</returns> protected override GetActiveProductPriceResponse Process(GetActiveProductPriceRequest request) { ThrowIf.Null(request, "request"); var validateCustomerAccountRequest = new GetValidatedCustomerAccountNumberServiceRequest(request.CustomerAccountNumber, throwOnValidationFailure: true); var validateCustomerAccountResponse = this.Context.Execute <GetValidatedCustomerAccountNumberServiceResponse>(validateCustomerAccountRequest); if (validateCustomerAccountResponse.IsCustomerAccountNumberInContextDifferent) { request.CustomerAccountNumber = validateCustomerAccountResponse.ValidatedAccountNumber; } bool downloadedProductsFilter = false; if (request.Context.ChannelId != this.Context.GetPrincipal().ChannelId) { downloadedProductsFilter = true; } var settings = new QueryResultSettings(PagingInfo.CreateWithExactCount(request.ProductIds.Count(), 0)); var productsRequest = new GetProductsDataRequest(request.ProductIds, settings, downloadedProductsFilter); var products = this.Context.Execute <EntityDataServiceResponse <SimpleProduct> >(productsRequest).PagedEntityCollection.Results; var activePrices = new List <ProductPrice>(products.Count); // package sales lines to calculate var salesLines = new List <SalesLine>(products.Count); foreach (var product in products) { salesLines.Add(new SalesLine { ItemId = product.ItemId, InventoryDimensionId = product.InventoryDimensionId, SalesOrderUnitOfMeasure = product.DefaultUnitOfMeasure, LineId = System.Guid.NewGuid().ToString("N"), Quantity = 1, ProductId = product.RecordId, CatalogId = request.Context.CatalogId.GetValueOrDefault() }); } // set the catalogIds on the sales lines if (request.Context.CatalogId != null) { if (request.Context.CatalogId.Value > 0) { // If a specific catalogId is set on the context, add it to the catalogIds on the sales lines. foreach (var sl in salesLines) { sl.CatalogIds.Add(request.Context.CatalogId.Value); } } else { // If catalogId is 0, add all active catalogs to the catalogIds on the sales lines. foreach (var sl in salesLines) { var productCatalogAssociationRequest = new GetProductCatalogAssociationsDataRequest(salesLines.Select(p => p.ProductId)) { QueryResultSettings = QueryResultSettings.AllRecords }; var productCatalogs = request.RequestContext.Runtime.Execute <GetProductCatalogAssociationsDataResponse>( productCatalogAssociationRequest, request.RequestContext).CatalogAssociations; sl.CatalogIds.UnionWith(productCatalogs.Where(pc => pc.ProductRecordId == sl.ProductId).Select(pc => pc.CatalogRecordId)); } } } Customer customer = null; if (!string.IsNullOrWhiteSpace(request.CustomerAccountNumber)) { var getCustomerDataRequest = new GetCustomerDataRequest(request.CustomerAccountNumber); SingleEntityDataServiceResponse <Customer> getCustomerDataResponse = this.Context.Runtime.Execute <SingleEntityDataServiceResponse <Customer> >(getCustomerDataRequest, this.Context); customer = getCustomerDataResponse.Entity; } string priceGroup = customer != null ? customer.PriceGroup : string.Empty; // calculate prices for sales lines var itemPriceServiceRequest = new GetPricesServiceRequest(salesLines, request.DateWhenActive, request.CustomerAccountNumber, priceGroup, PricingCalculationMode.Independent, request.AffiliationLoyaltyTiers); var itemPriceServiceResponse = this.Context.Execute <GetPricesServiceResponse>(itemPriceServiceRequest); var salesLineDictionary = itemPriceServiceResponse.SalesLines.Results.ToDictionary(sl => sl.ProductId); foreach (var product in products) { SalesLine salesLine; if (!salesLineDictionary.TryGetValue(product.RecordId, out salesLine)) { salesLine = new SalesLine(); } ProductPrice activePrice = GetActiveProductPriceRequestHandler.ActivePriceFromSalesLine(product.RecordId, salesLine); activePrice.ProductId = product.RecordId; activePrice.ValidFrom = request.DateWhenActive; activePrice.CurrencyCode = itemPriceServiceResponse.CurrencyCode; activePrice.ChannelId = request.Context.ChannelId.GetValueOrDefault(); activePrice.CatalogId = request.Context.CatalogId.GetValueOrDefault(); activePrices.Add(activePrice); } return(new GetActiveProductPriceResponse(activePrices.AsPagedResult())); }
/// <summary> /// Gets the products requested based on their record identifiers. /// </summary> /// <param name="request">The request to retrieve <see cref="SimpleProduct"/> objects.</param> /// <returns>The response containing the collection of products requested.</returns> private static GetProductsServiceResponse GetProducts(GetProductsServiceRequest request) { ThrowIf.Null(request, "request"); ThrowIf.Null(request.QueryResultSettings, "request.QueryResultSettings"); if (request.ProductIds.IsNullOrEmpty() && request.ItemAndInventDimIdCombinations.IsNullOrEmpty()) { return(new GetProductsServiceResponse(PagedResult <SimpleProduct> .Empty())); } if (request.ProductIds != null && request.ProductIds.Any() && request.ItemAndInventDimIdCombinations != null && request.ItemAndInventDimIdCombinations.Any()) { throw new ArgumentOutOfRangeException("request", "The GetProductsServiceRequest cannot be processed when both product ids and item-inventdim ids are specified. Please specify only one."); } if (request.SearchLocation == SearchLocation.Remote) { throw new NotSupportedException(string.Format("SearchLocation {0} is not supported.", request.SearchLocation)); } bool?downloadedProductsFilter = null; switch (request.SearchLocation) { case SearchLocation.Local: downloadedProductsFilter = false; break; case SearchLocation.Remote: downloadedProductsFilter = true; break; case SearchLocation.All: downloadedProductsFilter = null; break; default: throw new InvalidOperationException(string.Format("SearchLocation '{0}' is not supported.", request.SearchLocation)); } if (request.QueryResultSettings.Sorting.IsSpecified) { // We have to enforce paging by "IsRemote" flag and retrieve local products first. Otherwise result set can be shifted once remote product is inserted to local database. throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidRequest, "When retrieving products by identifiers only default sort order is supported."); } request.QueryResultSettings.Sorting.Add(new SortColumn(SimpleProduct.IsRemoteColumnName, isDescending: false)); GetProductsDataRequest productsDataRequest; if (!request.ProductIds.IsNullOrEmpty()) { productsDataRequest = new GetProductsDataRequest(request.ProductIds, request.QueryResultSettings, downloadedProductsFilter); } else { productsDataRequest = new GetProductsDataRequest(request.ItemAndInventDimIdCombinations, request.QueryResultSettings, downloadedProductsFilter); } PagedResult <SimpleProduct> products = request.RequestContext.Execute <EntityDataServiceResponse <SimpleProduct> >(productsDataRequest).PagedEntityCollection; // If requested products are not found in the current store, download it to local database as assorted to current channel and then retrieve them. int numberOfProductsRequested = request.ProductIds.IsNullOrEmpty() ? request.ItemAndInventDimIdCombinations.Count : request.ProductIds.Count; int numberOfProductsExpected = request.QueryResultSettings.Paging.NoPageSizeLimit ? numberOfProductsRequested : Math.Min(numberOfProductsRequested, (int)request.QueryResultSettings.Paging.Top); if (request.SearchLocation.HasFlag(SearchLocation.Remote) && (products == null || products.Results.IsNullOrEmpty() || products.TotalCount < numberOfProductsExpected)) { try { UpsertRemoteProductData(request); } catch (FeatureNotSupportedException) { // Suppress FeatureNotSupportException for offline scenario. // Exception will be logged by ExceptionNotificationHandler. } products = request.RequestContext.Execute <EntityDataServiceResponse <SimpleProduct> >(productsDataRequest).PagedEntityCollection; } products = PopulateComplexProductProperties(request.ChannelId, products, request.RequestContext, request.SearchLocation, downloadedProductsFilter, request.CalculatePrice); // If a product is assorted locally and downloaded from virtual catalog, we only return the locally assorted version. // Ideally, collapsing these should happen from the underlying product data service. products.Results = products.Results.GroupBy(p => p.RecordId).Select(group => group.OrderBy(p => p.IsRemote).First()).AsReadOnly(); return(new GetProductsServiceResponse(products)); }
private static EntityDataServiceResponse <Microsoft.Dynamics.Commerce.Runtime.DataModel.Product> ProcessGetProductsDataRequest(GetProductsDataRequest request) { ThrowIf.Null(request, "request"); ThrowIf.Null(request.QueryResultSettings, "request.QueryResultSettings"); if (request.QueryResultSettings.ColumnSet == null || request.QueryResultSettings.ColumnSet.Count <= 0) { throw new ArgumentOutOfRangeException("request", request.QueryResultSettings.ColumnSet, "Columnset cannot be null or empty for this data request."); } if (request.ProductIds.IsNullOrEmpty() && request.ItemAndInventDimIdCombinations.IsNullOrEmpty()) { throw new ArgumentOutOfRangeException("request", "The GetProductsDataRequest cannot be processed when both product ids and item-inventdim ids are specified. Please specify only one."); } if (request.ProductIds.IsNullOrEmpty() && request.ItemAndInventDimIdCombinations.IsNullOrEmpty()) { return(new EntityDataServiceResponse <Microsoft.Dynamics.Commerce.Runtime.DataModel.Product>(new PagedResult <Microsoft.Dynamics.Commerce.Runtime.DataModel.Product>(new List <Microsoft.Dynamics.Commerce.Runtime.DataModel.Product>().AsReadOnly()))); } PagedResult <Microsoft.Dynamics.Commerce.Runtime.DataModel.Product> results = null; if (!request.ProductIds.IsNullOrEmpty()) { var getProductsByIdsProcedure = new GetProductsByIdsProcedure(request); results = getProductsByIdsProcedure.Execute(); } else if (!request.ItemAndInventDimIdCombinations.IsNullOrEmpty()) { throw new NotImplementedException("Coming soon!"); } return(new EntityDataServiceResponse <Microsoft.Dynamics.Commerce.Runtime.DataModel.Product>(results)); }