/// <summary> /// Method to delete an orphan shift - happens when a shift is deleted from Kronos. /// </summary> /// <param name="configurationDetails">The configuration details.</param> /// <param name="lookUpDataFoundList">The list of data that has been found.</param> /// <param name="userModelList">The list of users.</param> /// <param name="lookUpData">The Shifts look up data.</param> /// <returns>A unit of execution.</returns> private async Task DeleteOrphanDataShiftsEntityMappingAsync( IntegrationApi.SetupDetails configurationDetails, List <TeamsShiftMappingEntity> lookUpDataFoundList, List <UserDetailsModel> userModelList, List <TeamsShiftMappingEntity> lookUpData) { // Delete entries from orphan list var orphanList = lookUpData.Except(lookUpDataFoundList); // Iterating over each item in the orphanList. foreach (var item in orphanList) { var user = userModelList.FirstOrDefault(u => u.KronosPersonNumber == item.KronosPersonNumber); if (user == null) { return; } var httpClient = this.httpClientFactory.CreateClient("ShiftsAPI"); httpClient.DefaultRequestHeaders.Add("X-MS-WFMPassthrough", configurationDetails.WFIId); // If the shift mapping doesnt have a teamId take the users teamId var teamId = string.IsNullOrEmpty(item.ShiftsTeamId) ? user.ShiftTeamId : item.ShiftsTeamId; var requestUrl = $"teams/{teamId}/schedule/shifts/{item.RowKey}"; var response = await this.graphUtility.SendHttpRequest(configurationDetails.GraphConfigurationDetails, httpClient, HttpMethod.Delete, requestUrl).ConfigureAwait(false); if (response.IsSuccessStatusCode) { var successfulDeleteProps = new Dictionary <string, string>() { { "ResponseCode", response.StatusCode.ToString() }, { "ResponseHeader", response.Headers.ToString() }, }; this.telemetryClient.TrackTrace(MethodBase.GetCurrentMethod().Name, successfulDeleteProps); await this.shiftMappingEntityProvider.DeleteOrphanDataFromShiftMappingAsync(item).ConfigureAwait(false); } else { var errorDeleteProps = new Dictionary <string, string>() { { "ResponseCode", response.StatusCode.ToString() }, { "ResponseHeader", response.Headers.ToString() }, }; this.telemetryClient.TrackTrace(MethodBase.GetCurrentMethod().Name, errorDeleteProps); } } }
/// <summary> /// Method to delete an orphan shift - happens when a shift is deleted from Kronos. /// </summary> /// <param name="configurationDetails">The configuration details.</param> /// <param name="lookUpDataFoundList">The list of data that has been found.</param> /// <param name="userModelList">The list of users.</param> /// <param name="lookUpData">The Shifts look up data.</param> /// <returns>A unit of execution.</returns> private async Task DeleteOrphanDataShiftsEntityMappingAsync( IntegrationApi.SetupDetails configurationDetails, List <TeamsShiftMappingEntity> lookUpDataFoundList, List <UserDetailsModel> userModelList, List <TeamsShiftMappingEntity> lookUpData) { // Delete entries from orphan list var orphanList = lookUpData.Except(lookUpDataFoundList); // Iterating over each item in the orphanList. foreach (var item in orphanList) { var user = userModelList.FirstOrDefault(u => u.KronosPersonNumber == item.KronosPersonNumber); var httpClient = this.httpClientFactory.CreateClient("ShiftsAPI"); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", configurationDetails.ShiftsAccessToken); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); if (user != null) { using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Delete, $"teams/{user.ShiftTeamId}/schedule/shifts/{item.RowKey}")) { var response = await httpClient.SendAsync(httpRequestMessage).ConfigureAwait(false); if (response.IsSuccessStatusCode) { var successfulDeleteProps = new Dictionary <string, string>() { { "ResponseCode", response.StatusCode.ToString() }, { "ResponseHeader", response.Headers.ToString() }, }; this.telemetryClient.TrackTrace(MethodBase.GetCurrentMethod().Name, successfulDeleteProps); await this.shiftMappingEntityProvider.DeleteOrphanDataFromShiftMappingAsync(item).ConfigureAwait(false); } else { var errorDeleteProps = new Dictionary <string, string>() { { "ResponseCode", response.StatusCode.ToString() }, { "ResponseHeader", response.Headers.ToString() }, }; this.telemetryClient.TrackTrace(MethodBase.GetCurrentMethod().Name, errorDeleteProps); } } } } }
/// <summary> /// Method that will create the new Shifts Entity Mapping. /// </summary> /// <param name="configurationDetails">The configuration details.</param> /// <param name="userModelNotFoundList">The list of users that have not been found.</param> /// <param name="notFoundShifts">The shifts which have not been found.</param> /// <param name="monthPartitionKey">The monthwise partition key.</param> /// <returns>A unit of execution.</returns> private async Task CreateEntryShiftsEntityMappingAsync( IntegrationApi.SetupDetails configurationDetails, List <UserDetailsModel> userModelNotFoundList, List <Shift> notFoundShifts, string monthPartitionKey) { // create entries from not found list for (int i = 0; i < notFoundShifts.Count; i++) { var requestString = JsonConvert.SerializeObject(notFoundShifts[i]); var httpClient = this.httpClientFactory.CreateClient("ShiftsAPI"); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", configurationDetails.ShiftsAccessToken); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "teams/" + userModelNotFoundList[i].ShiftTeamId + "/schedule/shifts") { 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); var shiftResponse = JsonConvert.DeserializeObject <Models.Response.Shifts.Shift>(responseContent); var shiftId = shiftResponse.Id; var shiftMappingEntity = this.CreateNewShiftMappingEntity(shiftResponse, notFoundShifts[i].KronosUniqueId, userModelNotFoundList[i]); await this.shiftMappingEntityProvider.SaveOrUpdateShiftMappingEntityAsync(shiftMappingEntity, shiftId, monthPartitionKey).ConfigureAwait(false); continue; } else { var errorProps = new Dictionary <string, string>() { { "ResultCode", response.StatusCode.ToString() }, { "IntegerResult", Convert.ToInt32(response.StatusCode, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture) }, }; // Have the log to capture the 403. this.telemetryClient.TrackTrace(MethodBase.GetCurrentMethod().Name, errorProps); } } } }
/// <summary> /// Method that will create the new Shifts Entity Mapping. /// </summary> /// <param name="configurationDetails">The configuration details.</param> /// <param name="userModelNotFoundList">The list of users that have not been found.</param> /// <param name="notFoundShifts">The shifts which have not been found.</param> /// <param name="monthPartitionKey">The monthwise partition key.</param> /// <returns>A unit of execution.</returns> private async Task CreateEntryShiftsEntityMappingAsync( IntegrationApi.SetupDetails configurationDetails, List <UserDetailsModel> userModelNotFoundList, List <Shift> notFoundShifts, string monthPartitionKey) { // create entries from not found list for (int i = 0; i < notFoundShifts.Count; i++) { var httpClient = this.httpClientFactory.CreateClient("ShiftsAPI"); httpClient.DefaultRequestHeaders.Add("X-MS-WFMPassthrough", configurationDetails.WFIId); var requestUrl = $"teams/{userModelNotFoundList[i].ShiftTeamId}/schedule/shifts"; var requestString = JsonConvert.SerializeObject(notFoundShifts[i]); var response = await this.graphUtility.SendHttpRequest(configurationDetails.GraphConfigurationDetails, httpClient, HttpMethod.Post, requestUrl, requestString).ConfigureAwait(false); if (response.IsSuccessStatusCode) { var responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var shiftResponse = JsonConvert.DeserializeObject <Models.Response.Shifts.Shift>(responseContent); var shiftId = shiftResponse.Id; var shiftMappingEntity = this.CreateNewShiftMappingEntity(shiftResponse, notFoundShifts[i].KronosUniqueId, userModelNotFoundList[i]); await this.shiftMappingEntityProvider.SaveOrUpdateShiftMappingEntityAsync(shiftMappingEntity, shiftId, monthPartitionKey).ConfigureAwait(false); continue; } else { var errorProps = new Dictionary <string, string>() { { "ResultCode", response.StatusCode.ToString() }, { "IntegerResult", Convert.ToInt32(response.StatusCode, CultureInfo.InvariantCulture).ToString(CultureInfo.InvariantCulture) }, }; // Have the log to capture the 403. this.telemetryClient.TrackTrace(MethodBase.GetCurrentMethod().Name, errorProps); } } }
/// <summary> /// Method to process the shift entities in a batch manner. /// </summary> /// <param name="configurationDetails">The configuration details.</param> /// <param name="lookUpEntriesFoundList">The lookUp entries that have been found.</param> /// <param name="shiftsNotFoundList">The shifts that have not been found.</param> /// <param name="userModelList">The users list.</param> /// <param name="userModelNotFoundList">The list of users that have not been found.</param> /// <param name="lookUpData">The look up data from the Shift Entity Mapping table.</param> /// <param name="processKronosUsersQueueInBatch">The Kronos users in the queue.</param> /// <param name="shiftsResponse">The Shifts Response from MS Graph.</param> /// <param name="monthPartitionKey">The monthwise partition.</param> /// <returns>A unit of execution.</returns> private async Task ProcessShiftEntitiesBatchAsync( IntegrationApi.SetupDetails configurationDetails, List <TeamsShiftMappingEntity> lookUpEntriesFoundList, List <Shift> shiftsNotFoundList, List <UserDetailsModel> userModelList, List <UserDetailsModel> userModelNotFoundList, List <TeamsShiftMappingEntity> lookUpData, IEnumerable <UserDetailsModel> processKronosUsersQueueInBatch, App.KronosWfc.Models.ResponseEntities.Shifts.UpcomingShifts.Response shiftsResponse, string monthPartitionKey) { this.telemetryClient.TrackTrace($"ShiftController - ProcessShiftEntitiesBatchAsync started at: {DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)}"); var shiftNotes = string.Empty; // This foreach loop processes each user in the batch. foreach (var user in processKronosUsersQueueInBatch) { // This foreach loop will process the shift(s) that belong to each user. foreach (var kronosShift in shiftsResponse?.Schedule?.ScheduleItems?.ScheduleShift) { if (user.KronosPersonNumber == kronosShift.Employee.FirstOrDefault().PersonNumber) { this.telemetryClient.TrackTrace($"ShiftController - Processing the shifts for user: {user.KronosPersonNumber}"); var shift = this.GenerateTeamsShiftObject(user, kronosShift); shift.KronosUniqueId = this.utility.CreateUniqueId(shift, user.KronosTimeZone); this.telemetryClient.TrackTrace($"ShiftController-KronosHash: {shift.KronosUniqueId}"); userModelList.Add(user); if (lookUpData.Count == 0) { shiftsNotFoundList.Add(shift); userModelNotFoundList.Add(user); } else { var kronosUniqueIdExists = lookUpData.Where(c => c.KronosUniqueId == shift.KronosUniqueId); if (kronosUniqueIdExists.Any() && (kronosUniqueIdExists != default(List <TeamsShiftMappingEntity>))) { lookUpEntriesFoundList.Add(kronosUniqueIdExists.FirstOrDefault()); } else { shiftsNotFoundList.Add(shift); userModelNotFoundList.Add(user); } } } } } if (lookUpData.Except(lookUpEntriesFoundList).Any()) { await this.DeleteOrphanDataShiftsEntityMappingAsync(configurationDetails, lookUpEntriesFoundList, userModelList, lookUpData).ConfigureAwait(false); } await this.CreateEntryShiftsEntityMappingAsync(configurationDetails, userModelNotFoundList, shiftsNotFoundList, monthPartitionKey).ConfigureAwait(false); this.telemetryClient.TrackTrace($"ShiftController - ProcessShiftEntitiesBatchAsync ended at: {DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)}"); }
/// <summary> /// This method will cause the thread to wait allowing us to retrun a success response /// for the delete WFI request. It will then share the changes. /// </summary> /// <param name="shift">The shift we want to share.</param> /// <param name="mappedTeam">The team details of the schedule we want to share.</param> /// <param name="allRequiredConfigurations">The required configuration.</param> /// <returns>A unit of execution.</returns> private async Task ShareScheduleAfterShiftDeletion(ShiftsShift shift, TeamToDepartmentJobMappingEntity mappedTeam, IntegrationApi.SetupDetails allRequiredConfigurations) { // We want to wait so that there is time to respond a success to the WFI request // meaning the shift will be deleted in Teams. Thread.Sleep(int.Parse(appSettings.AutoShareScheduleWaitTime)); // We now want to share the schedule between the start and end time of the deleted shift. await this.graphUtility.ShareSchedule( allRequiredConfigurations.GraphConfigurationDetails, mappedTeam.TeamId, shift.SharedShift.StartDateTime, shift.SharedShift.EndDateTime, false).ConfigureAwait(false); }