Exemple #1
0
 /// <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));
            }