コード例 #1
0
        /// <summary>
        /// Generates the response for each outbound request.
        /// </summary>
        /// <param name="itemId">Id for response.</param>
        /// <param name="statusCode">HttpStatusCode for the request been processed.</param>
        /// <param name="eTag">Etag based on response.</param>
        /// <param name="error">Forward error to Shifts if any.</param>
        /// <returns>ShiftsIntegResponse.</returns>
        private static ShiftsIntegResponse GenerateResponse(string itemId, HttpStatusCode statusCode, string eTag, ResponseError error)
        {
            // The outbound acknowledgement does not honor the null Etag, 502 Bad Gateway is thrown if so.
            // Checking for the null eTag value, from the attributes in the payload.
            string responseEtag;

            if (string.IsNullOrEmpty(eTag))
            {
                responseEtag = GenerateNewGuid();
            }
            else
            {
                responseEtag = eTag;
            }

            var integrationResponse = new ShiftsIntegResponse()
            {
                Id     = itemId,
                Status = (int)statusCode,
                Body   = new Body
                {
                    Error = error,
                    ETag  = responseEtag,
                },
            };

            return(integrationResponse);
        }
        /// <summary>
        /// Generate response to prevent actions.
        /// </summary>
        /// <param name="jsonModel">The request payload.</param>
        /// <param name="errorMessage">Error message to send while preventing action.</param>
        /// <returns>List of ShiftsIntegResponse.</returns>
        public static List <ShiftsIntegResponse> CreateMultipleBadResponses(RequestModel jsonModel, string errorMessage)
        {
            List <ShiftsIntegResponse> shiftsIntegResponses = new List <ShiftsIntegResponse>();
            var integrationResponse = new ShiftsIntegResponse();

            foreach (var item in jsonModel.Requests)
            {
                integrationResponse = CreateBadResponse(item.Id, error: errorMessage);
                shiftsIntegResponses.Add(integrationResponse);
            }

            return(shiftsIntegResponses);
        }
コード例 #3
0
        /// <summary>
        /// Generate response to prevent actions.
        /// </summary>
        /// <param name="jsonModel">The request payload.</param>
        /// <param name="errorMessage">Error message to send while preventing action.</param>
        /// <returns>List of ShiftsIntegResponse.</returns>
        private static List <ShiftsIntegResponse> GenerateResponseToPreventAction(RequestModel jsonModel, string errorMessage)
        {
            List <ShiftsIntegResponse> shiftsIntegResponses = new List <ShiftsIntegResponse>();
            var integrationResponse = new ShiftsIntegResponse();

            foreach (var item in jsonModel.Requests)
            {
                ResponseError responseError = new ResponseError();
                responseError.Code    = HttpStatusCode.BadRequest.ToString();
                responseError.Message = errorMessage;
                integrationResponse   = GenerateResponse(item.Id, HttpStatusCode.BadRequest, null, responseError);
                shiftsIntegResponses.Add(integrationResponse);
            }

            return(shiftsIntegResponses);
        }
コード例 #4
0
        /// <summary>
        /// Returns a response if a given object is null.
        /// </summary>
        /// <typeparam name="T">The type of the object.</typeparam>
        /// <param name="potentialNullObject">The object.</param>
        /// <param name="id">The id for the response.</param>
        /// <param name="error">The error message for the response.</param>
        /// <param name="response">The output of the response.</param>
        /// <returns><see cref="bool"/> to denote whether it passed or failed.</returns>
        public static bool ErrorIfNull <T>(
            this T potentialNullObject,
            string id,
            string error,
            out ShiftsIntegResponse response)
        {
            response = null;

            if (potentialNullObject == null)
            {
                response = CreateBadResponse(id, error: error);
                return(true);
            }

            return(false);
        }
        public async Task <ShiftsIntegResponse> SubmitOpenShiftRequestToKronosAsync(
            Models.IntegrationAPI.OpenShiftRequestIS request, string teamsId)
        {
            ShiftsIntegResponse openShiftSubmitResponse;

            this.telemetryClient.TrackTrace($"{Resource.SubmitOpenShiftRequestToKronosAsync} starts at: {DateTime.Now.ToString("O", CultureInfo.InvariantCulture)}");

            if (request is null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            GraphOpenShift graphOpenShift;
            var            telemetryProps = new Dictionary <string, string>()
            {
                { "CallingAssembly", Assembly.GetCallingAssembly().GetName().Name },
                { "CallingMethod", "UpdateTeam" },
                { "OpenShiftId", request.OpenShiftId },
                { "OpenShiftRequestId", request.Id },
                { "RequesterId", request.SenderUserId },
            };

            // Prereq. Steps
            // Step 1 - Obtain the necessary prerequisites required.
            // Step 1a - Obtain the ConfigurationInfo entity.
            // Step 1b - Obtain the Team-Department Mapping.
            // Step 1c - Obtain the Graph Token and other prerequisite information.
            // Step 1d - Obtain the user from the user to user mapping table.
            // Step 1e - Login to Kronos.

            // Step 1c.
            var allRequiredConfigurations = await this.utility.GetAllConfigurationsAsync().ConfigureAwait(false);

            var kronosTimeZoneId   = this.appSettings.KronosTimeZone;
            var kronosTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById(kronosTimeZoneId);

            if (allRequiredConfigurations != null && (bool)allRequiredConfigurations?.IsAllSetUpExists)
            {
                // Step 1d.
                var userMappingRecord = await this.GetMappedUserDetailsAsync(
                    allRequiredConfigurations.WFIId,
                    request?.SenderUserId,
                    teamsId).ConfigureAwait(false);

                // Submit open shift request to Kronos if user and it's corresponding team is mapped correctly.
                if (string.IsNullOrEmpty(userMappingRecord.Error))
                {
                    var queryingOrgJobPath    = userMappingRecord.OrgJobPath;
                    var teamDepartmentMapping = await this.teamDepartmentMappingProvider.GetTeamMappingForOrgJobPathAsync(
                        allRequiredConfigurations.WFIId,
                        queryingOrgJobPath).ConfigureAwait(false);

                    telemetryProps.Add("TenantId", allRequiredConfigurations.TenantId);
                    telemetryProps.Add("WorkforceIntegrationId", allRequiredConfigurations.WFIId);

                    // Step 2 - Getting the Open Shift - the start date/time and end date/time are needed.
                    var httpClient = this.httpClientFactory.CreateClient("ShiftsAPI");
                    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", allRequiredConfigurations.ShiftsAccessToken);
                    using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "teams/" + teamDepartmentMapping.TeamId + "/schedule/openShifts/" + request.OpenShiftId))
                    {
                        var response = await httpClient.SendAsync(httpRequestMessage).ConfigureAwait(false);

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

                            graphOpenShift = JsonConvert.DeserializeObject <GraphOpenShift>(responseContent);

                            // Logging the required Open Shift ID from the Graph call.
                            this.telemetryClient.TrackTrace($"OpenShiftRequestController - OpenShift Graph API call succeeded with getting the Open Shift: {graphOpenShift?.Id}");

                            var shiftStartDate = graphOpenShift.SharedOpenShift.StartDateTime.AddDays(
                                -Convert.ToInt16(this.appSettings.CorrectedDateSpanForOutboundCalls, CultureInfo.InvariantCulture))
                                                 .ToString(this.appSettings.KronosQueryDateSpanFormat, CultureInfo.InvariantCulture);

                            var shiftEndDate = graphOpenShift.SharedOpenShift.EndDateTime.AddDays(
                                Convert.ToInt16(this.appSettings.CorrectedDateSpanForOutboundCalls, CultureInfo.InvariantCulture))
                                               .ToString(this.appSettings.KronosQueryDateSpanFormat, CultureInfo.InvariantCulture);

                            var openShiftReqQueryDateSpan = $"{shiftStartDate}-{shiftEndDate}";

                            // Builds out the Open Shift Segments prior to actual object being built.
                            // Take into account the activities of the open shift that has been retrieved
                            // from the Graph API call for open shift details.
                            var openShiftSegments = this.BuildKronosOpenShiftSegments(
                                graphOpenShift.SharedOpenShift.Activities,
                                queryingOrgJobPath,
                                kronosTimeZoneInfo,
                                graphOpenShift.Id);

                            // Step 3 - Create the necessary OpenShiftObj
                            // Having the open shift segments which have been retrieved.
                            var inputDraftOpenShiftRequest = new OpenShiftObj()
                            {
                                StartDayNumber    = Constants.StartDayNumberString,
                                EndDayNumber      = Constants.EndDayNumberString,
                                SegmentTypeName   = Resource.DraftOpenShiftRequestSegmentTypeName,
                                StartTime         = TimeZoneInfo.ConvertTime(graphOpenShift.SharedOpenShift.StartDateTime, kronosTimeZoneInfo).ToString("h:mm tt", CultureInfo.InvariantCulture),
                                EndTime           = TimeZoneInfo.ConvertTime(graphOpenShift.SharedOpenShift.EndDateTime, kronosTimeZoneInfo).ToString("h:mm tt", CultureInfo.InvariantCulture),
                                ShiftDate         = TimeZoneInfo.ConvertTime(graphOpenShift.SharedOpenShift.StartDateTime, kronosTimeZoneInfo).ToString(Constants.DateFormat, CultureInfo.InvariantCulture).Replace('-', '/'),
                                OrgJobPath        = Utility.OrgJobPathKronosConversion(userMappingRecord?.OrgJobPath),
                                QueryDateSpan     = openShiftReqQueryDateSpan,
                                PersonNumber      = userMappingRecord?.KronosPersonNumber,
                                OpenShiftSegments = openShiftSegments,
                            };

                            // Step 4 - Submit over to Kronos WFC, Open Shift Request goes into DRAFT state.
                            var postDraftOpenShiftRequestResult = await this.openShiftActivity.PostDraftOpenShiftRequestAsync(
                                allRequiredConfigurations.TenantId,
                                allRequiredConfigurations.KronosSession,
                                inputDraftOpenShiftRequest,
                                new Uri(allRequiredConfigurations.WfmEndPoint)).ConfigureAwait(false);

                            if (postDraftOpenShiftRequestResult?.Status == ApiConstants.Success)
                            {
                                this.telemetryClient.TrackTrace($"{Resource.SubmitOpenShiftRequestToKronosAsync} - Operation to submit the DRAFT request has succeeded with: {postDraftOpenShiftRequestResult?.Status}");

                                // Step 5 - Update the submitted Open Shift Request from DRAFT to SUBMITTED
                                // so that it renders inside of the Kronos WFC Request Manager for final approval/decline.
                                var postUpdateOpenShiftRequestStatusResult = await this.openShiftActivity.PostOpenShiftRequestStatusUpdateAsync(
                                    userMappingRecord.KronosPersonNumber,
                                    postDraftOpenShiftRequestResult.EmployeeRequestMgmt?.RequestItems?.EmployeeGlobalOpenShiftRequestItem?.Id,
                                    openShiftReqQueryDateSpan,
                                    Resource.KronosOpenShiftStatusUpdateToSubmittedMessage,
                                    new Uri(allRequiredConfigurations.WfmEndPoint),
                                    allRequiredConfigurations.KronosSession).ConfigureAwait(false);

                                if (postUpdateOpenShiftRequestStatusResult?.Status == ApiConstants.Success)
                                {
                                    this.telemetryClient.TrackTrace($"{Resource.SubmitOpenShiftRequestToKronosAsync} - Operation to update the DRAFT request to SUBMITTED has succeeded with: {postUpdateOpenShiftRequestStatusResult?.Status}");

                                    var openShiftEntityWithKronosUniqueId = await this.openShiftMappingEntityProvider.GetOpenShiftMappingEntitiesAsync(
                                        request.OpenShiftId).ConfigureAwait(false);

                                    // Step 6 - Insert the submitted open shift request into Azure table storage.
                                    // Ensuring to pass the monthwise partition key from the Open Shift as the partition key for the Open Shift
                                    // Request mapping entity.
                                    var openShiftRequestMappingEntity = CreateOpenShiftRequestMapping(
                                        request?.OpenShiftId,
                                        request?.Id,
                                        request?.SenderUserId,
                                        userMappingRecord?.KronosPersonNumber,
                                        postDraftOpenShiftRequestResult.EmployeeRequestMgmt?.RequestItems?.EmployeeGlobalOpenShiftRequestItem?.Id,
                                        ApiConstants.Submitted,
                                        openShiftEntityWithKronosUniqueId.FirstOrDefault().RowKey,
                                        openShiftEntityWithKronosUniqueId.FirstOrDefault().PartitionKey,
                                        ApiConstants.Pending);

                                    telemetryProps.Add(
                                        "KronosRequestId",
                                        postDraftOpenShiftRequestResult.EmployeeRequestMgmt?.RequestItems?.EmployeeGlobalOpenShiftRequestItem?.Id);
                                    telemetryProps.Add(
                                        "KronosRequestStatus",
                                        postUpdateOpenShiftRequestStatusResult.EmployeeRequestMgmt?.RequestItems?.EmployeeGlobalOpenShiftRequestItem?.StatusName);
                                    telemetryProps.Add("KronosOrgJobPath", Utility.OrgJobPathKronosConversion(userMappingRecord?.OrgJobPath));

                                    await this.openShiftRequestMappingEntityProvider.SaveOrUpdateOpenShiftRequestMappingEntityAsync(openShiftRequestMappingEntity).ConfigureAwait(false);

                                    this.telemetryClient.TrackTrace(Resource.SubmitOpenShiftRequestToKronosAsync, telemetryProps);

                                    openShiftSubmitResponse = new ShiftsIntegResponse()
                                    {
                                        Id     = request.Id,
                                        Status = StatusCodes.Status200OK,
                                        Body   = new Body
                                        {
                                            Error = null,
                                            ETag  = GenerateNewGuid(),
                                        },
                                    };
                                }
                                else
                                {
                                    this.telemetryClient.TrackTrace(Resource.SubmitOpenShiftRequestToKronosAsync, telemetryProps);
                                    openShiftSubmitResponse = new ShiftsIntegResponse()
                                    {
                                        Id     = request.Id,
                                        Status = StatusCodes.Status500InternalServerError,
                                        Body   = new Body
                                        {
                                            Error = new ResponseError
                                            {
                                                Code    = Resource.KronosWFCOpenShiftRequestErrorCode,
                                                Message = postUpdateOpenShiftRequestStatusResult?.Status,
                                            },
                                        },
                                    };
                                }
                            }
                            else
                            {
                                this.telemetryClient.TrackTrace($"{Resource.SubmitOpenShiftRequestToKronosAsync} - There was an error from Kronos WFC when updating the DRAFT request to SUBMITTED status: {postDraftOpenShiftRequestResult?.Status}");

                                openShiftSubmitResponse = new ShiftsIntegResponse()
                                {
                                    Id     = request.Id,
                                    Status = StatusCodes.Status500InternalServerError,
                                    Body   = new Body
                                    {
                                        Error = new ResponseError
                                        {
                                            Code    = Resource.KronosWFCOpenShiftRequestErrorCode,
                                            Message = postDraftOpenShiftRequestResult?.Status,
                                        },
                                    },
                                };
                            }
                        }
                        else
                        {
                            this.telemetryClient.TrackTrace($"{Resource.SubmitOpenShiftRequestToKronosAsync} - There is an error when getting Open Shift: {request?.OpenShiftId} from Graph APIs: {response.StatusCode.ToString()}");

                            openShiftSubmitResponse = new ShiftsIntegResponse
                            {
                                Id     = request.Id,
                                Status = StatusCodes.Status404NotFound,
                                Body   = new Body
                                {
                                    Error = new ResponseError()
                                    {
                                        Code    = Resource.OpenShiftNotFoundCode,
                                        Message = string.Format(CultureInfo.InvariantCulture, Resource.OpenShiftNotFoundMessage, request.OpenShiftId),
                                    },
                                },
                            };
                        }
                    }
                }

                // Either user or it's team is not mapped correctly.
                else
                {
                    openShiftSubmitResponse = new ShiftsIntegResponse
                    {
                        Id     = request.Id,
                        Status = StatusCodes.Status500InternalServerError,
                        Body   = new Body
                        {
                            Error = new ResponseError
                            {
                                Code    = userMappingRecord.Error,
                                Message = userMappingRecord.Error,
                            },
                        },
                    };
                }
            }
            else
            {
                this.telemetryClient.TrackTrace(Resource.SubmitOpenShiftRequestToKronosAsync + "-" + Resource.SetUpNotDoneMessage);

                openShiftSubmitResponse = new ShiftsIntegResponse
                {
                    Id     = request.Id,
                    Status = StatusCodes.Status500InternalServerError,
                    Body   = new Body
                    {
                        Error = new ResponseError
                        {
                            Code    = Resource.SetUpNotDoneCode,
                            Message = Resource.SetUpNotDoneMessage,
                        },
                    },
                };
            }

            this.telemetryClient.TrackTrace($"{Resource.SubmitOpenShiftRequestToKronosAsync} ends at: {DateTime.Now.ToString("O", CultureInfo.InvariantCulture)}");
            return(openShiftSubmitResponse);
        }
コード例 #6
0
        /// <summary>
        /// This method further processes the Swap Shift request approval.
        /// </summary>
        /// <param name="jsonModel">The decryped JSON payload from Shifts/MS Graph.</param>
        /// <param name="aadGroupId">The team ID for which the Swap Shift request has been approved.</param>
        /// <returns>A unit of execution that contains the type of <see cref="ShiftsIntegResponse"/>.</returns>
        private async Task <List <ShiftsIntegResponse> > ProcessSwapShiftRequestApprovalAsync(RequestModel jsonModel, string aadGroupId)
        {
            List <ShiftsIntegResponse> swapShiftsIntegResponses = new List <ShiftsIntegResponse>();
            ShiftsIntegResponse        integrationResponse      = null;
            var swapShiftApprovalRes = from requests in jsonModel.Requests
                                       group requests by requests.Url;

            var swapRequests = jsonModel.Requests.Where(c => c.Url.Contains("/swapRequests/", StringComparison.InvariantCulture));

            // Filter all the system declined requests.
            var autoDeclinedRequests = swapRequests.Where(c => c.Body != null && c.Body["state"].Value <string>() == ApiConstants.Declined && c.Body["assignedTo"].Value <string>() == ApiConstants.System).ToList();

            // Filter approved swap shift request.
            var approvedSwapShiftRequest = swapRequests.Where(c => c.Body != null && c.Body["state"].Value <string>() == ApiConstants.ShiftsApproved && c.Body["assignedTo"].Value <string>() == ApiConstants.ShiftsManager).FirstOrDefault();

            var swapShiftRequest = JsonConvert.DeserializeObject <SwapRequest>(approvedSwapShiftRequest.Body.ToString());

            var postedShifts = jsonModel.Requests.Where(x => x.Url.Contains("/shifts/", StringComparison.InvariantCulture) && x.Method == "POST").ToList();

            var deletedShifts = jsonModel.Requests.Where(x => x.Url.Contains("/shifts/", StringComparison.InvariantCulture) && x.Method == "DELETE").ToList();

            if (swapShiftRequest != null)
            {
                var newShiftFirst  = JsonConvert.DeserializeObject <Shift>(postedShifts.First().Body.ToString());
                var newShiftSecond = JsonConvert.DeserializeObject <Shift>(postedShifts.Last().Body.ToString());

                // Step 1 - Create the Kronos Unique ID.
                var kronosUniqueIdFirst  = this.utility.CreateUniqueId(newShiftFirst);
                var kronosUniqueIdSecond = this.utility.CreateUniqueId(newShiftSecond);

                try
                {
                    var userMappingRecord = await this.userMappingProvider.GetUserMappingEntityAsyncNew(
                        newShiftFirst?.UserId,
                        aadGroupId).ConfigureAwait(false);

                    // When getting the month partition key, make sure to take into account the Kronos Time Zone as well
                    var provider = CultureInfo.InvariantCulture;
                    var actualStartDateTimeStr = this.utility.CalculateStartDateTime(
                        newShiftFirst.SharedShift.StartDateTime.Date).ToString("M/dd/yyyy", provider);
                    var actualEndDateTimeStr = this.utility.CalculateEndDateTime(
                        newShiftFirst.SharedShift.EndDateTime.Date).ToString("M/dd/yyyy", provider);

                    // Create the month partition key based on the finalShift object.
                    var monthPartitions = Common.Utility.GetMonthPartition(actualStartDateTimeStr, actualEndDateTimeStr);
                    var monthPartition  = monthPartitions?.FirstOrDefault();

                    // Create the shift mapping entity based on the finalShift object also.
                    var shiftEntity = this.utility.CreateShiftMappingEntity(newShiftFirst, userMappingRecord, kronosUniqueIdFirst);
                    await this.shiftMappingEntityProvider.SaveOrUpdateShiftMappingEntityAsync(
                        shiftEntity,
                        newShiftFirst.Id,
                        monthPartition).ConfigureAwait(false);

                    var userMappingRecordSec = await this.userMappingProvider.GetUserMappingEntityAsyncNew(
                        newShiftSecond?.UserId,
                        aadGroupId).ConfigureAwait(false);

                    integrationResponse = GenerateResponse(newShiftFirst.Id, HttpStatusCode.OK, null, null);
                    swapShiftsIntegResponses.Add(integrationResponse);

                    // When getting the month partition key, make sure to take into account the Kronos Time Zone as well
                    var actualStartDateTimeStrSec = this.utility.CalculateStartDateTime(
                        newShiftSecond.SharedShift.StartDateTime).ToString("M/dd/yyyy", provider);
                    var actualEndDateTimeStrSec = this.utility.CalculateEndDateTime(
                        newShiftSecond.SharedShift.EndDateTime).ToString("M/dd/yyyy", provider);

                    // Create the month partition key based on the finalShift object.
                    var monthPartitionsSec = Common.Utility.GetMonthPartition(actualStartDateTimeStrSec, actualEndDateTimeStrSec);
                    var monthPartitionSec  = monthPartitionsSec?.FirstOrDefault();

                    // Create the shift mapping entity based on the finalShift object also.
                    var shiftEntitySec = this.utility.CreateShiftMappingEntity(newShiftSecond, userMappingRecordSec, kronosUniqueIdSecond);
                    await this.shiftMappingEntityProvider.SaveOrUpdateShiftMappingEntityAsync(
                        shiftEntitySec,
                        newShiftSecond.Id,
                        monthPartitionSec).ConfigureAwait(false);

                    integrationResponse = GenerateResponse(newShiftSecond.Id, HttpStatusCode.OK, null, null);
                    swapShiftsIntegResponses.Add(integrationResponse);

                    foreach (var delShifts in deletedShifts)
                    {
                        integrationResponse = GenerateResponse(delShifts.Id, HttpStatusCode.OK, null, null);
                        swapShiftsIntegResponses.Add(integrationResponse);
                    }

                    integrationResponse = GenerateResponse(approvedSwapShiftRequest.Id, HttpStatusCode.OK, swapShiftRequest.ETag, null);
                    swapShiftsIntegResponses.Add(integrationResponse);

                    foreach (var declinedRequest in autoDeclinedRequests)
                    {
                        this.telemetryClient.TrackTrace($"SystemDeclinedOpenShiftRequestId: {declinedRequest.Id}");
                        var declinedSwapShiftRequest = JsonConvert.DeserializeObject <SwapRequest>(declinedRequest.Body.ToString());

                        // Get the requests from storage.
                        var entityToUpdate = await this.swapShiftMappingEntityProvider.GetKronosReqAsync(
                            declinedRequest.Id).ConfigureAwait(false);

                        entityToUpdate.KronosStatus = declinedSwapShiftRequest.State;
                        entityToUpdate.ShiftsStatus = declinedSwapShiftRequest.State;

                        // Commit the change to the database.
                        await this.swapShiftMappingEntityProvider.AddOrUpdateSwapShiftMappingAsync(entityToUpdate).ConfigureAwait(false);

                        this.telemetryClient.TrackTrace($"OpenShiftRequestId: {declinedSwapShiftRequest.Id}, assigned to: {declinedSwapShiftRequest.AssignedTo}, state: {declinedSwapShiftRequest.State}");

                        // Adding response for system declined open shift request.
                        integrationResponse = GenerateResponse(declinedSwapShiftRequest.Id, HttpStatusCode.OK, declinedSwapShiftRequest.ETag, null);
                        swapShiftsIntegResponses.Add(integrationResponse);
                    }
                }
                catch (Exception ex)
                {
                    var exceptionProps = new Dictionary <string, string>()
                    {
                        { "NewFirstShiftId", newShiftFirst.Id },
                        { "NewSecondShiftId", newShiftSecond.Id },
                    };

                    this.telemetryClient.TrackException(ex, exceptionProps);
                    throw;
                }
            }

            return(swapShiftsIntegResponses);
        }
コード例 #7
0
        /// <summary>
        /// This method processes the open shift request approval, and proceeds to update the Azure table storage accordingly with the Shifts status
        /// of the open shift request, and also ensures that the ShiftMappingEntity table is properly in sync.
        /// </summary>
        /// <param name="jsonModel">The decrypted JSON payload.</param>
        /// <param name="updateProps">A dictionary of string, string that will be logged to ApplicationInsights.</param>
        /// <returns>A unit of execution.</returns>
        private async Task <List <ShiftsIntegResponse> > ProcessOpenShiftRequestApprovalAsync(RequestModel jsonModel, Dictionary <string, string> updateProps)
        {
            List <ShiftsIntegResponse> responseModelList   = new List <ShiftsIntegResponse>();
            ShiftsIntegResponse        integrationResponse = null;

            var openShiftRequests = jsonModel?.Requests?.Where(x => x.Url.Contains("/openshiftrequests/", StringComparison.InvariantCulture));
            var finalOpenShiftObj = jsonModel?.Requests?.FirstOrDefault(x => x.Url.Contains("/openshifts/", StringComparison.InvariantCulture));
            var finalShiftObj     = jsonModel?.Requests?.FirstOrDefault(x => x.Url.Contains("/shifts/", StringComparison.InvariantCulture));

            // Filter all the system declined requests.
            var autoDeclinedRequests = openShiftRequests.Where(c => c.Body != null && c.Body["state"].Value <string>() == ApiConstants.Declined && c.Body["assignedTo"].Value <string>() == ApiConstants.System).ToList();

            // Filter approved open shift request.
            var approvedOpenShiftRequest = openShiftRequests.Where(c => c.Body != null && c.Body["state"].Value <string>() == ApiConstants.ShiftsApproved && c.Body["assignedTo"].Value <string>() == ApiConstants.ShiftsManager).FirstOrDefault();

            var finalShift            = JsonConvert.DeserializeObject <Shift>(finalShiftObj.Body.ToString());
            var finalOpenShiftRequest = JsonConvert.DeserializeObject <OpenShiftRequestIS>(approvedOpenShiftRequest.Body.ToString());
            var finalOpenShift        = JsonConvert.DeserializeObject <OpenShiftIS>(finalOpenShiftObj.Body.ToString());

            updateProps.Add("NewShiftId", finalShift.Id);
            updateProps.Add("GraphOpenShiftRequestId", finalOpenShiftRequest.Id);
            updateProps.Add("GraphOpenShiftId", finalOpenShift.Id);

            // Step 1 - Create the Kronos Unique ID.
            var kronosUniqueId = this.utility.CreateUniqueId(finalShift);

            this.telemetryClient.TrackTrace("KronosHash-OpenShiftRequestApproval-TeamsController: " + kronosUniqueId);

            try
            {
                this.telemetryClient.TrackTrace("Updating entities-OpenShiftRequestApproval started: " + DateTime.Now.ToString(CultureInfo.InvariantCulture));

                // Step 1 - Get the temp shift record first by table scan against RowKey.
                var tempShiftRowKey = $"SHFT_PENDING_{finalOpenShiftRequest.Id}";
                var tempShiftEntity = await this.shiftMappingEntityProvider.GetShiftMappingEntityByRowKeyAsync(tempShiftRowKey).ConfigureAwait(false);

                // We need to check if the tempShift is not null because in the Open Shift Request controller, the tempShift was created
                // as part of the Graph API call to approve the Open Shift Request.
                if (tempShiftEntity != null)
                {
                    // Step 2 - Form the new shift record.
                    var shiftToInsert = new TeamsShiftMappingEntity()
                    {
                        RowKey             = finalShift.Id,
                        KronosPersonNumber = tempShiftEntity.KronosPersonNumber,
                        KronosUniqueId     = tempShiftEntity.KronosUniqueId,
                        PartitionKey       = tempShiftEntity.PartitionKey,
                        AadUserId          = tempShiftEntity.AadUserId,
                        ShiftStartDate     = this.utility.UTCToKronosTimeZone(finalShift.SharedShift.StartDateTime),
                    };

                    // Step 3 - Save the new shift record.
                    await this.shiftMappingEntityProvider.SaveOrUpdateShiftMappingEntityAsync(shiftToInsert, shiftToInsert.RowKey, shiftToInsert.PartitionKey).ConfigureAwait(false);

                    // Step 4 - Delete the temp shift record.
                    await this.shiftMappingEntityProvider.DeleteOrphanDataFromShiftMappingAsync(tempShiftEntity).ConfigureAwait(false);

                    // Adding response for create new shift.
                    integrationResponse = GenerateResponse(finalShift.Id, HttpStatusCode.OK, null, null);
                    responseModelList.Add(integrationResponse);
                }
                else
                {
                    // We are logging to ApplicationInsights that the tempShift entity could not be found.
                    this.telemetryClient.TrackTrace(string.Format(CultureInfo.InvariantCulture, Resource.EntityNotFoundWithRowKey, tempShiftRowKey));
                }

                // Logging to ApplicationInsights the OpenShiftRequestId.
                this.telemetryClient.TrackTrace("OpenShiftRequestId = " + finalOpenShiftRequest.Id);

                // Find the open shift request for which we update the ShiftsStatus to Approved.
                var openShiftRequestEntityToUpdate = await this.openShiftRequestMappingEntityProvider.GetOpenShiftRequestMappingEntityByOpenShiftIdAsync(
                    finalOpenShift.Id,
                    finalOpenShiftRequest.Id).ConfigureAwait(false);

                openShiftRequestEntityToUpdate.ShiftsStatus = finalOpenShiftRequest.State;

                // Update the open shift request to Approved in the ShiftStatus column.
                await this.openShiftRequestMappingEntityProvider.SaveOrUpdateOpenShiftRequestMappingEntityAsync(openShiftRequestEntityToUpdate).ConfigureAwait(false);

                // Delete the open shift entity accordingly from the OpenShiftEntityMapping table in Azure Table storage as the open shift request has been approved.
                await this.openShiftMappingEntityProvider.DeleteOrphanDataFromOpenShiftMappingByOpenShiftIdAsync(finalOpenShift.Id).ConfigureAwait(false);

                // Adding response for delete open shift.
                integrationResponse = GenerateResponse(finalOpenShift.Id, HttpStatusCode.OK, null, null);
                responseModelList.Add(integrationResponse);

                // Adding response for approved open shift request.
                integrationResponse = GenerateResponse(finalOpenShiftRequest.Id, HttpStatusCode.OK, null, null);
                responseModelList.Add(integrationResponse);

                foreach (var declinedRequest in autoDeclinedRequests)
                {
                    this.telemetryClient.TrackTrace($"SystemDeclinedOpenShiftRequestId: {declinedRequest.Id}");
                    var declinedOpenShiftRequest = JsonConvert.DeserializeObject <OpenShiftRequestIS>(declinedRequest.Body.ToString());

                    // Update the status in Azure table storage.
                    var entityToUpdate = await this.openShiftRequestMappingEntityProvider.GetOpenShiftRequestMappingEntityByOpenShiftRequestIdAsync(
                        declinedRequest.Id).ConfigureAwait(false);

                    entityToUpdate.KronosStatus = declinedOpenShiftRequest.State;
                    entityToUpdate.ShiftsStatus = declinedOpenShiftRequest.State;

                    // Commit the change to the database.
                    await this.openShiftRequestMappingEntityProvider.SaveOrUpdateOpenShiftRequestMappingEntityAsync(entityToUpdate).ConfigureAwait(false);

                    this.telemetryClient.TrackTrace($"OpenShiftRequestId: {declinedOpenShiftRequest.Id}, assigned to: {declinedOpenShiftRequest.AssignedTo}, state: {declinedOpenShiftRequest.State}");

                    // Adding response for system declined open shift request.
                    integrationResponse = GenerateResponse(declinedOpenShiftRequest.Id, HttpStatusCode.OK, null, null);
                    responseModelList.Add(integrationResponse);
                }

                this.telemetryClient.TrackTrace("Updating entities-OpenShiftRequestApproval complete: " + DateTime.Now.ToString(CultureInfo.InvariantCulture));
            }
            catch (Exception ex)
            {
                if (ex.InnerException != null)
                {
                    this.telemetryClient.TrackTrace($"Shift mapping has failed for {finalOpenShiftRequest.Id}: " + ex.InnerException.ToString());
                }

                this.telemetryClient.TrackTrace($"Shift mapping has resulted in some type of error with the following: {ex.StackTrace.ToString(CultureInfo.InvariantCulture)}");

                throw;
            }

            return(responseModelList);
        }
コード例 #8
0
        /// <summary>
        /// Process swap shift requests outbound calls.
        /// </summary>
        /// <param name="jsonModel">Incoming payload for the request been made in Shifts.</param>
        /// <param name="aadGroupId">AAD Group id.</param>
        /// <returns>Returns list of ShiftIntegResponse for request.</returns>
        private async Task <List <ShiftsIntegResponse> > ProcessSwapShiftRequest(RequestModel jsonModel, string aadGroupId, bool isRequestFromCorrectIntegration)
        {
            List <ShiftsIntegResponse> responseModelList = new List <ShiftsIntegResponse>();
            var requestBody = jsonModel.Requests.First(x => x.Url.Contains("/swapRequests/", StringComparison.InvariantCulture)).Body;
            ShiftsIntegResponse integrationResponseSwap = null;

            try
            {
                // If the requestBody is not null - represents either a new Swap Shift request being created by FLW1,
                // FLW2 accepts or declines FLW1's request, or FLM approves or declines the Swap Shift request.
                // If the requestBody is null - represents FLW1's cancellation of the Swap Shift Request.
                if (requestBody != null)
                {
                    var requestState      = requestBody?["state"].Value <string>();
                    var requestAssignedTo = requestBody?["assignedTo"].Value <string>();

                    var swapRequest = JsonConvert.DeserializeObject <SwapRequest>(requestBody.ToString());

                    // FLW1 has requested for swap shift, submit the request in Kronos.
                    if (requestState == ApiConstants.ShiftsPending && requestAssignedTo == ApiConstants.ShiftsRecipient)
                    {
                        integrationResponseSwap = await this.swapShiftController.SubmitSwapShiftRequestToKronosAsync(swapRequest, aadGroupId).ConfigureAwait(false);

                        responseModelList.Add(integrationResponseSwap);
                    }

                    // FLW2 has approved the swap shift, updates the status in Kronos to submitted and request goes to manager for approval.
                    else if (requestState == ApiConstants.ShiftsPending && requestAssignedTo == ApiConstants.ShiftsManager)
                    {
                        integrationResponseSwap = await this.swapShiftController.ApproveOrDeclineSwapShiftRequestToKronosAsync(swapRequest, aadGroupId).ConfigureAwait(false);

                        responseModelList.Add(integrationResponseSwap);
                    }

                    // FLW2 has declined the swap shift, updates the status in Kronos to refused.
                    else if (requestState == ApiConstants.Declined && requestAssignedTo == ApiConstants.ShiftsRecipient)
                    {
                        integrationResponseSwap = await this.swapShiftController.ApproveOrDeclineSwapShiftRequestToKronosAsync(swapRequest, aadGroupId).ConfigureAwait(false);

                        responseModelList.Add(integrationResponseSwap);
                    }

                    // Manager has declined the request in Kronos, which declines the request in Shifts also.
                    else if (requestState == ApiConstants.ShiftsDeclined && requestAssignedTo == ApiConstants.ShiftsManager)
                    {
                        // The request is coming from intended workforce integration.
                        if (isRequestFromCorrectIntegration)
                        {
                            this.telemetryClient.TrackTrace($"Request coming from correct workforce integration is {isRequestFromCorrectIntegration} for SwapShiftRequest decline outbound call.");
                            integrationResponseSwap = GenerateResponse(swapRequest.Id, HttpStatusCode.OK, swapRequest.ETag, null);
                            responseModelList.Add(integrationResponseSwap);
                        }

                        // Request is coming from either Shifts UI or from incorrect workforce integration.
                        else
                        {
                            this.telemetryClient.TrackTrace($"Request coming from correct workforce integration is {isRequestFromCorrectIntegration} for SwapShiftRequest decline outbound call.");
                            responseModelList = GenerateResponseToPreventAction(jsonModel, Resource.InvalidApproval);
                        }
                    }

                    // Manager has approved the request in Kronos.
                    else if (requestState == ApiConstants.ShiftsApproved && requestAssignedTo == ApiConstants.ShiftsManager)
                    {
                        // The request is coming from intended workforce integration.
                        if (isRequestFromCorrectIntegration)
                        {
                            this.telemetryClient.TrackTrace($"Request coming from correct workforce integration is {isRequestFromCorrectIntegration} for SwapShiftRequest approval outbound call.");
                            responseModelList = await this.ProcessSwapShiftRequestApprovalAsync(jsonModel, aadGroupId).ConfigureAwait(false);
                        }

                        // Request is coming from either Shifts UI or from incorrect workforce integration.
                        else
                        {
                            this.telemetryClient.TrackTrace($"Request coming from correct workforce integration is {isRequestFromCorrectIntegration} for SwapShiftRequest approval outbound call.");
                            responseModelList = GenerateResponseToPreventAction(jsonModel, Resource.InvalidApproval);
                        }
                    }

                    // There is a System decline with the Swap Shift Request
                    else if (requestState == ApiConstants.Declined && requestAssignedTo == ApiConstants.System)
                    {
                        var           systemDeclineSwapReqId = jsonModel.Requests.First(x => x.Url.Contains("/swapRequests/", StringComparison.InvariantCulture)).Id;
                        ResponseError responseError          = new ResponseError
                        {
                            Message = Resource.SystemDeclined,
                        };

                        integrationResponseSwap = GenerateResponse(systemDeclineSwapReqId, HttpStatusCode.OK, null, responseError);
                        responseModelList.Add(integrationResponseSwap);
                    }
                }
                else if (jsonModel.Requests.Any(c => c.Method == "DELETE"))
                {
                    // Code below handles the delete swap shift request.
                    var deleteSwapRequestId = jsonModel.Requests.First(x => x.Url.Contains("/swapRequests/", StringComparison.InvariantCulture)).Id;

                    // Logging to telemetry the incoming cancelled request by FLW1.
                    this.telemetryClient.TrackTrace($"The Swap Shift Request: {deleteSwapRequestId} has been declined by FLW1.");

                    var entityToCancel = await this.swapShiftMappingEntityProvider.GetKronosReqAsync(deleteSwapRequestId).ConfigureAwait(false);

                    // Updating the ShiftsStatus to Cancelled.
                    entityToCancel.ShiftsStatus = ApiConstants.SwapShiftCancelled;

                    // Updating the entity accordingly
                    await this.swapShiftMappingEntityProvider.AddOrUpdateSwapShiftMappingAsync(entityToCancel).ConfigureAwait(false);

                    integrationResponseSwap = GenerateResponse(deleteSwapRequestId, HttpStatusCode.OK, null, null);
                    responseModelList.Add(integrationResponseSwap);
                }
            }
            catch (Exception)
            {
                this.telemetryClient.TrackTrace("Teams Controller swapRequests responseModelList Exception" + JsonConvert.SerializeObject(responseModelList));
                throw;
            }

            this.telemetryClient.TrackTrace("Teams Controller swapRequests responseModelList" + JsonConvert.SerializeObject(responseModelList));

            return(responseModelList);
        }
コード例 #9
0
        /// <summary>
        /// Process open shift requests outbound calls.
        /// </summary>
        /// <param name="jsonModel">Incoming payload for the request been made in Shifts.</param>
        /// <param name="updateProps">telemetry properties.</param>
        /// <returns>Returns list of ShiftIntegResponse for request.</returns>
        private async Task <List <ShiftsIntegResponse> > ProcessOpenShiftRequest(RequestModel jsonModel, Dictionary <string, string> updateProps, string teamsId, bool isRequestFromCorrectIntegration)
        {
            List <ShiftsIntegResponse> responseModelList = new List <ShiftsIntegResponse>();
            var requestBody = jsonModel.Requests.First(x => x.Url.Contains("/openshiftrequests/", StringComparison.InvariantCulture)).Body;

            if (requestBody != null)
            {
                var requestState = requestBody?["state"].Value <string>();

                switch (requestState)
                {
                // The Open shift request is submitted in Shifts and is pending with manager for approval.
                case ApiConstants.ShiftsPending:
                {
                    var openShiftRequest = JsonConvert.DeserializeObject <OpenShiftRequestIS>(requestBody.ToString());
                    responseModelList = await this.ProcessOutboundOpenShiftRequestAsync(openShiftRequest, updateProps, teamsId).ConfigureAwait(false);
                }

                break;

                // The Open shift request is approved by manager.
                case ApiConstants.ShiftsApproved:
                {
                    // The request is coming from intended workforce integration.
                    if (isRequestFromCorrectIntegration)
                    {
                        this.telemetryClient.TrackTrace($"Request coming from correct workforce integration is {isRequestFromCorrectIntegration} for OpenShiftRequest approval outbound call.");
                        responseModelList = await this.ProcessOpenShiftRequestApprovalAsync(jsonModel, updateProps).ConfigureAwait(false);
                    }

                    // Request is coming from either Shifts UI or from incorrect workforce integration.
                    else
                    {
                        this.telemetryClient.TrackTrace($"Request coming from correct workforce integration is {isRequestFromCorrectIntegration} for OpenShiftRequest approval outbound call.");
                        responseModelList = GenerateResponseToPreventAction(jsonModel, Resource.InvalidApproval);
                    }
                }

                break;

                // The code below would be when there is a decline.
                case ApiConstants.ShiftsDeclined:
                {
                    // The request is coming from intended workforce integration.
                    if (isRequestFromCorrectIntegration)
                    {
                        this.telemetryClient.TrackTrace($"Request coming from correct workforce integration is {isRequestFromCorrectIntegration} for OpenShiftRequest decline outbound call.");
                        var integrationResponse = new ShiftsIntegResponse();
                        foreach (var item in jsonModel.Requests)
                        {
                            integrationResponse = GenerateResponse(item.Id, HttpStatusCode.OK, null, null);
                            responseModelList.Add(integrationResponse);
                        }
                    }

                    // Request is coming from either Shifts UI or from incorrect workforce integration.
                    else
                    {
                        this.telemetryClient.TrackTrace($"Request coming from correct workforce integration is {isRequestFromCorrectIntegration} for OpenShiftRequest decline outbound call.");
                        responseModelList = GenerateResponseToPreventAction(jsonModel, Resource.InvalidApproval);
                    }
                }

                break;
                }
            }

            return(responseModelList);
        }
コード例 #10
0
        /// <summary>
        /// This method further processes the Swap Shift request approval.
        /// </summary>
        /// <param name="jsonModel">The decryped JSON payload from Shifts/MS Graph.</param>
        /// <param name="aadGroupId">The team ID for which the Swap Shift request has been approved.</param>
        /// <returns>A unit of execution that contains the type of <see cref="ShiftsIntegResponse"/>.</returns>
        private async Task <List <ShiftsIntegResponse> > ProcessSwapShiftRequestApprovalAsync(RequestModel jsonModel, string aadGroupId)
        {
            List <ShiftsIntegResponse> swapShiftsIntegResponses = new List <ShiftsIntegResponse>();
            ShiftsIntegResponse        integrationResponse      = null;
            var swapShiftApprovalRes = from requests in jsonModel.Requests
                                       group requests by requests.Url;

            var swapShiftRequestObj = swapShiftApprovalRes?.FirstOrDefault(x => x.Key.Contains("/swapRequests/", StringComparison.InvariantCulture))?.First();
            var swapShiftRequest    = JsonConvert.DeserializeObject <SwapRequest>(swapShiftRequestObj.Body.ToString());

            var postedShifts = jsonModel.Requests.Where(x => x.Url.Contains("/shifts/", StringComparison.InvariantCulture) && x.Method == "POST").ToList();

            if (swapShiftRequest != null)
            {
                var newShiftFirst  = JsonConvert.DeserializeObject <Shift>(postedShifts.First().Body.ToString());
                var newShiftSecond = JsonConvert.DeserializeObject <Shift>(postedShifts.Last().Body.ToString());

                // Step 1 - Create the Kronos Unique ID.
                var kronosUniqueIdFirst  = this.utility.CreateUniqueId(newShiftFirst);
                var kronosUniqueIdSecond = this.utility.CreateUniqueId(newShiftSecond);

                try
                {
                    var userMappingRecord = await this.userMappingProvider.GetUserMappingEntityAsyncNew(
                        newShiftFirst?.UserId,
                        aadGroupId).ConfigureAwait(false);

                    // When getting the month partition key, make sure to take into account the Kronos Time Zone as well
                    var provider = CultureInfo.InvariantCulture;
                    var actualStartDateTimeStr = this.utility.CalculateStartDateTime(
                        newShiftFirst.SharedShift.StartDateTime.Date).ToString("M/dd/yyyy", provider);
                    var actualEndDateTimeStr = this.utility.CalculateEndDateTime(
                        newShiftFirst.SharedShift.EndDateTime.Date).ToString("M/dd/yyyy", provider);

                    // Create the month partition key based on the finalShift object.
                    var monthPartitions = Common.Utility.GetMonthPartition(actualStartDateTimeStr, actualEndDateTimeStr);
                    var monthPartition  = monthPartitions?.FirstOrDefault();

                    // Create the shift mapping entity based on the finalShift object also.
                    var shiftEntity = Common.Utility.CreateShiftMappingEntity(newShiftFirst, userMappingRecord, kronosUniqueIdFirst);
                    await this.shiftMappingEntityProvider.SaveOrUpdateShiftMappingEntityAsync(
                        shiftEntity,
                        newShiftFirst.Id,
                        monthPartition).ConfigureAwait(false);

                    var userMappingRecordSec = await this.userMappingProvider.GetUserMappingEntityAsyncNew(
                        newShiftSecond?.UserId,
                        aadGroupId).ConfigureAwait(false);

                    // When getting the month partition key, make sure to take into account the Kronos Time Zone as well
                    var actualStartDateTimeStrSec = this.utility.CalculateStartDateTime(
                        newShiftSecond.SharedShift.StartDateTime).ToString("M/dd/yyyy", provider);
                    var actualEndDateTimeStrSec = this.utility.CalculateEndDateTime(
                        newShiftSecond.SharedShift.EndDateTime).ToString("M/dd/yyyy", provider);

                    // Create the month partition key based on the finalShift object.
                    var monthPartitionsSec = Common.Utility.GetMonthPartition(actualStartDateTimeStrSec, actualEndDateTimeStrSec);
                    var monthPartitionSec  = monthPartitionsSec?.FirstOrDefault();

                    // Create the shift mapping entity based on the finalShift object also.
                    var shiftEntitySec = Common.Utility.CreateShiftMappingEntity(newShiftSecond, userMappingRecordSec, kronosUniqueIdSecond);
                    await this.shiftMappingEntityProvider.SaveOrUpdateShiftMappingEntityAsync(
                        shiftEntitySec,
                        newShiftSecond.Id,
                        monthPartitionSec).ConfigureAwait(false);

                    foreach (var item in jsonModel.Requests)
                    {
                        if (item.Url.Contains("/swapRequests/", StringComparison.InvariantCulture))
                        {
                            integrationResponse = GenerateResponse(item.Id, HttpStatusCode.OK, swapShiftRequest.ETag, null);
                        }
                        else
                        {
                            integrationResponse = GenerateResponse(item.Id, HttpStatusCode.OK, null, null);
                        }

                        swapShiftsIntegResponses.Add(integrationResponse);
                    }
                }
                catch (Exception ex)
                {
                    var exceptionProps = new Dictionary <string, string>()
                    {
                        { "NewFirstShiftId", newShiftFirst.Id },
                        { "NewSecondShiftId", newShiftSecond.Id },
                    };

                    this.telemetryClient.TrackException(ex, exceptionProps);
                    throw;
                }
            }

            return(swapShiftsIntegResponses);
        }
コード例 #11
0
        /// <summary>
        /// This method processes the open shift request approval, and proceeds to update the Azure table storage accordingly with the Shifts status
        /// of the open shift request, and also ensures that the ShiftMappingEntity table is properly in sync.
        /// </summary>
        /// <param name="jsonModel">The decrypted JSON payload.</param>
        /// <param name="updateProps">A dictionary of string, string that will be logged to ApplicationInsights.</param>
        /// <returns>A unit of execution.</returns>
        private async Task <List <ShiftsIntegResponse> > ProcessOpenShiftRequestApprovalAsync(RequestModel jsonModel, Dictionary <string, string> updateProps)
        {
            List <ShiftsIntegResponse> responseModelList   = new List <ShiftsIntegResponse>();
            ShiftsIntegResponse        integrationResponse = null;

            var finalOpenShiftReqObj = jsonModel?.Requests?.FirstOrDefault(x => x.Url.Contains("/openshiftrequests/", StringComparison.InvariantCulture));
            var finalOpenShiftObj    = jsonModel?.Requests?.FirstOrDefault(x => x.Url.Contains("/openshifts/", StringComparison.InvariantCulture));
            var finalShiftObj        = jsonModel?.Requests?.FirstOrDefault(x => x.Url.Contains("/shifts/", StringComparison.InvariantCulture));

            var finalShift            = JsonConvert.DeserializeObject <Shift>(finalShiftObj.Body.ToString());
            var finalOpenShiftRequest = JsonConvert.DeserializeObject <OpenShiftRequestIS>(finalOpenShiftReqObj.Body.ToString());
            var finalOpenShift        = JsonConvert.DeserializeObject <OpenShiftIS>(finalOpenShiftObj.Body.ToString());

            updateProps.Add("NewShiftId", finalShift.Id);
            updateProps.Add("GraphOpenShiftRequestId", finalOpenShiftRequest.Id);
            updateProps.Add("GraphOpenShiftId", finalOpenShift.Id);

            // Step 1 - Create the Kronos Unique ID.
            var kronosUniqueId = this.utility.CreateUniqueId(finalShift);

            this.telemetryClient.TrackTrace("KronosHash-OpenShiftRequestApproval-TeamsController: " + kronosUniqueId);

            try
            {
                this.telemetryClient.TrackTrace("Updating entities-OpenShiftRequestApproval started: " + DateTime.Now.ToString(CultureInfo.InvariantCulture));

                // Step 1 - Get the temp shift record first by table scan against RowKey.
                var tempShiftRowKey = $"SHFT_PENDING_{finalOpenShiftRequest.Id}";
                var tempShiftEntity = await this.shiftMappingEntityProvider.GetShiftMappingEntityByRowKeyAsync(tempShiftRowKey).ConfigureAwait(false);

                // We need to check if the tempShift is not null because in the Open Shift Request controller, the tempShift was created
                // as part of the Graph API call to approve the Open Shift Request.
                if (tempShiftEntity != null)
                {
                    // Step 2 - Form the new shift record.
                    var shiftToInsert = new TeamsShiftMappingEntity()
                    {
                        RowKey             = finalShift.Id,
                        KronosPersonNumber = tempShiftEntity.KronosPersonNumber,
                        KronosUniqueId     = tempShiftEntity.KronosUniqueId,
                        PartitionKey       = tempShiftEntity.PartitionKey,
                        AadUserId          = tempShiftEntity.AadUserId,
                    };

                    // Step 3 - Save the new shift record.
                    await this.shiftMappingEntityProvider.SaveOrUpdateShiftMappingEntityAsync(shiftToInsert, shiftToInsert.RowKey, shiftToInsert.PartitionKey).ConfigureAwait(false);

                    // Step 4 - Delete the temp shift record.
                    await this.shiftMappingEntityProvider.DeleteOrphanDataFromShiftMappingAsync(tempShiftEntity).ConfigureAwait(false);
                }
                else
                {
                    // We are logging to ApplicationInsights that the tempShift entity could not be found.
                    this.telemetryClient.TrackTrace(string.Format(CultureInfo.InvariantCulture, Resource.EntityNotFoundWithRowKey, tempShiftRowKey));
                }

                // Logging to ApplicationInsights the OpenShiftRequestId.
                this.telemetryClient.TrackTrace("OpenShiftRequestId = " + finalOpenShiftRequest.Id);

                // Find the open shift request for which we update the ShiftsStatus to Approved.
                var openShiftRequestEntityToUpdate = await this.openShiftRequestMappingEntityProvider.GetOpenShiftRequestMappingEntityByOpenShiftIdAsync(
                    finalOpenShift.Id,
                    finalOpenShiftRequest.Id).ConfigureAwait(false);

                openShiftRequestEntityToUpdate.ShiftsStatus = finalOpenShiftRequest.State;

                // Update the open shift request to Approved in the ShiftStatus column.
                await this.openShiftRequestMappingEntityProvider.SaveOrUpdateOpenShiftRequestMappingEntityAsync(openShiftRequestEntityToUpdate).ConfigureAwait(false);

                // Delete the open shift entity accordingly from the OpenShiftEntityMapping table in Azure Table storage as the open shift request has been approved.
                await this.openShiftMappingEntityProvider.DeleteOrphanDataFromOpenShiftMappingByOpenShiftIdAsync(finalOpenShift.Id).ConfigureAwait(false);

                // Sending the acknowledgement for each subrequest from the request payload received from Shifts.
                foreach (var item in jsonModel.Requests)
                {
                    integrationResponse = GenerateResponse(item.Id, HttpStatusCode.OK, null, null);
                    responseModelList.Add(integrationResponse);
                }

                this.telemetryClient.TrackTrace("Updating entities-OpenShiftRequestApproval complete: " + DateTime.Now.ToString(CultureInfo.InvariantCulture));
            }
            catch (Exception ex)
            {
                // Logging when the inner exception is not null - including the open shift request ID.
                if (ex.InnerException != null)
                {
                    this.telemetryClient.TrackTrace($"Shift mapping has failed for {finalOpenShiftRequest.Id}: " + ex.InnerException.ToString());
                    this.telemetryClient.TrackException(ex.InnerException);
                }

                // Logging the exception regardless, and making sure to add the open shift request ID as well.
                this.telemetryClient.TrackTrace($"Shift mapping has resulted in some type of error with the following: {ex.StackTrace.ToString(CultureInfo.InvariantCulture)}, happening with open shift request ID: {finalOpenShiftRequest.Id}");
                this.telemetryClient.TrackException(ex);

                throw;
            }

            return(responseModelList);
        }
コード例 #12
0
        /// <summary>
        /// Process open shift requests outbound calls.
        /// </summary>
        /// <param name="jsonModel">Incoming payload for the request been made in Shifts.</param>
        /// <param name="updateProps">telemetry properties.</param>
        /// <returns>Returns list of ShiftIntegResponse for request.</returns>
        private async Task <List <ShiftsIntegResponse> > ProcessOpenShiftRequest(RequestModel jsonModel, Dictionary <string, string> updateProps)
        {
            List <ShiftsIntegResponse> responseModelList = new List <ShiftsIntegResponse>();
            var requestBody  = jsonModel.Requests.First(x => x.Url.Contains("/openshiftrequests/", StringComparison.InvariantCulture)).Body;
            var requestState = requestBody != null ? requestBody["state"].Value <string>() : null;

            if (requestBody != null)
            {
                switch (requestState)
                {
                // The Open shift request is submitted in Shifts and is pending with manager for approval.
                case ApiConstants.ShiftsPending:
                {
                    responseModelList = await this.ProcessOutboundOpenShiftRequestAsync(jsonModel, updateProps).ConfigureAwait(false);
                }

                break;

                // The Open shift request is approved by manager.
                case ApiConstants.ShiftsApproved:
                {
                    responseModelList = await this.ProcessOpenShiftRequestApprovalAsync(jsonModel, updateProps).ConfigureAwait(false);
                }

                break;

                // The code below would be when there is a decline. There is no need for further
                // processing, the decline was made on Kronos side.
                case ApiConstants.ShiftsDeclined:
                {
                    var integrationResponse = new ShiftsIntegResponse();
                    foreach (var item in jsonModel.Requests)
                    {
                        integrationResponse = GenerateResponse(item.Id, HttpStatusCode.OK, null, null);
                        responseModelList.Add(integrationResponse);
                    }
                }

                break;

                // The code below handles the system declined request.
                default:
                {
                    var integrationResponse = new ShiftsIntegResponse();
                    foreach (var item in jsonModel.Requests)
                    {
                        integrationResponse = GenerateResponse(item.Id, HttpStatusCode.OK, null, null);
                        responseModelList.Add(integrationResponse);
                    }
                }

                break;
                }
            }
            else
            {
                // Code below handles the delete open shift request.
                var integrationResponse = new ShiftsIntegResponse();
                foreach (var item in jsonModel.Requests)
                {
                    integrationResponse = GenerateResponse(item.Id, HttpStatusCode.OK, null, null);
                    responseModelList.Add(integrationResponse);
                }
            }

            return(responseModelList);
        }