diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/api/converter/ConvertToSpecimenProps.java b/backend/src/main/java/gov/cdc/usds/simplereport/api/converter/ConvertToSpecimenProps.java new file mode 100644 index 0000000000..c00d73e782 --- /dev/null +++ b/backend/src/main/java/gov/cdc/usds/simplereport/api/converter/ConvertToSpecimenProps.java @@ -0,0 +1,18 @@ +package gov.cdc.usds.simplereport.api.converter; + +import java.time.ZonedDateTime; +import lombok.Builder; +import lombok.Getter; + +@Builder +@Getter +public class ConvertToSpecimenProps { + private String specimenCode; + private String specimenName; + private String collectionCode; + private String collectionName; + private String id; + private String identifier; + private ZonedDateTime collectionDate; + private ZonedDateTime receivedTime; +} diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/api/converter/FhirConverter.java b/backend/src/main/java/gov/cdc/usds/simplereport/api/converter/FhirConverter.java index 0970843c89..d98b6ac744 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/api/converter/FhirConverter.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/api/converter/FhirConverter.java @@ -73,7 +73,6 @@ import java.util.TimeZone; import java.util.UUID; import java.util.function.Function; -import java.util.stream.Collectors; import javax.validation.constraints.NotNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -158,7 +157,7 @@ public HumanName convertToHumanName(String first, String middle, String last, St public List convertPhoneNumbersToContactPoint( @NotNull List phoneNumber) { - return phoneNumber.stream().map(this::convertToContactPoint).collect(Collectors.toList()); + return phoneNumber.stream().map(this::convertToContactPoint).toList(); } public ContactPoint convertToContactPoint(@NotNull PhoneNumber phoneNumber) { @@ -187,9 +186,7 @@ public ContactPoint convertToContactPoint(ContactPointUse contactPointUse, Strin } public List convertEmailsToContactPoint(ContactPointUse use, List emails) { - return emails.stream() - .map(email -> convertEmailToContactPoint(use, email)) - .collect(Collectors.toList()); + return emails.stream().map(email -> convertEmailToContactPoint(use, email)).toList(); } public ContactPoint convertEmailToContactPoint(ContactPointUse use, @NotNull String email) { @@ -203,11 +200,9 @@ public ContactPoint convertToContactPoint( public AdministrativeGender convertToAdministrativeGender(@NotNull String gender) { switch (gender.toLowerCase()) { - case "male": - case "m": + case "male", "m": return AdministrativeGender.MALE; - case "female": - case "f": + case "female", "f": return AdministrativeGender.FEMALE; default: return AdministrativeGender.UNKNOWN; @@ -496,41 +491,33 @@ public Device convertToDevice(String manufacturer, @NotNull String model, String return device; } - public Specimen convertToSpecimen( - String specimenCode, - String specimenName, - String collectionCode, - String collectionName, - String id, - String identifier, - ZonedDateTime collectionDate, - ZonedDateTime receivedTime) { + public Specimen convertToSpecimen(ConvertToSpecimenProps props) { var specimen = new Specimen(); - specimen.setId(id); - specimen.addIdentifier().setValue(identifier); - if (StringUtils.isNotBlank(specimenCode)) { + specimen.setId(props.getId()); + specimen.addIdentifier().setValue(props.getIdentifier()); + if (StringUtils.isNotBlank(props.getSpecimenCode())) { var codeableConcept = specimen.getType(); var coding = codeableConcept.addCoding(); coding.setSystem(SNOMED_CODE_SYSTEM); - coding.setCode(specimenCode); - codeableConcept.setText(specimenName); + coding.setCode(props.getSpecimenCode()); + codeableConcept.setText(props.getSpecimenName()); } - if (StringUtils.isNotBlank(collectionCode)) { + if (StringUtils.isNotBlank(props.getCollectionCode())) { var collection = specimen.getCollection(); var codeableConcept = collection.getBodySite(); var coding = codeableConcept.addCoding(); coding.setSystem(SNOMED_CODE_SYSTEM); - coding.setCode(collectionCode); - codeableConcept.setText(collectionName); + coding.setCode(props.getCollectionCode()); + codeableConcept.setText(props.getCollectionName()); } - if (collectionDate != null) { + if (props.getCollectionDate() != null) { var collection = specimen.getCollection(); - collection.setCollected(convertToDateTimeType(collectionDate)); + collection.setCollected(convertToDateTimeType(props.getCollectionDate())); } - if (receivedTime != null) { - specimen.setReceivedTimeElement(convertToDateTimeType(receivedTime)); + if (props.getReceivedTime() != null) { + specimen.setReceivedTimeElement(convertToDateTimeType(props.getReceivedTime())); } return specimen; @@ -542,14 +529,16 @@ public Specimen convertToSpecimen( ZonedDateTime collectionDate, ZonedDateTime receivedTime) { return convertToSpecimen( - specimenType.getTypeCode(), - specimenType.getName(), - specimenType.getCollectionLocationCode(), - specimenType.getCollectionLocationName(), - specimenType.getInternalId().toString(), - specimenIdentifier.toString(), - collectionDate, - receivedTime); + ConvertToSpecimenProps.builder() + .specimenCode(specimenType.getTypeCode()) + .specimenName(specimenType.getName()) + .collectionCode(specimenType.getCollectionLocationCode()) + .collectionName(specimenType.getCollectionLocationName()) + .id(specimenType.getInternalId().toString()) + .identifier(specimenIdentifier.toString()) + .collectionDate(collectionDate) + .receivedTime(receivedTime) + .build()); } public List convertToObservation( @@ -586,7 +575,7 @@ public List convertToObservation( deviceType.getModel(), resultDate); }) - .collect(Collectors.toList()); + .toList(); } public String getCommonDiseaseValue( @@ -728,7 +717,7 @@ public Set convertToAOEObservation( public Set convertToAOEObservations(String eventId, AskOnEntrySurvey surveyData) { Boolean symptomatic = null; - if (surveyData.getNoSymptoms()) { + if (Boolean.TRUE.equals(surveyData.getNoSymptoms())) { symptomatic = false; } else if (surveyData.getSymptoms().containsValue(Boolean.TRUE)) { symptomatic = true; 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 d0825e6f16..11fab763ce 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 @@ -31,12 +31,17 @@ public class ResultsUploaderCachingService { private final SpecimenTypeRepository specimenTypeRepository; private final AddressValidationService addressValidationService; + private static final String NASAL_SWAB_SNOMED = "445297001"; + private static final String NASAL_THROAT_SWAB_SNOMED = "433801000124107"; + private static final String BRONCHOALVEOLAR_LAVAGE = "258607008"; + private static final String DRIED_BLOOD_SPOT = "440500007"; + private static final Map specimenSNOMEDMap = Map.ofEntries( - Map.entry("swab of internal nose", "445297001"), - Map.entry("nasal swab", "445297001"), - Map.entry("nasal", "445297001"), - Map.entry("varied", "445297001"), + Map.entry("swab of internal nose", NASAL_SWAB_SNOMED), + Map.entry("nasal swab", NASAL_SWAB_SNOMED), + Map.entry("nasal", NASAL_SWAB_SNOMED), + Map.entry("varied", NASAL_SWAB_SNOMED), Map.entry("nasopharyngeal swab", "258500001"), Map.entry("mid-turbinate nasal swab", "871810001"), Map.entry("anterior nares swab", "697989009"), @@ -64,17 +69,17 @@ public class ResultsUploaderCachingService { Map.entry("blood specimen", "119297000"), Map.entry("capillary blood specimen", "122554006"), Map.entry("fingerstick whole blood", "122554006"), - Map.entry("dried blood spot specimen", "440500007"), - Map.entry("dried blood spot", "440500007"), - Map.entry("fingerstick blood dried blood spot", "440500007"), - Map.entry("nasopharyngeal and oropharyngeal swab", "433801000124107"), - Map.entry("nasal and throat swab combination", "433801000124107"), - Map.entry("nasal and throat swab", "433801000124107"), + Map.entry("dried blood spot specimen", DRIED_BLOOD_SPOT), + Map.entry("dried blood spot", DRIED_BLOOD_SPOT), + Map.entry("fingerstick blood dried blood spot", DRIED_BLOOD_SPOT), + Map.entry("nasopharyngeal and oropharyngeal swab", NASAL_THROAT_SWAB_SNOMED), + Map.entry("nasal and throat swab combination", NASAL_THROAT_SWAB_SNOMED), + Map.entry("nasal and throat swab", NASAL_THROAT_SWAB_SNOMED), Map.entry("lower respiratory fluid sample", "309171007"), Map.entry("lower respiratory tract aspirates", "309171007"), - Map.entry("bronchoalveolar lavage fluid sample", "258607008"), - Map.entry("bronchoalveolar lavage fluid", "258607008"), - Map.entry("bronchoalveolar lavage", "258607008")); + Map.entry("bronchoalveolar lavage fluid sample", BRONCHOALVEOLAR_LAVAGE), + Map.entry("bronchoalveolar lavage fluid", BRONCHOALVEOLAR_LAVAGE), + Map.entry("bronchoalveolar lavage", BRONCHOALVEOLAR_LAVAGE)); @Cacheable(DEVICE_MODEL_AND_TEST_PERFORMED_CODE_MAP) public Map getModelAndTestPerformedCodeToDeviceMap() { diff --git a/backend/src/main/java/gov/cdc/usds/simplereport/utils/BulkUploadResultsToFhir.java b/backend/src/main/java/gov/cdc/usds/simplereport/utils/BulkUploadResultsToFhir.java index 83e38928ac..e835b499e9 100644 --- a/backend/src/main/java/gov/cdc/usds/simplereport/utils/BulkUploadResultsToFhir.java +++ b/backend/src/main/java/gov/cdc/usds/simplereport/utils/BulkUploadResultsToFhir.java @@ -13,6 +13,7 @@ import gov.cdc.usds.simplereport.api.Translators; import gov.cdc.usds.simplereport.api.converter.ConvertToObservationProps; import gov.cdc.usds.simplereport.api.converter.ConvertToPatientProps; +import gov.cdc.usds.simplereport.api.converter.ConvertToSpecimenProps; import gov.cdc.usds.simplereport.api.converter.CreateFhirBundleProps; import gov.cdc.usds.simplereport.api.converter.FhirConverter; import gov.cdc.usds.simplereport.api.model.errors.CsvProcessingException; @@ -37,7 +38,6 @@ import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -121,7 +121,7 @@ public List convertToFhirBundles(InputStream csvStream, UUID orgId) { throw new CsvProcessingException("Unable to process file."); } }) - .collect(Collectors.toList()); + .toList(); // Clear cache to free memory resultsUploaderCachingService.clearAddressTimezoneLookupCache(); @@ -331,14 +331,16 @@ private Bundle convertRowToFhirBundle(TestResultRow row, UUID orgId) { var specimen = fhirConverter.convertToSpecimen( - getSpecimenTypeSnomed(row.getSpecimenType().getValue()), - getDescriptionValue(row.getSpecimenType().getValue()), - null, - null, - uuidGenerator.randomUUID().toString(), - uuidGenerator.randomUUID().toString(), - specimenCollectionDate, - testingLabSpecimenReceivedDate); + ConvertToSpecimenProps.builder() + .specimenCode(getSpecimenTypeSnomed(row.getSpecimenType().getValue())) + .specimenName(getDescriptionValue(row.getSpecimenType().getValue())) + .collectionCode(null) + .collectionName(null) + .id(uuidGenerator.randomUUID().toString()) + .identifier(uuidGenerator.randomUUID().toString()) + .collectionDate(specimenCollectionDate) + .receivedTime(testingLabSpecimenReceivedDate) + .build()); var observation = List.of( diff --git a/backend/src/test/java/gov/cdc/usds/simplereport/api/converter/FhirConverterTest.java b/backend/src/test/java/gov/cdc/usds/simplereport/api/converter/FhirConverterTest.java index 50627d46a0..f0477ea71f 100644 --- a/backend/src/test/java/gov/cdc/usds/simplereport/api/converter/FhirConverterTest.java +++ b/backend/src/test/java/gov/cdc/usds/simplereport/api/converter/FhirConverterTest.java @@ -513,17 +513,22 @@ void convertToDevice_DeviceType_matchesJson() throws IOException { @Test void convertToSpecimen_Strings_valid() { + var collectionDate = + ZonedDateTime.ofInstant(Instant.parse("2023-06-22T16:38:00.000Z"), DEFAULT_TIME_ZONE_ID); + var receivedTime = ZonedDateTime.of(2023, 6, 23, 12, 0, 0, 0, ZoneId.of("US/Eastern")); + var actual = fhirConverter.convertToSpecimen( - "258500001", - "Nasopharyngeal swab", - "53342003", - "Internal nose structure (body structure)", - "id-123", - "uuid-123", - ZonedDateTime.ofInstant( - Instant.parse("2023-06-22T16:38:00.000Z"), DEFAULT_TIME_ZONE_ID), - ZonedDateTime.of(2023, 6, 23, 12, 0, 0, 0, ZoneId.of("US/Eastern"))); + ConvertToSpecimenProps.builder() + .specimenCode("258500001") + .specimenName("Nasopharyngeal swab") + .collectionCode("53342003") + .collectionName("Internal nose structure (body structure)") + .id("id-123") + .identifier("uuid-123") + .collectionDate(collectionDate) + .receivedTime(receivedTime) + .build()); assertThat(actual.getId()).isEqualTo("id-123"); assertThat(actual.getIdentifierFirstRep().getValue()).isEqualTo("uuid-123"); @@ -545,7 +550,7 @@ void convertToSpecimen_Strings_valid() { @Test void convertToSpecimen_Strings_null() { - var actual = fhirConverter.convertToSpecimen(null, null, null, null, null, null, null, null); + var actual = fhirConverter.convertToSpecimen(ConvertToSpecimenProps.builder().build()); assertThat(actual.getId()).isNull(); assertThat(actual.getType().getText()).isNull();