예제 #1
0
        public void UpgradeOrders()
        {
            List <long> orderToUpgradeIdList      = null;
            List <long> orderToResetUpgradeIdList = null;

            using (var db = _dbFactory.GetRWDb())
            {
                var orders      = db.Orders.GetAll().Where(o => o.OrderStatus == OrderStatusEnumEx.Unshipped).ToList();
                var orderIdList = orders
                                  .Where(o => !ShippingUtils.IsInternational(o.ShippingCountry) &&
                                         o.SourceShippingService == ShippingUtils.StandardServiceName)
                                  .Select(o => o.Id)
                                  .ToList();
                var shippings = db.OrderShippingInfos.GetAll().Where(sh => orderIdList.Contains(sh.OrderId) &&
                                                                     sh.IsActive &&
                                                                     sh.AvgDeliveryDays >= 1.99M).ToList();

                orderToUpgradeIdList = shippings.Select(sh => sh.OrderId).Distinct().ToList();

                var orderItems = db.OrderItemSources.GetAll().Where(oi => orderToUpgradeIdList.Contains(oi.OrderId)).ToList();
                orderToUpgradeIdList = orderToUpgradeIdList
                                       .Where(o => orderItems.Where(oi => oi.OrderId == o).Sum(oi => oi.ItemPrice) > 10)
                                       .ToList();

                var ordersToUpgrade = orders.Where(o => orderToUpgradeIdList.Contains(o.Id)).ToList();
                _log.Info(String.Join(", ", ordersToUpgrade.Select(o => o.AmazonIdentifier).ToList()));
                var zipList = ordersToUpgrade.Select(o => o.ShippingZip).ToList();
                _log.Info(String.Join(", ", zipList));
            }

            UpgradeOrderList(orderToUpgradeIdList);
        }
        public static IList <MessageString> ValidateQuickReturnLabel(IUnitOfWork db,
                                                                     string orderNumber)
        {
            var messages = new List <MessageString>();
            var order    = db.Orders.GetAll().FirstOrDefault(o => o.AmazonIdentifier == orderNumber);

            if (ShippingUtils.IsInternational(order.ShippingCountry))
            {
                messages.Add(MessageString.Warning("The International return label cannot be generated automatically"));
            }
            var existReturnLabel = db.MailLabelInfos.GetAllAsDto()
                                   .Where(m => m.OrderId == order.Id &&
                                          m.MailReasonId == (int)MailLabelReasonCodes.ReturnLabelReasonCode).ToList();

            if (existReturnLabel.Any())
            {
                messages.Add(MessageString.Warning("Order already has return label"));
            }
            return(messages);
        }
        public CheckResult Check(DTOMarketOrder order)
        {
            CheckResult result = new CheckResult()
            {
                IsSuccess = false
            };

            var serviceType = order.InitialServiceType;

            if ((ShippingUtils.IsServiceTwoDays(serviceType) ||
                 ShippingUtils.IsServiceNextDay(serviceType)) &&
                ShippingUtils.IsInternational(order.ShippingCountry))
            {
                return(new CheckResult()
                {
                    IsSuccess = true
                });
            }

            return(result);
        }
예제 #4
0
        public CheckResult Check(IUnitOfWork db,
                                 DTOOrder order,
                                 IList <ListingOrderDTO> orderItems)
        {
            var min = 1.99M;

            if (ShippingUtils.IsInternational(order.FinalShippingCountry) ||
                order.InitialServiceType != ShippingUtils.StandardServiceName ||
                orderItems.Sum(i => i.ItemPrice) <= 10)
            {
                return(new CheckResult()
                {
                    IsSuccess = false
                });
            }

            var avgDeliveryDays = GetAvgDeliveryInfo(db, order);

            if (avgDeliveryDays != null &&
                avgDeliveryDays.AverageFirstClassDeliveryDays.HasValue &&
                avgDeliveryDays.AverageFirstClassDeliveryDays.Value >= min)
            {
                _log.Info("Zip=" + avgDeliveryDays.Zip + ", Avg FC Days=" + avgDeliveryDays.AverageFirstClassDeliveryDays + ", min=" + min);

                order.UpgradeLevel = 1;
                return(new CheckResult()
                {
                    IsSuccess = true
                });
            }

            return(new CheckResult()
            {
                IsSuccess = false
            });
        }
        public AddressDTO ComposeAddressDto()
        {
            var address = new AddressDTO();

            //NOTE: Original address dosn't came after submit

            address.FullName         = ManuallyPersonName;
            address.ManuallyAddress1 = ManuallyShippingAddress1;
            address.ManuallyAddress2 = ManuallyShippingAddress2;
            address.ManuallyCity     = ManuallyShippingCity;
            address.ManuallyCountry  = ManuallyShippingCountry;

            address.ManuallyState = !ShippingUtils.IsInternational(address.ManuallyCountry) // == "US"
                ? ManuallyShippingUSState
                : ManuallyShippingState;

            address.ManuallyZip      = ManuallyShippingZip;
            address.ManuallyZipAddon = ManuallyShippingZipAddon;
            address.ManuallyPhone    = ManuallyShippingPhone;

            address.IsManuallyUpdated = true;

            return(address);
        }
예제 #6
0
        public CheckResult Check(IUnitOfWork db,
                                 long orderId,
                                 IList <ListingOrderDTO> orderItems,
                                 IList <OrderShippingInfoDTO> shippings,
                                 DTOMarketOrder marketOrder)
        {
            if (!orderItems.Any() || !shippings.Any())
            {
                return new CheckResult()
                       {
                           IsSuccess = false
                       }
            }
            ;

            if (marketOrder.UpgradeLevel > 0)
            {
                return new CheckResult()
                       {
                           IsSuccess = false
                       }
            }
            ;

            if (marketOrder.Market == (int)MarketType.Groupon)
            {
                return new CheckResult()
                       {
                           IsSuccess = false
                       }
            }
            ;

            CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US");

            culture.NumberFormat.CurrencyNegativePattern = 1;

            decimal paidShppingCost = orderItems.Sum(i => i.ShippingPrice);
            string  currency        = orderItems.First().ShippingPriceCurrency;

            paidShppingCost = PriceHelper.RougeConvertToUSD(currency, paidShppingCost);
            if (marketOrder.OrderType == (int)OrderTypeEnum.Prime)
            {
                paidShppingCost += orderItems.Sum(oi => AmazonPrimeHelper.GetShippingAmount(oi.Weight));
            }

            decimal?actualShippingsCost = null;

            if (shippings != null && shippings.Any(sh => sh.IsActive))
            {
                actualShippingsCost = shippings.Where(sh => sh.IsActive &&
                                                      sh.ShippingMethodId != ShippingUtils.FedexSmartPost).Sum(sh => sh.StampsShippingCost ?? 0);
            }

            _log.Info("CheckIsExceededShippingCost: paid=" + paidShppingCost + " < actual=" + actualShippingsCost);


            if (shippings != null)
            {
                //"Excessive shipping cost. Because priority flat went up I get lots of “excesive” in cases like. We need to ignore those cases…"
                var activeShipping = shippings.FirstOrDefault(sh => sh.IsActive);
                if (activeShipping != null &&
                    activeShipping.ShippingMethod != null &&
                    activeShipping.ShippingMethod.Id == ShippingUtils.PriorityFlatShippingMethodId)
                {
                    return new CheckResult()
                           {
                               IsSuccess = false
                           }
                }
                ;
            }

            #region New Checking
            //price/1.17-shipping price-product cost-2 > -exc

            if (actualShippingsCost != null)
            {
                decimal totalThreashold = 0;
                decimal totalCost       = 0;
                bool    allHaveCost     = true;
                foreach (var item in orderItems)
                {
                    decimal?styleThreashold = null;

                    if (item.StyleId.HasValue)
                    {
                        var featureValue = db.StyleFeatureTextValues.GetFeatureValueByStyleIdByFeatureId(
                            item.StyleId.Value, StyleFeatureHelper.EXCESSIVE_SHIPMENT);
                        if (featureValue != null && !String.IsNullOrEmpty(featureValue.Value))
                        {
                            styleThreashold = StringHelper.TryGetDecimal(featureValue.Value);
                        }
                        var cost = db.StyleItemCaches.GetAllAsDto().Select(i => new { i.Id, i.Cost }).FirstOrDefault(i => i.Id == item.StyleItemId)?.Cost;
                        if (cost.HasValue)
                        {
                            totalCost += cost.Value * item.QuantityOrdered;
                        }
                        else
                        {
                            allHaveCost = false;
                        }
                    }
                    if (styleThreashold.HasValue)
                    {
                        totalThreashold += styleThreashold.Value * item.QuantityOrdered;
                    }
                }

                if (allHaveCost)
                {
                    var totalPaid = PriceHelper.RougeConvertToUSD(currency, orderItems.Sum(i => i.ShippingPrice + i.ItemPrice));

                    //Please ignore income disparity<1 like 180-111-825-1659 / 381-205-041-7263
                    if (totalThreashold < 1)
                    {
                        totalThreashold = 1;
                    }

                    var isValid = totalPaid / 1.17M - actualShippingsCost - totalCost - 2 > -totalThreashold;
                    if (!isValid)
                    {
                        var excpectIncome = totalPaid / 1.17M - actualShippingsCost.Value - totalCost - 2;

                        _log.Info(String.Format("Added Income disparity, income: {0}, totalPaid: {1}, actualShippingCost: {2}, totalCost: {3}",
                                                excpectIncome.ToString("C", culture),
                                                totalPaid,
                                                actualShippingsCost,
                                                totalCost));

                        var message = String.Format("Income disparity, income: {0}",
                                                    excpectIncome.ToString("C", culture));

                        db.OrderComments.Add(new OrderComment()
                        {
                            OrderId    = orderId,
                            Message    = message,
                            Type       = (int)CommentType.System,
                            CreateDate = _time.GetAppNowTime(),
                        });
                        db.Commit();

                        return(new CheckResult()
                        {
                            IsSuccess = true
                        });
                    }
                }
            }

            #endregion

            #region Old Checking
            //TASK: When order has 2 robes, and they sent as 2 First class (like 102-1792536-3635439) don’t show Excess ship. cost
            if (shippings.Where(sh => sh.IsActive).All(sh => sh.ShippingMethodId == ShippingUtils.AmazonFirstClassShippingMethodId ||
                                                       sh.ShippingMethodId == ShippingUtils.FirstClassShippingMethodId ||
                                                       sh.ShippingMethodId == ShippingUtils.DhlEComSMParcelGroundShippingMethodId ||
                                                       sh.ShippingMethodId == ShippingUtils.DhlEComSMParcelExpeditedShippingMethodId))
            {
                if (orderItems.All(
                        i => ItemStyleHelper.GetFromItemStyleOrTitle(i.ItemStyle, i.Title) == ItemStyleType.Robe))
                {
                    return(new CheckResult()
                    {
                        IsSuccess = false
                    });
                }
            }

            //NOTE: used default threashold: $1
            //NOTE: if price disparity <$2 it's ok
            var threshold = 2.0M;

            //TASK: When order has 2 or more items and service "Standard" made threashold $2
            if (orderItems.Sum(oi => oi.QuantityOrdered) >= 2 &&
                ShippingUtils.IsServiceStandard(marketOrder.InitialServiceType))
            {
                threshold = 2.5M;
            }

            var withEmptyThreashold    = 0;
            var withNotEmptyThreashold = 0;
            foreach (var item in orderItems)
            {
                decimal?styleThreashold = null;
                if (item.StyleId.HasValue)
                {
                    var featureValue = db.StyleFeatureTextValues.GetFeatureValueByStyleIdByFeatureId(
                        item.StyleId.Value, StyleFeatureHelper.EXCESSIVE_SHIPMENT);
                    if (featureValue != null && !String.IsNullOrEmpty(featureValue.Value))
                    {
                        styleThreashold = StringHelper.TryGetDecimal(featureValue.Value);
                    }
                }
                if (styleThreashold.HasValue)
                {
                    threshold += styleThreashold.Value * item.QuantityOrdered;
                    withNotEmptyThreashold++;
                }
                else
                {
                    withEmptyThreashold++;
                }
            }
            //if (withEmptyThreashold > 0)
            //    threshold += 1.0M;

            //if (withNotEmptyThreashold == 0)
            //    threshold = 1.0M;

            if (actualShippingsCost > 0 && paidShppingCost > 0 && paidShppingCost + threshold < actualShippingsCost)
            {
                bool    isOverchargeSkipped        = false;
                decimal totalIntlListingPriceInUSD = 0M;
                decimal totalUsListingPrice        = 0;
                if (ShippingUtils.IsInternational(marketOrder.FinalShippingCountry))
                {
                    #region Calc US Shipping Cost
                    decimal?actualUsShippingCost = 0M;

                    var shippingService = ShippingUtils.StandardServiceName; //ShippingUtils.InitialShippingServiceIncludeUpgrade(marketOrder.InitialServiceType.Replace("i:", ""), //convert to local
                    //marketOrder.UpgradeLevel);
                    decimal?paidUsShippingCost = ShippingUtils.GetRougePaidUSShippingAmount(shippingService, orderItems.Sum(i => i.QuantityOrdered));

                    var usRates = RateHelper.GetRougeChipestUSRate(_log,
                                                                   _stampsRateProvider,
                                                                   _fromAddress,
                                                                   marketOrder,
                                                                   shippingService,
                                                                   orderItems,
                                                                   orderItems);

                    if (usRates.Any())
                    {
                        actualUsShippingCost = usRates.Sum(r => r.Amount);
                    }
                    #endregion

                    foreach (var orderItem in orderItems)
                    {
                        totalIntlListingPriceInUSD += PriceHelper.RougeConvertToUSD(orderItem.ItemPriceCurrency, orderItem.ItemPrice);
                        var usListingPrice = GetUSListingPrice(db, orderItem);
                        if (usListingPrice == null)
                        {
                            totalUsListingPrice = 0;
                            break;
                        }
                        totalUsListingPrice += (usListingPrice * orderItem.QuantityOrdered) ?? 0;
                    }

                    decimal?usEarnedValue      = ((totalUsListingPrice) + (paidUsShippingCost ?? 0) - (actualUsShippingCost ?? 0));
                    decimal?marketEarnedValue  = (totalIntlListingPriceInUSD + paidShppingCost - actualShippingsCost.Value);
                    decimal?howMachEarnedValue = null;
                    if (actualUsShippingCost.HasValue &&
                        paidUsShippingCost.HasValue &&
                        totalUsListingPrice > 0 &&
                        actualShippingsCost.HasValue)
                    {
                        howMachEarnedValue = (totalIntlListingPriceInUSD + paidShppingCost - actualShippingsCost.Value) -
                                                                                                                            //how much we have earned now
                                             (totalUsListingPrice + paidUsShippingCost.Value - actualUsShippingCost.Value); //how much we have earned if we sell it in US

                        isOverchargeSkipped = howMachEarnedValue > -threshold;                                              //NOTE: Threashold
                    }

                    if (!isOverchargeSkipped)
                    {
                        //var message = internationalOverchargeSkip ? "No Excessive Shipping cost" : "Excessive Shipping cost";
                        var message = "";
                        if (totalUsListingPrice > 0)
                        {
                            message = String.Format("Income disparity: {0}+{1}-{2}={3} vs {4} => income diff.: {5}",
                                                    //MarketHelper.GetShortName((int)marketOrder.Market, marketOrder.MarketplaceId),
                                                    (totalUsListingPrice).ToString("C", culture),
                                                    (paidUsShippingCost ?? 0).ToString("C", culture),
                                                    (actualUsShippingCost ?? 0).ToString("C", culture),
                                                    usEarnedValue?.ToString("C", culture),
                                                    marketEarnedValue?.ToString("C", culture),
                                                    (howMachEarnedValue ?? 0).ToString("C", culture));
                        }
                        else
                        {
                            isOverchargeSkipped = true; //SKIP
                            message             = "Excessive Shipping validation: no similar US listing";
                        }

                        db.OrderComments.Add(new OrderComment()
                        {
                            OrderId    = orderId,
                            Message    = message,
                            Type       = (int)CommentType.System,
                            CreateDate = _time.GetAppNowTime(),
                        });
                        db.Commit();
                    }
                }
                else
                {
                    //сделай пока $3.02 threashold
                    var localThreshold = Math.Max(threshold, 3.02M);
                    if (paidShppingCost + localThreshold < actualShippingsCost)
                    {
                        var message = String.Format("Paid shipping ({0}) lower shipping cost ({1}) more than threshold ({2})",
                                                    (paidShppingCost).ToString("C", culture),
                                                    (actualShippingsCost ?? 0).ToString("C", culture),
                                                    (localThreshold).ToString("C", culture));
                        db.OrderComments.Add(new OrderComment()
                        {
                            OrderId    = orderId,
                            Message    = message,
                            Type       = (int)CommentType.System,
                            CreateDate = _time.GetAppNowTime(),
                        });
                    }
                    else
                    {
                        //NOTE: Temp Do Nothing
                        isOverchargeSkipped = true;
                    }
                }

                if (!isOverchargeSkipped)
                {
                    db.OrderNotifies.Add(
                        ComposeNotify(orderId,
                                      (int)OrderNotifyType.OverchargedShpppingCost,
                                      1,
                                      paidShppingCost + "<" + actualShippingsCost,
                                      _time.GetAppNowTime()));
                    db.Commit();
                }

                if (!isOverchargeSkipped)
                {
                    foreach (var orderItem in orderItems)
                    {
                        if (orderItem.SourceListingId.HasValue)
                        {
                            var listing = db.Listings.Get(orderItem.SourceListingId.Value);
                            if (listing != null)
                            {
                                SystemActionHelper.RequestPriceRecalculation(db, _actionService, listing.Id, null);
                                if (listing.Market == (int)MarketType.Walmart) //NOTE: need to update Second Day flag
                                {
                                    SystemActionHelper.RequestItemUpdate(db, _actionService, listing.Id, null);
                                }
                            }
                        }
                    }
                }

                return(new CheckResult()
                {
                    IsSuccess = !isOverchargeSkipped
                });
            }
            #endregion

            return(new CheckResult()
            {
                IsSuccess = false
            });
        }
예제 #7
0
        public bool IsAccept(OrderToTrackDTO orderToTrackInfo,
                             string status,
                             DateTime?statusDate,
                             IList <TrackingRecord> records)
        {
            /*TASK: When tracking history contains “Undeliverable as Addressed” like order 114-8804539-8077829
             * When it’s being scanned back in Hallandale (after that),and if there is no Notes in account after the day it was scanned as undeliverable, send client an email:
             * “Dear %Name%,
             * Your order of %List Of pajamas% being returned to us by USPS because the address you have provided for this order is undeliverable.
             * Please review full tracking history of this order at %link to USPS with tracking number%.
             * Please let us know how would you like us to proceed with your order once we get it back.
             *
             * Best Regards,
             * Customer Service”
             *
             * Please also add a note to the account: Order being returned, emailed customer.
             */

            var today = _time.GetAppNowTime().Date;

            //NOTE: processing only fresh records
            if (statusDate.HasValue &&
                statusDate.Value < today.AddDays(-10))
            {
                _log.Info("Skip old status, pass more than 10 days");
                return(false);
            }

            if (orderToTrackInfo.Carrier == ShippingServiceUtils.USPSCarrier)
            {
                //TASK: When tracking history contains “Undeliverable as Addressed”
                var undeliverableAsAddressStatus = records.FirstOrDefault(s =>
                                                                          String.Compare(s.Message, "Undeliverable as Addressed", StringComparison.OrdinalIgnoreCase) == 0 ||
                                                                          (s.Message ?? "").IndexOf("Addressee not available", StringComparison.OrdinalIgnoreCase) >= 0);
                if (undeliverableAsAddressStatus != null)
                {
                    //TASK: sent only to US and CA, for other country we always do refund
                    if (ShippingUtils.IsInternational(orderToTrackInfo.ShippingAddress.FinalCountry) &&
                        orderToTrackInfo.ShippingAddress.FinalCountry != "CA")
                    {
                        return(false);
                    }

                    _log.Info("Found \"Undeliverable As Addressed\"");
                    var scanInHallandale = records.FirstOrDefault(r => r.Date > undeliverableAsAddressStatus.Date &&
                                                                  _addressService.IsMine(r.AsAddressDto()));
                    if (scanInHallandale != null)
                    {
                        _log.Info("Being scanned back");
                        //When it’s being scanned back in Hallandale (after that),and if there is no Notes in account after the day it was scanned as undeliverable, send client an email

                        //NOTE: disable check and send message at same day when scanned back
                        //if (scanInHallandale.Date.HasValue && _time.GetBizDaysCount(scanInHallandale.Date.Value, today) > 1)
                        //{
                        //    if (!records.Any(r => r.Date >= scanInHallandale.Date.Value
                        //                          && !_addressService.IsMine(r.AsAddressDto())))
                        //    {
                        //        _log.Info("no Notes in account after the day it was scanned. Send email.");

                        //        return true;
                        //    }
                        //    else
                        //    {
                        //        _log.Info("Found extra notes after package was scanned back");
                        //    }
                        //}

                        return(true);
                    }
                }
            }

            return(false);
        }
예제 #8
0
        public void GetIntlRatesTest(string orderId, ShipmentProviderType type)
        {
            using (var db = _dbFactory.GetRWDb())
            {
                var order = db.ItemOrderMappings.GetOrderWithItems(_weightService, orderId, unmaskReferenceStyle: false, includeSourceItems: true);

                var shippingService       = ShippingUtils.InitialShippingServiceIncludeUpgrade(order.InitialServiceType, order.UpgradeLevel); //order.ShippingService
                var orderItemInfoes       = OrderHelper.BuildAndGroupOrderItems(order.Items);
                var sourceOrderItemInfoes = OrderHelper.BuildAndGroupOrderItems(order.SourceItems);

                var providers = GetShipmentProviders(_company);
                var provider  = providers.FirstOrDefault(p => p.Type == type);

                var companyAddress = new CompanyAddressService(_company);

                if (ShippingUtils.IsInternational(order.ShippingCountry))
                {
                    var rates = provider.GetInternationalRates(
                        companyAddress.GetReturnAddress(order.GetMarketId()),
                        companyAddress.GetPickupAddress(order.GetMarketId()),
                        order.GetAddressDto(),
                        _time.GetAppNowTime(),
                        order.WeightD,
                        null,
                        order.IsInsured ? order.TotalPrice : 0,
                        order.IsSignConfirmation,
                        new OrderRateInfo()
                    {
                        ShippingService = shippingService,
                        OrderNumber     = order.OrderId,
                        Items           = orderItemInfoes,
                        SourceItems     = sourceOrderItemInfoes,
                        TotalPrice      = order.TotalPrice,
                        Currency        = order.TotalPriceCurrency,
                    },
                        RetryModeType.Normal);

                    Console.WriteLine(rates.Rates.Count);
                }
                else
                {
                    var rates = provider.GetLocalRate(
                        companyAddress.GetReturnAddress(order.GetMarketId()),
                        companyAddress.GetPickupAddress(order.GetMarketId()),
                        order.GetAddressDto(),
                        _time.GetAppNowTime(),
                        order.WeightD,
                        null,
                        order.IsInsured ? order.TotalPrice : 0,
                        order.IsSignConfirmation,
                        new OrderRateInfo()
                    {
                        ShippingService    = shippingService,
                        InitialServiceType = order.InitialServiceType,
                        OrderNumber        = order.OrderId,
                        Items       = orderItemInfoes,
                        SourceItems = sourceOrderItemInfoes,
                        TotalPrice  = order.TotalPrice,
                        Currency    = order.TotalPriceCurrency,
                    },
                        RetryModeType.Normal);

                    Console.WriteLine(rates.Rates.Count);
                }
            }
        }
예제 #9
0
        public void FillIBCRateTable()
        {
            using (var db = _dbFactory.GetRWDb())
            {
                var newRateTable = new List <RateByCountryDTO>();
                var addressList  = new List <AddressDTO>()
                {
                    //RateHelper.GetSampleUSAddress(),
                    RateHelper.GetSampleCAAddress(),
                    RateHelper.GetSampleUKAddress()
                };

                var serviceFactory = new ServiceFactory();

                var rateProviders = serviceFactory.GetShipmentProviders(_log,
                                                                        _time,
                                                                        _dbFactory,
                                                                        _weightService,
                                                                        _company.ShipmentProviderInfoList,
                                                                        null,
                                                                        null,
                                                                        null,
                                                                        null);

                var stampsRateProvider = rateProviders.FirstOrDefault(r => r.Type == ShipmentProviderType.IBC);
                var companyAddress     = new CompanyAddressService(_company);

                var shippingSizes = new string[] { //"S",
                    "XL"
                };
                var internationalPackages = new string[] { "", "" };

                for (var oz = 1; oz < 50; oz++)
                {
                    //International Package Type: Regular, Flat
                    //Shipping Size: S, XL

                    foreach (var address in addressList)
                    {
                        foreach (var shippingSize in shippingSizes)
                        {
                            var packageType = shippingSize == "XL" ?
                                              PackageTypeCode.Regular :
                                              (ShippingUtils.IsInternational(address.Country) ? PackageTypeCode.LargeEnvelopeOrFlat : PackageTypeCode.Flat);

                            var shippintType = ShippingUtils.IsInternational(address.Country)
                                ? ShippingTypeCode.IStandard
                                : ShippingTypeCode.Standard;

                            var rate = RateHelper.GetRougeChipestRate(_log,
                                                                      stampsRateProvider,
                                                                      companyAddress.GetReturnAddress(MarketIdentifier.Empty()),
                                                                      address,
                                                                      oz,
                                                                      DateTime.Today,
                                                                      shippintType,
                                                                      packageType);

                            if (rate != null && rate.Amount.HasValue)
                            {
                                _log.Info("Add rate: " + address.Country + ", " + oz + "oz, " + shippingSize + ", " + rate.Amount.Value + ", package=" + ((PackageTypeCode)rate.PackageTypeUniversal).ToString() + ", shippingType=" + ((ShippingTypeCode)rate.ServiceTypeUniversal).ToString());
                                newRateTable.Add(new RateByCountryDTO()
                                {
                                    Cost             = rate.Amount.Value,
                                    Country          = address.Country,
                                    Weight           = oz,
                                    PackageType      = packageType.ToString(), //NOTE: need to use source package type, no matter what actual package is ((PackageTypeCode) rate.PackageTypeUniversal).ToString(),
                                    ShipmentProvider = stampsRateProvider.Type.ToString(),
                                    UpdateDate       = _time.GetAppNowTime()
                                });
                            }
                            else
                            {
                                _log.Info("No rates: " + oz + "oz, " + shippingSize);
                            }
                        }
                    }
                }

                var existRates = db.RateByCountries.GetAll();
                foreach (var rate in newRateTable)
                {
                    var exist = existRates.FirstOrDefault(r => r.Country == rate.Country &&
                                                          r.PackageType == rate.PackageType &&
                                                          r.Weight == rate.Weight);
                    if (exist == null)
                    {
                        db.RateByCountries.Add(new RateByCountry()
                        {
                            Country          = rate.Country,
                            PackageType      = rate.PackageType,
                            Cost             = rate.Cost,
                            Weight           = rate.Weight,
                            ShipmentProvider = rate.ShipmentProvider,
                            UpdateDate       = rate.UpdateDate,
                        });
                    }
                    else
                    {
                        exist.Cost             = rate.Cost;
                        exist.ShipmentProvider = rate.ShipmentProvider;
                    }
                }
                db.Commit();
            }
        }
예제 #10
0
        public CheckResult Check(IUnitOfWork db,
                                 DTOMarketOrder order,
                                 IList <ListingOrderDTO> items,
                                 AddressValidationStatus addressValidationStatus)
        {
            if (order.Id == 0)
            {
                throw new ArgumentOutOfRangeException("order.Id", "Should be non zero");
            }

            if (order.OrderStatus == OrderStatusEnumEx.Pending)
            {
                throw new ArgumentException("order.OrderStatus", "Not supported status Pending");
            }

            //International order has issue with PersonName
            if (ShippingUtils.IsInternational(order.FinalShippingCountry))
            {
                if (String.IsNullOrEmpty(order.FinalShippingPhone))
                {
                    var emailInfo = new PhoneMissingEmailInfo(_emailService.AddressService,
                                                              null,
                                                              order.OrderId,
                                                              (MarketType)order.Market,
                                                              items,
                                                              order.BuyerName,
                                                              order.BuyerEmail);

                    _emailService.SendEmail(emailInfo, CallSource.Service);
                    _log.Info("Send phone missing email, orderId=" + order.Id);

                    db.OrderEmailNotifies.Add(new OrderEmailNotify()
                    {
                        OrderNumber = order.OrderId,
                        Reason      = "System emailed, missing phone number",
                        Type        = (int)OrderEmailNotifyType.OutputPhoneMissingEmail,
                        CreateDate  = _time.GetUtcTime(),
                    });

                    db.OrderComments.Add(new OrderComment()
                    {
                        OrderId    = order.Id,
                        Message    = "[System] Missing phone email sent",
                        Type       = (int)CommentType.Address,
                        CreateDate = _time.GetAppNowTime(),
                        UpdateDate = _time.GetAppNowTime()
                    });

                    db.Commit();

                    return(new CheckResult()
                    {
                        IsSuccess = false
                    });
                }
            }

            return(new CheckResult()
            {
                IsSuccess = true
            });
        }
예제 #11
0
        public virtual ActionResult ReCalcShippingService(long batchId,
                                                          string orderIds,
                                                          int?switchToProviderId,
                                                          int?switchToMethodId)
        {
            LogI("ReCalcShippingService begin, orderIds=" + orderIds);

            IList <string> failedUpdate  = new List <string>();
            IList <string> successUpdate = new List <string>();

            if (!string.IsNullOrEmpty(orderIds))
            {
                var stringOrderIdList = orderIds.Split(", ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                var orderIdList       = stringOrderIdList.Select(long.Parse).ToArray();
                var rateProviders     = ServiceFactory.GetShipmentProviders(LogService,
                                                                            Time,
                                                                            DbFactory,
                                                                            WeightService,
                                                                            AccessManager.Company.ShipmentProviderInfoList,
                                                                            null,
                                                                            null,
                                                                            null,
                                                                            null);

                var syncInfo = new EmptySyncInformer(LogService, SyncType.Orders);

                IList <DTOOrder> dtoOrders = Db.ItemOrderMappings.GetSelectedOrdersWithItems(WeightService, orderIdList, includeSourceItems: true).ToList();
                foreach (var dtoOrder in dtoOrders)
                {
                    //Ignore shipped orders
                    if ((dtoOrder.Market != (int)MarketType.eBay && ShippingUtils.IsOrderShipped(dtoOrder.OrderStatus)) ||
                        dtoOrder.ShippingInfos.Any(s => !String.IsNullOrEmpty(s.LabelPath)))
                    {
                        failedUpdate.Add(dtoOrder.OrderId);
                        continue;
                    }

                    if (switchToProviderId.HasValue &&
                        dtoOrder.ShipmentProviderType != switchToProviderId.Value)
                    {
                        var skipChanges = false;
                        if (switchToProviderId == (int)ShipmentProviderType.FedexOneRate)
                        {
                            if (ShippingUtils.IsInternational(dtoOrder.FinalShippingCountry))
                            {
                                skipChanges = true;
                            }
                        }

                        if (!skipChanges)
                        {
                            var dbOrder = Db.Orders.Get(dtoOrder.Id);
                            dbOrder.ShipmentProviderType = switchToProviderId.Value;
                            Db.Commit();
                            dtoOrder.ShipmentProviderType = switchToProviderId.Value;
                        }
                    }

                    var synchronizer = new AmazonOrdersSynchronizer(LogService,
                                                                    AccessManager.Company,
                                                                    syncInfo,
                                                                    rateProviders,
                                                                    CompanyAddress,
                                                                    Time,
                                                                    WeightService,
                                                                    MessageService);

                    if (synchronizer.UIUpdate(Db, dtoOrder, false, false, keepCustomShipping: false, switchToMethodId: switchToMethodId))
                    {
                        successUpdate.Add(dtoOrder.OrderId);
                    }
                    else
                    {
                        failedUpdate.Add(dtoOrder.OrderId);
                    }
                }
            }
            LogI("ReCalcShippingService result, failedUpdate=" + String.Join(", ", failedUpdate)
                 + ", successUpdate=" + String.Join(", ", successUpdate));

            return(new JsonResult
            {
                Data = ValueResult <IList <string> > .Success("", new List <string>() { String.Join(", ", failedUpdate), String.Join(", ", successUpdate) }),
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            });
        }
        public CheckResult <AddressDTO> CheckAddress(CallSource callSource, AddressDTO inputAddress)
        {
            var additionalData = new List <string>()
            {
                OrderNotifyType.AddressCheckMelissa.ToString()
            };

            if (ShippingUtils.IsInternational(inputAddress.FinalCountry))
            {
                return(new CheckResult <AddressDTO>()
                {
                    IsSuccess = false,
                    AdditionalData = additionalData
                });
            }

            //The Check action will validate the individual input data pieces for validity and correct them if possible.
            //If the data is correctable, additional information will often be appended as well. US and Canada only.
            //Set the Server URL to the form input
            var url = "https://personator.melissadata.net/v3/WEB/ContactVerify/doContactVerify";

            url += "?t=";                //TransmissionReference
            url += "&id=" + _customerId; // "114035921";
            url += "&act=Check";
            //-Plus4
            //Returns the 4-digit plus4 for the input address. If this column is requested, the PostalCode field will
            //only contain the 5-digit ZIP for U.S. addresses.
            //-PrivateMailBox
            //Returns the private mail box number for the address in the AddressLine field, if any. Private mailboxes
            //are private mail boxes in commercial mail receiving agencies, like a UPS Store. If requested, the Private
            //mailbox will be populated in this field instead of the Address field.
            //-Suite
            //Returns the suite for the address in the AddressLine field, if any. If requested, the suite will be
            //populated in this field instead of the Address field.
            url += "&cols=Plus4"; //Columns "Plus4,PrivateMailBox,Suite";
            url += "&opt=";       //Options
            url += "&first=";
            url += "&last=";
            url += "&full=" + HttpUtility.UrlEncode(inputAddress.FinalFullName);
            url += "&comp=";
            url += "&a1=" + HttpUtility.UrlEncode(inputAddress.FinalAddress1);
            url += "&a2=" + HttpUtility.UrlEncode(inputAddress.FinalAddress2);
            url += "&city=" + HttpUtility.UrlEncode(inputAddress.FinalCity);
            url += "&state=" + HttpUtility.UrlEncode(inputAddress.FinalState);
            url += "&postal=" + HttpUtility.UrlEncode(inputAddress.FinalZip
                                                      + (!String.IsNullOrEmpty(inputAddress.FinalZipAddon) ? "-" + inputAddress.FinalZipAddon : ""));
            url += "&ctry=" + HttpUtility.UrlEncode(inputAddress.FinalCountry);
            url += "&lastlines=";
            url += "&freeform=";
            url += "&email=";
            url += "&phone=" + HttpUtility.UrlEncode(inputAddress.FinalPhone);
            url += "&reserved=";

            //url = url.Replace("#", "%23");
            var uri = new Uri(url);

            CheckResult <AddressDTO> result = null;

            try
            {
                var request = (HttpWebRequest)WebRequest.Create(uri);
                using (var response = request.GetResponse() as HttpWebResponse)
                {
                    using (var responseStream = response.GetResponseStream())
                    {
                        var doc = new XmlDocument();
                        doc.Load(responseStream);

                        result = ProcessResult(doc);
                        result.AdditionalData = additionalData;
                    }
                }
            }
            catch (Exception ex)
            {
                result = new CheckResult <AddressDTO>()
                {
                    IsSuccess      = false,
                    Message        = ex.Message,
                    AdditionalData = additionalData
                };
            }

            if (result.Data != null)
            {
                var outputAddress = result.Data;
                if (!String.IsNullOrEmpty(outputAddress.AddressKey))
                {
                    if (inputAddress.Address1 == outputAddress.Address1 &&
                        inputAddress.Address2 == outputAddress.Address2 &&
                        inputAddress.City == outputAddress.City &&
                        inputAddress.Country == outputAddress.Country &&
                        inputAddress.State == outputAddress.State &&
                        inputAddress.Zip == outputAddress.Zip &&
                        inputAddress.ZipAddon == outputAddress.ZipAddon)
                    {
                        result.Data = null;
                    }
                }
                else
                {
                    result.Data = null;
                }
            }

            return(result);
        }
예제 #13
0
        public void Process(IUnitOfWork db, EmailReadingResult result)
        {
            if (result.Status != EmailMatchingResultStatus.New ||
                !result.HasMatches)
            {
                return;
            }

            var subject       = result.Email.Subject ?? "";
            var returnRequest = subject.StartsWith("Return authorization request for order") ||
                                subject.StartsWith("Return authorisation request for order") ||
                                subject.StartsWith("Return authorisation notification for order") ||
                                subject.StartsWith("Return authorization notification for order");

            if (returnRequest)
            {
                result.WasEmailProcessed = true; //NOTE: skipped comment added to other Rules
                _log.Info("ReturnRequsetEmailRule, WasEmailProcessed=" + result.WasEmailProcessed);

                var orderNumber = result.MatchedIdList.FirstOrDefault();
                _log.Info("Received Return authorization request, orderNumber=" + orderNumber);

                if (_existanceCheck)
                {
                    var existReturn = db.ReturnRequests.GetAll().FirstOrDefault(r => r.OrderNumber == orderNumber);
                    if (existReturn != null)
                    {
                        //Already exist
                        return;
                    }
                }

                var order          = db.Orders.GetByOrderNumber(orderNumber);
                var orderItems     = db.Listings.GetOrderItems(order.Id);
                var orderShippings = db.OrderShippingInfos.GetByOrderIdAsDto(order.Id).Where(sh => sh.IsActive).ToList();

                //Return codes: https://sellercentral.amazon.com/gp/help/help-page.html/ref=ag_200453320_cont_scsearch?ie=UTF8&itemID=200453320&language=en_CA

                /*Order ID: # 112-4884600-1049826
                 * Item: Toy Story Woody Buzz Boys 4 pc Cotton Pajamas Set (6)
                 * Quantity: 1
                 * Return reason: Too small
                 * Customer comments: I need 5T or 6T sizes. (Optional)
                 * Details: ... (Optional)
                 * Request received: February 27, 2016*/

                /*
                 * Order ID: # 114-8683360-8244230
                 *  Item: Shopkins Girls' Little Girls' Luxe Plush 2-Piece Pajama Snuggle Set, Pink, 6
                 *  Quantity: 1
                 *  Return reason: Too small
                 *
                 *  Item: Shopkins Girls' Little Girls' 2-Piece Fleece Pajama Set, Pink, 6
                 *  Quantity: 1
                 *  Return reason: Too small
                 */

                var messages = result.Email.Message.Split(new string[] { "<br />", "<br>", "<br/>", "/r/n" },
                                                          StringSplitOptions.RemoveEmptyEntries);

//                var regex = new Regex(@"Order ID: # (?<OrderId>.*)
//                    ([\s\S]+)Item: (?<ItemName>.*)
//                    ([\s\S]+)Quantity: (?<Quantity>.*)
//                    ([\s\S]+)Return reason: (?<Reason>.*)
//                    ([\s\S]+)Request received: (?<Date>.*)");

//                var match = regex.Match(message);
//                string receiveDate = match.Groups["Date"].Value;
//                string orderId = match.Groups["OrderId"].Value;
//                string itemName = match.Groups["ItemName"].Value;
//                string quantity = match.Groups["Quantity"].Value;
//                string reasonText = match.Groups["Reason"].Value;

                var returns = new List <ReturnRequestDTO>();

                ReturnRequestDTO currentReturn = null;

                foreach (var message in messages)
                {
                    if (message.StartsWith("Item: "))
                    {
                        currentReturn = new ReturnRequestDTO();
                        returns.Add(currentReturn);
                        currentReturn.ItemName = message.Replace("Item: ", "");
                    }

                    if (currentReturn != null)
                    {
                        if (message.StartsWith("Return reason: "))
                        {
                            currentReturn.Reason = StringHelper.Substring(message.Replace("Return reason: ", ""), 255);
                        }
                        if (message.StartsWith("Quantity: "))
                        {
                            currentReturn.Quantity = StringHelper.TryGetInt(message.Replace("Quantity: ", ""));
                        }

                        if (message.StartsWith("Request received:"))
                        {
                            currentReturn.ReceiveDate =
                                DateHelper.FromDateString(message.Replace("Request received: ", ""));
                        }
                        if (message.StartsWith("Customer comments:"))
                        {
                            currentReturn.CustomerComments =
                                StringHelper.Substring(message.Replace("Customer comments: ", ""), 255);
                        }
                        if (message.StartsWith("Details:"))
                        {
                            currentReturn.Details = StringHelper.Substring(message.Replace("Details: ", ""), 255);
                        }
                    }
                }

                //var reason = ReasonCode.None;

                //ListingOrderDTO itemToCheck = null;
                //var itemsToExchange = new List<StyleItemCache>();

                foreach (var ret in returns)
                {
                    var itemToCheck = orderItems.FirstOrDefault(i => i.Title == ret.ItemName);
                    //If not found check all items
                    if (itemToCheck == null && orderItems.Count == 1)
                    {
                        itemToCheck = orderItems.FirstOrDefault();
                    }
                    _log.Info("Item to check=" + (itemToCheck != null ? itemToCheck.SKU : "[null}"));

                    if (itemToCheck != null)
                    {
                        ret.StyleId     = itemToCheck.StyleId;
                        ret.StyleItemId = itemToCheck.StyleItemId;
                        ret.SKU         = itemToCheck.SKU;
                        ret.StyleString = itemToCheck.StyleID;
                    }
                }

                foreach (var ret in returns)
                {
                    var requestDb = new ReturnRequest()
                    {
                        ItemName         = StringHelper.Substring(ret.ItemName, 255),
                        OrderNumber      = orderNumber,
                        Quantity         = ret.Quantity,
                        Reason           = ret.Reason,
                        CustomerComments = StringHelper.Substring(ret.CustomerComments, 255),
                        Details          = StringHelper.Substring(ret.Details, 255),
                        ReceiveDate      = ret.ReceiveDate,
                        CreateDate       = _time.GetAppNowTime(),

                        StyleId     = ret.StyleId,
                        StyleItemId = ret.StyleItemId,
                        SKU         = ret.SKU,
                    };

                    db.ReturnRequests.Add(requestDb);
                    db.Commit();
                }

                _log.Info("Request saved into DB");

                if (!_enableSendEmail)
                {
                    //Skip logic with composing comment / email message
                    return;
                }

                if (ShippingUtils.IsInternational(order.ShippingCountry))
                {
                    //Don't offer exchange to international order
                    return;
                }

                var comments = new List <string>();
                foreach (var request in returns)
                {
                    var reason          = GetReasonCode(request.Reason);
                    var itemsToExchange = GetItemsToExchange(db, request);
                    if (reason == ReasonCode.TooSmall || reason == ReasonCode.TooLarge)
                    {
                        var itemsToExchangeWithQty = itemsToExchange.Where(i => i.RemainingQuantity > 0).ToList();

                        //TASK: Don’t send those emails to orders which can’t be returned already, because more than 30 days passed like order 105-5461372-1374643.
                        //TASK: orders, which were placed  Nov 1-Jan 31, can be returned/exchanged by January 31
                        var returnRequestToLate = false;
                        if (order.OrderDate.HasValue)
                        {
                            returnRequestToLate = OrderHelper.AcceptReturnRequest(order.OrderDate.Value,
                                                                                  order.EstDeliveryDate,
                                                                                  orderShippings.Max(sh => sh.ActualDeliveryDate),
                                                                                  result.Email.ReceiveDate,
                                                                                  _time.GetAppNowTime());
                        }

                        if (returnRequestToLate)
                        {
                            var message = String.Format("Return request received (reason: {0}, style: {1}). Return request came too late. No email was sent to client by the system.",
                                                        request.Reason,
                                                        request.StyleString);
                            comments.Add(message);
                        }
                        else
                        {
                            //TASK: don’t send Too small/big emails to clients who already purchased bigger/smaller size of same pajama, like this client - 105-1300286-6499443.
                            var alreadyPurchasedOrdersByCustomer =
                                db.Orders.GetAll().Where(o => o.OrderStatus == OrderStatusEnumEx.Unshipped &&
                                                         o.BuyerEmail == order.BuyerEmail)
                                .Select(o => o.Id).ToList();

                            var alreadyPurchasedItems = db.OrderItems.GetWithListingInfo()
                                                        .Where(oi => alreadyPurchasedOrdersByCustomer.Contains(oi.OrderId.Value))
                                                        .ToList();

                            var alreadyPurchasedAnotherSize = false;
                            if (request.StyleId.HasValue)
                            {
                                alreadyPurchasedAnotherSize =
                                    alreadyPurchasedItems.Any(i => i.StyleEntityId == request.StyleId &&
                                                              i.StyleItemId != request.StyleItemId);
                            }

                            if (alreadyPurchasedAnotherSize)
                            {
                                var message = String.Format("Return request received (reason: {0}, style: {1}). Customer already purchased bigger/smaller size of same pajama. No email was sent to client by the system.",
                                                            request.Reason,
                                                            request.StyleString);
                                comments.Add(message);
                            }
                            else
                            {
                                if (itemsToExchangeWithQty.Any())
                                {
                                    var sizeList = itemsToExchangeWithQty
                                                   .OrderBy(i => SizeHelper.GetSizeIndex(i.Size))
                                                   .Select(i => i.Size)
                                                   .ToList();
                                    var sizeString = String.Join(" or ", sizeList);

                                    _log.Info("Send email for customer: " + reason + ", sizes=" + sizeString);

                                    var commentText = String.Format("Return request received (reason: {0}, style: {1}).",
                                                                    request.Reason,
                                                                    request.StyleString,
                                                                    reason == ReasonCode.TooLarge ? "smaller" : "bigger");
                                    comments.Add(commentText);
                                    //TEMP: Disabled email
                                    //var commentText = String.Format("Return request received (reason: {0}, style: {1}). System offered client {2} size. Exchange request email sent.",
                                    //        request.Reason,
                                    //        request.StyleString,
                                    //        reason == ReasonCode.TooLarge ? "smaller" : "bigger");
                                    //comments.Add(commentText);

                                    //var emailInfoToBuyer = new AcceptReturnRequestEmailInfo(null,
                                    //    orderNumber,
                                    //    (MarketType) order.Market,
                                    //    reason == ReasonCode.TooLarge,
                                    //    sizeString,
                                    //    order.BuyerName,
                                    //    order.BuyerEmail);

                                    //_emailService.SendEmail(emailInfoToBuyer, CallSource.Service);
                                }
                                else
                                {
                                    var sizeList = itemsToExchange
                                                   .OrderBy(i => SizeHelper.GetSizeIndex(i.Size))
                                                   .Select(i => i.Size)
                                                   .ToList();
                                    var sizeString = String.Join(", ", sizeList);

                                    var message = String.Format("Return request received (reason: {0}). System didn't find any items to offer exchange (style: {1}, size: {2}). No email was sent to client by the system.",
                                                                request.Reason,
                                                                request?.StyleString ?? "[null]",
                                                                sizeString);
                                    comments.Add(message);
                                }
                            }
                        }
                        db.Commit();
                    }
                }

                if (comments.Any())
                {
                    db.OrderComments.Add(new OrderComment()
                    {
                        OrderId    = order.Id,
                        Message    = "[System] " + String.Join(", ", comments),
                        Type       = (int)CommentType.ReturnExchange,
                        CreateDate = _time.GetAppNowTime(),
                        UpdateDate = _time.GetAppNowTime()
                    });
                }
            }
        }
        public CheckResult Check(IUnitOfWork db,
                                 DTOMarketOrder order,
                                 IList <ListingOrderDTO> items,
                                 AddressValidationStatus addressValidationStatus)
        {
            if (order.Id == 0)
            {
                throw new ArgumentOutOfRangeException("order.Id", "Should be non zero");
            }

            if (order.OrderStatus == OrderStatusEnumEx.Pending)
            {
                throw new ArgumentException("order.OrderStatus", "Not supported status Pending");
            }

            //International order has issue with PersonName
            if (!AddressHelper.IsStampsValidPersonName(order.FinalPersonName) &&
                (order.AddressValidationStatus == (int)AddressValidationStatus.InvalidRecipientName ||
                 ShippingUtils.IsInternationalState(order.FinalShippingState) ||
                 ShippingUtils.IsInternational(order.FinalShippingCountry)))
            {
                //If can resolved using BuyerName
                var nameKeywords = (order.FinalPersonName ?? "").Split(", .".ToCharArray()).Where(n => n.Length > 2).ToArray();
                if (!nameKeywords.Any())
                {
                    nameKeywords = (order.FinalPersonName ?? "").Split(", .".ToCharArray()).ToArray();
                }

                if (AddressHelper.IsStampsValidPersonName(order.BuyerName)
                    //NOTE: #1 Exclude prefix Mr., initials, like a.cheszes
                    //NOTE: #2 Include when name has only one letter
                    && StringHelper.ContrainOneOfKeywords(order.BuyerName, nameKeywords))
                {
                    db.OrderComments.Add(new OrderComment()
                    {
                        OrderId = order.Id,
                        Message = "[System] Incomplete recipient name was replaced with buyer name: "
                                  + order.FinalPersonName + "=>" + order.BuyerName,
                        Type       = (int)CommentType.Address,
                        CreateDate = _time.GetAppNowTime()
                    });

                    if (order.IsManuallyUpdated)
                    {
                        order.ManuallyPersonName = order.BuyerName;
                    }
                    else
                    {
                        order.PersonName = order.BuyerName;
                    }

                    return(new CheckResult()
                    {
                        IsSuccess = true,
                        AdditionalData = new[] { order.PersonName }
                    });
                }
                //Send email
                else
                {
                    var emailInfo = new IncompleteNameEmailInfo(_emailService.AddressService,
                                                                null,
                                                                order.OrderId,
                                                                (MarketType)order.Market,
                                                                order.GetAddressDto(),
                                                                items,
                                                                order.BuyerName,
                                                                order.BuyerEmail);

                    _emailService.SendEmail(emailInfo, CallSource.Service);
                    _log.Info("Send incomplete person name email, orderId=" + order.Id);

                    db.OrderEmailNotifies.Add(new OrderEmailNotify()
                    {
                        OrderNumber = order.OrderId,
                        Reason      = "System emailed, incomplete name",
                        Type        = (int)OrderEmailNotifyType.OutputIncompleteNameEmail,
                        CreateDate  = _time.GetUtcTime(),
                    });

                    db.OrderComments.Add(new OrderComment()
                    {
                        OrderId    = order.Id,
                        Message    = "[System] Incomplete name email sent",
                        Type       = (int)CommentType.Address,
                        CreateDate = _time.GetAppNowTime(),
                        UpdateDate = _time.GetAppNowTime()
                    });

                    db.Commit();

                    return(new CheckResult()
                    {
                        IsSuccess = false,
                        AdditionalData = new List <string>()
                        {
                            "OnHold"
                        }
                    });
                }
            }

            return(new CheckResult()
            {
                IsSuccess = false
            });
        }
        public ApplyOrderResult Apply(ILogService log,
                                      IUnitOfWork db,
                                      IOrderHistoryService orderHistoryService,
                                      IQuantityManager quantityManager,
                                      DateTime when,
                                      long?by)
        {
            var dbOrder                 = db.Orders.GetById(EntityId);
            var addressChanged          = false;
            var shipmentProviderChanged = false;
            var shouldRecalcRates       = dbOrder.IsInsured != IsInsured ||
                                          dbOrder.IsSignConfirmation != IsSignConfirmation;

            var manuallyAddress = ComposeAddressDto();

            //NOTE: empty when fields was readonly
            if (!AddressHelper.IsEmptyManually(manuallyAddress))
            {
                var originalAddress = dbOrder.GetAddressDto();

                addressChanged    = AddressHelper.CompareWithManuallyAllFields(originalAddress, manuallyAddress);
                shouldRecalcRates = shouldRecalcRates || AddressHelper.CompareWithManuallyBigChanges(originalAddress, manuallyAddress);

                if (addressChanged)
                {
                    orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ManuallyPersonNameKey, dbOrder.IsManuallyUpdated ? dbOrder.ManuallyPersonName : dbOrder.PersonName, ManuallyPersonName, by);
                    dbOrder.ManuallyPersonName = ManuallyPersonName;
                    orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ManuallyShippingAddress1Key, dbOrder.IsManuallyUpdated ? dbOrder.ManuallyShippingAddress1 : dbOrder.ShippingAddress1, ManuallyShippingAddress1, by);
                    dbOrder.ManuallyShippingAddress1 = ManuallyShippingAddress1;
                    orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ManuallyShippingAddress2Key, dbOrder.IsManuallyUpdated ? dbOrder.ManuallyShippingAddress2 : dbOrder.ShippingAddress2, ManuallyShippingAddress2, by);
                    dbOrder.ManuallyShippingAddress2 = ManuallyShippingAddress2;
                    orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ManuallyShippingCityKey, dbOrder.IsManuallyUpdated ? dbOrder.ManuallyShippingCity : dbOrder.ShippingCity, ManuallyShippingCity, by);
                    dbOrder.ManuallyShippingCity = ManuallyShippingCity;
                    orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ManuallyShippingCountryKey, dbOrder.IsManuallyUpdated ? dbOrder.ManuallyShippingCountry : dbOrder.ShippingCountry, ManuallyShippingCountry, by);
                    dbOrder.ManuallyShippingCountry = ManuallyShippingCountry;

                    dbOrder.ManuallyShippingState = !ShippingUtils.IsInternational(dbOrder.ManuallyShippingCountry)
                                                    // == "US"
                        ? ManuallyShippingUSState
                        : ManuallyShippingState;

                    orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ManuallyShippingZipKey, dbOrder.IsManuallyUpdated ? dbOrder.ManuallyShippingZip : dbOrder.ShippingZip, ManuallyShippingZip, by);
                    dbOrder.ManuallyShippingZip = StringHelper.TrimWhitespace(ManuallyShippingZip);
                    orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ManuallyShippingZipAddonKey, dbOrder.IsManuallyUpdated ? dbOrder.ManuallyShippingZipAddon : dbOrder.ShippingZipAddon, ManuallyShippingZipAddon, by);
                    dbOrder.ManuallyShippingZipAddon = StringHelper.TrimWhitespace(ManuallyShippingZipAddon);
                    orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ManuallyShippingPhoneKey, dbOrder.IsManuallyUpdated ? dbOrder.ManuallyShippingPhone : dbOrder.ShippingPhone, ManuallyShippingPhone, by);
                    dbOrder.ManuallyShippingPhone = ManuallyShippingPhone;

                    dbOrder.IsManuallyUpdated = true;
                }
                else
                {
                    dbOrder.ManuallyPersonName       = String.Empty;
                    dbOrder.ManuallyShippingAddress1 = String.Empty;
                    dbOrder.ManuallyShippingAddress2 = String.Empty;
                    dbOrder.ManuallyShippingCity     = String.Empty;
                    dbOrder.ManuallyShippingCountry  = String.Empty;

                    dbOrder.ManuallyShippingState    = String.Empty;
                    dbOrder.ManuallyShippingZip      = String.Empty;
                    dbOrder.ManuallyShippingZipAddon = String.Empty;
                    dbOrder.ManuallyShippingPhone    = String.Empty;

                    dbOrder.IsManuallyUpdated = false;
                }
            }

            dbOrder.InsuredValue = InsuredValue;
            orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.IsInsuredKey, dbOrder.IsInsured, IsInsured, by);
            dbOrder.IsInsured = IsInsured;
            orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.IsSignConfirmationKey, dbOrder.IsSignConfirmation, IsSignConfirmation, by);
            dbOrder.IsSignConfirmation = IsSignConfirmation;

            if (ManuallyShipmentProviderType.HasValue)
            {
                if (dbOrder.ShipmentProviderType != ManuallyShipmentProviderType.Value)
                {
                    shipmentProviderChanged = true;
                    shouldRecalcRates       = true;
                }

                orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ShipmentProviderTypeKey, dbOrder.ShipmentProviderType, ManuallyShipmentProviderType, by);
                dbOrder.ShipmentProviderType = ManuallyShipmentProviderType.Value;
            }

            //dbOrder.OnHold = OnHold;

            dbOrder.UpdateDate = when;
            dbOrder.UpdatedBy  = by;

            if (Items.All(i => i.NewListingId > 0)) //NOTE: only when enabled items edit
            {
                var changeNotes        = "";
                var itemSizeWasChanged = false;
                var joinItems          = JoinItems(Items);
                var dbOrderItems       = db.OrderItems.GetAll().Where(i => i.OrderId == dbOrder.Id).ToList();
                var orderItemSources   = db.OrderItemSources.GetAllAsDto().Where(i => i.OrderId == dbOrder.Id).ToList();

                foreach (var item in joinItems)
                {
                    var dbOrderItem = dbOrderItems.FirstOrDefault(im => im.ItemOrderIdentifier == item.ItemOrderId);

                    //NOTE: Get source info for set proprotionally ItemPrice etc.
                    var sourceItemOrderId = item.SourceItemOrderId;
                    var sourceItemMapping = orderItemSources.FirstOrDefault(i => i.ItemOrderIdentifier == sourceItemOrderId);

                    if (dbOrderItem != null)
                    {
                        log.Info("Updated orderItemId=" + item.ItemOrderId + ", qty=" + item.Quantity);
                    }
                    else
                    {
                        log.Info("Added orderItemId=" + item.ItemOrderId + ", qty=" + item.Quantity);
                        dbOrderItem            = db.OrderItemSources.CreateItemFromSourceDto(sourceItemMapping);
                        dbOrderItem.CreateDate = when;

                        db.OrderItems.Add(dbOrderItem);
                    }

                    dbOrderItem.ItemOrderIdentifier = item.ItemOrderId;
                    dbOrderItem.QuantityOrdered     = item.Quantity;
                    dbOrderItem.ListingId           = item.NewListingId;

                    dbOrderItem.SourceListingId           = sourceItemMapping.ListingId;
                    dbOrderItem.SourceItemOrderIdentifier = sourceItemMapping.ItemOrderIdentifier;

                    var newListing = db.Listings.GetViewListingsAsDto(withUnmaskedStyles: false)
                                     .FirstOrDefault(l => l.Id == item.NewListingId);

                    var keepListingUpdateOnlyStyle = newListing.StyleItemId != dbOrderItem.StyleItemId;
                    if (dbOrderItem.Id == 0 ||
                        item.NewListingId != item.ListingId ||
                        keepListingUpdateOnlyStyle)
                    {
                        var oldListing = db.Listings.GetViewListingsAsDto(withUnmaskedStyles: false)
                                         .FirstOrDefault(l => l.Id == sourceItemMapping.ListingId);

                        if (newListing != null && oldListing != null)
                        {
                            itemSizeWasChanged = newListing.StyleItemId != oldListing.StyleItemId;
                            if (itemSizeWasChanged)
                            {
                                var isStyleChanged = newListing.StyleString != oldListing.StyleString;
                                changeNotes += (isStyleChanged ? "Order item" : "Size") + " was changed from: " +
                                               (isStyleChanged ? oldListing.StyleString + " - " : " ") +
                                               SizeHelper.ToVariation(oldListing.StyleSize, oldListing.StyleColor)
                                               + " to: " + (isStyleChanged ? newListing.StyleString + " - " : "") +
                                               SizeHelper.ToVariation(newListing.StyleSize, newListing.StyleColor);

                                dbOrderItem.ReplaceType = (int)ItemReplaceTypes.Change;
                                dbOrderItem.ReplaceDate = when;
                                orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ReplaceItemKey, dbOrderItem.StyleItemId, dbOrderItem.Id.ToString(), newListing.StyleItemId, null, by);

                                var quantityOperation = new QuantityOperationDTO()
                                {
                                    Type            = (int)QuantityOperationType.Lost,
                                    QuantityChanges = new List <QuantityChangeDTO>()
                                    {
                                        new QuantityChangeDTO()
                                        {
                                            StyleId     = oldListing.StyleId.Value,
                                            StyleItemId = oldListing.StyleItemId.Value,
                                            Quantity    = dbOrderItem.QuantityOrdered,
                                            //NOTE: W/o sign means that the qty will be substracted
                                        }
                                    },
                                    Comment = "Order edit, change style/size",
                                };

                                quantityManager.AddQuantityOperation(db,
                                                                     quantityOperation,
                                                                     when,
                                                                     by);
                            }

                            //NOTE: Actualize current style info
                            dbOrderItem.StyleId     = newListing.StyleId;
                            dbOrderItem.StyleItemId = newListing.StyleItemId;
                            dbOrderItem.StyleString = newListing.StyleString;

                            dbOrderItem.SourceStyleString = oldListing.StyleString;
                            dbOrderItem.SourceStyleItemId = oldListing.StyleItemId;
                            dbOrderItem.SourceStyleSize   = oldListing.StyleSize;
                            dbOrderItem.SourceStyleColor  = oldListing.StyleColor;
                        }
                    }

                    if (dbOrderItem.ItemOrderIdentifier != dbOrderItem.SourceItemOrderIdentifier)
                    {
                        var portionCoef = dbOrderItem.QuantityOrdered / (decimal)sourceItemMapping.QuantityOrdered;

                        dbOrderItem.ItemPrice             = sourceItemMapping.ItemPrice * portionCoef;
                        dbOrderItem.ItemPriceInUSD        = sourceItemMapping.ItemPriceInUSD * portionCoef;
                        dbOrderItem.ShippingPrice         = sourceItemMapping.ShippingPrice * portionCoef;
                        dbOrderItem.ShippingPriceInUSD    = sourceItemMapping.ShippingPriceInUSD * portionCoef;
                        dbOrderItem.ShippingDiscount      = sourceItemMapping.ShippingDiscount * portionCoef;
                        dbOrderItem.ShippingDiscountInUSD = sourceItemMapping.ShippingDiscountInUSD * portionCoef;
                    }
                    else //NOTE: m.b. no needed, for now no cases, but can be found in future
                    {
                        dbOrderItem.ItemPrice             = sourceItemMapping.ItemPrice;
                        dbOrderItem.ItemPriceInUSD        = sourceItemMapping.ItemPriceInUSD;
                        dbOrderItem.ShippingPrice         = sourceItemMapping.ShippingPrice;
                        dbOrderItem.ShippingPriceInUSD    = sourceItemMapping.ShippingPriceInUSD;
                        dbOrderItem.ShippingDiscount      = sourceItemMapping.ShippingDiscount;
                        dbOrderItem.ShippingDiscountInUSD = sourceItemMapping.ShippingDiscountInUSD;
                    }
                }
                db.Commit();

                var toRemoveOrderItems = dbOrderItems.Where(oi => joinItems.All(i => i.ItemOrderId != oi.ItemOrderIdentifier) &&
                                                            oi.QuantityOrdered > 0).ToList(); //Keeping cancelled items with qty = 0
                foreach (var toRemove in toRemoveOrderItems)
                {
                    log.Info("Remove orderItem, ordrItemId=" + toRemove.ItemOrderIdentifier
                             + ", qty=" + toRemove.QuantityOrdered);
                    db.OrderItems.Remove(toRemove);

                    itemSizeWasChanged = true;
                }
                db.Commit();

                if (itemSizeWasChanged)
                {
                    shouldRecalcRates = true;

                    Comments.Add(new CommentViewModel()
                    {
                        Comment = changeNotes,
                        Type    = (int)CommentType.ReturnExchange
                    });
                }
            }


            if (!string.IsNullOrEmpty(ManuallyShippingGroupId))
            {
                var groupId   = int.Parse(ManuallyShippingGroupId);
                var shippings = db.OrderShippingInfos.GetByOrderId(EntityId).ToList();
                var previousIsActiveMethodIds = String.Join(";", shippings.Where(sh => sh.IsActive).Select(sh => sh.ShippingMethodId).ToList());
                var hasDropdown = shippings.Where(sh => sh.IsVisible).GroupBy(sh => sh.ShippingMethodId).Count() > 1;
                if (shippings.Any(sh => sh.ShippingGroupId == groupId))
                {
                    foreach (var shipping in shippings)
                    {
                        shipping.IsActive = shipping.ShippingGroupId == groupId;
                        if (hasDropdown) //Keep is visible
                        {
                            shipping.IsVisible = shipping.IsVisible || shipping.ShippingGroupId == groupId;
                        }
                        else
                        {
                            shipping.IsVisible = shipping.ShippingGroupId == groupId;
                        }
                    }
                    var newIsActiveMethodIds = String.Join(";", shippings.Where(sh => sh.IsActive).Select(sh => sh.ShippingMethodId).ToList());
                    orderHistoryService.AddRecord(dbOrder.Id, OrderHistoryHelper.ShippingMethodKey, previousIsActiveMethodIds, newIsActiveMethodIds, by);
                }
                else
                {
                    //Can't change active shipping to not exists
                }
            }
            db.Commit();

            //Update Package Sizes
            var activeShippings = db.OrderShippingInfos.GetByOrderId(EntityId)
                                  .Where(sh => sh.IsActive)
                                  .OrderBy(sh => sh.Id)
                                  .ToList();

            for (var i = 0; i < activeShippings.Count; i++)
            {
                if (Packages != null && i < Packages.Count)
                {
                    if (activeShippings[i].PackageLength != Packages[i].PackageLength)
                    {
                        log.Info("Changed length: " + activeShippings[i].PackageLength + "=>" + Packages[i].PackageLength);
                        activeShippings[i].PackageLength = Packages[i].PackageLength;

                        shouldRecalcRates = true;
                    }
                    if (activeShippings[i].PackageWidth != Packages[i].PackageWidth)
                    {
                        log.Info("Changed width: " + activeShippings[i].PackageWidth + "=>" + Packages[i].PackageWidth);
                        activeShippings[i].PackageWidth = Packages[i].PackageWidth;

                        shouldRecalcRates = true;
                    }
                    if (activeShippings[i].PackageHeight != Packages[i].PackageHeight)
                    {
                        log.Info("Changed height: " + activeShippings[i].PackageHeight + "=>" + Packages[i].PackageHeight);
                        activeShippings[i].PackageHeight = Packages[i].PackageHeight;

                        shouldRecalcRates = true;
                    }
                }
            }
            db.Commit();



            foreach (var comment in Comments)
            {
                if (comment.Id == 0)
                {
                    log.Info("New comment: " + comment.Comment);
                }
            }

            db.OrderComments.AddComments(
                Comments.Select(c => new CommentDTO()
            {
                Id      = c.Id,
                Message = c.Comment,
                Type    = c.Type,
            }).ToList(),
                EntityId,
                when,
                by);

            return(new ApplyOrderResult()
            {
                RateRecalcRequested = shouldRecalcRates,
                AddressValidationRequested = addressChanged ||
                                             dbOrder.AddressValidationStatus == (int)Core.Models.AddressValidationStatus.ExceptionCommunication ||
                                             dbOrder.AddressValidationStatus == (int)Core.Models.AddressValidationStatus.Exception,
                ShipmentProviderChanged = shipmentProviderChanged
            });
        }
        public static CustomShippingViewModel Get(IUnitOfWork db, long orderId, long?defaultShippingMethodId)
        {
            var result = new CustomShippingViewModel();

            var order           = db.Orders.GetById(orderId);
            var isIntl          = ShippingUtils.IsInternational(order.ShippingCountry);
            var shippingMethods = db.ShippingMethods.GetAllAsDto()
                                  .Where(m => m.ShipmentProviderType == order.ShipmentProviderType &&
                                         m.IsInternational == isIntl &&
                                         m.IsActive)
                                  .ToList();

            result.PackageList = new List <SelectListItemTag>();
            foreach (var shippingMethod in shippingMethods)
            {
                for (int i = 0; i <= 6; i++)
                {
                    result.PackageList.Add(new SelectListItemTag()
                    {
                        Text  = shippingMethod.Name + " - #" + (i + 1),
                        Value = shippingMethod.Id.ToString() + "-" + (i + 1),
                    });
                }
            }

            var customShippings = db.OrderShippingInfos.GetAllAsDto()
                                  .Where(sh => sh.OrderId == orderId &&
                                         sh.ShippingGroupId == RateHelper.CustomPartialGroupId)
                                  .OrderBy(sh => sh.ShippingNumber)
                                  .ToList();

            var orderItems = db.Listings.GetOrderItems(orderId)
                             .OrderBy(oi => oi.ItemOrderId)
                             .ToList();

            //var orderItems = db.OrderItems.GetWithListingInfo()
            //    .Where(oi => oi.OrderId == orderId)
            //    .OrderBy(oi => oi.ItemOrderId)
            //    .ToList();

            var itemToShipping = new List <OrderShippingInfoDTO>();

            if (customShippings.Any())
            {
                var shippingIds = customShippings.Select(sh => sh.Id).ToList();

                itemToShipping = (from m in db.ItemOrderMappings.GetAll()
                                  join sh in db.OrderShippingInfos.GetAll() on m.ShippingInfoId equals sh.Id
                                  join sm in db.ShippingMethods.GetAll() on sh.ShippingMethodId equals sm.Id
                                  where shippingIds.Contains(m.ShippingInfoId)
                                  select new OrderShippingInfoDTO()
                {
                    Id = m.ShippingInfoId,
                    Items = new List <DTOOrderItem>()
                    {
                        new DTOOrderItem()
                        {
                            OrderItemEntityId = m.OrderItemId,
                            Quantity = m.MappedQuantity
                        }
                    },
                    ShippingMethod = new ShippingMethodDTO()
                    {
                        Id = sm.Id,
                        Name = sm.Name,
                        ShortName = sm.ShortName,
                        RequiredPackageSize = sm.RequiredPackageSize
                    }
                }).ToList();
            }

            var shippingNumbers    = new Dictionary <long, int>();
            var shippings          = itemToShipping.GroupBy(sh => sh.Id).Select(sh => sh.First()).ToList();
            var processedShippings = new List <OrderShippingInfoDTO>();

            foreach (var shipping in shippings)
            {
                var count = processedShippings.Count(sh => sh.ShippingMethod.Id == shipping.ShippingMethod.Id);
                shippingNumbers.Add(shipping.Id, count + 1);
                processedShippings.Add(shipping);
            }

            ShippingMethodDTO defaultShippingMethod = null;

            if (defaultShippingMethodId.HasValue)
            {
                defaultShippingMethod = shippingMethods.FirstOrDefault(m => m.Id == defaultShippingMethodId.Value);
            }
            if (defaultShippingMethod == null)
            {
                defaultShippingMethod = shippingMethods.FirstOrDefault(m => m.Id == ShippingUtils.AmazonFedEx2DayOneRatePakShippingMethodId ||
                                                                       m.Id == ShippingUtils.FedexOneRate2DayPak);
            }

            var defaultPackageNumber = defaultShippingMethod != null ? 1 : (int?)null;

            var items = new List <CustomShippingItemViewModel>();

            foreach (var orderItem in orderItems)
            {
                for (int q = 0; q < orderItem.QuantityOrdered; q++)
                {
                    var existCustomMapping = itemToShipping.FirstOrDefault(i => i.Items.First().OrderItemEntityId == orderItem.OrderItemEntityId &&
                                                                           i.Items.First().Quantity > 0);

                    if (existCustomMapping != null)
                    {
                        existCustomMapping.Items.First().Quantity--;
                    }

                    var image = orderItem.Picture;
                    if (String.IsNullOrEmpty(image))
                    {
                        image = orderItem.StyleImage;
                    }
                    if (orderItem.ReplaceType == (int)ItemReplaceTypes.Combined)
                    {
                        image = orderItem.StyleImage;
                    }
                    var pictureUrl = ImageHelper.GetFirstOrDefaultPicture(image);

                    items.Add(new CustomShippingItemViewModel()
                    {
                        ASIN        = orderItem.ASIN,
                        StyleString = orderItem.StyleID,
                        StyleSize   = orderItem.StyleSize,

                        Weight = orderItem.Weight ?? 0,

                        PictureUrl = pictureUrl,

                        OrderItemId        = orderItem.OrderItemEntityId,
                        ShippingInfoId     = existCustomMapping != null ? existCustomMapping.Id : (long?)null,
                        ShippingMethodName = existCustomMapping != null ? existCustomMapping.ShippingMethod.Name : defaultShippingMethod?.Name,
                        ShippingMethodId   = existCustomMapping != null ? existCustomMapping.ShippingMethod.Id : defaultShippingMethod?.Id,

                        PackageNumber = existCustomMapping != null ? shippingNumbers[existCustomMapping.Id] : defaultPackageNumber,
                    });
                }
            }

            items.ForEach(i =>
            {
                if (i.PackageNumber.HasValue && i.ShippingMethodId.HasValue)
                {
                    i.PackageValue = i.ShippingMethodId.Value + "-" + i.PackageNumber;
                }
            });

            result.Items = items.OrderBy(i => i.ShippingMethodId)
                           .ThenBy(i => i.PackageNumber)
                           .ThenBy(i => i.StyleString) //TODO: by location
                           .ThenBy(i => SizeHelper.GetSizeIndex(i.StyleSize))
                           .ToList();

            return(result);
        }