diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/MapLocalObservationCodes.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/MapLocalObservationCodes.java index e28c7baaf..4749f3779 100644 --- a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/MapLocalObservationCodes.java +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/MapLocalObservationCodes.java @@ -42,7 +42,8 @@ public void transform(FhirResource resource, Map args) { } var coding = codingList.get(0); - if (!HapiHelper.hasDefinedAlternateCoding(coding, HapiHelper.LOCAL_CODE_URL)) { + if (!HapiHelper.hasDefinedCoding( + coding, HapiHelper.EXTENSION_ALT_CODING, HapiHelper.LOCAL_CODE)) { continue; } diff --git a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/RemoveObservationByCode.java b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/RemoveObservationByCode.java index 161c54d1d..dbbd7a88e 100644 --- a/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/RemoveObservationByCode.java +++ b/etor/src/main/java/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/RemoveObservationByCode.java @@ -5,10 +5,8 @@ import gov.hhs.cdc.trustedintermediary.external.hapi.HapiHelper; import java.util.HashSet; import java.util.Map; -import java.util.Objects; import java.util.Set; import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Resource; @@ -26,35 +24,17 @@ public void transform(FhirResource resource, Map args) { Resource resourceEntry = entry.getResource(); if (resourceEntry instanceof Observation observation) { - removeMatchingObservation(observation, resourcesToRemove, args); - } - } - bundle.getEntry().removeIf(entry -> resourcesToRemove.contains(entry.getResource())); - } - - private void removeMatchingObservation( - Observation observation, Set resourcesToRemove, Map args) { - for (Coding coding : observation.getCode().getCoding()) { - if (isMatchingCode(coding, args)) { - resourcesToRemove.add(observation); - break; + if (HapiHelper.hasMatchingCoding( + observation, + args.get(CODE_NAME).toString(), + args.get(CODING_NAME).toString(), + args.get(CODING_SYSTEM_NAME).toString())) { + resourcesToRemove.add(observation); + } } } - } - // TODO: Need to refactor this to handle missing extensions, etc. and determine if we can - // generalize it - private Boolean isMatchingCode(Coding coding, Map args) { - // Let it fail if args.get() is not a string - return Objects.equals(coding.getCode(), args.get(CODE_NAME)) - && coding.getExtensionByUrl(HapiHelper.EXTENSION_CODING_SYSTEM) - .getValue() - .toString() - .equals(args.get(CODING_SYSTEM_NAME)) - && coding.getExtensionByUrl(HapiHelper.EXTENSION_CWE_CODING) - .getValue() - .toString() - .equals(args.get(CODING_NAME)); + bundle.getEntry().removeIf(entry -> resourcesToRemove.contains(entry.getResource())); } } diff --git a/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/RemoveAccessionNumberTest.groovy b/etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/RemoveObservationByCodeTest.groovy similarity index 100% rename from etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/RemoveAccessionNumberTest.groovy rename to etor/src/test/groovy/gov/hhs/cdc/trustedintermediary/etor/ruleengine/transformation/custom/RemoveObservationByCodeTest.groovy diff --git a/shared/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiHelper.java b/shared/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiHelper.java index b9592129c..8ff7cb02f 100644 --- a/shared/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiHelper.java +++ b/shared/src/main/java/gov/hhs/cdc/trustedintermediary/external/hapi/HapiHelper.java @@ -13,6 +13,7 @@ import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.MessageHeader; import org.hl7.fhir.r4.model.Meta; +import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Practitioner; @@ -684,25 +685,55 @@ public static String urlForCodeType(String code) { } /** - * Check if a given Coding resource has alternate coding, and if it has a value of the expected - * type. + * Check if a given Coding resource has a coding extension and coding system extension with the + * specified type. * * @param coding the resource to check. Expected to be converted from an HL7 CWE format field. - * @param codingSystem Name of coding system to look for (e.g. Local code, LOINC...) + * @param codingExt Name of coding extension (e.g. "coding", "alt-coding") + * @param codingSystemExt Name of coding system to look for (e.g. Local code "L", LOINC "LN"...) * @return True if the Coding is formatted correctly and has the expected code type, else false */ - public static Boolean hasDefinedAlternateCoding(Coding coding, String codingSystem) { - if (!HapiHelper.hasCodingSystem(coding) - || !HapiHelper.hasCodingExtensionWithUrl(coding, HapiHelper.EXTENSION_CWE_CODING)) { + public static boolean hasDefinedCoding( + Coding coding, String codingExt, String codingSystemExt) { + var codingExtMatch = + hasMatchingCodingExtension(coding, HapiHelper.EXTENSION_CWE_CODING, codingExt); + var codingSystemExtMatch = + hasMatchingCodingExtension( + coding, HapiHelper.EXTENSION_CODING_SYSTEM, codingSystemExt); + return codingExtMatch && codingSystemExtMatch; + } + + private static boolean hasMatchingCodingExtension( + Coding coding, String extensionUrl, String valueToMatch) { + if (!HapiHelper.hasCodingExtensionWithUrl(coding, extensionUrl)) { return false; } - var cwe = - HapiHelper.getCodingExtensionByUrl(coding, HapiHelper.EXTENSION_CWE_CODING) - .getValue() - .toString(); + var extensionValue = + HapiHelper.getCodingExtensionByUrl(coding, extensionUrl).getValue().toString(); + return Objects.equals(valueToMatch, extensionValue); + } - return Objects.equals(cwe, HapiHelper.EXTENSION_ALT_CODING) - && HapiHelper.getCodingSystem(coding).equals(codingSystem); + /** + * Check if an observation has a Coding resource with the given code, coding, and coding system + * + * @param codeToMatch The code to look for. + * @param codingExtToMatch Name of coding extension (e.g. "coding", "alt-coding") + * @param codingSystemToMatch Name of coding system to look for (e.g. Local code "L", LOINC + * "LN"...) + * @return True if the Coding is present in the observation, else false + */ + public static boolean hasMatchingCoding( + Observation observation, + String codeToMatch, + String codingExtToMatch, + String codingSystemToMatch) { + for (Coding coding : observation.getCode().getCoding()) { + if (Objects.equals(coding.getCode(), codeToMatch) + && hasDefinedCoding(coding, codingExtToMatch, codingSystemToMatch)) { + return true; + } + } + return false; } } diff --git a/shared/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiHelperTest.groovy b/shared/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiHelperTest.groovy index a4f8d9494..b8ff46c6b 100644 --- a/shared/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiHelperTest.groovy +++ b/shared/src/test/groovy/gov/hhs/cdc/trustedintermediary/external/hapi/HapiHelperTest.groovy @@ -931,4 +931,24 @@ class HapiHelperTest extends Specification { def pr = HapiHelper.getPractitioner(role) pr.id == practitioner.id } + + def "hasDefinedCoding returns the correct result"() { + given: + def coding = new Coding() + coding.code = "SOME_CODE" + coding.addExtension(HapiHelper.EXTENSION_CWE_CODING, new StringType("coding")) + coding.addExtension(HapiHelper.EXTENSION_CODING_SYSTEM, new StringType("L")) + + when: + def actualResult = HapiHelper.hasDefinedCoding(coding, codingExt, codingSystemExt) + + then: + actualResult == expectedResult + + where: + codingExt | codingSystemExt || expectedResult + "coding" | "L" || true + "alt-coding" | "L" || false + "coding" | "LN" || false + } }