diff --git a/CHANGELOG.md b/CHANGELOG.md index 32d89a31d..1b83b9218 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,10 +20,13 @@ corresponding FHIR resource will now be [appropriately populated][nopat-docs]. corresponding FHIR resource will now be [appropriately populated][nopat-docs]. * If a `bloodPressure` record includes a `confidentialityCode`, the `meta.security` field of the corresponding FHIR resource will now be [appropriately populated][nopat-docs]. +* If a `Observation`, `Specimen`, `DiagnosticReport` record includes a `confidentialityCode`, the `meta.security` field of the + corresponding FHIR resource will now be [appropriately populated][nopat-docs]. * Addressed a bug in the PS adaptor where immunizations were incorrectly mapped to observations. The adaptor now verifies the Snomed CT ID against both the Concept ID and the Description ID, ensuring that immunizations are correctly identified when a match is found. + ### Fixed * Resolved issue where the SNOMED import script would reject a password containing a '%' character. * Fixed some Test Results being given a duplicated `Observation.category` entries for `Laboratory`. diff --git a/gp2gp-translator/src/integrationTest/java/uk/nhs/adaptors/pss/translator/mapper/ConditionMapperIT.java b/gp2gp-translator/src/integrationTest/java/uk/nhs/adaptors/pss/translator/mapper/ConditionMapperIT.java index c37a7021f..ab195721d 100644 --- a/gp2gp-translator/src/integrationTest/java/uk/nhs/adaptors/pss/translator/mapper/ConditionMapperIT.java +++ b/gp2gp-translator/src/integrationTest/java/uk/nhs/adaptors/pss/translator/mapper/ConditionMapperIT.java @@ -80,7 +80,6 @@ public static Stream ehrExtractsWithAllergyIntoleranceActualProblemCo Arguments.of("linkset-problem-allergy-in-category.xml"), Arguments.of("linkset-problem-allergy-flat.xml"), Arguments.of("linkset-problem-allergy-in-topic.xml") - ); } diff --git a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/ObservationMapper.java b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/ObservationMapper.java index 687b5a05d..b0d73dce8 100644 --- a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/ObservationMapper.java +++ b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/ObservationMapper.java @@ -8,6 +8,7 @@ import org.hl7.fhir.dstu3.model.CodeableConcept; import org.hl7.fhir.dstu3.model.DateTimeType; import org.hl7.fhir.dstu3.model.Encounter; +import org.hl7.fhir.dstu3.model.Meta; import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Period; @@ -18,14 +19,18 @@ import org.hl7.v3.CR; import org.hl7.v3.CV; import org.hl7.v3.RCMRMT030101UKAnnotation; +import org.hl7.v3.RCMRMT030101UKCompoundStatement; import org.hl7.v3.RCMRMT030101UKEhrComposition; import org.hl7.v3.RCMRMT030101UKEhrExtract; import org.hl7.v3.RCMRMT030101UKObservationStatement; import org.hl7.v3.RCMRMT030101UKPertinentInformation02; import org.hl7.v3.RCMRMT030101UKRequestStatement; import org.hl7.v3.RCMRMT030101UKSubject; +import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import uk.nhs.adaptors.pss.translator.service.ConfidentialityService; +import uk.nhs.adaptors.pss.translator.util.CompoundStatementResourceExtractors; import uk.nhs.adaptors.pss.translator.util.DatabaseImmunizationChecker; import uk.nhs.adaptors.pss.translator.util.DegradedCodeableConcepts; @@ -40,7 +45,6 @@ import java.util.stream.Stream; import static org.hl7.fhir.dstu3.model.Observation.ObservationStatus.FINAL; - import static uk.nhs.adaptors.pss.translator.util.CompoundStatementResourceExtractors.extractAllObservationStatementsWithoutAllergiesAndBloodPressures; import static uk.nhs.adaptors.pss.translator.util.CompoundStatementResourceExtractors.extractAllRequestStatements; import static uk.nhs.adaptors.pss.translator.util.ObservationUtil.getEffective; @@ -50,7 +54,6 @@ import static uk.nhs.adaptors.pss.translator.util.ObservationUtil.getValueQuantity; import static uk.nhs.adaptors.pss.translator.util.ParticipantReferenceUtil.getParticipantReference; import static uk.nhs.adaptors.pss.translator.util.ResourceUtil.buildIdentifier; -import static uk.nhs.adaptors.pss.translator.util.ResourceUtil.generateMeta; import static uk.nhs.adaptors.pss.translator.util.ResourceUtil.addContextToObservation; @Service @@ -66,6 +69,7 @@ public class ObservationMapper extends AbstractMapper { private final CodeableConceptMapper codeableConceptMapper; private final DatabaseImmunizationChecker immunizationChecker; + private final ConfidentialityService confidentialityService; public List mapResources(RCMRMT030101UKEhrExtract ehrExtract, Patient patient, List encounters, String practiseCode) { @@ -93,12 +97,43 @@ public List mapResources(RCMRMT030101UKEhrExtract ehrExtract, Patie } private Observation mapObservation(RCMRMT030101UKEhrComposition ehrComposition, - RCMRMT030101UKObservationStatement observationStatement, Patient patient, List encounters, + RCMRMT030101UKObservationStatement observationStatement, + Patient patient, + List encounters, String practiseCode) { + var compoundStatement = ehrComposition + .getComponent() + .stream() + .flatMap(CompoundStatementResourceExtractors::extractAllCompoundStatements) + .filter(Objects::nonNull) + .findFirst().orElseGet(RCMRMT030101UKCompoundStatement::new); + var id = observationStatement.getId().getRoot(); + var meta = confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + observationStatement.getConfidentialityCode(), + compoundStatement.getConfidentialityCode()); - Observation observation = new Observation() + var observation = buildBaseObservation(ehrComposition, observationStatement, patient, practiseCode, id, meta); + + addContextToObservation(observation, encounters, ehrComposition); + addValue(observation, getValueQuantity(observationStatement.getValue(), observationStatement.getUncertaintyCode()), + getValueString(observationStatement.getValue())); + addEffective(observation, + getEffective(observationStatement.getEffectiveTime(), observationStatement.getAvailabilityTime())); + + return observation; + } + + private @NotNull Observation buildBaseObservation(RCMRMT030101UKEhrComposition ehrComposition, + RCMRMT030101UKObservationStatement observationStatement, + Patient patient, + String practiseCode, + String id, + Meta meta) { + var observation = new Observation() .setStatus(FINAL) .addIdentifier(buildIdentifier(id, practiseCode)) .setCode(getCode(observationStatement.getCode())) @@ -106,25 +141,23 @@ private Observation mapObservation(RCMRMT030101UKEhrComposition ehrComposition, .addPerformer(getParticipantReference(observationStatement.getParticipant(), ehrComposition)) .setInterpretation(getInterpretation(observationStatement.getInterpretationCode())) .setComment(getComment( - observationStatement.getPertinentInformation(), - observationStatement.getSubject(), - observationStatement.getCode(), - Optional.of(Optional.ofNullable(observationStatement.getCode()) - .map(CD::getQualifier) - .orElse(Collections.emptyList())) + observationStatement.getPertinentInformation(), + observationStatement.getSubject(), + observationStatement.getCode(), + Optional.of(getQualifiers(observationStatement)) )) .setReferenceRange(getReferenceRange(observationStatement.getReferenceRange())) - .setSubject(new Reference(patient)); - observation.setId(id); - observation.setMeta(generateMeta(META_PROFILE)); + .setSubject(new Reference(patient)) + .setMeta(meta) + .setId(id); - addContextToObservation(observation, encounters, ehrComposition); - addValue(observation, getValueQuantity(observationStatement.getValue(), observationStatement.getUncertaintyCode()), - getValueString(observationStatement.getValue())); - addEffective(observation, - getEffective(observationStatement.getEffectiveTime(), observationStatement.getAvailabilityTime())); + return (Observation) observation; + } - return observation; + private static @NotNull List getQualifiers(RCMRMT030101UKObservationStatement observationStatement) { + return Optional.ofNullable(observationStatement.getCode()) + .map(CD::getQualifier) + .orElse(Collections.emptyList()); } private Observation mapObservationFromRequestStatement(RCMRMT030101UKEhrComposition ehrComposition, @@ -132,6 +165,11 @@ private Observation mapObservationFromRequestStatement(RCMRMT030101UKEhrComposit List encounters, String practiseCode) { var id = requestStatement.getId().get(0).getRoot(); + var meta = confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + requestStatement.getConfidentialityCode()); + Observation observation = new Observation() .setStatus(FINAL) @@ -144,7 +182,7 @@ private Observation mapObservationFromRequestStatement(RCMRMT030101UKEhrComposit .setComponent(createComponentList(requestStatement)); observation.setId(id); - observation.setMeta(generateMeta(META_PROFILE)); + observation.setMeta(meta); addContextToObservation(observation, encounters, ehrComposition); addEffective(observation, diff --git a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/DiagnosticReportMapper.java b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/DiagnosticReportMapper.java index 272cf0fd9..e24b7fbe0 100644 --- a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/DiagnosticReportMapper.java +++ b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/DiagnosticReportMapper.java @@ -6,7 +6,6 @@ import static uk.nhs.adaptors.pss.translator.util.CompoundStatementResourceExtractors.extractAllCompoundStatements; import static uk.nhs.adaptors.pss.translator.util.DateFormatUtil.parseToInstantType; import static uk.nhs.adaptors.pss.translator.util.ResourceUtil.buildIdentifier; -import static uk.nhs.adaptors.pss.translator.util.ResourceUtil.generateMeta; import static uk.nhs.adaptors.pss.translator.util.TextUtil.extractPmipComment; import java.util.ArrayList; @@ -41,6 +40,7 @@ import org.springframework.stereotype.Service; import uk.nhs.adaptors.pss.translator.mapper.AbstractMapper; +import uk.nhs.adaptors.pss.translator.service.ConfidentialityService; import uk.nhs.adaptors.pss.translator.service.IdGeneratorService; import uk.nhs.adaptors.pss.translator.util.CompoundStatementResourceExtractors; import uk.nhs.adaptors.pss.translator.util.ResourceFilterUtil; @@ -51,7 +51,7 @@ @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class DiagnosticReportMapper extends AbstractMapper { private static final String PMIP_EXTENSION_IDENTIFIER_ROOT = "2.16.840.1.113883.2.1.4.5.5"; - private static final String META_PROFILE_URL_SUFFIX = "DiagnosticReport-1"; + private static final String META_PROFILE = "DiagnosticReport-1"; public static final String CODING_CODE = "721981007"; public static final String CODING_SYSTEM = "http://snomed.info/sct"; public static final String CODING_DISPLAY = "Diagnostic studies report"; @@ -61,6 +61,7 @@ public class DiagnosticReportMapper extends AbstractMapper { public static final String USER_COMMENT_COMMENT_TYPE = "CommentType:USER COMMENT"; private final IdGeneratorService idGeneratorService; + private final ConfidentialityService confidentialityService; public static void addResultToDiagnosticReport(Observation observation, DiagnosticReport diagnosticReport) { if (!containsReference(diagnosticReport.getResult(), observation.getId())) { @@ -126,7 +127,12 @@ private DiagnosticReport createDiagnosticReport(RCMRMT030101UKCompoundStatement final DiagnosticReport diagnosticReport = new DiagnosticReport(); final String id = compoundStatement.getId().get(0).getRoot(); - diagnosticReport.setMeta(generateMeta(META_PROFILE_URL_SUFFIX)); + var meta = confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + composition.getConfidentialityCode(), + compoundStatement.getConfidentialityCode()); + + diagnosticReport.setMeta(meta); diagnosticReport.setId(id); diagnosticReport.addIdentifier(buildIdentifier(id, practiceCode)); diagnosticReport.setCode(createCode()); diff --git a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenCompoundsMapper.java b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenCompoundsMapper.java index c8283b14a..fe19a3f4a 100644 --- a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenCompoundsMapper.java +++ b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenCompoundsMapper.java @@ -33,6 +33,7 @@ import lombok.RequiredArgsConstructor; import uk.nhs.adaptors.pss.translator.mapper.diagnosticreport.SpecimenBatteryMapper.SpecimenBatteryParameters; +import uk.nhs.adaptors.pss.translator.service.ConfidentialityService; import uk.nhs.adaptors.pss.translator.util.CompoundStatementResourceExtractors; import uk.nhs.adaptors.pss.translator.util.DateFormatUtil; @@ -49,8 +50,10 @@ public class SpecimenCompoundsMapper { public static final String CODING_CODE = "laboratory"; public static final String CODING_SYSTEM = "http://hl7.org/fhir/observation-category"; public static final String CODING_DISPLAY = "Laboratory"; + private static final String META_PROFILE = "Observation-1"; private final SpecimenBatteryMapper batteryMapper; + private final ConfidentialityService confidentialityService; public List handleSpecimenChildComponents( RCMRMT030101UKEhrExtract ehrExtract, @@ -59,8 +62,8 @@ public List handleSpecimenChildComponents( List diagnosticReports, Patient patient, List encounters, - String practiseCode - ) { + String practiseCode) { + final List batteryObservations = new ArrayList<>(); for (var diagnosticReport : diagnosticReports) { @@ -69,14 +72,17 @@ public List handleSpecimenChildComponents( continue; } + var ehrComposition = getCurrentEhrComposition(ehrExtract, diagnosticReportCompoundStatement.orElseThrow()); + for (var specimenCompoundStatement : getSpecimenCompoundStatements(diagnosticReportCompoundStatement.get())) { - handleSpecimenObservationStatement(observations, diagnosticReport, specimenCompoundStatement); + handleSpecimenObservationStatement(ehrComposition, observations, diagnosticReport, specimenCompoundStatement); var nestedSpecimenCompoundStatements = getNestedSpecimenCompoundStatements(specimenCompoundStatement); for (var nestedSpecimenCompoundStatement : nestedSpecimenCompoundStatements) { - if (CLUSTER_CLASSCODE.equals(nestedSpecimenCompoundStatement.getClassCode().get(0))) { + if (CLUSTER_CLASSCODE.equals(nestedSpecimenCompoundStatement.getClassCode().getFirst())) { handleClusterCompoundStatement( + ehrComposition, specimenCompoundStatement, nestedSpecimenCompoundStatement, observations, @@ -86,8 +92,9 @@ public List handleSpecimenChildComponents( ); } - if (BATTERY_CLASSCODE.equals(nestedSpecimenCompoundStatement.getClassCode().get(0))) { + if (BATTERY_CLASSCODE.equals(nestedSpecimenCompoundStatement.getClassCode().getFirst())) { handleBatteryCompoundStatement( + ehrComposition, specimenCompoundStatement, nestedSpecimenCompoundStatement, observations, @@ -99,7 +106,7 @@ public List handleSpecimenChildComponents( .ehrExtract(ehrExtract) .batteryCompoundStatement(nestedSpecimenCompoundStatement) .specimenCompoundStatement(specimenCompoundStatement) - .ehrComposition(getCurrentEhrComposition(ehrExtract, diagnosticReportCompoundStatement.orElseThrow())) + .ehrComposition(ehrComposition) .diagnosticReport(diagnosticReport) .patient(patient) .encounters(encounters) @@ -118,8 +125,8 @@ public List handleSpecimenChildComponents( } private static @NotNull List getNestedSpecimenCompoundStatements( - RCMRMT030101UKCompoundStatement specimenCompoundStatement - ) { + RCMRMT030101UKCompoundStatement specimenCompoundStatement) { + return specimenCompoundStatement.getComponent() .stream() .filter(RCMRMT030101UKComponent02::hasCompoundStatement) @@ -129,20 +136,29 @@ public List handleSpecimenChildComponents( } private void handleSpecimenObservationStatement( + RCMRMT030101UKEhrComposition ehrComposition, List observations, DiagnosticReport diagnosticReport, - RCMRMT030101UKCompoundStatement specimenCompoundStatement - ) { + RCMRMT030101UKCompoundStatement specimenCompoundStatement) { + getObservationStatementsInCompound(specimenCompoundStatement).forEach(specimenObservationStatement -> getObservationById(observations, specimenObservationStatement.getId().getRoot()) .ifPresent(observation -> { - handleObservationStatement(specimenCompoundStatement, specimenObservationStatement, observation); + handleObservationStatement(ehrComposition, specimenCompoundStatement, specimenObservationStatement, observation); DiagnosticReportMapper.addResultToDiagnosticReport(observation, diagnosticReport); })); } - private void handleObservationStatement(RCMRMT030101UKCompoundStatement specimenCompoundStatement, - RCMRMT030101UKObservationStatement observationStatement, Observation observation) { + private void handleObservationStatement(RCMRMT030101UKEhrComposition ehrComposition, + RCMRMT030101UKCompoundStatement specimenCompoundStatement, + RCMRMT030101UKObservationStatement observationStatement, + Observation observation) { + + var meta = confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + specimenCompoundStatement.getConfidentialityCode()); + final Reference specimenReference = new Reference(new IdType( Specimen.name(), specimenCompoundStatement.getId().get(0).getRoot() @@ -156,6 +172,7 @@ private void handleObservationStatement(RCMRMT030101UKCompoundStatement specimen } observation.setSpecimen(specimenReference); observation.addCategory(createCategory()); + observation.setMeta(meta); } private void handleNarrativeStatements(RCMRMT030101UKCompoundStatement compoundStatement, @@ -165,15 +182,22 @@ private void handleNarrativeStatements(RCMRMT030101UKCompoundStatement compoundS getNarrativeStatementsInCompound(compoundStatement).forEach(childNarrativeStatement -> { + var meta = confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + compoundStatement.getConfidentialityCode(), + childNarrativeStatement.getConfidentialityCode()); + if (childNarrativeStatement.getText().contains(USER_COMMENT_HEADER)) { getObservationById(observationComments, childNarrativeStatement.getId().getRoot()) .ifPresent(observationComment -> { observationComment.setEffective(null); observationComment.setComment(extractPmipComment(observationComment.getComment())); + observationComment.setMeta(meta); createRelationship(observation, observationComment); }); } else if (observation != null) { observation.setComment(addLine(observation.getComment(), extractPmipComment(childNarrativeStatement.getText()))); + observation.setMeta(meta); getObservationById(observationComments, childNarrativeStatement.getId().getRoot()) .ifPresent(surplusObservationComments::add); @@ -190,9 +214,11 @@ private void createRelationship(Observation observation, Observation observation } } - private void handleClusterCompoundStatement(RCMRMT030101UKCompoundStatement specimenCompoundStatement, - RCMRMT030101UKCompoundStatement clusterCompoundStatement, - List observations, List observationComments, DiagnosticReport diagnosticReport, boolean isNestedCluster) { + private void handleClusterCompoundStatement(RCMRMT030101UKEhrComposition ehrComposition, + RCMRMT030101UKCompoundStatement specimenCompoundStatement, + RCMRMT030101UKCompoundStatement clusterCompoundStatement, + List observations, List observationComments, + DiagnosticReport diagnosticReport, boolean isNestedCluster) { var nestedObservationStatements = clusterCompoundStatement.getComponent().stream() .filter(RCMRMT030101UKComponent02::hasObservationStatement) @@ -206,14 +232,15 @@ private void handleClusterCompoundStatement(RCMRMT030101UKCompoundStatement spec if (!isNestedCluster) { DiagnosticReportMapper.addResultToDiagnosticReport(observation, diagnosticReport); } - handleObservationStatement(specimenCompoundStatement, observationStatement, observation); + handleObservationStatement(ehrComposition, specimenCompoundStatement, observationStatement, observation); }); handleNarrativeStatements(clusterCompoundStatement, observationComments, observationOpt.orElse(null)); } } - private void handleBatteryCompoundStatement(RCMRMT030101UKCompoundStatement specimenCompoundStatement, + private void handleBatteryCompoundStatement(RCMRMT030101UKEhrComposition ehrComposition, + RCMRMT030101UKCompoundStatement specimenCompoundStatement, RCMRMT030101UKCompoundStatement batteryCompoundStatement, List observations, List observationComments, @@ -225,6 +252,7 @@ private void handleBatteryCompoundStatement(RCMRMT030101UKCompoundStatement spec .filter(compoundStatement -> CLUSTER_CLASSCODE.equals(compoundStatement.getClassCode().get(0))) .forEach(compoundStatement -> handleClusterCompoundStatement( + ehrComposition, specimenCompoundStatement, compoundStatement, observations, @@ -237,8 +265,8 @@ private void handleBatteryCompoundStatement(RCMRMT030101UKCompoundStatement spec .map(RCMRMT030101UKComponent02::getObservationStatement) .forEach( observationStatement -> getObservationById(observations, observationStatement.getId().getRoot()).ifPresent( - observation -> handleObservationStatement(specimenCompoundStatement, observationStatement, observation))); - + observation -> handleObservationStatement(ehrComposition, specimenCompoundStatement, + observationStatement, observation))); } private Optional getCompoundStatementByDRId(RCMRMT030101UKEhrExtract ehrExtract, String id) { @@ -292,7 +320,7 @@ private List getObservationStatementsInCompo .toList(); } - private List getNarrativeStatementsInCompound( + protected List getNarrativeStatementsInCompound( RCMRMT030101UKCompoundStatement compoundStatement) { return compoundStatement.getComponent() diff --git a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenMapper.java b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenMapper.java index 834ae0913..5c27dbab7 100644 --- a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenMapper.java +++ b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenMapper.java @@ -2,7 +2,6 @@ import static uk.nhs.adaptors.pss.translator.util.CDUtil.extractSnomedCode; import static uk.nhs.adaptors.pss.translator.util.ResourceUtil.buildIdentifier; -import static uk.nhs.adaptors.pss.translator.util.ResourceUtil.generateMeta; import static uk.nhs.adaptors.pss.translator.util.TextUtil.extractPmipComment; import java.util.List; @@ -21,6 +20,8 @@ import org.hl7.fhir.dstu3.model.Specimen; import org.hl7.fhir.dstu3.model.Specimen.SpecimenCollectionComponent; import org.hl7.v3.RCMRMT030101UKComponent02; +import org.hl7.v3.RCMRMT030101UKComponent3; +import org.hl7.v3.RCMRMT030101UKEhrComposition; import org.hl7.v3.RCMRMT030101UKEhrExtract; import org.hl7.v3.RCMRMT030101UKCompoundStatement; import org.hl7.v3.RCMRMT030101UKSpecimenRole; @@ -29,6 +30,7 @@ import lombok.RequiredArgsConstructor; import uk.nhs.adaptors.pss.translator.mapper.DateTimeMapper; +import uk.nhs.adaptors.pss.translator.service.ConfidentialityService; import uk.nhs.adaptors.pss.translator.util.CompoundStatementResourceExtractors; @Service @@ -38,6 +40,7 @@ public class SpecimenMapper { private static final String SPECIMEN_META_PROFILE_SUFFIX = "Specimen-1"; private static final String REFERENCE_PREFIX = "Specimen/"; private static final String SPECIMEN_CODE = "123038009"; + private final ConfidentialityService confidentialityService; private final DateTimeMapper dateTimeMapper; @@ -53,7 +56,10 @@ public List mapSpecimens(RCMRMT030101UKEhrExtract ehrExtract, List createSpecimen(childCompoundStatement, patient, practiceCode)) + .map(childCompoundStatement -> { + var ehrComposition = getEhrComposition(ehrExtract, childCompoundStatement); + return createSpecimen(ehrComposition, childCompoundStatement, patient, practiceCode); + }) .toList(); } @@ -78,15 +84,24 @@ public List removeSurplusObservationComments(RCMRMT030101UKEhrExtra return observationComments; } - private Specimen createSpecimen(RCMRMT030101UKCompoundStatement specimenCompoundStatement, Patient patient, String practiceCode) { + private Specimen createSpecimen(RCMRMT030101UKEhrComposition ehrComposition, + RCMRMT030101UKCompoundStatement specimenCompoundStatement, + Patient patient, String practiceCode) { + + var meta = confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + SPECIMEN_META_PROFILE_SUFFIX, + ehrComposition.getConfidentialityCode(), + specimenCompoundStatement.getConfidentialityCode()); Specimen specimen = new Specimen(); - final String id = specimenCompoundStatement.getId().get(0).getRoot(); - specimen.setId(id); - specimen.setMeta(generateMeta(SPECIMEN_META_PROFILE_SUFFIX)); - specimen.addIdentifier(buildIdentifier(id, practiceCode)); - specimen.setSubject(new Reference(patient)); - specimen.setNote(getNote(specimenCompoundStatement)); + final String id = specimenCompoundStatement.getId().getFirst().getRoot(); + + specimen.addIdentifier(buildIdentifier(id, practiceCode)) + .setSubject(new Reference(patient)) + .setNote(getNote(specimenCompoundStatement)) + .setId(id) + .setMeta(meta); + getAccessionIdentifier(specimenCompoundStatement).ifPresent(specimen::setAccessionIdentifier); getType(specimenCompoundStatement).ifPresent(specimen::setType); getCollectedDateTime(specimenCompoundStatement).ifPresent(specimen::setCollection); @@ -147,14 +162,14 @@ private Optional getAccessionIdentifier(RCMRMT030101UKCompoundStatem private Optional getSpecimenRole(RCMRMT030101UKCompoundStatement specimenCompoundStatement) { return !specimenCompoundStatement.getSpecimen().isEmpty() - ? Optional.ofNullable(specimenCompoundStatement.getSpecimen().get(0).getSpecimenRole()) + ? Optional.ofNullable(specimenCompoundStatement.getSpecimen().getFirst().getSpecimenRole()) : Optional.empty(); } private Optional getParentCompoundStatementByChildId( RCMRMT030101UKEhrExtract ehrExtract, String id) { - return ehrExtract.getComponent().get(0).getEhrFolder().getComponent().stream() + return ehrExtract.getComponent().getFirst().getEhrFolder().getComponent().stream() .flatMap(component3 -> component3.getEhrComposition().getComponent().stream()) .flatMap(CompoundStatementResourceExtractors::extractAllCompoundStatements) .filter(Objects::nonNull) @@ -162,13 +177,13 @@ private Optional getParentCompoundStatementByCh .stream() .map(RCMRMT030101UKComponent02::getCompoundStatement) .filter(Objects::nonNull) - .anyMatch(e -> id.equals(e.getId().get(0).getRoot())) + .anyMatch(e -> id.equals(e.getId().getFirst().getRoot())) ).findFirst(); } private List findAllSpecimenCompoundStatements(RCMRMT030101UKEhrExtract ehrExtract) { - var topLevelComponents = ehrExtract.getComponent().get(0).getEhrFolder().getComponent().stream() + var topLevelComponents = ehrExtract.getComponent().getFirst().getEhrFolder().getComponent().stream() .flatMap(component3 -> component3.getEhrComposition().getComponent().stream()) .toList(); @@ -182,4 +197,18 @@ private List findAllSpecimenCompoundStatements( }) .toList(); } + + private RCMRMT030101UKEhrComposition getEhrComposition(RCMRMT030101UKEhrExtract ehrExtract, + RCMRMT030101UKCompoundStatement parentCompoundStatement) { + + return ehrExtract.getComponent().getFirst().getEhrFolder().getComponent() + .stream() + .filter(RCMRMT030101UKComponent3::hasEhrComposition) + .map(RCMRMT030101UKComponent3::getEhrComposition) + .filter(ehrComposition -> ehrComposition.getComponent() + .stream() + .flatMap(CompoundStatementResourceExtractors::extractAllCompoundStatements) + .anyMatch(parentCompoundStatement::equals)) + .findFirst().get(); + } } diff --git a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/service/BundleMapperService.java b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/service/BundleMapperService.java index fefba2c8c..3662dc1c4 100644 --- a/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/service/BundleMapperService.java +++ b/gp2gp-translator/src/main/java/uk/nhs/adaptors/pss/translator/service/BundleMapperService.java @@ -185,8 +185,8 @@ private void mapDiagnosticReports(Bundle bundle, RCMRMT030101UKEhrExtract ehrExt private List handleMappedEncounterResources( Map> mappedEncounterEhrCompositions, - Bundle bundle - ) { + Bundle bundle) { + var encounters = (List) mappedEncounterEhrCompositions.get(ENCOUNTER_KEY); var consultations = (List) mappedEncounterEhrCompositions.get(CONSULTATION_KEY); var topics = (List) mappedEncounterEhrCompositions.get(TOPIC_KEY); @@ -220,8 +220,7 @@ private List mapLocations(RCMRMT030101UKEhrFolder ehrFolder, String lo .map( ehrComposition -> locationMapper.mapToLocation( ehrComposition.getLocation(), - losingPracticeOdsCode - ) + losingPracticeOdsCode) ) .collect( Collectors.collectingAndThen( diff --git a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/ObservationMapperTest.java b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/ObservationMapperTest.java index a3389073d..107a2018a 100644 --- a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/ObservationMapperTest.java +++ b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/ObservationMapperTest.java @@ -1,28 +1,41 @@ package uk.nhs.adaptors.pss.translator.mapper; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; import static org.springframework.util.ResourceUtils.getFile; +import static uk.nhs.adaptors.pss.translator.MetaFactory.MetaType.META_WITH_SECURITY; +import static uk.nhs.adaptors.pss.translator.util.CompoundStatementResourceExtractors.extractAllCompoundStatements; import static uk.nhs.adaptors.pss.translator.util.XmlUnmarshallUtil.unmarshallFile; import java.math.BigDecimal; import java.util.List; +import java.util.Optional; import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.dstu3.model.CodeableConcept; +import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.DateTimeType; import org.hl7.fhir.dstu3.model.Encounter; +import org.hl7.fhir.dstu3.model.Meta; import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.Observation.ObservationStatus; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Period; import org.hl7.fhir.dstu3.model.Quantity; import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.dstu3.model.UriType; +import org.hl7.v3.CV; +import org.hl7.v3.RCMRMT030101UKComponent02; +import org.hl7.v3.RCMRMT030101UKEhrComposition; import org.hl7.v3.RCMRMT030101UKEhrExtract; +import org.hl7.v3.RCMRMT030101UKObservationStatement; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -30,6 +43,9 @@ import org.mockito.junit.jupiter.MockitoExtension; import lombok.SneakyThrows; +import uk.nhs.adaptors.pss.translator.MetaFactory; +import uk.nhs.adaptors.pss.translator.TestUtility; +import uk.nhs.adaptors.pss.translator.service.ConfidentialityService; import uk.nhs.adaptors.pss.translator.util.DatabaseImmunizationChecker; import uk.nhs.adaptors.pss.translator.util.DegradedCodeableConcepts; @@ -40,7 +56,6 @@ public class ObservationMapperTest { private static final String XML_RESOURCES_BASE = "xml/Observation/"; private static final String EXAMPLE_ID = "263B2A9F-0B1D-4697-943A-328F70E068DE"; - private static final String META_PROFILE = "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Observation-1"; private static final String PRACTISE_CODE = "TESTPRACTISECODE"; private static final String IDENTIFIER_SYSTEM = "https://PSSAdaptor/TESTPRACTISECODE"; private static final String INTERPRETATION_SYSTEM = "http://hl7.org/fhir/v2/0078"; @@ -67,10 +82,19 @@ public class ObservationMapperTest { "{Episodicity : code=255217005, displayName=First}"; private static final String EPISODICITY_WITH_ORIGINAL_TEXT_NOTE_TEXT_WITH_ORIGINAL_TEXT = "{Episodicity : code=303350001, displayName=Ongoing, originalText=Review}"; + private static final String META_PROFILE = "Observation-1"; + private static final Meta META = MetaFactory.getMetaFor(META_WITH_SECURITY, META_PROFILE); + private static final CV NOPAT_CV = TestUtility.createCv( + "NOPAT", + "http://hl7.org/fhir/v3/ActCode", + "no disclosure to patient, family or caregivers without attending provider's authorization"); @Mock private CodeableConceptMapper codeableConceptMapper; + @Mock + private ConfidentialityService confidentialityService; + @Mock private DatabaseImmunizationChecker immunizationChecker; @@ -80,9 +104,96 @@ public class ObservationMapperTest { @InjectMocks private ObservationMapper observationMapper; + @Test + public void mapTwoObservationsWrappedInCompoundStatementMetaSecurityWithNoPapExpectObservationsWithNoPat() { + var ehrExtract = unmarshallEhrExtractElement("nopat_compound_statement_with_observation.xml"); + + var ehrComposition = getEhrComposition(ehrExtract); + var observationStatements = getObservationStatementIncludedIntoCompoundStatement(ehrExtract); + var compoundStatement = ehrComposition + .getComponent() + .stream() + .flatMap(component4 -> extractAllCompoundStatements(component4)) + .findFirst().get(); + + observationStatements.getFirst().setConfidentialityCode(NOPAT_CV); + ehrComposition.setConfidentialityCode(NOPAT_CV); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + observationStatements.get(0).getConfidentialityCode(), + compoundStatement.getConfidentialityCode() + )).thenReturn(META); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + observationStatements.get(1).getConfidentialityCode(), + compoundStatement.getConfidentialityCode() + )).thenReturn(META); + + var observations = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE); + + assertThat(observations).hasSize(2); + assertMetaSecurityIsPresent(observations.get(0).getMeta()); + assertMetaSecurityIsPresent(observations.get(1).getMeta()); + } + + @Test + public void mapObservationMetaSecurityWithNoPatWhenConfidentialityCodeIsPresentForObservationStatementAndEhrComposition() { + var ehrExtract = unmarshallEhrExtractElement("full_valid_data_observation_example.xml"); + + var ehrComposition = getEhrComposition(ehrExtract); + ehrComposition.setConfidentialityCode(NOPAT_CV); + + var observationStatement = getObservationStatement(ehrExtract); + observationStatement.setConfidentialityCode(NOPAT_CV); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + observationStatement.getConfidentialityCode(), + Optional.empty() + )).thenReturn(META); + + var observation = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE).getFirst(); + + assertMetaSecurityIsPresent(observation.getMeta()); + } + + @Test + public void mapObservationMetaSecurityWithNoPatWhenConfidentialityCodeIsPresentOnlyForEhrComposition() { + var ehrExtract = unmarshallEhrExtractElement("full_valid_data_observation_example.xml"); + + var ehrComposition = getEhrComposition(ehrExtract); + ehrComposition.setConfidentialityCode(NOPAT_CV); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + Optional.empty(), + Optional.empty() + )).thenReturn(META); + + var observation = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE).get(0); + + assertMetaSecurityIsPresent(observation.getMeta()); + } + @Test public void mapObservationWithValidData() { var ehrExtract = unmarshallEhrExtractElement("full_valid_data_observation_example.xml"); + var ehrComposition = getEhrComposition(ehrExtract); + var observationStatement = getObservationStatement(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + observationStatement.getConfidentialityCode(), + Optional.empty() + )).thenReturn(META); + var observation = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE).get(0); assertFixedValues(observation); @@ -98,7 +209,7 @@ public void mapObservationWithValidData() { assertThat(observation.getReferenceRange().get(0).getText()).isEqualTo("Age and sex based"); assertQuantity(observation.getReferenceRange().get(0).getLow(), REFERENCE_RANGE_LOW_VALUE, "liter", "L"); assertQuantity(observation.getReferenceRange().get(0).getHigh(), REFERENCE_RANGE_HIGH_VALUE, "liter", "L"); - assertThat(observation.hasSubject()).isTrue(); + assertTrue(observation.hasSubject()); } /** @@ -108,6 +219,16 @@ public void mapObservationWithValidData() { @Test public void mapObservationWithEpisodicity() { var ehrExtract = unmarshallEhrExtractElement("data_observation_with_episodicity.xml"); + var ehrComposition = getEhrComposition(ehrExtract); + var observationStatement = getObservationStatement(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + observationStatement.getConfidentialityCode(), + Optional.empty() + )).thenReturn(META); + var observation = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE).get(0); assertFixedValues(observation); @@ -120,6 +241,16 @@ public void mapObservationWithEpisodicity() { @Test public void mapObservationWithEpisodicityWithOriginalText() { var ehrExtract = unmarshallEhrExtractElement("data_observation_with_episodicity_with_original_text.xml"); + var ehrComposition = getEhrComposition(ehrExtract); + var observationStatement = getObservationStatement(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + observationStatement.getConfidentialityCode(), + Optional.empty() + )).thenReturn(META); + var observation = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE).get(0); assertFixedValues(observation); @@ -128,6 +259,16 @@ public void mapObservationWithEpisodicityWithOriginalText() { @Test public void mapObservationWithEpisodicityWithOriginalTextAndExistingComment() { var ehrExtract = unmarshallEhrExtractElement("data_observation_with_episodicity_with_existing_comment.xml"); + var ehrComposition = getEhrComposition(ehrExtract); + var observationStatement = getObservationStatement(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + observationStatement.getConfidentialityCode(), + Optional.empty() + )).thenReturn(META); + var observation = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE).get(0); assertFixedValues(observation); @@ -153,19 +294,28 @@ public void mappingObservationWhichIsBloodPressureExpectObservationNotMapped() { @Test public void mapObservationWithNoOptionalData() { - //when(codeableConceptMapper.mapToCodeableConcept(any())).thenReturn(CODEABLE_CONCEPT); + var ehrExtract = unmarshallEhrExtractElement("no_optional_data_observation_example.xml"); + var ehrComposition = getEhrComposition(ehrExtract); + var observationStatement = getObservationStatement(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + observationStatement.getConfidentialityCode(), + Optional.empty() + )).thenReturn(META); + var observation = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE).get(0); assertFixedValues(observation); assertThat(observation.getId()).isEqualTo(EXAMPLE_ID); - //assertThat(observation.getCode().getCodingFirstRep().getDisplay()).isEqualTo(CODING_DISPLAY_MOCK); assertThat(observation.getIssuedElement().asStringValue()).isEqualTo(ISSUED_EHR_COMPOSITION_EXAMPLE); assertThat(observation.getPerformer().get(0).getReference()).isEqualTo(PPRF_PARTICIPANT_ID); - assertThat(observation.getEffective()).isNull(); - assertThat(observation.getValue()).isNull(); + assertNull(observation.getEffective()); + assertNull(observation.getValue()); assertThat(observation.getInterpretation().getCoding()).isEmpty(); - assertThat(observation.getComment()).isNull(); + assertNull(observation.getComment()); assertThat(observation.getReferenceRange()).isEmpty(); } @@ -200,7 +350,7 @@ public void mapObservationWithCompositionIdMatchingEncounter() { var ehrExtract = unmarshallEhrExtractElement("ehr_composition_id_matching_encounter_observation_example.xml"); var observation = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE).get(0); - assertThat(observation.hasContext()).isTrue(); + assertTrue(observation.hasContext()); } @Test @@ -209,7 +359,7 @@ public void mapObservationWithEffectiveDateTime() { "effective_date_time_type_using_effective_time_center.xml"); var observation = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE).get(0); - assertThat(observation.getEffective() instanceof DateTimeType); + assertTrue(observation.getEffective() instanceof DateTimeType); assertThat(observation.getEffectiveDateTimeType().getValueAsString()).isEqualTo("2010-05-21"); } @@ -219,7 +369,7 @@ public void mapObservationWithEffectivePeriod() { "effective_period_start_end_using_effective_time_observation_example.xml"); var observation = observationMapper.mapResources(ehrExtract, patient, ENCOUNTER_LIST, PRACTISE_CODE).get(0); - assertThat(observation.getEffective() instanceof Period); + assertTrue(observation.getEffective() instanceof Period); assertThat(observation.getEffectivePeriod().getStartElement().getValueAsString()).isEqualTo("2010-05-21"); assertThat(observation.getEffectivePeriod().getEndElement().getValueAsString()).isEqualTo("2010-05-22"); } @@ -364,6 +514,46 @@ private void assertQuantity(Quantity quantity, BigDecimal value, String unit, St assertThat(quantity.getCode()).isEqualTo(code); } + private void assertMetaSecurityIsPresent(final Meta meta) { + final List metaSecurity = meta.getSecurity(); + final int metaSecuritySize = metaSecurity.size(); + final Coding metaSecurityCoding = metaSecurity.get(0); + final UriType metaProfile = meta.getProfile().get(0); + + assertAll( + () -> assertThat(metaSecuritySize).isEqualTo(1), + () -> assertThat(metaProfile.getValue()).isEqualTo(META_PROFILE), + () -> assertThat(metaSecurityCoding.getCode()).isEqualTo(NOPAT_CV.getCode()), + () -> assertThat(metaSecurityCoding.getDisplay()).isEqualTo(NOPAT_CV.getDisplayName()), + () -> assertThat(metaSecurityCoding.getSystem()).isEqualTo(NOPAT_CV.getCodeSystem()) + ); + } + + private RCMRMT030101UKEhrComposition getEhrComposition(RCMRMT030101UKEhrExtract ehrExtract) { + + return ehrExtract.getComponent().get(0) + .getEhrFolder().getComponent().get(0) + .getEhrComposition(); + } + + private RCMRMT030101UKObservationStatement getObservationStatement(RCMRMT030101UKEhrExtract ehrExtract) { + return ehrExtract.getComponent().get(0) + .getEhrFolder().getComponent().get(0) + .getEhrComposition().getComponent().get(0) + .getObservationStatement(); + } + + private List getObservationStatementIncludedIntoCompoundStatement( + RCMRMT030101UKEhrExtract ehrExtract) { + + return ehrExtract.getComponent().get(0) + .getEhrFolder().getComponent().get(0) + .getEhrComposition().getComponent().get(0).getCompoundStatement().getComponent().stream() + .filter(RCMRMT030101UKComponent02::hasObservationStatement) + .map(RCMRMT030101UKComponent02::getObservationStatement) + .toList(); + } + @SneakyThrows private RCMRMT030101UKEhrExtract unmarshallEhrExtractElement(String fileName) { return unmarshallFile(getFile("classpath:" + XML_RESOURCES_BASE + fileName), RCMRMT030101UKEhrExtract.class); diff --git a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/DiagnosticReportMapperTest.java b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/DiagnosticReportMapperTest.java index ae691a16b..28bbff4ab 100644 --- a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/DiagnosticReportMapperTest.java +++ b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/DiagnosticReportMapperTest.java @@ -5,6 +5,12 @@ import java.io.IOException; import java.nio.file.Files; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static uk.nhs.adaptors.pss.translator.MetaFactory.MetaType.META_WITH_SECURITY; import static uk.nhs.adaptors.pss.translator.util.DateFormatUtil.parseToInstantType; import static uk.nhs.adaptors.pss.translator.util.XmlUnmarshallUtil.unmarshallString; import java.nio.file.Paths; @@ -12,13 +18,20 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Optional; +import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.DateTimeType; import org.hl7.fhir.dstu3.model.Encounter; import org.hl7.fhir.dstu3.model.Identifier; import org.hl7.fhir.dstu3.model.InstantType; +import org.hl7.fhir.dstu3.model.Meta; import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.Patient; +import org.hl7.fhir.dstu3.model.UriType; +import org.hl7.v3.CV; +import org.hl7.v3.RCMRMT030101UKCompoundStatement; +import org.hl7.v3.RCMRMT030101UKEhrComposition; import org.hl7.v3.RCMRMT030101UKEhrExtract; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -29,6 +42,9 @@ import lombok.SneakyThrows; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; +import uk.nhs.adaptors.pss.translator.MetaFactory; +import uk.nhs.adaptors.pss.translator.TestUtility; +import uk.nhs.adaptors.pss.translator.service.ConfidentialityService; import uk.nhs.adaptors.pss.translator.service.IdGeneratorService; import uk.nhs.adaptors.pss.translator.util.DateFormatUtil; import static org.hl7.fhir.dstu3.model.Observation.ObservationStatus.UNKNOWN; @@ -49,6 +65,11 @@ public class DiagnosticReportMapperTest { private static final Patient PATIENT = (Patient) new Patient().setId("PATIENT_TEST_ID"); private static final String CONCLUSION_FIELD_TEXT = "TEXT_OF_DIRECT_COMPOUND_STATEMENT_CHILD_NARRATIVE_STATEMENT_1\n" + "TEXT_OF_DIRECT_COMPOUND_STATEMENT_CHILD_NARRATIVE_STATEMENT_2"; + private static final Meta META = MetaFactory.getMetaFor(META_WITH_SECURITY, DIAGNOSTIC_REPORT_META_SUFFIX); + private static final CV NOPAT_CV = TestUtility.createCv( + "NOPAT", + "http://hl7.org/fhir/v3/ActCode", + "no disclosure to patient, family or caregivers without attending provider's authorization"); private static final String NARRATIVE_STATEMENT_COMMENT_BLOCK = """ CommentType:LABORATORY RESULT COMMENT(E141) @@ -78,12 +99,87 @@ public class DiagnosticReportMapperTest { """; + private static final String EHR_EXTRACT_TEMPLATE_WITH_EHR_COMPOSITION = """ + + + + + + + + + {DiagnosticReportCompoundStatement} + + + + + + + """; + @Mock private IdGeneratorService idGeneratorService; + @Mock + private ConfidentialityService confidentialityService; + @InjectMocks private DiagnosticReportMapper diagnosticReportMapper; + @Test + public void When_DiagnosticReportWithNoPatIsMapped_Expect_DiagnosticReportWithNoPatMeta() { + var inputXml = buildEhrExtractStringFromDiagnosticReportXml( + """ + + + + + + + """); + + var ehrExtract = unmarshallEhrExtractFromXmlString(inputXml); + final var compoundStatement = getCompoundStatement(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + DIAGNOSTIC_REPORT_META_SUFFIX, + Optional.empty(), + compoundStatement.getConfidentialityCode() + )).thenReturn(META); + + var diagnosticReports = diagnosticReportMapper.mapResources(ehrExtract, PATIENT, List.of(), PRACTICE_CODE); + var diagnosticReport = diagnosticReports.getFirst(); + + assertMetaSecurityIsPresent(diagnosticReport.getMeta()); + } + + @Test + public void When_DiagnosticReportWithNoPatEhrCompositionIsMapped_Expect_DiagnosticReportWithNoPatMeta() { + var inputXml = buildEhrExtractStringWithNoPatEhrCompositionFromDiagnosticReportXml( + """ + + + + + + """); + + var ehrExtract = unmarshallEhrExtractFromXmlString(inputXml); + final var ehrComposition = getEhrComposition(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + DIAGNOSTIC_REPORT_META_SUFFIX, + ehrComposition.getConfidentialityCode(), + Optional.empty() + )).thenReturn(META); + + var diagnosticReports = diagnosticReportMapper.mapResources(ehrExtract, PATIENT, List.of(), PRACTICE_CODE); + var diagnosticReport = diagnosticReports.getFirst(); + + assertMetaSecurityIsPresent(diagnosticReport.getMeta()); + } @Test public void When_DiagnosticReportWithNoReferenceIsMapped_Expect_DiagnosticReportIsCorrectlyMapped() { @@ -97,29 +193,27 @@ public void When_DiagnosticReportWithNoReferenceIsMapped_Expect_DiagnosticReport """); var ehrExtract = unmarshallEhrExtractFromXmlString(inputXml); + final var compoundStatement = getCompoundStatement(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + DIAGNOSTIC_REPORT_META_SUFFIX, + Optional.empty(), + compoundStatement.getConfidentialityCode() + )).thenReturn(META); var diagnosticReports = diagnosticReportMapper.mapResources(ehrExtract, PATIENT, List.of(), PRACTICE_CODE); - var diagnosticReport = diagnosticReports.get(0); + var diagnosticReport = diagnosticReports.getFirst(); assertAll( - () -> assertThat(diagnosticReport.getId()) - .isEqualTo(DIAGNOSTIC_REPORT_ID), - () -> assertThat(diagnosticReport.getMeta().getProfile().get(0).getValue()) - .contains(DIAGNOSTIC_REPORT_META_SUFFIX), - () -> assertThat(diagnosticReport.getIdentifierFirstRep().getSystem()) - .contains(PRACTICE_CODE), - () -> assertThat(diagnosticReport.getIdentifierFirstRep().getValue()) - .isEqualTo(DIAGNOSTIC_REPORT_ID), - () -> assertThat(diagnosticReport.getSubject().getResource().getIdElement().getValue()) - .isEqualTo(PATIENT.getId()), - () -> assertThat(diagnosticReport.getIssuedElement().getValueAsString()) - .isEqualTo(ISSUED_ELEMENT.getValueAsString()), - () -> assertThat(diagnosticReport.hasContext()) - .isFalse(), - () -> assertThat(diagnosticReport.getSpecimen()) - .isEmpty(), - () -> assertThat(diagnosticReport.getResult()) - .isEmpty() + () -> assertThat(diagnosticReport.getId()).isEqualTo(DIAGNOSTIC_REPORT_ID), + () -> assertThat(diagnosticReport.getMeta().getProfile().getFirst().getValue()).contains(DIAGNOSTIC_REPORT_META_SUFFIX), + () -> assertThat(diagnosticReport.getIdentifierFirstRep().getSystem()).contains(PRACTICE_CODE), + () -> assertThat(diagnosticReport.getIdentifierFirstRep().getValue()).isEqualTo(DIAGNOSTIC_REPORT_ID), + () -> assertThat(diagnosticReport.getSubject().getResource().getIdElement().getValue()).isEqualTo(PATIENT.getId()), + () -> assertThat(diagnosticReport.getIssuedElement().getValueAsString()).isEqualTo(ISSUED_ELEMENT.getValueAsString()), + () -> assertFalse(diagnosticReport.hasContext()), + () -> assertThat(diagnosticReport.getSpecimen()).isEmpty(), + () -> assertThat(diagnosticReport.getResult()).isEmpty() ); } @@ -137,13 +231,11 @@ public void When_DiagnosticReportContainsIdExtensionWithPMIPOid_Expect_MappedExt var ehrExtract = unmarshallEhrExtractFromXmlString(inputXml); var diagnosticReports = diagnosticReportMapper.mapResources(ehrExtract, PATIENT, List.of(), PRACTICE_CODE); - var actualPMIPExtension = diagnosticReports.get(0).getIdentifier().get(1); + var actualPMIPExtension = diagnosticReports.getFirst().getIdentifier().get(1); assertAll( - () -> assertThat(actualPMIPExtension.getSystem()) - .isEqualTo("urn:oid:2.16.840.1.113883.2.1.4.5.5"), - () -> assertThat(actualPMIPExtension.getValue()) - .isEqualTo("TEST_PMIP_EXTENSION_VALUE") + () -> assertThat(actualPMIPExtension.getSystem()).isEqualTo("urn:oid:2.16.840.1.113883.2.1.4.5.5"), + () -> assertThat(actualPMIPExtension.getValue()).isEqualTo("TEST_PMIP_EXTENSION_VALUE") ); } @@ -166,13 +258,11 @@ public void When_DiagnosticReportWithSpecimenIsMapped_Expect_DiagnosticReportCon var ehrExtract = unmarshallEhrExtractFromXmlString(inputXml); var diagnosticReports = diagnosticReportMapper.mapResources(ehrExtract, PATIENT, List.of(), PRACTICE_CODE); - var diagnosticReport = diagnosticReports.get(0); + var diagnosticReport = diagnosticReports.getFirst(); assertAll( - () -> assertThat(diagnosticReport.getSpecimen()) - .isNotEmpty(), - () -> assertThat(diagnosticReport.getSpecimenFirstRep().getReference()) - .contains(COMPOUND_STATEMENT_CHILD_ID) + () -> assertThat(diagnosticReport.getSpecimen()).isNotEmpty(), + () -> assertThat(diagnosticReport.getSpecimenFirstRep().getReference()).contains(COMPOUND_STATEMENT_CHILD_ID) ); } @@ -204,13 +294,11 @@ public void When_DiagnosticReportContainsUnknownCommentType_Expect_ResultReferen var ehrExtract = unmarshallEhrExtractFromXmlString(inputXml); var diagnosticReports = diagnosticReportMapper.mapResources(ehrExtract, PATIENT, List.of(), PRACTICE_CODE); - var diagnosticReport = diagnosticReports.get(0); + var diagnosticReport = diagnosticReports.getFirst(); assertAll( - () -> assertThat(diagnosticReport.getResult()) - .hasSize(1), - () -> assertThat(diagnosticReport.getResultFirstRep().getReference()) - .contains(NARRATIVE_STATEMENT_ID_2) + () -> assertThat(diagnosticReport.getResult()).hasSize(1), + () -> assertThat(diagnosticReport.getResultFirstRep().getReference()).contains(NARRATIVE_STATEMENT_ID_2) ); } @@ -242,13 +330,11 @@ public void When_DiagnosticReportContainsUserCommentType_Expect_ResultReferenceI var ehrExtract = unmarshallEhrExtractFromXmlString(inputXml); var diagnosticReports = diagnosticReportMapper.mapResources(ehrExtract, PATIENT, List.of(), PRACTICE_CODE); - var diagnosticReport = diagnosticReports.get(0); + var diagnosticReport = diagnosticReports.getFirst(); assertAll( - () -> assertThat(diagnosticReport.getResult()) - .hasSize(1), - () -> assertThat(diagnosticReport.getResultFirstRep().getReference()) - .contains(NARRATIVE_STATEMENT_ID_2) + () -> assertThat(diagnosticReport.getResult()).hasSize(1), + () -> assertThat(diagnosticReport.getResultFirstRep().getReference()).contains(NARRATIVE_STATEMENT_ID_2) ); } @@ -288,12 +374,9 @@ public void When_DiagnosticReportContainsChildObservationComment_Expect_Observat diagnosticReportMapper.handleChildObservationComments(ehrExtract, observationComments); assertAll( - () -> assertThat(observationComments) - .hasSize(1), - () -> assertThat(observationComments.get(0).hasEffective()) - .isFalse(), - () -> assertThat(observationComments.get(0).getComment()) - .isEqualTo(NARRATIVE_STATEMENT_2_TEXT) + () -> assertThat(observationComments).hasSize(1), + () -> assertFalse(observationComments.getFirst().hasEffective()), + () -> assertThat(observationComments.getFirst().getComment()).isEqualTo(NARRATIVE_STATEMENT_2_TEXT) ); } @@ -310,7 +393,7 @@ public void When_DiagnosticReportWithSomeNarativeStatements_Expect_DiagnosticRep PATIENT, createEncounterList(), PRACTICE_CODE); - var diagnosticReport = diagnosticReports.get(0); + var diagnosticReport = diagnosticReports.getFirst(); assertThat(diagnosticReport.getResult()).map(r -> r.getReference()) .isEqualTo(List.of("Observation/3E1A4EA2-661B-4467-8843-6A6B21DEF14F", @@ -341,15 +424,12 @@ public void When_MappingDiagnosticReport_Expect_DiagnosticReportContainsContextR PATIENT, createEncounterList(), PRACTICE_CODE); - var diagnosticReport = diagnosticReports.get(0); + var diagnosticReport = diagnosticReports.getFirst(); assertAll( - () -> assertThat(diagnosticReport.hasContext()) - .isTrue(), - () -> assertThat(diagnosticReport.getContext().getResource()) - .isNotNull(), - () -> assertThat(diagnosticReport.getContext().getResource().getIdElement().getValue()) - .isEqualTo(ENCOUNTER_ID) + () -> assertTrue(diagnosticReport.hasContext()), + () -> assertNotNull(diagnosticReport.getContext().getResource()), + () -> assertThat(diagnosticReport.getContext().getResource().getIdElement().getValue()).isEqualTo(ENCOUNTER_ID) ); } @@ -396,13 +476,11 @@ public void When_DiagnosticReportIsMapped_Expect_LaboratoryResultCommentsAreMapp PATIENT, createEncounterList(), PRACTICE_CODE); - var diagnosticReport = diagnosticReports.get(0); + var diagnosticReport = diagnosticReports.getFirst(); assertAll( - () -> assertThat(diagnosticReport.hasConclusion()) - .isTrue(), - () -> assertThat(diagnosticReport.getConclusion()) - .isEqualTo(CONCLUSION_FIELD_TEXT) + () -> assertTrue(diagnosticReport.hasConclusion()), + () -> assertThat(diagnosticReport.getConclusion()).isEqualTo(CONCLUSION_FIELD_TEXT) ); } @@ -460,13 +538,11 @@ public void When_MappingWithUserCommentInBattery_Expect_DiagnosticReportToRefere PRACTICE_CODE, new ArrayList<>(Collections.singleton(batteryLevelFilingComment))); - final var diagnosticReport = diagnosticReports.get(0); + final var diagnosticReport = diagnosticReports.getFirst(); assertAll( - () -> assertThat(diagnosticReport.getResult()) - .hasSize(1), - () -> assertThat(diagnosticReport.getResult().get(0).getReference()) - .isEqualTo(expectedReference) + () -> assertThat(diagnosticReport.getResult()).hasSize(1), + () -> assertThat(diagnosticReport.getResult().getFirst().getReference()).isEqualTo(expectedReference) ); } @@ -524,16 +600,14 @@ public void When_MappingWithUserCommentInBattery_Expect_NewFilingCommentObservat observationComments); assertAll( - () -> assertThat(observationComments) - .hasSize(2), - () -> assertThat(observationComments.get(1).getId()) - .isEqualTo(NEW_OBSERVATION_ID), - () -> assertThat(observationComments.get(1).getIdentifierFirstRep().getValue()) - .isEqualTo(NEW_OBSERVATION_ID), - () -> assertThat(observationComments.get(1).getEffectiveDateTimeType().getValueAsString()) - .isEqualTo("2024-01-01"), - () -> assertThat(observationComments.get(1).getComment()).isNull(), - () -> assertThat(observationComments.get(1).getStatus()).isEqualTo(UNKNOWN) + () -> assertThat(observationComments).hasSize(2), + () -> assertThat(observationComments.get(1).getId()).isEqualTo(NEW_OBSERVATION_ID), + () -> assertThat(observationComments.get(1).getIdentifierFirstRep().getValue()) + .isEqualTo(NEW_OBSERVATION_ID), + () -> assertThat(observationComments.get(1).getEffectiveDateTimeType().getValueAsString()) + .isEqualTo("2024-01-01"), + () -> assertNull(observationComments.get(1).getComment()), + () -> assertThat(observationComments.get(1).getStatus()).isEqualTo(UNKNOWN) ); } @@ -561,15 +635,42 @@ private Observation createBatteryLevelFilingComment() { .setId("C515E722-2473-11EE-808B-AC162D1F16F0"); } + private RCMRMT030101UKCompoundStatement getCompoundStatement(RCMRMT030101UKEhrExtract ehrExtract) { + return ehrExtract.getComponent().getFirst() + .getEhrFolder().getComponent().getFirst() + .getEhrComposition().getComponent().getFirst() + .getCompoundStatement(); + } + private List createEncounterList() { return List.of((Encounter) new Encounter().setId(ENCOUNTER_ID)); } + private void assertMetaSecurityIsPresent(final Meta meta) { + final List metaSecurity = meta.getSecurity(); + final int metaSecuritySize = metaSecurity.size(); + final Coding metaSecurityCoding = metaSecurity.getFirst(); + final UriType metaProfile = meta.getProfile().getFirst(); + + assertAll( + () -> assertThat(metaSecuritySize).isEqualTo(1), + () -> assertThat(metaProfile.getValue()).isEqualTo(DIAGNOSTIC_REPORT_META_SUFFIX), + () -> assertThat(metaSecurityCoding.getCode()).isEqualTo(NOPAT_CV.getCode()), + () -> assertThat(metaSecurityCoding.getDisplay()).isEqualTo(NOPAT_CV.getDisplayName()), + () -> assertThat(metaSecurityCoding.getSystem()).isEqualTo(NOPAT_CV.getCodeSystem())); + } + @SneakyThrows private RCMRMT030101UKEhrExtract unmarshallEhrExtractFromXmlString(String xmlString) { return unmarshallString(xmlString, RCMRMT030101UKEhrExtract.class); } + private RCMRMT030101UKEhrComposition getEhrComposition(RCMRMT030101UKEhrExtract ehrExtract) { + return ehrExtract.getComponent().getFirst() + .getEhrFolder().getComponent().getFirst() + .getEhrComposition(); + } + private static String readFileAsString(String path) throws IOException { Resource resource = new ClassPathResource(path); return Files.readString(Paths.get(resource.getURI())); @@ -578,4 +679,8 @@ private static String readFileAsString(String path) throws IOException { private static String buildEhrExtractStringFromDiagnosticReportXml(String diagnosticReportXml) { return EHR_EXTRACT_TEMPLATE.replace("{DiagnosticReportCompoundStatement}", diagnosticReportXml); } + + private static String buildEhrExtractStringWithNoPatEhrCompositionFromDiagnosticReportXml(String diagnosticReportXml) { + return EHR_EXTRACT_TEMPLATE_WITH_EHR_COMPOSITION.replace("{DiagnosticReportCompoundStatement}", diagnosticReportXml); + } } diff --git a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenCompoundsMapperTest.java b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenCompoundsMapperTest.java index b2ec73596..044d73716 100644 --- a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenCompoundsMapperTest.java +++ b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenCompoundsMapperTest.java @@ -2,24 +2,34 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.AdditionalAnswers.answer; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.springframework.util.ResourceUtils.getFile; +import static uk.nhs.adaptors.pss.translator.MetaFactory.MetaType.META_WITH_SECURITY; import static uk.nhs.adaptors.pss.translator.mapper.diagnosticreport.SpecimenBatteryMapper.SpecimenBatteryParameters; import static uk.nhs.adaptors.pss.translator.util.XmlUnmarshallUtil.unmarshallFile; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.DiagnosticReport; import org.hl7.fhir.dstu3.model.IdType; +import org.hl7.fhir.dstu3.model.Meta; import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Reference; import org.hl7.fhir.dstu3.model.ResourceType; +import org.hl7.fhir.dstu3.model.UriType; +import org.hl7.v3.CV; +import org.hl7.v3.RCMRMT030101UKCompoundStatement; +import org.hl7.v3.RCMRMT030101UKEhrComposition; import org.hl7.v3.RCMRMT030101UKEhrExtract; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -32,6 +42,9 @@ import lombok.SneakyThrows; import org.mockito.stubbing.Answer1; +import uk.nhs.adaptors.pss.translator.MetaFactory; +import uk.nhs.adaptors.pss.translator.TestUtility; +import uk.nhs.adaptors.pss.translator.service.ConfidentialityService; @ExtendWith(MockitoExtension.class) @RunWith(MockitoJUnitRunner.class) @@ -48,6 +61,12 @@ public class SpecimenCompoundsMapperTest { private static final String SPECIMEN_ID = "TEST_SPECIMEN_ID"; private static final String TEST_COMMENT_LINE = "First comment Line"; private static final String TEST_COMMENT_LINE_1 = "Test Comment"; + private static final String META_PROFILE = "Observation-1"; + private static final Meta META = MetaFactory.getMetaFor(META_WITH_SECURITY, META_PROFILE); + private static final CV NOPAT_CV = TestUtility.createCv( + "NOPAT", + "http://hl7.org/fhir/v3/ActCode", + "no disclosure to patient, family or caregivers without attending provider's authorization"); private static final Patient PATIENT = (Patient) new Patient().setId("TEST_PATIENT_ID"); @@ -58,6 +77,9 @@ public class SpecimenCompoundsMapperTest { @Mock private SpecimenBatteryMapper specimenBatteryMapper; + @Mock + private ConfidentialityService confidentialityService; + @InjectMocks private SpecimenCompoundsMapper specimenCompoundsMapper; @@ -68,6 +90,47 @@ public void setup() { diagnosticReports = createDiagnosticReports(); } + @Test + public void testHandlingNoPatCompoundStatementWithObservationStatement() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_observation_statement_with_nopat_conf_code.xml"); + final var compoundStatement = getCompoundStatement(ehrExtract); + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + Optional.empty(), + compoundStatement.getConfidentialityCode() + )).thenReturn(META); + + specimenCompoundsMapper.handleSpecimenChildComponents( + ehrExtract, observations, observationComments, diagnosticReports, PATIENT, List.of(), TEST_PRACTISE_CODE + ); + + final Reference result = diagnosticReports.getFirst().getResult().getFirst(); + + assertMetaSecurityIsPresent(observations.getFirst().getMeta()); + assertMetaSecurityIsPresent((Meta) result.getResource().getMeta()); + } + + @Test + public void testHandlingNoPatEhrCompositionWithObservationStatement() { + final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_ehr_composition_with_nopat_conf_code.xml"); + final var ehrComposition = getEhrComposition(ehrExtract); + final var compoundStatement = getCompoundStatement(ehrExtract); + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + ehrComposition.getConfidentialityCode(), + compoundStatement.getConfidentialityCode() + )).thenReturn(META); + + specimenCompoundsMapper.handleSpecimenChildComponents( + ehrExtract, observations, observationComments, diagnosticReports, PATIENT, List.of(), TEST_PRACTISE_CODE); + + + final Reference result = diagnosticReports.getFirst().getResult().getFirst(); + + assertMetaSecurityIsPresent(observations.getFirst().getMeta()); + assertMetaSecurityIsPresent((Meta) result.getResource().getMeta()); + } + @Test public void testHandlingFirstLevelObservationStatement() { final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_observation_statement.xml"); @@ -75,12 +138,12 @@ public void testHandlingFirstLevelObservationStatement() { ehrExtract, observations, observationComments, diagnosticReports, PATIENT, List.of(), TEST_PRACTISE_CODE ); - assertParentSpecimenIsReferenced(observations.get(0)); - assertThat(observations.get(0).getIssuedElement().asStringValue()).isEqualTo("2010-02-25T15:41:00.000+00:00"); - assertThat(diagnosticReports.get(0).getResult()).isNotEmpty(); + assertParentSpecimenIsReferenced(observations.getFirst()); + assertThat(observations.getFirst().getIssuedElement().asStringValue()).isEqualTo("2010-02-25T15:41:00.000+00:00"); + assertThat(diagnosticReports.getFirst().getResult()).isNotEmpty(); - final Reference result = diagnosticReports.get(0).getResult().get(0); - assertThat(result.getResource()).isNotNull(); + final Reference result = diagnosticReports.getFirst().getResult().getFirst(); + assertNotNull(result.getResource()); assertThat(result.getResource().getIdElement().getValue()).isEqualTo(OBSERVATION_STATEMENT_ID); } @@ -91,9 +154,9 @@ public void testHandlingSpecimenChildClusterCompoundStatement() { ehrExtract, observations, observationComments, diagnosticReports, PATIENT, List.of(), TEST_PRACTISE_CODE ); - final Observation observation = observations.get(0); + final Observation observation = observations.getFirst(); - final Observation observationComment = observationComments.get(0); + final Observation observationComment = observationComments.getFirst(); assertParentSpecimenIsReferenced(observation); assertThat(observation.getIssuedElement().asStringValue()).isEqualTo("2010-02-25T15:41:00.000+00:00"); @@ -102,10 +165,10 @@ public void testHandlingSpecimenChildClusterCompoundStatement() { assertThat(observationComments).hasSize(2); assertThat(observationComment.getComment()).isEqualTo(TEST_COMMENT_LINE_1); assertThat(observationComment.getRelated()).isNotEmpty(); - assertThat(observationComment.getRelated().get(0).getTarget().getResource()).isNotNull(); - assertThat(observationComment.getRelated().get(0).getTarget().getResource().getIdElement().getValue()) + assertThat(observationComment.getRelated().getFirst().getTarget().getResource()).isNotNull(); + assertThat(observationComment.getRelated().getFirst().getTarget().getResource().getIdElement().getValue()) .isEqualTo(observation.getId()); - assertThat(diagnosticReports.get(0).getResult().size()).isOne(); + assertThat(diagnosticReports.getFirst().getResult().size()).isOne(); } @Test @@ -115,61 +178,72 @@ public void testHandlingSpecimenChildBatteryCompoundStatement() { ehrExtract, observations, observationComments, diagnosticReports, PATIENT, List.of(), TEST_PRACTISE_CODE ); - assertParentSpecimenIsReferenced(observations.get(0)); - assertThat(observations.get(0).getIssuedElement().asStringValue()).isEqualTo("2010-02-25T15:41:00.000+00:00"); + assertParentSpecimenIsReferenced(observations.getFirst()); + assertThat(observations.getFirst().getIssuedElement().asStringValue()).isEqualTo("2010-02-25T15:41:00.000+00:00"); assertParentSpecimenIsReferenced(observations.get(1)); - assertThat(observations.get(0).getIssuedElement().asStringValue()).isEqualTo("2010-02-25T15:41:00.000+00:00"); + assertThat(observations.getFirst().getIssuedElement().asStringValue()).isEqualTo("2010-02-25T15:41:00.000+00:00"); assertThat(observationComments).hasSize(2); - assertThat(observationComments.get(0).getComment()).isEqualTo(TEST_COMMENT_LINE_1); + assertThat(observationComments.getFirst().getComment()).isEqualTo(TEST_COMMENT_LINE_1); - assertThat(diagnosticReports.get(0).getResult()).isEmpty(); + assertThat(diagnosticReports.getFirst().getResult()).isEmpty(); verify(specimenBatteryMapper, times(1)).mapBatteryObservation(any()); } @Test - public void testHandlingUserNarrativeStatement() { + public void testHandlingUserNarrativeStatementWithNoPat() { final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_user_narrative_statement.xml"); + final var compoundStatement = getCompoundStatement(ehrExtract); + var compoundStatementWithNarrativeStatement = compoundStatement.getComponent().getFirst().getCompoundStatement(); + + specimenCompoundsMapper.getNarrativeStatementsInCompound(compoundStatementWithNarrativeStatement).forEach(narrativeStatement -> + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + Optional.empty(), + Optional.empty() + )).thenReturn(null) + ); + + specimenCompoundsMapper.getNarrativeStatementsInCompound(compoundStatementWithNarrativeStatement).forEach(narrativeStatement -> + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + META_PROFILE, + compoundStatement.getConfidentialityCode(), + narrativeStatement.getConfidentialityCode() + )).thenReturn(META) + ); + specimenCompoundsMapper.handleSpecimenChildComponents( ehrExtract, observations, observationComments, diagnosticReports, PATIENT, List.of(), TEST_PRACTISE_CODE ); - assertParentSpecimenIsReferenced(observations.get(0)); - assertThat(observations.get(0).getIssuedElement().asStringValue()).isEqualTo("2022-03-14T18:24:45.000+00:00"); - assertThat(observationComments).hasSize(2); - assertThat(observationComments.get(0).getRelated()).isNotEmpty(); - assertThat(observationComments.get(0).getRelated()).isNotEmpty(); - assertThat(observationComments.get(0).getRelated().get(0).getTarget().getResource()).isNotNull(); - assertThat(observationComments.get(0).getRelated().get(0).getTarget().getResource().getIdElement().getValue()) - .isEqualTo(observations.get(0).getId()); - assertThat(observations.get(0).getComment()).isEqualTo(TEST_COMMENT_LINE); + assertMetaSecurityIsPresent(observationComments.getFirst().getMeta()); } @Test - public void testHandlingNonUserNarrativeStatement() { + void testHandlingNonUserNarrativeStatement() { final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_non_user_narrative_statement.xml"); specimenCompoundsMapper.handleSpecimenChildComponents( ehrExtract, observations, observationComments, diagnosticReports, PATIENT, List.of(), TEST_PRACTISE_CODE ); - assertParentSpecimenIsReferenced(observations.get(0)); - assertThat(observations.get(0).getIssuedElement().asStringValue()).isEqualTo("2022-03-14T18:24:45.000+00:00"); + assertParentSpecimenIsReferenced(observations.getFirst()); + assertThat(observations.getFirst().getIssuedElement().asStringValue()).isEqualTo("2022-03-14T18:24:45.000+00:00"); assertThat(observationComments.size()).isOne(); - assertThat(observations.get(0).getComment()).isEqualTo(TEST_COMMENT_LINE + "\n" + TEST_COMMENT_LINE_1); + assertThat(observations.getFirst().getComment()).isEqualTo(TEST_COMMENT_LINE + "\n" + TEST_COMMENT_LINE_1); } - @Test public void testHandlingObservationStatementWithUnkAvailabilityTime() { + @Test void testHandlingObservationStatementWithUnkAvailabilityTime() { final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_cluster_compound_statement_availability_time_unk.xml"); specimenCompoundsMapper.handleSpecimenChildComponents( ehrExtract, observations, observationComments, diagnosticReports, PATIENT, List.of(), TEST_PRACTISE_CODE ); - final Observation observation = observations.get(0); + final Observation observation = observations.getFirst(); assertThat(observation.getIssuedElement().asStringValue()).isNull(); } - @Test public void testOrderingIsPreservedForDiagnosticReportResults() { + @Test void testOrderingIsPreservedForDiagnosticReportResults() { final RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_with_three_test_group_headers.xml"); @@ -185,7 +259,7 @@ public void testHandlingNonUserNarrativeStatement() { doAnswer( answer( (Answer1) batteryParameters -> { - var id = batteryParameters.getBatteryCompoundStatement().getId().get(0).getRoot(); + var id = batteryParameters.getBatteryCompoundStatement().getId().getFirst().getRoot(); var observation = new Observation(); observation.setId(id); @@ -205,10 +279,10 @@ public void testHandlingNonUserNarrativeStatement() { TEST_PRACTISE_CODE ); - var diagnosticReport = diagnosticReports.get(0); + var diagnosticReport = diagnosticReports.getFirst(); assertAll( - () -> assertThat(getReferenceId(diagnosticReport.getResult().get(0))) + () -> assertThat(getReferenceId(diagnosticReport.getResult().getFirst())) .isEqualTo("Observation/TEST-GROUP-HEADER-1"), () -> assertThat(getReferenceId(diagnosticReport.getResult().get(1))) .isEqualTo("OBSERVATION-STATEMENT-ID-2"), @@ -267,10 +341,40 @@ private String getReferenceId(Reference reference) { : reference.getResource().getIdElement().getValue(); } + private void assertMetaSecurityIsPresent(final Meta meta) { + final List metaSecurity = meta.getSecurity(); + final int metaSecuritySize = metaSecurity.size(); + final Coding metaSecurityCoding = metaSecurity.getFirst(); + final UriType metaProfile = meta.getProfile().getFirst(); + + assertAll( + () -> assertThat(metaSecuritySize).isEqualTo(1), + () -> assertThat(metaProfile.getValue()).isEqualTo(META_PROFILE), + () -> assertThat(metaSecurityCoding.getCode()).isEqualTo(NOPAT_CV.getCode()), + () -> assertThat(metaSecurityCoding.getDisplay()).isEqualTo(NOPAT_CV.getDisplayName()), + () -> assertThat(metaSecurityCoding.getSystem()).isEqualTo(NOPAT_CV.getCodeSystem()) + ); + } + @SneakyThrows private RCMRMT030101UKEhrExtract unmarshallEhrExtract(String fileName) { return unmarshallFile(getFile("classpath:" + XML_RESOURCES_BASE + fileName), RCMRMT030101UKEhrExtract.class); } + private RCMRMT030101UKEhrComposition getEhrComposition(RCMRMT030101UKEhrExtract ehrExtract) { + + return ehrExtract.getComponent().getFirst() + .getEhrFolder().getComponent().getFirst() + .getEhrComposition(); + } + + private RCMRMT030101UKCompoundStatement getCompoundStatement(RCMRMT030101UKEhrExtract ehrExtract) { + return ehrExtract.getComponent().getFirst() + .getEhrFolder().getComponent().getFirst() + .getEhrComposition().getComponent().getFirst() + .getCompoundStatement().getComponent().getFirst() + .getCompoundStatement(); + } + } diff --git a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenMapperTest.java b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenMapperTest.java index c03847752..b723e264c 100644 --- a/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenMapperTest.java +++ b/gp2gp-translator/src/test/java/uk/nhs/adaptors/pss/translator/mapper/diagnosticreport/SpecimenMapperTest.java @@ -1,23 +1,31 @@ package uk.nhs.adaptors.pss.translator.mapper.diagnosticreport; import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import static org.springframework.util.ResourceUtils.getFile; +import static uk.nhs.adaptors.pss.translator.MetaFactory.MetaType.META_WITH_SECURITY; import static uk.nhs.adaptors.pss.translator.util.DateFormatUtil.parseToDateTimeType; import static uk.nhs.adaptors.pss.translator.util.XmlUnmarshallUtil.unmarshallFile; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.UUID; +import org.hl7.fhir.dstu3.model.Coding; import org.hl7.fhir.dstu3.model.DateTimeType; import org.hl7.fhir.dstu3.model.DiagnosticReport; +import org.hl7.fhir.dstu3.model.Meta; import org.hl7.fhir.dstu3.model.Observation; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Reference; import org.hl7.fhir.dstu3.model.Specimen; +import org.hl7.v3.CV; +import org.hl7.v3.RCMRMT030101UKCompoundStatement; +import org.hl7.v3.RCMRMT030101UKEhrComposition; import org.hl7.v3.RCMRMT030101UKEhrExtract; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -26,13 +34,15 @@ import org.mockito.junit.jupiter.MockitoExtension; import lombok.SneakyThrows; +import uk.nhs.adaptors.pss.translator.MetaFactory; +import uk.nhs.adaptors.pss.translator.TestUtility; import uk.nhs.adaptors.pss.translator.mapper.DateTimeMapper; +import uk.nhs.adaptors.pss.translator.service.ConfidentialityService; @ExtendWith(MockitoExtension.class) public class SpecimenMapperTest { private static final String XML_RESOURCES_BASE = "xml/Specimen/"; - private static final String SPECIMEN_META_PROFILE = "https://fhir.nhs.uk/STU3/StructureDefinition/CareConnect-GPC-Specimen-1"; private static final String SPECIMEN_PREFIX = "Specimen/"; private static final String TEST_SPECIMEN_ID = "COMPOUND_STATEMENT_CHILD_ID_1"; private static final String PRACTICE_CODE = "TEST_PRACTICE_CODE"; @@ -45,57 +55,122 @@ public class SpecimenMapperTest { private static final String DR_ID = "DIAGNOSTIC_REPORT_ID"; private static final DiagnosticReport DIAGNOSTIC_REPORT_WITH_SPECIMEN = generateDiagnosticReportWithSpecimenReference(); private static final DiagnosticReport DIAGNOSTIC_REPORT_WITHOUT_SPECIMEN = generateDiagnosticReportWithNoSpecimenReference(); + private static final String SPECIMEN_META_PROFILE = "Specimen-1"; + private static final Meta META_WITH_SECURITY_ADDED = MetaFactory.getMetaFor(META_WITH_SECURITY, SPECIMEN_META_PROFILE); + private static final CV NOPAT_CV = TestUtility.createCv( + "NOPAT", + "http://hl7.org/fhir/v3/ActCode", + "no disclosure to patient, family or caregivers without attending provider's authorization"); private static final String NARRATIVE_STATEMENT_ID = "9326C01E-488B-4EDF-B9C9-529E69EE0361"; @Mock private DateTimeMapper dateTimeMapper; + @Mock + private ConfidentialityService confidentialityService; + @InjectMocks private SpecimenMapper specimenMapper; @Test - public void testSpecimenIsMapped() { + public void testThatSpecimenIsPopulatedWithMetaSecurityWhenNoPatCompoundStatement() { + when(dateTimeMapper.mapDateTime(any())).thenCallRealMethod(); + RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_valid_with_nopat_compound_statement.xml"); + final var compoundStatement = getCompoundStatement(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + SPECIMEN_META_PROFILE, + Optional.empty(), + compoundStatement.getConfidentialityCode() + )).thenReturn(META_WITH_SECURITY_ADDED); + + List specimenList = specimenMapper.mapSpecimens( + ehrExtract, List.of(DIAGNOSTIC_REPORT_WITH_SPECIMEN), PATIENT, PRACTICE_CODE); + + assertThat(specimenList).isNotEmpty(); + final Specimen specimen = specimenList.getFirst(); + assertMetaSecurityIsPresent(specimen.getMeta()); + } + + @Test + public void testHandlingSpecimenNoPatEhrComposition() { + when(dateTimeMapper.mapDateTime(any())).thenCallRealMethod(); + RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_valid_with_nopat_ehr_composition.xml"); + final var ehrComposition = getEhrComposition(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + SPECIMEN_META_PROFILE, + ehrComposition.getConfidentialityCode(), + Optional.empty() + )).thenReturn(META_WITH_SECURITY_ADDED); + + List specimenList = specimenMapper.mapSpecimens( + ehrExtract, List.of(DIAGNOSTIC_REPORT_WITH_SPECIMEN), PATIENT, PRACTICE_CODE); + + assertThat(specimenList).isNotEmpty(); + final Specimen specimen = specimenList.getFirst(); + assertMetaSecurityIsPresent(specimen.getMeta()); + } + + @Test + void testSpecimenIsMapped() { when(dateTimeMapper.mapDateTime(any())).thenCallRealMethod(); RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_valid.xml"); + final var compoundStatement = getCompoundStatement(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + SPECIMEN_META_PROFILE, + Optional.empty(), + compoundStatement.getConfidentialityCode() + )).thenReturn(META_WITH_SECURITY_ADDED); + List specimenList = specimenMapper.mapSpecimens( ehrExtract, List.of(DIAGNOSTIC_REPORT_WITH_SPECIMEN), PATIENT, PRACTICE_CODE ); assertThat(specimenList).isNotEmpty(); - final Specimen specimen = specimenList.get(0); + final Specimen specimen = specimenList.getFirst(); checkFixedValues(specimen); - assertThat(specimen.getNote().get(0).getText()).isEqualTo(NOTE_TEXT); + assertThat(specimen.getNote().getFirst().getText()).isEqualTo(NOTE_TEXT); assertThat(specimen.getAccessionIdentifier().getValue()).isEqualTo(ACCESSION_IDENTIFIER_VALUE); assertThat(specimen.getType().getText()).isEqualTo(SPECIMEN_TYPE_TEXT); assertThat(specimen.getCollection().getCollected().toString()).isEqualTo(SPECIMEN_COLLECTED_DATETIME.toString()); } @Test - public void testSpecimenIsMappedWithNoOptionalFields() { + void testSpecimenIsMappedWithNoOptionalFields() { RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_no_optional_fields.xml"); + final var compoundStatement = getCompoundStatement(ehrExtract); + + when(confidentialityService.createMetaAndAddSecurityIfConfidentialityCodesPresent( + SPECIMEN_META_PROFILE, + Optional.empty(), + compoundStatement.getConfidentialityCode() + )).thenReturn(META_WITH_SECURITY_ADDED); + List specimenList = specimenMapper.mapSpecimens( ehrExtract, List.of(DIAGNOSTIC_REPORT_WITH_SPECIMEN), PATIENT, PRACTICE_CODE ); - Specimen specimen = specimenList.get(0); + Specimen specimen = specimenList.getFirst(); assertThat(specimen.getCollection().getCollected()).isNull(); assertThat(specimen.hasAccessionIdentifier()).isFalse(); assertThat(specimen.getType().getText()).isNullOrEmpty(); checkFixedValues(specimen); } - private void checkFixedValues(Specimen specimen) { + void checkFixedValues(Specimen specimen) { assertThat(specimen.getId()).isEqualTo(TEST_SPECIMEN_ID); - assertThat(specimen.getMeta().getProfile().get(0).getValue()).isEqualTo(SPECIMEN_META_PROFILE); + assertThat(specimen.getMeta().getProfile().getFirst().getValue()).isEqualTo(SPECIMEN_META_PROFILE); assertThat(specimen.getIdentifierFirstRep().getSystem()).isEqualTo(IDENTIFIER_SYSTEM); assertThat(specimen.getIdentifierFirstRep().getValue()).isEqualTo(TEST_SPECIMEN_ID); assertThat(specimen.getSubject().getResource().getIdElement().getValue()).isEqualTo(PATIENT.getId()); } @Test - public void testInvalidSpecimenIsNotMapped() { + void testInvalidSpecimenIsNotMapped() { RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_invalid.xml"); List specimenList = specimenMapper.mapSpecimens( ehrExtract, List.of(DIAGNOSTIC_REPORT_WITHOUT_SPECIMEN), PATIENT, PRACTICE_CODE @@ -105,7 +180,7 @@ public void testInvalidSpecimenIsNotMapped() { } @Test - public void When_RemoveSurplusObservationComments_With_ChildNarrativeStatements_Expect_CommentsRemoved() { + void When_RemoveSurplusObservationComments_With_ChildNarrativeStatements_Expect_CommentsRemoved() { RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_valid.xml"); var outputList = specimenMapper @@ -121,7 +196,7 @@ public void When_RemoveSurplusObservationComments_With_ChildNarrativeStatements_ } @Test - public void When_RemoveSurplusObservationComments_Without_NoChildNarrativeStatements_Expect_CommentsUnchanged() { + void When_RemoveSurplusObservationComments_Without_NoChildNarrativeStatements_Expect_CommentsUnchanged() { RCMRMT030101UKEhrExtract ehrExtract = unmarshallEhrExtract("specimen_valid_without_comment.xml"); var observationComments = getObservationComments(); @@ -162,6 +237,31 @@ private static DiagnosticReport generateDiagnosticReportWithNoSpecimenReference( return (DiagnosticReport) new DiagnosticReport().setId(DR_ID); } + private void assertMetaSecurityIsPresent(final Meta meta) { + final List metaSecurity = meta.getSecurity(); + final int metaSecuritySize = metaSecurity.size(); + + assertAll( + () -> assertThat(metaSecuritySize).isEqualTo(1), + () -> assertThat(meta).usingRecursiveComparison().isEqualTo(META_WITH_SECURITY_ADDED) + ); + } + + private RCMRMT030101UKCompoundStatement getCompoundStatement(RCMRMT030101UKEhrExtract ehrExtract) { + return ehrExtract.getComponent().getFirst() + .getEhrFolder().getComponent().getFirst() + .getEhrComposition().getComponent().getFirst() + .getCompoundStatement().getComponent().getFirst() + .getCompoundStatement(); + } + + private RCMRMT030101UKEhrComposition getEhrComposition(RCMRMT030101UKEhrExtract ehrExtract) { + + return ehrExtract.getComponent().getFirst() + .getEhrFolder().getComponent().getFirst() + .getEhrComposition(); + } + @SneakyThrows private RCMRMT030101UKEhrExtract unmarshallEhrExtract(String fileName) { return unmarshallFile(getFile("classpath:" + XML_RESOURCES_BASE + fileName), RCMRMT030101UKEhrExtract.class); diff --git a/gp2gp-translator/src/test/resources/xml/Observation/nopat_compound_statement_with_observation.xml b/gp2gp-translator/src/test/resources/xml/Observation/nopat_compound_statement_with_observation.xml new file mode 100644 index 000000000..5190047d0 --- /dev/null +++ b/gp2gp-translator/src/test/resources/xml/Observation/nopat_compound_statement_with_observation.xml @@ -0,0 +1,148 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + Testvale Surgery, GP2GPTEST + + + + + + + + + + + + + FTX4 + + + +
+ + + + + + + + O/E - Systolic BP reading + + + + + +
+ + + + + + Value: 120.0 mm[Hg] + + + + + + + + + O/E - Diastolic BP reading + + + + + +
+ + + + + + O/E - Diastolic BP reading L Value: 90.0 mm[Hg] + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gp2gp-translator/src/test/resources/xml/Specimen/specimen_valid_with_nopat_compound_statement.xml b/gp2gp-translator/src/test/resources/xml/Specimen/specimen_valid_with_nopat_compound_statement.xml new file mode 100644 index 000000000..aac0d26f3 --- /dev/null +++ b/gp2gp-translator/src/test/resources/xml/Specimen/specimen_valid_with_nopat_compound_statement.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + +
+ + + + + + + + +
+ + + EINE KLEINE + + + + + + + CommentType:LAB SPECIMEN COMMENT(E271) +CommentDate:20020330092100 + +Received Date: 2002-03-30 09:21 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gp2gp-translator/src/test/resources/xml/Specimen/specimen_valid_with_nopat_ehr_composition.xml b/gp2gp-translator/src/test/resources/xml/Specimen/specimen_valid_with_nopat_ehr_composition.xml new file mode 100644 index 000000000..e83a2f2f2 --- /dev/null +++ b/gp2gp-translator/src/test/resources/xml/Specimen/specimen_valid_with_nopat_ehr_composition.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + +
+ + + + + + + +
+ + + EINE KLEINE + + + + + + + CommentType:LAB SPECIMEN COMMENT(E271) +CommentDate:20020330092100 + +Received Date: 2002-03-30 09:21 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gp2gp-translator/src/test/resources/xml/SpecimenComponents/specimen_ehr_composition_with_nopat_conf_code.xml b/gp2gp-translator/src/test/resources/xml/SpecimenComponents/specimen_ehr_composition_with_nopat_conf_code.xml new file mode 100644 index 000000000..49d200e40 --- /dev/null +++ b/gp2gp-translator/src/test/resources/xml/SpecimenComponents/specimen_ehr_composition_with_nopat_conf_code.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + Filed Report + + + +
+ + + + + + + + + + + + + +
+ + + + + + + +
+ + + URINE + + + + + + + + + + + +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/gp2gp-translator/src/test/resources/xml/SpecimenComponents/specimen_observation_statement_with_nopat_conf_code.xml b/gp2gp-translator/src/test/resources/xml/SpecimenComponents/specimen_observation_statement_with_nopat_conf_code.xml new file mode 100644 index 000000000..39e81cebf --- /dev/null +++ b/gp2gp-translator/src/test/resources/xml/SpecimenComponents/specimen_observation_statement_with_nopat_conf_code.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + Filed Report + + + +
+ + + + + + + + + + + + + +
+ + + + + + + + +
+ + + URINE + + + + + + + + + + + +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/gp2gp-translator/src/test/resources/xml/SpecimenComponents/specimen_user_narrative_statement.xml b/gp2gp-translator/src/test/resources/xml/SpecimenComponents/specimen_user_narrative_statement.xml index 8a3d9f847..6dbb34cb0 100644 --- a/gp2gp-translator/src/test/resources/xml/SpecimenComponents/specimen_user_narrative_statement.xml +++ b/gp2gp-translator/src/test/resources/xml/SpecimenComponents/specimen_user_narrative_statement.xml @@ -94,6 +94,8 @@ Test Comment +