public static Dictionary <string, short> ComputeDailyTotals(WorkHoursFields whf) { Dictionary <string, short> FinalDictObj = new Dictionary <string, short>(); //For Email Hours if (whf.EmailAdjustedHours > 0 || whf.EmailAdjustedMinutes > 0) { FinalDictObj.Add("FinalEmailHrs", whf.EmailAdjustedHours); FinalDictObj.Add("FinalEmailMins", whf.EmailAdjustedMinutes); } else { FinalDictObj.Add("FinalEmailHrs", whf.EmailHours); FinalDictObj.Add("FinalEmailMins", whf.EmailMinutes); } //For Meeting Hours if (whf.MeetingAdjustedHours > 0 || whf.MeetingAdjustedMinutes > 0) { FinalDictObj.Add("FinalMeetingHrs", whf.MeetingAdjustedHours); FinalDictObj.Add("FinalMeetingMins", whf.MeetingAdjustedMinutes); } else { FinalDictObj.Add("FinalMeetingHrs", whf.MeetingHours); FinalDictObj.Add("FinalMeetingMins", whf.MeetingMinutes); } //For Other Hours if (whf.OtherAdjustedHours > 0 || whf.OtherAdjustedMinutes > 0) { FinalDictObj.Add("FinalOtherHrs", whf.OtherAdjustedHours); FinalDictObj.Add("FinalOtherMins", whf.OtherAdjustedMinutes); } else { FinalDictObj.Add("FinalOtherHrs", whf.OtherHours); FinalDictObj.Add("FinalOtherMins", whf.OtherMinutes); } // Total Calculation var Mins = FinalDictObj["FinalEmailMins"] + FinalDictObj["FinalMeetingMins"] + FinalDictObj["FinalOtherMins"]; var totalMins = Mins % 60; var totalHrs = FinalDictObj["FinalEmailHrs"] + FinalDictObj["FinalMeetingHrs"] + FinalDictObj["FinalOtherHrs"] + Mins / 60; FinalDictObj.Add("FinalTotalHrs", (short)totalHrs); FinalDictObj.Add("FinalTotalMins", (short)totalMins); return(FinalDictObj); }
public async Task <IEnumerable <WorkHours> > ComputeHours( DateTime date, IEnumerable <GraphResultItem> results, SiteList siteList, string userObjectIdentifier, TimeTrackerOptions timeTrackerOptions, GraphAppSharePointService graphSharePointService, GraphAppCalendarService graphCalendarService, GraphAppTasksService graphTasksService, GraphAppMailService graphMailService, TimezoneHelper timezoneHelper, List <string> categoryFilter, List <string> showAsFilter, int allDayCountHours) { try { var workHoursList = new List <WorkHours>(); // Create a variable to track last day retrieved from SharePoint var lastDay = new DateTime(date.Year, date.Month, 1); foreach (var item in results) { var workHoursFields = ConvertToWorkHours(item, userObjectIdentifier); lastDay = DateTime.ParseExact(workHoursFields.Date, "yyyyMMdd", CultureInfo.InvariantCulture); workHoursList.Add(new WorkHours { Id = item.Id, Fields = workHoursFields }); } // WorkHours Compute Logic // // New Logic - retrieve 1 week at a time then pause & repeat. // Create Arrays[] to hold partial results. // Calculate: 1. BeginDate = beginning of Month // 2. EndOfWeek - BeginDate +7 days // (if EndOfWeek => Now, EndOfWeek = Now, finishWeeks = true) // 3. BeginDate = EndOfWeek date +1 // 4. if !(finishWeeks), pause - to avoid throttling // 5. Repeat 2-4. var fullCalendar = new List <GraphResultItem>(); var fullMail = new List <GraphResultItem>(); var fullTaskItems = new List <JToken>(); bool finishWeeks = false; // Add remaining days till today for calendar var endOfMonth = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month)); if (lastDay.Date != endOfMonth.Date) { // Ensure we only calculate until today if (DateTime.Now.Month == date.Month && endOfMonth > DateTime.Now) { endOfMonth = DateTime.Now; } endOfMonth = new DateTime(endOfMonth.Year, endOfMonth.Month, endOfMonth.Day, 23, 59, 59, 999); // Skip lastDay TODO: test when today is the first if (endOfMonth.Date > lastDay.Date && lastDay.Day != 1) { lastDay = lastDay.AddDays(1); } lastDay = new DateTime(lastDay.Year, lastDay.Month, lastDay.Day, 0, 0, 0, 0); // Get calendar items //var calendarResults = await graphCalendarService.GetCalendarEventsAsync(lastDay, endOfMonth); var taskCalendar = Task.Run(() => graphCalendarService.GetCalendarEventsAsync(lastDay, endOfMonth)); var weeklyCalResults = await taskCalendar; if (weeklyCalResults != null) { foreach (var item in weeklyCalResults) { fullCalendar.Add(item); } } // Get Emails in inbox for count //var emailResults = await graphMailService.GetMailItemsAsync(lastDay, endOfMonth); var taskMail = Task.Run(() => graphMailService.GetMailItemsAsync(lastDay, endOfMonth)); var weeklyMailResults = await taskMail; if (weeklyMailResults != null) { foreach (var item in weeklyMailResults) { fullMail.Add(item); } } // Get task items for count //var tasksResults = await graphTasksService.GetUserTasksAsync(lastDay, endOfMonth); // TODO: Varma: uncomment the following after ensuring app context is supported //var taskTasksItems = Task.Run(() => graphTasksService.GetUserTasksAsync(lastDay, endOfMonth)); //var weeklyTaskItemsResults = await taskTasksItems; //if (weeklyTaskItemsResults != null) //{ // foreach (var item in weeklyTaskItemsResults) // { // fullTaskItems.Add(item); // } //} // *** Loop Back and do more weeks *** // // To track the day that is being calculated in the while var dateToCalculate = lastDay; while (dateToCalculate.Date <= endOfMonth.Date) { var workHoursFields = new WorkHoursFields { Date = dateToCalculate.ToString("yyyyMMdd"), ObjectIdentifier = userObjectIdentifier, TeamHoursItemState = ItemState.NotSubmitted, ItemState = ItemState.NotSubmitted, AdjustedHoursReason = "", TeamHoursSubmittedDate = new DateTime(), SubmittedDate = new DateTime(), MeetingHours = 0, MeetingMinutes = 0, EmailHours = 0, EmailMinutes = 0, OtherHours = 0, OtherMinutes = 0, OtherTimerHours = 0, OtherTimerMinutes = 0, EmailTimerHours = 0, EmailTimerMinutes = 0, MeetingTimerHours = 0, MeetingTimerMinutes = 0 }; #region calendar items // var calendarResults = await taskCalendar; // Variables needed for calculating sum for calendar events double totalTimeSpan = 0; var span = TimeSpan.FromHours(0); // Calculate time spent in calendar events //////// if (fullCalendar != null) { // TODO: can refactor into a select type statement and remove foreach? var calendarEventsToSum = calendarResults.Select<> foreach (var item in fullCalendar) { // Filter out rules var includeItem = true; var categories = (List <string>)item.Properties["Categories"]; foreach (var value in categories) { if (categoryFilter.Contains(value)) { includeItem = false; } } if (showAsFilter.Contains(item.Properties["ShowAs"].ToString())) { includeItem = false; } if (includeItem && !Convert.ToBoolean(item.Properties["IsCancelled"])) { if (Convert.ToBoolean(item.Properties["IsAllDay"])) { if (allDayCountHours > 0) { totalTimeSpan = totalTimeSpan + allDayCountHours; } } else { var startTime = Convert.ToDateTime(item.Properties["Start"]); var endTime = Convert.ToDateTime(item.Properties["End"]); if (startTime.Date == dateToCalculate.Date) { span = endTime.Subtract(startTime); totalTimeSpan = totalTimeSpan + span.TotalHours; } } } } span = TimeSpan.FromHours(totalTimeSpan); workHoursFields.MeetingHours = Convert.ToInt16(span.Hours); workHoursFields.MeetingMinutes = Convert.ToInt16(span.Minutes); } #endregion #region mail items // var emailResults = await taskMail; // Variables needed for calculating counts of emails var sentEmailCount = 0; var receivedEmailCount = 0; // Calculate time spent in email ////////////// if (fullMail != null) { foreach (var item in fullMail) { // Filter out rules var includeItem = true; var categories = (List <string>)item.Properties["Categories"]; foreach (var category in categories) { if (categoryFilter.Contains(category)) { includeItem = false; } } if (includeItem) { if (Convert.ToDateTime(item.Properties["DateTime"]).Date == dateToCalculate.Date) { if (item.Properties["EmailType"].ToString() == "received") { if (Convert.ToBoolean(item.Properties["IsRead"])) { receivedEmailCount = receivedEmailCount + 1; } } else if (item.Properties["EmailType"].ToString() == "sent") { sentEmailCount = sentEmailCount + 1; } } } } // Calculate total time in minutes span = TimeSpan.FromMinutes((sentEmailCount * timeTrackerOptions.SentEmailTime) + (receivedEmailCount * timeTrackerOptions.ReceivedEmailTime)); workHoursFields.EmailHours = Convert.ToInt16(span.Hours); workHoursFields.EmailMinutes = Convert.ToInt16(span.Minutes); } #endregion #region task items // var tasksResults = await taskTasksItems; // Variables needed for calculating counts of tasks var tasksCount = 0; if (fullTaskItems?.Count > 0) { // Initialize the Time Zone based on appSettings value. var definedZone = timezoneHelper.timeZoneInfo; // TODO: can refactor into a select type statement and remove foreach? var calendarEventsToSum = calendarResults.Select<> foreach (var item in fullTaskItems) { var dateTime = DateTime.Parse(item["startDateTime"]["dateTime"].ToString()); // Adjust for TimeZone stored in appSettings. var adjustedDateTime = TimeZoneInfo.ConvertTime(dateTime, definedZone); if (adjustedDateTime.Date == dateToCalculate.Date) { tasksCount = tasksCount + 1; } } // Calculate total time in minutes span = TimeSpan.FromMinutes(tasksCount * timeTrackerOptions.TaskTime); workHoursFields.OtherHours = Convert.ToInt16(span.Hours); workHoursFields.OtherMinutes = Convert.ToInt16(span.Minutes); } #endregion var workHours = new WorkHours { Id = "", Fields = workHoursFields }; // Persist to SharePoint if (dateToCalculate.Date < DateTime.Now.Date) { // Create JSON object dynamic fieldsObject = new JObject(); fieldsObject.ObjectIdentifier = workHoursFields.ObjectIdentifier; fieldsObject.Date = workHoursFields.Date; fieldsObject.MeetingHours = workHoursFields.MeetingHours; fieldsObject.MeetingMinutes = workHoursFields.MeetingMinutes; fieldsObject.MeetingAdjustedHours = workHoursFields.MeetingAdjustedHours; fieldsObject.MeetingAdjustedMinutes = workHoursFields.MeetingAdjustedMinutes; fieldsObject.EmailHours = workHoursFields.EmailHours; fieldsObject.EmailMinutes = workHoursFields.EmailMinutes; fieldsObject.EmailAdjustedHours = workHoursFields.EmailAdjustedHours; fieldsObject.EmailAdjustedMinutes = workHoursFields.EmailAdjustedMinutes; fieldsObject.OtherHours = workHoursFields.OtherHours; fieldsObject.OtherMinutes = workHoursFields.OtherMinutes; fieldsObject.OtherAdjustedHours = workHoursFields.OtherAdjustedHours; fieldsObject.OtherAdjustedMinutes = workHoursFields.OtherAdjustedMinutes; fieldsObject.AdjustedHoursReason = workHoursFields.AdjustedHoursReason; fieldsObject.TeamHoursItemState = workHoursFields.TeamHoursItemState.ToString(); fieldsObject.ItemState = workHoursFields.ItemState.ToString(); fieldsObject.MeetingTimerHours = workHoursFields.MeetingTimerHours.ToString(); fieldsObject.MeetingTimerMinutes = workHoursFields.MeetingTimerMinutes.ToString(); fieldsObject.EmailTimerHours = workHoursFields.EmailTimerHours.ToString(); fieldsObject.EmailTimerMinutes = workHoursFields.EmailTimerMinutes.ToString(); fieldsObject.OtherTimerHours = workHoursFields.OtherTimerHours.ToString(); fieldsObject.OtherTimerMinutes = workHoursFields.OtherTimerMinutes.ToString(); dynamic jsonObject = new JObject(); jsonObject.fields = fieldsObject; // Call graph to create the item in the SHarePoint List var saveResults = await graphSharePointService.CreateSiteListItemAsync(siteList, jsonObject.ToString()); workHours.Id = saveResults; workHoursList.Add(workHours); } dateToCalculate = dateToCalculate.AddDays(1); } } return(workHoursList); } catch (Exception ex) { throw; } }
public static WorkHoursFields ConvertToWorkHours(GraphResultItem graphResultsItem, string userObjectIdentifier) { try { var workHoursFields = new WorkHoursFields(); object objectValue; workHoursFields.ObjectIdentifier = userObjectIdentifier; if (graphResultsItem.Properties.TryGetValue("Date", out objectValue)) { workHoursFields.Date = objectValue.ToString(); } if (graphResultsItem.Properties.TryGetValue("MeetingHours", out objectValue)) { workHoursFields.MeetingHours = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("MeetingMinutes", out objectValue)) { workHoursFields.MeetingMinutes = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("MeetingAdjustedHours", out objectValue)) { workHoursFields.MeetingAdjustedHours = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("MeetingAdjustedMinutes", out objectValue)) { workHoursFields.MeetingAdjustedMinutes = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("MeetingTimerHours", out objectValue)) { workHoursFields.MeetingTimerHours = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("MeetingTimerMinutes", out objectValue)) { workHoursFields.MeetingTimerMinutes = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("EmailHours", out objectValue)) { workHoursFields.EmailHours = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("EmailMinutes", out objectValue)) { workHoursFields.EmailMinutes = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("EmailAdjustedHours", out objectValue)) { workHoursFields.EmailAdjustedHours = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("EmailAdjustedMinutes", out objectValue)) { workHoursFields.EmailAdjustedMinutes = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("EmailTimerHours", out objectValue)) { workHoursFields.EmailTimerHours = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("EmailTimerMinutes", out objectValue)) { workHoursFields.EmailTimerMinutes = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("OtherHours", out objectValue)) { workHoursFields.OtherHours = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("OtherMinutes", out objectValue)) { workHoursFields.OtherMinutes = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("OtherTimerHours", out objectValue)) { workHoursFields.OtherTimerHours = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("OtherTimerMinutes", out objectValue)) { workHoursFields.OtherTimerMinutes = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("OtherAdjustedHours", out objectValue)) { workHoursFields.OtherAdjustedHours = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("OtherAdjustedMinutes", out objectValue)) { workHoursFields.OtherAdjustedMinutes = Convert.ToInt16(objectValue); } if (graphResultsItem.Properties.TryGetValue("AdjustedHoursReason", out objectValue)) { workHoursFields.AdjustedHoursReason = objectValue.ToString(); } if (graphResultsItem.Properties.TryGetValue("TeamHoursItemState", out objectValue)) { workHoursFields.TeamHoursItemState = (ItemState)Enum.Parse(typeof(ItemState), objectValue.ToString()); } if (graphResultsItem.Properties.TryGetValue("TeamHoursSubmittedDate", out objectValue)) { workHoursFields.TeamHoursSubmittedDate = Convert.ToDateTime(objectValue.ToString()); } if (graphResultsItem.Properties.TryGetValue("ItemState", out objectValue)) { workHoursFields.ItemState = (ItemState)Enum.Parse(typeof(ItemState), objectValue.ToString()); } if (graphResultsItem.Properties.TryGetValue("SubmittedDate", out objectValue)) { workHoursFields.SubmittedDate = Convert.ToDateTime(objectValue.ToString()); } return(workHoursFields); } catch (Exception ex) { throw; } }
public async Task <bool> UpdateAnalytics() { try { // Get the site list string objectIdentifier = Guid.NewGuid().ToString(); var analyticsSiteList = await _graphSharePointService.GetSiteListAsync(objectIdentifier, ListSchema.TotalHrsListSchema); bool processForToday = true; var analyticsRecords = await _graphSharePointService.GetSiteListItemsAsync(analyticsSiteList); processForToday = analyticsRecords.Count > 0; // get the reportHours var reportHoursSiteList = await _graphSharePointService.GetSiteListAsync(_reportHoursListIdentifier, ListSchema.ReportHoursListSchema); // if is first time process the submissions during current month, else check for any submits today. //var submittedDate = DateTime.Now.Date.ToString("yyyyMMdd", CultureInfo.InvariantCulture); ////var todayDate = DateTime.ParseExact(submittedDate, "yyyyMMdd", CultureInfo.InvariantCulture); //submittedDate = processForToday ? submittedDate : submittedDate.Remove(6); //var options = new List<QueryOption>(); //options.Add(new QueryOption("filter", @"startswith(fields/TeamHoursSubmittedDate,'" + submittedDate + "')")); //var reportHoursList = await _graphSharePointService.GetSiteListItemsAsync(reportHoursSiteList, options); var submitDate = DateTime.Now.Date.AddDays(-1); var startDate = processForToday ? submitDate : submitDate.AddDays(1 - submitDate.Day); var endDate = submitDate; // processForToday ? submitDate : startDate.AddMonths(1).AddDays(-1); var reportHoursList = await _graphSharePointService.GetSiteListItemsAsync(reportHoursSiteList); var filteredList = reportHoursList.Where(k => (DateTime.Parse(k.Properties["TeamHoursSubmittedDate"].ToString()).Date >= startDate) && (DateTime.Parse(k.Properties["TeamHoursSubmittedDate"].ToString()).Date <= endDate)).ToList(); foreach (var item in filteredList) { // Get work hours list for this teamHours entry and update the TeamHoursItemState var userObjectIdentifier = item.Properties["ObjectIdentifier"].ToString(); var workHoursSiteList = await _graphSharePointService.GetSiteListAsync(userObjectIdentifier, ListSchema.WorkHoursListSchema); // Works for longer yyyyMMdd date. var dateQuery = item.Properties["Date"].ToString().Remove(6); var workHoursResult = await _graphSharePointService.GetSiteListItemsAsync(workHoursSiteList, dateQuery); if (workHoursResult?.Count == 0) { throw new ServiceException(new Error { Code = "invalidRequest", Message = "Can't retrieve work hours for a team hours entry" }); } foreach (var workHoursItem in workHoursResult) { if ((workHoursItem.Properties["TeamHoursItemState"].ToString() != ItemState.Submitted.ToString()) || (item.Properties["TeamHoursSubmittedDate"].ToString() != workHoursItem.Properties["TeamHoursSubmittedDate"].ToString())) { // log error and continue; // continue; //TODO: find out why only one item is getting updated in workhours with teamhourssubmitteddate. } WorkHoursFields whf = WorkHoursRepository.ConvertToWorkHours(workHoursItem, userObjectIdentifier); Dictionary <string, short> dailyTotals = Helpers.HoursComputeHelper.ComputeDailyTotals(whf); // calculate totals and overtime int totalHours = Convert.ToInt16(dailyTotals["FinalTotalHrs"]); int totalMins = Convert.ToInt16(dailyTotals["FinalTotalMins"]); int dailyGoalHrs = _timeTrackerOptions.DayHours; int dailyGoalMin = 0; int OTHours = 0; int OTMins = 0; if ((totalHours > dailyGoalHrs) || ((totalHours == dailyGoalHrs) && (dailyGoalMin > 0) && (totalMins > dailyGoalMin))) { OTHours = totalHours - dailyGoalHrs; OTMins = totalMins - dailyGoalMin; //TODO: verify -ve values if (OTMins < 0) { OTMins += 60; OTHours--; } } // create analytic record. // Create JSON object to add a new list item in Daily OT Hours list in SharePoint dynamic dailyOTHoursFieldsObject = new JObject(); dailyOTHoursFieldsObject.ObjectIdentifier = userObjectIdentifier; dailyOTHoursFieldsObject.Date = workHoursItem.Properties["Date"].ToString(); dailyOTHoursFieldsObject.TotalHours = totalHours; dailyOTHoursFieldsObject.TotalMins = totalMins; dailyOTHoursFieldsObject.OTHours = OTHours; dailyOTHoursFieldsObject.OTMins = OTMins; dynamic dailyOTHoursRootObject = new JObject(); dailyOTHoursRootObject.fields = dailyOTHoursFieldsObject; var saveResults = await _graphSharePointService.CreateSiteListItemAsync(analyticsSiteList, dailyOTHoursRootObject.ToString()); } } } catch (Exception ex) { _logger.LogError("Error saving team hours in submit: " + ex.Message); throw ex; } return(true); }