AttendancePanel.xaml.cs 26 KB

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