/// <summary>
        /// Creates and sends the relevant request to approve or deny a time off request.
        /// </summary>
        /// <param name="kronosReqId">The Kronos request id for the time off request.</param>
        /// <param name="kronosUserId">The Kronos user id for the assigned user.</param>
        /// <param name="teamsTimeOffEntity">The Teams time off entity.</param>
        /// <param name="timeOffRequestMapping">The mapping for the time off request.</param>
        /// <param name="managerMessage">The manager action message from Teams.</param>
        /// <param name="approved">Whether the request should be approved (true) or denied (false).</param>
        /// <param name="kronosTimeZone">The Kronos timezone.</param>
        /// <returns>Returns a bool that represents whether the request was a success (true) or not (false).</returns>
        internal async Task <bool> ApproveOrDenyTimeOffRequestInKronos(
            string kronosReqId,
            string kronosUserId,
            TimeOffRequestItem teamsTimeOffEntity,
            TimeOffMappingEntity timeOffRequestMapping,
            string managerMessage,
            bool approved,
            string kronosTimeZone)
        {
            var provider = CultureInfo.InvariantCulture;

            this.telemetryClient.TrackTrace($"{Resource.ProcessTimeOffRequestsAsync} start at: {DateTime.Now.ToString("o", provider)}");

            // Teams provides date times in UTC so convert to the local time.
            var localStartDateTime = this.utility.UTCToKronosTimeZone(teamsTimeOffEntity.StartDateTime, kronosTimeZone);
            var localEndDateTime   = this.utility.UTCToKronosTimeZone(teamsTimeOffEntity.EndDateTime, kronosTimeZone);

            var queryDateSpanStart = localStartDateTime.ToString(this.appSettings.KronosQueryDateSpanFormat, CultureInfo.InvariantCulture);
            var queryDateSpanEnd   = localEndDateTime.ToString(this.appSettings.KronosQueryDateSpanFormat, CultureInfo.InvariantCulture);

            var timeOffRequestQueryDateSpan = $"{queryDateSpanStart}-{queryDateSpanEnd}";

            // Get all the necessary prerequisites.
            var allRequiredConfigurations = await this.utility.GetAllConfigurationsAsync().ConfigureAwait(false);

            Dictionary <string, string> data = new Dictionary <string, string>
            {
                { "KronosPersonNumber", $"{kronosUserId}" },
                { "KronosTimeOffRequestId", $"{kronosReqId}" },
                { "Approved", $"{approved}" },
                { "Configured correctly", $"{allRequiredConfigurations.IsAllSetUpExists}" },
                { "Date range", $"{timeOffRequestQueryDateSpan}" },
            };

            if (allRequiredConfigurations.IsAllSetUpExists)
            {
                var commentTimeStamp = this.utility.UTCToKronosTimeZone(DateTime.UtcNow, kronosTimeZone).ToString(CultureInfo.InvariantCulture);
                var comments         = XmlHelper.GenerateKronosComments(managerMessage, this.appSettings.ManagerTimeOffRequestCommentText, commentTimeStamp);

                var response = await this.timeOffActivity.ApproveOrDenyTimeOffRequestAsync(
                    new Uri(allRequiredConfigurations.WfmEndPoint),
                    allRequiredConfigurations.KronosSession,
                    timeOffRequestQueryDateSpan,
                    kronosUserId,
                    approved,
                    kronosReqId,
                    comments).ConfigureAwait(false);

                data.Add("ResponseStatus", $"{response.Status}");

                if (response.Status == "Success" && approved)
                {
                    this.telemetryClient.TrackTrace($"Update table for approval of time off request: {kronosReqId}", data);
                    timeOffRequestMapping.KronosStatus = ApiConstants.ApprovedStatus;
                    await this.timeOffMappingEntityProvider.SaveOrUpdateTimeOffMappingEntityAsync(timeOffRequestMapping).ConfigureAwait(false);

                    return(true);
                }

                if (response.Status == "Success" && !approved)
                {
                    this.telemetryClient.TrackTrace($"Update table for refusal of time off request: {kronosReqId}", data);
                    timeOffRequestMapping.KronosStatus = ApiConstants.Refused;
                    await this.timeOffMappingEntityProvider.SaveOrUpdateTimeOffMappingEntityAsync(timeOffRequestMapping).ConfigureAwait(false);

                    return(true);
                }
            }

            this.telemetryClient.TrackTrace("ApproveOrDenyTimeOffRequestInKronos - Configuration incorrect", data);
            return(false);
        }
예제 #2
0
        /// <summary>
        /// Method that approves a time off request.
        /// </summary>
        /// <param name="timeOffLookUpEntriesFoundList">The time off look up entries that are found.</param>
        /// <param name="user">The user.</param>
        /// <param name="timeOffReasonId">The Shifts Time Off Reason ID.</param>
        /// <param name="accessToken">The MS Graph Access Token.</param>
        /// <param name="monthPartitionKey">The monthwise partition key.</param>
        /// <param name="globalTimeOffRequestDetails">The list of global time off request details.</param>
        /// <returns>A unit of execution.</returns>
        private async Task ApproveTimeOffRequestAsync(
            List <TimeOffMappingEntity> timeOffLookUpEntriesFoundList,
            List <UserDetailsModel> user,
            List <PayCodeToTimeOffReasonsMappingEntity> timeOffReasonId,
            string accessToken,
            string monthPartitionKey,
            List <GlobalTimeOffRequestItem> globalTimeOffRequestDetails)
        {
            this.telemetryClient.TrackTrace($"ApproveTimeOffRequestAsync started for {monthPartitionKey}.");

            for (int i = 0; i < timeOffLookUpEntriesFoundList.Count; i++)
            {
                var timeOffReqCon = new TimeOffRequestItem
                {
                    Id = timeOffLookUpEntriesFoundList[i].ShiftsRequestId,
                    CreatedDateTime      = DateTime.Now,
                    LastModifiedDateTime = DateTime.Now,
                    AssignedTo           = ApiConstants.Manager,
                    State                 = ApiConstants.Pending,
                    SenderDateTime        = DateTime.Now,
                    SenderMessage         = globalTimeOffRequestDetails[i].Comments?.Comment.FirstOrDefault()?.CommentText,
                    SenderUserId          = Guid.Parse(user[i].ShiftUserId),
                    ManagerActionDateTime = null,
                    ManagerActionMessage  = null,
                    ManagerUserId         = string.Empty,
                    StartDateTime         = this.utility.CalculateStartDateTime(globalTimeOffRequestDetails[i]),
                    EndDateTime           = this.CalculateEndDate(globalTimeOffRequestDetails[i]),
                    TimeOffReasonId       = timeOffReasonId[i].TimeOffReasonId,
                    LastModifiedBy        = new LastModifiedBy
                    {
                        Application  = null,
                        Device       = null,
                        Conversation = null,
                        User         = new TimeOffRequest.User
                        {
                            Id          = Guid.Parse(user[i].ShiftUserId),
                            DisplayName = user[i].ShiftUserDisplayName,
                        },
                    },
                };

                var requestString = JsonConvert.SerializeObject(timeOffReqCon);
                var httpClient    = this.httpClientFactory.CreateClient("ShiftsAPI");
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "teams/" + user[i].ShiftTeamId + "/schedule/timeOffRequests/" + timeOffLookUpEntriesFoundList[i].ShiftsRequestId + "/approve")
                {
                    Content = new StringContent(requestString, Encoding.UTF8, "application/json"),
                })
                {
                    var response = await httpClient.SendAsync(httpRequestMessage).ConfigureAwait(false);

                    if (response.IsSuccessStatusCode)
                    {
                        var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                        TimeOffMappingEntity timeOffMappingEntity = new TimeOffMappingEntity
                        {
                            Duration           = globalTimeOffRequestDetails[i].TimeOffPeriods.TimeOffPeriod.Duration,
                            EndDate            = globalTimeOffRequestDetails[i].TimeOffPeriods.TimeOffPeriod.EndDate,
                            StartDate          = globalTimeOffRequestDetails[i].TimeOffPeriods.TimeOffPeriod.StartDate,
                            StartTime          = globalTimeOffRequestDetails[i].TimeOffPeriods.TimeOffPeriod.StartTime,
                            PayCodeName        = globalTimeOffRequestDetails[i].TimeOffPeriods.TimeOffPeriod.PayCodeName,
                            KronosPersonNumber = globalTimeOffRequestDetails[i].Employee.PersonIdentity.PersonNumber,
                            PartitionKey       = monthPartitionKey,
                            RowKey             = globalTimeOffRequestDetails[i].Id,
                            ShiftsRequestId    = timeOffLookUpEntriesFoundList[i].ShiftsRequestId,
                            IsActive           = true,
                            KronosRequestId    = globalTimeOffRequestDetails[i].Id,
                            StatusName         = ApiConstants.ApprovedStatus,
                        };

                        this.AddorUpdateTimeOffMappingAsync(timeOffMappingEntity);
                    }
                }
            }

            this.telemetryClient.TrackTrace($"ApproveTimeOffRequestAsync ended for {monthPartitionKey}.");
        }
        /// <summary>
        /// Creates a time off request that was requested in Teams.
        /// </summary>
        /// <param name="user">The user details of the time off requestor.</param>
        /// <param name="timeOffEntity">The time off to be created.</param>
        /// <param name="timeOffReason">The time off reason.</param>
        /// <param name="allRequiredConfigurations">Setup details.</param>
        /// <param name="kronosTimeZone">The kronos timezone.</param>
        /// <returns>Whether the time off request was created successfully or not.</returns>
        internal async Task <bool> CreateTimeOffRequestInKronosAsync(
            UserDetailsModel user,
            TimeOffRequestItem timeOffEntity,
            PayCodeToTimeOffReasonsMappingEntity timeOffReason,
            SetupDetails allRequiredConfigurations,
            string kronosTimeZone)
        {
            // Teams provides date times in UTC so convert to the local time.
            var localStartDateTime = this.utility.UTCToKronosTimeZone(timeOffEntity.StartDateTime, kronosTimeZone);
            var localEndDateTime   = this.utility.UTCToKronosTimeZone(timeOffEntity.EndDateTime, kronosTimeZone);

            // Construct the query date span for the Kronos request
            var queryStartDate = localStartDateTime.AddDays(
                -Convert.ToInt16(this.appSettings.CorrectedDateSpanForOutboundCalls, CultureInfo.InvariantCulture))
                                 .ToString(this.appSettings.KronosQueryDateSpanFormat, CultureInfo.InvariantCulture);

            var queryEndDate = localEndDateTime.AddDays(
                Convert.ToInt16(this.appSettings.CorrectedDateSpanForOutboundCalls, CultureInfo.InvariantCulture))
                               .ToString(this.appSettings.KronosQueryDateSpanFormat, CultureInfo.InvariantCulture);

            var timeOffReqQueryDateSpan = $"{queryStartDate}-{queryEndDate}";

            var commentTimeStamp = this.utility.UTCToKronosTimeZone(DateTime.UtcNow, kronosTimeZone).ToString(CultureInfo.InvariantCulture);
            var comments         = XmlHelper.GenerateKronosComments(timeOffEntity.SenderMessage, this.appSettings.SenderTimeOffRequestCommentText, commentTimeStamp);

            // Create the Kronos Time Off Request.
            var timeOffResponse = await this.timeOffActivity.CreateTimeOffRequestAsync(
                allRequiredConfigurations.KronosSession,
                localStartDateTime,
                localEndDateTime,
                timeOffReqQueryDateSpan,
                user.KronosPersonNumber,
                timeOffReason.RowKey,
                comments,
                new Uri(allRequiredConfigurations.WfmEndPoint)).ConfigureAwait(false);

            if (!string.IsNullOrWhiteSpace(timeOffResponse?.Error?.Message))
            {
                this.telemetryClient.TrackTrace($"Could not create the time off request : {timeOffResponse?.Error?.Message} ");
                return(false);
            }

            var submitTimeOffResponse = await this.timeOffActivity.SubmitTimeOffRequestAsync(
                allRequiredConfigurations.KronosSession,
                user.KronosPersonNumber,
                timeOffResponse?.EmployeeRequestMgm?.RequestItem?.GlobalTimeOffRequestItms?.FirstOrDefault()?.Id,
                timeOffReqQueryDateSpan,
                new Uri(allRequiredConfigurations.WfmEndPoint)).ConfigureAwait(false);

            TimeOffMappingEntity newTimeOffReq = new TimeOffMappingEntity();

            // IsActive represents whether the time off was successfully created.
            if (submitTimeOffResponse?.Status == ApiConstants.Failure)
            {
                newTimeOffReq.IsActive = false;
            }
            else
            {
                newTimeOffReq.IsActive = true;
            }

            newTimeOffReq.Duration           = timeOffResponse.EmployeeRequestMgm.RequestItem.GlobalTimeOffRequestItms.FirstOrDefault().TimeOffPeriodsList.TimeOffPerd.FirstOrDefault().Duration;
            newTimeOffReq.EndDate            = timeOffResponse.EmployeeRequestMgm.RequestItem.GlobalTimeOffRequestItms.FirstOrDefault().TimeOffPeriodsList.TimeOffPerd.FirstOrDefault().EndDate;
            newTimeOffReq.StartDate          = timeOffResponse.EmployeeRequestMgm.RequestItem.GlobalTimeOffRequestItms.FirstOrDefault().TimeOffPeriodsList.TimeOffPerd.FirstOrDefault().StartDate;
            newTimeOffReq.StartTime          = timeOffResponse.EmployeeRequestMgm.RequestItem.GlobalTimeOffRequestItms.FirstOrDefault().TimeOffPeriodsList.TimeOffPerd.FirstOrDefault().StartTime;
            newTimeOffReq.PayCodeName        = timeOffResponse.EmployeeRequestMgm.RequestItem.GlobalTimeOffRequestItms.FirstOrDefault().TimeOffPeriodsList.TimeOffPerd.FirstOrDefault().PayCodeName;
            newTimeOffReq.KronosPersonNumber = timeOffResponse.EmployeeRequestMgm.Employees.PersonIdentity.PersonNumber;
            newTimeOffReq.PartitionKey       = $"{localStartDateTime.Month}_{localStartDateTime.Year}";
            newTimeOffReq.RowKey             = timeOffResponse.EmployeeRequestMgm.RequestItem.GlobalTimeOffRequestItms.FirstOrDefault().Id;
            newTimeOffReq.ShiftsRequestId    = timeOffEntity.Id;
            newTimeOffReq.KronosRequestId    = timeOffResponse.EmployeeRequestMgm.RequestItem.GlobalTimeOffRequestItms.FirstOrDefault().Id;
            newTimeOffReq.KronosStatus       = ApiConstants.Submitted;
            newTimeOffReq.ShiftsStatus       = ApiConstants.Pending;

            this.AddorUpdateTimeOffMappingAsync(newTimeOffReq);

            // If isActive is false time off request was not submitted so return false and vice versa.
            return(newTimeOffReq.IsActive);
        }