Skip to content

Commit

Permalink
Add test date to Observation.issued for single-entry and bulk upload (#…
Browse files Browse the repository at this point in the history
…5982)

* Add test date to Observation.issued for single-entry and bulk upload
* also force time zones to make fhir converter easier to test
* also fix rounding of test date to start of day
* using system default time zone for now but should look into what time zone to infer for dates in bulk upload
  • Loading branch information
mehansen authored Jun 16, 2023
1 parent f1f93ed commit e4df864
Show file tree
Hide file tree
Showing 9 changed files with 77 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gov.cdc.usds.simplereport.api.converter;

import gov.cdc.usds.simplereport.db.model.auxiliary.TestCorrectionStatus;
import java.util.Date;
import lombok.Builder;
import lombok.Getter;

Expand All @@ -17,4 +18,5 @@ public class ConvertToObservationProps {
private String testkitNameId;
private String equipmentUid;
private String deviceModel;
private Date issued;
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.UNIVERSAL_ID_SYSTEM;
import static gov.cdc.usds.simplereport.api.converter.FhirConstants.YESNO_CODE_SYSTEM;

import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat;
Expand Down Expand Up @@ -489,7 +490,8 @@ public List<Observation> convertToObservation(
Set<Result> results,
DeviceType deviceType,
TestCorrectionStatus correctionStatus,
String correctionReason) {
String correctionReason,
Date resultDate) {
return results.stream()
.map(
result -> {
Expand All @@ -515,7 +517,8 @@ public List<Observation> convertToObservation(
correctionReason,
testkitNameId,
equipmentUid,
deviceType.getModel());
deviceType.getModel(),
resultDate);
})
.collect(Collectors.toList());
}
Expand All @@ -534,7 +537,8 @@ public Observation convertToObservation(
String correctionReason,
String testkitNameId,
String equipmentUid,
String deviceModel) {
String deviceModel,
Date resultDate) {
if (result != null && result.getDisease() != null) {

return convertToObservation(
Expand All @@ -550,6 +554,7 @@ public Observation convertToObservation(
.testkitNameId(testkitNameId)
.equipmentUid(equipmentUid)
.deviceModel(deviceModel)
.issued(resultDate)
.build());
}
return null;
Expand Down Expand Up @@ -582,6 +587,9 @@ public Observation convertToObservation(ConvertToObservationProps props) {
.addInterpretation()
.addCoding(convertToAbnormalFlagInterpretation(props.getResultCode()));

observation.setIssued(props.getIssued());
observation.getIssuedElement().setTimeZoneZulu(true).setPrecision(TemporalPrecisionEnum.SECOND);

return observation;
}

Expand Down Expand Up @@ -793,7 +801,7 @@ public DiagnosticReport convertToDiagnosticReport(
var diagnosticReport =
new DiagnosticReport()
.setStatus(status)
.setEffective(new DateTimeType(dateTested))
.setEffective(new DateTimeType(dateTested).setTimeZoneZulu(true))
.setIssued(dateUpdated);

// Allows EffectiveDateTimeType to be mocked during tests
Expand Down Expand Up @@ -834,7 +842,8 @@ public Bundle createFhirBundle(
testEvent.getResults(),
testEvent.getDeviceType(),
testEvent.getCorrectionStatus(),
testEvent.getReasonForCorrection()))
testEvent.getReasonForCorrection(),
testEvent.getDateTested()))
.aoeObservations(
convertToAOEObservations(
testEvent.getInternalId().toString(), testEvent.getSurveyData()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
import gov.cdc.usds.simplereport.service.ResultsUploaderDeviceValidationService;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.temporal.TemporalAccessor;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
Expand Down Expand Up @@ -127,6 +129,17 @@ private Bundle convertRowToFhirBundle(TestResultRow row, UUID orgId) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("M/d/yyyy[ HH:mm]");

var testEventId = row.getAccessionNumber().getValue();

LocalDateTime testResultDate;
TemporalAccessor temporalAccessor =
dateTimeFormatter.parseBest(
row.getTestResultDate().getValue(), LocalDateTime::from, LocalDate::from);
if (temporalAccessor instanceof LocalDateTime) {
testResultDate = (LocalDateTime) temporalAccessor;
} else {
testResultDate = ((LocalDate) temporalAccessor).atStartOfDay();
}

var patientAddr =
new StreetAddress(
row.getPatientStreet().getValue(),
Expand Down Expand Up @@ -309,6 +322,9 @@ private Bundle convertRowToFhirBundle(TestResultRow row, UUID orgId) {
.testkitNameId(testKitNameId)
.equipmentUid(equipmentUid)
.deviceModel(row.getEquipmentModelName().getValue())
.issued(
Date.from(
testResultDate.atZone(zoneIdGenerator.getSystemZoneId()).toInstant()))
.build()));

LocalDate symptomOnsetDate = null;
Expand Down Expand Up @@ -336,13 +352,12 @@ private Bundle convertRowToFhirBundle(TestResultRow row, UUID orgId) {
testOrderLoinc,
uuidGenerator.randomUUID().toString());

var testDate = LocalDate.parse(row.getTestResultDate().getValue(), dateTimeFormatter);
var diagnosticReport =
fhirConverter.convertToDiagnosticReport(
mapTestResultStatusToFhirValue(row.getTestResultStatus().getValue()),
testPerformedCode,
testEventId,
Date.from(testDate.atStartOfDay(zoneIdGenerator.getSystemZoneId()).toInstant()),
Date.from(testResultDate.atZone(zoneIdGenerator.getSystemZoneId()).toInstant()),
dateGenerator.newDate());

return fhirConverter.createFhirBundle(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,7 @@ void convertToObservation_Strings_valid() {
.testkitNameId("testKitName")
.equipmentUid("equipmentUid")
.deviceModel("modelName")
.issued(Date.from(Instant.parse("2023-06-10T23:15:00.00Z")))
.build());

assertThat(actual.getId()).isEqualTo("id-123");
Expand All @@ -625,6 +626,7 @@ void convertToObservation_Strings_valid() {
.isEqualTo("resultCode");
assertThat(actual.getNote()).isEmpty();
assertThat(actual.getMethod().getCodingFirstRep().getDisplay()).isEqualTo("modelName");
assertThat(actual.getIssued()).isEqualTo("2023-06-10T23:15:00.00Z");
}

@Test
Expand All @@ -642,7 +644,8 @@ void convertToObservation_Result_valid() {
null,
"testkitName",
"equipmentUid",
"modelName");
"modelName",
Date.from(Instant.parse("2023-06-10T23:15:00.00Z")));

assertThat(actual.getId()).isEqualTo(internalId.toString());
assertThat(actual.getStatus().getDisplay()).isEqualTo(ObservationStatus.FINAL.getDisplay());
Expand All @@ -657,6 +660,7 @@ void convertToObservation_Result_valid() {
.isEqualTo("260373001");
assertThat(actual.getNote()).isEmpty();
assertThat(actual.getMethod().getCodingFirstRep().getDisplay()).isEqualTo("modelName");
assertThat(actual.getIssued()).isEqualTo("2023-06-10T23:15:00.00Z");
}

@Test
Expand All @@ -674,7 +678,8 @@ void convertToObservation_Result_correction() {
"Oopsy Daisy",
"testkitName",
"equipmentUid",
"modelName");
"modelName",
new Date());

assertThat(actual.getId()).isEqualTo(internalId.toString());
assertThat(actual.getStatus().getDisplay()).isEqualTo(ObservationStatus.CORRECTED.getDisplay());
Expand All @@ -697,7 +702,8 @@ void convertToObservation_Result_removeWithoutReason() {
null,
"testkitName",
"equipmentUid",
"modelName");
"modelName",
new Date());

assertThat(actual.getId()).isEqualTo(internalId.toString());
assertThat(actual.getStatus().getDisplay())
Expand All @@ -716,7 +722,8 @@ void convertToObservation_Result_null() {
null,
"testkitName",
"equipmentUid",
"modelName");
"modelName",
new Date());

assertThat(actual).isNull();
}
Expand All @@ -733,7 +740,8 @@ void convertToObservation_Result_nullDisease() {
null,
"testkitName",
"equipmentUid",
"modelName");
"modelName",
new Date());

assertThat(actual).isNull();
}
Expand Down Expand Up @@ -765,7 +773,11 @@ void convertToObservation_Result_matchesJson() throws IOException {

var actual =
fhirConverter.convertToObservation(
Set.of(covidResult, fluResult), device, TestCorrectionStatus.ORIGINAL, null);
Set.of(covidResult, fluResult),
device,
TestCorrectionStatus.ORIGINAL,
null,
Date.from(Instant.parse("2023-06-10T23:15:00.00Z")));

assertThat(actual).hasSize(2);
String covidSerialized =
Expand Down Expand Up @@ -815,7 +827,11 @@ void convertToObservation_Result_correctionMatchesJson() throws IOException {

var actual =
fhirConverter.convertToObservation(
Set.of(result), device, TestCorrectionStatus.CORRECTED, "woops");
Set.of(result),
device,
TestCorrectionStatus.CORRECTED,
"woops",
Date.from(Instant.parse("2023-06-10T23:15:00.00Z")));

String actualSerialized = parser.encodeResourceToString(actual.get(0));
var expectedSerialized1 =
Expand Down Expand Up @@ -936,7 +952,8 @@ void convertToDiagnosticReport_TestEvent_matchesJson() throws IOException {
StandardCharsets.UTF_8);
expectedSerialized =
expectedSerialized.replace(
"$EFFECTIVE_DATE_TIME_TESTED", new DateTimeType(date).getValueAsString());
"$EFFECTIVE_DATE_TIME_TESTED",
new DateTimeType(date).setTimeZoneZulu(true).getValueAsString());

JSONAssert.assertEquals(expectedSerialized, actualSerialized, true);
}
Expand All @@ -953,8 +970,8 @@ void convertToDiagnosticReport_Strings_valid() {
assertThat(actual.getCode().getCoding()).hasSize(1);
assertThat(actual.getCode().getCodingFirstRep().getSystem()).isEqualTo("http://loinc.org");
assertThat(actual.getCode().getCodingFirstRep().getCode()).isEqualTo("95422-2");
assertThat(((DateTimeType) actual.getEffective()).getAsV3())
.isEqualTo(new DateTimeType(date).getAsV3());
assertThat(((DateTimeType) actual.getEffective()).getValueAsString())
.isEqualTo(new DateTimeType(date).setTimeZoneZulu(true).getValueAsString());
assertThat((actual.getIssued())).isEqualTo(date);
}

Expand Down Expand Up @@ -1461,7 +1478,8 @@ void createFhirBundle_TestEvent_matchesJson() throws IOException {
expectedSerialized = expectedSerialized.replace("$PROVENANCE_ID", provenanceId);
expectedSerialized =
expectedSerialized.replace(
"$EFFECTIVE_DATE_TIME_TESTED", new DateTimeType(dateTested).getValueAsString());
"$EFFECTIVE_DATE_TIME_TESTED",
new DateTimeType(dateTested).setTimeZoneZulu(true).getValueAsString());
expectedSerialized =
expectedSerialized.replace(
"$PROVENANCE_RECORDED_DATE",
Expand Down
9 changes: 6 additions & 3 deletions backend/src/test/resources/fhir/bundle.json
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,8 @@
}
}
]
}
},
"issued": "$EFFECTIVE_DATE_TIME_TESTED"
}
},
{
Expand Down Expand Up @@ -522,7 +523,8 @@
}
}
]
}
},
"issued": "$EFFECTIVE_DATE_TIME_TESTED"
}
},
{
Expand Down Expand Up @@ -594,7 +596,8 @@
}
}
]
}
},
"issued": "$EFFECTIVE_DATE_TIME_TESTED"
}
},
{
Expand Down
3 changes: 2 additions & 1 deletion backend/src/test/resources/fhir/observationCorrection.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@
{
"text": "Corrected Result: woops"
}
]
],
"issued": "2023-06-10T23:15:00Z"
}
3 changes: 2 additions & 1 deletion backend/src/test/resources/fhir/observationCovid.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@
}
}
]
}
},
"issued": "2023-06-10T23:15:00Z"
}
3 changes: 2 additions & 1 deletion backend/src/test/resources/fhir/observationFlu.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,6 @@
}
}
]
}
},
"issued": "2023-06-10T23:15:00Z"
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
"subject": {
"reference": "Patient/1234"
},
"effectiveDateTime": "2021-12-20T00:00:00Z",
"effectiveDateTime": "2021-12-20T14:00:00Z",
"issued": "2023-05-24T19:33:06.472Z",
"specimen": [
{
Expand Down Expand Up @@ -486,7 +486,8 @@
},
"device": {
"reference": "Device/00000000-0000-0000-0000-000000000003"
}
},
"issued": "2021-12-20T14:00:00Z"
}
},
{
Expand Down

0 comments on commit e4df864

Please sign in to comment.