From 32b36f0fca5bca40238ea2526d5fccb95ad6dcdb Mon Sep 17 00:00:00 2001 From: Lucero Velasco <165824244+lucero-v@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:33:28 -0700 Subject: [PATCH] MMTC sender transform and getStateFromZipCode custom fhir function (#16440) * added mmtc sender transform and custom fhir path function that grabs the state(s) from the given zip code --- .../engine/CustomFhirPathFunctions.kt | 32 ++++++++ .../senders/MMTC/mmtc-sender-transform.yml | 12 +++ .../engine/CustomFhirPathFunctionTest.kt | 82 +++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 prime-router/src/main/resources/metadata/fhir_transforms/senders/MMTC/mmtc-sender-transform.yml diff --git a/prime-router/src/main/kotlin/fhirengine/engine/CustomFhirPathFunctions.kt b/prime-router/src/main/kotlin/fhirengine/engine/CustomFhirPathFunctions.kt index 0083feea221..b0e19c12982 100644 --- a/prime-router/src/main/kotlin/fhirengine/engine/CustomFhirPathFunctions.kt +++ b/prime-router/src/main/kotlin/fhirengine/engine/CustomFhirPathFunctions.kt @@ -36,6 +36,7 @@ class CustomFhirPathFunctions : FhirPathFunctions { LivdTableLookup, GetFakeValueForElement, FIPSCountyLookup, + GetStateFromZipCode, ; companion object { @@ -84,6 +85,14 @@ class CustomFhirPathFunctions : FhirPathFunctions { ) } + CustomFhirPathFunctionNames.GetStateFromZipCode -> { + FunctionDetails( + "Looks up the states that match the given zip code", + 0, + 0 + ) + } + else -> null } } @@ -110,6 +119,9 @@ class CustomFhirPathFunctions : FhirPathFunctions { CustomFhirPathFunctionNames.FIPSCountyLookup -> { fipsCountyLookup(parameters) } + CustomFhirPathFunctionNames.GetStateFromZipCode -> { + getStateFromZipCode(focus) + } else -> error(IllegalStateException("Tried to execute invalid FHIR Path function $functionName")) } ) @@ -353,4 +365,24 @@ class CustomFhirPathFunctions : FhirPathFunctions { mutableListOf(StringType(parameters.first().first().primitiveValue())) } } + + /** + * Returns a comma-separated string of the states that + * match the zip code stored in the [focus] element. + * @return a mutable list containing the state abbreviations + */ + fun getStateFromZipCode( + focus: MutableList, + metadata: Metadata = Metadata.getInstance(), + ): MutableList { + val lookupTable = metadata.findLookupTable("zip-code-data") + var filters = lookupTable?.FilterBuilder() ?: error("Could not find table zip-code-data") + + val zipCode = focus[0].primitiveValue() + filters = filters.isEqualTo("zipcode", zipCode) + val result = filters.findAllUnique("state_abbr") + + val stateList = result.joinToString(",") + return mutableListOf(StringType(stateList)) + } } \ No newline at end of file diff --git a/prime-router/src/main/resources/metadata/fhir_transforms/senders/MMTC/mmtc-sender-transform.yml b/prime-router/src/main/resources/metadata/fhir_transforms/senders/MMTC/mmtc-sender-transform.yml new file mode 100644 index 00000000000..60110a9f807 --- /dev/null +++ b/prime-router/src/main/resources/metadata/fhir_transforms/senders/MMTC/mmtc-sender-transform.yml @@ -0,0 +1,12 @@ +extends: classpath:/metadata/fhir_transforms/senders/original-pipeline-transforms.yml + +elements: + - name: patient-state-from-zip-code + resource: "Bundle.entry.resource.ofType(Patient).address" + bundleProperty: '%resource.extension("https://reportstream.cdc.gov/fhir/StructureDefinition/state-from-zip-code").value[x]' + value: [ '%resource.postalCode.getStateFromZipCode()' ] + + - name: ordering-facility-state-from-zip-code + resource: "Bundle.entry.resource.ofType(ServiceRequest).requester.resolve().organization.resolve().address" + bundleProperty: '%resource.extension("https://reportstream.cdc.gov/fhir/StructureDefinition/state-from-zip-code").value[x]' + value: [ '%resource.postalCode.getStateFromZipCode()' ] diff --git a/prime-router/src/test/kotlin/fhirengine/engine/CustomFhirPathFunctionTest.kt b/prime-router/src/test/kotlin/fhirengine/engine/CustomFhirPathFunctionTest.kt index 95f92e40785..7080940cfc9 100644 --- a/prime-router/src/test/kotlin/fhirengine/engine/CustomFhirPathFunctionTest.kt +++ b/prime-router/src/test/kotlin/fhirengine/engine/CustomFhirPathFunctionTest.kt @@ -2,6 +2,7 @@ package gov.cdc.prime.router.fhirengine.engine import assertk.assertFailure import assertk.assertThat +import assertk.assertions.contains import assertk.assertions.isEqualTo import assertk.assertions.isNotNull import assertk.assertions.isNull @@ -323,4 +324,85 @@ class CustomFhirPathFunctionTest { (result[0] as StringType).value ).isEqualTo("Shasta") } + + @Test + fun `test getting state from zip code - one state`() { + val testTable = Table.create( + "zip-code-data", + StringColumn.create("state_fips", "40", "48", "6"), + StringColumn.create("state", "Oklahoma", "Texas", "California"), + StringColumn.create("state_abbr", "OK", "TX", "CA"), + StringColumn.create("zipcode", "73949", "73949", "92356"), + StringColumn.create("county", "Texas", "Sherman", "San Bernardino"), + StringColumn.create("city", "Texhoma", "", "Lucerne valley") + + ) + val testLookupTable = LookupTable(name = "zip-code-data", table = testTable) + + mockkConstructor(Metadata::class) + every { anyConstructed().findLookupTable("zip-code-data") } returns testLookupTable + mockkObject(Metadata) + every { Metadata.getInstance() } returns UnitTestUtils.simpleMetadata + + val result = CustomFhirPathFunctions().getStateFromZipCode(mutableListOf(StringType("92356"))) + + assertThat( + (result[0] as StringType).value + ).isEqualTo("CA") + } + + @Test + fun `test getting state from zip code - multiple states`() { + val testTable = Table.create( + "zip-code-data", + StringColumn.create("state_fips", "40", "48", "6"), + StringColumn.create("state", "Oklahoma", "Texas", "California"), + StringColumn.create("state_abbr", "OK", "TX", "CA"), + StringColumn.create("zipcode", "73949", "73949", "92356"), + StringColumn.create("county", "Texas", "Sherman", "San Bernardino"), + StringColumn.create("city", "Texhoma", "", "Lucerne valley") + + ) + val testLookupTable = LookupTable(name = "zip-code-data", table = testTable) + + mockkConstructor(Metadata::class) + every { anyConstructed().findLookupTable("zip-code-data") } returns testLookupTable + mockkObject(Metadata) + every { Metadata.getInstance() } returns UnitTestUtils.simpleMetadata + + val result = CustomFhirPathFunctions().getStateFromZipCode(mutableListOf(StringType("73949"))) + + assertThat( + (result[0] as StringType).value + ).contains("OK") + assertThat( + (result[0] as StringType).value + ).contains("TX") + } + + @Test + fun `test getting state from zip code - no matching state found`() { + val testTable = Table.create( + "zip-code-data", + StringColumn.create("state_fips", "40", "48", "6"), + StringColumn.create("state", "Oklahoma", "Texas", "California"), + StringColumn.create("state_abbr", "OK", "TX", "CA"), + StringColumn.create("zipcode", "73949", "73949", "92356"), + StringColumn.create("county", "Texas", "Sherman", "San Bernardino"), + StringColumn.create("city", "Texhoma", "", "Lucerne valley") + + ) + val testLookupTable = LookupTable(name = "zip-code-data", table = testTable) + + mockkConstructor(Metadata::class) + every { anyConstructed().findLookupTable("zip-code-data") } returns testLookupTable + mockkObject(Metadata) + every { Metadata.getInstance() } returns UnitTestUtils.simpleMetadata + + val result = CustomFhirPathFunctions().getStateFromZipCode(mutableListOf(StringType("79902"))) + + assertThat( + (result[0] as StringType).value + ).isEqualTo("") + } } \ No newline at end of file