From e1dbdb771c09a88f9aa4e6f3e1c41c59d2f81525 Mon Sep 17 00:00:00 2001 From: Mike Brown Date: Fri, 14 Jun 2024 14:23:05 -0400 Subject: [PATCH 1/3] Add syphilis history field to bulk uploader --- .../api/model/filerow/TestResultRow.java | 25 +++++++++ .../simplereport/config/CachingConfig.java | 3 ++ .../simplereport/service/DiseaseService.java | 1 + .../ResultsUploaderCachingService.java | 7 +++ .../service/TestResultUploadService.java | 2 + .../validators/CsvValidatorUtils.java | 51 +++++++++++++++++++ .../validators/TestResultRowTest.java | 34 +++++++++++++ 7 files changed, 123 insertions(+) diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/api/model/filerow/TestResultRow.java b/backend/src/main/java/gov/cdc/usds/simplereport/api/model/filerow/TestResultRow.java index 4c7fb1fe10..fbd0b14a3b 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/api/model/filerow/TestResultRow.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/api/model/filerow/TestResultRow.java @@ -16,6 +16,7 @@ import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateGendersOfSexualPartners; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePhoneNumber; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePositiveHIVRequiredAOEFields; +import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePositiveSyphilisRequiredAOEFields; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateRace; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateResidence; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateSpecimenType; @@ -105,6 +106,7 @@ public class TestResultRow implements FileRow { final ValueOrError testResultStatus; final ValueOrError testOrderedCode; final ValueOrError gendersOfSexualPartners; + final ValueOrError syphilisHistory; static final String PATIENT_LAST_NAME = "patient_last_name"; static final String PATIENT_FIRST_NAME = "patient_first_name"; @@ -149,6 +151,7 @@ public class TestResultRow implements FileRow { public static final String ORDERING_FACILITY_ZIP_CODE = "ordering_facility_zip_code"; public static final String ORDERING_FACILITY_PHONE_NUMBER = "ordering_facility_phone_number"; public static final String GENDERS_OF_SEXUAL_PARTNERS = "genders_of_sexual_partners"; + public static final String SYPHILIS_HISTORY = "syphilis_history"; public static final ImmutableMap diseaseSpecificLoincMap = new ImmutableMap.Builder() @@ -452,6 +455,7 @@ public TestResultRow(Map rawRow) { testOrderedCode = getValue(rawRow, "test_ordered_code", isRequired("test_ordered_code")); gendersOfSexualPartners = getValue(rawRow, GENDERS_OF_SEXUAL_PARTNERS, isRequired(GENDERS_OF_SEXUAL_PARTNERS)); + syphilisHistory = getValue(rawRow, SYPHILIS_HISTORY, isRequired(SYPHILIS_HISTORY)); } private List validateDeviceModelAndTestPerformedCode( @@ -487,6 +491,17 @@ private boolean isHivResult() { equipmentModelName.getValue(), testPerformedCode.getValue())); } + private boolean isSyphilisResult() { + if (equipmentModelName.getValue() == null || testPerformedCode.getValue() == null) { + return false; + } + return resultsUploaderCachingService + .getSyphilisEquipmentModelAndTestPerformedCodeSet() + .contains( + ResultsUploaderCachingService.getKey( + equipmentModelName.getValue(), testPerformedCode.getValue())); + } + private List generateInvalidDataErrorMessages() { String errorMessage = "Invalid " + EQUIPMENT_MODEL_NAME + " and " + TEST_PERFORMED_CODE + " combination"; @@ -602,6 +617,16 @@ public List validateIndividualValues() { validatePositiveHIVRequiredAOEFields(testResult, gendersOfSexualPartners, pregnant)); } + if (isSyphilisResult()) { + errors.addAll( + validatePositiveSyphilisRequiredAOEFields( + testResult, + gendersOfSexualPartners, + pregnant, + syphilisHistory, + symptomaticForDisease)); + } + return errors; } } diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/config/CachingConfig.java b/backend/src/main/java/gov/cdc/usds/simplereport/config/CachingConfig.java index ccf162e08a..051b1591dc 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/config/CachingConfig.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/config/CachingConfig.java @@ -14,6 +14,8 @@ public class CachingConfig { "covidEquipmentModelAndTestPerformedCodeSet"; public static final String HIV_EQUIPMENT_MODEL_AND_TEST_PERFORMED_CODE_SET = "hivEquipmentModelAndTestPerformedCodeSet"; + public static final String SYPHILIS_EQUIPMENT_MODEL_AND_TEST_PERFORMED_CODE_SET = + "syphilisEquipmentModelAndTestPerformedCodeSet"; public static final String DEVICE_MODEL_AND_TEST_PERFORMED_CODE_MAP = "deviceModelAndTestPerformedCodeMap"; public static final String SPECIMEN_NAME_TO_SNOMED_MAP = "specimenTypeNameSNOMEDMap"; @@ -26,6 +28,7 @@ public CacheManager cacheManager() { return new ConcurrentMapCacheManager( COVID_EQUIPMENT_MODEL_AND_TEST_PERFORMED_CODE_SET, HIV_EQUIPMENT_MODEL_AND_TEST_PERFORMED_CODE_SET, + SYPHILIS_EQUIPMENT_MODEL_AND_TEST_PERFORMED_CODE_SET, DEVICE_MODEL_AND_TEST_PERFORMED_CODE_MAP, SPECIMEN_NAME_TO_SNOMED_MAP, SNOMED_TO_SPECIMEN_NAME_MAP, diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/service/DiseaseService.java b/backend/src/main/java/gov/cdc/usds/simplereport/service/DiseaseService.java index 7c86d3f10b..8f88368197 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/service/DiseaseService.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/service/DiseaseService.java @@ -23,6 +23,7 @@ public class DiseaseService { public static final String FLU_RNA_NAME = "Flu RNA"; public static final String RSV_NAME = "RSV"; public static final String HIV_NAME = "HIV"; + public static final String SYPHILIS_NAME = "Syphilis"; private final DiseaseCacheService diseaseCacheService; diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/service/ResultsUploaderCachingService.java b/backend/src/main/java/gov/cdc/usds/simplereport/service/ResultsUploaderCachingService.java index 38bb70db04..80bf60deb2 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/service/ResultsUploaderCachingService.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/service/ResultsUploaderCachingService.java @@ -6,6 +6,7 @@ import static gov.cdc.usds.simplereport.config.CachingConfig.HIV_EQUIPMENT_MODEL_AND_TEST_PERFORMED_CODE_SET; import static gov.cdc.usds.simplereport.config.CachingConfig.SNOMED_TO_SPECIMEN_NAME_MAP; import static gov.cdc.usds.simplereport.config.CachingConfig.SPECIMEN_NAME_TO_SNOMED_MAP; +import static gov.cdc.usds.simplereport.config.CachingConfig.SYPHILIS_EQUIPMENT_MODEL_AND_TEST_PERFORMED_CODE_SET; import gov.cdc.usds.simplereport.db.model.DeviceType; import gov.cdc.usds.simplereport.db.model.SpecimenType; @@ -150,6 +151,12 @@ public Set getHivEquipmentModelAndTestPerformedCodeSet() { return getDiseaseSpecificEquipmentModelAndTestPerformedCodeSet(DiseaseService.HIV_NAME); } + @Cacheable(SYPHILIS_EQUIPMENT_MODEL_AND_TEST_PERFORMED_CODE_SET) + public Set getSyphilisEquipmentModelAndTestPerformedCodeSet() { + log.info("generating syphilisEquipmentModelAndTestPerformedCodeSet cache"); + return getDiseaseSpecificEquipmentModelAndTestPerformedCodeSet(DiseaseService.SYPHILIS_NAME); + } + @Cacheable(COVID_EQUIPMENT_MODEL_AND_TEST_PERFORMED_CODE_SET) public Set getCovidEquipmentModelAndTestPerformedCodeSet() { log.info("generating covidEquipmentModelAndTestPerformedCodeSet cache"); diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/service/TestResultUploadService.java b/backend/src/main/java/gov/cdc/usds/simplereport/service/TestResultUploadService.java index 0c3ab1d980..7c77aad146 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/service/TestResultUploadService.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/service/TestResultUploadService.java @@ -9,6 +9,7 @@ import static gov.cdc.usds.simplereport.api.model.filerow.TestResultRow.ORDERING_FACILITY_STREET; import static gov.cdc.usds.simplereport.api.model.filerow.TestResultRow.ORDERING_FACILITY_STREET2; import static gov.cdc.usds.simplereport.api.model.filerow.TestResultRow.ORDERING_FACILITY_ZIP_CODE; +import static gov.cdc.usds.simplereport.api.model.filerow.TestResultRow.SYPHILIS_HISTORY; import static gov.cdc.usds.simplereport.api.model.filerow.TestResultRow.TESTING_LAB_CITY; import static gov.cdc.usds.simplereport.api.model.filerow.TestResultRow.TESTING_LAB_NAME; import static gov.cdc.usds.simplereport.api.model.filerow.TestResultRow.TESTING_LAB_PHONE_NUMBER; @@ -305,6 +306,7 @@ private Map transformCsvRow(Map row) { row.put(DATE_RESULT_RELEASED_COLUMN_NAME, dateResultReleased.toOffsetDateTime().toString()); row.remove(GENDERS_OF_SEXUAL_PARTNERS); + row.remove(SYPHILIS_HISTORY); return row; } diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java b/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java index 80308eccbb..1242d392e4 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java @@ -260,6 +260,12 @@ private static String getRequiredHivAoeValuesErrorMessage(String columnName) { + " column. This is required because the row contains a positive HIV test result."; } + private static String getRequiredSyphilisAoeValuesErrorMessage(String columnName) { + return "File is missing data in the " + + columnName + + " column. This is required because the row contains a positive Syphilis test result."; + } + public static List validateTestResult(ValueOrError input) { return validateSpecificValueOrSNOMED(input, TEST_RESULT_VALUES); } @@ -673,6 +679,51 @@ public static List validatePositiveHIVRequiredAOEFields( return errors; } + private static FeedbackMessage buildSyphilisMissingDataFeedbackMessage(ValueOrError field) { + return FeedbackMessage.builder() + .scope(ITEM_SCOPE) + .fieldHeader(field.getHeader()) + .source(ResultUploadErrorSource.SIMPLE_REPORT) + .message(getRequiredSyphilisAoeValuesErrorMessage(field.getHeader())) + .errorType(ResultUploadErrorType.MISSING_DATA) + .fieldRequired(field.isRequired()) + .build(); + } + + public static List validatePositiveSyphilisRequiredAOEFields( + ValueOrError testResult, + ValueOrError gendersOfSexualPartners, + ValueOrError pregnant, + ValueOrError previousSyphilisDiagnosis, + ValueOrError symptomaticForDisease) { + List errors = new ArrayList<>(); + // includes SNOMED values for positive and detected + Set positiveTestResultValues = Set.of("positive", "detected", "260373001", "10828004"); + if (!positiveTestResultValues.contains(testResult.getValue().toLowerCase())) { + return errors; + } + + if (gendersOfSexualPartners.getValue() == null + || gendersOfSexualPartners.getValue().isBlank()) { + errors.add(buildSyphilisMissingDataFeedbackMessage(gendersOfSexualPartners)); + } + + if (pregnant.getValue() == null || pregnant.getValue().isBlank()) { + errors.add(buildSyphilisMissingDataFeedbackMessage(pregnant)); + } + + if (previousSyphilisDiagnosis.getValue() == null + || previousSyphilisDiagnosis.getValue().isBlank()) { + errors.add(buildSyphilisMissingDataFeedbackMessage(previousSyphilisDiagnosis)); + } + + if (symptomaticForDisease.getValue() == null || symptomaticForDisease.getValue().isBlank()) { + errors.add(buildSyphilisMissingDataFeedbackMessage(symptomaticForDisease)); + } + + return errors; + } + private static List validateRegex(ValueOrError input, String regex) { List errors = new ArrayList<>(); String value = parseString(input.getValue()); diff --git a/backend/src/test/java/gov/cdc/usds/simplereport/validators/TestResultRowTest.java b/backend/src/test/java/gov/cdc/usds/simplereport/validators/TestResultRowTest.java index a0cdfff34c..50dd28244a 100644 --- a/backend/src/test/java/gov/cdc/usds/simplereport/validators/TestResultRowTest.java +++ b/backend/src/test/java/gov/cdc/usds/simplereport/validators/TestResultRowTest.java @@ -461,6 +461,40 @@ void validatePositiveHivRequiredAoeFields() { .contains("This is required because the row contains a positive HIV test result.")); } + @Test + void validatePositiveSyphilisRequiredAoeFields() { + var missingSyphilisRequiredAoeFields = validRowMap; + missingSyphilisRequiredAoeFields.put("equipment_model_name", "Syphilis model"); + missingSyphilisRequiredAoeFields.put("test_performed_code", "80387-4"); + missingSyphilisRequiredAoeFields.put("specimen_type", "123456789"); + missingSyphilisRequiredAoeFields.put("test_result", "Detected"); + missingSyphilisRequiredAoeFields.put("pregnant", ""); + missingSyphilisRequiredAoeFields.put("genders_of_sexual_partners", ""); + missingSyphilisRequiredAoeFields.put("previous_syphilis_diagnosis", ""); + missingSyphilisRequiredAoeFields.put("symptomatic_for_disease", ""); + + var resultsUploaderCachingService = mock(ResultsUploaderCachingService.class); + when(resultsUploaderCachingService.getModelAndTestPerformedCodeToDeviceMap()) + .thenReturn(Map.of("syphilis model|80387-4", TestDataBuilder.createDeviceType())); + when(resultsUploaderCachingService.getSyphilisEquipmentModelAndTestPerformedCodeSet()) + .thenReturn(Set.of("syphilis model|80387-4")); + + var testResultRow = + new TestResultRow( + missingSyphilisRequiredAoeFields, + resultsUploaderCachingService, + mock(FeatureFlagsConfig.class)); + + var actual = testResultRow.validateIndividualValues(); + + assertThat(actual).hasSize(4); + actual.forEach( + message -> + assertThat(message.getMessage()) + .contains( + "This is required because the row contains a positive Syphilis test result.")); + } + private ResultsUploaderCachingService mockResultsUploaderCachingService() { var resultsUploaderCachingService = mock(ResultsUploaderCachingService.class); when(resultsUploaderCachingService.getModelAndTestPerformedCodeToDeviceMap()) From bb3626fbc4af4b2302e95c12d874243209b5e0df Mon Sep 17 00:00:00 2001 From: Mike Brown Date: Fri, 14 Jun 2024 15:33:21 -0400 Subject: [PATCH 2/3] Use string literals --- .../validators/CsvValidatorUtils.java | 38 ++++++++++++------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java b/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java index 1242d392e4..d4bbc3a0ec 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java @@ -54,6 +54,7 @@ import gov.cdc.usds.simplereport.api.model.filerow.FileRow; import gov.cdc.usds.simplereport.db.model.auxiliary.ResultUploadErrorSource; import gov.cdc.usds.simplereport.db.model.auxiliary.ResultUploadErrorType; +import gov.cdc.usds.simplereport.service.DiseaseService; import gov.cdc.usds.simplereport.service.model.reportstream.FeedbackMessage; import gov.cdc.usds.simplereport.utils.UnknownAddressUtils; import java.io.BufferedReader; @@ -138,6 +139,10 @@ public class CsvValidatorUtils { private static final String NOT_HISPANIC_LITERAL = "not hispanic or latino"; private static final String NOT_HISPANIC_CODE = "2186-5"; private static final String NOT_HISPANIC_DB_VALUE = "not_hispanic"; + private static final String POSITIVE_LITERAL = "positive"; + private static final String POSITIVE_CODE = "10828004"; + private static final String DETECTED_LITERAL = "detected"; + private static final String DETECTED_CODE = "260373001"; private static final Set GENDER_VALUES = Set.of( "m", MALE_LITERAL, @@ -176,7 +181,7 @@ public class CsvValidatorUtils { "n", "no", "u", UNKNOWN_CODE); private static final Set TEST_RESULT_VALUES = - Set.of("positive", "negative", "not detected", "detected", "invalid result"); + Set.of(POSITIVE_LITERAL, "negative", "not detected", DETECTED_LITERAL, "invalid result"); private static final Set RESIDENCE_VALUES = Set.of( @@ -254,16 +259,13 @@ private static String getRequiredValueErrorMessage(String columnName) { return "File is missing data in the " + columnName + " column."; } - private static String getRequiredHivAoeValuesErrorMessage(String columnName) { + private static String getPositiveResultRequiredValueErrorMessage( + String columnName, String diseaseName) { return "File is missing data in the " + columnName - + " column. This is required because the row contains a positive HIV test result."; - } - - private static String getRequiredSyphilisAoeValuesErrorMessage(String columnName) { - return "File is missing data in the " - + columnName - + " column. This is required because the row contains a positive Syphilis test result."; + + " column. This is required because the row contains a positive " + + diseaseName + + " test result."; } public static List validateTestResult(ValueOrError input) { @@ -647,7 +649,8 @@ public static List validatePositiveHIVRequiredAOEFields( ValueOrError testResult, ValueOrError gendersOfSexualPartners, ValueOrError pregnant) { List errors = new ArrayList<>(); // includes SNOMED values for positive and detected - Set positiveTestResultValues = Set.of("positive", "detected", "260373001", "10828004"); + Set positiveTestResultValues = + Set.of(POSITIVE_LITERAL, DETECTED_LITERAL, POSITIVE_CODE, DETECTED_CODE); if (!positiveTestResultValues.contains(testResult.getValue().toLowerCase())) { return errors; } @@ -659,7 +662,9 @@ public static List validatePositiveHIVRequiredAOEFields( .scope(ITEM_SCOPE) .fieldHeader(gendersOfSexualPartners.getHeader()) .source(ResultUploadErrorSource.SIMPLE_REPORT) - .message(getRequiredHivAoeValuesErrorMessage(gendersOfSexualPartners.getHeader())) + .message( + getPositiveResultRequiredValueErrorMessage( + gendersOfSexualPartners.getHeader(), DiseaseService.HIV_NAME)) .errorType(ResultUploadErrorType.MISSING_DATA) .fieldRequired(gendersOfSexualPartners.isRequired()) .build()); @@ -671,7 +676,9 @@ public static List validatePositiveHIVRequiredAOEFields( .scope(ITEM_SCOPE) .fieldHeader(pregnant.getHeader()) .source(ResultUploadErrorSource.SIMPLE_REPORT) - .message(getRequiredHivAoeValuesErrorMessage(pregnant.getHeader())) + .message( + getPositiveResultRequiredValueErrorMessage( + pregnant.getHeader(), DiseaseService.HIV_NAME)) .errorType(ResultUploadErrorType.MISSING_DATA) .fieldRequired(pregnant.isRequired()) .build()); @@ -684,7 +691,9 @@ private static FeedbackMessage buildSyphilisMissingDataFeedbackMessage(ValueOrEr .scope(ITEM_SCOPE) .fieldHeader(field.getHeader()) .source(ResultUploadErrorSource.SIMPLE_REPORT) - .message(getRequiredSyphilisAoeValuesErrorMessage(field.getHeader())) + .message( + getPositiveResultRequiredValueErrorMessage( + field.getHeader(), DiseaseService.SYPHILIS_NAME)) .errorType(ResultUploadErrorType.MISSING_DATA) .fieldRequired(field.isRequired()) .build(); @@ -698,7 +707,8 @@ public static List validatePositiveSyphilisRequiredAOEFields( ValueOrError symptomaticForDisease) { List errors = new ArrayList<>(); // includes SNOMED values for positive and detected - Set positiveTestResultValues = Set.of("positive", "detected", "260373001", "10828004"); + Set positiveTestResultValues = + Set.of(POSITIVE_LITERAL, DETECTED_LITERAL, POSITIVE_CODE, DETECTED_CODE); if (!positiveTestResultValues.contains(testResult.getValue().toLowerCase())) { return errors; } From 5d39ae3d79612f49aedd43fc19dcb232da9d4f89 Mon Sep 17 00:00:00 2001 From: Mike Brown Date: Mon, 17 Jun 2024 06:42:08 -0400 Subject: [PATCH 3/3] Refactor using list of fields --- .../api/model/filerow/TestResultRow.java | 15 ++- .../validators/CsvValidatorUtils.java | 105 +++++------------- .../validators/CsvValidatorUtilsTest.java | 18 ++- 3 files changed, 46 insertions(+), 92 deletions(-) diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/api/model/filerow/TestResultRow.java b/backend/src/main/java/gov/cdc/usds/simplereport/api/model/filerow/TestResultRow.java index fbd0b14a3b..ebd9dce10e 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/api/model/filerow/TestResultRow.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/api/model/filerow/TestResultRow.java @@ -15,9 +15,8 @@ import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateEthnicity; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateGendersOfSexualPartners; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePhoneNumber; -import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePositiveHIVRequiredAOEFields; -import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePositiveSyphilisRequiredAOEFields; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateRace; +import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateRequiredFieldsForPositiveResult; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateResidence; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateSpecimenType; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateState; @@ -31,6 +30,7 @@ import gov.cdc.usds.simplereport.config.FeatureFlagsConfig; import gov.cdc.usds.simplereport.db.model.auxiliary.ResultUploadErrorSource; import gov.cdc.usds.simplereport.db.model.auxiliary.ResultUploadErrorType; +import gov.cdc.usds.simplereport.service.DiseaseService; import gov.cdc.usds.simplereport.service.ResultsUploaderCachingService; import gov.cdc.usds.simplereport.service.ResultsUploaderDeviceService; import gov.cdc.usds.simplereport.service.model.reportstream.FeedbackMessage; @@ -614,17 +614,16 @@ public List validateIndividualValues() { if (isHivResult()) { errors.addAll( - validatePositiveHIVRequiredAOEFields(testResult, gendersOfSexualPartners, pregnant)); + validateRequiredFieldsForPositiveResult( + testResult, DiseaseService.HIV_NAME, List.of(gendersOfSexualPartners, pregnant))); } if (isSyphilisResult()) { errors.addAll( - validatePositiveSyphilisRequiredAOEFields( + validateRequiredFieldsForPositiveResult( testResult, - gendersOfSexualPartners, - pregnant, - syphilisHistory, - symptomaticForDisease)); + DiseaseService.SYPHILIS_NAME, + List.of(gendersOfSexualPartners, pregnant, syphilisHistory, symptomaticForDisease))); } return errors; diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java b/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java index d4bbc3a0ec..a4b0e43151 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtils.java @@ -54,7 +54,6 @@ import gov.cdc.usds.simplereport.api.model.filerow.FileRow; import gov.cdc.usds.simplereport.db.model.auxiliary.ResultUploadErrorSource; import gov.cdc.usds.simplereport.db.model.auxiliary.ResultUploadErrorType; -import gov.cdc.usds.simplereport.service.DiseaseService; import gov.cdc.usds.simplereport.service.model.reportstream.FeedbackMessage; import gov.cdc.usds.simplereport.utils.UnknownAddressUtils; import java.io.BufferedReader; @@ -73,6 +72,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import lombok.Getter; +import org.apache.commons.lang3.StringUtils; public class CsvValidatorUtils { @@ -143,6 +143,8 @@ public class CsvValidatorUtils { private static final String POSITIVE_CODE = "10828004"; private static final String DETECTED_LITERAL = "detected"; private static final String DETECTED_CODE = "260373001"; + private static final Set POSITIVE_TEST_RESULT_VALUES = + Set.of(POSITIVE_LITERAL, DETECTED_LITERAL, POSITIVE_CODE, DETECTED_CODE); private static final Set GENDER_VALUES = Set.of( "m", MALE_LITERAL, @@ -645,92 +647,35 @@ public static List validateGendersOfSexualPartners(ValueOrError return errors; } - public static List validatePositiveHIVRequiredAOEFields( - ValueOrError testResult, ValueOrError gendersOfSexualPartners, ValueOrError pregnant) { + public static List validateRequiredFieldsForPositiveResult( + ValueOrError testResult, String diseaseName, List fields) { List errors = new ArrayList<>(); - // includes SNOMED values for positive and detected - Set positiveTestResultValues = - Set.of(POSITIVE_LITERAL, DETECTED_LITERAL, POSITIVE_CODE, DETECTED_CODE); - if (!positiveTestResultValues.contains(testResult.getValue().toLowerCase())) { - return errors; - } - - if (gendersOfSexualPartners.getValue() == null - || gendersOfSexualPartners.getValue().isBlank()) { - errors.add( - FeedbackMessage.builder() - .scope(ITEM_SCOPE) - .fieldHeader(gendersOfSexualPartners.getHeader()) - .source(ResultUploadErrorSource.SIMPLE_REPORT) - .message( - getPositiveResultRequiredValueErrorMessage( - gendersOfSexualPartners.getHeader(), DiseaseService.HIV_NAME)) - .errorType(ResultUploadErrorType.MISSING_DATA) - .fieldRequired(gendersOfSexualPartners.isRequired()) - .build()); - } - if (pregnant.getValue() == null || pregnant.getValue().isBlank()) { - errors.add( - FeedbackMessage.builder() - .scope(ITEM_SCOPE) - .fieldHeader(pregnant.getHeader()) - .source(ResultUploadErrorSource.SIMPLE_REPORT) - .message( - getPositiveResultRequiredValueErrorMessage( - pregnant.getHeader(), DiseaseService.HIV_NAME)) - .errorType(ResultUploadErrorType.MISSING_DATA) - .fieldRequired(pregnant.isRequired()) - .build()); - } - return errors; - } - - private static FeedbackMessage buildSyphilisMissingDataFeedbackMessage(ValueOrError field) { - return FeedbackMessage.builder() - .scope(ITEM_SCOPE) - .fieldHeader(field.getHeader()) - .source(ResultUploadErrorSource.SIMPLE_REPORT) - .message( - getPositiveResultRequiredValueErrorMessage( - field.getHeader(), DiseaseService.SYPHILIS_NAME)) - .errorType(ResultUploadErrorType.MISSING_DATA) - .fieldRequired(field.isRequired()) - .build(); - } - - public static List validatePositiveSyphilisRequiredAOEFields( - ValueOrError testResult, - ValueOrError gendersOfSexualPartners, - ValueOrError pregnant, - ValueOrError previousSyphilisDiagnosis, - ValueOrError symptomaticForDisease) { - List errors = new ArrayList<>(); - // includes SNOMED values for positive and detected - Set positiveTestResultValues = - Set.of(POSITIVE_LITERAL, DETECTED_LITERAL, POSITIVE_CODE, DETECTED_CODE); - if (!positiveTestResultValues.contains(testResult.getValue().toLowerCase())) { + if (testResult.getValue() == null) { + // if test result is null, then it should already give an error when validating required + // fields return errors; } - if (gendersOfSexualPartners.getValue() == null - || gendersOfSexualPartners.getValue().isBlank()) { - errors.add(buildSyphilisMissingDataFeedbackMessage(gendersOfSexualPartners)); - } - - if (pregnant.getValue() == null || pregnant.getValue().isBlank()) { - errors.add(buildSyphilisMissingDataFeedbackMessage(pregnant)); - } - - if (previousSyphilisDiagnosis.getValue() == null - || previousSyphilisDiagnosis.getValue().isBlank()) { - errors.add(buildSyphilisMissingDataFeedbackMessage(previousSyphilisDiagnosis)); - } - - if (symptomaticForDisease.getValue() == null || symptomaticForDisease.getValue().isBlank()) { - errors.add(buildSyphilisMissingDataFeedbackMessage(symptomaticForDisease)); + if (!POSITIVE_TEST_RESULT_VALUES.contains(testResult.getValue().toLowerCase())) { + return errors; } + fields.forEach( + field -> { + if (StringUtils.isBlank(field.getValue())) { + errors.add( + FeedbackMessage.builder() + .scope(ITEM_SCOPE) + .fieldHeader(field.getHeader()) + .source(ResultUploadErrorSource.SIMPLE_REPORT) + .message( + getPositiveResultRequiredValueErrorMessage(field.getHeader(), diseaseName)) + .errorType(ResultUploadErrorType.MISSING_DATA) + .fieldRequired(field.isRequired()) + .build()); + } + }); return errors; } diff --git a/backend/src/test/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtilsTest.java b/backend/src/test/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtilsTest.java index dbb67527c2..67e6ffe367 100644 --- a/backend/src/test/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtilsTest.java +++ b/backend/src/test/java/gov/cdc/usds/simplereport/validators/CsvValidatorUtilsTest.java @@ -11,7 +11,7 @@ import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateGendersOfSexualPartners; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePartialUnkAddress; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePhoneNumber; -import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validatePositiveHIVRequiredAOEFields; +import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateRequiredFieldsForPositiveResult; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateSpecimenType; import static gov.cdc.usds.simplereport.validators.CsvValidatorUtils.validateZipCode; import static org.assertj.core.api.Assertions.assertThat; @@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.MappingIterator; import com.fasterxml.jackson.databind.RuntimeJsonMappingException; import gov.cdc.usds.simplereport.api.model.errors.CsvProcessingException; +import gov.cdc.usds.simplereport.service.DiseaseService; import gov.cdc.usds.simplereport.service.model.reportstream.FeedbackMessage; import gov.cdc.usds.simplereport.utils.UnknownAddressUtils; import java.io.IOException; @@ -293,7 +294,10 @@ void validNegativeHIVNoRequiredAOEFields() { ValueOrError testResult = new ValueOrError("negative", "test_result"); ValueOrError genders = new ValueOrError("", "genders_of_sexual_partners"); ValueOrError pregnant = new ValueOrError("", "pregnant"); - assertThat(validatePositiveHIVRequiredAOEFields(testResult, genders, pregnant)).isEmpty(); + assertThat( + validateRequiredFieldsForPositiveResult( + testResult, DiseaseService.HIV_NAME, List.of(genders, pregnant))) + .isEmpty(); } @Test @@ -301,7 +305,10 @@ void validPositiveHIVRequiredAOEFields() { ValueOrError testResult = new ValueOrError("positive", "test_result"); ValueOrError genders = new ValueOrError("m, f, tm, tw", "genders_of_sexual_partners"); ValueOrError pregnant = new ValueOrError("n", "pregnant"); - assertThat(validatePositiveHIVRequiredAOEFields(testResult, genders, pregnant)).isEmpty(); + assertThat( + validateRequiredFieldsForPositiveResult( + testResult, DiseaseService.HIV_NAME, List.of(genders, pregnant))) + .isEmpty(); } @Test @@ -309,6 +316,9 @@ void invalidPositiveHIVRequiredAOEFields() { ValueOrError testResult = new ValueOrError("positive", "test_result"); ValueOrError genders = new ValueOrError("", "genders_of_sexual_partners"); ValueOrError pregnant = new ValueOrError("", "pregnant"); - assertThat(validatePositiveHIVRequiredAOEFields(testResult, genders, pregnant)).hasSize(2); + assertThat( + validateRequiredFieldsForPositiveResult( + testResult, DiseaseService.HIV_NAME, List.of(genders, pregnant))) + .hasSize(2); } }