Exemplo n.º 1
0
            /// <summary>
            /// Loads customer.
            /// </summary>
            /// <param name="context">The service request context.</param>
            /// <param name="accountNumber">The account number.</param>
            /// <returns>The customer, or null if not found.</returns>
            private static Customer GetCustomer(RequestContext context, string accountNumber)
            {
                var getCustomerDataRequest = new GetCustomerDataRequest(accountNumber);
                SingleEntityDataServiceResponse <Customer> getCustomerDataResponse = context.Execute <SingleEntityDataServiceResponse <Customer> >(getCustomerDataRequest);
                Customer customer = getCustomerDataResponse.Entity;

                return(customer);
            }
Exemplo n.º 2
0
            /// <summary>
            /// Calculates the auto charges for the transaction / sales lines.
            /// </summary>
            /// <param name="request">The request.</param>
            /// <param name="transaction">Current sales transaction.</param>
            private static void CalculateAutoCharges(GetChargesServiceRequest request, SalesTransaction transaction)
            {
                // get customer to see their markup group
                string customerAccount     = transaction.CustomerId ?? string.Empty;
                string customerChargeGroup = string.Empty;

                if (!string.IsNullOrWhiteSpace(customerAccount))
                {
                    var getCustomerDataRequest = new GetCustomerDataRequest(customerAccount);
                    SingleEntityDataServiceResponse <Customer> getCustomerDataResponse = request.RequestContext.Execute <SingleEntityDataServiceResponse <Customer> >(getCustomerDataRequest);
                    var customer = getCustomerDataResponse.Entity;
                    customerChargeGroup = (customer != null) ? customer.ChargeGroup : string.Empty;
                }

                // get delivery mode information off the transaction
                string deliveryMode      = transaction.DeliveryMode ?? string.Empty;
                string deliveryModeGroup = GetDeliveryModeGroupFromCode(request.RequestContext, deliveryMode);

                var    channelConfiguration = request.RequestContext.GetChannelConfiguration();
                string currencyCode         = (channelConfiguration != null) ? channelConfiguration.Currency : string.Empty;

                // put charges on the transaction
                var transactionCharges = CalculateTransactionCharges(request.RequestContext, customerAccount, customerChargeGroup, deliveryMode, deliveryModeGroup, transaction);

                foreach (var charge in transactionCharges)
                {
                    transaction.ChargeLines.Add(charge);
                }

                // put charges on the transaction lines
                // Consider calculable lines only. Ignore voided or return-by-receipt lines.
                foreach (var salesLine in transaction.ChargeCalculableSalesLines)
                {
                    // get delivery mode information off the sales line
                    deliveryMode      = string.IsNullOrEmpty(salesLine.DeliveryMode) ? (transaction.DeliveryMode ?? string.Empty) : salesLine.DeliveryMode;
                    deliveryModeGroup = GetDeliveryModeGroupFromCode(request.RequestContext, deliveryMode);

                    var lineCharges = CalculateLineCharges(request.RequestContext, customerAccount, customerChargeGroup, deliveryMode, deliveryModeGroup, salesLine, transaction);

                    foreach (var charge in lineCharges)
                    {
                        salesLine.ChargeLines.Add(charge);
                    }
                }

                // now that all auto charges are on the transaction, calculate their amounts
                CalculateAutoChargeAmounts(request.RequestContext, transaction);

                // convert any charge amounts not in the channel currency
                var transactionAutoChargeLines = transaction.ChargeLines.Where(cl => cl.ChargeType == ChargeType.AutoCharge);

                // Consider calculable lines only. Ignore voided or return-by-receipt lines.
                var lineAutoChargeLines = transaction.ChargeCalculableSalesLines.SelectMany(sl => sl.ChargeLines).Where(cl => cl.ChargeType == ChargeType.AutoCharge);

                var allAutoChargeLines = transactionAutoChargeLines.Concat(lineAutoChargeLines);

                ChargeAmountsToStoreCurrency(request.RequestContext, allAutoChargeLines, currencyCode);
            }
Exemplo n.º 3
0
            internal static Customer GetCustomer(RequestContext context, string customerAccount)
            {
                Customer customer = null;

                if (!string.IsNullOrWhiteSpace(customerAccount))
                {
                    var getCustomerDataRequest = new GetCustomerDataRequest(customerAccount);
                    SingleEntityDataServiceResponse <Customer> getCustomerDataResponse = context.Execute <SingleEntityDataServiceResponse <Customer> >(getCustomerDataRequest);
                    customer = getCustomerDataResponse.Entity;
                }

                return(customer ?? (new Customer()));
            }
Exemplo n.º 4
0
            private static string GetCustomerPriceGroup(RequestContext context, string customerAccount)
            {
                string customerPriceGroup = string.Empty;

                if (!string.IsNullOrWhiteSpace(customerAccount))
                {
                    var getCustomerDataRequest = new GetCustomerDataRequest(customerAccount);
                    SingleEntityDataServiceResponse <Customer> getCustomerDataResponse = context.Execute <SingleEntityDataServiceResponse <Customer> >(getCustomerDataRequest);
                    Customer customer = getCustomerDataResponse.Entity;

                    if (customer != null)
                    {
                        if (!string.IsNullOrWhiteSpace(customer.PriceGroup))
                        {
                            customerPriceGroup = customer.PriceGroup;
                        }
                    }
                }

                return(customerPriceGroup);
            }
Exemplo n.º 5
0
            /// <summary>
            /// Factory method to construct the SalesTaxGroupPicker.
            /// </summary>
            /// <param name="channel">The current channel.</param>
            /// <param name="context">The request context.</param>
            /// <param name="address">The destination address object.</param>
            /// <param name="deliveryMode">The delivery mode used.</param>
            /// <param name="fulfillmentStoreId">The store that fulfills the purchase (pick up from).</param>
            /// <param name="shippingFromInventLocation">The invent location that item shipped from.</param>
            /// <param name="customerId">Customer account number.</param>
            /// <returns>
            /// The SalesTaxGroupPicker object.
            /// </returns>
            public static SalesTaxGroupPicker Create(Channel channel, RequestContext context, Address address, string deliveryMode, string fulfillmentStoreId, string shippingFromInventLocation, string customerId)
            {
                ThrowIf.Null(channel, "channel");
                ThrowIf.Null(context, "context");

                if (channel.OrgUnitType != RetailChannelType.RetailStore)
                {
                    return(CreatePickerForOnlineChannel(context, address, deliveryMode, fulfillmentStoreId, shippingFromInventLocation));
                }

                Customer customer = null;

                if (!string.IsNullOrWhiteSpace(customerId))
                {
                    var getCustomerDataRequest = new GetCustomerDataRequest(customerId);
                    SingleEntityDataServiceResponse <Customer> getCustomerDataResponse = context.Runtime.Execute <SingleEntityDataServiceResponse <Customer> >(getCustomerDataRequest, context);
                    customer = getCustomerDataResponse.Entity;
                }

                OrgUnit store = channel as OrgUnit;

                return(CreatePickerForStore(store, customer, context, address, deliveryMode, fulfillmentStoreId, shippingFromInventLocation));
            }
            /// <summary>
            /// Updates the tax overrides for cart.
            /// </summary>
            /// <param name="context">The context.</param>
            /// <param name="transaction">Transaction to calculate taxes for.</param>
            internal static void CalculateTaxOverrides(RequestContext context, SalesTransaction transaction)
            {
                // apply cart level
                if (!string.IsNullOrWhiteSpace(transaction.TaxOverrideCode))
                {
                    context.Execute <NullResponse>(new CheckAccessServiceRequest(RetailOperation.OverrideTaxTransactionList));

                    GetTaxOverrideDetailsDataRequest dataServiceRequest = new GetTaxOverrideDetailsDataRequest(transaction.TaxOverrideCode);
                    dataServiceRequest.QueryResultSettings = QueryResultSettings.AllRecords;
                    SingleEntityDataServiceResponse <TaxOverride> response = context.Runtime.Execute <SingleEntityDataServiceResponse <TaxOverride> >(dataServiceRequest, context);

                    ApplyTransactionLevelOverride(transaction, response.Entity);
                }

                // apply linelevel
                // note: it is not a meaningful business case to have both cart and line level overrides, but technically it is still possible
                // on the off chance, this happens, line's will override cart-inherited overrides
                if (transaction.SalesLines != null &&
                    transaction.SalesLines.Any())
                {
                    foreach (var line in transaction.SalesLines)
                    {
                        if (!string.IsNullOrWhiteSpace(line.TaxOverrideCode) &&
                            string.CompareOrdinal(line.TaxOverrideCode, transaction.TaxOverrideCode) != 0)
                        {
                            context.Execute <NullResponse>(new CheckAccessServiceRequest(RetailOperation.OverrideTaxLineList));

                            GetTaxOverrideDetailsDataRequest dataServiceRequest = new GetTaxOverrideDetailsDataRequest(line.TaxOverrideCode);
                            dataServiceRequest.QueryResultSettings = QueryResultSettings.AllRecords;
                            SingleEntityDataServiceResponse <TaxOverride> response = context.Runtime.Execute <SingleEntityDataServiceResponse <TaxOverride> >(dataServiceRequest, context);

                            ApplyLineLevelOverride(transaction, response.Entity, line.LineId);
                        }
                    }
                }
            }
Exemplo n.º 7
0
            public static SalesOrder GetSalesOrderFromInfo(CustomerOrderInfo orderInfo, ChannelConfiguration channelConfiguration, RequestContext context)
            {
                // Stores the local copy. There is high probability of having the same shipping/delivery address on all the lines.
                Dictionary <long, Address> shippingAddressDictionary = new Dictionary <long, Address>();

                decimal shippingChargeAmount;

                ColumnSet columnSet  = new ColumnSet();
                var       salesOrder = new SalesOrder
                {
                    SalesId              = orderInfo.Id,
                    TransactionType      = SalesTransactionType.CustomerOrder,
                    CustomerOrderMode    = CustomerOrderMode.OrderRecalled,
                    CartType             = CartType.CustomerOrder,
                    CustomerOrderType    = orderInfo.OrderType,
                    StoreId              = orderInfo.StoreId,
                    IsTaxIncludedInPrice = Convert.ToBoolean(orderInfo.IsTaxIncludedInPrice)
                };

                switch (orderInfo.OrderType)
                {
                case CustomerOrderType.Quote:
                    salesOrder.Status = Utilities.GetSalesStatus((SalesQuotationStatus)orderInfo.Status);
                    break;

                case CustomerOrderType.SalesOrder:
                    salesOrder.Status = Utilities.GetSalesStatus((SalesOrderStatus)orderInfo.Status, (DocumentStatus)orderInfo.DocumentStatus);
                    break;

                default:
                    salesOrder.Status = SalesStatus.Unknown;
                    break;
                }

                DateTimeOffset currentChannelDate = context.GetNowInChannelTimeZone();

                salesOrder.RequestedDeliveryDate = Utilities.ParseDateStringAsDateTimeOffset(orderInfo.RequestedDeliveryDateString, currentChannelDate.Date, currentChannelDate.Offset);
                salesOrder.QuotationExpiryDate   = Utilities.ParseDateStringAsDateTimeOffset(orderInfo.ExpiryDateString, currentChannelDate.Date, currentChannelDate.Offset);

                // CreationDate is stored in UTC. It needs to be converted to local time zone where order is accessed.
                salesOrder.BeginDateTime = Utilities.ParseDateString(orderInfo.CreationDateString, currentChannelDate.ToUniversalTime().DateTime, DateTimeStyles.AssumeUniversal);

                salesOrder.Comment = orderInfo.Comment;

                // Header delivery
                salesOrder.InventoryLocationId = orderInfo.WarehouseId;
                salesOrder.DeliveryMode        = orderInfo.DeliveryMode;

                foreach (var discountCode in orderInfo.DiscountCodes)
                {
                    salesOrder.DiscountCodes.Add(discountCode);
                }

                // Customer info
                salesOrder.CustomerId = orderInfo.CustomerAccount;
                long addressRecordIdLong = 0;

                if (long.TryParse(orderInfo.AddressRecordId, out addressRecordIdLong))
                {
                    var dataServiceRequest = new GetAddressDataRequest(addressRecordIdLong, columnSet);
                    SingleEntityDataServiceResponse <Address> dataServiceResponse = context.Execute <SingleEntityDataServiceResponse <Address> >(dataServiceRequest);

                    if (dataServiceResponse.Entity == null)
                    {
                        Utilities.DownloadCustomerData(context, salesOrder.CustomerId);
                        dataServiceResponse = context.Execute <SingleEntityDataServiceResponse <Address> >(dataServiceRequest);
                    }

                    if (dataServiceResponse.Entity != null)
                    {
                        salesOrder.ShippingAddress = dataServiceResponse.Entity;
                        shippingAddressDictionary.Add(salesOrder.ShippingAddress.RecordId, salesOrder.ShippingAddress);
                    }
                }

                if (!string.IsNullOrEmpty(orderInfo.SalespersonStaffId))
                {
                    // Sets the sales person id and name according to AX values
                    // This is done because we do not know whether the sales person information is available on this store
                    salesOrder.StaffId = orderInfo.SalespersonStaffId;
                }

                salesOrder.ChannelReferenceId = orderInfo.ChannelReferenceId;
                salesOrder.LoyaltyCardId      = orderInfo.LoyaltyCardId;

                salesOrder.ReceiptEmail = orderInfo.Email;

                string shippingChargeCode = channelConfiguration.ShippingChargeCode;

                // Items
                int lineId = 0;

                foreach (ItemInfo item in orderInfo.Items)
                {
                    lineId++;
                    var lineItem = new SalesLine
                    {
                        LineId                  = lineId.ToString(CultureInfo.InvariantCulture),
                        Found                   = true,
                        RecordId                = item.RecId,
                        ItemId                  = item.ItemId,
                        Comment                 = item.Comment,
                        Quantity                = item.Quantity,
                        ReturnQuantity          = item.Quantity,
                        SalesOrderUnitOfMeasure = item.Unit,
                        UnitOfMeasureSymbol     = item.Unit,
                        Price                   = item.Price,
                        NetAmount               = item.NetAmount,
                        QuantityOrdered         = item.Quantity,
                        QuantityInvoiced        = item.QuantityPicked,
                        DeliveryMode            = item.DeliveryMode,
                        RequestedDeliveryDate   = Utilities.ParseDateStringAsDateTimeOffset(item.RequestedDeliveryDateString, currentChannelDate.Date, currentChannelDate.Offset),
                        FulfillmentStoreId      = item.FulfillmentStoreId,
                        InventoryLocationId     = item.WarehouseId,
                        SerialNumber            = item.SerialId,
                        BatchId                 = item.BatchId,
                        Status                  = TransactionStatus.Normal,
                        SalesStatus             = Utilities.GetSalesStatus((SalesOrderStatus)item.Status)
                    };

                    // Copy charges to line and calculates total shipping charge amount
                    lineItem.ChargeLines.AddRange(SalesOrderHelper.CreateChargeLines(item.Charges, shippingChargeCode, salesOrder.BeginDateTime, out shippingChargeAmount));
                    lineItem.DeliveryModeChargeAmount = shippingChargeAmount;

                    // Line level discount amounts
                    lineItem.LineDiscount                 = item.LineDscAmount;
                    lineItem.PeriodicDiscount             = item.PeriodicDiscount;
                    lineItem.PeriodicPercentageDiscount   = item.PeriodicPercentageDiscount;
                    lineItem.LineManualDiscountAmount     = item.LineManualDiscountAmount;
                    lineItem.LineManualDiscountPercentage = item.LineManualDiscountPercentage;
                    lineItem.TotalDiscount                = item.TotalDiscount;
                    lineItem.TotalPercentageDiscount      = item.TotalPctDiscount;

                    // Copy discounts to line
                    lineItem.DiscountLines.AddRange(SalesOrderHelper.CreateDiscountLines(item.Discounts));

                    long itemAddressRecordIdLong;
                    if (long.TryParse(item.AddressRecordId, out itemAddressRecordIdLong))
                    {
                        Address lineLevelshippingAddress = new Address();

                        if (!shippingAddressDictionary.TryGetValue(itemAddressRecordIdLong, out lineLevelshippingAddress))
                        {
                            var dataServiceRequest = new GetAddressDataRequest(itemAddressRecordIdLong, columnSet);
                            SingleEntityDataServiceResponse <Address> dataServiceResponse = context.Execute <SingleEntityDataServiceResponse <Address> >(dataServiceRequest);

                            // If address not found download and get.
                            if (dataServiceResponse.Entity == null)
                            {
                                Utilities.DownloadCustomerData(context, salesOrder.CustomerId);
                                dataServiceResponse = context.Execute <SingleEntityDataServiceResponse <Address> >(dataServiceRequest);
                            }

                            if (dataServiceResponse.Entity != null)
                            {
                                lineItem.ShippingAddress = dataServiceResponse.Entity;
                                shippingAddressDictionary.Add(lineItem.ShippingAddress.RecordId, lineItem.ShippingAddress);
                            }
                        }
                        else
                        {
                            lineItem.ShippingAddress = lineLevelshippingAddress;
                        }
                    }

                    Utilities.SetUpVariantAndProduct(context, item.InventDimensionId, lineItem.ItemId, lineItem);

                    lineItem.DiscountAmount = item.Discount;

                    // Set tax info after defaults, as it may have been overridden.
                    lineItem.SalesTaxGroupId = item.SalesTaxGroup ?? string.Empty;
                    lineItem.ItemTaxGroupId  = item.ItemTaxGroup ?? string.Empty;

                    // Add it to the transaction
                    salesOrder.SalesLines.Add(lineItem);
                }

                // Charges for the header
                salesOrder.ChargeLines.AddRange(SalesOrderHelper.CreateChargeLines(orderInfo.Charges, shippingChargeCode, salesOrder.BeginDateTime, out shippingChargeAmount));
                salesOrder.DeliveryModeChargeAmount = shippingChargeAmount;

                // Payments
                // - total up amounts
                // - add history entries
                decimal nonPrepayments       = decimal.Zero;
                decimal prepaymentAmountPaid = decimal.Zero;

                int tenderLineId = 0;

                foreach (PaymentInfo payment in orderInfo.Payments)
                {
                    if (salesOrder.TenderLines == null)
                    {
                        salesOrder.TenderLines = new Collection <TenderLine>();
                    }

                    decimal amount = 0M;
                    if (string.IsNullOrWhiteSpace(payment.Currency) || payment.Currency.Equals(channelConfiguration.Currency, StringComparison.OrdinalIgnoreCase))
                    {
                        amount = payment.Amount;
                    }
                    else
                    {
                        GetCurrencyValueServiceRequest  currencyValueRequest  = new GetCurrencyValueServiceRequest(payment.Currency, channelConfiguration.Currency, payment.Amount);
                        GetCurrencyValueServiceResponse currencyValueResponse = context.Execute <GetCurrencyValueServiceResponse>(currencyValueRequest);
                        amount = currencyValueResponse.RoundedConvertedAmount;
                    }

                    if (payment.Prepayment)
                    {
                        // Sum prepayments to track total deposits paid
                        prepaymentAmountPaid += amount;
                    }
                    else
                    {
                        // Sum non-prepayments as base for calculating deposits applied to pickups
                        nonPrepayments += amount;
                    }

                    tenderLineId++;
                    var tenderLine = new TenderLine
                    {
                        TenderLineId = tenderLineId.ToString(CultureInfo.InvariantCulture),
                        Amount       = payment.Amount,
                        Currency     = payment.Currency,
                        CardTypeId   = string.Empty,
                        Status       = TenderLineStatus.Historical,
                        IsVoidable   = false,
                        TenderDate   =
                            Utilities.ParseDateString(
                                payment.DateString,
                                currentChannelDate.Date,
                                DateTimeStyles.None)         // On channel timezone
                    };

                    salesOrder.TenderLines.Add(tenderLine);
                }

                if (orderInfo.Affiliations != null && orderInfo.Affiliations.Any())
                {
                    salesOrder.AffiliationLoyaltyTierLines.Clear();
                    salesOrder.AffiliationLoyaltyTierLines.AddRange(orderInfo.Affiliations.Select(line =>
                                                                                                  new SalesAffiliationLoyaltyTier
                    {
                        AffiliationId   = line.AffiliationRecordId,
                        LoyaltyTierId   = line.LoyaltyTierRecordId,
                        AffiliationType = line.AffiliationType
                    }));
                }

                // Prepayment/Deposit override info
                if (orderInfo.PrepaymentAmountOverridden)
                {
                    salesOrder.OverriddenDepositAmount = prepaymentAmountPaid;
                }

                salesOrder.PrepaymentAmountPaid = prepaymentAmountPaid;

                // Portion of the prepayment that has been applied to invoices
                // (total amount invoiced less payments, difference is the deposit applied)
                salesOrder.PrepaymentAmountInvoiced = orderInfo.PreviouslyInvoicedAmount - nonPrepayments;

                // if the prepayment invoiced is greater than the total paid as deposit, there is no credit left
                salesOrder.AvailableDepositAmount = Math.Max(decimal.Zero, salesOrder.PrepaymentAmountPaid - salesOrder.PrepaymentAmountInvoiced);

                salesOrder.HasLoyaltyPayment = orderInfo.HasLoyaltyPayment;
                salesOrder.CurrencyCode      = orderInfo.CurrencyCode;

                return(salesOrder);
            }
            /// <summary>
            /// Make the transaction service call to email the receipt.
            /// </summary>
            /// <param name="salesOrder">The sales order.</param>
            private void SendReceiptMail(SalesOrder salesOrder)
            {
                List <ReceiptType> receiptTypes = new List <ReceiptType>();

                receiptTypes.Add(ReceiptType.SalesReceipt);

                var emailReceipt = new GetEmailReceiptServiceRequest(
                    salesOrder,
                    receiptTypes,
                    salesOrder.TenderLines,
                    false);

                var emailResponse = this.Context.Execute <GetEmailReceiptServiceResponse>(emailReceipt);

                if (emailResponse.Receipts == null || emailResponse.Receipts.Results.Count == 0)
                {
                    return;
                }

                string emailMessage = emailResponse.Receipts.Results[0].Header + emailResponse.Receipts.Results[0].Body + emailResponse.Receipts.Results[0].Footer;

                emailMessage = this.ConvertToHTML(emailMessage);

                string language = string.Empty;

                if (!string.IsNullOrEmpty(salesOrder.CustomerId))
                {
                    var getCustomerDataRequest = new GetCustomerDataRequest(salesOrder.CustomerId);
                    SingleEntityDataServiceResponse <Customer> getCustomerDataResponse = this.Context.Runtime.Execute <SingleEntityDataServiceResponse <Customer> >(getCustomerDataRequest, this.Context);
                    Customer customer = getCustomerDataResponse.Entity;

                    if (customer == null)
                    {
                        language = this.Context.GetChannelConfiguration().DefaultLanguageId;
                    }
                    else
                    {
                        language = customer.Language;
                    }
                }

                if (string.IsNullOrEmpty(language))
                {
                    language = CultureInfo.CurrentUICulture.ToString();
                }

                NameValuePair mapping = new NameValuePair
                {
                    Name  = this.receiptEmailTemplateParameter,
                    Value = emailMessage
                };

                Collection <NameValuePair> mappings = new Collection <NameValuePair>();

                mappings.Add(mapping);

                var emailServiceRequest = new SendEmailRealtimeRequest(
                    salesOrder.ReceiptEmail,
                    mappings,
                    language,
                    string.Empty,
                    this.receiptEmailTemplate);

                this.Context.Execute <NullResponse>(emailServiceRequest);
            }
            /// <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()));
            }