AttendancePanel.xaml.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Windows;
  5. using System.Windows.Controls;
  6. using System.Windows.Input;
  7. using System.Windows.Media.Imaging;
  8. using System.Windows.Threading;
  9. using Comal.Classes;
  10. using InABox.Clients;
  11. using InABox.Core;
  12. using InABox.DynamicGrid;
  13. using InABox.WPF;
  14. using InABox.Wpf;
  15. using PRS.Shared;
  16. using Syncfusion.UI.Xaml.Kanban;
  17. using System.ComponentModel;
  18. namespace PRSDesktop
  19. {
  20. /// <summary>
  21. /// Interaction logic for AttendancePanel.xaml
  22. /// </summary>
  23. public partial class AttendancePanel : UserControl, IPanel<TimeSheet>
  24. {
  25. private string _search = "";
  26. public CoreTable Activities;
  27. private bool bIncludeInactive;
  28. private readonly DispatcherTimer columnsizer = new();
  29. public CoreTable Employees;
  30. private readonly List<AttendanceKanban> Kanbans = new();
  31. public CoreTable LeaveRequests;
  32. public CoreTable TimeSheets;
  33. public CoreTable StandardLeaves;
  34. public AttendancePanel()
  35. {
  36. InitializeComponent();
  37. columnsizer.Interval = new TimeSpan(0, 0, 0, 0, 500);
  38. columnsizer.Tick += Columnsizer_Tick;
  39. columnsizer.IsEnabled = true;
  40. }
  41. public bool IsReady { get; set; }
  42. public event DataModelUpdateEvent? OnUpdateDataModel;
  43. public Dictionary<string, object[]> Selected()
  44. {
  45. return new Dictionary<string, object[]>
  46. {
  47. { typeof(Employee).EntityName(), Employees.Rows.ToArray() },
  48. { typeof(TimeSheet).EntityName(), TimeSheets.Rows.ToArray() }
  49. };
  50. }
  51. public void CreateToolbarButtons(IPanelHost host)
  52. {
  53. }
  54. public string SectionName => "Attendance";
  55. public DataModel DataModel(Selection selection)
  56. {
  57. var ids = selection != Selection.None ? Employees.ExtractValues<Employee, Guid>(x => x.ID).ToArray() : new Guid[] { };
  58. var filter = new Filter<Employee>(x => x.ID).InList(ids);
  59. if (!bIncludeInactive)
  60. {
  61. filter.And(x => x.ShowOnInOutBoard);
  62. }
  63. return new AttendanceDataModel(filter);
  64. }
  65. public void Refresh()
  66. {
  67. // if there is a current timesheet (start < now, finish > now or empty), => activity color
  68. // if there is a current standard leave (start < now, finish > now) => activity color
  69. // if there is a current leave request (start < now, finish > now) => activity color
  70. // if there is a roster (day = today, start < now, finish > now) => red
  71. // => lightgray
  72. using (var cursor = new WaitCursor())
  73. {
  74. var query = new MultiQuery();
  75. query.Add(
  76. new Filter<TimeSheet>(x => x.Date).IsEqualTo(DateTime.Today),
  77. Columns.None<TimeSheet>().Add(x => x.EmployeeLink.ID)
  78. .Add(x => x.Start)
  79. .Add(x => x.Finish)
  80. .Add(x => x.Address)
  81. .Add(x => x.ActivityLink.ID)
  82. .Add(x => x.SoftwareVersion),
  83. new SortOrder<TimeSheet>(x => x.Start)
  84. );
  85. query.Add(
  86. new Filter<StandardLeave>(x => x.From).IsLessThanOrEqualTo(DateTime.Today)
  87. .And(x => x.To).IsGreaterThanOrEqualTo(DateTime.Today),
  88. Columns.None<StandardLeave>().Add(x => x.From)
  89. .Add(x => x.FromTime)
  90. .Add(x => x.To)
  91. .Add(x => x.ToTime)
  92. .Add(x => x.LeaveType.ID)
  93. );
  94. query.Add(
  95. new Filter<LeaveRequest>(x => x.From).IsLessThanOrEqualTo(DateTime.Today)
  96. .And(x => x.To).IsGreaterThanOrEqualTo(DateTime.Today)
  97. .And(x => x.Status).IsNotEqualTo(LeaveRequestStatus.Rejected),
  98. Columns.None<LeaveRequest>().Add(x => x.EmployeeLink.ID)
  99. .Add(x => x.From)
  100. .Add(x => x.FromTime)
  101. .Add(x => x.To)
  102. .Add(x => x.ToTime)
  103. .Add(x => x.LeaveType.ID)
  104. );
  105. query.Query();
  106. TimeSheets = query.Get<TimeSheet>();
  107. StandardLeaves = query.Get<StandardLeave>();
  108. LeaveRequests = query.Get<LeaveRequest>();
  109. foreach (var emprow in Employees.Rows)
  110. {
  111. var empid = emprow.Get<Employee, Guid>(c => c.ID);
  112. var kanban = Kanbans.FirstOrDefault(x => string.Equals(x.ID, empid.ToString()));
  113. if (kanban != null)
  114. {
  115. var bOK = CheckTimeSheet(empid, kanban);
  116. if (!bOK)
  117. bOK = CheckStandardLeave(empid, kanban);
  118. if (!bOK)
  119. bOK = CheckLeaveRequest(empid, kanban);
  120. if (!bOK)
  121. bOK = CheckRoster(empid, kanban, emprow);
  122. if (!bOK)
  123. UpdateKanban(kanban,
  124. TimeSpan.MinValue,
  125. TimeSpan.MinValue,
  126. "Not Rostered On",
  127. "White",
  128. "Gainsboro",
  129. "",
  130. ""
  131. );
  132. }
  133. }
  134. FilterKanbans();
  135. }
  136. }
  137. public void Setup()
  138. {
  139. Kanban.Columns.Clear();
  140. MultiQuery query = new MultiQuery();
  141. query.Add<Employee>(
  142. LookupFactory.DefineFilter<Employee>(),
  143. Columns.Required<Employee>().Add(
  144. x => x.ID,
  145. x => x.Name,
  146. x => x.Thumbnail.ID,
  147. x => x.Group.ID,
  148. x => x.Group.Description,
  149. x => x.Type,
  150. x => x.ShowOnInOutBoard,
  151. x => x.Roster,
  152. x => x.RosterStart
  153. ),
  154. new SortOrder<Employee>(x => x.Name)
  155. );
  156. query.Add<Activity>();
  157. query.Query();
  158. Employees = query.Get<Employee>();
  159. Activities = query.Get<Activity>();
  160. CreateColumns();
  161. CreateKanbans();
  162. var imageids = Employees.Rows
  163. .Select(r => r.EntityLinkID<Employee, ImageDocumentLink>(x => x.Thumbnail) ?? Guid.Empty)
  164. .Where(x => x != Guid.Empty).ToArray();
  165. new Client<Document>().Query(
  166. new Filter<Document>(x => x.ID).InList(imageids),
  167. Columns.None<Document>().Add(
  168. x => x.ID,
  169. x => x.Data
  170. ),
  171. null,
  172. CoreRange.All,
  173. (data, error) => ProcessImages(data)
  174. );
  175. }
  176. public void Shutdown(CancelEventArgs? cancel)
  177. {
  178. }
  179. public void Heartbeat(TimeSpan time)
  180. {
  181. }
  182. private void Columnsizer_Tick(object? sender, EventArgs e)
  183. {
  184. columnsizer.IsEnabled = false;
  185. ResizeColumns();
  186. columnsizer.IsEnabled = true;
  187. }
  188. private void ResizeColumns()
  189. {
  190. using (var d = Dispatcher.DisableProcessing())
  191. {
  192. var CollapsedWidth = 50;
  193. var CollapsedColumns = 0;
  194. Array.ForEach(Kanban.Columns.ToArray(), x => { CollapsedColumns += x.IsExpanded ? 0 : 1; });
  195. if (Kanban.Columns.Count > 0 && CollapsedColumns != Kanban.Columns.Count)
  196. {
  197. var ColumnWidth = (Kanban.ActualWidth - CollapsedColumns * CollapsedWidth) / (Kanban.Columns.Count - CollapsedColumns) - 2;
  198. if (ColumnWidth != Kanban.ColumnWidth)
  199. {
  200. Kanban.ColumnWidth = ColumnWidth;
  201. }
  202. }
  203. }
  204. }
  205. private void CreateKanbans()
  206. {
  207. foreach (var row in Employees.Rows)
  208. {
  209. var empid = row.Get<Employee, Guid>(x => x.ID);
  210. var empname = row.Get<Employee, string>(x => x.Name);
  211. var groupid = row.Get<Employee, Guid>(x => x.Group.ID);
  212. var imgid = row.Get<Employee, Guid>(x => x.Thumbnail.ID);
  213. var img = PRSDesktop.Resources.anonymous.AsBitmapImage();
  214. var active = row.Get<Employee, bool>(x => x.ShowOnInOutBoard);
  215. var color = "White";
  216. var kanban = new AttendanceKanban
  217. {
  218. ID = empid.ToString(),
  219. Name = empname,
  220. Category = groupid.ToString(),
  221. Image = img,
  222. Clockin = "",
  223. Clockout = "",
  224. Address = "",
  225. ColorKey = "White",
  226. TextColor = "Gainsboro",
  227. Type = "",
  228. Version = "",
  229. Active = active
  230. };
  231. Kanbans.Add(kanban);
  232. }
  233. }
  234. private void CreateColumns()
  235. {
  236. //Dictionary<Guid, String> columns = Employees.ToDictionary<Employee, Guid>(x => x.ID, new System.Linq.Expressions.Expression<Func<Employee, object>>[] { x => x.Group.Description });
  237. Kanban.Columns.Clear();
  238. var columns = new List<Tuple<Guid, string>>();
  239. foreach (var row in Employees.Rows)
  240. {
  241. var active = row.Get<Employee, bool>(c => c.ShowOnInOutBoard);
  242. if (bIncludeInactive || active)
  243. {
  244. var id = row.Get<Employee, Guid>(c => c.Group.ID);
  245. var desc = row.Get<Employee, string>(c => c.Group.Description);
  246. if (!columns.Any(x => x.Item1.Equals(id)))
  247. columns.Add(new Tuple<Guid, string>(id, desc));
  248. }
  249. }
  250. columns = columns.OrderBy(x => x.Item2).ToList();
  251. foreach (var column in columns)
  252. {
  253. var newcol = new KanbanColumn
  254. {
  255. Title = column.Item1 != Guid.Empty ? column.Item2 : "(No Group Assigned)",
  256. Categories = column.Item1.ToString()
  257. };
  258. newcol.AllowDrag = false;
  259. newcol.AllowDrop = false;
  260. Kanban.Columns.Add(newcol);
  261. }
  262. }
  263. private void UpdateKanban(AttendanceKanban kanban, TimeSpan start, TimeSpan finish, string address, string background, string foreground,
  264. string description, string version)
  265. {
  266. kanban.Clockin = start.TotalMilliseconds > 0 ? string.Format("{0:hh\\:mm}", start) : "";
  267. kanban.Clockout = finish.TotalMilliseconds > 0 ? string.Format("{0:hh\\:mm}", finish) : "";
  268. kanban.Address = address;
  269. kanban.ColorKey = background;
  270. kanban.TextColor = foreground;
  271. kanban.Type = description;
  272. kanban.Version = version;
  273. }
  274. private bool CheckTimeSheet(Guid empid, AttendanceKanban kanban)
  275. {
  276. var firstrow = TimeSheets.Rows.FirstOrDefault(r => r.Get<TimeSheet, Guid>(c => c.EmployeeLink.ID).Equals(empid));
  277. if (firstrow == null)
  278. return false;
  279. var lastrow = TimeSheets.Rows.LastOrDefault(r => r.Get<TimeSheet, Guid>(c => c.EmployeeLink.ID).Equals(empid));
  280. var actid = lastrow.Get<TimeSheet, Guid>(c => c.ActivityLink.ID);
  281. var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(actid));
  282. var color = "White";
  283. var finish = lastrow.Get<TimeSheet, TimeSpan>(c => c.Finish);
  284. if (finish.Ticks > 0 && finish < DateTime.Now - DateTime.Today)
  285. {
  286. color = "Gainsboro";
  287. }
  288. else
  289. {
  290. color = actrow != null ? actrow.Get<Activity, string>(c => c.Color) : "";
  291. if (string.IsNullOrWhiteSpace(color))
  292. color = "LightGreen";
  293. }
  294. UpdateKanban(kanban,
  295. firstrow.Get<TimeSheet, TimeSpan>(c => c.Start),
  296. lastrow.Get<TimeSheet, TimeSpan>(c => c.Finish),
  297. lastrow.Get<TimeSheet, string>(c => c.Address),
  298. color,
  299. "Black",
  300. actrow != null ? actrow.Get<Activity, string>(c => c.Description) : "",
  301. lastrow.Get<TimeSheet, string>(c => c.SoftwareVersion)
  302. );
  303. //kanban.Clockin = firstrow != null ? String.Format("{0:hh\\:mm}", firstrow.Get<TimeSheet, TimeSpan>(c => c.Start)) : "";
  304. //kanban.Clockout = (lastrow != null) && (lastrow.Get<TimeSheet, TimeSpan>(c => c.Finish).Ticks > 0) ? String.Format("{0:hh\\:mm}", lastrow.Get<TimeSheet, TimeSpan>(c => c.Finish)) : "";
  305. //kanban.Address = lastrow != null ? lastrow.Get<TimeSheet, String>(c => c.Address) : "";
  306. //kanban.ColorKey = color;
  307. //kanban.TextColor = lastrow != null ? "Black" : "Gainsboro";
  308. //kanban.Type = actrow != null ? actrow.Get<Activity, String>(c => c.Description) : "";
  309. //kanban.Version = lastrow != null ? lastrow.Get<TimeSheet, String>(c => c.SoftwareVersion) : "";
  310. return true;
  311. }
  312. private bool CheckStandardLeave(Guid empid, AttendanceKanban kanban)
  313. {
  314. var row = StandardLeaves.Rows.FirstOrDefault();
  315. if (row == null)
  316. return false;
  317. var actid = row.Get<StandardLeave, Guid>(c => c.LeaveType.ID);
  318. var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(actid));
  319. var color = actrow?.Get<Activity, string>(c => c.Color);
  320. if (string.IsNullOrWhiteSpace(color))
  321. color = "Gainsboro";
  322. var description = actrow?.Get<Activity, string>(c => c.Description);
  323. if (string.IsNullOrWhiteSpace(description))
  324. description = "Leave";
  325. UpdateKanban(kanban,
  326. row.Get<StandardLeave, DateTime>(c => c.From) == DateTime.Today
  327. ? row.Get<StandardLeave, TimeSpan>(c => c.FromTime)
  328. : TimeSpan.MinValue,
  329. row.Get<StandardLeave, DateTime>(c => c.To) == DateTime.Today
  330. ? row.Get<StandardLeave, TimeSpan>(c => c.ToTime)
  331. : TimeSpan.MinValue,
  332. "",
  333. color,
  334. "Black",
  335. description,
  336. ""
  337. );
  338. return true;
  339. }
  340. private bool CheckLeaveRequest(Guid empid, AttendanceKanban kanban)
  341. {
  342. var row = LeaveRequests.Rows.FirstOrDefault(r => r.Get<LeaveRequest, Guid>(c => c.EmployeeLink.ID) == empid);
  343. if (row == null)
  344. return false;
  345. var actid = row.Get<LeaveRequest, Guid>(c => c.LeaveType.ID);
  346. var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(actid));
  347. var color = actrow?.Get<Activity, string>(c => c.Color);
  348. if (string.IsNullOrWhiteSpace(color))
  349. color = "Gainsboro";
  350. var description = actrow?.Get<Activity, string>(c => c.Description);
  351. if (string.IsNullOrWhiteSpace(description))
  352. description = "Leave";
  353. UpdateKanban(kanban,
  354. row.Get<LeaveRequest, DateTime>(c => c.From) == DateTime.Today
  355. ? row.Get<LeaveRequest, TimeSpan>(c => c.FromTime)
  356. : TimeSpan.MinValue,
  357. row.Get<LeaveRequest, DateTime>(c => c.To) == DateTime.Today
  358. ? row.Get<LeaveRequest, TimeSpan>(c => c.ToTime)
  359. : TimeSpan.MinValue,
  360. "",
  361. color,
  362. "Black",
  363. description,
  364. ""
  365. );
  366. return true;
  367. }
  368. private bool CheckRoster(Guid empid, AttendanceKanban kanban, CoreRow empdata)
  369. {
  370. var rosterdata = empdata.Get<Employee, String>(c => c.Roster);
  371. var rosters = !String.IsNullOrWhiteSpace(rosterdata)
  372. ? Serialization.Deserialize<List<EmployeeRosterItem>>(rosterdata).ToArray()
  373. : null;
  374. var roster = RosterUtils.GetRoster(rosters, empdata.Get<Employee,DateTime>(c=>c.RosterStart), DateTime.Today);
  375. if ((roster == null) || (!roster.Enabled))
  376. return false;
  377. var time = DateTime.Now.TimeOfDay;
  378. var backgroundcolor = "Gainsboro";
  379. var foregroundcolor = "Black";
  380. var text = "";
  381. var starttime = TimeSpan.MinValue;
  382. var endtime = TimeSpan.MinValue;
  383. if (time < roster.Start)
  384. {
  385. starttime = roster.Start;
  386. endtime = roster.Finish;
  387. text = $"Not Yet Started";
  388. }
  389. else if (time < roster.Finish)
  390. {
  391. starttime = roster.Start;
  392. endtime = roster.Finish;
  393. text = "Overdue";
  394. backgroundcolor = "LightSalmon";
  395. }
  396. else if (time < roster.Start2)
  397. {
  398. starttime = roster.Start2;
  399. endtime = roster.Finish2;
  400. text = "Not Yet Started (2nd Shift)";
  401. }
  402. else if (time < roster.Finish2)
  403. {
  404. starttime = roster.Start2;
  405. endtime = roster.Finish2;
  406. text = "Overdue (2nd Shift)";
  407. backgroundcolor = "LightSalmon";
  408. }
  409. else
  410. {
  411. text = "No time recorded";
  412. backgroundcolor = "LightSalmon";
  413. }
  414. UpdateKanban(kanban,
  415. starttime,
  416. endtime,
  417. "",
  418. backgroundcolor,
  419. foregroundcolor,
  420. text,
  421. ""
  422. );
  423. return true;
  424. }
  425. private void FilterKanbans()
  426. {
  427. var visible = Kanbans.Where(x =>
  428. (x.Name?.ToUpper().Contains(_search.ToUpper()) == true || x.Address?.ToUpper().Contains(_search.ToUpper()) == true)
  429. && (bIncludeInactive || x.Active)
  430. );
  431. Kanban.ItemsSource = visible;
  432. }
  433. private void ProcessImages(CoreTable data)
  434. {
  435. foreach (var row in data.Rows)
  436. {
  437. var imageid = row.Get<Document, Guid>(c => c.ID);
  438. var docData = row.Get<Document, byte[]>(x => x.Data);
  439. if(docData is not null && docData.Length != 0)
  440. {
  441. BitmapImage? img = null;
  442. var empids = Employees.Rows.Where(r => r.Get<Employee, Guid>(c => c.Thumbnail.ID).Equals(imageid))
  443. .Select(r => r.Get<Employee, Guid>(c => c.ID));
  444. foreach (var empid in empids)
  445. {
  446. var kanban = Kanbans.FirstOrDefault(x => string.Equals(x.ID, empid.ToString()));
  447. if (kanban != null)
  448. {
  449. img ??= ImageUtils.LoadImage(docData);
  450. kanban.Image = img;
  451. }
  452. }
  453. }
  454. }
  455. Dispatcher.Invoke(() => { FilterKanbans(); });
  456. }
  457. private void AttendanceMenu_Opened(object sender, RoutedEventArgs e)
  458. {
  459. var menu = sender as ContextMenu;
  460. var model = menu.Tag as AttendanceKanban;
  461. var sick = menu.Items[0] as MenuItem;
  462. var onoff = menu.Items[2] as MenuItem;
  463. if (string.IsNullOrWhiteSpace(model.Clockin) || !string.IsNullOrWhiteSpace(model.Clockout))
  464. onoff.Header = "Clock Employee On to PRS";
  465. else
  466. onoff.Header = "Clock Employee Out of PRS";
  467. var show = menu.Items[4] as MenuItem;
  468. show.Visibility = !model.Active ? Visibility.Visible : Visibility.Collapsed;
  469. var hide = menu.Items[5] as MenuItem;
  470. hide.Visibility = model.Active ? Visibility.Visible : Visibility.Collapsed;
  471. }
  472. private void SickLeave_Click(object sender, RoutedEventArgs e)
  473. {
  474. var actrow = Activities.Rows.FirstOrDefault(
  475. r => r.Get<Activity, bool>(c => c.IsLeave) && r.Get<Activity, bool>(c => c.IsDefault)
  476. );
  477. if (actrow == null)
  478. {
  479. MessageBox.Show("You must set up a default Sick Leave Activity before using this option!");
  480. return;
  481. }
  482. var item = (MenuItem)sender;
  483. var model = (AttendanceKanban)item.Tag;
  484. var empid = Guid.Parse(model.ID);
  485. var row = Employees.Rows.FirstOrDefault(r => r.Get<Employee, Guid>(c => c.ID).Equals(empid));
  486. if (row == null)
  487. {
  488. MessageBox.Show("Cannot Find Employee: " + empid);
  489. return;
  490. }
  491. var emp = row.ToObject<Employee>();
  492. var request = new LeaveRequest();
  493. request.EmployeeLink.ID = empid;
  494. request.From = DateTime.Today;
  495. request.FromTime = DateTime.Now.TimeOfDay;
  496. request.To = DateTime.Today;
  497. request.ToTime = new TimeSpan(23, 59, 59);
  498. request.Status = LeaveRequestStatus.InProgress;
  499. request.LeaveType.ID = actrow.Get<Activity, Guid>(c => c.ID);
  500. request.Notes = string.Format("Marked As Sick at {0:hh\\:mm} by {1}", DateTime.Now, ClientFactory.UserID);
  501. if (new LeaveRequests().EditItems(new[] { request }))
  502. Refresh();
  503. }
  504. private void ClockOnOff_Click(object sender, RoutedEventArgs e)
  505. {
  506. var item = (MenuItem)sender;
  507. var model = (AttendanceKanban)item.Tag;
  508. var empid = Guid.Parse(model.ID);
  509. var bOK = true;
  510. var time = new TimeSpan(DateTime.Now.Hour, DateTime.Now.Minute, 0);
  511. if (Security.IsAllowed<CanChangeStartFinishTimes>())
  512. bOK = TimeEdit.Execute("Enter Time", ref time);
  513. if (!bOK)
  514. return;
  515. if (string.IsNullOrWhiteSpace(model.Clockin) || !string.IsNullOrWhiteSpace(model.Clockout))
  516. {
  517. var timesheet = new TimeSheet();
  518. timesheet.EmployeeLink.ID = empid;
  519. timesheet.Date = DateTime.Today;
  520. timesheet.Start = time;
  521. timesheet.Notes = string.Format("Clocked in at {0:hh\\:mm} by {1}", DateTime.Now, ClientFactory.UserID);
  522. new Client<TimeSheet>().Save(timesheet, "Clocked on from In/Out Board");
  523. Refresh();
  524. }
  525. else
  526. {
  527. var timesheet = new Client<TimeSheet>().Load(
  528. new Filter<TimeSheet>(x => x.Date).IsEqualTo(DateTime.Today).And(x => x.Finish).IsEqualTo(new TimeSpan())
  529. .And(x => x.EmployeeLink.ID)
  530. .IsEqualTo(empid),
  531. new SortOrder<TimeSheet>(x => x.Start)
  532. ).LastOrDefault();
  533. if (timesheet != null)
  534. {
  535. if (!string.IsNullOrWhiteSpace(timesheet.Notes))
  536. timesheet.Notes = timesheet.Notes + "\n";
  537. else
  538. timesheet.Notes = "";
  539. timesheet.Notes = string.Format("{0}Clocked out at {1:hh\\:mm} by {2}", timesheet.Notes, DateTime.Now, ClientFactory.UserID);
  540. timesheet.Finish = time;
  541. new Client<TimeSheet>().Save(timesheet, "Clocked off from In/Out Board");
  542. Refresh();
  543. }
  544. }
  545. }
  546. private void Search_KeyUp(object sender, KeyEventArgs e)
  547. {
  548. _search = Search.Text;
  549. if (string.IsNullOrWhiteSpace(Search.Text) || e.Key == Key.Return) FilterKanbans();
  550. }
  551. private void Export_Click(object sender, RoutedEventArgs e)
  552. {
  553. var form = new DynamicExportForm(typeof(TimeSheet), TimeSheets.Columns.Select(x => x.ColumnName));
  554. if (form.ShowDialog() != true)
  555. return;
  556. var export = new Client<TimeSheet>().Query(
  557. new Filter<TimeSheet>(x => x.Date).IsEqualTo(DateTime.Today),
  558. Columns.None<TimeSheet>().Add(form.Fields),
  559. LookupFactory.DefineSort<TimeSheet>()
  560. );
  561. ExcelExporter.DoExport<TimeSheet>(export, string.Format("Attendance {0:dd-MMM-yy}", DateTime.Today));
  562. }
  563. private void ShowAll_Click(object sender, RoutedEventArgs e)
  564. {
  565. if (string.Equals(ShowAll.Content as string, "Show All"))
  566. {
  567. ShowAll.Content = "Hide Inactive";
  568. bIncludeInactive = true;
  569. }
  570. else
  571. {
  572. ShowAll.Content = "Show All";
  573. bIncludeInactive = false;
  574. }
  575. FilterKanbans();
  576. }
  577. private void ShowOnInOut_Click(object sender, RoutedEventArgs e)
  578. {
  579. var menu = sender as MenuItem;
  580. var model = menu.Tag as AttendanceKanban;
  581. UpdateInOutStatus(model, true);
  582. }
  583. private void UpdateInOutStatus(AttendanceKanban model, bool include)
  584. {
  585. var id = Guid.Parse(model.ID);
  586. var row = Employees.Rows.FirstOrDefault(r => r.Get<Employee, Guid>(c => c.ID) == id);
  587. if (row != null)
  588. {
  589. var emp = new Employee { ID = id, ShowOnInOutBoard = include };
  590. new Client<Employee>().Save(emp, include ? "Added To" : "Removed From" + " In/Out Board", (o, e) => { });
  591. row.Set<Employee, bool>(x => x.ShowOnInOutBoard, include);
  592. model.Active = include;
  593. }
  594. }
  595. private void RemoveFromInOut_Click(object sender, RoutedEventArgs e)
  596. {
  597. var menu = sender as MenuItem;
  598. var model = menu.Tag as AttendanceKanban;
  599. UpdateInOutStatus(model, false);
  600. FilterKanbans();
  601. }
  602. }
  603. }