public async Task <ConfirmOrderLabelPurchaseValidationResult> Validate(string subject, ConfirmOrderLabelPurchaseCommand command)
        {
            if (string.IsNullOrWhiteSpace(subject))
            {
                throw new ArgumentException(nameof(subject));
            }

            if (command == null)
            {
                throw new ArgumentNullException(nameof(command));
            }

            var order = await _orderRepository.Get(command.OrderId);

            if (order == null) // Check order exists.
            {
                return(new ConfirmOrderLabelPurchaseValidationResult(ErrorDescriptions.TheOrderDoesntExist));
            }

            if (order.SellerId != subject) // Only the seller can purchase the label.
            {
                return(new ConfirmOrderLabelPurchaseValidationResult(ErrorDescriptions.TheOrderLabelCanBePurchasedOnlyBySeller));
            }

            if (order.Status != OrderAggregateStatus.Confirmed) // The order state should be confirmed.
            {
                return(new ConfirmOrderLabelPurchaseValidationResult(ErrorDescriptions.TheOrderIsNotConfirmed));
            }

            var payer = await _openidClient.GetPublicClaims(_settingsProvider.GetBaseOpenidUrl(), subject); // Retrieve the payer information.

            if (payer == null)
            {
                return(new ConfirmOrderLabelPurchaseValidationResult(ErrorDescriptions.ThePayerPaypalAccountNotExist));
            }

            var seller = await _openidClient.GetPublicClaims(_settingsProvider.GetBaseOpenidUrl(), order.SellerId); // Retrieve the seller information.

            if (seller == null)
            {
                return(new ConfirmOrderLabelPurchaseValidationResult(ErrorDescriptions.TheSellerPaypalAccountNotExist));
            }

            var paypalBuyer  = payer.Claims.FirstOrDefault(c => c.Type == "paypal_email");
            var paypalSeller = seller.Claims.FirstOrDefault(c => c.Type == "paypal_email");

            if (paypalBuyer == null || string.IsNullOrWhiteSpace(paypalBuyer.Value))
            {
                return(new ConfirmOrderLabelPurchaseValidationResult(ErrorDescriptions.ThePayerPaypalAccountNotExist));
            }

            if (paypalSeller == null || string.IsNullOrWhiteSpace(paypalSeller.Value))
            {
                return(new ConfirmOrderLabelPurchaseValidationResult(ErrorDescriptions.TheSellerPaypalAccountNotExist));
            }

            return(new ConfirmOrderLabelPurchaseValidationResult(order, payer, seller));
        }
        public async Task <PurchaseOrderLabelValidationResult> Validate(string subject, PurchaseOrderLabelCommand parameter)
        {
            if (string.IsNullOrWhiteSpace(subject))
            {
                throw new ArgumentException(nameof(subject));
            }

            if (parameter == null)
            {
                throw new ArgumentNullException(nameof(parameter));
            }

            if (parameter.ParcelSize == null)
            {
                throw new ArgumentNullException(nameof(parameter.ParcelSize));
            }

            var order = await _orderRepository.Get(parameter.OrderId);

            if (order == null) // Check order exists.
            {
                return(new PurchaseOrderLabelValidationResult(ErrorDescriptions.TheOrderDoesntExist));
            }

            if (parameter.ParcelSize.Height < 0 || parameter.ParcelSize.Length < 0 || parameter.ParcelSize.Weight < 0 || parameter.ParcelSize.Width < 0)
            {
                return(new PurchaseOrderLabelValidationResult(ErrorDescriptions.TheParcelSizeIsInvalid));
            }

            if (order.SellerId != subject) // Only the seller can purchase the label.
            {
                return(new PurchaseOrderLabelValidationResult(ErrorDescriptions.TheOrderLabelCanBePurchasedOnlyBySeller));
            }

            if (order.Status != OrderAggregateStatus.Confirmed) // The order state should be confirmed.
            {
                return(new PurchaseOrderLabelValidationResult(ErrorDescriptions.TheOrderIsNotConfirmed));
            }

            if (order.OrderPayment == null || order.OrderPayment.Status != OrderPaymentStatus.Approved) // The order payment should be approved by the buyer.
            {
                return(new PurchaseOrderLabelValidationResult(ErrorDescriptions.TheOrderPaymentHasNotBeenConfirmed));
            }

            double shippingPrice = 0;
            var    payer         = await _openidClient.GetPublicClaims(_settingsProvider.GetBaseOpenidUrl(), subject); // Get the payer information.

            if (payer == null)
            {
                return(new PurchaseOrderLabelValidationResult(ErrorDescriptions.ThePayerPaypalAccountNotExist));
            }

            var seller = await _openidClient.GetPublicClaims(_settingsProvider.GetBaseOpenidUrl(), order.SellerId); // Get the seller information.

            if (seller == null)
            {
                return(new PurchaseOrderLabelValidationResult(ErrorDescriptions.TheSellerPaypalAccountNotExist));
            }

            var paypalBuyer  = payer.Claims.FirstOrDefault(c => c.Type == "paypal_email");
            var paypalSeller = seller.Claims.FirstOrDefault(c => c.Type == "paypal_email");

            if (paypalBuyer == null || string.IsNullOrWhiteSpace(paypalBuyer.Value))
            {
                return(new PurchaseOrderLabelValidationResult(ErrorDescriptions.ThePayerPaypalAccountNotExist));
            }

            if (paypalSeller == null || string.IsNullOrWhiteSpace(paypalSeller.Value))
            {
                return(new PurchaseOrderLabelValidationResult(ErrorDescriptions.TheSellerPaypalAccountNotExist));
            }

            string trackingNumber = null;
            string shipmentDigest = null;

            if (order.OrderParcel.Transporter == Transporters.Ups) // Retrieve UPS ratings.
            {
                var buyerName   = payer.Claims.First(c => c.Type == SimpleIdentityServer.Core.Jwt.Constants.StandardResourceOwnerClaimNames.Name).Value;
                var sellerName  = seller.Claims.First(c => c.Type == SimpleIdentityServer.Core.Jwt.Constants.StandardResourceOwnerClaimNames.Name).Value;
                var confirmShip = await _upsClient.ConfirmShip(new ConfirmShipParameter // 1. Confirm UPS shippment.
                {
                    Credentials = new UpsCredentials
                    {
                        LicenseNumber = _settingsProvider.GetUpsLicenseNumber(),
                        Password      = _settingsProvider.GetUpsPassword(),
                        UserName      = _settingsProvider.GetUpsUsername()
                    },
                    AlternateDeliveryAddress = new UpsAlternateDeliveryAddressParameter
                    {
                        Name    = order.OrderParcel.ParcelShopName,
                        Address = new UpsAddressParameter
                        {
                            AddressLine = order.OrderParcel.ParcelShopAddressLine,
                            City        = order.OrderParcel.ParcelShopCity,
                            Country     = order.OrderParcel.ParcelShopCountryCode,
                            PostalCode  = order.OrderParcel.ParcelShopPostalCode.ToString()
                        }
                    },
                    Shipper = new UpsShipperParameter
                    {
                        Name    = buyerName,
                        Address = new UpsAddressParameter
                        {
                            AddressLine = order.OrderParcel.BuyerAddressLine,
                            City        = order.OrderParcel.BuyerCity,
                            Country     = order.OrderParcel.BuyerCountryCode,
                            PostalCode  = order.OrderParcel.BuyerPostalCode.ToString()
                        }
                    },
                    ShipFrom = new UpsShipParameter
                    {
                        Name          = buyerName,
                        AttentionName = buyerName,
                        CompanyName   = buyerName,
                        Address       = new UpsAddressParameter
                        {
                            AddressLine = order.OrderParcel.BuyerAddressLine,
                            City        = order.OrderParcel.BuyerCity,
                            Country     = order.OrderParcel.BuyerCountryCode,
                            PostalCode  = order.OrderParcel.BuyerPostalCode.ToString()
                        }
                    },
                    ShipTo = new UpsShipParameter
                    {
                        Name          = sellerName,
                        AttentionName = sellerName,
                        CompanyName   = sellerName,
                        Address       = new UpsAddressParameter
                        {
                            AddressLine = order.OrderParcel.SellerAddressLine,
                            City        = order.OrderParcel.SellerCity,
                            Country     = order.OrderParcel.SellerCountryCode,
                            PostalCode  = order.OrderParcel.SellerPostalCode.ToString()
                        }
                    },
                    Package = new UpsPackageParameter
                    {
                        Length = parameter.ParcelSize.Length,
                        Height = parameter.ParcelSize.Height,
                        Weight = parameter.ParcelSize.Weight,
                        Width  = parameter.ParcelSize.Width
                    },
                    EmailAddress = "*****@*****.**",
                    UpsService   = CommonBuilder.MappingBothUpsServices.First(kvp => kvp.Key == order.OrderParcel.UpsServiceCode).Value
                });

                if (confirmShip.Response.ResponseStatusCode == "0")
                {
                    return(new PurchaseOrderLabelValidationResult(confirmShip.Response.Error.ErrorDescription));
                }

                /*
                 * var acceptUpsShipment = await _upsClient.AcceptShip(new AcceptShipParameter // 2. Accept UPS shipment.
                 * {
                 *  Credentials = new UpsCredentials
                 *  {
                 *      LicenseNumber = _settingsProvider.GetUpsLicenseNumber(),
                 *      Password = _settingsProvider.GetUpsPassword(),
                 *      UserName = _settingsProvider.GetUpsUsername()
                 *  },
                 *  ShipmentDigest = confirmShip.ShipmentDigest
                 * });
                 *
                 * if (acceptUpsShipment.Response.ResponseStatusCode == "0")
                 * {
                 *  return new PurchaseOrderLabelValidationResult(acceptUpsShipment.Response.Error.ErrorDescription);
                 * }
                 */


                shipmentDigest = confirmShip.ShipmentDigest;
                shippingPrice  = confirmShip.ShipmentCharges.TotalCharges.MonetaryValue;
            }

            return(new PurchaseOrderLabelValidationResult(order, paypalBuyer.Value, paypalSeller.Value, shippingPrice, shipmentDigest));
        }
        public async Task <UpdateOrderValidationResult> Validate(UpdateOrderCommand order, string subject)
        {
            if (order == null)
            {
                throw new ArgumentNullException(nameof(order));
            }

            if (string.IsNullOrWhiteSpace(subject))
            {
                throw new ArgumentNullException(nameof(subject));
            }

            var record = await _orderRepository.Get(order.Id);

            if (record == null)
            {
                return(new UpdateOrderValidationResult(ErrorDescriptions.TheOrderDoesntExist));
            }

            if (record.Status == OrderAggregateStatus.Received) // Cannot update received order.
            {
                return(new UpdateOrderValidationResult(ErrorDescriptions.TheReceivedOrderCannotBeUpdated));
            }

            if (record.Status != OrderAggregateStatus.Created && record.Status == order.Status) // Confirmed & received order cannot be updated.
            {
                return(new UpdateOrderValidationResult(string.Format(ErrorDescriptions.TheOrderCannotBeUpdatedBecauseOfItsState, Enum.GetName(typeof(OrderAggregateStatus), order.Status))));
            }

            if (record.Status != order.Status)
            {
                if (record.Status == OrderAggregateStatus.Created && order.Status != OrderAggregateStatus.Confirmed) // created => confirmed.
                {
                    return(new UpdateOrderValidationResult(string.Format(ErrorDescriptions.TheOrderStateCannotBeUpdated, Enum.GetName(typeof(OrderAggregateStatus), record.Status), Enum.GetName(typeof(OrderAggregateStatus), order))));
                }

                if (record.Status == OrderAggregateStatus.Confirmed && order.Status != OrderAggregateStatus.Received) // confirmed => received
                {
                    return(new UpdateOrderValidationResult(string.Format(ErrorDescriptions.TheOrderStateCannotBeUpdated, Enum.GetName(typeof(OrderAggregateStatus), record.Status), Enum.GetName(typeof(OrderAggregateStatus), order))));
                }
            }

            if (order.TransportMode == OrderTransportModes.Manual && order.Status == OrderAggregateStatus.Received && record.Subject != subject)  // Only the creator can confirm the order.
            {
                return(new UpdateOrderValidationResult(ErrorDescriptions.TheOrderReceptionCanBeConfirmedOnlyByItsCreator));
            }

            IEnumerable <ProductAggregate> prods = null;

            if (order.OrderLines != null && order.OrderLines.Any()) // Check the lines.
            {
                var productIds = order.OrderLines.Select(o => o.ProductId);
                var products   = await _productRepository.Search(new SearchProductsParameter { ProductIds = productIds });

                if (products.Content.Count() != productIds.Count())
                {
                    return(new UpdateOrderValidationResult(ErrorDescriptions.TheOrderLineProductIsInvalid));
                }

                if (order.OrderLines.Any(o => o.Quantity <= 0))
                {
                    return(new UpdateOrderValidationResult(ErrorDescriptions.TheOrderLineQuantityIsInvalid));
                }

                foreach (var orderLine in order.OrderLines)
                {
                    var product = products.Content.First(p => p.Id == orderLine.ProductId);
                    if (orderLine.Quantity > product.AvailableInStock && product.AvailableInStock.HasValue)
                    {
                        return(new UpdateOrderValidationResult(ErrorDescriptions.TheOrderLineQuantityIsTooMuch));
                    }
                }

                prods = products.Content;
                var discountCodes = order.OrderLines.Select(o => o.DiscountCode).Where(dc => !string.IsNullOrEmpty(dc));
                if (discountCodes.Any()) // Check discounts.
                {
                    var discounts = await _discountRepository.Search(new SearchDiscountsParameter
                    {
                        IsPagingEnabled = false,
                        DiscountCodes   = discountCodes
                    });

                    if (discounts.Content == null || !discounts.Content.Any() || discounts.Content.Count() != discountCodes.Count())
                    {
                        return(new UpdateOrderValidationResult(ErrorDescriptions.TheDiscountCodesAreNotValid));
                    }

                    foreach (var orderLine in order.OrderLines)
                    {
                        if (string.IsNullOrWhiteSpace(orderLine.DiscountCode))
                        {
                            continue;
                        }

                        var discount = discounts.Content.First(c => c.Code == orderLine.DiscountCode);
                        if (discount.Products == null || !discount.Products.Any(p => p.ProductId == orderLine.ProductId)) // Check discount is valid for the product.
                        {
                            return(new UpdateOrderValidationResult(string.Format(ErrorDescriptions.TheDiscountCannotBeUsedForThisProduct, orderLine.ProductId)));
                        }

                        if (!discount.IsValid()) // Check discount is valid.
                        {
                            return(new UpdateOrderValidationResult(string.Format(ErrorDescriptions.TheProductDiscountIsInvalid, orderLine.DiscountCode)));
                        }

                        orderLine.DiscountId = discount.Id;
                    }
                }
            }

            double shippingPrice = 0;
            string payerEmail    = string.Empty;
            string sellerEmail   = string.Empty;

            if (order.Status == OrderAggregateStatus.Confirmed && order.TransportMode == OrderTransportModes.Packet)
            {
                if (order.OrderParcel == null)
                {
                    return(new UpdateOrderValidationResult(ErrorDescriptions.TheParcelDoesntExist));
                }

                var payer = await _openidClient.GetPublicClaims(_settingsProvider.GetBaseOpenidUrl(), subject);

                if (payer == null)
                {
                    return(new UpdateOrderValidationResult(ErrorDescriptions.ThePayerPaypalAccountNotExist));
                }

                var seller = await _openidClient.GetPublicClaims(_settingsProvider.GetBaseOpenidUrl(), record.SellerId);

                if (seller == null)
                {
                    return(new UpdateOrderValidationResult(ErrorDescriptions.TheSellerPaypalAccountNotExist));
                }

                var paypalBuyer  = payer.Claims.FirstOrDefault(c => c.Type == "paypal_email");
                var paypalSeller = seller.Claims.FirstOrDefault(c => c.Type == "paypal_email");
                if (paypalBuyer == null || string.IsNullOrWhiteSpace(paypalBuyer.Value))
                {
                    return(new UpdateOrderValidationResult(ErrorDescriptions.ThePayerPaypalAccountNotExist));
                }

                if (paypalSeller == null || string.IsNullOrWhiteSpace(paypalSeller.Value))
                {
                    return(new UpdateOrderValidationResult(ErrorDescriptions.TheSellerPaypalAccountNotExist));
                }

                if (order.OrderParcel.Transporter == Transporters.Dhl)
                {
                    return(new UpdateOrderValidationResult(ErrorDescriptions.TheTransporterDhlIsNotSupported));
                }

                if (order.OrderParcel.Transporter == Transporters.Ups)
                {
                    var buyerName  = payer.Claims.First(c => c.Type == SimpleIdentityServer.Core.Jwt.Constants.StandardResourceOwnerClaimNames.Name).Value;
                    var sellerName = seller.Claims.First(c => c.Type == SimpleIdentityServer.Core.Jwt.Constants.StandardResourceOwnerClaimNames.Name).Value;
                    var parameter  = new GetUpsRatingsParameter
                    {
                        Credentials = new UpsCredentials
                        {
                            LicenseNumber = _settingsProvider.GetUpsLicenseNumber(),
                            Password      = _settingsProvider.GetUpsPassword(),
                            UserName      = _settingsProvider.GetUpsUsername()
                        },
                        Shipper = new UpsShipperParameter
                        {
                            Name    = buyerName,
                            Address = new UpsAddressParameter
                            {
                                AddressLine = order.OrderParcel.BuyerAddressLine,
                                City        = order.OrderParcel.BuyerCity,
                                Country     = order.OrderParcel.BuyerCountryCode,
                                PostalCode  = order.OrderParcel.BuyerPostalCode.ToString()
                            }
                        },
                        ShipFrom = new UpsShipParameter
                        {
                            Name          = buyerName,
                            AttentionName = buyerName,
                            CompanyName   = buyerName,
                            Address       = new UpsAddressParameter
                            {
                                AddressLine = order.OrderParcel.BuyerAddressLine,
                                City        = order.OrderParcel.BuyerCity,
                                Country     = order.OrderParcel.BuyerCountryCode,
                                PostalCode  = order.OrderParcel.BuyerPostalCode.ToString()
                            }
                        },
                        ShipTo = new UpsShipParameter
                        {
                            Name          = sellerName,
                            AttentionName = sellerName,
                            CompanyName   = sellerName,
                            Address       = new UpsAddressParameter
                            {
                                AddressLine = order.OrderParcel.SellerAddressLine,
                                City        = order.OrderParcel.SellerCity,
                                Country     = order.OrderParcel.SellerCountryCode,
                                PostalCode  = order.OrderParcel.SellerPostalCode.ToString()
                            }
                        },
                        Package = new UpsPackageParameter
                        {
                            Height = Constants.PackageInfo.Height,
                            Length = Constants.PackageInfo.Length,
                            Weight = Constants.PackageInfo.Weight,
                            Width  = Constants.PackageInfo.Width
                        },
                        AlternateDeliveryAddress = new UpsAlternateDeliveryAddressParameter
                        {
                            Name    = order.OrderParcel.ParcelShopName,
                            Address = new UpsAddressParameter
                            {
                                AddressLine = order.OrderParcel.ParcelShopAddressLine,
                                City        = order.OrderParcel.ParcelShopCity,
                                Country     = order.OrderParcel.ParcelShopCountryCode,
                                PostalCode  = order.OrderParcel.ParcelShopPostalCode.ToString()
                            }
                        },
                        UpsService = CommonBuilder.MappingBothUpsServices.First(kvp => kvp.Key == order.OrderParcel.UpsServiceCode).Value
                    };
                    var ratingsResponse = await _upsClient.GetRatings(parameter);

                    if (ratingsResponse.Response.Error != null)
                    {
                        return(new UpdateOrderValidationResult(ratingsResponse.Response.Error.ErrorDescription));
                    }

                    shippingPrice = ratingsResponse.RatedShipment.TotalCharges.MonetaryValue;
                    payerEmail    = paypalBuyer.Value;
                    sellerEmail   = paypalSeller.Value;
                }
            }

            return(new UpdateOrderValidationResult(record, prods, payerEmail, sellerEmail, shippingPrice));
        }