using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using Comal.Classes;
using InABox.Clients;
using InABox.Core;
using InABox.DynamicGrid;
using InABox.WPF;
using Syncfusion.UI.Xaml.Kanban;
namespace PRSDesktop
{
///
/// Interaction logic for AttendancePanel.xaml
///
public partial class AttendancePanel : UserControl, IPanel
{
private string _search = "";
public CoreTable Activities;
private bool bIncludeInactive;
private readonly DispatcherTimer columnsizer = new();
public CoreTable Employees;
private readonly List Kanbans = new();
public CoreTable LeaveRequests;
public CoreTable TimeSheets;
public AttendancePanel()
{
InitializeComponent();
columnsizer.Interval = new TimeSpan(0, 0, 0, 0, 500);
columnsizer.Tick += Columnsizer_Tick;
columnsizer.IsEnabled = true;
}
public bool IsReady { get; set; }
public event DataModelUpdateEvent OnUpdateDataModel;
public Dictionary Selected()
{
return new Dictionary
{
{ typeof(Employee).EntityName(), Employees.Rows.ToArray() },
{ typeof(TimeSheet).EntityName(), TimeSheets.Rows.ToArray() }
};
}
public void CreateToolbarButtons(IPanelHost host)
{
}
public string SectionName => "Attendance";
public DataModel DataModel(Selection selection)
{
var ids = selection != Selection.None ? Employees.ExtractValues(x => x.ID).ToArray() : new Guid[] { };
var filter = new Filter(x => x.ID).InList(ids);
if (!bIncludeInactive)
{
filter.And(x => x.ShowOnInOutBoard);
}
return new AttendanceDataModel(filter);
}
public void Refresh()
{
using (var cursor = new WaitCursor())
{
var query = new MultiQuery();
query.Add(
new Filter(x => x.Date).IsEqualTo(DateTime.Today),
new Columns(x => x.EmployeeLink.ID)
.Add(x => x.Start)
.Add(x => x.Finish)
.Add(x => x.Address)
.Add(x => x.ActivityLink.ID)
.Add(x => x.SoftwareVersion),
new SortOrder(x => x.Start)
);
query.Add(
new Filter(x => x.From).IsLessThanOrEqualTo(DateTime.Today)
.And(x => x.To).IsGreaterThanOrEqualTo(DateTime.Today)
.And(x => x.Status).IsEqualTo(LeaveRequestStatus.InProgress),
new Columns(x => x.EmployeeLink.ID)
.Add(x => x.From)
.Add(x => x.FromTime)
.Add(x => x.To)
.Add(x => x.ToTime)
.Add(x => x.LeaveType.ID)
);
query.Query();
TimeSheets = query.Get();
LeaveRequests = query.Get();
foreach (var emprow in Employees.Rows)
{
var empid = emprow.Get(c => c.ID);
var kanban = Kanbans.FirstOrDefault(x => string.Equals(x.ID, empid.ToString()));
if (kanban != null)
{
var bOK = CheckTimeSheet(empid, kanban);
if (!bOK)
bOK = CheckLeave(empid, kanban);
if (!bOK)
UpdateKanban(kanban,
TimeSpan.MinValue,
TimeSpan.MinValue,
"",
"White",
"Gainsboro",
"",
""
);
}
}
FilterKanbans();
}
}
public void Setup()
{
Kanban.Columns.Clear();
var filter = LookupFactory.DefineFilter(); //.And(x=>x.Type).IsEqualTo(EmployeeType.Employee);
var tables = Client.QueryMultiple(
new KeyedQueryDef(
filter,
new Columns(
x => x.ID,
x => x.Name,
x => x.Thumbnail.ID,
x => x.Group.ID,
x => x.Group.Description,
x => x.Type,
x => x.UsualStart,
x => x.UsualFinish,
x => x.ShowOnInOutBoard
),
new SortOrder(x => x.Name)),
new KeyedQueryDef());
Employees = tables[nameof(Employee)];
Activities = tables[nameof(Activity)];
CreateColumns();
CreateKanbans();
var imageids = Employees.Rows
.Select(r => r.EntityLinkID(x => x.Thumbnail) ?? Guid.Empty)
.Where(x => x != Guid.Empty).ToArray();
new Client().Query(
new Filter(x => x.ID).InList(imageids),
new Columns(
x => x.ID,
x => x.Data
),
null,
(data, error) => ProcessImages(data)
);
}
public void Shutdown()
{
}
public void Heartbeat(TimeSpan time)
{
}
private void Columnsizer_Tick(object sender, EventArgs e)
{
columnsizer.IsEnabled = false;
ResizeColumns();
columnsizer.IsEnabled = true;
}
private void ResizeColumns()
{
using (var d = Dispatcher.DisableProcessing())
{
var CollapsedWidth = 50;
var CollapsedColumns = 0;
Array.ForEach(Kanban.Columns.ToArray(), x => { CollapsedColumns += x.IsExpanded ? 0 : 1; });
if (Kanban.Columns.Count > 0 && CollapsedColumns != Kanban.Columns.Count)
{
var ColumnWidth = (Kanban.ActualWidth - CollapsedColumns * CollapsedWidth) / (Kanban.Columns.Count - CollapsedColumns) - 2;
if (ColumnWidth != Kanban.ColumnWidth) Kanban.ColumnWidth = ColumnWidth;
}
}
}
private void CreateKanbans()
{
foreach (var row in Employees.Rows)
{
var empid = row.Get(x => x.ID);
var empname = row.Get(x => x.Name);
var groupid = row.Get(x => x.Group.ID);
var imgid = row.Get(x => x.Thumbnail.ID);
var img = PRSDesktop.Resources.anonymous.AsBitmapImage();
var active = row.Get(x => x.ShowOnInOutBoard);
var color = "White";
var kanban = new AttendanceKanban
{
ID = empid.ToString(),
Name = empname,
Category = groupid.ToString(),
Image = img,
Clockin = "",
Clockout = "",
Address = "",
ColorKey = "White",
TextColor = "Gainsboro",
Type = "",
Version = "",
Active = active
};
Kanbans.Add(kanban);
}
}
private void CreateColumns()
{
//Dictionary columns = Employees.ToDictionary(x => x.ID, new System.Linq.Expressions.Expression>[] { x => x.Group.Description });
Kanban.Columns.Clear();
var columns = new List>();
foreach (var row in Employees.Rows)
{
var active = row.Get(c => c.ShowOnInOutBoard);
if (bIncludeInactive || active)
{
var id = row.Get(c => c.Group.ID);
var desc = row.Get(c => c.Group.Description);
if (!columns.Any(x => x.Item1.Equals(id)))
columns.Add(new Tuple(id, desc));
}
}
columns = columns.OrderBy(x => x.Item2).ToList();
foreach (var column in columns)
{
var newcol = new KanbanColumn
{
Title = column.Item1 != Guid.Empty ? column.Item2 : "(No Group Assigned)",
Categories = column.Item1.ToString()
};
newcol.AllowDrag = false;
newcol.AllowDrop = false;
Kanban.Columns.Add(newcol);
}
}
private void UpdateKanban(AttendanceKanban kanban, TimeSpan start, TimeSpan finish, string address, string background, string foreground,
string description, string version)
{
kanban.Clockin = start.TotalMilliseconds > 0 ? string.Format("{0:hh\\:mm}", start) : "";
kanban.Clockout = finish.TotalMilliseconds > 0 ? string.Format("{0:hh\\:mm}", finish) : "";
kanban.Address = address;
kanban.ColorKey = background;
kanban.TextColor = foreground;
kanban.Type = description;
kanban.Version = version;
}
private bool CheckTimeSheet(Guid empid, AttendanceKanban kanban)
{
var firstrow = TimeSheets.Rows.FirstOrDefault(r => r.Get(c => c.EmployeeLink.ID).Equals(empid));
if (firstrow == null)
return false;
var lastrow = TimeSheets.Rows.LastOrDefault(r => r.Get(c => c.EmployeeLink.ID).Equals(empid));
var actid = lastrow.Get(c => c.ActivityLink.ID);
var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get(c => c.ID).Equals(actid));
var color = "White";
var finish = lastrow.Get(c => c.Finish);
if (finish.Ticks > 0 && finish < DateTime.Now - DateTime.Today)
{
color = "Gainsboro";
}
else
{
color = actrow != null ? actrow.Get(c => c.Color) : "";
if (string.IsNullOrWhiteSpace(color))
color = "LightGreen";
}
UpdateKanban(kanban,
firstrow.Get(c => c.Start),
lastrow.Get(c => c.Finish),
lastrow.Get(c => c.Address),
color,
kanban.TextColor = "Black",
actrow != null ? actrow.Get(c => c.Description) : "",
lastrow.Get(c => c.SoftwareVersion)
);
//kanban.Clockin = firstrow != null ? String.Format("{0:hh\\:mm}", firstrow.Get(c => c.Start)) : "";
//kanban.Clockout = (lastrow != null) && (lastrow.Get(c => c.Finish).Ticks > 0) ? String.Format("{0:hh\\:mm}", lastrow.Get(c => c.Finish)) : "";
//kanban.Address = lastrow != null ? lastrow.Get(c => c.Address) : "";
//kanban.ColorKey = color;
//kanban.TextColor = lastrow != null ? "Black" : "Gainsboro";
//kanban.Type = actrow != null ? actrow.Get(c => c.Description) : "";
//kanban.Version = lastrow != null ? lastrow.Get(c => c.SoftwareVersion) : "";
return true;
}
private bool CheckLeave(Guid empid, AttendanceKanban kanban)
{
var row = LeaveRequests.Rows.FirstOrDefault(r => r.Get(c => c.EmployeeLink.ID) == empid);
if (row == null)
return false;
var actid = row.Get(c => c.LeaveType.ID);
var actrow = Equals(actid, Guid.Empty) ? null : Activities.Rows.FirstOrDefault(r => r.Get(c => c.ID).Equals(actid));
var color = actrow?.Get(c => c.Color);
if (string.IsNullOrWhiteSpace(color))
color = "Gainsboro";
var description = actrow?.Get(c => c.Description);
if (string.IsNullOrWhiteSpace(description))
description = "Leave";
UpdateKanban(kanban,
row.Get(c => c.From) == DateTime.Today
? row.Get(c => c.FromTime)
: TimeSpan.MinValue,
row.Get(c => c.To) == DateTime.Today
? row.Get(c => c.ToTime)
: TimeSpan.MinValue,
"",
color,
kanban.TextColor = "Black",
description,
""
);
return true;
}
private void FilterKanbans()
{
var visible = Kanbans.Where(x =>
(x.Name?.ToUpper().Contains(_search.ToUpper()) == true || x.Address?.ToUpper().Contains(_search.ToUpper()) == true)
&& (bIncludeInactive || x.Active)
);
Kanban.ItemsSource = visible;
}
private void ProcessImages(CoreTable data)
{
foreach (var row in data.Rows)
{
var imageid = row.Get(c => c.ID);
BitmapImage img = null;
var empids = Employees.Rows.Where(r => r.Get(c => c.Thumbnail.ID).Equals(imageid))
.Select(r => r.Get(c => c.ID));
foreach (var empid in empids)
{
var kanban = Kanbans.FirstOrDefault(x => string.Equals(x.ID, empid.ToString()));
if (kanban != null)
{
if (img == null)
{
img = new BitmapImage();
img.LoadImage(row.Get(c => c.Data));
}
kanban.Image = img;
}
}
}
Dispatcher.Invoke(() => { FilterKanbans(); });
}
private void AttendanceMenu_Opened(object sender, RoutedEventArgs e)
{
var menu = sender as ContextMenu;
var model = menu.Tag as AttendanceKanban;
var sick = menu.Items[0] as MenuItem;
var onoff = menu.Items[2] as MenuItem;
if (string.IsNullOrWhiteSpace(model.Clockin) || !string.IsNullOrWhiteSpace(model.Clockout))
onoff.Header = "Clock Employee On to PRS";
else
onoff.Header = "Clock Employee Out of PRS";
var show = menu.Items[4] as MenuItem;
show.Visibility = !model.Active ? Visibility.Visible : Visibility.Collapsed;
var hide = menu.Items[5] as MenuItem;
hide.Visibility = model.Active ? Visibility.Visible : Visibility.Collapsed;
}
private void SickLeave_Click(object sender, RoutedEventArgs e)
{
var actrow = Activities.Rows.FirstOrDefault(
r => r.Get(c => c.IsLeave) && r.Get(c => c.IsDefault)
);
if (actrow == null)
{
MessageBox.Show("You must set up a default Sick Leave Activity before using this option!");
return;
}
var item = (MenuItem)sender;
var model = (AttendanceKanban)item.Tag;
var empid = Guid.Parse(model.ID);
var row = Employees.Rows.FirstOrDefault(r => r.Get(c => c.ID).Equals(empid));
if (row == null)
{
MessageBox.Show("Cannot Find Employee: " + empid);
return;
}
var emp = row.ToObject();
var request = new LeaveRequest();
request.EmployeeLink.ID = empid;
request.From = DateTime.Today;
request.FromTime = DateTime.Now.TimeOfDay;
request.To = DateTime.Today;
request.ToTime = emp.UsualFinish != TimeSpan.FromMilliseconds(0) ? emp.UsualFinish : new TimeSpan(23, 59, 59);
request.Status = LeaveRequestStatus.InProgress;
request.LeaveType.ID = actrow.Get(c => c.ID);
request.Notes = string.Format("Marked As Sick at {0:hh\\:mm} by {1}", DateTime.Now, ClientFactory.UserID);
if (new LeaveRequests().EditItems(new[] { request }))
Refresh();
}
private void ClockOnOff_Click(object sender, RoutedEventArgs e)
{
var item = (MenuItem)sender;
var model = (AttendanceKanban)item.Tag;
var empid = Guid.Parse(model.ID);
var bOK = true;
var time = new TimeSpan(DateTime.Now.Hour, DateTime.Now.Minute, 0);
if (Security.IsAllowed())
bOK = TimeEdit.Execute("Enter Time", ref time);
if (!bOK)
return;
if (string.IsNullOrWhiteSpace(model.Clockin) || !string.IsNullOrWhiteSpace(model.Clockout))
{
var timesheet = new TimeSheet();
timesheet.EmployeeLink.ID = empid;
timesheet.Date = DateTime.Today;
timesheet.Start = time;
timesheet.Notes = string.Format("Clocked in at {0:hh\\:mm} by {1}", DateTime.Now, ClientFactory.UserID);
new Client().Save(timesheet, "Clocked on from In/Out Board");
Refresh();
}
else
{
var timesheet = new Client().Load(
new Filter(x => x.Date).IsEqualTo(DateTime.Today).And(x => x.Finish).IsEqualTo(new TimeSpan())
.And(x => x.EmployeeLink.ID)
.IsEqualTo(empid),
new SortOrder(x => x.Start)
).LastOrDefault();
if (timesheet != null)
{
if (!string.IsNullOrWhiteSpace(timesheet.Notes))
timesheet.Notes = timesheet.Notes + "\n";
else
timesheet.Notes = "";
timesheet.Notes = string.Format("{0}Clocked out at {1:hh\\:mm} by {2}", timesheet.Notes, DateTime.Now, ClientFactory.UserID);
timesheet.Finish = time;
new Client().Save(timesheet, "Clocked off from In/Out Board");
Refresh();
}
}
}
private void Search_KeyUp(object sender, KeyEventArgs e)
{
_search = Search.Text;
if (string.IsNullOrWhiteSpace(Search.Text) || e.Key == Key.Return) FilterKanbans();
}
private void Export_Click(object sender, RoutedEventArgs e)
{
var form = new DynamicExportForm(typeof(TimeSheet), TimeSheets.Columns.Select(x => x.ColumnName));
if (form.ShowDialog() != true)
return;
var export = new Client().Query(
new Filter(x => x.Date).IsEqualTo(DateTime.Today),
new Columns(form.Fields),
LookupFactory.DefineSort()
);
ExcelExporter.DoExport(export, string.Format("Attendance {0:dd-MMM-yy}", DateTime.Today));
}
private void ShowAll_Click(object sender, RoutedEventArgs e)
{
if (string.Equals(ShowAll.Content as string, "Show All"))
{
ShowAll.Content = "Hide Inactive";
bIncludeInactive = true;
}
else
{
ShowAll.Content = "Show All";
bIncludeInactive = false;
}
FilterKanbans();
}
private void ShowOnInOut_Click(object sender, RoutedEventArgs e)
{
var menu = sender as MenuItem;
var model = menu.Tag as AttendanceKanban;
UpdateInOutStatus(model, true);
}
private void UpdateInOutStatus(AttendanceKanban model, bool include)
{
var id = Guid.Parse(model.ID);
var row = Employees.Rows.FirstOrDefault(r => r.Get(c => c.ID) == id);
if (row != null)
{
var emp = new Employee { ID = id, ShowOnInOutBoard = include };
new Client().Save(emp, include ? "Added To" : "Removed From" + " In/Out Board", (o, e) => { });
row.Set(x => x.ShowOnInOutBoard, include);
model.Active = include;
}
}
private void RemoveFromInOut_Click(object sender, RoutedEventArgs e)
{
var menu = sender as MenuItem;
var model = menu.Tag as AttendanceKanban;
UpdateInOutStatus(model, false);
FilterKanbans();
}
}
}