/// <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); }
/// <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); }