AttendancePanel.xaml.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688
  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. new Columns<TimeSheet>(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. new Columns<StandardLeave>(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. new Columns<LeaveRequest>(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. new Columns<Employee>(
  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. new Columns<Document>(
  168. x => x.ID,
  169. x => x.Data
  170. ),
  171. null,
  172. (data, error) => ProcessImages(data)
  173. );
  174. }
  175. public void Shutdown(CancelEventArgs? cancel)
  176. {
  177. }
  178. public void Heartbeat(TimeSpan time)
  179. {
  180. }
  181. private void Columnsizer_Tick(object? sender, EventArgs e)
  182. {
  183. columnsizer.IsEnabled = false;
  184. ResizeColumns();
  185. columnsizer.IsEnabled = true;
  186. }
  187. private void ResizeColumns()
  188. {
  189. using (var d = Dispatcher.DisableProcessing())
  190. {
  191. var CollapsedWidth = 50;
  192. var CollapsedColumns = 0;
  193. Array.ForEach(Kanban.Columns.ToArray(), x => { CollapsedColumns += x.IsExpanded ? 0 : 1; });
  194. if (Kanban.Columns.Count > 0 && CollapsedColumns != Kanban.Columns.Count)
  195. {
  196. var ColumnWidth = (Kanban.ActualWidth - CollapsedColumns * CollapsedWidth) / (Kanban.Columns.Count - CollapsedColumns) - 2;
  197. if (ColumnWidth != Kanban.ColumnWidth)
  198. {
  199. Kanban.ColumnWidth = ColumnWidth;
  200. }
  201. }
  202. }
  203. }
  204. private void CreateKanbans()
  205. {
  206. foreach (var row in Employees.Rows)
  207. {
  208. var empid = row.Get<Employee, Guid>(x => x.ID);
  209. var empname = row.Get<Employee, string>(x => x.Name);
  210. var groupid = row.Get<Employee, Guid>(x => x.Group.ID);
  211. var imgid = row.Get<Employee, Guid>(x => x.Thumbnail.ID);
  212. var img = PRSDesktop.Resources.anonymous.AsBitmapImage();
  213. var active = row.Get<Employee, bool>(x => x.ShowOnInOutBoard);
  214. var color = "White";
  215. var kanban = new AttendanceKanban
  216. {
  217. ID = empid.ToString(),
  218. Name = empname,
  219. Category = groupid.ToString(),
  220. Image = img,
  221. Clockin = "",
  222. Clockout = "",
  223. Address = "",
  224. ColorKey = "White",
  225. TextColor = "Gainsboro",
  226. Type = "",
  227. Version = "",
  228. Active = active
  229. };
  230. Kanbans.Add(kanban);
  231. }
  232. }
  233. private void CreateColumns()
  234. {
  235. //Dictionary<Guid, String> columns = Employees.ToDictionary<Employee, Guid>(x => x.ID, new System.Linq.Expressions.Expression<Func<Employee, object>>[] { x => x.Group.Description });
  236. Kanban.Columns.Clear();
  237. var columns = new List<Tuple<Guid, string>>();
  238. foreach (var row in Employees.Rows)
  239. {
  240. var active = row.Get<Employee, bool>(c => c.ShowOnInOutBoard);
  241. if (bIncludeInactive || active)
  242. {
  243. var id = row.Get<Employee, Guid>(c => c.Group.ID);
  244. var desc = row.Get<Employee, string>(c => c.Group.Description);
  245. if (!columns.Any(x => x.Item1.Equals(id)))
  246. columns.Add(new Tuple<Guid, string>(id, desc));
  247. }
  248. }
  249. columns = columns.OrderBy(x => x.Item2).ToList();
  250. foreach (var column in columns)
  251. {
  252. var newcol = new KanbanColumn
  253. {
  254. Title = column.Item1 != Guid.Empty ? column.Item2 : "(No Group Assigned)",
  255. Categories = column.Item1.ToString()
  256. };
  257. newcol.AllowDrag = false;
  258. newcol.AllowDrop = false;
  259. Kanban.Columns.Add(newcol);
  260. }
  261. }
  262. private void UpdateKanban(AttendanceKanban kanban, TimeSpan start, TimeSpan finish, string address, string background, string foreground,
  263. string description, string version)
  264. {
  265. kanban.Clockin = start.TotalMilliseconds > 0 ? string.Format("{0:hh\\:mm}", start) : "";
  266. kanban.Clockout = finish.TotalMilliseconds > 0 ? string.Format("{0:hh\\:mm}", finish) : "";
  267. kanban.Address = address;
  268. kanban.ColorKey = background;
  269. kanban.TextColor = foreground;
  270. kanban.Type = description;
  271. kanban.Version = version;
  272. }
  273. private bool CheckTimeSheet(Guid empid, AttendanceKanban kanban)
  274. {
  275. var firstrow = TimeSheets.Rows.FirstOrDefault(r => r.Get<TimeSheet, Guid>(c => c.EmployeeLink.ID).Equals(empid));
  276. if (firstrow == null)
  277. return false;
  278. var lastrow = TimeSheets.Rows.LastOrDefault(r => r.Get<TimeSheet, Guid>(c => c.EmployeeLink.ID).Equals(empid));
  279. var actid = lastrow.Get<TimeSheet, Guid>(c => c.ActivityLink.ID);
  280. var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(actid));
  281. var color = "White";
  282. var finish = lastrow.Get<TimeSheet, TimeSpan>(c => c.Finish);
  283. if (finish.Ticks > 0 && finish < DateTime.Now - DateTime.Today)
  284. {
  285. color = "Gainsboro";
  286. }
  287. else
  288. {
  289. color = actrow != null ? actrow.Get<Activity, string>(c => c.Color) : "";
  290. if (string.IsNullOrWhiteSpace(color))
  291. color = "LightGreen";
  292. }
  293. UpdateKanban(kanban,
  294. firstrow.Get<TimeSheet, TimeSpan>(c => c.Start),
  295. lastrow.Get<TimeSheet, TimeSpan>(c => c.Finish),
  296. lastrow.Get<TimeSheet, string>(c => c.Address),
  297. color,
  298. "Black",
  299. actrow != null ? actrow.Get<Activity, string>(c => c.Description) : "",
  300. lastrow.Get<TimeSheet, string>(c => c.SoftwareVersion)
  301. );
  302. //kanban.Clockin = firstrow != null ? String.Format("{0:hh\\:mm}", firstrow.Get<TimeSheet, TimeSpan>(c => c.Start)) : "";
  303. //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)) : "";
  304. //kanban.Address = lastrow != null ? lastrow.Get<TimeSheet, String>(c => c.Address) : "";
  305. //kanban.ColorKey = color;
  306. //kanban.TextColor = lastrow != null ? "Black" : "Gainsboro";
  307. //kanban.Type = actrow != null ? actrow.Get<Activity, String>(c => c.Description) : "";
  308. //kanban.Version = lastrow != null ? lastrow.Get<TimeSheet, String>(c => c.SoftwareVersion) : "";
  309. return true;
  310. }
  311. private bool CheckStandardLeave(Guid empid, AttendanceKanban kanban)
  312. {
  313. var row = StandardLeaves.Rows.FirstOrDefault();
  314. if (row == null)
  315. return false;
  316. var actid = row.Get<StandardLeave, Guid>(c => c.LeaveType.ID);
  317. var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(actid));
  318. var color = actrow?.Get<Activity, string>(c => c.Color);
  319. if (string.IsNullOrWhiteSpace(color))
  320. color = "Gainsboro";
  321. var description = actrow?.Get<Activity, string>(c => c.Description);
  322. if (string.IsNullOrWhiteSpace(description))
  323. description = "Leave";
  324. UpdateKanban(kanban,
  325. row.Get<StandardLeave, DateTime>(c => c.From) == DateTime.Today
  326. ? row.Get<StandardLeave, TimeSpan>(c => c.FromTime)
  327. : TimeSpan.MinValue,
  328. row.Get<StandardLeave, DateTime>(c => c.To) == DateTime.Today
  329. ? row.Get<StandardLeave, TimeSpan>(c => c.ToTime)
  330. : TimeSpan.MinValue,
  331. "",
  332. color,
  333. "Black",
  334. description,
  335. ""
  336. );
  337. return true;
  338. }
  339. private bool CheckLeaveRequest(Guid empid, AttendanceKanban kanban)
  340. {
  341. var row = LeaveRequests.Rows.FirstOrDefault(r => r.Get<LeaveRequest, Guid>(c => c.EmployeeLink.ID) == empid);
  342. if (row == null)
  343. return false;
  344. var actid = row.Get<LeaveRequest, Guid>(c => c.LeaveType.ID);
  345. var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get<Activity, Guid>(c => c.ID).Equals(actid));
  346. var color = actrow?.Get<Activity, string>(c => c.Color);
  347. if (string.IsNullOrWhiteSpace(color))
  348. color = "Gainsboro";
  349. var description = actrow?.Get<Activity, string>(c => c.Description);
  350. if (string.IsNullOrWhiteSpace(description))
  351. description = "Leave";
  352. UpdateKanban(kanban,
  353. row.Get<LeaveRequest, DateTime>(c => c.From) == DateTime.Today
  354. ? row.Get<LeaveRequest, TimeSpan>(c => c.FromTime)
  355. : TimeSpan.MinValue,
  356. row.Get<LeaveRequest, DateTime>(c => c.To) == DateTime.Today
  357. ? row.Get<LeaveRequest, TimeSpan>(c => c.ToTime)
  358. : TimeSpan.MinValue,
  359. "",
  360. color,
  361. "Black",
  362. description,
  363. ""
  364. );
  365. return true;
  366. }
  367. private bool CheckRoster(Guid empid, AttendanceKanban kanban, CoreRow empdata)
  368. {
  369. var rosterdata = empdata.Get<Employee, String>(c => c.Roster);
  370. var rosters = !String.IsNullOrWhiteSpace(rosterdata)
  371. ? Serialization.Deserialize<List<EmployeeRosterItem>>(rosterdata).ToArray()
  372. : null;
  373. var roster = RosterUtils.GetRoster(rosters, empdata.Get<Employee,DateTime>(c=>c.RosterStart), DateTime.Today);
  374. if ((roster == null) || (!roster.Enabled))
  375. return false;
  376. var time = DateTime.Now.TimeOfDay;
  377. var backgroundcolor = "Gainsboro";
  378. var foregroundcolor = "Black";
  379. var text = "";
  380. var starttime = TimeSpan.MinValue;
  381. var endtime = TimeSpan.MinValue;
  382. if (time < roster.Start)
  383. {
  384. starttime = roster.Start;
  385. endtime = roster.Finish;
  386. text = $"Not Yet Started";
  387. }
  388. else if (time < roster.Finish)
  389. {
  390. starttime = roster.Start;
  391. endtime = roster.Finish;
  392. text = "Overdue";
  393. backgroundcolor = "LightSalmon";
  394. }
  395. else if (time < roster.Start2)
  396. {
  397. starttime = roster.Start2;
  398. endtime = roster.Finish2;
  399. text = "Not Yet Started (2nd Shift)";
  400. }
  401. else if (time < roster.Finish2)
  402. {
  403. starttime = roster.Start2;
  404. endtime = roster.Finish2;
  405. text = "Overdue (2nd Shift)";
  406. backgroundcolor = "LightSalmon";
  407. }
  408. else
  409. {
  410. text = "No time recorded";
  411. backgroundcolor = "LightSalmon";
  412. }
  413. UpdateKanban(kanban,
  414. starttime,
  415. endtime,
  416. "",
  417. backgroundcolor,
  418. foregroundcolor,
  419. text,
  420. ""
  421. );
  422. return true;
  423. }
  424. private void FilterKanbans()
  425. {
  426. var visible = Kanbans.Where(x =>
  427. (x.Name?.ToUpper().Contains(_search.ToUpper()) == true || x.Address?.ToUpper().Contains(_search.ToUpper()) == true)
  428. && (bIncludeInactive || x.Active)
  429. );
  430. Kanban.ItemsSource = visible;
  431. }
  432. private void ProcessImages(CoreTable data)
  433. {
  434. foreach (var row in data.Rows)
  435. {
  436. var imageid = row.Get<Document, Guid>(c => c.ID);
  437. var docData = row.Get<Document, byte[]>(x => x.Data);
  438. if(docData is not null && docData.Length != 0)
  439. {
  440. BitmapImage? img = null;
  441. var empids = Employees.Rows.Where(r => r.Get<Employee, Guid>(c => c.Thumbnail.ID).Equals(imageid))
  442. .Select(r => r.Get<Employee, Guid>(c => c.ID));
  443. foreach (var empid in empids)
  444. {
  445. var kanban = Kanbans.FirstOrDefault(x => string.Equals(x.ID, empid.ToString()));
  446. if (kanban != null)
  447. {
  448. img ??= ImageUtils.LoadImage(docData);
  449. kanban.Image = img;
  450. }
  451. }
  452. }
  453. }
  454. Dispatcher.Invoke(() => { FilterKanbans(); });
  455. }
  456. private void AttendanceMenu_Opened(object sender, RoutedEventArgs e)
  457. {
  458. var menu = sender as ContextMenu;
  459. var model = menu.Tag as AttendanceKanban;
  460. var sick = menu.Items[0] as MenuItem;
  461. var onoff = menu.Items[2] as MenuItem;
  462. if (string.IsNullOrWhiteSpace(model.Clockin) || !string.IsNullOrWhiteSpace(model.Clockout))
  463. onoff.Header = "Clock Employee On to PRS";
  464. else
  465. onoff.Header = "Clock Employee Out of PRS";
  466. var show = menu.Items[4] as MenuItem;
  467. show.Visibility = !model.Active ? Visibility.Visible : Visibility.Collapsed;
  468. var hide = menu.Items[5] as MenuItem;
  469. hide.Visibility = model.Active ? Visibility.Visible : Visibility.Collapsed;
  470. }
  471. private void SickLeave_Click(object sender, RoutedEventArgs e)
  472. {
  473. var actrow = Activities.Rows.FirstOrDefault(
  474. r => r.Get<Activity, bool>(c => c.IsLeave) && r.Get<Activity, bool>(c => c.IsDefault)
  475. );
  476. if (actrow == null)
  477. {
  478. MessageBox.Show("You must set up a default Sick Leave Activity before using this option!");
  479. return;
  480. }
  481. var item = (MenuItem)sender;
  482. var model = (AttendanceKanban)item.Tag;
  483. var empid = Guid.Parse(model.ID);
  484. var row = Employees.Rows.FirstOrDefault(r => r.Get<Employee, Guid>(c => c.ID).Equals(empid));
  485. if (row == null)
  486. {
  487. MessageBox.Show("Cannot Find Employee: " + empid);
  488. return;
  489. }
  490. var emp = row.ToObject<Employee>();
  491. var request = new LeaveRequest();
  492. request.EmployeeLink.ID = empid;
  493. request.From = DateTime.Today;
  494. request.FromTime = DateTime.Now.TimeOfDay;
  495. request.To = DateTime.Today;
  496. request.ToTime = new TimeSpan(23, 59, 59);
  497. request.Status = LeaveRequestStatus.InProgress;
  498. request.LeaveType.ID = actrow.Get<Activity, Guid>(c => c.ID);
  499. request.Notes = string.Format("Marked As Sick at {0:hh\\:mm} by {1}", DateTime.Now, ClientFactory.UserID);
  500. if (new LeaveRequests().EditItems(new[] { request }))
  501. Refresh();
  502. }
  503. private void ClockOnOff_Click(object sender, RoutedEventArgs e)
  504. {
  505. var item = (MenuItem)sender;
  506. var model = (AttendanceKanban)item.Tag;
  507. var empid = Guid.Parse(model.ID);
  508. var bOK = true;
  509. var time = new TimeSpan(DateTime.Now.Hour, DateTime.Now.Minute, 0);
  510. if (Security.IsAllowed<CanChangeStartFinishTimes>())
  511. bOK = TimeEdit.Execute("Enter Time", ref time);
  512. if (!bOK)
  513. return;
  514. if (string.IsNullOrWhiteSpace(model.Clockin) || !string.IsNullOrWhiteSpace(model.Clockout))
  515. {
  516. var timesheet = new TimeSheet();
  517. timesheet.EmployeeLink.ID = empid;
  518. timesheet.Date = DateTime.Today;
  519. timesheet.Start = time;
  520. timesheet.Notes = string.Format("Clocked in at {0:hh\\:mm} by {1}", DateTime.Now, ClientFactory.UserID);
  521. new Client<TimeSheet>().Save(timesheet, "Clocked on from In/Out Board");
  522. Refresh();
  523. }
  524. else
  525. {
  526. var timesheet = new Client<TimeSheet>().Load(
  527. new Filter<TimeSheet>(x => x.Date).IsEqualTo(DateTime.Today).And(x => x.Finish).IsEqualTo(new TimeSpan())
  528. .And(x => x.EmployeeLink.ID)
  529. .IsEqualTo(empid),
  530. new SortOrder<TimeSheet>(x => x.Start)
  531. ).LastOrDefault();
  532. if (timesheet != null)
  533. {
  534. if (!string.IsNullOrWhiteSpace(timesheet.Notes))
  535. timesheet.Notes = timesheet.Notes + "\n";
  536. else
  537. timesheet.Notes = "";
  538. timesheet.Notes = string.Format("{0}Clocked out at {1:hh\\:mm} by {2}", timesheet.Notes, DateTime.Now, ClientFactory.UserID);
  539. timesheet.Finish = time;
  540. new Client<TimeSheet>().Save(timesheet, "Clocked off from In/Out Board");
  541. Refresh();
  542. }
  543. }
  544. }
  545. private void Search_KeyUp(object sender, KeyEventArgs e)
  546. {
  547. _search = Search.Text;
  548. if (string.IsNullOrWhiteSpace(Search.Text) || e.Key == Key.Return) FilterKanbans();
  549. }
  550. private void Export_Click(object sender, RoutedEventArgs e)
  551. {
  552. var form = new DynamicExportForm(typeof(TimeSheet), TimeSheets.Columns.Select(x => x.ColumnName));
  553. if (form.ShowDialog() != true)
  554. return;
  555. var export = new Client<TimeSheet>().Query(
  556. new Filter<TimeSheet>(x => x.Date).IsEqualTo(DateTime.Today),
  557. new Columns<TimeSheet>(form.Fields),
  558. LookupFactory.DefineSort<TimeSheet>()
  559. );
  560. ExcelExporter.DoExport<TimeSheet>(export, string.Format("Attendance {0:dd-MMM-yy}", DateTime.Today));
  561. }
  562. private void ShowAll_Click(object sender, RoutedEventArgs e)
  563. {
  564. if (string.Equals(ShowAll.Content as string, "Show All"))
  565. {
  566. ShowAll.Content = "Hide Inactive";
  567. bIncludeInactive = true;
  568. }
  569. else
  570. {
  571. ShowAll.Content = "Show All";
  572. bIncludeInactive = false;
  573. }
  574. FilterKanbans();
  575. }
  576. private void ShowOnInOut_Click(object sender, RoutedEventArgs e)
  577. {
  578. var menu = sender as MenuItem;
  579. var model = menu.Tag as AttendanceKanban;
  580. UpdateInOutStatus(model, true);
  581. }
  582. private void UpdateInOutStatus(AttendanceKanban model, bool include)
  583. {
  584. var id = Guid.Parse(model.ID);
  585. var row = Employees.Rows.FirstOrDefault(r => r.Get<Employee, Guid>(c => c.ID) == id);
  586. if (row != null)
  587. {
  588. var emp = new Employee { ID = id, ShowOnInOutBoard = include };
  589. new Client<Employee>().Save(emp, include ? "Added To" : "Removed From" + " In/Out Board", (o, e) => { });
  590. row.Set<Employee, bool>(x => x.ShowOnInOutBoard, include);
  591. model.Active = include;
  592. }
  593. }
  594. private void RemoveFromInOut_Click(object sender, RoutedEventArgs e)
  595. {
  596. var menu = sender as MenuItem;
  597. var model = menu.Tag as AttendanceKanban;
  598. UpdateInOutStatus(model, false);
  599. FilterKanbans();
  600. }
  601. }
  602. }