public async Task And_No_Option_Has_Been_Selected_And_ReservationId_Is_Null_Then_The_Validation_Errors_Are_Returned_To_The_User_And_ViewModel_Recreated(
            ReservationsRouteModel routeModel,
            GetAvailableReservationsResult availableReservationsResult,
            SelectReservationViewModel viewModel,
            string cohortDetailsUrl,
            [Frozen] Mock <IExternalUrlHelper> mockUrlHelper,
            [Frozen] Mock <IMediator> mockMediator,
            SelectReservationsController controller)
        {
            viewModel.SelectedReservationId = null;
            mockMediator
            .Setup(x => x.Send(It.Is <GetAvailableReservationsQuery>(c => c.AccountId.Equals(viewModel.AccountId)),
                               It.IsAny <CancellationToken>())).ReturnsAsync(availableReservationsResult);
            mockUrlHelper
            .Setup(helper => helper.GenerateUrl(
                       It.Is <UrlParameters>(parameters =>
                                             parameters.Id == routeModel.UkPrn.ToString() &&
                                             parameters.Controller == $"apprentices/{viewModel.CohortReference}" &&
                                             parameters.Action == "details")))
            .Returns(cohortDetailsUrl);

            var result = await controller.PostSelectReservation(routeModel, viewModel) as ViewResult;

            result.ViewName.Should().Be("Select");
            var actualModel = result.Model as SelectReservationViewModel;

            actualModel.Should().NotBeNull();
            actualModel.AvailableReservations.Should().BeEquivalentTo(availableReservationsResult.Reservations.Select(c => new AvailableReservationViewModel(c)));
        }
        public async Task And_Has_Ukprn_And_ReservationId_And_Not_CohortRef_Then_Redirects_To_AddApprentice_With_Reservation_Details(
            ReservationsRouteModel routeModel,
            SelectReservationViewModel viewModel,
            GetReservationResult reservationResult,
            string addApprenticeUrl,
            [Frozen] Mock <IExternalUrlHelper> mockUrlHelper,
            [Frozen] Mock <IMediator> mockMediator,
            SelectReservationsController controller)
        {
            routeModel.CohortReference = string.Empty;
            viewModel.CohortReference  = string.Empty;
            mockMediator.Setup(x => x.Send(It.Is <GetReservationQuery>(c => c.Id.Equals(viewModel.SelectedReservationId)),
                                           It.IsAny <CancellationToken>()))
            .ReturnsAsync(reservationResult);
            mockUrlHelper
            .Setup(helper => helper.GenerateAddApprenticeUrl(viewModel.SelectedReservationId.Value,
                                                             routeModel.AccountLegalEntityPublicHashedId, reservationResult.Course.Id, routeModel.UkPrn.Value,
                                                             reservationResult.StartDate, viewModel.CohortReference, routeModel.EmployerAccountId,
                                                             true, string.Empty, viewModel.JourneyData))
            .Returns(addApprenticeUrl);

            var result = await controller.PostSelectReservation(routeModel, viewModel) as RedirectResult;

            result.Url.Should().Be(addApprenticeUrl);
        }
        public async Task And_Provider_Has_No_Create_Permission_Then_NoPermissions_View_Is_Shown_With_The_Back_Link_Going_To_Cohort_Details(
            ReservationsRouteModel routeModel,
            SelectReservationViewModel viewModel,
            GetTrustedEmployersResponse employersResponse,
            string cohortDetailsUrl,
            [Frozen] Mock <IExternalUrlHelper> mockUrlHelper,
            [Frozen] Mock <IMediator> mockMediator,
            SelectReservationsController controller)
        {
            var matchedEmployer = employersResponse.Employers.First();

            routeModel.AccountLegalEntityPublicHashedId = matchedEmployer.AccountLegalEntityPublicHashedId;
            viewModel.SelectedReservationId             = Guid.Parse(Guid.Empty.ToString().Replace("0", "9"));
            routeModel.Id = Guid.Empty;
            mockMediator
            .Setup(mediator => mediator.Send(
                       It.IsAny <GetTrustedEmployersQuery>(),
                       It.IsAny <CancellationToken>()))
            .ReturnsAsync(employersResponse);
            mockMediator.Setup(x => x.Send(It.IsAny <CacheReservationEmployerCommand>(), It.IsAny <CancellationToken>()))
            .ThrowsAsync(new ProviderNotAuthorisedException(viewModel.AccountId, routeModel.UkPrn.Value));
            mockUrlHelper
            .Setup(helper => helper.GenerateCohortDetailsUrl(routeModel.UkPrn, routeModel.EmployerAccountId,
                                                             routeModel.CohortReference, false, It.IsAny <string>()))
            .Returns(cohortDetailsUrl);

            //Act
            var result = await controller.PostSelectReservation(routeModel, viewModel) as ViewResult;

            //Assert
            result.ViewName.Should().Be("NoPermissions");
            result.Model.Should().Be(cohortDetailsUrl);
        }
        public async Task And_GlobalRule_Is_In_Place_Then_The_Funding_Paused_View_Is_Shown_For_Employer(
            ReservationsRouteModel routeModel,
            SelectReservationViewModel viewModel,
            GetLegalEntitiesResponse employersResponse,
            string cohortDetailsUrl,
            long expectedAccountId,
            [Frozen] Mock <IExternalUrlHelper> mockUrlHelper,
            [Frozen] Mock <IMediator> mockMediator,
            [Frozen] Mock <IEncodingService> encodingService,
            SelectReservationsController controller)
        {
            routeModel.UkPrn = null;
            viewModel.SelectedReservationId = Guid.Parse(Guid.Empty.ToString().Replace("0", "9"));
            routeModel.Id = Guid.Empty;
            encodingService.Setup(x => x.Decode(routeModel.EmployerAccountId, EncodingType.AccountId)).Returns(expectedAccountId);
            var matchedEmployer = employersResponse.AccountLegalEntities.First();

            routeModel.AccountLegalEntityPublicHashedId = matchedEmployer.AccountLegalEntityPublicHashedId;
            mockMediator
            .Setup(mediator => mediator.Send(
                       It.Is <GetLegalEntitiesQuery>(c => c.AccountId.Equals(expectedAccountId)),
                       It.IsAny <CancellationToken>()))
            .ReturnsAsync(employersResponse);
            mockMediator.Setup(x => x.Send(It.IsAny <CacheReservationEmployerCommand>(), It.IsAny <CancellationToken>()))
            .ThrowsAsync(new GlobalReservationRuleException(viewModel.AccountId));

            //Act
            var result = await controller.PostSelectReservation(routeModel, viewModel) as ViewResult;

            //Assert
            result.ViewName.Should().Be("EmployerFundingPaused");
        }
        public async Task And_Has_UkPrn_And_New_Reservation_Then_Redirects_To_ProviderApprenticeshipTraining_And_The_Cached_Reservation_Is_Created(
            ReservationsRouteModel routeModel,
            SelectReservationViewModel viewModel,
            GetTrustedEmployersResponse employersResponse,
            [Frozen] Mock <IMediator> mockMediator,
            SelectReservationsController controller)
        {
            var matchedEmployer = employersResponse.Employers.First();

            routeModel.AccountLegalEntityPublicHashedId = matchedEmployer.AccountLegalEntityPublicHashedId;
            viewModel.SelectedReservationId             = Guid.Parse(Guid.Empty.ToString().Replace("0", "9"));
            routeModel.Id = Guid.Empty;

            mockMediator.Setup(m =>
                               m.Send(It.IsAny <GetProviderCacheReservationCommandQuery>(), It.IsAny <CancellationToken>()))
            .ReturnsAsync(new GetProviderCacheReservationCommandResponse
            {
                Command = new CacheReservationEmployerCommand
                {
                    Id        = Guid.NewGuid(),
                    AccountId = matchedEmployer.AccountId,
                    AccountLegalEntityPublicHashedId = matchedEmployer.AccountLegalEntityPublicHashedId,
                    AccountLegalEntityId             = matchedEmployer.AccountLegalEntityId,
                    AccountLegalEntityName           = matchedEmployer.AccountLegalEntityName,
                    AccountName = matchedEmployer.AccountName,
                    CohortRef   = viewModel.CohortReference,
                    UkPrn       = routeModel.UkPrn.Value
                }
            });


            var result = await controller.PostSelectReservation(routeModel, viewModel) as RedirectToRouteResult;

            result?.RouteName.Should().NotBeNull();
            result.RouteName.Should().Be(RouteNames.ProviderApprenticeshipTrainingRuleCheck);
            result.RouteValues["ukPrn"].Should().Be(routeModel.UkPrn);
            result.RouteValues["id"].Should().NotBe(Guid.Empty);
            mockMediator.Verify(x =>
                                x.Send(It.Is <CacheReservationEmployerCommand>(
                                           c =>
                                           c.CohortRef.Equals(viewModel.CohortReference) &&
                                           c.AccountId.Equals(matchedEmployer.AccountId) &&
                                           c.AccountLegalEntityName.Equals(matchedEmployer.AccountLegalEntityName) &&
                                           c.AccountLegalEntityPublicHashedId.Equals(matchedEmployer.AccountLegalEntityPublicHashedId) &&
                                           c.AccountName.Equals(matchedEmployer.AccountName) &&
                                           c.UkPrn.Equals(routeModel.UkPrn) &&
                                           !c.Id.Equals(Guid.Empty) &&
                                           c.AccountLegalEntityId.Equals(matchedEmployer.AccountLegalEntityId))
                                       , It.IsAny <CancellationToken>()), Times.Once);
        }
        public void WhenIViewTheSelectReservationScreen()
        {
            var controller = Services.GetService <SelectReservationsController>();
            var claim      = new Claim(EmployerClaims.IdamsUserIdClaimTypeIdentifier, TestData.UserId.ToString());
            var apiClient  = Services.GetService <IApiClient>();
            var mock       = Mock.Get(apiClient);

            controller.HttpContext.User = new ClaimsPrincipal(new ClaimsIdentity(new[] { claim }));
            mock.Setup(x => x.GetAll <GetReservationResponse>(
                           It.IsAny <ReservationApiRequest>())).ReturnsAsync(TestData.Reservations);

            _actionResult = controller.SelectReservation(TestData.ReservationRouteModel, _viewModel).Result;

            var actual = _actionResult as ViewResult;

            _actualModel = actual?.Model as SelectReservationViewModel;
        }
        public async Task And_Is_An_Employer_And_New_Reservation_Then_Redirects_To_EmployerApprenticeshipTraining_And_The_Cached_Reservation_Is_Created(
            ReservationsRouteModel routeModel,
            SelectReservationViewModel viewModel,
            long expectedAccountId,
            GetLegalEntitiesResponse employersResponse,
            [Frozen] Mock <IMediator> mockMediator,
            [Frozen] Mock <IEncodingService> encodingService,
            SelectReservationsController controller)
        {
            viewModel.SelectedReservationId = Guid.Parse(Guid.Empty.ToString().Replace("0", "9"));
            routeModel.Id    = Guid.Empty;
            routeModel.UkPrn = null;

            encodingService.Setup(x => x.Decode(routeModel.EmployerAccountId, EncodingType.AccountId)).Returns(expectedAccountId);
            var matchedEmployer = employersResponse.AccountLegalEntities.First();

            routeModel.AccountLegalEntityPublicHashedId = matchedEmployer.AccountLegalEntityPublicHashedId;
            mockMediator
            .Setup(mediator => mediator.Send(
                       It.Is <GetLegalEntitiesQuery>(c => c.AccountId.Equals(expectedAccountId)),
                       It.IsAny <CancellationToken>()))
            .ReturnsAsync(employersResponse);

            var result = await controller.PostSelectReservation(routeModel, viewModel) as RedirectToRouteResult;

            result?.RouteName.Should().NotBeNull();
            result.RouteName.Should().Be(RouteNames.EmployerSelectCourseRuleCheck);
            result.RouteValues["EmployerAccountId"].Should().Be(routeModel.EmployerAccountId);
            result.RouteValues["id"].Should().NotBe(Guid.Empty);
            mockMediator.Verify(x =>
                                x.Send(It.Is <CacheReservationEmployerCommand>(
                                           c =>
                                           c.CohortRef.Equals(viewModel.CohortReference) &&
                                           c.AccountId.Equals(expectedAccountId) &&
                                           c.AccountLegalEntityName.Equals(matchedEmployer.AccountLegalEntityName) &&
                                           c.AccountLegalEntityPublicHashedId.Equals(matchedEmployer.AccountLegalEntityPublicHashedId) &&
                                           !c.Id.Equals(Guid.Empty) &&
                                           c.AccountLegalEntityId.Equals(matchedEmployer.AccountLegalEntityId))
                                       , It.IsAny <CancellationToken>()), Times.Once);
        }
        public async Task <IActionResult> SelectReservation(
            ReservationsRouteModel routeModel,
            SelectReservationViewModel viewModel)
        {
            var backUrl = _urlHelper.GenerateCohortDetailsUrl(routeModel.UkPrn, routeModel.EmployerAccountId,
                                                              viewModel.CohortReference, journeyData: viewModel.JourneyData);

            try
            {
                var apprenticeshipTrainingRouteName = RouteNames.EmployerSelectCourseRuleCheck;
                CacheReservationEmployerCommand cacheReservationEmployerCommand;
                Guid?userId = null;
                if (routeModel.UkPrn.HasValue)
                {
                    var response = await _mediator.Send(new GetProviderCacheReservationCommandQuery
                    {
                        AccountLegalEntityPublicHashedId = routeModel.AccountLegalEntityPublicHashedId,
                        CohortRef = routeModel.CohortReference,
                        CohortId  = _encodingService.Decode(routeModel.CohortReference, EncodingType.CohortReference),
                        UkPrn     = routeModel.UkPrn.Value
                    });

                    cacheReservationEmployerCommand = response.Command;

                    apprenticeshipTrainingRouteName = RouteNames.ProviderApprenticeshipTrainingRuleCheck;
                }
                else
                {
                    var userAccountIdClaim = HttpContext.User.Claims.First(c =>
                                                                           c.Type.Equals(EmployerClaims.IdamsUserIdClaimTypeIdentifier));
                    userId = Guid.Parse(userAccountIdClaim.Value);

                    cacheReservationEmployerCommand = await BuildEmployerReservationCacheCommand(
                        routeModel.EmployerAccountId, routeModel.AccountLegalEntityPublicHashedId,
                        viewModel.CohortReference, viewModel.ProviderId, viewModel.JourneyData);
                }

                var redirectResult = await CheckCanAutoReserve(cacheReservationEmployerCommand.AccountId,
                                                               viewModel.TransferSenderId, viewModel.JourneyData,
                                                               cacheReservationEmployerCommand.AccountLegalEntityPublicHashedId,
                                                               routeModel.UkPrn ?? viewModel.ProviderId, viewModel.CohortReference,
                                                               routeModel.EmployerAccountId, userId);

                if (!string.IsNullOrEmpty(redirectResult))
                {
                    if (redirectResult == RouteNames.Error500)
                    {
                        return(RedirectToRoute(redirectResult));
                    }

                    return(Redirect(redirectResult));
                }

                var availableReservationsResult = await _mediator.Send(
                    new GetAvailableReservationsQuery { AccountId = cacheReservationEmployerCommand.AccountId });

                if (availableReservationsResult.Reservations != null &&
                    availableReservationsResult.Reservations.Any())
                {
                    viewModel.AvailableReservations = availableReservationsResult.Reservations
                                                      .Select(reservation => new AvailableReservationViewModel(reservation));
                    viewModel.AccountId = cacheReservationEmployerCommand.AccountId;
                    viewModel.BackLink  = backUrl;
                    return(View(ViewNames.Select, viewModel));
                }

                await _mediator.Send(cacheReservationEmployerCommand);

                routeModel.Id = cacheReservationEmployerCommand.Id;

                return(RedirectToRoute(apprenticeshipTrainingRouteName, routeModel));
            }
            catch (ValidationException e)
            {
                _logger.LogWarning(e, "Validation error trying to render select reservation.");
                return(RedirectToRoute(RouteNames.Error500));
            }
            catch (ProviderNotAuthorisedException e)
            {
                _logger.LogWarning(e,
                                   $"Provider (UKPRN: {e.UkPrn}) does not has access to create a reservation for legal entity for account (Id: {e.AccountId}).");
                return(View("NoPermissions", backUrl));
            }
            catch (ReservationLimitReachedException)
            {
                return(View("ReservationLimitReached", backUrl));
            }
            catch (GlobalReservationRuleException)
            {
                if (routeModel.UkPrn.HasValue)
                {
                    return(View("ProviderFundingPaused", backUrl));
                }

                return(View("EmployerFundingPaused", backUrl));
            }
            catch (AccountLegalEntityNotFoundException e)
            {
                _logger.LogWarning($"Account legal entity not found [{e.AccountLegalEntityPublicHashedId}].");
                return(RedirectToRoute(RouteNames.Error404));
            }
            catch (AccountLegalEntityInvalidException ex)
            {
                _logger.LogWarning(ex.Message);
                return(RedirectToRoute(RouteNames.Error500));
            }
            catch (TransferSenderNotAllowedException e)
            {
                _logger.LogWarning(e,
                                   $"AccountId: {e.AccountId} does not have sender id {e.TransferSenderId} allowed).");
                return(RedirectToRoute(RouteNames.Error500));
            }
            catch (EmployerAgreementNotSignedException e)
            {
                _logger.LogWarning(e, $"AccountId: {e.AccountId} does not have a signed agreement for ALE {e.AccountLegalEntityId}).");

                var routeName = RouteNames.EmployerTransactorSignAgreement;
                if (routeModel.UkPrn.HasValue)
                {
                    routeName = RouteNames.ProviderEmployerAgreementNotSigned;
                }
                else
                {
                    if (_userClaimsService.UserIsInRole(routeModel.EmployerAccountId,
                                                        EmployerUserRole.Owner, User.Claims))
                    {
                        routeName = RouteNames.EmployerOwnerSignAgreement;
                    }
                }

                routeModel.IsFromSelect = true;
                routeModel.PreviousPage = backUrl;

                return(RedirectToRoute(routeName, routeModel));
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Error trying to render select reservation.");
                return(RedirectToRoute(RouteNames.Error500));
            }
        }
        public async Task <IActionResult> PostSelectReservation(
            ReservationsRouteModel routeModel,
            SelectReservationViewModel viewModel)
        {
            var backUrl = _urlHelper.GenerateCohortDetailsUrl(routeModel.UkPrn, routeModel.EmployerAccountId,
                                                              routeModel.CohortReference, journeyData: viewModel.JourneyData);

            if (!viewModel.SelectedReservationId.HasValue || viewModel.SelectedReservationId == Guid.Empty)
            {
                var availableReservationsResult = await _mediator.Send(
                    new GetAvailableReservationsQuery { AccountId = viewModel.AccountId });

                viewModel.AvailableReservations = availableReservationsResult.Reservations
                                                  .Select(reservation => new AvailableReservationViewModel(reservation));

                ModelState.AddModelError(nameof(viewModel.SelectedReservationId), "Select an option");

                viewModel.BackLink = backUrl;

                return(View(ViewNames.Select, viewModel));
            }

            if (viewModel.SelectedReservationId != Guid.Empty &&
                viewModel.SelectedReservationId != Guid.Parse(Guid.Empty.ToString().Replace("0", "9")))
            {
                var reservation = await _mediator.Send(new GetReservationQuery { Id = viewModel.SelectedReservationId.Value });

                var url = _urlHelper.GenerateAddApprenticeUrl(viewModel.SelectedReservationId.Value,
                                                              routeModel.AccountLegalEntityPublicHashedId, reservation.Course.Id, routeModel.UkPrn ?? viewModel.ProviderId, reservation.StartDate,
                                                              viewModel.CohortReference, routeModel.EmployerAccountId, string.IsNullOrEmpty(viewModel.CohortReference), journeyData: viewModel.JourneyData);

                var addApprenticeUrl = url;

                return(Redirect(addApprenticeUrl));
            }

            try
            {
                CacheReservationEmployerCommand cacheReservationEmployerCommand;

                if (routeModel.UkPrn.HasValue)
                {
                    var response = await _mediator.Send(new GetProviderCacheReservationCommandQuery
                    {
                        AccountLegalEntityPublicHashedId = routeModel.AccountLegalEntityPublicHashedId,
                        CohortRef = routeModel.CohortReference,
                        CohortId  = _encodingService.Decode(routeModel.CohortReference, EncodingType.CohortReference),
                        UkPrn     = routeModel.UkPrn.Value
                    });

                    cacheReservationEmployerCommand = response.Command;
                }
                else
                {
                    cacheReservationEmployerCommand = await BuildEmployerReservationCacheCommand(
                        routeModel.EmployerAccountId, routeModel.AccountLegalEntityPublicHashedId,
                        viewModel.CohortReference, viewModel.ProviderId, viewModel.JourneyData);
                }

                await _mediator.Send(cacheReservationEmployerCommand);

                routeModel.Id = cacheReservationEmployerCommand.Id;
            }
            catch (ReservationLimitReachedException)
            {
                return(View("ReservationLimitReached", backUrl));
            }
            catch (ProviderNotAuthorisedException e)
            {
                _logger.LogWarning(e, $"Provider (UKPRN: {e.UkPrn}) does not has access to create a reservation for legal entity for account (Id: {e.AccountId}).");
                return(View("NoPermissions", backUrl));
            }
            catch (GlobalReservationRuleException)
            {
                if (routeModel.UkPrn.HasValue)
                {
                    return(View("ProviderFundingPaused", backUrl));
                }
                return(View("EmployerFundingPaused", backUrl));
            }
            var routeName = RouteNames.ProviderApprenticeshipTrainingRuleCheck;

            if (!routeModel.UkPrn.HasValue)
            {
                routeName = RouteNames.EmployerSelectCourseRuleCheck;
            }

            return(RedirectToRoute(routeName, routeModel));
        }
 public EmployerSelectReservationSteps(TestServiceProvider serviceProvider, TestData testData) : base(serviceProvider, testData)
 {
     _viewModel = new SelectReservationViewModel();
 }