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