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; /// /// All Active Employees of the Company /// public EmployeeModel Employees { get; private set; } /// /// EmployeeDetails for Currently Logged in User /// public EmployeeDetailModel Me { get; private set; } /// /// 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 /// public EmployeeTeamModel EmployeeTeams { get; private set; } /// /// Current Employee Form Instances for this employee /// public EmployeeFormModel EmployeeForms { get; private set; } /// /// Available Activity Codes for this Employee /// public ActivityModel Activities { get; private set; } /// /// All Available Contacts - used in Deliveries /// public ContactModel Contacts { get; private set; } /// /// All Defined Bluetooth-enabled Gates /// public BluetoothGateModel BluetoothGates { get; private set; } /// /// Unprocessed Timesheets for Currently Logged in User /// public TimeSheetModel TimeSheets { get; private set; } /// /// List of Jobs that Currently Logged in User has access To /// public JobModel Jobs { get; private set; } /// /// 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? /// public AssignmentModel Assignments { get; private set; } /// /// Master Product Catalogue for the company /// This should be split into Lookups and Shells /// public ProductModel Products { get; private set; } /// /// Master Product Groups List (Lookup?) /// public ProductGroupModel ProductGroups { get; private set; } /// /// All GPS Tracker Devices registered by the company /// public GPSTrackerModel GPSTrackers { get; private set; } /// /// Master Equipment Register /// public EquipmentModel Equipment { get; private set; } /// /// Master List of Equipment Groups /// public EquipmentGroupModel EquipmentGroups { get; private set; } /// /// List of all Deliveries made in the last 90 days /// hmmm.. should be configurable? /// public DeliveryModel Deliveries { get; private set; } /// /// List of all available Delivery Barcodes /// hmmm.. should be configurable? /// public DeliveryItemModel DeliveryItems { get; private set; } /// /// My Notifications (open only?) /// public NotificationModel Notifications { get; private set; } /// /// All Tasks I am subscribed to /// public KanbanModel Kanbans { get; private set; } /// /// All Kanban Types /// public KanbanTypeModel KanbanTypes { get; private set; } /// /// Available Form Library - this includes all "Applies To" values /// You can filter to a specific type by using the "Search" function /// 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; } /// /// List of Employees, along with Clock on / off status /// public InOutModel InOut { get; private set; } /// /// List of all available Document Set Tags /// public JobDocumentSetTagModel DocumentSetTags { get; private set; } /// /// List of Open Purchase Orders /// 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(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid) ); Employees = new EmployeeModel(this, () => LookupFactory.DefineFilter()); EmployeeTeams = new EmployeeTeamModel(this, () => new Filter(x => x.EmployeeLink.ID) .InQuery(LookupFactory.DefineFilter(), x => x.ID) ); EmployeeForms = new EmployeeFormModel(this, () => new Filter(x => x.Parent.ID).IsEqualTo(App.Data.Me.ID) ); Activities = new ActivityModel(this, () => new Filter(x => x.Employee.ID).IsEqualTo(App.Data.Me.ID) ); InOut = new InOutModel(this, () => new Filters() .Add(LookupFactory.DefineFilter()) .Add(new Filter(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); ProductGroups = new ProductGroupModel(this, LookupFactory.DefineFilter); GPSTrackers = new GPSTrackerModel(this, LookupFactory.DefineFilter); Equipment = new EquipmentModel(this, () => { var filters = new Filters(); filters.Add(LookupFactory.DefineFilter()); if (!Security.IsAllowed()) filters.Add(new Filter(x => x.Private).IsEqualTo(false)); return filters.Combine(); }, "equipment.index"); EquipmentGroups = new EquipmentGroupModel(this, LookupFactory.DefineFilter); Deliveries = new DeliveryModel(this, () => null); DeliveryItems = new DeliveryItemModel(this, LookupFactory.DefineFilter ); Notifications = new NotificationModel(this, () => new Filter(x=>x.Employee.ID).IsEqualTo(App.Data.Me.ID) .And(new Filter(x=>x.Closed).IsEqualTo(DateTime.MinValue) .Or(x=>x.Created).IsGreaterThanOrEqualTo(DateTime.Today.AddDays(-90))) ); TimeSheets = new TimeSheetModel(this, () => new Filter(x=>x.Processed).IsEqualTo(DateTime.MinValue) .And(x=>x.EmployeeLink.ID).IsEqualTo(App.Data.Me.ID)); Assignments = new AssignmentModel(this, () => new Filter(x => x.Date).IsGreaterThanOrEqualTo(DateTime.Today.AddDays(-90)) .And(x => x.Date).IsLessThanOrEqualTo(DateTime.Today.AddDays(90)) ); Contacts = new ContactModel(this, () => LookupFactory.DefineFilter()); Kanbans = new KanbanModel(this, () => new Filter(x => x.ID).InQuery( new Filter(x=>x.Employee.ID).IsEqualTo(App.Data.Me.ID), x=>x.Kanban.ID) ); KanbanTypes = new KanbanTypeModel(this, () => null); BluetoothGates = new BluetoothGateModel(this, () => new Filter(x => x.Active).IsEqualTo(true) ); DigitalForms = new DigitalFormModel(this, () => new Filter(x => x.Employee.ID).IsEqualTo(App.Data.Me.ID) .And(x => x.Form.Active).IsEqualTo(true) ); KanbanForms = new KanbanFormModel(this, () => new Filter(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(x => x.ClosedDate).IsEqualTo(DateTime.MinValue) ); ManufacturingPackets = new ManufacturingPacketModel(this, () => new Filter(x => x.Archived).IsEqualTo(DateTime.MinValue) ); ManufacturingFactories = new ManufacturingFactoryModel(this, () => null ); } private static Filter MyJobsFilter() { return Security.IsAllowed() ? new Filter(X => X.Completed).IsEqualTo(DateTime.MinValue) .And(x => x.JobStatus.Active).IsEqualTo(true) : new Filter(X => X.Completed).IsEqualTo(DateTime.MinValue) .And(x => x.JobStatus.Active).IsEqualTo(true) .And(x => x.ID).InQuery( new Filter(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().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 updates = new List(); 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().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().Query( new Filter(x => x.Employee.ID).IsEqualTo(Me.ID), new Columns( x => x.ID, //0 x => x.Expiry, //1 x => x.FrontPhoto.ID //2 ) ); if (table.Rows.Any()) { List IDs = new List(); foreach (CoreRow row in table.Rows) { List 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().Query( new Filter(x => x.ID).IsEqualTo(Guid.Parse(list[2].ToString())), new Columns(x => x.Created) ); CoreRow innerRow = innerTable.Rows.First(); List 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().Query( new Filter(x => x.Parent.ID).IsEqualTo(Me.ID).And (x => x.FormCompleted).IsEqualTo(DateTime.MinValue), new Columns(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().Query( new Filter(x => x.Parent.ID).IsEqualTo(Me.ID).And (x => x.FormCompleted).IsEqualTo(DateTime.MinValue), new Columns(x => x.FormCompleted) ); if (table1.Rows.Any()) { EmployeeFormsToDo = table1.Rows.Count; } else { EmployeeFormsToDo = 0; } } catch { } } } }