using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Threading; using Comal.Classes; using InABox.Clients; using InABox.Configuration; using InABox.Core; using InABox.DynamicGrid; using InABox.DynamicGrid.Spreadsheet; using InABox.WPF; using Microsoft.Office.Interop.Outlook; using Selection = InABox.Core.Selection; namespace PRSDesktop { public class JobPanelSettings : BaseObject, IGlobalConfigurationSettings { [Caption("Milestone Task",IncludePath = false)] public KanbanTypeLink DocumentMilestoneKanbanType { get; set; } public JobPanelSettings() { DocumentMilestoneKanbanType = new KanbanTypeLink(); } } /// /// Interaction logic for JobPanel.xaml /// public partial class JobPanel : UserControl, IPanel { private enum PageIndex { Details = 00, Financials, Documents, Stages, ITPs, BOM, Requisitions, Orders, Designs, Manufacturing, Dispatch, Delivery, Onsite, Kanban, Equipment, Employee, Tracker, Assignment, Timesheet, Form, Invoice, Spreadsheets, Summary } private int CurrentPage = -1; private JobDetails JobDetailsPage; private JobFinancialGrid JobFinancialPage; private JobDocumentSetPanel JobDocumentsPage; private JobStagesPanel JobPlanningPage; private JobITPGrid JobITPPage; private JobBillOfMaterialsPanel JobBillOfMaterialsPage; private JobRequisitionPanel JobRequisitionsPage; private JobDesignList JobDesignsPage; private JobOrderGrid JobOrderPage; private ManufacturingGrid JobManufacturingPage; private ReadyToGoGrid JobReadyToGoPage; private DeliveryPanel JobDeliveriesPage; private DeliveredOnSiteGrid JobOnSitePage; private TaskPanel JobTasksPage; private JobEquipmentGrid JobEquipmentPage; private JobEmployeePanel JobEmployeePage; private JobTrackerGrid JobTrackerPage; private JobAssignmentPanel JobActivitiesPage; private JobTimesheetGrid JobTimeSheetsPage; private JobFormGrid JobFormsPage; private InvoicePanel JobInvoicePage; private JobSpreadsheetGrid JobSpreadsheetPage; private JobSummaryPanel JobSummaryPage; private DateTime lastselection = DateTime.MaxValue; private IDataModelSource modelsource; // User Settings private JobScreenSettings settings; // Global Settings private JobPanelSettings _settings = null; private DispatcherTimer timer; public JobPanel() { InitializeComponent(); } public bool IsReady { get; set; } public Dictionary Selected() { return (PageIndex)JobPages.SelectedIndex switch { PageIndex.Details => JobDetailsPage.Selected(), PageIndex.Financials => JobFinancialPage.Selected(), PageIndex.Documents => JobDocumentsPage.Selected(), PageIndex.Stages => JobPlanningPage.Selected(), PageIndex.ITPs => new Dictionary { { typeof(JobITP).EntityName(), JobITPPage.SelectedRows } }, PageIndex.BOM => new Dictionary { { typeof(JobBillOfMaterials).EntityName(), JobBillOfMaterialsPage.SelectedRows } }, PageIndex.Designs => JobDesignsPage.Selected(), PageIndex.Orders => new Dictionary { { typeof(PurchaseOrderItem).EntityName(), JobOrderPage.SelectedRows } }, PageIndex.Requisitions => new Dictionary { { typeof(JobRequisition).EntityName(), JobRequisitionsPage.Requisitions.SelectedRows } }, PageIndex.Manufacturing => new Dictionary { { typeof(ManufacturingPacket).EntityName(), JobManufacturingPage.SelectedRows } }, PageIndex.Dispatch => new Dictionary { { typeof(DeliveryItem).EntityName(), JobReadyToGoPage.SelectedRows } }, PageIndex.Delivery => new Dictionary { { typeof(Delivery).EntityName(), JobDeliveriesPage.Deliveries.SelectedRows } }, PageIndex.Onsite => new Dictionary { { typeof(DeliveryItem).EntityName(), JobOnSitePage.SelectedRows } }, PageIndex.Kanban => JobTasksPage.Selected(), PageIndex.Equipment => new Dictionary { { typeof(Equipment).EntityName(), JobEquipmentPage.SelectedRows } }, PageIndex.Employee => new Dictionary { { typeof(Employee).EntityName(), JobEmployeePage.Employees.SelectedRows } }, PageIndex.Tracker => new Dictionary { { typeof(GPSTracker).EntityName(), JobTrackerPage.SelectedRows } }, PageIndex.Assignment => new Dictionary { { typeof(Assignment).EntityName(), JobActivitiesPage.Assignments.SelectedRows } }, PageIndex.Timesheet => new Dictionary { { typeof(TimeSheet).EntityName(), JobTimeSheetsPage.SelectedRows } }, PageIndex.Form => new Dictionary { { typeof(JobForm).EntityName(), JobFormsPage.SelectedRows } }, PageIndex.Invoice => new Dictionary { { typeof(Invoice).EntityName(), JobInvoicePage.Invoices.SelectedRows } }, PageIndex.Spreadsheets => new Dictionary { { typeof(JobSpreadsheet).EntityName(), JobSpreadsheetPage.SelectedRows } }, PageIndex.Summary => new Dictionary { { typeof(JobMaterial).EntityName(), JobSummaryPage.Summary.SelectedRows } }, _ => new Dictionary {{ typeof(Job).EntityName(), JobGrid.SelectedRows}} }; } public void Setup() { Task[] settingstasks = new Task[] { Task.Run(() => { _settings = new GlobalConfiguration().Load(); }), Task.Run(() => { settings = new UserConfiguration().Load(); }) }; Task.WaitAll(settingstasks); SplitPanel.View = settings.ViewType == ScreenViewType.Register ? DynamicSplitPanelView.Master : settings.ViewType == ScreenViewType.Details ? DynamicSplitPanelView.Detail : DynamicSplitPanelView.Combined; SplitPanel.AnchorWidth = settings.AnchorWidth; var sc = new Dictionary { { Guid.Empty, "All Jobs" } }; var statuses = new Client().Query(); foreach (var row in statuses.Rows) sc[row.Get(x => x.ID)] = row.Get(x => x.Description); JobStatus.ItemsSource = sc; if (sc.ContainsKey(settings.JobStatus)) JobStatus.SelectedValue = settings.JobStatus; else JobStatus.SelectedValue = sc.Keys.First(); JobGrid.OnSelectItem += JobGrid_OnSelectItem; Financials.Visibility = Security.CanView() ? Visibility.Visible : Visibility.Collapsed; Documents.Visibility = Security.CanView() ? Visibility.Visible : Visibility.Collapsed; Stages.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; ITPs.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; BOM.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Requisitions.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Orders.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Setouts.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Manufacturing.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Dispatch.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Deliveries.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; OnSite.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Tasks.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; EquipmentTab.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Employees.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Trackers.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Assignments.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Timesheets.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; Forms.Visibility = Security.CanView() ? Visibility.Visible : Visibility.Collapsed; Invoices.Visibility = Security.CanView() ? Visibility.Visible : Visibility.Collapsed; Spreadsheets.Visibility = Security.CanView() ? Visibility.Visible : Visibility.Collapsed; Summary.Visibility = ClientFactory.IsSupported() ? Visibility.Visible : Visibility.Collapsed; JobGrid.ColumnsTag = settings.ViewType == ScreenViewType.Register ? settings.ViewType.ToString() : ""; JobGrid.Refresh(true, false); timer = new DispatcherTimer(); timer.Tick += Timer_Tick; timer.Interval = new TimeSpan(0, 0, 0, 0, 100); timer.IsEnabled = true; } public void Shutdown() { timer.IsEnabled = false; timer = null; Details.Content = null; JobDetailsPage = null; Financials.Content = null; JobFinancialPage = null; Documents.Content = null; JobDocumentsPage = null; Stages.Content = null; JobPlanningPage = null; //Levels.Content = null; //LevelGrid = null; //Zones.Content = null; //ZoneGrid = null; ITPs.Content = null; JobITPPage = null; BOM.Content = null; JobBillOfMaterialsPage = null; Setouts.Content = null; JobDesignsPage = null; Requisitions.Content = null; JobRequisitionsPage = null; Orders.Content = null; JobOrderPage = null; Manufacturing.Content = null; JobManufacturingPage = null; Dispatch.Content = null; JobReadyToGoPage = null; Deliveries.Content = null; JobDeliveriesPage = null; OnSite.Content = null; JobOnSitePage = null; Tasks.Content = null; JobTasksPage = null; EquipmentTab.Content = null; JobEquipmentPage = null; Employees.Content = null; JobEmployeePage = null; Trackers.Content = null; JobTrackerPage = null; Assignments.Content = null; JobActivitiesPage = null; Timesheets.Content = null; JobTimeSheetsPage = null; Forms.Content = null; JobFormsPage = null; Invoices.Content = null; JobInvoicePage = null; Spreadsheets.Content = null; JobSpreadsheetPage = null; Summary.Content = null; JobSummaryPage = null; } public void Refresh() { JobGrid.StatusID = (Guid)JobStatus.SelectedValue; // Refresh(false, true); lastselection = DateTime.MinValue; } public void CreateToolbarButtons(IPanelHost host) { host.CreateSetupAction(new PanelAction() { Caption = "Job Settings", Image = PRSDesktop.Resources.specifications, OnExecute = JobSettingsClick }); } private void JobSettingsClick(PanelAction obj) { var pages = new DynamicEditorPages(); var buttons = new DynamicEditorButtons(); buttons.Add( "", PRSDesktop.Resources.help.AsBitmapImage(), _settings, (f, i) => { Process.Start(new ProcessStartInfo("https://prsdigital.com.au/wiki/index.php/" + typeof(Equipment).Name.SplitCamelCase().Replace(" ", "_")) { UseShellExecute = true }); } ); var propertyEditor = new DynamicEditorForm(typeof(JobPanelSettings), pages, buttons); propertyEditor.OnDefineLookups += sender => { var editor = sender.EditorDefinition as ILookupEditor; var colname = sender.ColumnName; var values = editor.Values(colname, new [] { _settings }); sender.LoadLookups(values); }; propertyEditor.OnEditorValueChanged += (sender, name, value) => { CoreUtils.SetPropertyValue(_settings, name, value); return new Dictionary(); }; propertyEditor.Items = new BaseObject[] { _settings }; if (propertyEditor.ShowDialog() == true) { new GlobalConfiguration().Save(_settings); } } public event DataModelUpdateEvent? OnUpdateDataModel; public string SectionName => modelsource?.SectionName ?? "Job Details"; public DataModel DataModel(Selection selection) { if (modelsource == null) { var row = JobGrid.SelectedRows.FirstOrDefault(); var jobid = row != null ? row.Get(x => x.ID) : CoreUtils.FullGuid; return new JobDetailsDataModel(new Filter(x => x.ID).IsEqualTo(jobid)); } return modelsource.DataModel(selection); } public void Heartbeat(TimeSpan time) { } private void Timer_Tick(object sender, EventArgs e) { if (lastselection < DateTime.Now.AddMilliseconds(-500)) { lastselection = DateTime.MaxValue; var row = JobGrid.SelectedRows.FirstOrDefault(); var jobid = row != null ? row.Get(x => x.ID) : CoreUtils.FullGuid; //Guid customerid = row != null ? row.Get(x => x.Customer.ID) : Guid.Empty; var page = (PageIndex)JobPages.SelectedIndex; switch (page) { case PageIndex.Details : RefreshPanel(Details, ref JobDetailsPage, jobid, row != null); break; case PageIndex.Financials : RefreshGrid(Financials, ref JobFinancialPage, jobid, row != null); break; case PageIndex.Documents : RefreshPanel(Documents, ref JobDocumentsPage, jobid, row != null); break; case PageIndex.Stages : RefreshPanel(Stages, ref JobPlanningPage, jobid, row != null); break; case PageIndex.ITPs : RefreshGrid(ITPs, ref JobITPPage, jobid, row != null); break; case PageIndex.BOM : RefreshPanel(BOM, ref JobBillOfMaterialsPage, jobid, row != null); break; case PageIndex.Requisitions : RefreshPanel(Requisitions, ref JobRequisitionsPage, jobid, row != null); break; case PageIndex.Orders : RefreshGrid(Orders, ref JobOrderPage, jobid, row != null); break; case PageIndex.Designs : RefreshPanel(Setouts, ref JobDesignsPage, jobid, row != null); break; case PageIndex.Manufacturing : RefreshGrid(Manufacturing, ref JobManufacturingPage, jobid, row != null); break; case PageIndex.Dispatch : RefreshGrid(Dispatch, ref JobReadyToGoPage, jobid, row != null); break; case PageIndex.Delivery : RefreshPanel(Deliveries, ref JobDeliveriesPage, jobid, row != null); break; case PageIndex.Onsite : RefreshGrid(OnSite, ref JobOnSitePage, jobid, row != null); break; case PageIndex.Kanban : RefreshPanel(Tasks, ref JobTasksPage, jobid, row != null); break; case PageIndex.Equipment : RefreshGrid(EquipmentTab, ref JobEquipmentPage, jobid, row != null); break; case PageIndex.Employee : RefreshPanel(Employees, ref JobEmployeePage, jobid, row != null); break; case PageIndex.Tracker : RefreshGrid(Trackers, ref JobTrackerPage, jobid, row != null); break; case PageIndex.Assignment : RefreshPanel(Assignments, ref JobActivitiesPage, jobid, row != null); break; case PageIndex.Timesheet : RefreshGrid(Timesheets, ref JobTimeSheetsPage, jobid, row != null); break; case PageIndex.Form : RefreshGrid(Forms, ref JobFormsPage, jobid, row != null); break; case PageIndex.Invoice : RefreshPanel(Invoices, ref JobInvoicePage, jobid, row != null); break; case PageIndex.Spreadsheets : RefreshGrid(Spreadsheets, ref JobSpreadsheetPage, jobid, row != null); break; case PageIndex.Summary : RefreshPanel(Summary, ref JobSummaryPage, jobid, row != null); break; } } } private void RefreshPanel(TabItem container, ref T panel, Guid jobid, bool data) where T : IBasePanel, IJobControl, new() { if (panel == null) { panel = new T(); panel.IsReady = false; panel.ParentID = CoreUtils.FullGuid; panel.Settings = _settings; panel.Setup(); panel.IsReady = true; container.Content = panel; } if (JobPages.SelectedIndex != CurrentPage) { modelsource = panel; OnUpdateDataModel?.Invoke(panel.SectionName, panel.DataModel(Selection.None)); CurrentPage = JobPages.SelectedIndex; } panel.ParentID = jobid; panel.Settings = _settings; panel.Refresh(); } private void RefreshGrid(TabItem container, ref T grid, Guid jobid, bool data) where T : IDynamicGrid, IJobControl, IDataModelSource, new() { var bInitialised = false; if (grid == null) { grid = new T(); container.Content = grid; } else { bInitialised = true; } if (JobPages.SelectedIndex != CurrentPage) { modelsource = grid; OnUpdateDataModel?.Invoke(grid.SectionName, grid.DataModel(Selection.None)); CurrentPage = JobPages.SelectedIndex; } grid.ParentID = jobid; grid.Settings = _settings; grid.Refresh(!bInitialised, true); } private void JobGrid_OnSelectItem(object sender, DynamicGridSelectionEventArgs e) { lastselection = DateTime.Now; } private void ShowEmailInterface(PanelAction obj) { var form = new EmailInterfaceForm(); form.ShowDialog(); } private MAPIFolder? FindFolder(NameSpace oNS, string foldername) { var folder = oNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox); if (string.IsNullOrEmpty(foldername)) return folder; var comps = foldername.Split('/'); foreach (var comp in comps) { var curfolder = folder; var bFound = false; foreach (MAPIFolder subfolder in folder.Folders) if (subfolder.Name.Equals(comp)) { curfolder = subfolder; bFound = true; break; } if (bFound) folder = curfolder; else return null; } return folder; } private string ConstructReply(string job, string name, string body, bool html) { var emp = new Client().Load(new Filter(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid)).FirstOrDefault(); var template = html ? "

Dear {0}

Thankyou for your email.

It has been allocated Job #{1}, and will be attended to as soon as possible.

Job Description:
{2}

Regards,

{3}" : "Dear {0}\n\nThankyou for your email.\n\nIt has been allocated Job #{1}, and will be attended to as soon as possible.\n\nJob Description:\n================\n{2}\n\nRegards,\n\n{3}"; return string.Format(template, name.Split(' ').First(), job, body, emp != null ? emp.Name : "Frog Software"); } private void CheckMailbox(PanelAction obj) { Progress.SetMessage("Connecting to Mail Service"); var mailer = ClientFactory.CreateMailer(); if (!mailer.Connect()) { Progress.Close(); MessageBox.Show("Unable to Connect to Mail System!"); return; } Progress.SetMessage("Locating PRS Folder"); var prs = mailer.FindFolder(null, "PRS"); if (prs == null) { Progress.Close(); MessageBox.Show("Unable to Find PRS Folder"); return; } Progress.SetMessage("Locating Archive Folder"); var archive = mailer.FindFolder(prs, "Archive"); if (archive == null) { Progress.Close(); MessageBox.Show("Unable to Find PRS/Archive Folder"); return; } var me = new Client().Load(new Filter(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid)).FirstOrDefault(); if (me == null) { Progress.Close(); MessageBox.Show(string.Format("Employee [{0}] does not have a valid email address", me.Name)); return; } //Outlook.Application app = new Outlook.Application(); //Outlook.NameSpace ns = app.GetNamespace("mapi"); //ns.Logon(Missing.Value, Missing.Value, false, true); //Outlook.MAPIFolder inbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox); //Outlook.MAPIFolder folder = FindFolder(ns,"PRS"); //if (folder == null) // folder = (Outlook.Folder)inbox.Folders.Add("PRS",Outlook.OlDefaultFolders.olFolderInbox); //Outlook.MAPIFolder archive = FindFolder(ns, "PRS/Archive"); //if (archive == null) // archive = (Outlook.Folder)folder.Folders.Add("Archive", Outlook.OlDefaultFolders.olFolderInbox); JobGrid jg = null; Customer[] customers = null; Progress.SetMessage("Scanning PRS Folder"); var items = mailer.GetMessages(prs); foreach (var item in items) { if (customers == null) { Progress.SetMessage("Loading Customer Details"); customers = new Client().Load(); } var cust = customers.FirstOrDefault(x => x.Email.Equals(item.From)); if (cust != null) { if (jg == null) jg = new JobGrid(); var job = new Job(); jg.OnCustomiseEditor += Jg_OnCustomiseEditor; job.Name = item.Subject; job.Notes = new[] { item.Body }; job.Customer.ID = cust.ID; job.Customer.Synchronise(cust); job.Account.ID = !cust.Account.IsValid() ? cust.ID : cust.Account.ID; var defstatus = new Client().Query(new Filter(x => x.Default).IsEqualTo(true)); if (defstatus.Rows.Any()) job.JobStatus.ID = defstatus.Rows.First().Get(x => x.ID); Progress.Close(); if (jg.EditItems(new[] { job })) { item.Subject = string.Format("{0} (PRS #{1})", job.Name, job.JobNumber); item.Save(); mailer.MoveMessage(item, archive); //item.Move(archive); var message = mailer.CreateMessage(); message.From = me.Email; message.Subject = string.Format("RE: {0}", item.Subject); message.Body = ConstructReply(job.JobNumber, cust.Name, string.Join("\n\n", job.Notes), false); message.To = new[] { cust.Email }; mailer.SendMessage(message); //Outlook.MailItem replyMail = item.ReplyAll(); //replyMail.To = cust.Email; //replyMail.Body = ConstructReply(job.JobNumber, cust.Name, String.Join("\n\n",job.Notes), false); //replyMail.Send(); } Progress.Show("Scanning PRS Folder"); } } items = null; Progress.SetMessage("Refreshing"); Refresh(); Progress.Close(); MessageBox.Show("All Done"); //ns.Logoff(); //folder = null; //ns = null; //app = null; } private void Jg_OnCustomiseEditor(IDynamicEditorForm sender, Job[]? items, DynamicGridColumn column, BaseEditor editor) { if (column.ColumnName.Equals("Notes")) { if (editor is NotesEditor notes) notes.AlwaysEnabled = true; } } public Dictionary DataEnvironment() { var env = new Dictionary(); env[typeof(Job)] = JobGrid.Data; return env; } private void JobPages_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (e.Source == JobPages) lastselection = DateTime.MinValue; } private void JobStatus_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (IsReady) { settings.JobStatus = (Guid)JobStatus.SelectedValue; new UserConfiguration().Save(settings); JobGrid.StatusID = (Guid)JobStatus.SelectedValue; } } private void SplitPanel_OnChanged(object sender, DynamicSplitPanelSettings e) { settings.ViewType = SplitPanel.View == DynamicSplitPanelView.Master ? ScreenViewType.Register : SplitPanel.View == DynamicSplitPanelView.Detail ? ScreenViewType.Details : ScreenViewType.Combined; settings.AnchorWidth = SplitPanel.AnchorWidth; new UserConfiguration().Save(settings); var newTag = settings.ViewType == ScreenViewType.Register ? settings.ViewType.ToString() : ""; if (JobGrid.ColumnsTag != newTag) { JobGrid.ColumnsTag = newTag; JobGrid.Refresh(true, true); } } } }