public OrderChangeViewModel(OrderChangeHistoryDTO change, IList <EmailOrderDTO> emails)
        {
            //Value = change.ToValue;
            ChangedBy     = change.ChangedBy;
            ChangedByName = change.ChangedByName;
            ChangeDate    = change.ChangeDate;

            if (change.FieldName == OrderHistoryHelper.OnHoldKey && change.ToValue == "True")
            {
                ChangeType = OrderChangeTypes.Hold;
            }
            if (change.FieldName == OrderHistoryHelper.OnHoldKey && change.ToValue == "False")
            {
                ChangeType = OrderChangeTypes.UnHold;
            }
            if (change.FieldName == OrderHistoryHelper.ShippingMethodKey)
            {
                ChangeType = OrderChangeTypes.ChangeShippingMethod;
                Message    = "";
                int shippingMethodId;
                if (!String.IsNullOrEmpty(change.FromValue) && change.FromValue != "0")
                {
                    var parts = change.FromValue.Split(';');
                    if (Int32.TryParse(parts[0], out shippingMethodId))
                    {
                        Message = ShippingUtils.GetPackageType(shippingMethodId).ToString() + " - " +
                                  ShippingUtils.GetShippingType(shippingMethodId).ToString();
                    }
                }
                else
                {
                    Message = "-";
                }
                Message += " -> ";
                if (!String.IsNullOrEmpty(change.ToValue) && change.ToValue != "0")
                {
                    var parts = change.ToValue.Split(';');
                    if (Int32.TryParse(parts[0], out shippingMethodId))
                    {
                        Message += ShippingUtils.GetPackageType(shippingMethodId).ToString() + " - " +
                                   ShippingUtils.GetShippingType(shippingMethodId).ToString();
                    }
                }
                else
                {
                    Message += "-";
                }
            }
            if (change.FieldName == OrderHistoryHelper.EmailStatusChangedKey)
            {
                var toValue = (EmailResponseStatusEnum)Enum.Parse(typeof(EmailResponseStatusEnum), change.ToValue);
                if (toValue == EmailResponseStatusEnum.NoResponseNeeded)
                {
                    var email = emails.FirstOrDefault(e => e.Id.ToString() == change.ExtendFromValue);
                    ChangeType = OrderChangeTypes.EmailStatusChanged;
                    Message    = "Set No Response Needed";
                    if (email != null)
                    {
                        Value    = email.Subject;
                        ValueUrl = UrlHelper.GetViewEmailUrl(email.Id, email.OrderIdString);
                    }
                }
            }

            if (change.FieldName == OrderHistoryHelper.RecalculateRatesKey)
            {
                ChangeType = OrderChangeTypes.RatesRecalculated;
            }
            if (change.FieldName == OrderHistoryHelper.ShipmentProviderTypeKey)
            {
                ChangeType = OrderChangeTypes.ChangeShippingProvider;
                Message    = ""; //TODO:
            }

            if (change.FieldName == OrderHistoryHelper.AddToBatchKey && change.ToValue != null)
            {
                ChangeType = OrderChangeTypes.AddToBatch;
                Message    = StringHelper.GetFirstNotEmpty(change.ExtendToValue, "Orders page");
            }
            if (change.FieldName == OrderHistoryHelper.AddToBatchKey && change.ToValue == null)
            {
                ChangeType = OrderChangeTypes.RemoveFromBatch;
                Message    = "Name:" + (change.ExtendToValue ?? "-");
            }
            if (change.FieldName == OrderHistoryHelper.DismissAddressWarnKey)
            {
                ChangeType = OrderChangeTypes.DismissAddressWarn;
            }
            if (change.FieldName == OrderHistoryHelper.StatusChangedKey)
            {
                ChangeType = OrderChangeTypes.StatusChanged;
                Message    = change.FromValue + " -> " + change.ToValue;
            }

            if (change.FieldName == OrderHistoryHelper.ManuallyPersonNameKey ||
                change.FieldName == OrderHistoryHelper.ManuallyShippingAddress1Key ||
                change.FieldName == OrderHistoryHelper.ManuallyShippingAddress2Key ||
                change.FieldName == OrderHistoryHelper.ManuallyShippingCityKey ||
                change.FieldName == OrderHistoryHelper.ManuallyShippingCountryKey ||
                change.FieldName == OrderHistoryHelper.ManuallyShippingPhoneKey ||
                change.FieldName == OrderHistoryHelper.ManuallyShippingZipKey ||
                change.FieldName == OrderHistoryHelper.ManuallyShippingZipAddonKey)
            {
                ChangeType = OrderChangeTypes.ChangeAddress;
                Message    = OrderHistoryHelper.PrepareFieldName(change.FieldName) + ": " + OrderHistoryHelper.PrepareFieldValue(change.FromValue) + " -> " + OrderHistoryHelper.PrepareFieldValue(change.ToValue);
            }
        }
        public static CallResult <IList <SelectListShippingOption> > Apply(IUnitOfWork db,
                                                                           ILogService log,
                                                                           ITime time,
                                                                           IWeightService weightService,
                                                                           long orderId,
                                                                           IList <IShipmentApi> ratePrividers,
                                                                           AddressDTO returnAddress,
                                                                           AddressDTO pickupAddress,
                                                                           IList <CustomShippingItemViewModel> customShippingItems,
                                                                           bool isFulfilmentUser)
        {
            var order = db.Orders.GetById(orderId);

            var correctedInitialShippingType = ShippingUtils.CorrectInitialShippingService(order.InitialServiceType, order.SourceShippingService, (OrderTypeEnum)order.OrderType);
            var shippingService = ShippingUtils.InitialShippingServiceIncludeUpgrade(correctedInitialShippingType, order.UpgradeLevel);

            var shippingProviderType = (ShipmentProviderType)db.Orders.GetById(orderId).ShipmentProviderType;
            var rateProvider         = ratePrividers.FirstOrDefault(p => p.Type == shippingProviderType);

            var oldShippings          = db.OrderShippingInfos.GetByOrderId(orderId).ToList();
            var previousNumberInBatch = oldShippings.FirstOrDefault(sh => sh.IsActive)?.NumberInBatch;

            var items = db.OrderItems.GetWithListingInfo()
                        .Where(oi => oi.OrderId == orderId)
                        .Select(oi => new ListingOrderDTO()
            {
                ItemOrderId       = oi.ItemOrderId,
                OrderItemEntityId = oi.OrderItemEntityId,
                Weight            = oi.Weight
            }).ToList();

            if (items.Any(i => !i.Weight.HasValue || i.Weight == 0))
            {
                return(CallResult <IList <SelectListShippingOption> > .Fail("No rates. Order has items w/o weight.", null));
            }

            var packageDict = new Dictionary <string, PackageInfo>();

            foreach (var shippingItem in customShippingItems.OrderBy(sh => sh.PackageValue).ToList())
            {
                var packageValue = shippingItem.PackageValue;

                var orderItem = items.FirstOrDefault(oi => oi.OrderItemEntityId == shippingItem.OrderItemId);
                var package   = packageDict.ContainsKey(packageValue) ? packageDict[packageValue] : null;
                if (package == null)
                {
                    var shippingMethodId = int.Parse(shippingItem.PackageValue.Split('-')[0]);
                    var dbShippingMethod = db.ShippingMethods.GetAll().FirstOrDefault(m => m.Id == shippingMethodId);

                    package = new PackageInfo
                    {
                        Items = new List <OrderItemRateInfo>(),
                        RequiredServiceIdentifier = dbShippingMethod.ServiceIdentifier,
                        ServiceTypeUniversal      = ShippingUtils.GetShippingType(shippingMethodId),
                        PackageTypeUniversal      = ShippingUtils.GetPackageType(shippingMethodId),
                        GroupId = RateHelper.CustomPartialGroupId,
                    };

                    packageDict[packageValue] = package;
                }

                package.Items.Add(new OrderItemRateInfo()
                {
                    Quantity    = 1,
                    ItemOrderId = orderItem.ItemOrderId,
                    Weight      = orderItem.Weight ?? 0,
                });
            }

            var packages = packageDict.Values;

            var addressTo = db.Orders.GetAddressInfo(order.Id);
            var shipDate  = db.Dates.GetOrderShippingDate(null);

            var rates = new List <RateDTO>();

            foreach (var package in packages)
            {
                package.Weight = weightService.AdjustWeight(package.Items.Sum(i => i.Weight * i.Quantity),
                                                            package.Items.Sum(i => i.Quantity));

                GetRateResult rateResult = null;
                log.Info("GetSpecificLocalRate, orderId=" + orderId);
                rateResult = rateProvider.GetAllRate(returnAddress,
                                                     pickupAddress,
                                                     addressTo,
                                                     shipDate,
                                                     package.Weight ?? 1,
                                                     package.GetDimension(),
                                                     order.IsInsured ? order.TotalPrice : 0,
                                                     order.IsSignConfirmation,
                                                     new OrderRateInfo()
                {
                    OrderNumber = order.AmazonIdentifier,

                    Items       = package.Items,
                    SourceItems = package.Items,

                    EstimatedShipDate = ShippingUtils.AlignMarketDateByEstDayEnd(order.LatestShipDate, (MarketType)order.Market),
                    ShippingService   = shippingService,
                    TotalPrice        = order.TotalPrice,
                    Currency          = order.TotalPriceCurrency,
                },
                                                     RetryModeType.Random);

                if (rateResult.Result != GetRateResultType.Success)
                {
                    return(CallResult <IList <SelectListShippingOption> > .Fail("Error when get rates for package, serviceType=" + package.ServiceTypeUniversal.ToString() + ", packageType=" + package.PackageTypeUniversal.ToString(), null));
                }

                var rate = rateResult.Rates.FirstOrDefault(r => r.ServiceIdentifier == package.RequiredServiceIdentifier);
                if (rate == null)
                {
                    return(CallResult <IList <SelectListShippingOption> > .Fail("Not rates for package, serviceType=" + package.ServiceTypeUniversal.ToString() + ", packageType=" + package.PackageTypeUniversal.ToString(), null));
                }

                rate.GroupId = RateHelper.CustomPartialGroupId;

                RateHelper.GroupPackageItems(package);
                rate.ItemOrderIds = package.Items.Select(i => new RateItemDTO()
                {
                    OrderItemId = i.ItemOrderId,
                    Quantity    = i.Quantity
                }).ToList();

                rates.AddRange(new List <RateDTO>()
                {
                    rate
                });
            }

            foreach (var rate in rates)
            {
                rate.IsDefault = true;
                rate.IsVisible = true;
                if (previousNumberInBatch.HasValue)
                {
                    rate.NumberInBatch    = previousNumberInBatch;
                    previousNumberInBatch = null;
                }
            }

            //save
            var newShippings       = new List <OrderShippingInfo>();
            var shippingMethodList = db.ShippingMethods.GetAllAsDto().ToList();
            var lastShippingNumber = oldShippings.Any() ? oldShippings.Max(sh => sh.ShippingNumber) ?? 0 : 0;
            var shippingNumber     = lastShippingNumber;

            foreach (var rate in rates)
            {
                log.Debug("store rate, service" + rate.ServiceTypeUniversal
                          + ", package=" + rate.PackageTypeUniversal
                          + ", cost=" + rate.Amount
                          + ", defualt=" + rate.IsDefault
                          + ", visible=" + rate.IsVisible
                          + ", groupId=" + rate.GroupId
                          + ", shipDate=" + rate.ShipDate
                          + ", deliveryDate=" + rate.DeliveryDate
                          + ", daysInfo=" + rate.DeliveryDaysInfo
                          + ", items=" + (rate.ItemOrderIds != null ? String.Join(", ", rate.ItemOrderIds.Select(i => (i.OrderItemId.ToString() + "-" + i.Quantity.ToString())).ToList()) : ""));
                var currentRate = rate;

                shippingNumber++;
                var method = shippingMethodList.FirstOrDefault(m => m.ServiceIdentifier == currentRate.ServiceIdentifier);
                if (method != null)
                {
                    currentRate.DeliveryDays = time.GetBizDaysCount(currentRate.ShipDate,
                                                                    currentRate.DeliveryDate);

                    var shippingInfo = db.OrderShippingInfos.CreateShippingInfo(currentRate,
                                                                                orderId,
                                                                                shippingNumber,
                                                                                method.Id);
                    newShippings.Add(shippingInfo);

                    if (currentRate.ItemOrderIds != null && currentRate.ItemOrderIds.Any())
                    {
                        log.Debug("store partial, items="
                                  +
                                  String.Join(", ",
                                              currentRate.ItemOrderIds.Select(
                                                  i => (i.OrderItemId.ToString() + "-" + i.Quantity.ToString())).ToList()));
                        db.ItemOrderMappings.StorePartialShippingItemMappings(shippingInfo.Id,
                                                                              currentRate.ItemOrderIds,
                                                                              items,
                                                                              time.GetAppNowTime());
                    }
                    else
                    {
                        db.ItemOrderMappings.StoreShippingItemMappings(shippingInfo.Id,
                                                                       items,
                                                                       time.GetAppNowTime());
                    }
                }
            }

            foreach (var oldShipping in oldShippings)
            {
                if (oldShipping.ShippingGroupId == RateHelper.CustomPartialGroupId)
                {
                    db.OrderShippingInfos.Remove(oldShipping);
                }
                else
                {
                    oldShipping.IsActive = false;
                }
            }

            order.ShippingCalculationStatus = (int)ShippingCalculationStatusEnum.FullCalculation;

            db.Commit();

            //Return actual values
            var allShippings = db.OrderShippingInfos.GetByOrderIdAsDto(orderId);
            var results      = OrderViewModel.GetShippingOptions(allShippings,
                                                                 (MarketType)order.Market,
                                                                 order.IsSignConfirmation,
                                                                 order.IsInsured,
                                                                 isFulfilmentUser,
                                                                 showOptionsPrices: true,
                                                                 showProviderName: false);

            return(CallResult <IList <SelectListShippingOption> > .Success(results));
        }