/// <summary>
            /// Executes the workflow for getting item available quantities.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>The response.</returns>
            protected override GetItemAvailableQuantitiesResponse Process(GetItemAvailableQuantitiesRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.Null(request.ItemUnits, "request.ItemUnits");

                // Gets all distinct items.
                IEnumerable <ItemVariantInventoryDimension> distinctItems = request.ItemUnits.Select(itemUnit => itemUnit.GetItem()).Distinct();

                // Get item available quantities.
                var quantityRequest  = new GetItemAvailableQuantitiesByItemsServiceRequest(request.QueryResultSettings, distinctItems, request.CustomerAccountNumber);
                var quantityResponse = this.Context.Execute <GetItemAvailableQuantitiesByItemsServiceResponse>(quantityRequest);

                // Converts to requested unit of measure if possible.
                var convertedItemAvailableQuantities = ChannelAvailabilityHelper.ConvertUnitOfMeasure(this.Context, quantityResponse.ItemAvailableQuantities.Results, request.ItemUnits);

                // Get item available quantities.
                return(new GetItemAvailableQuantitiesResponse(convertedItemAvailableQuantities.AsPagedResult(quantityResponse.ItemAvailableQuantities.TotalCount)));
            }
            /// <summary>
            /// Processes the specified request.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <returns>
            /// Available quantities of specified listings at the requested warehouse.
            /// </returns>
            protected override GetListingAvailableQuantitiesResponse Process(GetListingAvailableQuantitiesRequest request)
            {
                ThrowIf.Null(request, "request");
                ThrowIf.NullOrEmpty(request.ProductIds, "No Ids have been provided");

                QueryResultSettings settings = QueryResultSettings.AllRecords;
                var productIds = request.ProductIds.Distinct().ToList();
                ProductSearchCriteria queryCriteria = new ProductSearchCriteria(this.Context.GetPrincipal().ChannelId)
                {
                    Ids       = productIds,
                    DataLevel = CommerceEntityDataLevel.Identity,
                };

                var productSearchResult = request.RequestContext.Runtime.Execute <ProductSearchServiceResponse>(
                    new ProductSearchServiceRequest(queryCriteria, settings), request.RequestContext).ProductSearchResult;

                if (productSearchResult.Results.IsNullOrEmpty())
                {
                    string nonResolvedProductIdsInfo = string.Join(" ", productIds);
                    //// This is a valid situtation for cross channel scenarios, wish lists for example.
                    NetTracer.Warning("None of the specified product ids were found on the current channel {0}. ProductIds = {1}", this.Context.GetPrincipal().ChannelId, nonResolvedProductIdsInfo);
                    return(new GetListingAvailableQuantitiesResponse());
                }

                var productMap = productSearchResult.Results.ToDictionary(p => p.RecordId, p => p);
                var items      = this.GetItemAndInventDimId(productIds, productSearchResult, productMap);

                settings = new QueryResultSettings(new PagingInfo(items.Count(), 0));
                var itemAvailabilities = new HashSet <ItemAvailability>();
                var itemUnits          = new HashSet <ItemUnit>();

                if (request.ChannelId == 0)
                {
                    var itemVariantInventoryDimensions = new HashSet <ItemVariantInventoryDimension>();
                    foreach (var item in items)
                    {
                        itemVariantInventoryDimensions.Add(new ItemVariantInventoryDimension(item.Item1, item.Item2));
                    }

                    var itemAvailableQuantitiesRequest  = new GetItemAvailableQuantitiesByItemsServiceRequest(settings, itemVariantInventoryDimensions, string.Empty);
                    var itemAvailableQuantitiesResponse = this.Context.Execute <GetItemAvailableQuantitiesByItemsServiceResponse>(itemAvailableQuantitiesRequest);
                    foreach (var quantity in itemAvailableQuantitiesResponse.ItemAvailableQuantities.Results)
                    {
                        if (quantity != null)
                        {
                            var productAvailableQuantity = new ItemAvailability
                            {
                                ItemId = quantity.ItemId,
                                VariantInventoryDimensionId = quantity.VariantInventoryDimensionId,
                                AvailableQuantity           = quantity.AvailableQuantity,
                                UnitOfMeasure = quantity.UnitOfMeasure
                            };

                            itemAvailabilities.Add(productAvailableQuantity);

                            var itemUnit = new ItemUnit
                            {
                                ItemId = quantity.ItemId,
                                VariantInventoryDimensionId = quantity.VariantInventoryDimensionId,
                                UnitOfMeasure = items.Where(i => i.Item1.Equals(quantity.ItemId) && i.Item2.Equals(quantity.VariantInventoryDimensionId)).SingleOrDefault().Item3
                            };

                            itemUnits.Add(itemUnit);
                        }
                    }
                }
                else
                {
                    var itemWarehouses = new HashSet <ItemWarehouse>();
                    foreach (var item in items)
                    {
                        var itemWarehouse = new ItemWarehouse()
                        {
                            ItemId = item.Item1,
                            VariantInventoryDimensionId = item.Item2,
                            InventoryLocationId         = this.Context.GetChannelConfiguration().InventLocation
                        };
                        itemWarehouses.Add(itemWarehouse);
                    }

                    var warehouseRequest  = new GetItemAvailabilitiesByItemWarehousesServiceRequest(settings, itemWarehouses);
                    var warehouseResponse = this.Context.Execute <GetItemAvailabilitiesByItemWarehousesServiceResponse>(warehouseRequest);
                    foreach (var quantity in warehouseResponse.ItemAvailabilities.Results)
                    {
                        if (quantity != null)
                        {
                            itemAvailabilities.Add(quantity);

                            var itemUnit = new ItemUnit
                            {
                                ItemId = quantity.ItemId,
                                VariantInventoryDimensionId = quantity.VariantInventoryDimensionId,
                                UnitOfMeasure = items.Where(i => i.Item1.Equals(quantity.ItemId) && i.Item2.Equals(quantity.VariantInventoryDimensionId)).SingleOrDefault().Item3
                            };

                            itemUnits.Add(itemUnit);
                        }
                    }
                }

                var itemAvailabilitiesList  = ChannelAvailabilityHelper.ConvertUnitOfMeasure(this.Context, itemAvailabilities.ToList(), itemUnits.ToList());
                var processedAvailabilities = this.ProcessItemAvailabilities(itemAvailabilitiesList, productIds, productSearchResult, productMap);

                return(new GetListingAvailableQuantitiesResponse(processedAvailabilities.AsPagedResult()));
            }
            private static GetItemAvailableQuantitiesByItemsServiceResponse GetItemAvailableQuantitiesByItems(GetItemAvailableQuantitiesByItemsServiceRequest request)
            {
                var settings = request.QueryResultSettings ?? QueryResultSettings.AllRecords;
                PagedResult <ItemAvailableQuantity> itemAvailableQuantities = null;

                try
                {
                    var searchCriteria = new ItemAvailabilitiesQueryCriteria(request.CustomerAccountNumber, request.Items, includeQuantities: true);
                    var dataRequest    = new GetItemAvailabilitiesDataRequest(searchCriteria, settings);
                    itemAvailableQuantities = request.RequestContext.Execute <EntityDataServiceResponse <ItemAvailableQuantity> >(dataRequest).PagedEntityCollection;
                }
                catch (StorageException)
                {
                    // supress exception in order to not block the order
                    // raise the notification instead
                    UnableToDetermineQuantityNotification notification = new UnableToDetermineQuantityNotification(request.Items);
                    request.RequestContext.Notify(notification);
                }

                return(new GetItemAvailableQuantitiesByItemsServiceResponse(itemAvailableQuantities));
            }