private async Task AutoApproveRequestAsync(OpenShiftsChangeRequest openShiftRequest, string teamId, IDurableOrchestrationClient starter) { var deferredActionModel = new DeferredActionModel { ActionType = DeferredActionModel.DeferredActionType.ApproveOpenShiftRequest, DelaySeconds = _teamOptions.DelayedActionSeconds, RequestId = openShiftRequest.Id, TeamId = teamId }; await starter.StartNewAsync(nameof(DeferredActionOrchestrator), deferredActionModel).ConfigureAwait(false); }
private async Task ShareDelete(ShiftModel shift, string teamId, IDurableOrchestrationClient starter) { var deferredActionModel = new DeferredActionModel { ActionType = DeferredActionModel.DeferredActionType.ShareTeamSchedule, DelaySeconds = _teamOptions.DelayedActionSeconds, ShareStartDate = shift.StartDate, ShareEndDate = shift.EndDate, TeamId = teamId }; await starter.StartNewAsync(nameof(DeferredActionOrchestrator), deferredActionModel).ConfigureAwait(false); }
public async Task Run([ActivityTrigger] DeferredActionModel delayedActionModel, ILogger log) { log.LogApproveSwapShiftsRequestActivity(delayedActionModel); try { if (delayedActionModel.ActionType == DeferredActionModel.DeferredActionType.ApproveSwapShiftsRequest) { await _teamsService.ApproveSwapShiftsRequest(delayedActionModel.Message, delayedActionModel.RequestId, delayedActionModel.TeamId).ConfigureAwait(false); } } catch (Exception ex) { log.LogApproveSwapShiftsRequestActivityFailure(ex, delayedActionModel); } }
public async Task Run([ActivityTrigger] DeferredActionModel delayedActionModel, ILogger log) { log.LogReviewOpenShiftRequestActivity(delayedActionModel); try { if (delayedActionModel.ActionType == DeferredActionModel.DeferredActionType.ApproveOpenShiftRequest) { await _teamsService.ApproveOpenShiftRequest(delayedActionModel.RequestId, delayedActionModel.TeamId).ConfigureAwait(false); } else if (delayedActionModel.ActionType == DeferredActionModel.DeferredActionType.DeclineOpenShiftRequest) { await _teamsService.DeclineOpenShiftRequest(delayedActionModel.RequestId, delayedActionModel.TeamId, delayedActionModel.Message).ConfigureAwait(false); } } catch (Exception ex) { // the automated approval could fail because all slots have already been allocated // to other users by the time the approval is processed log.LogReviewOpenShiftRequestActivityFailure(ex, delayedActionModel); } }
public override async Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { var swapRequest = await ReadRequestObjectAsync <SwapRequest>(changeItemRequest, teamId).ConfigureAwait(false); if (swapRequest == null) { return(new ChangeErrorResult(changeResponse, ErrorCodes.SwapRequestNotFound, _stringLocalizer[ErrorCodes.SwapRequestNotFound])); } // are we already processing a request, if so block premature retries var changeData = await ReadChangeDataAsync(swapRequest).ConfigureAwait(false); if (changeData.RecipientStatus == ChangeData.RequestStatus.InProgress) { changeData = await WaitAndReadChangeDataAsync(swapRequest).ConfigureAwait(false); if (changeData.RecipientStatus == ChangeData.RequestStatus.InProgress) { return(new ChangeErrorResult(changeResponse, ErrorCodes.RequestInProgress, _stringLocalizer[ErrorCodes.RequestInProgress], HttpStatusCode.Processing)); } } if (changeData.RecipientStatus == ChangeData.RequestStatus.Complete) { if (changeData.RecipientResult.StatusCode == (int)HttpStatusCode.OK) { return(new ChangeSuccessResult(changeResponse)); } return(new ChangeErrorResult(changeResponse, changeItemRequest, changeData.RecipientResult.ErrorCode, changeData.RecipientResult.ErrorMessage)); } changeData.RecipientStatus = ChangeData.RequestStatus.InProgress; // clear other statuses to avoid blocking subsequent requests for the same two shifts ResetChangeDataStatuses(changeData); await SaveChangeDataAsync(swapRequest, changeData).ConfigureAwait(false); var connectionModel = await _scheduleConnectorService.GetConnectionAsync(teamId).ConfigureAwait(false); var wfmSwapRequest = swapRequest.AsWfmSwapRequest(); wfmSwapRequest.BuId = connectionModel.WfmBuId; var approve = swapRequest.EvaluateState(changeItemRequest.Method) == ChangeRequestState.RecipientApproved; var wfmResponse = await _wfmActionService.RecipientApproveShiftSwapRequestAsync(wfmSwapRequest, approve, log).ConfigureAwait(false); var actionResult = WfmResponseToActionResult(wfmResponse, changeItemRequest, changeResponse); if (wfmResponse.Success) { await _requestCacheService.SaveRequestAsync(teamId, changeItemRequest.Id, swapRequest).ConfigureAwait(false); await SaveChangeResultAsync(swapRequest).ConfigureAwait(false); } else { await SaveChangeResultAsync(swapRequest, HttpStatusCode.BadRequest, wfmResponse.Error.Code, wfmResponse.Error.Message).ConfigureAwait(false); } await _requestCacheService.SaveRequestAsync(teamId, changeItemRequest.Id, swapRequest).ConfigureAwait(false); // flag that the recipient approval has now finished changeData = await ReadChangeDataAsync(swapRequest).ConfigureAwait(false); changeData.RecipientStatus = ChangeData.RequestStatus.Complete; await SaveChangeDataAsync(swapRequest, changeData).ConfigureAwait(false); // if the auto manager approval feature is enabled, issue it now if (actionResult is ChangeSuccessResult && _featureOptions.EnableShiftSwapAutoApproval) { var deferredActionModel = new DeferredActionModel { ActionType = DeferredActionModel.DeferredActionType.ApproveSwapShiftsRequest, DelaySeconds = _teamOptions.DelayedActionSeconds, RequestId = swapRequest.Id, TeamId = teamId, Message = _stringLocalizer.GetString("ApproveSwapShifts") }; await starter.StartNewAsync(nameof(DeferredActionOrchestrator), deferredActionModel).ConfigureAwait(false); } return(actionResult); }
public override async Task <IActionResult> HandleRequest(ChangeRequest changeRequest, ChangeItemRequest changeItemRequest, ChangeResponse changeResponse, string teamId, ILogger log, IDurableOrchestrationClient starter) { // get the open shift from the change item var openShift = changeItemRequest.Body.ToObject <OpenShiftResponse>(); // get the proposed shift to be created from the open shift var proposedShift = changeRequest.Requests .Where(r => r.Method.Equals("POST", StringComparison.OrdinalIgnoreCase)) .Select(r => r.Body.ToObject <ShiftResponse>()) .First(); var connectionModel = await _scheduleConnectorService.GetConnectionAsync(teamId).ConfigureAwait(false); // get the corresponding open shift from cache var localStartDate = openShift.SharedOpenShift.StartDateTime.ApplyTimeZoneOffset(connectionModel.TimeZoneInfoId); var weekStartDate = localStartDate.StartOfWeek(_teamOptions.StartDayOfWeek); var scheduleId = teamId + ApplicationConstants.OpenShiftsSuffix; var cacheModel = await _scheduleCacheService.LoadScheduleAsync(scheduleId, weekStartDate).ConfigureAwait(false); var assignedShift = cacheModel.Tracked.FirstOrDefault(o => o.TeamsShiftId == openShift.Id); if (assignedShift == null) { // we didn't find an open shift with this ID return(new ChangeErrorResult(changeResponse, changeItemRequest, ErrorCodes.NoOpenShiftsFound, _stringLocalizer[ErrorCodes.NoOpenShiftsFound])); } // get the employee object for the manager who initiated the change var manager = await _cacheService.GetKeyAsync <EmployeeModel>(ApplicationConstants.TableNameEmployees, openShift.LastModifiedBy.User.Id).ConfigureAwait(false); if (manager == null) { return(new ChangeErrorResult(changeResponse, changeItemRequest, ErrorCodes.UserCredentialsNotFound, _stringLocalizer[ErrorCodes.UserCredentialsNotFound])); } // get the employee object for the user the open shift is assigned to var employee = await _cacheService.GetKeyAsync <EmployeeModel>(ApplicationConstants.TableNameEmployees, proposedShift.UserId).ConfigureAwait(false); if (employee == null) { return(new ChangeErrorResult(changeResponse, changeItemRequest, ErrorCodes.UserCredentialsNotFound, _stringLocalizer[ErrorCodes.UserCredentialsNotFound])); } var wfmResponse = await _wfmActionService.ManagerAssignOpenShiftAsync(assignedShift, manager, employee, connectionModel.WfmBuId, connectionModel.TimeZoneInfoId, log).ConfigureAwait(false); if (!wfmResponse.Success) { return(new ChangeErrorResult(changeResponse, changeItemRequest, wfmResponse.Error.Code, wfmResponse.Error.Message)); } var policy = GetConflictRetryPolicy(_teamOptions.RetryMaxAttempts, _teamOptions.RetryIntervalSeconds); // as it has been assigned successfully, decrement the quantity assignedShift.Quantity--; // update the open shift in the cache await policy.ExecuteAsync(() => UpdateCachedOpenShiftsAsync(scheduleId, assignedShift, weekStartDate)).ConfigureAwait(false); // convert the open shift to a shift and add it to the week shifts cache assignedShift.Quantity = 1; assignedShift.WfmEmployeeId = employee.WfmEmployeeId; assignedShift.TeamsEmployeeId = employee.TeamsEmployeeId; assignedShift.TeamsShiftId = proposedShift.Id; assignedShift.WfmShiftId = wfmResponse.NewEntityId; await policy.ExecuteAsync(() => UpdateCachedShiftsAsync(teamId, assignedShift, weekStartDate)).ConfigureAwait(false); // finally, set up a deferred action to share the schedule var deferredActionModel = new DeferredActionModel { ActionType = DeferredActionModel.DeferredActionType.ShareTeamSchedule, DelaySeconds = _teamOptions.DelayedActionSeconds, ShareStartDate = openShift.SharedOpenShift.StartDateTime.Date, ShareEndDate = openShift.SharedOpenShift.EndDateTime.Date.AddHours(23).AddMinutes(59), TeamId = teamId }; await starter.StartNewAsync(nameof(DeferredActionOrchestrator), deferredActionModel).ConfigureAwait(false); return(new ChangeSuccessResult(changeResponse)); }
public static void LogApproveSwapShiftsRequestActivityFailure(this ILogger log, Exception ex, DeferredActionModel delayedActionModel) { log.LogError(EventIds.ApproveSwapShiftsRequest, ex, "ApproveSwapShiftsRequest: Status={status} RequestId={requestId}, TeamId={teamId}, Message={message}", Status.Failed, delayedActionModel.RequestId, delayedActionModel.TeamId, delayedActionModel.Message); }
public static void LogApproveSwapShiftsRequestActivity(this ILogger log, DeferredActionModel delayedActionModel) { log.LogInformation(EventIds.ApproveSwapShiftsRequest, "ApproveSwapShiftsRequest: Stage={stage} RequestId={requestId}, TeamId={teamId}, Message={message}", Stage.Start, delayedActionModel.RequestId, delayedActionModel.TeamId, delayedActionModel.Message); }