public async Task <string> CreateTimerHoursAsync(DateTimeOffset dateTime, string requestId = "")
        {
            _logger.LogInformation($"RequestId: {requestId} - TimerHourRepository_CreateTimerHoursAsync called.");
            try
            {
                // Create JSON object
                dynamic fieldsObject = new JObject();
                fieldsObject.Date      = dateTime.ToString("MM/dd/yyyy");
                fieldsObject.StartTime = dateTime.ToString("h:mm tt");
                fieldsObject.StopTime  = "InProgress";
                dynamic jsonObject = new JObject();
                jsonObject.fields = fieldsObject;

                // Get the site list
                var userObjectIdentifier = _userContext.User.FindFirst(AzureAdAuthenticationBuilderExtensions.ObjectIdentifierType)?.Value;
                var siteList             = await _graphSharePointService.GetSiteListAsync(userObjectIdentifier, ListSchema.TimerHoursSchema);

                // Call graph to create the item in the SHarePoint List
                var entryId = await _graphSharePointService.CreateSiteListItemAsync(siteList, jsonObject.ToString());

                return(entryId);
            }
            catch (Exception ex)
            {
                _logger.LogError($"RequestId: {requestId} - TimerHoursRepository_CreateTimerHoursAsync Service Exception: {ex}");
                throw;
            }
        }
Example #2
0
        public async Task <UserProfile> GetItemAsync()
        {
            try
            {
                var identifier  = _userContext.User.FindFirst(AzureAdAuthenticationBuilderExtensions.ObjectIdentifierType)?.Value;
                var userProfile = new UserProfile
                {
                    Id = identifier
                };

                // Try to get the user profile from from cache
                var cacheKey = _userContext.User.FindFirst(AzureAdAuthenticationBuilderExtensions.ObjectIdentifierType)?.Value;
                userProfile = await _memoryCacheService.TryRetrieveFromCacheAsync(userProfile, cacheKey);

                if (userProfile != null)
                {
                    return(userProfile);
                }

                // Get user info from Graph
                var userInfoResults = await _graphUserService.GetMyUserInfoAsync(identifier);

                // Check to see that users exists on Users List, if not add it with default personal settings
                if (_usersList == null)
                {
                    _usersList = await _graphSharePointService.GetSiteListAsync("users", Helpers.ListSchema.UsersListSchema);
                }
                var queryOptions = new List <QueryOption>();
                queryOptions.Add(new QueryOption("filter", @"startswith(fields/ObjectIdentifier,'" + identifier + "')"));
                var usersListResults = await _graphSharePointService.GetSiteListItemsAsync(_usersList, queryOptions);

                if (usersListResults?.Count == 0)
                {
                    // Register user in Users List
                    // Create JSON object to add the user in the list
                    dynamic userListFieldsObject = new JObject();

                    userListFieldsObject.ObjectIdentifier          = identifier;
                    userListFieldsObject.UserMail                  = userInfoResults.Properties["Mail"].ToString() ?? userInfoResults.Properties["Upn"].ToString();
                    userListFieldsObject.FirstDayOfWeek            = _timeTrackerOptions.FirstDayWeek ?? "Monday";
                    userListFieldsObject.EmailNotificationsEnabled = true;
                    userListFieldsObject.AutoSubmitData            = "scheduled";
                    userListFieldsObject.DailyUpdateStatus         = "scheduled";
                    userListFieldsObject.UpdateDate                = DateTime.Now;
                    userListFieldsObject.AutoSubmitStatus          = "initial";
                    userListFieldsObject.SubmitDate                = Convert.ToDateTime("01/01/2017");

                    dynamic userListRootObject = new JObject();
                    userListRootObject.fields = userListFieldsObject;

                    // Call graph to create the entry i the list
                    await _graphSharePointService.CreateSiteListItemAsync(_usersList, userListRootObject.ToString());

                    // Call graph again to fetch the newly created entry (to confirm and have the object expected for functional below
                    usersListResults = await _graphSharePointService.GetSiteListItemsAsync(_usersList, queryOptions);
                }

                //var firstDayWeek = _timeTrackerOptions.FirstDayWeek;
                var firstDayWeek = usersListResults[0].Properties["FirstDayOfWeek"].ToString();

                // Get groups the user belongs to
                //var memberOfResults = await _graphUserService.GetMemberOfAsync();

                // Get manager info for the user
                var managerResults = await _graphUserService.GetMyManagerAsync(identifier);

                // Get the user direct reports list
                var isManager = await _graphUserService.GetMyHasDirectReportsAsync(identifier);

                var dailyUpdateStatus = usersListResults[0].Properties["DailyUpdateStatus"].ToString();

                var updateDate = usersListResults[0].Properties["UpdateDate"].ToString();

                var autoSubmitStatus = usersListResults[0].Properties["AutoSubmitStatus"].ToString();

                var submitDate = usersListResults[0].Properties["SubmitDate"].ToString();

                userProfile = new UserProfile
                {
                    Id = userInfoResults.Id,

                    Fields = new UserProfileFields
                    {
                        ObjectIdentifier = userInfoResults.Id,
                        DisplayName      = userInfoResults.DisplayName,
                        Upn         = userInfoResults.Properties["Upn"].ToString(),
                        Mail        = userInfoResults.Properties["Mail"].ToString(),
                        UserPicture = userInfoResults.Properties["Picture"].ToString(),
                        IsManager   = isManager,
                        //IsAdmin = memberOfResults.Exists(x => x.DisplayName == _timeTrackerOptions.AdminGroup),
                        IsAdmin = await _graphUserService.GetMemberOfAsync(_timeTrackerOptions.AdminGroup),
                        //IsHr = memberOfResults.Exists(x => x.DisplayName == _timeTrackerOptions.HrGroup),
                        IsHr = await _graphUserService.GetMemberOfAsync(_timeTrackerOptions.HrGroup),

                        // TODO: Store this in personalization settings for user, for now just set to default which is true
                        EmailNotifications = Convert.ToBoolean(usersListResults[0].Properties["EmailNotificationsEnabled"]),
                        Manager            = managerResults.DisplayName,
                        ManagerPicture     = managerResults.Properties["Picture"].ToString(),
                        SpSiteId           = _timeTrackerOptions.SharePointSiteId,
                        FirstDayWeek       = firstDayWeek,
                        DailyUpdateStatus  = dailyUpdateStatus,
                        UpdateDate         = Convert.ToDateTime(updateDate),
                        AutoSubmitStatus   = autoSubmitStatus,
                        SubmitDate         = Convert.ToDateTime(submitDate)
                    }
                };

                // Write the user profile to cache
                await _memoryCacheService.SaveToCacheAsync(userProfile, cacheKey);

                return(userProfile);
            }
            catch (Exception ex)
            {
                _logger.LogError("Error getting user in repository: " + ex.Message);
                return(null);
            }
        }
        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 async Task SendNotificationAsync(GraphResultItem sendToObject, NotificationType notificationType, string messageBody = "")
        {
            try
            {
                if (sendToObject == null)
                {
                    throw new ArgumentNullException(nameof(sendToObject));
                }

                var userProfile = await _userProfileRepository.GetItemAsync();

                // Create notification entry and persist
                var notification = new Notifications
                {
                    Fields = new NotificationsFields
                    {
                        SentToMail   = sendToObject.Properties["Mail"].ToString(),
                        SentToName   = sendToObject.DisplayName,
                        SentFromMail = userProfile.Fields.Mail ?? userProfile.Fields.Upn,
                        SentFromName = userProfile.Fields.DisplayName,
                        SentDate     = DateTime.Now,
                        MessageBody  = messageBody
                    }
                };

                if (!_timeTrackerOptions.HrNotificationAlerts && sendToObject.Id == "inbox")
                {
                    // Don't create the notification alert for HR if disabled in app settings
                }
                else
                {
                    // Get the SpSiteList, if the list does not exists, it will create one
                    var notificationsSiteList = await _graphSharePointService.GetSiteListAsync(sendToObject.Id, ListSchema.NotificationsListSchema);

                    // Create JSON object to update or create WORK HOURS (aka employee entries) in SharePoint
                    dynamic notificationsFieldsObject = new JObject();
                    notificationsFieldsObject.SentToMail   = notification.Fields.SentToMail;
                    notificationsFieldsObject.SentDate     = notification.Fields.SentDate;
                    notificationsFieldsObject.SentFromMail = notification.Fields.SentFromMail;
                    notificationsFieldsObject.MessageBody  = notification.Fields.MessageBody ?? "";

                    dynamic notificationsRootObject = new JObject();
                    notificationsRootObject.fields = notificationsFieldsObject;

                    // Add new notification in SharePoint
                    var result = await _graphSharePointService.CreateSiteListItemAsync(notificationsSiteList, notificationsRootObject.ToString());
                }

                // If user elected to get notifications by email, send the notification email
                if (userProfile.Fields.EmailNotifications)
                {
                    var emailTemplate = "/" + notificationType.ToString() + "_template.html";

                    // Send email TODO: Add localization to subject parameter below
                    await _graphUserService.SendEmailAsync(userProfile.Fields.ObjectIdentifier, notification.Fields.SentToMail, "Notification from Time Tracker", emailTemplate);
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Error sending a notification in workflow for WorkHours: " + ex.Message);
            }
        }
        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);
        }
        public async Task SubmitHoursAsync(IEnumerable <WorkHours> workHoursToSubmit, string userObjectIdentifier, GraphResultItem managerOfUser, string messageBody = "")
        {
            try
            {
                if (workHoursToSubmit == null)
                {
                    throw new ArgumentNullException(nameof(workHoursToSubmit));
                }
                if (((List <WorkHours>)workHoursToSubmit)?.Count == 0)
                {
                    return;                                                   // Nothing to do
                }
                if (String.IsNullOrEmpty(userObjectIdentifier))
                {
                    return;                                             // Nothing to do
                }
                // Try to get the work hours from cache
                var workHoursListCollectionPage = new ListCollectionPage <WorkHours>();
                var dateQuery = workHoursToSubmit.ToList();
                // Works for longer Date yyyyMMdd
                var cacheKey            = userObjectIdentifier + dateQuery[0].Fields.Date.Remove(6);
                var workHoursCacheEntry = await _cacheService.TryRetrieveFromCacheAsync(workHoursListCollectionPage, cacheKey);

                if (workHoursCacheEntry != null)
                {
                    workHoursListCollectionPage = workHoursCacheEntry;
                }

                var managerObjectIdentifier = managerOfUser.Id ?? "";

                var teamHoursSiteList = new SiteList();

                if (String.IsNullOrEmpty(managerObjectIdentifier))
                {
                    // Skip manager by passing report hours identifier as manager identifier and handling that when building the models for the report by setting the manager display name to blank
                    managerObjectIdentifier   = "";
                    managerOfUser.DisplayName = "";
                    teamHoursSiteList         = await _graphSharePointService.GetSiteListAsync("entries", ListSchema.ReportHoursListSchema);
                }

                // Get the SpSiteList, if the list does not exists, it will create one
                var workHoursSiteList = workHoursListCollectionPage.SiteList;
                if (String.IsNullOrEmpty(workHoursSiteList.ListId))
                {
                    workHoursSiteList = await _graphSharePointService.GetSiteListAsync(userObjectIdentifier, ListSchema.WorkHoursListSchema);
                }
                if (!String.IsNullOrEmpty(managerObjectIdentifier))
                {
                    teamHoursSiteList = await _graphSharePointService.GetSiteListAsync(managerObjectIdentifier, ListSchema.TeamHoursListSchema);
                }

                var teamHoursRow         = new TeamHours();
                var submittedDate        = DateTime.Now;
                var hasRequestedRevision = false;
                var tasksList            = new List <Task>();
                var workHoursDate        = DateTime.Now;

                foreach (var workHours in workHoursToSubmit)
                {
                    // Only count not submitted and requieres revision
                    if (workHours.Fields.ItemState == ItemState.NotSubmitted || workHours.Fields.ItemState == ItemState.RequiresRevision)
                    {
                        //Update the workHoursDate so we can assamble the message of the notification
                        workHoursDate = DateTime.ParseExact(workHours.Fields.Date, "yyyyMMdd", CultureInfo.InvariantCulture);

                        // To track if there is an entry that has a requiered revision
                        if (!hasRequestedRevision && workHours.Fields.ItemState == ItemState.RequiresRevision)
                        {
                            hasRequestedRevision = true;
                        }

                        teamHoursRow.Fields.Date             = workHours.Fields.Date;
                        teamHoursRow.Fields.ObjectIdentifier = workHours.Fields.ObjectIdentifier;

                        teamHoursRow.Fields.MeetingHours   += workHours.Fields.MeetingHours;
                        teamHoursRow.Fields.MeetingMinutes += workHours.Fields.MeetingMinutes;

                        if (workHours.Fields.MeetingAdjustedHours != 0 || workHours.Fields.MeetingAdjustedMinutes != 0)
                        {
                            teamHoursRow.Fields.MeetingAdjustedHours   += workHours.Fields.MeetingAdjustedHours;
                            teamHoursRow.Fields.MeetingAdjustedMinutes += workHours.Fields.MeetingAdjustedMinutes;
                        }
                        else
                        {
                            teamHoursRow.Fields.MeetingAdjustedHours   += workHours.Fields.MeetingHours;
                            teamHoursRow.Fields.MeetingAdjustedMinutes += workHours.Fields.MeetingMinutes;
                        }

                        teamHoursRow.Fields.EmailHours   += workHours.Fields.EmailHours;
                        teamHoursRow.Fields.EmailMinutes += workHours.Fields.EmailMinutes;

                        if (workHours.Fields.EmailAdjustedHours != 0 || workHours.Fields.EmailAdjustedMinutes != 0)
                        {
                            teamHoursRow.Fields.EmailAdjustedHours   += workHours.Fields.EmailAdjustedHours;
                            teamHoursRow.Fields.EmailAdjustedMinutes += workHours.Fields.EmailAdjustedMinutes;
                        }
                        else
                        {
                            teamHoursRow.Fields.EmailAdjustedHours   += workHours.Fields.EmailHours;
                            teamHoursRow.Fields.EmailAdjustedMinutes += workHours.Fields.EmailMinutes;
                        }

                        teamHoursRow.Fields.OtherHours   += workHours.Fields.OtherHours;
                        teamHoursRow.Fields.OtherMinutes += workHours.Fields.OtherMinutes;

                        if (workHours.Fields.OtherAdjustedHours != 0 || workHours.Fields.OtherAdjustedMinutes != 0)
                        {
                            teamHoursRow.Fields.OtherAdjustedHours   += workHours.Fields.OtherAdjustedHours;
                            teamHoursRow.Fields.OtherAdjustedMinutes += workHours.Fields.OtherAdjustedMinutes;
                        }
                        else
                        {
                            teamHoursRow.Fields.OtherAdjustedHours   += workHours.Fields.OtherHours;
                            teamHoursRow.Fields.OtherAdjustedMinutes += workHours.Fields.OtherMinutes;
                        }

                        teamHoursRow.Fields.TeamHoursItemState = ItemState.NotSubmitted;
                        teamHoursRow.Fields.ItemState          = ItemState.Submitted;
                        teamHoursRow.Fields.SubmittedDate      = submittedDate;

                        // Create JSON object to update WORK HOURS (aka employee entries) in SharePoint
                        dynamic workHoursFieldsObject = new JObject();
                        if (String.IsNullOrEmpty(managerObjectIdentifier))
                        {
                            // Skip submit to manager and send to HR since user does not has manager
                            workHoursFieldsObject.TeamHoursItemState     = ItemState.Submitted.ToString();
                            workHoursFieldsObject.TeamHoursSubmittedDate = submittedDate;
                        }
                        workHoursFieldsObject.ItemState     = ItemState.Submitted.ToString();
                        workHoursFieldsObject.SubmittedDate = submittedDate;

                        dynamic workHoursRootObject = new JObject();
                        workHoursRootObject.fields = workHoursFieldsObject;

                        // Update List Item in WorkHours List
                        await _graphSharePointService.UpdateSiteListItemAsync(workHoursSiteList, workHours.Id, workHoursRootObject.ToString());
                    }
                }

                // Adjust minutes to hours due the sum (above)
                var timeSpan = new TimeSpan(teamHoursRow.Fields.MeetingHours, teamHoursRow.Fields.MeetingMinutes, 0);
                teamHoursRow.Fields.MeetingHours   = Convert.ToInt16(timeSpan.Hours + (timeSpan.Days * 24));
                teamHoursRow.Fields.MeetingMinutes = Convert.ToInt16(timeSpan.Minutes);

                timeSpan = new TimeSpan(teamHoursRow.Fields.MeetingAdjustedHours, teamHoursRow.Fields.MeetingAdjustedMinutes, 0);
                teamHoursRow.Fields.MeetingAdjustedHours   = Convert.ToInt16(timeSpan.Hours + (timeSpan.Days * 24));
                teamHoursRow.Fields.MeetingAdjustedMinutes = Convert.ToInt16(timeSpan.Minutes);

                timeSpan = new TimeSpan(teamHoursRow.Fields.EmailHours, teamHoursRow.Fields.EmailMinutes, 0);
                teamHoursRow.Fields.EmailHours   = Convert.ToInt16(timeSpan.Hours + (timeSpan.Days * 24));
                teamHoursRow.Fields.EmailMinutes = Convert.ToInt16(timeSpan.Minutes);

                timeSpan = new TimeSpan(teamHoursRow.Fields.EmailAdjustedHours, teamHoursRow.Fields.EmailAdjustedMinutes, 0);
                teamHoursRow.Fields.EmailAdjustedHours   = Convert.ToInt16(timeSpan.Hours + (timeSpan.Days * 24));
                teamHoursRow.Fields.EmailAdjustedMinutes = Convert.ToInt16(timeSpan.Minutes);

                timeSpan = new TimeSpan(teamHoursRow.Fields.OtherHours, teamHoursRow.Fields.OtherMinutes, 0);
                teamHoursRow.Fields.OtherHours   = Convert.ToInt16(timeSpan.Hours + (timeSpan.Days * 24));
                teamHoursRow.Fields.OtherMinutes = Convert.ToInt16(timeSpan.Minutes);

                timeSpan = new TimeSpan(teamHoursRow.Fields.OtherAdjustedHours, teamHoursRow.Fields.OtherAdjustedMinutes, 0);
                teamHoursRow.Fields.OtherAdjustedHours   = Convert.ToInt16(timeSpan.Hours + (timeSpan.Days * 24));
                teamHoursRow.Fields.OtherAdjustedMinutes = Convert.ToInt16(timeSpan.Minutes);


                // Create JSON object to add a new list item in team Hours list in SharePoint
                dynamic teamHoursFieldsObject = new JObject();
                teamHoursFieldsObject.ObjectIdentifier       = teamHoursRow.Fields.ObjectIdentifier;
                teamHoursFieldsObject.Date                   = teamHoursRow.Fields.Date;
                teamHoursFieldsObject.MeetingHours           = teamHoursRow.Fields.MeetingHours;
                teamHoursFieldsObject.MeetingMinutes         = teamHoursRow.Fields.MeetingMinutes;
                teamHoursFieldsObject.MeetingAdjustedHours   = teamHoursRow.Fields.MeetingAdjustedHours;
                teamHoursFieldsObject.MeetingAdjustedMinutes = teamHoursRow.Fields.MeetingAdjustedMinutes;
                teamHoursFieldsObject.EmailHours             = teamHoursRow.Fields.EmailHours;
                teamHoursFieldsObject.EmailMinutes           = teamHoursRow.Fields.EmailMinutes;
                teamHoursFieldsObject.EmailAdjustedHours     = teamHoursRow.Fields.EmailAdjustedHours;
                teamHoursFieldsObject.EmailAdjustedMinutes   = teamHoursRow.Fields.EmailAdjustedMinutes;
                teamHoursFieldsObject.OtherHours             = teamHoursRow.Fields.OtherHours;
                teamHoursFieldsObject.OtherMinutes           = teamHoursRow.Fields.OtherMinutes;
                teamHoursFieldsObject.OtherAdjustedHours     = teamHoursRow.Fields.OtherAdjustedHours;
                teamHoursFieldsObject.OtherAdjustedMinutes   = teamHoursRow.Fields.OtherAdjustedMinutes;
                teamHoursFieldsObject.AdjustedHoursReason    = "" + teamHoursRow.Fields.AdjustedHoursReason;
                if (String.IsNullOrEmpty(managerObjectIdentifier))
                {
                    // Skip submit to manager and send to HR since user does not has manager
                    teamHoursFieldsObject.TeamHoursItemState     = ItemState.Submitted.ToString();
                    teamHoursFieldsObject.TeamHoursSubmittedDate = submittedDate;
                }
                else
                {
                    teamHoursFieldsObject.TeamHoursItemState = teamHoursRow.Fields.TeamHoursItemState.ToString();
                }
                teamHoursFieldsObject.ItemState     = teamHoursRow.Fields.ItemState.ToString();
                teamHoursFieldsObject.SubmittedDate = teamHoursRow.Fields.SubmittedDate;

                dynamic teamHoursRootObject = new JObject();
                teamHoursRootObject.fields = teamHoursFieldsObject;

                // If submit is not due to a request revision, create team hours entry otherwise we only update the existing one
                if (hasRequestedRevision)
                {
                    // Update existing team hours entry (this is the case for requesting revision)
                    List <QueryOption> options = new List <QueryOption>();
                    options.Add(new QueryOption("filter", @"startswith(fields/Date,'" + teamHoursRow.Fields.Date + "') and startswith(fields/ObjectIdentifier,'" + teamHoursRow.Fields.ObjectIdentifier + "')"));

                    var teamHoursResults = await _graphSharePointService.GetSiteListItemsAsync(teamHoursSiteList, options);

                    var updateResults = await _graphSharePointService.UpdateSiteListItemAsync(teamHoursSiteList, teamHoursResults[0].Id, teamHoursRootObject.ToString());
                }
                else
                {
                    // Create List Item in TeamHours list
                    var createResults = await _graphSharePointService.CreateSiteListItemAsync(teamHoursSiteList, teamHoursRootObject.ToString());
                }


                // Create notification and send email
                //var messageBody = _workflowServiceHelper.ComposeMessageBody(NotificationType.SubmitWorkHours, workHoursDate);
                await _workflowServiceHelper.SendNotificationAsync(managerOfUser, NotificationType.SubmitWorkHours, messageBody);

                // Clear te cache
                await _cacheService.ClearCacheAsync(cacheKey);
            }
            catch (Exception ex)
            {
                _logger.LogError("Error submitting work hours in workflow: " + ex.Message);
            }
        }
        public async Task SubmitHoursAsync(IEnumerable <TeamHours> teamHoursToSubmit, string messageBody = "")
        {
            try
            {
                if (teamHoursToSubmit == null)
                {
                    throw new ArgumentNullException(nameof(teamHoursToSubmit));
                }
                var hoursToSubmit = teamHoursToSubmit.ToList();
                if (hoursToSubmit?.Count == 0)
                {
                    return;                            // Nothing to do
                }
                // Get the Team hours site list for current user, if the list does not exists, it will create one
                var userProfile = await _userProfileRepository.GetItemAsync();

                var managerObjectIdentifier = userProfile.Id;
                var teamHoursSiteList       = await _graphSharePointService.GetSiteListAsync(managerObjectIdentifier, ListSchema.TeamHoursListSchema);

                var reportHoursSiteList = await _graphSharePointService.GetSiteListAsync(_reportHoursListIdentifier, ListSchema.ReportHoursListSchema);

                // Try fetching the data from cache
                var dateKey  = hoursToSubmit[0].Fields.Date.ToString();
                var cacheKey = managerObjectIdentifier + dateKey;
                await _cacheService.ClearCacheAsync(cacheKey);

                var teamHoursSubmitList = teamHoursToSubmit.ToList();
                var submittedDate       = DateTime.Now;
                var teamHoursDate       = DateTime.Now;

                foreach (var item in teamHoursToSubmit)
                {
                    // Hours Submitted, but NO HR Report.
                    //if (item.Fields.TeamHoursItemState == ItemState.NotSubmitted || item.Fields.TeamHoursItemState == ItemState.RequiresRevision)
                    if (item.Fields.TeamHoursItemState == ItemState.NotSubmitted && item.Fields.ItemState == ItemState.Submitted)
                    {
                        // Update teamHoursDate with last date value which is used in the notificationn message body
                        // Date contains a string! yyyyMMdd
                        teamHoursDate = DateTime.ParseExact(item.Fields.Date, "yyyyMMdd", CultureInfo.InvariantCulture);

                        // Create JSON object to update Team Hours in SharePoint
                        dynamic teamHoursFieldsObject = new JObject();
                        teamHoursFieldsObject.TeamHoursItemState     = ItemState.Submitted.ToString();
                        teamHoursFieldsObject.TeamHoursSubmittedDate = submittedDate;

                        dynamic teamHoursRootObject = new JObject();
                        teamHoursRootObject.fields = teamHoursFieldsObject;

                        // Create JSON object to create entries in Report Hours in SharePoint
                        dynamic reportHoursFieldsObject = new JObject();
                        reportHoursFieldsObject.ObjectIdentifier        = item.Fields.ObjectIdentifier;
                        reportHoursFieldsObject.ManagerObjectIdentifier = managerObjectIdentifier;
                        reportHoursFieldsObject.Date = item.Fields.Date;
                        reportHoursFieldsObject.TeamHoursItemState     = ItemState.Submitted.ToString();
                        reportHoursFieldsObject.TeamHoursSubmittedDate = submittedDate;
                        reportHoursFieldsObject.ItemState     = item.Fields.ItemState.ToString();
                        reportHoursFieldsObject.SubmittedDate = item.Fields.SubmittedDate;

                        dynamic reportHoursRootObject = new JObject();
                        reportHoursRootObject.fields = reportHoursFieldsObject;

                        // Update the team hours entry in SharePoint
                        await _graphSharePointService.UpdateSiteListItemAsync(teamHoursSiteList, item.Id, teamHoursRootObject.ToString());

                        // Create List Item in ReportHours List
                        var createResult = await _graphSharePointService.CreateSiteListItemAsync(reportHoursSiteList, reportHoursRootObject.ToString());

                        // Get work hours list for this teamHours entry and update the TeamHoursItemState
                        var workHoursSiteList = await _graphSharePointService.GetSiteListAsync(item.Fields.ObjectIdentifier, ListSchema.WorkHoursListSchema);

                        // Works for longer yyyyMMdd date.
                        var dateQuery       = item.Fields.Date.Remove(6);
                        var workHoursResult = await _graphSharePointService.GetSiteListItemsAsync(workHoursSiteList, dateQuery);

                        if (workHoursResult?.Count == 0)
                        {
                            throw new ServiceException(new Error {
                                Code = ErrorConstants.Codes.InvalidRequest, Message = "Can't retrieve work hours for a team hours entry"
                            });
                        }

                        foreach (var workHoursItem in workHoursResult)
                        {
                            // Create JSON object to update Work Hours list in SharePoint
                            dynamic workHoursFieldsObject = new JObject();
                            workHoursFieldsObject.TeamHoursItemState     = ItemState.Submitted.ToString();
                            workHoursFieldsObject.TeamHoursSubmittedDate = submittedDate;

                            dynamic workHoursRootObject = new JObject();
                            workHoursRootObject.fields = workHoursFieldsObject;

                            // Update List Item in WorkHours List
                            // var updateResult = await _graphSharePointService.UpdateSiteListItemAsync(workHoursSiteList, workHoursItem.Id, workHoursRootObject.ToString());
                            await _graphSharePointService.UpdateSiteListItemAsync(workHoursSiteList, workHoursItem.Id, workHoursRootObject.ToString());
                        }
                    }
                }

                // Create notification and send email
                var sendToObject = new GraphResultItem
                {
                    Id         = _hrListIdentifier,
                    Properties = new Dictionary <string, object>
                    {
                        { "Mail", _timeTrackerOptions.HrNotificationMail },
                    }
                };
                // Send notification
                //var messageBody = _workflowServiceHelper.ComposeMessageBody(NotificationType.SubmitTeamHours, teamHoursDate);
                await _workflowServiceHelper.SendNotificationAsync(sendToObject, NotificationType.SubmitTeamHours, messageBody);
            }

            catch (Exception ex)
            {
                _logger.LogError("Error saving team hours in submit: " + ex.Message);
                throw ex;
            }
        }
        public async Task SaveItemAsync(Notifications modelData)
        {
            try
            {
                if (modelData == null)
                {
                    throw new ArgumentNullException(nameof(modelData));
                }

                var notificationsList = new List <Notifications>();
                var notificationListCollectionPage = new ListCollectionPage <Notifications>();
                var userProfile = await _userProfileRepository.GetItemAsync();

                var userObjectIdentifier = userProfile.Id;
                var hrSiteListId         = _timeTrackerOptions.NotificationsListPrefix + _hrListIdentifier;

                // Try to get the work hours from cache
                var cacheKey = userObjectIdentifier;
                var notificationsListEntry = await _memoryCacheService.TryRetrieveFromCacheAsync(notificationListCollectionPage, cacheKey);

                if (notificationsListEntry != null)
                {
                    notificationsList = notificationsListEntry.DataList.ToList();
                    notificationListCollectionPage = notificationsListEntry;

                    // remove from cache so it can be updated and saved back in cache
                    await _memoryCacheService.RemoveFromCacheAsync(cacheKey);

                    // Find in the entries from cache the item to update then save it back to cache
                    var cacheUpdated = false;
                    foreach (var item in notificationsList)
                    {
                        if (item.Id == modelData.Id && item.ListId == modelData.ListId)
                        {
                            if (modelData.Fields.SentDate != null)
                            {
                                item.Fields.SentDate = modelData.Fields.SentDate;
                            }
                            if (modelData.Fields.ReadDate != null && !String.IsNullOrEmpty(modelData.Id))
                            {
                                item.Fields.ReadDate = modelData.Fields.ReadDate;
                            }
                            cacheUpdated = true;
                        }
                    }

                    // Save the entry back to cache
                    if (cacheUpdated)
                    {
                        notificationListCollectionPage.DataList = notificationsList;
                        await _memoryCacheService.SaveToCacheAsync(notificationListCollectionPage, cacheKey);
                    }
                }

                // Get the SpSiteList, if the list does not exists, it will create one
                if (String.IsNullOrEmpty(notificationListCollectionPage.SiteList.ListId))
                {
                    notificationListCollectionPage.SiteList = await _graphSharePointService.GetSiteListAsync(userObjectIdentifier, ListSchema.NotificationsListSchema);
                }
                var notificationsSiteList = notificationListCollectionPage.SiteList;
                if (modelData.ListId == hrSiteListId)
                {
                    notificationsSiteList.ListId = modelData.ListId;                                   // Change ListId if shared notifications in box (for HR)
                }
                // Add relevant properties to cache entry
                if (String.IsNullOrEmpty(notificationListCollectionPage.ObjectIdentifier))
                {
                    notificationListCollectionPage.ObjectIdentifier = userObjectIdentifier;
                }

                // Create JSON object to update or create WORK HOURS (aka employee entries) in SharePoint
                dynamic notificationsFieldsObject = new JObject();
                notificationsFieldsObject.SentToMail = modelData.Fields.SentToMail;
                if (modelData.Fields.SentDate != null)
                {
                    notificationsFieldsObject.SentDate = modelData.Fields.SentDate;
                }
                if (modelData.Fields.ReadDate != null && !String.IsNullOrEmpty(modelData.Id))
                {
                    notificationsFieldsObject.ReadDate = modelData.Fields.ReadDate;
                }
                notificationsFieldsObject.MessageBody = modelData.Fields.MessageBody ?? "";

                dynamic notificationsRootObject = new JObject();
                notificationsRootObject.fields = notificationsFieldsObject;

                // If Id empty we assume new notification: note creating via this methd does not trigger sending emails, that is part of workflow service helper
                if (String.IsNullOrEmpty(modelData.Id))
                {
                    // Add new notification in SharePoint
                    var result = await _graphSharePointService.CreateSiteListItemAsync(notificationsSiteList, notificationsRootObject.ToString());
                }
                else
                {
                    // Update an existing notification
                    var result = await _graphSharePointService.UpdateSiteListItemAsync(notificationsSiteList, modelData.Id, notificationsRootObject.ToString());
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Error saving notifiction items in repository: " + ex.Message);
                throw;
            }
        }