public void UpdateDraftApprenticeship(DraftApprenticeshipDetails draftApprenticeshipDetails, Party modifyingParty, UserInfo userInfo)
        {
            CheckIsWithParty(modifyingParty);

            var existingDraftApprenticeship = GetDraftApprenticeship(draftApprenticeshipDetails.Id);

            ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, ChangeOfPartyRequestId.HasValue);

            if (ChangeOfPartyRequestId.HasValue)
            {
                existingDraftApprenticeship.ValidateUpdateForChangeOfParty(draftApprenticeshipDetails);
            }

            StartTrackingSession(UserAction.UpdateDraftApprenticeship, modifyingParty, EmployerAccountId, ProviderId, userInfo);
            ChangeTrackingSession.TrackUpdate(this);
            ChangeTrackingSession.TrackUpdate(existingDraftApprenticeship);

            if (existingDraftApprenticeship.IsOtherPartyApprovalRequiredForUpdate(draftApprenticeshipDetails))
            {
                Approvals = Party.None;
            }
            existingDraftApprenticeship.Merge(draftApprenticeshipDetails, modifyingParty);

            UpdatedBy(modifyingParty, userInfo);
            LastUpdatedOn = DateTime.UtcNow;
            Publish(() => new DraftApprenticeshipUpdatedEvent(existingDraftApprenticeship.Id, Id, existingDraftApprenticeship.Uln, existingDraftApprenticeship.ReservationId, DateTime.UtcNow));
            ChangeTrackingSession.CompleteTrackingSession();
        }
 private void CheckDraftApprenticeshipDetails(DraftApprenticeshipDetails draftApprenticeshipDetails)
 {
     if (draftApprenticeshipDetails == null)
     {
         throw new DomainException(nameof(draftApprenticeshipDetails), "DraftApprenticeshipDetails must be supplied");
     }
 }
        public void Merge(DraftApprenticeshipDetails source, Party modifyingParty)
        {
            FirstName = source.FirstName;
            LastName  = source.LastName;
            if (modifyingParty == Party.Provider)
            {
                Uln = source.Uln;
            }
            else if (Uln != source.Uln)
            {
                throw new DomainException(nameof(Uln), "Only providers are allowed to update the Uln");
            }
            ProgrammeType = source.TrainingProgramme?.ProgrammeType;
            CourseCode    = source.TrainingProgramme?.CourseCode;
            CourseName    = source.TrainingProgramme?.Name;
            Cost          = source.Cost;
            StartDate     = source.StartDate;
            EndDate       = source.EndDate;
            DateOfBirth   = source.DateOfBirth;

            switch (modifyingParty)
            {
            case Party.Employer:
                EmployerRef = source.Reference;
                break;

            case Party.Provider:
                ProviderRef = source.Reference;
                break;
            }
        }
 private IEnumerable <DomainError> BuildLastNameValidationFailures(DraftApprenticeshipDetails draftApprenticeshipDetails)
 {
     if (string.IsNullOrWhiteSpace(draftApprenticeshipDetails.LastName))
     {
         yield return(new DomainError(nameof(draftApprenticeshipDetails.LastName), "Last name must be entered"));
     }
 }
 private async Task ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails draftApprenticeshipDetails, CancellationToken cancellationToken)
 {
     ValidateStartDate(draftApprenticeshipDetails);
     ValidateUln(draftApprenticeshipDetails);
     await ValidateOverlaps(draftApprenticeshipDetails, cancellationToken);
     await ValidateReservation(draftApprenticeshipDetails, cancellationToken);
 }
Пример #6
0
        public GetDraftApprenticeHandlerTestFixtures SetApprentice(Party creatingParty, string reference)
        {
            // This line is required.
            // ReSharper disable once ObjectCreationAsStatement
            new UnitOfWorkContext();

            var autoFixture = new Fixture();

            var draftApprenticeshipDetails = new DraftApprenticeshipDetails
            {
                Reference = reference,
                Id        = ApprenticeshipId,
                FirstName = "AFirstName",
                LastName  = "ALastName"
            };

            var commitment = new Cohort(
                autoFixture.Create <long>(),
                autoFixture.Create <long>(),
                autoFixture.Create <long>(),
                null,
                draftApprenticeshipDetails,
                creatingParty,
                new UserInfo());

            Db.Cohorts.Add(commitment);

            Db.SaveChanges();

            ApprenticeshipId = commitment.Apprenticeships.First().Id;
            CohortId         = commitment.Id;

            return(this);
        }
        /// <summary>
        /// Creates a cohort with a draft apprenticeship
        /// </summary>
        internal Cohort(long providerId,
                        long accountId,
                        long accountLegalEntityId,
                        long?transferSenderId,
                        DraftApprenticeshipDetails draftApprenticeshipDetails,
                        Party originatingParty,
                        UserInfo userInfo) : this(providerId, accountId, accountLegalEntityId, transferSenderId, originatingParty, userInfo)
        {
            CheckDraftApprenticeshipDetails(draftApprenticeshipDetails);
            ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, false);
            WithParty  = originatingParty;
            EditStatus = originatingParty.ToEditStatus();
            IsDraft    = true;

            var draftApprenticeship = new DraftApprenticeship(draftApprenticeshipDetails, originatingParty);

            Apprenticeships.Add(draftApprenticeship);

            Publish(() => new DraftApprenticeshipCreatedEvent(draftApprenticeship.Id, Id, draftApprenticeship.Uln, draftApprenticeship.ReservationId, draftApprenticeship.CreatedOn.Value));

            StartTrackingSession(UserAction.CreateCohort, originatingParty, accountId, providerId, userInfo);
            ChangeTrackingSession.TrackInsert(this);
            ChangeTrackingSession.TrackInsert(draftApprenticeship);
            ChangeTrackingSession.CompleteTrackingSession();
        }
Пример #8
0
 public virtual Cohort CreateCohort(long providerId,
                                    AccountLegalEntity accountLegalEntity,
                                    Account transferSender,
                                    DraftApprenticeshipDetails draftApprenticeshipDetails,
                                    UserInfo userInfo)
 {
     return(new Cohort(providerId, accountLegalEntity.AccountId, accountLegalEntity.Id, transferSender?.Id, draftApprenticeshipDetails, Party.Provider, userInfo));
 }
        private async Task ValidateOverlaps(DraftApprenticeshipDetails details, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(details.Uln) || !details.StartDate.HasValue || !details.EndDate.HasValue)
            {
                return;
            }

            var overlapResult = await _overlapCheckService.CheckForOverlaps(details.Uln, details.StartDate.Value.To(details.EndDate.Value), default, cancellationToken);
        public AddDraftApprenticeshipValidationTestsFixture WithApprenticeship(long id, string uln)
        {
            var draftApprenticeshipDetails = new DraftApprenticeshipDetails().Set(d => d.Uln, uln);
            var draftApprenticeship        = new DraftApprenticeship(draftApprenticeshipDetails, Party.Provider).Set(d => d.Id, id);

            Cohort.Apprenticeships.Add(draftApprenticeship);

            return(this);
        }
Пример #11
0
 private void TryUpdate(DraftApprenticeshipDetails details, Party modifyingParty, UserInfo userInfo)
 {
     try
     {
         Cohort.UpdateDraftApprenticeship(details, modifyingParty, userInfo);
     }
     catch (Exception ex)
     {
         Exception = ex;
     }
 }
        public CohortCreationTestFixture WithDraftApprenticeship()
        {
            DraftApprenticeshipDetails = new DraftApprenticeshipDetails
            {
                FirstName     = _autoFixture.Create <string>(),
                LastName      = _autoFixture.Create <string>(),
                ReservationId = Guid.NewGuid()
            };

            return(this);
        }
        private IEnumerable <DomainError> BuildTrainingProgramValidationFailures(DraftApprenticeshipDetails details)
        {
            if (details.TrainingProgramme == null)
            {
                yield break;
            }

            if (details.TrainingProgramme?.ProgrammeType == ProgrammeType.Framework && TransferSenderId.HasValue)
            {
                yield return(new DomainError(nameof(details.TrainingProgramme.CourseCode), "Entered course is not valid."));
            }
        }
        private IEnumerable <DomainError> BuildUlnValidationFailures(DraftApprenticeshipDetails draftApprenticeshipDetails)
        {
            if (string.IsNullOrWhiteSpace(draftApprenticeshipDetails.Uln))
            {
                yield break;
            }

            if (Apprenticeships.Any(a => a.Id != draftApprenticeshipDetails.Id && a.Uln == draftApprenticeshipDetails.Uln))
            {
                yield return(new DomainError(nameof(draftApprenticeshipDetails.Uln), "The unique learner number has already been used for an apprentice in this cohort"));
            }
        }
        private void ValidateStartDate(DraftApprenticeshipDetails details)
        {
            if (!details.StartDate.HasValue)
            {
                return;
            }

            if (details.StartDate.Value > _academicYearDateProvider.CurrentAcademicYearEndDate.AddYears(1))
            {
                throw new DomainException(nameof(details.StartDate),
                                          "The start date must be no later than one year after the end of the current teaching year");
            }
        }
        private IEnumerable <DomainError> BuildEndDateValidationFailures(DraftApprenticeshipDetails draftApprenticeshipDetails)
        {
            if (draftApprenticeshipDetails.EndDate.HasValue && draftApprenticeshipDetails.EndDate < Constants.DasStartDate)
            {
                yield return(new DomainError(nameof(draftApprenticeshipDetails.EndDate), "The end date must not be earlier than May 2017"));

                yield break;
            }

            if (draftApprenticeshipDetails.EndDate.HasValue && draftApprenticeshipDetails.StartDate.HasValue && draftApprenticeshipDetails.EndDate <= draftApprenticeshipDetails.StartDate)
            {
                yield return(new DomainError(nameof(draftApprenticeshipDetails.EndDate), "The end date must not be on or before the start date"));
            }
        }
        private IEnumerable <DomainError> BuildCostValidationFailures(DraftApprenticeshipDetails draftApprenticeshipDetails)
        {
            if (draftApprenticeshipDetails.Cost.HasValue && draftApprenticeshipDetails.Cost <= 0)
            {
                yield return(new DomainError(nameof(draftApprenticeshipDetails.Cost), "Enter the total agreed training cost"));

                yield break;
            }

            if (draftApprenticeshipDetails.Cost.HasValue && draftApprenticeshipDetails.Cost > Constants.MaximumApprenticeshipCost)
            {
                yield return(new DomainError(nameof(draftApprenticeshipDetails.Cost), "The total cost must be £100,000 or less"));
            }
        }
Пример #18
0
        public UpdateDraftApprenticeshipValidationTestsFixture WithApprenticeship(long id, string uln)
        {
            var draftApprenticeshipDetails = new DraftApprenticeshipDetails().Set(d => d.Uln, uln);

            draftApprenticeshipDetails.Set(x => x.FirstName, "TEST");
            draftApprenticeshipDetails.Set(x => x.LastName, "TEST");
            draftApprenticeshipDetails.Set(x => x.TrainingProgramme,
                                           new SFA.DAS.CommitmentsV2.Domain.Entities.TrainingProgramme("TEST", "TEST", ProgrammeType.Framework, DateTime.MinValue, DateTime.MaxValue));
            var draftApprenticeship = new DraftApprenticeship(draftApprenticeshipDetails, Party.Provider).Set(d => d.Id, id);

            Cohort.Apprenticeships.Add(draftApprenticeship);

            return(this);
        }
        private async Task ValidateReservation(DraftApprenticeshipDetails details, CancellationToken cancellationToken)
        {
            if (!details.ReservationId.HasValue || !details.StartDate.HasValue || details.TrainingProgramme == null)
            {
                return;
            }

            var validationRequest = new ReservationValidationRequest(details.ReservationId.Value, details.StartDate.Value, details.TrainingProgramme.CourseCode);

            var validationResult = await _reservationValidationService.Validate(validationRequest, cancellationToken);

            var errors = validationResult.ValidationErrors.Select(error => new DomainError(error.PropertyName, error.Reason)).ToList();

            errors.ThrowIfAny();
        }
        private DraftApprenticeshipDetails SetApprenticeDetails(int nullProperty)
        {
            var apprenticeDetails = new DraftApprenticeshipDetails
            {
                Id                = 1,
                FirstName         = "FirstName",
                LastName          = "LastName",
                TrainingProgramme = new SFA.DAS.CommitmentsV2.Domain.Entities.TrainingProgramme("code", "name", ProgrammeType.Framework, DateTime.Now, DateTime.Now),
                Cost              = 1500,
                StartDate         = new DateTime(2019, 10, 1),
                EndDate           = DateTime.Now,
                DateOfBirth       = new DateTime(2000, 1, 1),
                Reference         = "",
                ReservationId     = new Guid()
            };

            switch (nullProperty)
            {
            case 1:
                apprenticeDetails.FirstName = null;
                break;

            case 2:
                apprenticeDetails.LastName = null;
                break;

            case 3:
                apprenticeDetails.TrainingProgramme = null;
                break;

            case 4:
                apprenticeDetails.Cost = null;
                break;

            case 5:
                apprenticeDetails.StartDate = null;
                break;

            case 6:
                apprenticeDetails.EndDate = null;
                break;

            case 7:
                apprenticeDetails.DateOfBirth = null;
                break;
            }
            return(apprenticeDetails);
        }
        private void ValidateUln(DraftApprenticeshipDetails draftApprenticeshipDetails)
        {
            if (string.IsNullOrWhiteSpace(draftApprenticeshipDetails.Uln))
            {
                return;
            }

            switch (_ulnValidator.Validate(draftApprenticeshipDetails.Uln))
            {
            case UlnValidationResult.IsInValidTenDigitUlnNumber:
                throw new DomainException(nameof(draftApprenticeshipDetails.Uln), "You must enter a 10-digit unique learner number");

            case UlnValidationResult.IsInvalidUln:
                throw new DomainException(nameof(draftApprenticeshipDetails.Uln), "You must enter a valid unique learner number");
            }
        }
        private void ValidateDraftApprenticeshipDetails(DraftApprenticeshipDetails draftApprenticeshipDetails, bool isContinuation)
        {
            var errors = new List <DomainError>();

            errors.AddRange(BuildEndDateValidationFailures(draftApprenticeshipDetails));
            errors.AddRange(BuildCostValidationFailures(draftApprenticeshipDetails));
            if (!isContinuation)
            {
                errors.AddRange(BuildFirstNameValidationFailures(draftApprenticeshipDetails));
                errors.AddRange(BuildLastNameValidationFailures(draftApprenticeshipDetails));
                errors.AddRange(BuildStartDateValidationFailures(draftApprenticeshipDetails));
                errors.AddRange(BuildDateOfBirthValidationFailures(draftApprenticeshipDetails));
                errors.AddRange(BuildUlnValidationFailures(draftApprenticeshipDetails));
                errors.AddRange(BuildTrainingProgramValidationFailures(draftApprenticeshipDetails));
            }
            errors.ThrowIfAny();
        }
Пример #23
0
        public UpdateDraftApprenticeshipValidationTestsFixture()
        {
            var autoFixture = new Fixture();

            UnitOfWorkContext          = new UnitOfWorkContext();
            DraftApprenticeshipDetails = new DraftApprenticeshipDetails
            {
                TrainingProgramme = new SFA.DAS.CommitmentsV2.Domain.Entities.TrainingProgramme("TEST", "TEST", ProgrammeType.Framework, DateTime.MinValue, DateTime.MaxValue)
            };
            SetupMinimumNameProperties();
            Cohort = new CommitmentsV2.Models.Cohort {
                EditStatus = EditStatus.ProviderOnly, ProviderId = 1
            };
            CurrentDateTime          = new CurrentDateTime(new DateTime(2019, 04, 01, 0, 0, 0, DateTimeKind.Utc));
            AcademicYearDateProvider = new AcademicYearDateProvider(CurrentDateTime);
            UserInfo = autoFixture.Create <UserInfo>();
        }
        public async Task <Cohort> UpdateDraftApprenticeship(long cohortId, DraftApprenticeshipDetails draftApprenticeshipDetails, UserInfo userInfo, CancellationToken cancellationToken)
        {
            var cohort = await _dbContext.Value.GetCohortAggregate(cohortId, cancellationToken : cancellationToken);

            AssertHasProvider(cohortId, cohort.ProviderId);
            AssertHasApprenticeshipId(cohortId, draftApprenticeshipDetails.Id);

            cohort.UpdateDraftApprenticeship(draftApprenticeshipDetails, _authenticationService.GetUserParty(), userInfo);

            if (cohort.IsLinkedToChangeOfPartyRequest)
            {
                await ValidateStartDateForContinuation(cohort, draftApprenticeshipDetails);
            }

            await ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, cancellationToken);

            return(cohort);
        }
        public bool IsOtherPartyApprovalRequiredForUpdate(DraftApprenticeshipDetails update)
        {
            if (FirstName != update.FirstName)
            {
                return(true);
            }
            if (LastName != update.LastName)
            {
                return(true);
            }
            if (Cost != update.Cost)
            {
                return(true);
            }
            if (StartDate != update.StartDate)
            {
                return(true);
            }
            if (EndDate != update.EndDate)
            {
                return(true);
            }
            if (DateOfBirth != update.DateOfBirth)
            {
                return(true);
            }

            if (string.IsNullOrWhiteSpace(CourseCode))
            {
                if (update.TrainingProgramme != null)
                {
                    return(true);
                }
            }
            else
            {
                if (update.TrainingProgramme?.CourseCode != CourseCode)
                {
                    return(true);
                }
            }

            return(false);
        }
        private IEnumerable <DomainError> BuildStartDateValidationFailures(DraftApprenticeshipDetails details)
        {
            if (!details.StartDate.HasValue)
            {
                yield break;
            }

            var courseStartedBeforeDas = details.TrainingProgramme != null &&
                                         (!details.TrainingProgramme.EffectiveFrom.HasValue ||
                                          details.TrainingProgramme.EffectiveFrom.Value < Constants.DasStartDate);

            var trainingProgrammeStatus = details.TrainingProgramme?.GetStatusOn(details.StartDate.Value);

            if ((details.StartDate.Value < Constants.DasStartDate) && (!trainingProgrammeStatus.HasValue || courseStartedBeforeDas))
            {
                yield return(new DomainError(nameof(details.StartDate), "The start date must not be earlier than May 2017"));

                yield break;
            }

            if (trainingProgrammeStatus.HasValue && trainingProgrammeStatus.Value != TrainingProgrammeStatus.Active)
            {
                var suffix = trainingProgrammeStatus == TrainingProgrammeStatus.Pending
                    ? $"after {details.TrainingProgramme.EffectiveFrom.Value.AddMonths(-1):MM yyyy}"
                    : $"before {details.TrainingProgramme.EffectiveTo.Value.AddMonths(1):MM yyyy}";

                var errorMessage = $"This training course is only available to apprentices with a start date {suffix}";

                yield return(new DomainError(nameof(details.StartDate), errorMessage));

                yield break;
            }

            if (trainingProgrammeStatus.HasValue && TransferSenderId.HasValue &&
                details.StartDate.Value < Constants.TransferFeatureStartDate)
            {
                var errorMessage = $"Apprentices funded through a transfer can't start earlier than May 2018";

                yield return(new DomainError(nameof(details.StartDate), errorMessage));
            }
        }
        public virtual bool IsApprovedByAllParties => WithParty == Party.None; //todo: use new Approvals flag

        public DraftApprenticeship AddDraftApprenticeship(DraftApprenticeshipDetails draftApprenticeshipDetails, Party creator, UserInfo userInfo)
        {
            CheckIsWithParty(creator);
            ValidateDraftApprenticeshipDetails(draftApprenticeshipDetails, false);

            StartTrackingSession(UserAction.AddDraftApprenticeship, creator, EmployerAccountId, ProviderId, userInfo);
            ChangeTrackingSession.TrackUpdate(this);

            var draftApprenticeship = new DraftApprenticeship(draftApprenticeshipDetails, creator);

            Apprenticeships.Add(draftApprenticeship);
            Approvals = Party.None;
            UpdatedBy(creator, userInfo);
            LastUpdatedOn = DateTime.UtcNow;

            ChangeTrackingSession.TrackInsert(draftApprenticeship);
            ChangeTrackingSession.CompleteTrackingSession();

            Publish(() => new DraftApprenticeshipCreatedEvent(draftApprenticeship.Id, Id, draftApprenticeship.Uln, draftApprenticeship.ReservationId, draftApprenticeship.CreatedOn.Value));
            return(draftApprenticeship);
        }
        private IEnumerable <DomainError> BuildDateOfBirthValidationFailures(DraftApprenticeshipDetails draftApprenticeshipDetails)
        {
            if (draftApprenticeshipDetails.AgeOnStartDate.HasValue && draftApprenticeshipDetails.AgeOnStartDate.Value < Constants.MinimumAgeAtApprenticeshipStart)
            {
                yield return(new DomainError(nameof(draftApprenticeshipDetails.DateOfBirth), $"The apprentice must be at least {Constants.MinimumAgeAtApprenticeshipStart} years old at the start of their training"));

                yield break;
            }

            if (draftApprenticeshipDetails.AgeOnStartDate.HasValue && draftApprenticeshipDetails.AgeOnStartDate >= Constants.MaximumAgeAtApprenticeshipStart)
            {
                yield return(new DomainError(nameof(draftApprenticeshipDetails.DateOfBirth), $"The apprentice must be younger than {Constants.MaximumAgeAtApprenticeshipStart} years old at the start of their training"));

                yield break;
            }

            if (draftApprenticeshipDetails.DateOfBirth.HasValue && draftApprenticeshipDetails.DateOfBirth < Constants.MinimumDateOfBirth)
            {
                yield return(new DomainError(nameof(draftApprenticeshipDetails.DateOfBirth), $"The Date of birth is not valid"));
            }
        }
        public void ValidateUpdateForChangeOfParty(DraftApprenticeshipDetails update)
        {
            if (update.FirstName != FirstName)
            {
                throw new DomainException(nameof(FirstName), "FirstName for DraftApprenticeship in ChangeOfPartyCohort cannot be modified");
            }

            if (update.LastName != LastName)
            {
                throw new DomainException(nameof(LastName), "LastName for DraftApprenticeship in ChangeOfPartyCohort cannot be modified");
            }

            if (update.DateOfBirth != DateOfBirth)
            {
                throw new DomainException(nameof(LastName), "DateOfBirth for DraftApprenticeship in ChangeOfPartyCohort cannot be modified");
            }

            if (update.TrainingProgramme?.CourseCode != CourseCode)
            {
                throw new DomainException(nameof(LastName), "CourseCode for DraftApprenticeship in ChangeOfPartyCohort cannot be modified");
            }
        }
        private async Task ValidateStartDateForContinuation(Cohort cohort, DraftApprenticeshipDetails draftApprenticeshipDetails)
        {
            if (!draftApprenticeshipDetails.StartDate.HasValue)
            {
                return;
            }

            var existingDraftApprenticeship = cohort.GetDraftApprenticeship(draftApprenticeshipDetails.Id);

            if (!existingDraftApprenticeship.IsContinuation)
            {
                throw new InvalidOperationException(
                          $"Cohort {cohort.Id} is linked to Change Of Party Request {cohort.ChangeOfPartyRequestId} but DraftApprenticeship {existingDraftApprenticeship.Id} is not a Continuation");
            }

            var previousApprenticeship = await
                                         _dbContext.Value.GetApprenticeshipAggregate(existingDraftApprenticeship.ContinuationOfId.Value, default);

            if (draftApprenticeshipDetails.StartDate.Value < previousApprenticeship.StopDate)
            {
                throw new DomainException(nameof(draftApprenticeshipDetails.StartDate), "The date overlaps with existing dates for the same apprentice.");
            }
        }