/// <summary>
        /// Handles the specified command.
        /// </summary>
        /// <param name="command">The command.</param>
        public async void Handle(AmazonGetProductCategories3dPartyCommand command)
        {
            InfoAccumulator info = new InfoAccumulator();

            IDictionary <string, IEnumerable <AmazonProductCategory> > categoriesPerSku = new Dictionary <string, IEnumerable <AmazonProductCategory> >();

            foreach (var sku in command.SellerSKUs.Distinct())
            {
                if (string.IsNullOrEmpty(sku))
                {
                    Log.Warn("got empty sku");
                    continue;
                }

                var categoriesRequest = new GetProductCategoriesForSKURequest {
                    SellerId      = command.SellerId,
                    SellerSKU     = sku,
                    MarketplaceId = command.MarketplaceId
                };

                GetProductCategoriesForSKUResponse response = await AmazonService.Products.GetProductCategoriesForSKU(categoriesRequest);

                IEnumerable <AmazonProductCategory> categories = Enumerable.Empty <AmazonProductCategory>();
                if (response.IsSetGetProductCategoriesForSKUResult())
                {
                    categories = CreateCategories(response.GetProductCategoriesForSKUResult.Self);
                }

                categoriesPerSku.Add(sku, categories);
            }

            SendReply(info, command, resp => resp.CategoriesBySku = categoriesPerSku);
        }
        /// <summary>
        /// Handles the specified command.
        /// </summary>
        /// <param name="command">The command.</param>
        public async void Handle(AmazonRegisterCustomerCommand command)
        {
            InfoAccumulator info = new InfoAccumulator();

            AmazonGetOrders3dPartyCommand request = new AmazonGetOrders3dPartyCommand {
                SellerId           = command.SellerId,
                AuthorizationToken = command.AuthorizationToken,
                MarketplaceId      = command.MarketplaceId,
                DateFrom           = DateTime.UtcNow.AddYears(-1) //TODO
            };

            var response = await GetOrdersSendReceive.SendAsync(Config.Address, request);

            int customerId;

            try {
                customerId = CustomerIdEncryptor.DecryptCustomerId(command.CustomerId, command.CommandOriginator);
            } catch (Exception ex) {
                Log.Error(ex.Message);
                info.AddError("Invalid request");
                SendReply(info, command, resp => resp.CustomerId = command.CustomerId);
                return;
            }


            int customerMarketPlaceId = 0; //TODO
            int marketPlaceHistoryId  = 0; //TODO

            AmazonOrder order = new AmazonOrder {
                Created = DateTime.UtcNow,
                CustomerMarketPlaceId = customerMarketPlaceId,
                CustomerMarketPlaceUpdatingHistoryRecordId = marketPlaceHistoryId
            };

            int orderId = (int)AmazonOrdersQueries.SaveOrder(order);

            if (orderId < 1)
            {
                throw new Exception("could not save amazon order");
            }

            bool res = AmazonOrdersQueries.SaveOrdersPayments(response.OrderPayments, orderId);

            if (!res)
            {
                throw new Exception("could not save order/order's payments");
            }

            //Get top N order items
            IEnumerable <AmazonOrderItem> items = AmazonOrdersQueries.GetTopNOrderItems(customerMarketPlaceId);

            //Get order details of top N items
            AmazonGetOrdersDetails3PartyCommand detailsRequestCommand = new AmazonGetOrdersDetails3PartyCommand {
                SellerId           = command.SellerId,
                AuthorizationToken = command.AuthorizationToken,
                OrdersIds          = items.Where(o => o.AmazonOrderId.HasValue)
                                     .Select(o => o.AmazonOrderId.ToString())
            };

            AmazonGetOrdersDetails3PartyCommandResponse detailsResponse = await GetOrderDetailsSendReceive.SendAsync(Config.Address, detailsRequestCommand);

            var skuCollection = detailsResponse.OrderDetailsByOrderId.Values
                                .SelectMany(o => o)
                                .Select(o => o.SellerSKU);

            //Get categories of top N order items
            var getProductCategoriesCommand = new AmazonGetProductCategories3dPartyCommand {
                SellerId           = command.SellerId,
                AuthorizationToken = command.AuthorizationToken,
                SellerSKUs         = skuCollection
            };

            var productCategoriesResponse = await GetProductCategoriesSendReceive.SendAsync(Config.Address, getProductCategoriesCommand);

            IDictionary <string, IList <AmazonOrderItemDetail> > orderIdToOrderDetails = detailsResponse.OrderDetailsByOrderId;
            //save order item details
            var insertedOrderDetails = AmazonOrdersQueries.OrderDetails.SaveOrderDetails(orderIdToOrderDetails.Values.SelectMany(o => o));


            IDictionary <string, IEnumerable <AmazonProductCategory> > skuToCategory = productCategoriesResponse.CategoriesBySku;
            //upserts categories
            IDictionary <AmazonProductCategory, int> categoryToId = AmazonOrdersQueries.Categories.UpsertCategories(productCategoriesResponse.CategoriesBySku.Values.SelectMany(o => o));

            res = AmazonOrdersQueries.Categories.SaveCategoryOrderDetailsMapping(CreateOrderIdToOrderDetailsIdMappings(insertedOrderDetails, skuToCategory, categoryToId));
            if (!res)
            {
                throw new Exception("could not save category order details mapping");
            }
        }