/// <summary>
            /// Get availability of items for specified stores.
            /// </summary>
            /// <param name="context">The request context.</param>
            /// <param name="stores">The collection of store locations.</param>
            /// <param name="itemUnits">The collection of items.</param>
            /// <returns>
            /// The collection of store availability information.
            /// </returns>
            internal static Collection <OrgUnitAvailability> GetChannelAvailabiltiy(RequestContext context, IEnumerable <OrgUnitLocation> stores, IEnumerable <ItemUnit> itemUnits)
            {
                HashSet <ItemWarehouse> itemWarehouses = new HashSet <ItemWarehouse>();

                foreach (OrgUnitLocation storeLocation in stores)
                {
                    foreach (var itemUnit in itemUnits)
                    {
                        ItemWarehouse itemWarehouse = new ItemWarehouse
                        {
                            ItemId = itemUnit.ItemId,
                            VariantInventoryDimensionId = itemUnit.VariantInventoryDimensionId,
                            InventoryLocationId         = storeLocation.InventoryLocationId
                        };
                        itemWarehouses.Add(itemWarehouse);
                    }
                }

                var request  = new GetItemAvailabilitiesByItemWarehousesServiceRequest(QueryResultSettings.AllRecords, itemWarehouses);
                var response = context.Execute <GetItemAvailabilitiesByItemWarehousesServiceResponse>(request);

                ChannelAvailabilityHelper.ConvertUnitOfMeasure(context, response.ItemAvailabilities.Results, itemUnits);

                Collection <OrgUnitAvailability> storeAvailabilities = new Collection <OrgUnitAvailability>();

                foreach (OrgUnitLocation storeLocation in stores)
                {
                    List <ItemAvailability> itemAvailabilities = response.ItemAvailabilities.Results.Where(item => item.InventoryLocationId.Equals(storeLocation.InventoryLocationId, StringComparison.OrdinalIgnoreCase)).ToList();
                    storeAvailabilities.Add(new OrgUnitAvailability(storeLocation, itemAvailabilities));
                }

                return(storeAvailabilities);
            }
            /// <summary>
            /// Gets a list of item availability given the item warehouse filters.
            /// </summary>
            /// <param name="context">The request context.</param>
            /// <param name="itemWarehouses">The list of item warehouse filters.</param>
            /// <returns>The list of item availability.</returns>
            internal static IEnumerable <ItemAvailability> GetItemAvailabilitiesByItemWarehouses(
                RequestContext context,
                IEnumerable <ItemWarehouse> itemWarehouses)
            {
                var request  = new GetItemAvailabilitiesByItemWarehousesServiceRequest(QueryResultSettings.AllRecords, itemWarehouses.Distinct());
                var response = context.Execute <GetItemAvailabilitiesByItemWarehousesServiceResponse>(request);

                return(response.ItemAvailabilities.Results);
            }
            /// <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 GetItemAvailabilitiesByItemWarehousesServiceResponse GetItemAvailabilitiesByItemWarehouses(GetItemAvailabilitiesByItemWarehousesServiceRequest request)
            {
                QueryResultSettings            settings           = request.QueryResultSettings ?? QueryResultSettings.AllRecords;
                PagedResult <ItemAvailability> itemAvailabilities = null;

                try
                {
                    var searchCriteria = new ItemAvailabilitiesQueryCriteria(request.ItemWarehouses);
                    var dataRequest    = new GetItemAvailabilitiesDataRequest(searchCriteria, settings);
                    itemAvailabilities = request.RequestContext.Runtime.Execute <EntityDataServiceResponse <ItemAvailability> >(dataRequest, request.RequestContext).PagedEntityCollection;
                }
                catch (StorageException)
                {
                    // supress exception in order not to block the order
                    // raise the notification instead
                    UnableToDetermineQuantityForStoresNotification notification = new UnableToDetermineQuantityForStoresNotification(request.ItemWarehouses);
                    request.RequestContext.Notify(notification);
                }

                return(new GetItemAvailabilitiesByItemWarehousesServiceResponse(itemAvailabilities));
            }