JobPanel.xaml.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Threading.Tasks;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Threading;
  9. using Comal.Classes;
  10. using InABox.Clients;
  11. using InABox.Configuration;
  12. using InABox.Core;
  13. using InABox.DynamicGrid;
  14. using InABox.DynamicGrid.Spreadsheet;
  15. using InABox.WPF;
  16. using Microsoft.Office.Interop.Outlook;
  17. using System.ComponentModel;
  18. using Selection = InABox.Core.Selection;
  19. namespace PRSDesktop
  20. {
  21. public class JobPanelSettings : BaseObject, IGlobalConfigurationSettings
  22. {
  23. [Caption("Milestone Task",IncludePath = false)]
  24. public KanbanTypeLink DocumentMilestoneKanbanType { get; set; }
  25. }
  26. /// <summary>
  27. /// Interaction logic for JobPanel.xaml
  28. /// </summary>
  29. public partial class JobPanel : UserControl, IPanel<Job>
  30. {
  31. private enum PageIndex
  32. {
  33. Details = 00,
  34. Scopes,
  35. Documents,
  36. Stages,
  37. ITPs,
  38. BOM,
  39. Requisitions,
  40. Orders,
  41. Designs,
  42. Manufacturing,
  43. Dispatch,
  44. Delivery,
  45. Onsite,
  46. Kanban,
  47. Equipment,
  48. Employee,
  49. Tracker,
  50. Assignment,
  51. Timesheet,
  52. Form,
  53. Invoice,
  54. Spreadsheets,
  55. Summary
  56. }
  57. private int CurrentPage = -1;
  58. private JobDetails? JobDetailsPage;
  59. private JobScopePanel? _jobScopePage;
  60. private JobDocumentSetPanel? JobDocumentsPage;
  61. private JobStagesPanel? JobPlanningPage;
  62. private JobITPGrid? JobITPPage;
  63. private JobBillOfMaterialsPanel? JobBillOfMaterialsPage;
  64. private JobRequisitionPanel? JobRequisitionsPage;
  65. private JobDesignList? JobDesignsPage;
  66. private JobOrderGrid? JobOrderPage;
  67. private ManufacturingGrid? JobManufacturingPage;
  68. private ReadyToGoGrid? JobReadyToGoPage;
  69. private DeliveryPanel? JobDeliveriesPage;
  70. private DeliveredOnSiteGrid? JobOnSitePage;
  71. private TaskPanel? JobTasksPage;
  72. private JobEquipmentGrid? JobEquipmentPage;
  73. private JobEmployeePanel? JobEmployeePage;
  74. private JobTrackerGrid? JobTrackerPage;
  75. private JobAssignmentPanel? JobActivitiesPage;
  76. private JobTimesheetGrid? JobTimeSheetsPage;
  77. private JobFormGrid? JobFormsPage;
  78. private InvoicePanel? JobInvoicePage;
  79. private JobSpreadsheetGrid? JobSpreadsheetPage;
  80. private JobSummaryPanel? JobSummaryPage;
  81. private DateTime lastselection = DateTime.MaxValue;
  82. private IDataModelSource modelsource;
  83. // User Settings
  84. private JobScreenSettings settings;
  85. // Global Settings
  86. private JobPanelSettings _settings = null;
  87. private DispatcherTimer timer;
  88. public JobPanel()
  89. {
  90. InitializeComponent();
  91. }
  92. public bool IsReady { get; set; }
  93. public Dictionary<string, object[]> Selected()
  94. {
  95. return (PageIndex)JobPages.SelectedIndex switch
  96. {
  97. PageIndex.Details => JobDetailsPage?.Selected(),
  98. PageIndex.Scopes => _jobScopePage?.Selected(),
  99. PageIndex.Documents => JobDocumentsPage?.Selected(),
  100. PageIndex.Stages => JobPlanningPage?.Selected(),
  101. PageIndex.ITPs => new Dictionary<string, object[]> { { typeof(JobITP).EntityName(), JobITPPage.SelectedRows } },
  102. PageIndex.BOM => new Dictionary<string, object[]>
  103. { { typeof(JobBillOfMaterials).EntityName(), JobBillOfMaterialsPage.SelectedRows } },
  104. PageIndex.Designs => JobDesignsPage?.Selected(),
  105. PageIndex.Orders => new Dictionary<string, object[]> { { typeof(PurchaseOrderItem).EntityName(), JobOrderPage?.SelectedRows } },
  106. PageIndex.Requisitions => new Dictionary<string, object[]>
  107. { { typeof(JobRequisition).EntityName(), JobRequisitionsPage?.Requisitions?.SelectedRows } },
  108. PageIndex.Manufacturing => new Dictionary<string, object[]>
  109. { { typeof(ManufacturingPacket).EntityName(), JobManufacturingPage.SelectedRows } },
  110. PageIndex.Dispatch => new Dictionary<string, object[]> { { typeof(DeliveryItem).EntityName(), JobReadyToGoPage.SelectedRows } },
  111. PageIndex.Delivery => new Dictionary<string, object[]>
  112. { { typeof(Delivery).EntityName(), JobDeliveriesPage.Deliveries.SelectedRows } },
  113. PageIndex.Onsite => new Dictionary<string, object[]> { { typeof(DeliveryItem).EntityName(), JobOnSitePage.SelectedRows } },
  114. PageIndex.Kanban => JobTasksPage.Selected(),
  115. PageIndex.Equipment => new Dictionary<string, object[]> { { typeof(Equipment).EntityName(), JobEquipmentPage.SelectedRows } },
  116. PageIndex.Employee => new Dictionary<string, object[]>
  117. { { typeof(Employee).EntityName(), JobEmployeePage.Employees.SelectedRows } },
  118. PageIndex.Tracker => new Dictionary<string, object[]> { { typeof(GPSTracker).EntityName(), JobTrackerPage.SelectedRows } },
  119. PageIndex.Assignment => new Dictionary<string, object[]>
  120. { { typeof(Assignment).EntityName(), JobActivitiesPage.Assignments.SelectedRows } },
  121. PageIndex.Timesheet => new Dictionary<string, object[]> { { typeof(TimeSheet).EntityName(), JobTimeSheetsPage.SelectedRows } },
  122. PageIndex.Form => new Dictionary<string, object[]> { { typeof(JobForm).EntityName(), JobFormsPage.SelectedRows } },
  123. PageIndex.Invoice => new Dictionary<string, object[]> { { typeof(Invoice).EntityName(), JobInvoicePage.Invoices.SelectedRows } },
  124. PageIndex.Spreadsheets => new Dictionary<string, object[]> { { typeof(JobSpreadsheet).EntityName(), JobSpreadsheetPage.SelectedRows } },
  125. PageIndex.Summary => new Dictionary<string, object[]> { { typeof(JobMaterial).EntityName(), JobSummaryPage.Summary.SelectedRows } },
  126. _ => new Dictionary<string,object[]> {{ typeof(Job).EntityName(), JobGrid.SelectedRows}}
  127. };
  128. }
  129. public void Setup()
  130. {
  131. Task[] settingstasks = new Task[]
  132. {
  133. Task.Run(() =>
  134. {
  135. _settings = new GlobalConfiguration<JobPanelSettings>().Load();
  136. }),
  137. Task.Run(() =>
  138. {
  139. settings = new UserConfiguration<JobScreenSettings>().Load();
  140. })
  141. };
  142. Task.WaitAll(settingstasks);
  143. SplitPanel.View = settings.ViewType == ScreenViewType.Register ? DynamicSplitPanelView.Master :
  144. settings.ViewType == ScreenViewType.Details ? DynamicSplitPanelView.Detail : DynamicSplitPanelView.Combined;
  145. SplitPanel.AnchorWidth = settings.AnchorWidth;
  146. var sc = new Dictionary<Guid, string> { { Guid.Empty, "All Jobs" } };
  147. var statuses = new Client<JobStatus>().Query();
  148. foreach (var row in statuses.Rows)
  149. sc[row.Get<JobStatus, Guid>(x => x.ID)] = row.Get<JobStatus, string>(x => x.Description);
  150. JobStatus.ItemsSource = sc;
  151. if (sc.ContainsKey(settings.JobStatus))
  152. JobStatus.SelectedValue = settings.JobStatus;
  153. else
  154. JobStatus.SelectedValue = sc.Keys.First();
  155. JobGrid.OnSelectItem += JobGrid_OnSelectItem;
  156. JobGrid.BeforeRefresh += JobGrid_BeforeRefresh;
  157. JobGrid.AfterRefresh += JobGrid_AfterRefresh;
  158. Scopes.Visibility = Security.CanView<JobScope>() ? Visibility.Visible : Visibility.Collapsed;
  159. Documents.Visibility = Security.CanView<JobDocumentSet>() ? Visibility.Visible : Visibility.Collapsed;
  160. Stages.Visibility = ClientFactory.IsSupported<JobStage>() ? Visibility.Visible : Visibility.Collapsed;
  161. ITPs.Visibility = ClientFactory.IsSupported<JobITP>() ? Visibility.Visible : Visibility.Collapsed;
  162. BOM.Visibility = ClientFactory.IsSupported<JobBillOfMaterials>() ? Visibility.Visible : Visibility.Collapsed;
  163. Requisitions.Visibility = ClientFactory.IsSupported<JobRequisition>() ? Visibility.Visible : Visibility.Collapsed;
  164. Orders.Visibility = ClientFactory.IsSupported<PurchaseOrderItem>() ? Visibility.Visible : Visibility.Collapsed;
  165. Setouts.Visibility = ClientFactory.IsSupported<Setout>() ? Visibility.Visible : Visibility.Collapsed;
  166. Manufacturing.Visibility = ClientFactory.IsSupported<ManufacturingPacket>() ? Visibility.Visible : Visibility.Collapsed;
  167. Dispatch.Visibility = ClientFactory.IsSupported<DeliveryItem>() ? Visibility.Visible : Visibility.Collapsed;
  168. Deliveries.Visibility = ClientFactory.IsSupported<Delivery>() ? Visibility.Visible : Visibility.Collapsed;
  169. OnSite.Visibility = ClientFactory.IsSupported<DeliveryItem>() ? Visibility.Visible : Visibility.Collapsed;
  170. Tasks.Visibility = ClientFactory.IsSupported<Kanban>() ? Visibility.Visible : Visibility.Collapsed;
  171. EquipmentTab.Visibility = ClientFactory.IsSupported<Equipment>() ? Visibility.Visible : Visibility.Collapsed;
  172. Employees.Visibility = ClientFactory.IsSupported<Employee>() ? Visibility.Visible : Visibility.Collapsed;
  173. Trackers.Visibility = ClientFactory.IsSupported<GPSTracker>() ? Visibility.Visible : Visibility.Collapsed;
  174. Assignments.Visibility = ClientFactory.IsSupported<Assignment>() ? Visibility.Visible : Visibility.Collapsed;
  175. Timesheets.Visibility = ClientFactory.IsSupported<TimeSheet>() ? Visibility.Visible : Visibility.Collapsed;
  176. Forms.Visibility = Security.CanView<JobForm>() ? Visibility.Visible : Visibility.Collapsed;
  177. Invoices.Visibility = Security.CanView<Invoice>() ? Visibility.Visible : Visibility.Collapsed;
  178. Spreadsheets.Visibility = Security.CanView<JobSpreadsheet>() ? Visibility.Visible : Visibility.Collapsed;
  179. Summary.Visibility = ClientFactory.IsSupported<JobMaterial>() ? Visibility.Visible : Visibility.Collapsed;
  180. JobGrid.ColumnsTag = settings.ViewType == ScreenViewType.Register ? settings.ViewType.ToString() : "";
  181. JobGrid.Refresh(true, false);
  182. timer = new DispatcherTimer();
  183. timer.Tick += Timer_Tick;
  184. timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
  185. timer.IsEnabled = true;
  186. }
  187. private bool _jobGridRefreshing;
  188. private void JobGrid_BeforeRefresh(object sender, BeforeRefreshEventArgs args)
  189. {
  190. _jobGridRefreshing = true;
  191. }
  192. private void JobGrid_AfterRefresh(object sender, AfterRefreshEventArgs args)
  193. {
  194. if (settings.CurrentJob == Guid.Empty)
  195. {
  196. JobGrid.SelectedRows = Array.Empty<CoreRow>();
  197. }
  198. else
  199. {
  200. JobGrid.SelectedRows = JobGrid.Data.Rows.Where(x => x.Get<Job, Guid>(x => x.ID) == settings.CurrentJob).ToArray();
  201. }
  202. _jobGridRefreshing = false;
  203. }
  204. public void Shutdown(CancelEventArgs? cancel)
  205. {
  206. timer.IsEnabled = false;
  207. timer = null;
  208. Details.Content = null;
  209. JobDetailsPage = null;
  210. Scopes.Content = null;
  211. _jobScopePage = null;
  212. Documents.Content = null;
  213. JobDocumentsPage = null;
  214. Stages.Content = null;
  215. JobPlanningPage = null;
  216. //Levels.Content = null;
  217. //LevelGrid = null;
  218. //Zones.Content = null;
  219. //ZoneGrid = null;
  220. ITPs.Content = null;
  221. JobITPPage = null;
  222. BOM.Content = null;
  223. JobBillOfMaterialsPage = null;
  224. Setouts.Content = null;
  225. JobDesignsPage = null;
  226. Requisitions.Content = null;
  227. JobRequisitionsPage = null;
  228. Orders.Content = null;
  229. JobOrderPage = null;
  230. Manufacturing.Content = null;
  231. JobManufacturingPage = null;
  232. Dispatch.Content = null;
  233. JobReadyToGoPage = null;
  234. Deliveries.Content = null;
  235. JobDeliveriesPage = null;
  236. OnSite.Content = null;
  237. JobOnSitePage = null;
  238. Tasks.Content = null;
  239. JobTasksPage = null;
  240. EquipmentTab.Content = null;
  241. JobEquipmentPage = null;
  242. Employees.Content = null;
  243. JobEmployeePage = null;
  244. Trackers.Content = null;
  245. JobTrackerPage = null;
  246. Assignments.Content = null;
  247. JobActivitiesPage = null;
  248. Timesheets.Content = null;
  249. JobTimeSheetsPage = null;
  250. Forms.Content = null;
  251. JobFormsPage = null;
  252. Invoices.Content = null;
  253. JobInvoicePage = null;
  254. Spreadsheets.Content = null;
  255. JobSpreadsheetPage = null;
  256. Summary.Content = null;
  257. JobSummaryPage = null;
  258. }
  259. public void Refresh()
  260. {
  261. JobGrid.StatusID = (Guid)JobStatus.SelectedValue;
  262. JobGrid.Refresh(false, true);
  263. lastselection = DateTime.MinValue;
  264. }
  265. public void CreateToolbarButtons(IPanelHost host)
  266. {
  267. host.CreateSetupAction(new PanelAction() { Caption = "Job Settings", Image = PRSDesktop.Resources.specifications, OnExecute = JobSettingsClick });
  268. }
  269. private void JobSettingsClick(PanelAction obj)
  270. {
  271. var pages = new DynamicEditorPages();
  272. var buttons = new DynamicEditorButtons();
  273. buttons.Add(
  274. "",
  275. PRSDesktop.Resources.help.AsBitmapImage(),
  276. _settings,
  277. (f, i) =>
  278. {
  279. Process.Start(new ProcessStartInfo("https://prsdigital.com.au/wiki/index.php/" + typeof(Equipment).Name.SplitCamelCase().Replace(" ", "_"))
  280. { UseShellExecute = true });
  281. }
  282. );
  283. var propertyEditor = new DynamicEditorForm(typeof(JobPanelSettings), pages, buttons);
  284. propertyEditor.OnDefineLookups += sender =>
  285. {
  286. var editor = sender.EditorDefinition as ILookupEditor;
  287. var colname = sender.ColumnName;
  288. var values = editor.Values(colname, new [] { _settings });
  289. sender.LoadLookups(values);
  290. };
  291. propertyEditor.OnEditorValueChanged += (sender, name, value) =>
  292. {
  293. CoreUtils.SetPropertyValue(_settings, name, value);
  294. return new Dictionary<string, object?>();
  295. };
  296. propertyEditor.Items = new BaseObject[] { _settings };
  297. if (propertyEditor.ShowDialog() == true)
  298. {
  299. new GlobalConfiguration<JobPanelSettings>().Save(_settings);
  300. }
  301. }
  302. public event DataModelUpdateEvent? OnUpdateDataModel;
  303. public string SectionName => modelsource?.SectionName ?? "Job Details";
  304. public DataModel DataModel(Selection selection)
  305. {
  306. if (modelsource == null)
  307. {
  308. var row = JobGrid.SelectedRows.FirstOrDefault();
  309. var jobid = row != null ? row.Get<Job, Guid>(x => x.ID) : CoreUtils.FullGuid;
  310. return new JobDetailsDataModel(new Filter<Job>(x => x.ID).IsEqualTo(jobid));
  311. }
  312. return modelsource.DataModel(selection);
  313. }
  314. public void Heartbeat(TimeSpan time)
  315. {
  316. }
  317. private void Timer_Tick(object sender, EventArgs e)
  318. {
  319. if (lastselection < DateTime.Now.AddMilliseconds(-500))
  320. {
  321. lastselection = DateTime.MaxValue;
  322. var job = JobGrid.SelectedRows.FirstOrDefault()?.ToObject<Job>() ?? new Job();
  323. //var jobid = row != null ? row.Get<Job, Guid>(x => x.ID) : CoreUtils.FullGuid;
  324. //Guid customerid = row != null ? row.Get<Job, Guid>(x => x.Customer.ID) : Guid.Empty;
  325. var page = (PageIndex)JobPages.SelectedIndex;
  326. switch (page)
  327. {
  328. case PageIndex.Details :
  329. RefreshPanel(Details, ref JobDetailsPage, job);
  330. break;
  331. case PageIndex.Scopes : RefreshPanel(Scopes, ref _jobScopePage, job);
  332. break;
  333. case PageIndex.Documents : RefreshPanel(Documents, ref JobDocumentsPage, job);
  334. break;
  335. case PageIndex.Stages : RefreshPanel(Stages, ref JobPlanningPage, job);
  336. break;
  337. case PageIndex.ITPs : RefreshGrid(ITPs, ref JobITPPage, job);
  338. break;
  339. case PageIndex.BOM : RefreshPanel(BOM, ref JobBillOfMaterialsPage, job);
  340. break;
  341. case PageIndex.Requisitions : RefreshPanel(Requisitions, ref JobRequisitionsPage, job);
  342. break;
  343. case PageIndex.Orders : RefreshGrid(Orders, ref JobOrderPage, job);
  344. break;
  345. case PageIndex.Designs : RefreshPanel(Setouts, ref JobDesignsPage, job);
  346. break;
  347. case PageIndex.Manufacturing : RefreshGrid(Manufacturing, ref JobManufacturingPage, job);
  348. break;
  349. case PageIndex.Dispatch :
  350. RefreshGrid(Dispatch, ref JobReadyToGoPage, job);
  351. break;
  352. case PageIndex.Delivery :
  353. RefreshPanel(Deliveries, ref JobDeliveriesPage, job);
  354. break;
  355. case PageIndex.Onsite :
  356. RefreshGrid(OnSite, ref JobOnSitePage, job);
  357. break;
  358. case PageIndex.Kanban :
  359. RefreshPanel(Tasks, ref JobTasksPage, job);
  360. break;
  361. case PageIndex.Equipment :
  362. RefreshGrid(EquipmentTab, ref JobEquipmentPage, job);
  363. break;
  364. case PageIndex.Employee :
  365. RefreshPanel(Employees, ref JobEmployeePage, job);
  366. break;
  367. case PageIndex.Tracker :
  368. RefreshGrid(Trackers, ref JobTrackerPage, job);
  369. break;
  370. case PageIndex.Assignment :
  371. RefreshPanel(Assignments, ref JobActivitiesPage, job);
  372. break;
  373. case PageIndex.Timesheet :
  374. RefreshGrid(Timesheets, ref JobTimeSheetsPage, job);
  375. break;
  376. case PageIndex.Form :
  377. RefreshGrid(Forms, ref JobFormsPage, job);
  378. break;
  379. case PageIndex.Invoice :
  380. RefreshPanel(Invoices, ref JobInvoicePage, job);
  381. break;
  382. case PageIndex.Spreadsheets :
  383. RefreshGrid(Spreadsheets, ref JobSpreadsheetPage, job);
  384. break;
  385. case PageIndex.Summary :
  386. RefreshPanel(Summary, ref JobSummaryPage, job);
  387. break;
  388. }
  389. }
  390. }
  391. private void RefreshPanel<T>(TabItem container, ref T panel, Job job) where T : IBasePanel, IJobControl, new()
  392. {
  393. if (panel == null)
  394. {
  395. panel = new T();
  396. panel.IsReady = false;
  397. //panel.ParentID = CoreUtils.FullGuid;
  398. panel.Job = new Job();
  399. panel.Settings = _settings;
  400. panel.Setup();
  401. panel.IsReady = true;
  402. container.Content = panel;
  403. }
  404. if (JobPages.SelectedIndex != CurrentPage)
  405. {
  406. modelsource = panel;
  407. OnUpdateDataModel?.Invoke(panel.SectionName, panel.DataModel(Selection.None));
  408. CurrentPage = JobPages.SelectedIndex;
  409. }
  410. //panel.ParentID = jobid;
  411. panel.Job = job;
  412. panel.Settings = _settings;
  413. panel.Refresh();
  414. }
  415. private void RefreshGrid<T>(TabItem container, ref T grid, Job job) where T : IDynamicGrid, IJobControl, IDataModelSource, new()
  416. {
  417. var bInitialised = false;
  418. if (grid == null)
  419. {
  420. grid = new T();
  421. container.Content = grid;
  422. }
  423. else
  424. {
  425. bInitialised = true;
  426. }
  427. if (JobPages.SelectedIndex != CurrentPage)
  428. {
  429. modelsource = grid;
  430. OnUpdateDataModel?.Invoke(grid.SectionName, grid.DataModel(Selection.None));
  431. CurrentPage = JobPages.SelectedIndex;
  432. }
  433. //grid.ParentID = jobid;
  434. grid.Job = job;
  435. grid.Settings = _settings;
  436. grid.Refresh(!bInitialised, true);
  437. }
  438. private void JobGrid_OnSelectItem(object sender, DynamicGridSelectionEventArgs e)
  439. {
  440. lastselection = DateTime.Now;
  441. if (IsReady && !_jobGridRefreshing)
  442. {
  443. settings.CurrentJob = e.Rows?.FirstOrDefault()?.Get<Job, Guid>(x => x.ID) ?? Guid.Empty;
  444. new UserConfiguration<JobScreenSettings>().Save(settings);
  445. }
  446. }
  447. private void ShowEmailInterface(PanelAction obj)
  448. {
  449. var form = new EmailInterfaceForm();
  450. form.ShowDialog();
  451. }
  452. private MAPIFolder? FindFolder(NameSpace oNS, string foldername)
  453. {
  454. var folder = oNS.GetDefaultFolder(OlDefaultFolders.olFolderInbox);
  455. if (string.IsNullOrEmpty(foldername))
  456. return folder;
  457. var comps = foldername.Split('/');
  458. foreach (var comp in comps)
  459. {
  460. var curfolder = folder;
  461. var bFound = false;
  462. foreach (MAPIFolder subfolder in folder.Folders)
  463. if (subfolder.Name.Equals(comp))
  464. {
  465. curfolder = subfolder;
  466. bFound = true;
  467. break;
  468. }
  469. if (bFound)
  470. folder = curfolder;
  471. else
  472. return null;
  473. }
  474. return folder;
  475. }
  476. private string ConstructReply(string job, string name, string body, bool html)
  477. {
  478. var emp = new Client<Employee>().Load(new Filter<Employee>(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid)).FirstOrDefault();
  479. var template = html
  480. ? "<p>Dear {0}</p>Thankyou for your email.</p><p>It has been allocated Job #{1}, and will be attended to as soon as possible.</p><p><b><u>Job Description:</u></b><br>{2}</p><p>Regards,</p><p>{3}"
  481. : "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}";
  482. return string.Format(template, name.Split(' ').First(), job, body, emp != null ? emp.Name : "Frog Software");
  483. }
  484. private void CheckMailbox(PanelAction obj)
  485. {
  486. Progress.SetMessage("Connecting to Mail Service");
  487. var mailer = ClientFactory.CreateMailer();
  488. if (!mailer.Connect())
  489. {
  490. Progress.Close();
  491. MessageBox.Show("Unable to Connect to Mail System!");
  492. return;
  493. }
  494. Progress.SetMessage("Locating PRS Folder");
  495. var prs = mailer.FindFolder(null, "PRS");
  496. if (prs == null)
  497. {
  498. Progress.Close();
  499. MessageBox.Show("Unable to Find PRS Folder");
  500. return;
  501. }
  502. Progress.SetMessage("Locating Archive Folder");
  503. var archive = mailer.FindFolder(prs, "Archive");
  504. if (archive == null)
  505. {
  506. Progress.Close();
  507. MessageBox.Show("Unable to Find PRS/Archive Folder");
  508. return;
  509. }
  510. var me = new Client<Employee>().Load(new Filter<Employee>(x => x.UserLink.ID).IsEqualTo(ClientFactory.UserGuid)).FirstOrDefault();
  511. if (me == null)
  512. {
  513. Progress.Close();
  514. MessageBox.Show(string.Format("Employee [{0}] does not have a valid email address", me.Name));
  515. return;
  516. }
  517. //Outlook.Application app = new Outlook.Application();
  518. //Outlook.NameSpace ns = app.GetNamespace("mapi");
  519. //ns.Logon(Missing.Value, Missing.Value, false, true);
  520. //Outlook.MAPIFolder inbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
  521. //Outlook.MAPIFolder folder = FindFolder(ns,"PRS");
  522. //if (folder == null)
  523. // folder = (Outlook.Folder)inbox.Folders.Add("PRS",Outlook.OlDefaultFolders.olFolderInbox);
  524. //Outlook.MAPIFolder archive = FindFolder(ns, "PRS/Archive");
  525. //if (archive == null)
  526. // archive = (Outlook.Folder)folder.Folders.Add("Archive", Outlook.OlDefaultFolders.olFolderInbox);
  527. JobGrid jg = null;
  528. Customer[] customers = null;
  529. Progress.SetMessage("Scanning PRS Folder");
  530. var items = mailer.GetMessages(prs);
  531. foreach (var item in items)
  532. {
  533. if (customers == null)
  534. {
  535. Progress.SetMessage("Loading Customer Details");
  536. customers = new Client<Customer>().Load();
  537. }
  538. var cust = customers.FirstOrDefault(x => x.Email.Equals(item.From));
  539. if (cust != null)
  540. {
  541. if (jg == null)
  542. jg = new JobGrid();
  543. var job = new Job();
  544. jg.OnCustomiseEditor += Jg_OnCustomiseEditor;
  545. job.Name = item.Subject;
  546. job.Notes = new[] { item.Body };
  547. job.Customer.ID = cust.ID;
  548. job.Customer.Synchronise(cust);
  549. job.Account.ID = !cust.Account.IsValid() ? cust.ID : cust.Account.ID;
  550. var defstatus = new Client<JobStatus>().Query(new Filter<JobStatus>(x => x.Default).IsEqualTo(true));
  551. if (defstatus.Rows.Any())
  552. job.JobStatus.ID = defstatus.Rows.First().Get<JobStatus, Guid>(x => x.ID);
  553. Progress.Close();
  554. if (jg.EditItems(new[] { job }))
  555. {
  556. item.Subject = string.Format("{0} (PRS #{1})", job.Name, job.JobNumber);
  557. item.Save();
  558. mailer.MoveMessage(item, archive);
  559. //item.Move(archive);
  560. var message = mailer.CreateMessage();
  561. message.From = me.Email;
  562. message.Subject = string.Format("RE: {0}", item.Subject);
  563. message.Body = ConstructReply(job.JobNumber, cust.Name, string.Join("\n\n", job.Notes), false);
  564. message.To = new[] { cust.Email };
  565. mailer.SendMessage(message);
  566. //Outlook.MailItem replyMail = item.ReplyAll();
  567. //replyMail.To = cust.Email;
  568. //replyMail.Body = ConstructReply(job.JobNumber, cust.Name, String.Join("\n\n",job.Notes), false);
  569. //replyMail.Send();
  570. }
  571. Progress.Show("Scanning PRS Folder");
  572. }
  573. }
  574. items = null;
  575. Progress.SetMessage("Refreshing");
  576. Refresh();
  577. Progress.Close();
  578. MessageBox.Show("All Done");
  579. //ns.Logoff();
  580. //folder = null;
  581. //ns = null;
  582. //app = null;
  583. }
  584. private void Jg_OnCustomiseEditor(IDynamicEditorForm sender, Job[]? items, DynamicGridColumn column, BaseEditor editor)
  585. {
  586. if (column.ColumnName.Equals("Notes"))
  587. {
  588. if (editor is NotesEditor notes)
  589. notes.AlwaysEnabled = true;
  590. }
  591. }
  592. public Dictionary<Type, CoreTable> DataEnvironment()
  593. {
  594. var env = new Dictionary<Type, CoreTable>();
  595. env[typeof(Job)] = JobGrid.Data;
  596. return env;
  597. }
  598. private void JobPages_SelectionChanged(object sender, SelectionChangedEventArgs e)
  599. {
  600. if (e.Source == JobPages)
  601. lastselection = DateTime.MinValue;
  602. }
  603. private void JobStatus_SelectionChanged(object sender, SelectionChangedEventArgs e)
  604. {
  605. if (IsReady)
  606. {
  607. settings.JobStatus = (Guid)JobStatus.SelectedValue;
  608. new UserConfiguration<JobScreenSettings>().Save(settings);
  609. JobGrid.StatusID = (Guid)JobStatus.SelectedValue;
  610. JobGrid.Refresh(false, true);
  611. }
  612. }
  613. private void SplitPanel_OnChanged(object sender, DynamicSplitPanelSettings e)
  614. {
  615. settings.ViewType = SplitPanel.View == DynamicSplitPanelView.Master ? ScreenViewType.Register :
  616. SplitPanel.View == DynamicSplitPanelView.Detail ? ScreenViewType.Details : ScreenViewType.Combined;
  617. settings.AnchorWidth = SplitPanel.AnchorWidth;
  618. new UserConfiguration<JobScreenSettings>().Save(settings);
  619. var newTag = settings.ViewType == ScreenViewType.Register ? settings.ViewType.ToString() : "";
  620. if (JobGrid.ColumnsTag != newTag)
  621. {
  622. JobGrid.ColumnsTag = newTag;
  623. JobGrid.Refresh(true, true);
  624. }
  625. }
  626. }
  627. }