private async Task <ImportResult> ValidateAndImportNotificationGroupAsync(PerformContext context, string requestId, List <Notification> notifications) { var patientName = notifications.First().PatientDetails.FullName; var importResult = new ImportResult(patientName); _logger.LogInformation(context, requestId, $"{notifications.Count} notifications found to import for {patientName}"); // Verify that no repeated NotificationIds have returned var ids = notifications.Select(n => n.LegacyId).ToList(); if (ids.Distinct().Count() != ids.Count) { var errorMessage = $"Duplicate records found ({String.Join(',', ids)}) - aborting import for {patientName}"; importResult.AddGroupError(errorMessage); _logger.LogImportFailure(context, requestId, errorMessage); return(importResult); } bool isAnyNotificationInvalid = false; foreach (var notification in notifications) { var linkedNotificationId = notification.LegacyId; _logger.LogInformation(context, requestId, $"Validating notification with Id={linkedNotificationId}"); var validationErrors = await _importValidator.CleanAndValidateNotification(context, requestId, notification); if (!validationErrors.Any()) { _logger.LogInformation(context, requestId, "No validation errors found"); importResult.AddValidNotification(linkedNotificationId); } else { isAnyNotificationInvalid = true; importResult.AddValidationErrorsMessages(linkedNotificationId, validationErrors); _logger.LogWarning(context, requestId, $"{validationErrors.Count} validation errors found for notification with Id={linkedNotificationId}:"); foreach (var validationError in validationErrors) { _logger.LogWarning(context, requestId, validationError.ErrorMessage); } } } if (isAnyNotificationInvalid) { _logger.LogImportFailure(context, requestId, $"Terminating importing notifications for {patientName} due to validation errors"); return(importResult); } _logger.LogSuccess(context, requestId, $"Importing {notifications.Count} valid notifications"); try { var savedNotifications = await _notificationImportRepository.AddLinkedNotificationsAsync(notifications); await _migratedNotificationsMarker.MarkNotificationsAsImportedAsync(savedNotifications); importResult.NtbsIds = savedNotifications.ToDictionary(x => x.LegacyId, x => x.NotificationId); await ImportReferenceLabResultsAsync(context, requestId, savedNotifications, importResult); var newIdsString = string.Join(" ,", savedNotifications.Select(x => x.NotificationId)); _logger.LogSuccess(context, requestId, $"Imported notifications have following Ids: {newIdsString}"); _logger.LogInformation(context, requestId, $"Finished importing notification for {patientName}"); } catch (MarkingNotificationsAsImportedFailedException e) { Log.Error(e, e.Message); _logger.LogWarning(context, requestId, message: e.Message); importResult.AddGroupError($"{e.Message}: {e.StackTrace}"); } catch (Exception e) { Log.Error(e, e.Message); _logger.LogImportFailure(context, requestId, message: $"Failed to save notification for {patientName} or mark it as imported ", e); importResult.AddGroupError($"{e.Message}: {e.StackTrace}"); } return(importResult); }
public async Task correctlyCreates_basicNotification() { // Arrange var legacyIds = new List <string> { "130331" }; SetupNotificationsInGroups(("130331", "1")); const string royalBerkshireCode = "TBS001"; const string bristolRoyalCode = "TBS002"; const string westonGeneralCode = "TBS003"; _hospitalToTbServiceCodeDict = new Dictionary <Guid, TBService> { { new Guid("B8AA918D-233F-4C41-B9AE-BE8A8DC8BE7A"), new TBService { Code = royalBerkshireCode } }, { new Guid("F026FDCD-7BAF-4C96-994C-20E436CC8C59"), new TBService { Code = bristolRoyalCode } }, { new Guid("0AC033AB-9A11-4FA6-AA1A-1FCA71180C2F"), new TBService { Code = westonGeneralCode } } }; // Act var notification = (await _notificationMapper.GetNotificationsGroupedByPatient(null, "test-request-1", legacyIds)) .SelectMany(group => group) .Single(); var validationErrors = await _importValidator.CleanAndValidateNotification(null, "test-request-1", notification); // Assert Assert.Equal("130331", notification.ETSID); Assert.Equal("130331", notification.LegacyId); Assert.Equal(new DateTime(2015, 3, 31), notification.NotificationDate?.Date); Assert.Equal(NotificationStatus.Notified, notification.NotificationStatus); Assert.Equal("RG145UT", notification.PatientDetails.Postcode); Assert.Equal(false, notification.PatientDetails.NoFixedAbode); Assert.Equal("Winford", notification.PatientDetails.GivenName); Assert.Equal("Wongus", notification.PatientDetails.FamilyName); Assert.Equal("9815779000", notification.PatientDetails.NhsNumber); Assert.Equal(new DateTime(1981, 3, 24), notification.PatientDetails.Dob); Assert.Equal(2010, notification.PatientDetails.YearOfUkEntry); Assert.Equal(new Guid("B8AA918D-233F-4C41-B9AE-BE8A8DC8BE7A"), notification.HospitalDetails.HospitalId); Assert.Equal(royalBerkshireCode, notification.HospitalDetails.TBServiceCode); Assert.Equal("Dr McGown", notification.HospitalDetails.Consultant); Assert.Equal(HIVTestStatus.HIVStatusKnown, notification.ClinicalDetails.HIVTestState); Assert.Equal("Patient did not begin course of treatment under DOT", notification.ClinicalDetails.Notes); Assert.Equal(Status.No, notification.SocialRiskFactors.RiskFactorDrugs.Status); Assert.Equal(null, notification.SocialRiskFactors.RiskFactorDrugs.IsCurrent); Assert.Equal(null, notification.SocialRiskFactors.RiskFactorDrugs.InPastFiveYears); Assert.Equal(null, notification.SocialRiskFactors.RiskFactorDrugs.MoreThanFiveYearsAgo); Assert.Equal(null, notification.SocialRiskFactors.RiskFactorHomelessness.Status); Assert.Equal(null, notification.SocialRiskFactors.RiskFactorHomelessness.IsCurrent); Assert.Equal(null, notification.SocialRiskFactors.RiskFactorHomelessness.InPastFiveYears); Assert.Equal(null, notification.SocialRiskFactors.RiskFactorHomelessness.MoreThanFiveYearsAgo); Assert.Equal(Status.Yes, notification.SocialRiskFactors.RiskFactorImprisonment.Status); Assert.Equal(false, notification.SocialRiskFactors.RiskFactorImprisonment.IsCurrent); Assert.Equal(true, notification.SocialRiskFactors.RiskFactorImprisonment.InPastFiveYears); Assert.Equal(false, notification.SocialRiskFactors.RiskFactorImprisonment.MoreThanFiveYearsAgo); Assert.Empty(validationErrors); }
public async Task ImportValidatorValidatesBaseModels() { // Arrange var notification = CreateBasicNotification(); notification.MDRDetails = new MDRDetails { RelationshipToCase = "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" }; notification.PatientDetails = new PatientDetails { FamilyName = "<>Davis<>" }; notification.ClinicalDetails = new ClinicalDetails { DiagnosisDate = new DateTime(2000, 1, 1) }; notification.TravelDetails = new TravelDetails { HasTravel = Status.Yes, TotalNumberOfCountries = 51 }; notification.ImmunosuppressionDetails = new ImmunosuppressionDetails { HasOther = true, OtherDescription = "<>££<>" }; notification.HospitalDetails = new HospitalDetails { Consultant = "<>£Fred£<>" }; notification.VisitorDetails = new VisitorDetails { HasVisitor = Status.Yes, StayLengthInMonths1 = 3 }; notification.ContactTracing = new ContactTracing { AdultsIdentified = -1 }; notification.PreviousTbHistory = new PreviousTbHistory { PreviousTbDiagnosisYear = 1899 }; notification.MBovisDetails.MBovisExposureToKnownCases = new List <MBovisExposureToKnownCase> { new MBovisExposureToKnownCase() }; notification.MBovisDetails.ExposureToKnownCasesStatus = Status.No; notification.DrugResistanceProfile = new DrugResistanceProfile { Species = "M. bovis" }; // Act var validationResults = await _importValidator.CleanAndValidateNotification(null, RunId, notification); // Assert var errorMessages = validationResults.Select(r => r.ErrorMessage).ToList(); Assert.Contains("MDR details: The field Relationship of the current case to the contact must be a string or array type with a maximum length of '90'.", errorMessages); Assert.Contains("Personal details: " + String.Format(ValidationMessages.StandardStringFormat, "Family name"), errorMessages); Assert.Contains("Clinical details: " + ValidationMessages.DateValidityRangeStart("Diagnosis date", "01/01/2010"), errorMessages); Assert.Contains("Travel details: The field total number of countries must be between 1 and 50.", errorMessages); Assert.Contains("Immunosuppression: " + String.Format(ValidationMessages.InvalidCharacter, "Immunosuppression type description"), errorMessages); Assert.Contains("Hospital details: " + String.Format(ValidationMessages.InvalidCharacter, "Consultant"), errorMessages); Assert.Contains("Visitor details: " + ValidationMessages.TravelOrVisitDurationHasCountry, errorMessages); Assert.Contains("Previous history: " + ValidationMessages.ValidYear, errorMessages); Assert.Contains("M. bovis - exposure to another case: " + String.Format(ValidationMessages.RequiredSelect, "Exposure setting"), errorMessages); }
private async Task <ImportResult> ValidateAndImportNotificationGroupAsync(PerformContext context, int runId, List <Notification> notifications) { var importResult = new ImportResult(notifications.First().PatientDetails.FullName); _logger.LogInformation(context, runId, $"{notifications.Count} notifications found to import in notification group containing legacy ID {notifications.First().LegacyId}"); // Verify that no repeated NotificationIds have returned var ids = notifications.Select(n => n.LegacyId).ToList(); if (ids.Distinct().Count() != ids.Count) { importResult.AddGroupError("Aborting group import due to duplicate records found"); await _logger.LogImportGroupFailure(context, runId, notifications, "due to duplicate records found"); return(importResult); } var hasAnyRecordAlreadyBeenImported = false; foreach (var notification in notifications) { // Check that record hasn't already been imported var foundLtbr = notification.LTBRID is null ? false : await _notificationRepository.NotificationWithLegacyIdExistsAsync(notification.LTBRID); var foundEts = notification.ETSID is null ? false : await _notificationRepository.NotificationWithLegacyIdExistsAsync(notification.ETSID); if (foundEts || foundLtbr) { hasAnyRecordAlreadyBeenImported = true; var errorId = foundLtbr ? $"LTBRId = {notification.LTBRID}" : $"ETSId = {notification.ETSID}"; var errorMessage = $"A notification has already been imported with {errorId}. " + "Please contact your system administrator to fix this issue."; importResult.AddNotificationError(notification.LegacyId, errorMessage); } } if (hasAnyRecordAlreadyBeenImported) { await _logger.LogImportGroupFailure(context, runId, notifications, "due to notification having already been imported"); return(importResult); } var isAnyNotificationInvalid = false; foreach (var notification in notifications) { var linkedNotificationId = notification.LegacyId; _logger.LogInformation(context, runId, $"Validating notification with Id={linkedNotificationId}"); var validationErrors = await _importValidator.CleanAndValidateNotification(context, runId, notification); if (!validationErrors.Any()) { _logger.LogInformation(context, runId, "No validation errors found"); importResult.AddValidNotification(linkedNotificationId); } else { isAnyNotificationInvalid = true; importResult.AddValidationErrorsMessages(linkedNotificationId, validationErrors); await _logger.LogNotificationWarning(context, runId, linkedNotificationId, $"has {validationErrors.Count} validation errors"); foreach (var validationError in validationErrors) { await _logger.LogNotificationWarning(context, runId, linkedNotificationId, validationError.ErrorMessage); } } } if (isAnyNotificationInvalid) { await _logger.LogImportGroupFailure(context, runId, notifications, "due to validation errors"); return(importResult); } _logger.LogSuccess(context, runId, $"Importing {notifications.Count} valid notifications"); var savedNotifications = await SaveLinkedNotifications(context, runId, importResult, notifications); if (savedNotifications != null && await MarkNotificationsAsImported(context, runId, importResult, savedNotifications)) { importResult.NtbsIds = savedNotifications.ToDictionary(x => x.LegacyId, x => x.NotificationId); await ImportLabResults(context, runId, importResult, savedNotifications); await MigrateCultureResistanceSummaries(context, runId, savedNotifications); await UpdateDrugResistanceProfiles(context, runId, savedNotifications); await UpdateClusterInformation(context, runId, savedNotifications); await _logger.LogGroupSuccess(context, runId, notifications); } return(importResult); }
public async Task correctlyCreates_basicNotification() { // Arrange const int runId = 10101; const string legacyId = "130331"; SetupNotificationsInGroups((legacyId, "1")); // Act var notification = await GetSingleNotification(legacyId, runId); var validationErrors = await _importValidator.CleanAndValidateNotification(null, runId, notification); // Assert Assert.Equal("ETS", notification.LegacySource); Assert.Equal("130331", notification.ETSID); Assert.Equal("130331", notification.LegacyId); Assert.Equal(new DateTime(2015, 3, 31), notification.NotificationDate?.Date); Assert.Equal(NotificationStatus.Notified, notification.NotificationStatus); Assert.Equal("RG145UT", notification.PatientDetails.Postcode); Assert.False(notification.PatientDetails.NoFixedAbode); Assert.Equal("Winford", notification.PatientDetails.GivenName); Assert.Equal("Wongus", notification.PatientDetails.FamilyName); Assert.Equal("9815779000", notification.PatientDetails.NhsNumber); Assert.Equal(new DateTime(1981, 3, 24), notification.PatientDetails.Dob); Assert.Equal(2010, notification.PatientDetails.YearOfUkEntry); Assert.Equal("3 Winglass Place\nWongaton", notification.PatientDetails.Address); Assert.Equal(RoyalBerkshireGuid, notification.HospitalDetails.HospitalId); Assert.Equal(RoyalBerkshireCode, notification.HospitalDetails.TBServiceCode); Assert.Equal("Dr McGown", notification.HospitalDetails.Consultant); Assert.Equal(HIVTestStatus.HIVStatusKnown, notification.ClinicalDetails.HIVTestState); Assert.Equal(Status.Yes, notification.ClinicalDetails.HomeVisitCarriedOut); Assert.Equal(HealthcareSetting.AccidentAndEmergency, notification.ClinicalDetails.HealthcareSetting); Assert.Equal(new DateTime(2015, 03, 25, 00, 00, 00), notification.ClinicalDetails.FirstHomeVisitDate); Assert.Equal("Patient did not begin course of treatment under DOT", notification.ClinicalDetails.Notes); Assert.Equal("TestRefX019", notification.ClinicalDetails.HealthProtectionTeamReferenceNumber); Assert.Equal(Status.Yes, notification.ImmunosuppressionDetails.Status); Assert.False(notification.ImmunosuppressionDetails.HasBioTherapy); Assert.True(notification.ImmunosuppressionDetails.HasTransplantation); Assert.True(notification.ImmunosuppressionDetails.HasOther); Assert.Equal("Some other immunosuppression", notification.ImmunosuppressionDetails.OtherDescription); Assert.Equal(Status.No, notification.SocialRiskFactors.RiskFactorDrugs.Status); Assert.Null(notification.SocialRiskFactors.RiskFactorDrugs.IsCurrent); Assert.Null(notification.SocialRiskFactors.RiskFactorDrugs.InPastFiveYears); Assert.Null(notification.SocialRiskFactors.RiskFactorDrugs.MoreThanFiveYearsAgo); Assert.Null(notification.SocialRiskFactors.RiskFactorHomelessness.Status); Assert.Null(notification.SocialRiskFactors.RiskFactorHomelessness.IsCurrent); Assert.Null(notification.SocialRiskFactors.RiskFactorHomelessness.InPastFiveYears); Assert.Null(notification.SocialRiskFactors.RiskFactorHomelessness.MoreThanFiveYearsAgo); Assert.Equal(Status.Yes, notification.SocialRiskFactors.RiskFactorImprisonment.Status); Assert.False(notification.SocialRiskFactors.RiskFactorImprisonment.IsCurrent); Assert.True(notification.SocialRiskFactors.RiskFactorImprisonment.InPastFiveYears); Assert.False(notification.SocialRiskFactors.RiskFactorImprisonment.MoreThanFiveYearsAgo); Assert.Equal("12-13", notification.MDRDetails.ExpectedTreatmentDurationInMonths); Assert.Equal(2, notification.TravelDetails.TotalNumberOfCountries); Assert.Equal(Status.Yes, notification.TravelDetails.HasTravel); Assert.Equal(1, notification.TravelDetails.Country1Id); Assert.Equal(9, notification.TravelDetails.Country2Id); Assert.Null(notification.TravelDetails.Country3Id); Assert.Equal(1, notification.TravelDetails.StayLengthInMonths1); Assert.Equal(3, notification.TravelDetails.StayLengthInMonths2); Assert.Null(notification.TravelDetails.StayLengthInMonths3); Assert.False(notification.ShouldBeClosed()); Assert.Equal(NotificationStatus.Notified, notification.NotificationStatus); Assert.Empty(validationErrors); }