| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 | 
							- using System;
 
- using System.Collections.Generic;
 
- using System.Linq;
 
- using System.Threading.Tasks;
 
- using Comal.Classes;
 
- using InABox.Clients;
 
- using InABox.Core;
 
- using InABox.Mobile;
 
- using InABox.Rpc;
 
- namespace PRS.Mobile
 
- {
 
-     public class GPSEventArgs : EventArgs
 
-     {
 
-         
 
-     }
 
-     
 
-     public delegate void GPSLocationUpdatedEvent(GPSEventArgs args);
 
-     public class BluetoothEventArgs : EventArgs
 
-     {
 
-         
 
-     }
 
-     public delegate void BluetoothScanFinishedEvent(BluetoothEventArgs args);
 
-     
 
-     public class DataModel : IModelHost
 
-     {
 
-         public event GPSLocationUpdatedEvent GPSLocationUpdated;
 
-         public event BluetoothScanFinishedEvent BluetoothScanFinished;
 
-         /// <summary>
 
-         /// All Active Employees of the Company
 
-         /// </summary>
 
-         public EmployeeModel Employees { get; private set; }
 
-         /// <summary>
 
-         /// EmployeeDetails for Currently Logged in User
 
-         /// </summary>
 
-         public EmployeeDetailModel Me { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// All Employee Teams for the Company
 
-         /// Should this be just teams I am a part of, or all available teams
 
-         /// Need to implement a Security Token to differentiate
 
-         /// </summary>
 
-         public EmployeeTeamModel EmployeeTeams { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// Current Employee Form Instances for this employee
 
-         /// </summary>
 
-         public EmployeeFormModel EmployeeForms { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// Available Activity Codes for this Employee
 
-         /// </summary>
 
-         public ActivityModel Activities { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// All Available Contacts - used in Deliveries
 
-         /// </summary>
 
-         public ContactModel Contacts { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// All Defined Bluetooth-enabled Gates
 
-         /// </summary>
 
-         public BluetoothGateModel BluetoothGates { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// Unprocessed Timesheets for Currently Logged in User
 
-         /// </summary>
 
-         public TimeSheetModel TimeSheets { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// List of Jobs that Currently Logged in User has access To
 
-         /// </summary>
 
-         public JobModel Jobs { get; private set; }
 
-         /// <summary>
 
-         /// List of Assignments for ??? need to specify this.
 
-         /// Can I see other people's assignments?  (Security Token)
 
-         /// How far back / forward can I look.
 
-         /// This smells Transient, or maybe split into lookups (for all)
 
-         /// and shells (for mine)
 
-         /// Possibly need a back/forward window as well?
 
-         /// </summary>
 
-         public AssignmentModel Assignments { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// Master Product Catalogue for the company
 
-         /// This should be split into Lookups and Shells
 
-         /// </summary>
 
-         public ProductModel Products { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// Master Product Groups List (Lookup?)
 
-         /// </summary>
 
-         public ProductGroupModel ProductGroups { get; private set; }
 
-         /// <summary>
 
-         /// All GPS Tracker Devices registered by the company
 
-         /// </summary>
 
-         public GPSTrackerModel GPSTrackers { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// Master Equipment Register
 
-         /// </summary>
 
-         public EquipmentModel Equipment { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// Master List of Equipment Groups
 
-         /// </summary>
 
-         public EquipmentGroupModel EquipmentGroups { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// List of all Deliveries made in the last 90 days
 
-         /// hmmm.. should be configurable?
 
-         /// </summary>
 
-         public DeliveryModel Deliveries { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// List of all available Delivery Barcodes
 
-         /// hmmm.. should be configurable?
 
-         /// </summary>
 
-         public DeliveryItemModel DeliveryItems { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// My Notifications (open only?)
 
-         /// </summary>
 
-         public NotificationModel Notifications { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// All Tasks I am subscribed to
 
-         /// </summary>
 
-         public KanbanModel Kanbans { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// All Kanban Types
 
-         /// </summary>
 
-         public KanbanTypeModel KanbanTypes { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// Available Form Library - this includes all "Applies To" values
 
-         /// You can filter to a specific type by using the "Search" function
 
-         /// </summary>
 
-         public DigitalFormModel DigitalForms { get; private set; }
 
-         
 
-         // The list of open task-kased forms for the current user
 
-         // Specifically for us in the "Forms" module
 
-         // This overlaps the "Task" module a fair amount, but it provides
 
-         // an alternative paradigm for tasks
 
-         public KanbanFormModel KanbanForms { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// List of Employees, along with Clock on / off status
 
-         /// </summary>
 
-         public InOutModel InOut { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// List of all available Document Set Tags
 
-         /// </summary>
 
-         public JobDocumentSetTagModel DocumentSetTags { get; private set; }
 
-         
 
-         /// <summary>
 
-         /// List of Open Purchase Orders
 
-         /// </summary>
 
-         public PurchaseOrderModel PurchaseOrders { get; private set; }
 
-         
 
-         public ManufacturingFactoryModel ManufacturingFactories { get; private set; }
 
-         
 
-         public ManufacturingPacketModel ManufacturingPackets { get; private set; }
 
-         
 
-         public DataModel()
 
-         {
 
-             Me = new EmployeeDetailModel(this,
 
-                 () => new Filter<Employee>(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid)
 
-             );
 
-             
 
-             Employees = new EmployeeModel(this,
 
-                 () => LookupFactory.DefineFilter<Employee>());
 
-             EmployeeTeams = new EmployeeTeamModel(this,
 
-                 () => new Filter<EmployeeTeam>(x => x.EmployeeLink.ID)
 
-                     .InQuery(LookupFactory.DefineFilter<Employee>(), x => x.ID)
 
-             );
 
-             EmployeeForms = new EmployeeFormModel(this,
 
-                 () => new Filter<EmployeeForm>(x => x.Parent.ID).IsEqualTo(App.Data.Me.ID)
 
-             );
 
-             
 
-             Activities = new ActivityModel(this,
 
-                 () => new Filter<EmployeeActivity>(x => x.Employee.ID).IsEqualTo(App.Data.Me.ID)
 
-             );
 
-             
 
-             InOut = new InOutModel(this,
 
-                 () => new Filters<Employee>()
 
-                     .Add(LookupFactory.DefineFilter<Employee>())
 
-                     .Add(new Filter<Employee>(x=>x.ID).IsNotEqualTo(App.Data.Me.ID).And(x=>x.ShowOnInOutBoard).IsEqualTo(true))
 
-                     .Combine()
 
-             );
 
-             Jobs = new JobModel(this, MyJobsFilter);
 
-             
 
-             Products = new ProductModel(this,
 
-                 LookupFactory.DefineFilter<Product>);
 
-             ProductGroups = new ProductGroupModel(this,
 
-                 LookupFactory.DefineFilter<ProductGroup>);
 
-             GPSTrackers = new GPSTrackerModel(this,
 
-                 LookupFactory.DefineFilter<GPSTracker>);
 
-             Equipment = new EquipmentModel(this,
 
-                 () =>
 
-                 {
 
-                     var filters = new Filters<Equipment>();
 
-                     filters.Add(LookupFactory.DefineFilter<Equipment>());
 
-                     if (!Security.IsAllowed<CanViewPrivateEquipment>())
 
-                         filters.Add(new Filter<Equipment>(x => x.Private).IsEqualTo(false));
 
-                     return filters.Combine();
 
-                 },
 
-                 "equipment.index");
 
-             EquipmentGroups = new EquipmentGroupModel(this,
 
-                 LookupFactory.DefineFilter<EquipmentGroup>);
 
-             Deliveries = new DeliveryModel(this, () => null);
 
-             DeliveryItems = new DeliveryItemModel(this,
 
-                 LookupFactory.DefineFilter<DeliveryItem>
 
-             );
 
-             
 
-             Notifications = new NotificationModel(this, 
 
-                 () => new Filter<Notification>(x=>x.Employee.ID).IsEqualTo(App.Data.Me.ID)
 
-                     .And(new Filter<Notification>(x=>x.Closed).IsEqualTo(DateTime.MinValue)
 
-                         .Or(x=>x.Created).IsGreaterThanOrEqualTo(DateTime.Today.AddDays(-90)))
 
-             );
 
-             
 
-             TimeSheets = new TimeSheetModel(this,
 
-                 () => new Filter<TimeSheet>(x=>x.Processed).IsEqualTo(DateTime.MinValue)
 
-                     .And(x=>x.EmployeeLink.ID).IsEqualTo(App.Data.Me.ID));
 
-             Assignments = new AssignmentModel(this,
 
-                 () => new Filter<Assignment>(x => x.Date).IsGreaterThanOrEqualTo(DateTime.Today.AddDays(-90))
 
-                     .And(x => x.Date).IsLessThanOrEqualTo(DateTime.Today.AddDays(90))
 
-             );
 
-             
 
-             Contacts = new ContactModel(this, 
 
-                 () => LookupFactory.DefineFilter<Contact>());
 
-             Kanbans = new KanbanModel(this,
 
-                 () => new Filter<Kanban>(x => x.ID).InQuery(
 
-                     new Filter<KanbanSubscriber>(x=>x.Employee.ID).IsEqualTo(App.Data.Me.ID), x=>x.Kanban.ID)
 
-                 );
 
-             
 
-             KanbanTypes = new KanbanTypeModel(this, () => null);
 
-             BluetoothGates = new BluetoothGateModel(this,
 
-                 () => new Filter<JobTracker>(x => x.Active).IsEqualTo(true)
 
-             );
 
-             DigitalForms = new DigitalFormModel(this,
 
-                 () => new Filter<EmployeeDigitalForm>(x => x.Employee.ID).IsEqualTo(App.Data.Me.ID)
 
-                     .And(x => x.Form.Active).IsEqualTo(true)
 
-             );
 
-             KanbanForms = new KanbanFormModel(this,
 
-                 () => new Filter<KanbanForm>(x=>x.Parent.EmployeeLink.ID).IsEqualTo(App.Data.Me.ID)
 
-                     .And(x=>x.FormCompleted).IsEqualTo(DateTime.MinValue)
 
-             );
 
-             DocumentSetTags = new JobDocumentSetTagModel(this,
 
-                 () => null
 
-             );
 
-             PurchaseOrders = new PurchaseOrderModel(this,
 
-                 () => new Filter<PurchaseOrder>(x => x.ClosedDate).IsEqualTo(DateTime.MinValue)
 
-             );
 
-             ManufacturingPackets = new ManufacturingPacketModel(this,
 
-                 () => new Filter<ManufacturingPacket>(x => x.Archived).IsEqualTo(DateTime.MinValue)
 
-             );
 
-             ManufacturingFactories = new ManufacturingFactoryModel(this,
 
-                 () => null
 
-             );
 
-         }
 
-         private static Filter<Job> MyJobsFilter()
 
-         {
 
-             return Security.IsAllowed<CanViewAllJobs>()
 
-                 ? new Filter<Job>(X => X.Completed).IsEqualTo(DateTime.MinValue)
 
-                     .And(x => x.JobStatus.Active).IsEqualTo(true)
 
-                 : new Filter<Job>(X => X.Completed).IsEqualTo(DateTime.MinValue)
 
-                     .And(x => x.JobStatus.Active).IsEqualTo(true)
 
-                     .And(x => x.ID).InQuery(
 
-                         new Filter<JobEmployee>(x => x.EmployeeLink.ID).IsEqualTo(App.Data.Me.ID),
 
-                         x => x.JobLink.ID
 
-                     );
 
-         }
 
-         public void Setup()
 
-         {
 
-             _connected = true;
 
-             
 
-             Security.CheckTokens();
 
-             Me.Refresh(true);
 
-             
 
-             App.Bluetooth.OnScanFinished += OnBluetoothScanFinished;
 
-             App.GPS.OnLocationFound += OnGPSLocationFound;
 
-             
 
-             App.Transport.OnOpen += OnTransportConnected;
 
-             App.Transport.OnClose += OnTransportDisconnected;
 
-             
 
-         }
 
-         public bool IsConnected() => _connected;
 
-         private bool _connected;
 
-         public event TransportDisconnectedEvent TransportDisconnected;
 
-         
 
-         public event TransportConnectedEvent TransportConnected;
 
-         
 
-         private void OnTransportDisconnected(IRpcTransport transport, RpcTransportCloseArgs e)
 
-         {
 
-             _connected = false;
 
-             TransportDisconnected?.Invoke(new TransportDisconnectedEventArgs());
 
-             Task.Run(() =>
 
-             {
 
-                 while (!_connected)
 
-                     App.Transport.Connect();
 
-                 var status = ClientFactory.Validate(ClientFactory.SessionID);
 
-             });
 
-         }
 
-         private void OnTransportConnected(IRpcTransport transport, RpcTransportOpenArgs e)
 
-         {
 
-             _connected = true;
 
-             TransportConnected?.Invoke(new TransportConnectedEventArgs());
 
-         }
 
-         private GPSTrackerLocation GetGPSTrackerUpdate(string deviceid, InABox.Core.Location location,
 
-             TimeSpan threshold, double distance)
 
-         {
 
-             GPSTrackerShell tracker = GPSTrackers.FirstOrDefault(x => x.DeviceID.Equals(deviceid));
 
-             if (tracker != null)
 
-             {
 
-                 if ((tracker.Timestamp < location.Timestamp.Subtract(threshold)) || (tracker.Location.DistanceTo(location, UnitOfLength.Kilometers) > distance))
 
-                 {
 
-                     GPSTrackerLocation gpsTrackerLocation = new GPSTrackerLocation();
 
-                     gpsTrackerLocation.DeviceID = tracker.DeviceID;
 
-                     gpsTrackerLocation.Tracker.ID = tracker.ID;
 
-                     gpsTrackerLocation.Location = location; 
 
-                     return gpsTrackerLocation;
 
-                 }
 
-                 
 
-             }
 
-             return null;
 
-         }
 
-         
 
-         private InABox.Core.Location _lastgpslocation = new InABox.Core.Location();
 
-         
 
-         private void OnGPSLocationFound(LocationServices sender)
 
-         {
 
-             if (_lastgpslocation.Timestamp < DateTime.Now.Subtract(TimeSpan.FromMinutes(2)))
 
-             {
 
-                 
 
-                 var devicelocation = new InABox.Core.Location()
 
-                 {
 
-                     Latitude = App.GPS.Latitude,
 
-                     Longitude = App.GPS.Longitude,
 
-                     Timestamp = App.GPS.TimeStamp,
 
-                     Address = App.GPS.Address
 
-                 };    
 
-                 GPSTrackers.Refresh(false);
 
-                 var update = GetGPSTrackerUpdate(MobileUtils.GetDeviceID(), devicelocation, TimeSpan.FromMinutes(2), 0.1);
 
-                 if (update != null)
 
-                     new Client<GPSTrackerLocation>().Save(update, "Updated via Mobile Device", (o, e) => { });
 
-             }
 
-             GPSLocationUpdated?.Invoke(new GPSEventArgs());
 
-         }
 
-         
 
-         private void OnBluetoothScanFinished(Bluetooth sender)
 
-         {
 
-             UploadTiles();
 
-             BluetoothScanFinished?.Invoke(new BluetoothEventArgs());
 
-         }
 
-         private void UploadTiles()
 
-         {
 
-             try
 
-             {
 
-                 if (App.GPS.Latitude.Equals(0.0F) && App.GPS.Longitude.Equals(0.0F))
 
-                     return;
 
-                 if (App.Bluetooth.DetectedBlueToothMACAddresses.Count == 0)
 
-                     return;
 
-                 var devicelocation = new InABox.Core.Location()
 
-                 {
 
-                     Latitude = App.GPS.Latitude,
 
-                     Longitude = App.GPS.Longitude,
 
-                     Timestamp = App.GPS.TimeStamp,
 
-                     Address = App.GPS.Address
 
-                 };
 
-                 GPSTrackers.Refresh(true);
 
-                 List<GPSTrackerLocation> updates = new List<GPSTrackerLocation>();
 
-                 foreach (String deviceid in App.Bluetooth.DetectedBlueToothMACAddresses)
 
-                 {
 
-                     var update = GetGPSTrackerUpdate(deviceid, devicelocation, TimeSpan.FromMinutes(2), 0.1);
 
-                     if (update != null)
 
-                         updates.Add(update);
 
-                 }
 
-                 if (updates.Any())
 
-                     new Client<GPSTrackerLocation>().Save(updates, $"Updated by Mobile {MobileUtils.GetDeviceID()}",
 
-                         (o, e) => { });
 
-             }
 
-             catch (Exception ex)
 
-             {
 
-                 MobileLogging.Log($"UploadTiles() {ex.Message} \n {ex.StackTrace}");
 
-             }
 
-         }
 
-         
 
-         
 
-         public int EmployeeFormsToDo { get; set; }
 
-         
 
-         public int QualificationsNeedingAttention { get; set; }
 
-         public bool UpdateHRItemsNeedingAttention()
 
-         {
 
-             try
 
-             {
 
-                 EmployeeFormsToDo = 0;
 
-                 QualificationsNeedingAttention = 0;
 
-                 CoreTable table = new Client<EmployeeQualification>().Query(
 
-                     new Filter<EmployeeQualification>(x => x.Employee.ID).IsEqualTo(Me.ID),
 
-                     new Columns<EmployeeQualification>(
 
-                         x => x.ID, //0
 
-                         x => x.Expiry, //1
 
-                         x => x.FrontPhoto.ID //2
 
-                         )
 
-                     );
 
-                 if (table.Rows.Any())
 
-                 {
 
-                     List<Guid> IDs = new List<Guid>();
 
-                     foreach (CoreRow row in table.Rows)
 
-                     {
 
-                         List<object> list = row.Values;
 
-                         if (list[0] == null) { list[0] = Guid.Empty; } //0
 
-                         if (list[1] == null) { list[1] = DateTime.MinValue; } //1
 
-                         if (list[2] == null) { list[2] = Guid.Empty; } //2
 
-                         if (DateTime.Parse(list[1].ToString()) <= DateTime.Today.AddDays(30))
 
-                         {
 
-                             if (!Guid.Parse(list[2].ToString()).Equals(Guid.Empty))
 
-                             {
 
-                                 CoreTable innerTable = new Client<Document>().Query(
 
-                                     new Filter<Document>(x => x.ID).IsEqualTo(Guid.Parse(list[2].ToString())),
 
-                                     new Columns<Document>(x => x.Created)
 
-                                     );
 
-                                 CoreRow innerRow = innerTable.Rows.First();
 
-                                 List<object> innerList = innerRow.Values;
 
-                                 if (DateTime.Parse(innerList[0].ToString()) < DateTime.Today.AddDays(-7)) //if photo was added more than 7 days ago, added to list needing attention
 
-                                 {
 
-                                     if (!IDs.Contains(Guid.Parse(list[0].ToString())))
 
-                                         IDs.Add(Guid.Parse(list[0].ToString()));
 
-                                 }
 
-                             }
 
-                             else
 
-                             {
 
-                                 if (!IDs.Contains(Guid.Parse(list[0].ToString())))
 
-                                     IDs.Add(Guid.Parse(list[0].ToString()));
 
-                             }
 
-                         }
 
-                         if (Guid.Parse(list[2].ToString()).Equals(Guid.Empty))
 
-                         {
 
-                             if (!IDs.Contains(Guid.Parse(list[0].ToString())))
 
-                                 IDs.Add(Guid.Parse(list[0].ToString()));
 
-                         }
 
-                     }
 
-                     QualificationsNeedingAttention = IDs.Count;
 
-                 }
 
-                 CoreTable table1 = new Client<EmployeeForm>().Query(
 
-                     new Filter<EmployeeForm>(x => x.Parent.ID).IsEqualTo(Me.ID).And
 
-                     (x => x.FormCompleted).IsEqualTo(DateTime.MinValue),
 
-                     new Columns<EmployeeForm>(x => x.FormCompleted)
 
-                     );
 
-                 if (table1.Rows.Any())
 
-                 {
 
-                     EmployeeFormsToDo = table1.Rows.Count;
 
-                 }
 
-                 if (QualificationsNeedingAttention > 0 || EmployeeFormsToDo > 0)
 
-                 {
 
-                     return true;
 
-                 }
 
-                 else
 
-                     return false;
 
-             }
 
-             catch
 
-             {
 
-                 return false;
 
-             }
 
-         }
 
-         public void CheckEmployeeFormsToDo()
 
-         {
 
-             try
 
-             {
 
-                 CoreTable table1 = new Client<EmployeeForm>().Query(
 
-                     new Filter<EmployeeForm>(x => x.Parent.ID).IsEqualTo(Me.ID).And
 
-                     (x => x.FormCompleted).IsEqualTo(DateTime.MinValue),
 
-                     new Columns<EmployeeForm>(x => x.FormCompleted)
 
-                     );
 
-                 if (table1.Rows.Any())
 
-                 {
 
-                     EmployeeFormsToDo = table1.Rows.Count;
 
-                 }
 
-                 else
 
-                 {
 
-                     EmployeeFormsToDo = 0;
 
-                 }
 
-             }
 
-             catch
 
-             {
 
-             }
 
-         }
 
-     }
 
- }
 
 
  |