Example #1
0
        public static async Task SyncTrucksTable(CancellationToken cToken, UnitOfWork uow)
        {
            var trucks = await DocumentDBContext.GetAllItemsAsync <TruckEntity>(p => p.EntityType == EntityType.TRUCK);

            var localTruckIds = uow.TruckRepository.GetAllIds();

            if (cToken.IsCancellationRequested)
            {
                return;
            }
            using (var addWork = new UnitOfWork())
            {
                addWork.DisableChangeTracking();
                AddRemoteEntitiesToLocalOfType <TruckEntity>(addWork, addWork.TruckRepository, cToken, trucks, localTruckIds);
            }

            if (cToken.IsCancellationRequested)
            {
                return;
            }

            using (var updateWork = new UnitOfWork())
            {
                updateWork.DisableChangeTracking();
                SyncHelper.UpdateRemoteEntitiesOnLocalOfType <TruckEntity>(updateWork, updateWork.TruckRepository, cToken, trucks, localTruckIds, true);
            }

            if (cToken.IsCancellationRequested)
            {
                return;
            }
            SyncHelper.DeleteEntitiesOfTypeNoSourceCheck <TruckEntity>(uow, uow.TruckRepository, cToken, trucks);
        }
Example #2
0
        private async Task <bool> tryDownloadSettings()
        {
            bool savedSettings = false;

            try
            {
                using (var dp = SimpleIoc.Default.GetInstance <IUnitOfWorkFactory>().CreateUnitOfWork())
                {
                    var syncedSettings = await DocumentDBContext.GetAllItemsAsync <SyncedSettings>(p => p.EntityType == EntityType.SETTING_SUMMARY);

                    var settingsToSave     = syncedSettings.FirstOrDefault();
                    var localSyncedSetting = dp.SyncedSettingsRepo.GetAll().FirstOrDefault();

                    settingsToSave.SyncedToCloud = true;
                    if (localSyncedSetting == null)
                    {
                        dp.SyncedSettingsRepo.Add(settingsToSave);
                    }
                    else
                    {
                        dp.SyncedSettingsRepo.Update(settingsToSave);
                    }
                    dp.SaveChanges();
                    savedSettings = true;
                }
            }
            catch (Exception exc)
            {
                Logging.Logger.Log(exc);
            }

            return(savedSettings);
        }
Example #3
0
        private static async Task ClearDownloadedListsData(string appDataPath)
        {
            try
            {
                Console.WriteLine("Releasing downloaded lists...");
                string settingsFile    = appDataPath + "\\Truck\\settings.txt";
                string encryptedString = System.IO.File.ReadAllText(settingsFile);
                string decryptedString = CottonDBMS.Helpers.EncryptionHelper.Decrypt(encryptedString);
                var    parms           = Newtonsoft.Json.JsonConvert.DeserializeObject <TruckAppInstallParams>(decryptedString);

                if (!string.IsNullOrEmpty(parms.EndPoint) &&
                    !string.IsNullOrEmpty(parms.Key) &&
                    !string.IsNullOrEmpty(parms.TruckID))
                {
                    DocumentDBContext.Initialize(parms.EndPoint, parms.Key);

                    Console.WriteLine("Looking for downloaded lists...");
                    var docs = await DocumentDBContext.GetAllItemsAsync <TruckListsDownloaded>(p => p.Id == "TRUCKDOWNLOADS_" + parms.TruckID);

                    if (docs.Count() > 0)
                    {
                        Console.WriteLine("Releasing lists...");
                        //remove document tracking lists this truck has downloaded
                        //this allows them to be released for delete etc at the gin
                        await DocumentDBContext.DeleteItemAsync <TruckListsDownloaded>("TRUCKDOWNLOADS_" + parms.TruckID);
                    }
                }
                else
                {
                    Console.WriteLine("One or more settings null.");
                }
            }
            catch (Exception exc)
            {
                Console.WriteLine(exc.Message);
                Console.WriteLine(exc.StackTrace);
                Console.WriteLine("Press enter to continue.");
                Console.ReadLine();
            }
        }
Example #4
0
        public static async Task SyncModuleOwnershipTable(UnitOfWork uow, DateTime lastSyncTime, CancellationToken token)
        {
            //Sync module ownership table
            //get only modules updated or created
            var remoteModuleOwnerships = await DocumentDBContext.GetAllItemsAsync <ModuleOwnershipEntity>(p => p.EntityType == EntityType.MODULE_OWNERSHIP && (p.Created > lastSyncTime ||
                                                                                                                                                               (p.Updated.HasValue && p.Updated > lastSyncTime)));

            if (token.IsCancellationRequested)
            {
                return;
            }

            var localModuleOwnershipIds = uow.ModuleOwnershipRepository.GetAllIds();

            if (token.IsCancellationRequested)
            {
                return;
            }

            using (var addWork = new UnitOfWork())
            {
                addWork.DisableChangeTracking();
                AddRemoteEntitiesToLocalOfType <ModuleOwnershipEntity>(addWork, addWork.ModuleOwnershipRepository, token, remoteModuleOwnerships, localModuleOwnershipIds);
            }

            if (token.IsCancellationRequested)
            {
                return;
            }

            using (var updateWork = new UnitOfWork())
            {
                updateWork.DisableChangeTracking();
                UpdateRemoteEntitiesOnLocalOfType <ModuleOwnershipEntity>(updateWork, updateWork.ModuleOwnershipRepository, token, remoteModuleOwnerships, localModuleOwnershipIds, false);
            }
        }
Example #5
0
        private async Task <bool> tryDownloadTrucksFromCloud()
        {
            bool trucksDownloaded = false;

            using (var dp = SimpleIoc.Default.GetInstance <IUnitOfWorkFactory>().CreateUnitOfWork())
            {
                try
                {
                    Logging.Logger.Log("INFO", "Fetch local trucks.");
                    var localTrucks = dp.TruckRepository.GetAll();

                    Logging.Logger.Log("INFO", "Fetch local Drivers.");
                    var localDrivers = dp.DriverRepository.GetAll();

                    Logging.Logger.Log("INFO", "Fetch current truck.");
                    var currentTruck = dp.SettingsRepository.GetCurrentTruck();

                    Logging.Logger.Log("INFO", "Fetch current driver.");
                    var currentDriver = dp.SettingsRepository.GetCurrentDriver();

                    if (currentDriver == null || currentTruck == null) //if no truck or driver set try to pull down from cloud and set a truck/driver
                    {
                        Logging.Logger.Log("INFO", "Initialize document db context.");
                        CottonDBMS.Cloud.DocumentDBContext.Initialize(endpoint, key);

                        Logging.Logger.Log("INFO", "Download trucks from cloud.");
                        var trucks = await DocumentDBContext.GetAllItemsAsync <TruckEntity>(p => p.EntityType == EntityType.TRUCK);

                        Logging.Logger.Log("INFO", "Download drivers from cloud.");
                        var drivers = await DocumentDBContext.GetAllItemsAsync <DriverEntity>(p => p.EntityType == EntityType.DRIVER);

                        if (localTrucks.Count() == 0)
                        {
                            Logging.Logger.Log("INFO", "Adding local trucks.");
                            Trucks.Add(new ComboBoxItemViewModel {
                                DisplayText = "-- Choose Truck --", ID = ""
                            });
                            foreach (var t in trucks)
                            {
                                Logging.Logger.Log("INFO", "Adding truck " + t.Name);
                                dp.TruckRepository.Add(t);
                                Trucks.Add(new ComboBoxItemViewModel {
                                    DisplayText = t.Name, ID = t.Id.ToString()
                                });
                            }
                        }

                        if (localDrivers.Count() == 0)
                        {
                            Drivers.Add(new ComboBoxItemViewModel {
                                DisplayText = "-- Choose Driver --", ID = ""
                            });
                            foreach (var d in drivers)
                            {
                                Logging.Logger.Log("INFO", "Adding driver " + d.Name);
                                Drivers.Add(new ComboBoxItemViewModel {
                                    DisplayText = d.Name, ID = d.Id.ToString()
                                });
                                dp.DriverRepository.Add(d);
                            }
                        }

                        Logging.Logger.Log("INFO", "Saving db changes");
                        dp.SaveChanges();
                        Logging.Logger.Log("INFO", "Db changes saved");
                        trucksDownloaded = true;
                    }
                    else
                    {
                        Logging.Logger.Log("INFO", "Driver and truck already set.");
                    }
                }
                catch (Exception exc)
                {
                    Logging.Logger.Log(exc);
                }

                return(trucksDownloaded);
            }
        }
Example #6
0
        private async Task <bool> ValidateForm()
        {
            bool isValid = true;

            clearErrors();
            if (string.IsNullOrWhiteSpace(_documentDbConnection))
            {
                isValid = false;
                HasDocumentDbConnectionErrorMessage = true;
                DocumentDbConnectionErrorMessage    = "required";
            }

            if (string.IsNullOrWhiteSpace(DocumentDbEndpoint))
            {
                isValid = false;
                HasDocumentDbEndpointErrorMessage = true;
                DocumentDbEndpointErrorMessage    = "required";
            }
            else if (!ValidationHelper.ValidUrl(DocumentDbEndpoint))
            {
                isValid = false;
                HasDocumentDbEndpointErrorMessage = true;
                DocumentDbEndpointErrorMessage    = "Invalid URL";
            }


            if (!HasDocumentDbConnectionErrorMessage && !HasDocumentDbEndpointErrorMessage)
            {
                try
                {
                    DocumentDBContext.Initialize(_documentDbEndpoint, _documentDbConnection);
                    var trucks = await DocumentDBContext.GetAllItemsAsync <TruckEntity>(p => p.EntityType == EntityType.TRUCK);
                }
                catch (Exception exc)
                {
                    isValid = false;
                    HasDocumentDbEndpointErrorMessage = true;
                    DocumentDbEndpointErrorMessage    = "Unable to connect.";
                    Logging.Logger.Log(exc);
                }
            }

            if (string.IsNullOrWhiteSpace(TareWeight))
            {
                isValid = false;
                HasTareWeightErrorMessage = true;
                TareWeightErrorMessage    = "required";
            }
            else if (!ValidationHelper.ValidDecimal(TareWeight))
            {
                isValid = false;
                HasTareWeightErrorMessage = true;
                TareWeightErrorMessage    = "Invalid decimal number.";
            }


            if (BarcodePortName != "NONE" && BarcodePortName == PortName)
            {
                isValid = false;
                HasBarcodePortErrorMessage = true;
            }

            return(isValid);
        }
Example #7
0
        private void ExecuteSave()
        {
            Task.Run(async() =>
            {
                string key      = "";
                string endpoint = "";
                bool shutDown   = false;

                using (var dp = SimpleIoc.Default.GetInstance <IUnitOfWorkFactory>().CreateUnitOfWork())
                {
                    var documentDbSetting = dp.SettingsRepository.FindSingle(x => x.Key == TruckClientSettingKeys.DOCUMENT_DB_KEY);
                    var endpointSetting   = dp.SettingsRepository.FindSingle(x => x.Key == TruckClientSettingKeys.DOCUMENTDB_ENDPOINT);

                    if (documentDbSetting != null)
                    {
                        key = documentDbSetting.Value;
                    }

                    if (endpointSetting != null)
                    {
                        endpoint = endpointSetting.Value;
                    }

                    if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(endpoint))
                    {
                        shutDown = true;
                    }
                }

                if (string.IsNullOrWhiteSpace(_documentDbConnection))
                {
                    ShowErrorMessage = true;
                    ErrorMessage     = "Document db key is required.";
                }
                else if (string.IsNullOrWhiteSpace(_documentDbEndpoint))
                {
                    ShowErrorMessage = true;
                    ErrorMessage     = "Document db endpoint is required.";
                }
                else
                {
                    ErrorMessage     = "";
                    ShowErrorMessage = false;
                    Messenger.Default.Send <BusyMessage>(new Messages.BusyMessage {
                        IsBusy = true, Message = "Saving..."
                    });
                    using (var dp = SimpleIoc.Default.GetInstance <IUnitOfWorkFactory>().CreateUnitOfWork())
                    {
                        var documentDbEndpointSetting = dp.SettingsRepository.FindSingle(x => x.Key == TruckClientSettingKeys.DOCUMENTDB_ENDPOINT);
                        var documentDbKeySetting      = dp.SettingsRepository.FindSingle(x => x.Key == TruckClientSettingKeys.DOCUMENT_DB_KEY);
                        var syncIntervalSetting       = dp.SettingsRepository.FindSingle(x => x.Key == TruckClientSettingKeys.DATA_SYNC_INTERVAL);

                        var localTrucks  = dp.TruckRepository.GetAll();
                        var localDrivers = dp.DriverRepository.GetAll();

                        if (documentDbKeySetting != null)
                        {
                            documentDbKeySetting.Value = _documentDbConnection;
                        }
                        else
                        {
                            documentDbKeySetting       = new Setting();
                            documentDbKeySetting.Key   = TruckClientSettingKeys.DOCUMENT_DB_KEY;
                            documentDbKeySetting.Value = _documentDbConnection;
                            dp.SettingsRepository.Add(documentDbKeySetting);
                        }

                        if (documentDbEndpointSetting != null)
                        {
                            documentDbEndpointSetting.Value = _documentDbEndpoint;
                        }
                        else
                        {
                            documentDbEndpointSetting       = new Setting();
                            documentDbEndpointSetting.Key   = TruckClientSettingKeys.DOCUMENTDB_ENDPOINT;
                            documentDbEndpointSetting.Value = _documentDbEndpoint;
                            dp.SettingsRepository.Add(documentDbEndpointSetting);
                        }

                        if (syncIntervalSetting != null)
                        {
                            syncIntervalSetting.Value = _dataSyncInterval.ToString();
                        }
                        else
                        {
                            syncIntervalSetting       = new Setting();
                            syncIntervalSetting.Key   = TruckClientSettingKeys.DATA_SYNC_INTERVAL;
                            syncIntervalSetting.Value = _dataSyncInterval.ToString();
                            dp.SettingsRepository.Add(syncIntervalSetting);
                        }

                        AggregateDataProvider.UpdateReadDelay(_dataSyncInterval);
                        dp.SaveChanges();

                        try
                        {
                            var currentTruck  = dp.SettingsRepository.GetCurrentTruck();
                            var currentDriver = dp.SettingsRepository.GetCurrentDriver();

                            if (currentDriver == null || currentTruck == null) //if no truck or driver set try to pull down from cloud and set a truck/driver
                            {
                                CottonDBMS.Cloud.DocumentDBContext.Initialize(_documentDbEndpoint, _documentDbConnection);
                                var trucks  = await DocumentDBContext.GetAllItemsAsync <TruckEntity>(p => p.EntityType == EntityType.TRUCK);
                                var drivers = await DocumentDBContext.GetAllItemsAsync <DriverEntity>(p => p.EntityType == EntityType.DRIVER);

                                if (localTrucks.Count() == 0)
                                {
                                    foreach (var t in trucks)
                                    {
                                        dp.TruckRepository.Add(t);
                                    }
                                }

                                if (localDrivers.Count() == 0)
                                {
                                    foreach (var d in drivers)
                                    {
                                        dp.DriverRepository.Add(d);
                                    }
                                }

                                dp.SaveChanges();

                                localTrucks  = dp.TruckRepository.GetAll();
                                localDrivers = dp.DriverRepository.GetAll();

                                if (localTrucks.Count() > 0)
                                {
                                    dp.SettingsRepository.UpsertSetting(TruckClientSettingKeys.TRUCK_ID, localTrucks.First().Id);
                                }

                                if (localDrivers.Count() > 0)
                                {
                                    dp.SettingsRepository.UpsertSetting(TruckClientSettingKeys.DRIVER_ID, localDrivers.First().Id);
                                }

                                dp.SaveChanges();
                            }
                        }
                        catch (Exception exc)
                        {
                            ErrorMessage     = "Unable to connect to cloud.";
                            ShowErrorMessage = true;
                        }

                        try
                        {
                            var syncedSettings = await DocumentDBContext.GetAllItemsAsync <SyncedSettings>(p => p.EntityType == EntityType.SETTING_SUMMARY);
                            var settingsToSave = syncedSettings.FirstOrDefault();

                            var localSyncedSetting = dp.SyncedSettingsRepo.GetAll().FirstOrDefault();

                            settingsToSave.SyncedToCloud = true;
                            if (localSyncedSetting == null)
                            {
                                dp.SyncedSettingsRepo.Add(settingsToSave);
                                dp.SaveChanges();
                            }
                        }
                        catch (Exception exc)
                        {
                            ErrorMessage     = "Unable to retrieve system settings.";
                            ShowErrorMessage = true;
                            Logging.Logger.Log(exc);
                        }
                    }
                    Messenger.Default.Send <BusyMessage>(new Messages.BusyMessage {
                        IsBusy = true, Message = "Settings Saved."
                    });
                    System.Threading.Thread.Sleep(2000);
                    Messenger.Default.Send <BusyMessage>(new Messages.BusyMessage {
                        IsBusy = false, Message = ""
                    });

                    if (shutDown)
                    {
                        Environment.Exit(0);
                    }
                }
                CottonDBMS.TruckApp.Helpers.SettingsHelper.PersistSettingsToAppData();
            });
        }
        public static async Task DoSync()
        {
            try
            {
                if (!hasConnection())
                {
                    return;
                }

                using (var uow = new UnitOfWork())
                {
                    var documentDbSetting = uow.SettingsRepository.FindSingle(x => x.Key == TruckClientSettingKeys.DOCUMENT_DB_KEY);
                    var endpointSetting   = uow.SettingsRepository.FindSingle(x => x.Key == TruckClientSettingKeys.DOCUMENTDB_ENDPOINT);
                    DocumentDBContext.Initialize(endpointSetting.Value, documentDbSetting.Value);

                    //return;
                    if (DocumentDBContext.Initialized)
                    {
                        try
                        {
                            var truck = uow.SettingsRepository.GetCurrentTruck();

                            List <PickupListEntity> pickupLists = new List <PickupListEntity>();

                            Logging.Logger.Log("INFO", "Fetching pickuplists.");
                            if (truck != null)
                            {
                                //process deleted documents - this mainly cleans out the Docs to process table
                                //except for PickupLists if the truck deleted a pickup list a Release request doc is put in the cloud
                                //so the gin can remove the truck assignment
                                List <TruckPickupListRelease> releaseDocs = new List <TruckPickupListRelease>();

                                //get all lists that have been released by this truck previously
                                await processDeletedDocuments(uow, token, truck.Id, releaseDocs);

                                var cloudReleaseDocs = await DocumentDBContext.GetAllItemsAsync <TruckPickupListRelease>(x => x.TruckID == truck.Id);

                                releaseDocs.AddRange(cloudReleaseDocs);
                                var tempLists = await DocumentDBContext.GetAllItemsAsync <PickupListEntity>(p => p.EntityType == EntityType.PICKUPLIST && p.Source == InputSource.GIN && p.AssignedTruckIDs.Contains(truck.Id), 100);

                                foreach (var list in tempLists)  //only add lists that have not been released by truck
                                {
                                    if (!releaseDocs.Any(x => x.PickupListID == list.Id))
                                    {
                                        pickupLists.Add(list);
                                    }
                                }
                            }

                            //immediately mark lists that have been downloaded
                            TruckListsDownloaded document = new TruckListsDownloaded();
                            document.Id                    = "TRUCKDOWNLOADS_" + truck.Id;
                            document.Name                  = truck.Id;
                            document.Source                = InputSource.TRUCK;
                            document.SyncedToCloud         = true;
                            document.Created               = DateTime.UtcNow;
                            document.PickupListsDownloaded = new List <string>();
                            document.PickupListsDownloaded.AddRange(pickupLists.Select(x => x.Id).ToArray());
                            await DocumentDBContext.UpsertItemAsync <TruckListsDownloaded>(document);


                            var driver = uow.SettingsRepository.GetCurrentDriver();

                            if (truck == null || driver == null)
                            {
                                return;                                   //only sync if a truck and driver is configured
                            }
                            //pull down clients/farms/fields/trucks and pickuplists
                            Logging.Logger.Log("INFO", "Downloading  data.");
                            var clients = await DocumentDBContext.GetAllItemsAsync <ClientEntity>(p => p.EntityType == EntityType.CLIENT && p.Source == InputSource.GIN, 500);

                            var farms = await DocumentDBContext.GetAllItemsAsync <FarmEntity>(p => p.EntityType == EntityType.FARM && p.Source == InputSource.GIN, 500);

                            var fields = await DocumentDBContext.GetAllItemsAsync <FieldEntity>(p => p.EntityType == EntityType.FIELD && p.Source == InputSource.GIN, 500);

                            var trucks = await DocumentDBContext.GetAllItemsAsync <TruckEntity>(p => p.EntityType == EntityType.TRUCK);

                            var drivers = await DocumentDBContext.GetAllItemsAsync <DriverEntity>(p => p.EntityType == EntityType.DRIVER);

                            var syncedSettings = await DocumentDBContext.GetAllItemsAsync <SyncedSettings>(p => p.EntityType == EntityType.SETTING_SUMMARY);

                            var clientIdsToIgnore = new List <string>();
                            clientIdsToIgnore.Add(GUIDS.UNASSIGNED_CLIENT_ID);

                            var farmIdsToIgnore = new List <string>();
                            farmIdsToIgnore.Add(GUIDS.UNASSIGNED_FARM_ID);

                            var fieldIdsToIgnore = new List <string>();
                            fieldIdsToIgnore.Add(GUIDS.UNASSIGNED_FIELD_ID);

                            var listIdsToIgnore = new List <string>();
                            listIdsToIgnore.Add(GUIDS.UNASSIGNED_LIST_ID);


                            Logging.Logger.Log("INFO", "Fetching local  data.");
                            var localClients        = uow.ClientRepository.GetAll().Where(c => c.Id != GUIDS.UNASSIGNED_CLIENT_ID);
                            var localFarms          = uow.FarmRepository.GetAll().Where(c => c.Id != GUIDS.UNASSIGNED_FARM_ID);
                            var localFields         = uow.FieldRepository.GetAll().Where(c => c.Id != GUIDS.UNASSIGNED_FIELD_ID);
                            var localSyncedSettings = uow.SyncedSettingsRepo.GetAll();
                            var localPickupLists    = uow.PickupListRepository.GetAll(new string[] { "DownloadedToTrucks", "AssignedTrucks", "Field.Farm.Client" }).Where(c => c.Id != GUIDS.UNASSIGNED_LIST_ID);
                            var localModules        = uow.ModuleRepository.GetAll(new string[] { "Field.Farm.Client", "PickupList" });
                            var localDrivers        = uow.DriverRepository.GetAll();
                            var localTrucks         = uow.TruckRepository.GetAll();

                            var pickUpListIds = pickupLists.Select(t => t.Id).Distinct().ToArray();

                            Logging.Logger.Log("INFO", "Fetching modules");

                            //TODO PICKUPLIST ID
                            var modules = await DocumentDBContext.GetAllItemsAsync <ModuleEntity>(p => p.PickupListId != null && pickUpListIds.Contains(p.PickupListId) && p.EntityType == EntityType.MODULE, 50000);

                            Logging.Logger.Log("INFO", "Computing records to delete.");
                            var fieldsToRemove  = localFields.Where(f => !fields.Any(x => x.Id == f.Id)).ToList();
                            var farmsToRemove   = localFarms.Where(f => !farms.Any(x => x.Id == f.Id)).ToList();
                            var clientsToRemove = localClients.Where(f => !clients.Any(x => x.Id == f.Id)).ToList();
                            var trucksToRemove  = localTrucks.Where(t => !trucks.Any(x => x.Id == t.Id)).ToList();
                            var driversToRemove = localDrivers.Where(d => !drivers.Any(x => x.Id == d.Id)).ToList();
                            var listsToRemove   = localPickupLists.Where(p => !pickupLists.Any(x => x.Id == p.Id)).ToList();

                            if (token.IsCancellationRequested)
                            {
                                return;
                            }

                            //if there are items that were deleted at gin but got linked to truck entered data before
                            //truck data was synced then mark records to be sent to gin again to preserve
                            //data integrity
                            if (truck != null && trucksToRemove.Any(t => t.Id == truck.Id))
                            {
                                truck.Source  = InputSource.TRUCK;
                                truck.Updated = DateTime.UtcNow;
                                uow.TruckRepository.Update(truck);
                                uow.SaveChanges();
                            }

                            if (token.IsCancellationRequested)
                            {
                                return;
                            }

                            if (driver != null && driversToRemove.Any(d => d.Id == driver.Id))
                            {
                                driver.Source  = InputSource.TRUCK;
                                driver.Updated = DateTime.UtcNow;
                                uow.DriverRepository.Update(driver);
                                uow.SaveChanges();
                            }

                            ///////////// THIS SECTION COULD PROBABLY BE REMOVED SINCE WE ARE PREVENTING DELETE OF LISTS ONCE DOWNLOADED //////////////////////
                            foreach (var list in listsToRemove) //if list was removed at gin but had modules added, force it to be re-added
                            {
                                bool canDelete     = true;
                                var  cloudDocument = await DocumentDBContext.GetItemAsync <PickupListEntity>(list.Id);

                                //make sure modules get put back in cloud for reassignment
                                //TODO PICKUPLISTID
                                foreach (var m in localModules.Where(m => m.PickupListId == list.Id))
                                {
                                    var eventsWithSerial = uow.AggregateEventRepository.FindMatching(evt => evt.SerialNumber == m.Name).ToList();
                                    if (eventsWithSerial.Count() > 0)
                                    {
                                        canDelete = false;
                                        m.Source  = InputSource.TRUCK;
                                        m.Updated = DateTime.UtcNow;
                                        uow.ModuleRepository.Update(m);
                                    }
                                }

                                //TODO PICKUPLISTID
                                if (localModules.Any(m => m.PickupListId == list.Id) && !canDelete)
                                {
                                    list.Source  = InputSource.TRUCK;
                                    list.Updated = DateTime.UtcNow;
                                    uow.PickupListRepository.Update(list);

                                    if (cloudDocument != null) //list is in cloud but this truck was removed - add to ignored list to prevent overwriting
                                    {
                                        listIdsToIgnore.Add(list.Id);
                                    }
                                }
                            }
                            uow.SaveChanges();

                            foreach (var list in localPickupLists.Where(p => p.Source == InputSource.TRUCK))
                            {
                                if (token.IsCancellationRequested)
                                {
                                    return;
                                }

                                var field = localFields.SingleOrDefault(x => x.Id == list.FieldId);
                                if (field != null && fieldsToRemove.Any(x => x.Id == field.Id))
                                {
                                    field.Source  = InputSource.TRUCK;
                                    field.Updated = DateTime.UtcNow;
                                    uow.FieldRepository.Update(field);

                                    if (farmsToRemove.Any(x => x.Id == field.FarmId))
                                    {
                                        field.Farm.Source = InputSource.TRUCK;
                                        field.Updated     = DateTime.UtcNow;
                                        uow.FarmRepository.Update(field.Farm);
                                    }

                                    if (clientsToRemove.Any(x => x.Id == field.Farm.Client.Id))
                                    {
                                        field.Farm.Client.Source  = InputSource.TRUCK;
                                        field.Farm.Client.Updated = DateTime.UtcNow;
                                    }
                                }
                            }
                            uow.SaveChanges();

                            ///////////// THE ABOVE SECTION COULD PROBABLY BE REMOVED SINCE WE ARE PREVENTING DELETE OF LISTS ONCE DOWNLOADED //////////////////////

                            if (token.IsCancellationRequested)
                            {
                                return;
                            }

                            await pushEntitiesOfType <DriverEntity>(uow, uow.DriverRepository, token, drivers, new List <string>());
                            await pushEntitiesOfType <TruckEntity>(uow, uow.TruckRepository, token, trucks, new List <string>());

                            await pushEntitiesOfType <ClientEntity>(uow, uow.ClientRepository, token, clients, clientIdsToIgnore);
                            await pushEntitiesOfType <FarmEntity>(uow, uow.FarmRepository, token, farms, farmIdsToIgnore);
                            await pushEntitiesOfType <FieldEntity>(uow, uow.FieldRepository, token, fields, fieldIdsToIgnore);
                            await pushEntitiesOfType <PickupListEntity>(uow, uow.PickupListRepository, token, pickupLists, listIdsToIgnore);

                            await pushModules(uow, uow.ModuleRepository, token, modules);

                            if (token.IsCancellationRequested)
                            {
                                return;
                            }

                            using (var addWork = new UnitOfWork())
                            {
                                addWork.DisableChangeTracking();
                                addEntitiesOfType <DriverEntity>(addWork, addWork.DriverRepository, token, drivers, localDrivers);
                                addEntitiesOfType <TruckEntity>(addWork, addWork.TruckRepository, token, trucks, localTrucks);
                                addEntitiesOfType <ClientEntity>(addWork, addWork.ClientRepository, token, clients, localClients);
                                addEntitiesOfType <FarmEntity>(addWork, addWork.FarmRepository, token, farms, localFarms);
                                addEntitiesOfType <FieldEntity>(addWork, addWork.FieldRepository, token, fields, localFields);
                                addEntitiesOfType <PickupListEntity>(addWork, addWork.PickupListRepository, token, pickupLists, localPickupLists);
                                addEntitiesOfType <SyncedSettings>(addWork, addWork.SyncedSettingsRepo, token, syncedSettings, localSyncedSettings);
                                addEntitiesOfType <ModuleEntity>(addWork, addWork.ModuleRepository, token, modules, localModules);
                            }

                            if (token.IsCancellationRequested)
                            {
                                return;
                            }

                            using (var updateWork = new UnitOfWork())
                            {
                                updateWork.DisableChangeTracking();
                                updateEntitiesOfType <DriverEntity>(updateWork, updateWork.DriverRepository, token, drivers, localDrivers, false);
                                updateEntitiesOfType <TruckEntity>(updateWork, updateWork.TruckRepository, token, trucks, localTrucks, true);
                                updateEntitiesOfType <ClientEntity>(updateWork, updateWork.ClientRepository, token, clients, localClients, false);
                                updateEntitiesOfType <FarmEntity>(updateWork, updateWork.FarmRepository, token, farms, localFarms, false);
                                updateEntitiesOfType <FieldEntity>(updateWork, updateWork.FieldRepository, token, fields, localFields, false);
                                updateEntitiesOfType <PickupListEntity>(updateWork, updateWork.PickupListRepository, token, pickupLists, localPickupLists, false);
                                updateEntitiesOfTypeIfNewer <ModuleEntity>(updateWork, updateWork.ModuleRepository, token, modules, localModules, false);
                                updateEntitiesOfType <SyncedSettings>(updateWork, updateWork.SyncedSettingsRepo, token, syncedSettings, localSyncedSettings, false);
                            }

                            if (token.IsCancellationRequested)
                            {
                                return;
                            }

                            deleteEntitiesOfType <DriverEntity>(uow, uow.DriverRepository, token, drivers);
                            deleteEntitiesOfType <TruckEntity>(uow, uow.TruckRepository, token, trucks);
                            deleteEntitiesOfType <ModuleEntity>(uow, uow.ModuleRepository, token, modules);
                            deleteEntitiesOfType <PickupListEntity>(uow, uow.PickupListRepository, token, pickupLists);
                            deleteEntitiesOfType <FieldEntity>(uow, uow.FieldRepository, token, fields);
                            deleteEntitiesOfType <FarmEntity>(uow, uow.FarmRepository, token, farms);
                            deleteEntitiesOfType <ClientEntity>(uow, uow.ClientRepository, token, clients);

                            cleanDupedModules(uow, uow.ModuleRepository, token);


                            if (truck != null)
                            {
                                //send aggregate events to cloud
                                Logging.Logger.Log("INFO", "Send aggregate events");
                                foreach (var moduleEvent in uow.AggregateEventRepository.GetDirtyOrderedByTime())
                                {
                                    if (token.IsCancellationRequested)
                                    {
                                        return;
                                    }
                                    if (truck != null)
                                    {
                                        moduleEvent.TruckID = truck.Id;
                                    }
                                    if (driver != null)
                                    {
                                        moduleEvent.DriverID = driver.Id;
                                    }
                                    moduleEvent.Source = InputSource.TRUCK;

                                    //lookup module
                                    var module = uow.ModuleRepository.FindSingle(m => m.Name == moduleEvent.SerialNumber, "Field.Farm.Client", "PickupList");

                                    //add on field/farm/client/pickup list info it may be needed to re-create list at gin
                                    if (module != null)
                                    {
                                        moduleEvent.PickupListId   = module.PickupListId;
                                        moduleEvent.PickupListName = module.ListName;

                                        if (module.Field != null)
                                        {
                                            moduleEvent.FarmId = module.Field.FarmId;
                                        }

                                        moduleEvent.FarmName  = module.FarmName;
                                        moduleEvent.FieldId   = module.FieldId;
                                        moduleEvent.FieldName = module.FieldName;
                                        moduleEvent.ModuleId  = module.Id;

                                        if (module.Field.Farm != null)
                                        {
                                            moduleEvent.ClientId = module.Field.Farm.ClientId;
                                        }

                                        moduleEvent.ClientName = module.ClientName;
                                    }

                                    await DocumentDBContext.UpsertItemAsync <AggregateEvent>(moduleEvent);

                                    uow.AggregateEventRepository.Update(moduleEvent, true);
                                    uow.SaveChanges();
                                }

                                if (token.IsCancellationRequested)
                                {
                                    return;
                                }

                                //send list of pickup lists this truck has
                                Logging.Logger.Log("INFO", "Send list of pickup lists this truck has downloaded.");
                                var lists = uow.PickupListRepository.FindMatching(t => t.AssignedTrucks.Any(x => x.Id == truck.Id), new string[] { "AssignedTrucks" });
                                TruckListsDownloaded document2 = new TruckListsDownloaded();
                                document2.Id                    = "TRUCKDOWNLOADS_" + truck.Id;
                                document2.Name                  = truck.Id;
                                document2.Source                = InputSource.TRUCK;
                                document2.SyncedToCloud         = true;
                                document2.Created               = DateTime.UtcNow;
                                document2.PickupListsDownloaded = new List <string>();
                                document2.PickupListsDownloaded.AddRange(lists.Select(x => x.Id).ToArray());
                                await DocumentDBContext.UpsertItemAsync <TruckListsDownloaded>(document2);
                            }
                        }
                        catch (Exception exc)
                        {
                            Logging.Logger.Log(exc);
                        }
                    }
                }
            }
            catch (Exception outerExc)
            {
                Logging.Logger.Log(outerExc);
            }
        }