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); }
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(); }
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); }
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")); } }
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(); }
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."); } }