public async Task <IActionResult> ChangeOrganisationScope(string request)
        {
            // Ensure user has completed the registration process
            var checkResult = await CheckUserRegisteredOkAsync();

            if (checkResult != null)
            {
                return(checkResult);
            }

            // Decrypt request
            if (!request.DecryptToParams(out var requestParams))
            {
                return(new HttpBadRequestResult($"Cannot decrypt request parameters '{request}'"));
            }

            // Extract the request vars
            var organisationId     = requestParams[0].ToInt64();
            var reportingStartYear = requestParams[1].ToInt32();

            // Check the user has permission for this organisation
            var userOrg = VirtualUser.UserOrganisations.FirstOrDefault(uo => uo.OrganisationId == organisationId);

            if (userOrg == null)
            {
                return(new HttpForbiddenResult(
                           $"User {VirtualUser?.EmailAddress} is not registered for organisation id {organisationId}"));
            }

            // Generate the scope state model
            var stateModel = ScopePresentation.CreateScopingViewModel(userOrg.Organisation, CurrentUser);

            // Get the latest scope for the reporting year
            var latestScope = stateModel.ThisScope.SnapshotDate.Year == reportingStartYear ? stateModel.ThisScope :
                              stateModel.LastScope.SnapshotDate.Year == reportingStartYear ? stateModel.LastScope : null;

            // Set the return url
            stateModel.StartUrl = Url.Action("ManageOrganisation",
                                             new { id = Encryption.EncryptQuerystring(organisationId.ToString()) });
            stateModel.IsChangeJourney = true;
            stateModel.AccountingDate  = latestScope.SnapshotDate;

            //Set the in/out journey type
            stateModel.IsOutOfScopeJourney =
                latestScope.ScopeStatus.IsAny(ScopeStatuses.PresumedInScope, ScopeStatuses.InScope);

            // Stash the model for the scope controller
            StashModel(typeof(ScopeController), stateModel);

            if (stateModel.IsOutOfScopeJourney)
            {
                return(RedirectToAction("EnterOutOfScopeAnswers", "Scope"));
            }

            return(RedirectToAction("ConfirmInScope", "Scope"));
        }
        public async Task <IActionResult> ConfirmOutOfScopeAnswers(string command)
        {
            // When User is Admin then redirect to Admin\Home
            if (CurrentUser != null && _sharedBusinessLogic.AuthorisationBusinessLogic.IsAdministrator(CurrentUser))
            {
                return(RedirectToAction("Home", "Admin"));
            }

            var stateModel = UnstashModel <ScopingViewModel>();

            // when model is null then return session expired view
            if (stateModel == null)
            {
                return(SessionExpiredView());
            }

            ApplyUserContactDetails(CurrentUser, stateModel);

            // Save user as out of scope
            var snapshotYears = new HashSet <int> {
                stateModel.AccountingDate.Year
            };

            if (!stateModel.IsChangeJourney)
            {
                snapshotYears.Add(stateModel.AccountingDate.Year - 1);
            }

            await ScopePresentation.SaveScopesAsync(stateModel, snapshotYears);

            StashModel(stateModel);

            var organisation        = SharedBusinessLogic.DataRepository.Get <Organisation>(stateModel.OrganisationId);
            var currentSnapshotDate = _sharedBusinessLogic.GetAccountingStartDate(organisation.SectorType);

            if (stateModel.AccountingDate == currentSnapshotDate)
            {
                var emailAddressesForOrganisation = organisation.UserOrganisations.Select(uo => uo.User.EmailAddress);
                foreach (var emailAddress in emailAddressesForOrganisation)
                {
                    _sharedBusinessLogic.NotificationService.SendScopeChangeOutEmail(emailAddress,
                                                                                     organisation.OrganisationName);
                }
            }

            //Start new user registration
            return(RedirectToAction("FinishOutOfScope", "Scope"));
        }
        public async Task <IActionResult> OutOfScope(EnterCodesViewModel model)
        {
            // When User is Admin then redirect to Admin\Home
            if (CurrentUser != null && _sharedBusinessLogic.AuthorisationBusinessLogic.IsAdministrator(CurrentUser))
            {
                return(RedirectToAction("Home", "Admin"));
            }

            // When Spamlocked then return a CustomError view
            var remainingTime =
                await GetRetryLockRemainingTimeAsync("lastScopeCode", SharedBusinessLogic.SharedOptions.LockoutMinutes);

            if (remainingTime > TimeSpan.Zero)
            {
                return(View("CustomError",
                            WebService.ErrorViewModelFactory.Create(1125,
                                                                    new { remainingTime = remainingTime.ToFriendly(maxParts: 2) })));
            }

            // the following fields are validatable at this stage
            ModelState.Include(
                nameof(EnterCodesViewModel.EmployerReference),
                nameof(EnterCodesViewModel.SecurityToken));

            // When ModelState is Not Valid Then Return the EnterCodes View
            if (!ModelState.IsValid)
            {
                this.CleanModelErrors <EnterCodesViewModel>();
                return(View("EnterCodes", model));
            }

            // Generate the state model
            var stateModel = await ScopePresentation.CreateScopingViewModelAsync(model, CurrentUser);

            if (stateModel == null)
            {
                await IncrementRetryCountAsync("lastScopeCode", SharedBusinessLogic.SharedOptions.LockoutMinutes);

                ModelState.AddModelError(3027);
                this.CleanModelErrors <EnterCodesViewModel>();
                return(View("EnterCodes", model));
            }


            //Clear the retry locks
            await ClearRetryLocksAsync("lastScopeCode");

            // set the back link
            stateModel.StartUrl = Url.Action("OutOfScope");

            // set the journey to out-of-scope
            stateModel.IsOutOfScopeJourney = true;

            // save the state to the session cache
            StashModel(stateModel);

            // when security code has expired then redirect to the CodeExpired action
            if (stateModel.IsSecurityCodeExpired)
            {
                return(View("CodeExpired", stateModel));
            }


            //When on out-of-scope journey and any previous explicit scope then tell user scope is known
            if (!stateModel.IsChangeJourney &&
                (
                    stateModel.LastScope != null &&
                    stateModel.LastScope.ScopeStatus.IsAny(ScopeStatuses.InScope, ScopeStatuses.OutOfScope) ||
                    stateModel.ThisScope != null &&
                    stateModel.ThisScope.ScopeStatus.IsAny(ScopeStatuses.InScope, ScopeStatuses.OutOfScope)
                )
                )
            {
                return(View("ScopeKnown", stateModel));
            }

            // redirect to next step
            return(RedirectToAction("ConfirmOutOfScopeDetails"));
        }