private IList <TrackingResult> ProcessFileRecords(ITrackingProvider trackingProvider, IList <string> trackings)
        {
            var trackingList = trackings.Select(tr => new TrackingNumberToCheckDto()
            {
                TrackingNumber = tr,
                ToCountry      = "US"
            }).ToList();

            var trackResults = trackingProvider.TrackShipments(trackingList);

            if (trackResults.Count == 0)
            {
                _log.Info("No results. Wait.");
                Thread.Sleep(60000);
            }

            var results = new List <TrackingResult>();

            foreach (var track in trackResults)
            {
                var records = track.Records.OrderBy(r => r.Date).ToList();
                results.Add(new TrackingResult()
                {
                    TrackingNumber = track.TrackingNumber,
                    FirstTrackDate = records.FirstOrDefault()?.Date,
                    FirstZipCode   = records.FirstOrDefault()?.Zip,
                    SecondZipCode  = records.Skip(1).FirstOrDefault()?.Zip,
                });
            }

            return(results);
        }
        public IList <TrackingState> UpdateOrderTracking(
            IUnitOfWork db,
            CompanyDTO company,
            IList <OrderToTrackDTO> shippings,
            ITrackingProvider trackingProvider)
        {
            _log.Info("UpdateOrderTracking, shippings=" + shippings.Count);
            try
            {
                var ruleList = _ruleList;

                var trackingList = shippings
                                   .Where(o => !String.IsNullOrEmpty(o.TrackingNumber))
                                   .Select(o => new TrackingNumberToCheckDto()
                {
                    TrackingNumber = o.TrackingNumber,
                    ToCountry      = o.ShippingAddress != null ? o.ShippingAddress.FinalCountry : null,
                }).ToList();

                var stateList = trackingProvider.TrackShipments(trackingList);
                var today     = _time.GetAppNowTime();

                _log.Info("UpdateOrderTracking, track count get back=" + stateList.Count);
                var processedShipmentIds = new List <long>();
                var processedMailInfoIds = new List <long>();
                foreach (var state in stateList)
                {
                    //NOTE: Fedex has delivery records not as last record (ex.: 393418292108)
                    var deliveredRecord = state.Records != null?state.Records.FirstOrDefault(r => _deliveryEventList.Contains(r.Message ?? "") || (r.Message ?? "").ToLower().StartsWith("delivered")) : null;

                    var lastRecord = deliveredRecord != null ? deliveredRecord : (state.Records != null ? state.Records.FirstOrDefault() : null);
                    var isBack     = lastRecord != null?_addressService.IsMine(lastRecord.AsAddressDto()) : false;

                    var shippingDto = shippings.FirstOrDefault(sh => sh.TrackingNumber == state.TrackingNumber);
                    if (shippingDto != null)
                    {
                        var hasStateChanges = false;
                        if (lastRecord == null)
                        {
                            hasStateChanges = false;
                            shippingDto.TrackingRequestAttempts = shippingDto.TrackingRequestAttempts + 1;
                            shippingDto.LastTrackingRequestDate = _time.GetUtcTime();
                            _log.Warn("UpdateOrderTracking, empty Records!");
                        }
                        else
                        {
                            _log.Info("UpdateOrderTracking, o=" + shippingDto.OrderNumber + ", tr=" +
                                      shippingDto.TrackingNumber + ", at=" + shippingDto.OrderDate + ", new state=" +
                                      lastRecord.Message + " at=" + lastRecord.Date);

                            var newStateEvent = StringHelper.Substring(lastRecord.Message, 100);
                            hasStateChanges = shippingDto.TrackingStateDate != lastRecord.Date ||
                                              shippingDto.TrackingStateEvent != newStateEvent;

                            shippingDto.TrackingStateSource = (int)lastRecord.Source;
                            shippingDto.TrackingStateDate   = lastRecord.Date;
                            shippingDto.TrackingStateEvent  = newStateEvent;
                            shippingDto.TrackingLocation    = lastRecord.Country + ", " + lastRecord.State + ", " +
                                                              lastRecord.City + ", " + lastRecord.Zip;

                            if (_deliveryEventList.Contains(lastRecord.Message) ||
                                lastRecord.Message.ToLower().StartsWith("delivered") ||
                                (lastRecord.Message.ToLower().Contains("shipment picked up") &&
                                 (state.Records.Count > 5 && lastRecord.Date < today.AddDays(-2))))
                            //NOTE: temporary solution for "Shipment Picked Up", every shipment may have transit status with that name (not final)
                            {
                                shippingDto.DeliveredStatus = isBack
                                    ? (int)DeliveredStatusEnum.DeliveredToSender
                                    : (int)DeliveredStatusEnum.Delivered;

                                shippingDto.IsDelivered        = true;
                                shippingDto.ActualDeliveryDate = lastRecord.Date;
                            }
                            else
                            {
                                //May happend like with refused tracking number https://tools.usps.com/go/TrackConfirmAction!input.action?tRef=qt&tLc=1&tLabels=9400116901495496872649
                                //Order #1577164597317
                                shippingDto.DeliveredStatus    = (int)DeliveredStatusEnum.None;
                                shippingDto.IsDelivered        = false;
                                shippingDto.ActualDeliveryDate = null;
                            }

                            //For DHL
                            if (lastRecord.Message.ToLower().StartsWith("Returned to shipper"))
                            {
                                shippingDto.DeliveredStatus    = (int)DeliveredStatusEnum.DeliveredToSender;
                                shippingDto.IsDelivered        = true;
                                shippingDto.ActualDeliveryDate = lastRecord.Date;
                            }

                            shippingDto.LastTrackingRequestDate = _time.GetUtcTime();

                            if (!hasStateChanges)
                            {
                                shippingDto.TrackingRequestAttempts = shippingDto.TrackingRequestAttempts + 1;
                            }
                            else
                            {
                                shippingDto.TrackingRequestAttempts = 1;
                            }

                            //NOTE: If state no changes for a long time => no requests
                            if (lastRecord.Date < _time.GetAppNowTime().AddDays(-50) ||
                                (shippingDto.OrderDate < _time.GetAppNowTime().AddDays(-90) &&
                                 lastRecord.Message.StartsWith(TrackingHelper.UndefinedPrefix)))
                            {
                                shippingDto.TrackingRequestAttempts = 10000;
                                if (lastRecord.Message.StartsWith(TrackingHelper.UndefinedPrefix))
                                {
                                    _log.Info("Info Unavailable, message=" + lastRecord.Message);
                                    shippingDto.DeliveredStatus = (int)DeliveredStatusEnum.InfoUnavailable;
                                }
                                _log.Info("Last attempt (= 10000)");
                            }
                        }


                        if (shippingDto.ShipmentInfoId.HasValue)
                        {
                            if (processedShipmentIds.Any(sh => sh == shippingDto.ShipmentInfoId.Value))
                            {
                                _log.Info("Shipment with that Id already processed: " + shippingDto.ShipmentInfoId.Value);
                            }
                            else
                            {
                                processedShipmentIds.Add(shippingDto.ShipmentInfoId.Value);

                                var changeFields = new List <Expression <Func <OrderShippingInfo, object> > >()
                                {
                                    p => p.LastTrackingRequestDate,
                                    p => p.TrackingRequestAttempts
                                };
                                if (hasStateChanges)
                                {
                                    changeFields.Add(p => p.TrackingStateSource);
                                    changeFields.Add(p => p.TrackingStateDate);
                                    changeFields.Add(p => p.TrackingStateEvent);
                                    changeFields.Add(p => p.TrackingLocation);

                                    changeFields.Add(p => p.DeliveredStatus);
                                    changeFields.Add(p => p.IsDelivered);
                                    changeFields.Add(p => p.ActualDeliveryDate);
                                }
                                db.OrderShippingInfos.TrackItem(new OrderShippingInfo()
                                {
                                    Id = shippingDto.ShipmentInfoId.Value,
                                    TrackingStateSource     = shippingDto.TrackingStateSource,
                                    TrackingStateDate       = shippingDto.TrackingStateDate,
                                    TrackingStateEvent      = shippingDto.TrackingStateEvent,
                                    TrackingLocation        = shippingDto.TrackingLocation,
                                    DeliveredStatus         = shippingDto.DeliveredStatus,
                                    IsDelivered             = shippingDto.IsDelivered,
                                    ActualDeliveryDate      = shippingDto.ActualDeliveryDate,
                                    LastTrackingRequestDate = shippingDto.LastTrackingRequestDate,
                                    TrackingRequestAttempts = shippingDto.TrackingRequestAttempts ?? 1
                                },
                                                                changeFields);
                            }
                        }

                        if (shippingDto.MailInfoId.HasValue)
                        {
                            if (processedMailInfoIds.Any(sh => sh == shippingDto.MailInfoId.Value))
                            {
                                _log.Info("Shipment with that Id already processed: " + shippingDto.MailInfoId.Value);
                            }
                            else
                            {
                                processedMailInfoIds.Add(shippingDto.MailInfoId.Value);

                                var changeFields = new List <Expression <Func <MailLabelInfo, object> > >()
                                {
                                    p => p.LastTrackingRequestDate,
                                    p => p.TrackingRequestAttempts
                                };
                                if (hasStateChanges)
                                {
                                    changeFields.Add(p => p.TrackingStateSource);
                                    changeFields.Add(p => p.TrackingStateDate);
                                    changeFields.Add(p => p.TrackingStateEvent);
                                    changeFields.Add(p => p.TrackingLocation);

                                    changeFields.Add(p => p.DeliveredStatus);
                                    changeFields.Add(p => p.IsDelivered);
                                    changeFields.Add(p => p.ActualDeliveryDate);
                                }
                                db.MailLabelInfos.TrackItem(new MailLabelInfo()
                                {
                                    Id = shippingDto.MailInfoId.Value,
                                    TrackingStateSource     = shippingDto.TrackingStateSource,
                                    TrackingStateDate       = shippingDto.TrackingStateDate,
                                    TrackingStateEvent      = shippingDto.TrackingStateEvent,
                                    TrackingLocation        = shippingDto.TrackingLocation,
                                    DeliveredStatus         = shippingDto.DeliveredStatus,
                                    IsDelivered             = shippingDto.IsDelivered,
                                    ActualDeliveryDate      = shippingDto.ActualDeliveryDate,
                                    LastTrackingRequestDate = shippingDto.LastTrackingRequestDate,
                                    TrackingRequestAttempts = shippingDto.TrackingRequestAttempts ?? 1
                                },
                                                            changeFields);
                            }
                        }

                        //NOTE: if do checks only when state changed, the rules based on calculate business day were never activated
                        //if (hasStateChanges)
                        if (lastRecord != null)
                        {
                            CheckRules(db,
                                       shippingDto,
                                       lastRecord.Message,
                                       lastRecord.Date,
                                       state.Records,
                                       ruleList);
                        }
                    }
                }
                db.Commit();

                return(stateList);
            }
            catch (Exception ex)
            {
                _log.Error("UpdateOrderTracking", ex);
            }
            return(null);
        }