Skip to content

Commit

Permalink
feat: add marital status and religion (#2975)
Browse files Browse the repository at this point in the history
* feat: add marital status and religion

* test: longer timeout, fix snapshot

* feat: plumb through soc-history, clean up use of evaluateValue

* fix: handle valueBoolean

* test: moar tests

* Update containers/ecr-viewer/src/app/tests/utils.test.tsx

Co-authored-by: austin-hall-skylight <[email protected]>

* fix: update to new release

---------

Co-authored-by: austin-hall-skylight <[email protected]>
  • Loading branch information
mcmcgrath13 and austin-hall-skylight authored Dec 4, 2024
1 parent 0127fc2 commit c69e278
Show file tree
Hide file tree
Showing 10 changed files with 266 additions and 15 deletions.
20 changes: 11 additions & 9 deletions containers/ecr-viewer/src/app/api/fhirPath.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,20 @@ patientRaceDetailed: "Bundle.entry.resource.where(resourceType = 'Patient').exte
patientEthnicity: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity').extension.where(url = 'ombCategory').valueCoding.display"
patientEthnicityDetailed: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url = 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity').extension.where(url = 'detailed').valueCoding.display"
patientLanguage: "Bundle.entry.resource.where(resourceType = 'Patient').communication.first().language.coding.first().display"
patientTribalAffiliation: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url='http: //hl7.org/fhir/us/ecr/StructureDefinition/us-ph-tribal-affiliation-extension').extension.where(url='TribeName').value.display"
patientTribalAffiliation: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url='http://hl7.org/fhir/us/ecr/StructureDefinition/us-ph-tribal-affiliation-extension').extension.where(url='TribeName').value"
patientEmergencyContact: "Bundle.entry.resource.where(resourceType = 'Patient').contact"

# Social History
patientCurrentJobTitle: "Bundle.entry.resource.where(resourceType='Observation').where(meta.profile='http://hl7.org/fhir/us/odh/StructureDefinition/odh-PastOrPresentJob').where(effectivePeriod.end.exists().not()).iif(valueCodeableConcept.coding.display.exists(), valueCodeableConcept.coding.display, valueString)"
patientTobaccoUse: "Bundle.entry.resource.where(resourceType='Observation').where(code.coding.code='72166-2').where(category.coding.code='social-history').iif(valueCodeableConcept.coding.display.exists(), valueCodeableConcept.coding.display, valueString)"
patientDisabilityStatus: "Bundle.entry.resource.where(resourceType='Observation').where(meta.profile='http://hl7.org/fhir/us/ecr/StructureDefinition/us-ph-disability-status').where(category.coding.code='social-history').iif(valueBoolean.code.coding.display.exists(), valueBoolean.code.coding.display, valueString)"
patientHomelessStatus: "Bundle.entry.resource.where(resourceType='Observation').where(code.coding.code='75274-1').where(category.coding.code='social-history').iif(valueCodeableConcept.coding.display.exists(), valueCodeableConcept.coding.display, valueString)"
patientPregnancyStatus: "Bundle.entry.resource.where(resourceType='Observation').where(meta.profile='http://hl7.org/fhir/us/ecr/StructureDefinition/us-ph-pregnancy-status-observation').iif(valueCodeableConcept.coding.display.exists(), valueCodeableConcept.coding.display, valueString)"
patientAlcoholUse: "Bundle.entry.resource.where(resourceType='Observation').where(code.coding.code='11331-6').where(category.coding.code='social-history').iif(valueCodeableConcept.coding.display.exists(), valueCodeableConcept.coding.display, valueString)"
patientSexualOrientation: "Bundle.entry.resource.where(resourceType='Observation').where(code.coding.code='76690-7').iif(valueCodeableConcept.coding.display.exists(), valueCodeableConcept.coding.display, valueString)"
patientGenderIdentity: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url='http://hl7.org/fhir/us/ecr/StructureDefinition/us-ph-genderidentity-extension').extension.iif(valueCodeableConcept.coding.display.exists(), valueCodeableConcept.coding.display, valueString)"
patientCurrentJobTitle: "Bundle.entry.resource.where(resourceType='Observation').where(meta.profile='http://hl7.org/fhir/us/odh/StructureDefinition/odh-PastOrPresentJob').where(effectivePeriod.end.exists().not()).value"
patientTobaccoUse: "Bundle.entry.resource.where(resourceType='Observation').where(code.coding.code='72166-2').where(category.coding.code='social-history').value"
patientDisabilityStatus: "Bundle.entry.resource.where(resourceType='Observation').where(meta.profile='http://hl7.org/fhir/us/ecr/StructureDefinition/us-ph-disability-status').where(category.coding.code='social-history').value"
patientHomelessStatus: "Bundle.entry.resource.where(resourceType='Observation').where(code.coding.code='75274-1').where(category.coding.code='social-history').value"
patientPregnancyStatus: "Bundle.entry.resource.where(resourceType='Observation').where(meta.profile='http://hl7.org/fhir/us/ecr/StructureDefinition/us-ph-pregnancy-status-observation').value"
patientAlcoholUse: "Bundle.entry.resource.where(resourceType='Observation').where(code.coding.code='11331-6').where(category.coding.code='social-history').value"
patientSexualOrientation: "Bundle.entry.resource.where(resourceType='Observation').where(code.coding.code='76690-7').value"
patientGenderIdentity: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url='http://hl7.org/fhir/us/ecr/StructureDefinition/us-ph-genderidentity-extension').value"
patientReligion: "Bundle.entry.resource.where(resourceType = 'Patient').extension.where(url='http://hl7.org/fhir/StructureDefinition/patient-religion').value"
patientMaritalStatus: "Bundle.entry.resource.where(resourceType = 'Patient').maritalStatus"

#eCR Metadata
eicrIdentifier: "Bundle.entry.resource.where(resourceType= 'Composition').id"
Expand Down
26 changes: 22 additions & 4 deletions containers/ecr-viewer/src/app/services/evaluateFhirDataService.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
Bundle,
CodeableConcept,
Coding,
Condition,
Encounter,
Location,
Expand Down Expand Up @@ -250,6 +251,14 @@ export const evaluateSocialData = (
title: "Occupation",
value: evaluateValue(fhirBundle, mappings["patientCurrentJobTitle"]),
},
{
title: "Religious Affiliation",
value: evaluateValue(fhirBundle, mappings["patientReligion"]),
},
{
title: "Marital Status",
value: evaluateValue(fhirBundle, mappings["patientMaritalStatus"]),
},
];
return evaluateData(socialData);
};
Expand Down Expand Up @@ -300,7 +309,7 @@ export const evaluateDemographicsData = (
},
{
title: "Tribal Affiliation",
value: evaluate(fhirBundle, mappings.patientTribalAffiliation)[0],
value: evaluateValue(fhirBundle, mappings.patientTribalAffiliation),
},
{
title: "Preferred Language",
Expand Down Expand Up @@ -566,7 +575,7 @@ export const evaluateReference = (
};

/**
* Evaluates the FHIR path and returns the appropriate string value. Supports choice elements
* Evaluates the FHIR path and returns the appropriate string value. Supports choice elements (e.g. using `.value` in path to get valueString or valueCoding)
* @param entry - The FHIR resource to evaluate.
* @param path - The path within the resource to extract the value from.
* @returns - The evaluated value as a string.
Expand All @@ -576,7 +585,11 @@ export const evaluateValue = (entry: Element, path: string | Path): string => {

let value = "";
const originalValuePath = originalValue?.__path__?.path;
if (typeof originalValue === "string" || typeof originalValue === "number") {
if (
typeof originalValue === "string" ||
typeof originalValue === "number" ||
typeof originalValue === "boolean"
) {
value = originalValue.toString();
} else if (originalValuePath === "Quantity") {
const data = originalValue as Quantity;
Expand All @@ -588,10 +601,15 @@ export const evaluateValue = (entry: Element, path: string | Path): string => {
value = `${data.value ?? ""}${unit ?? ""}`;
} else if (originalValuePath === "CodeableConcept") {
const data = originalValue as CodeableConcept;
value = data.coding?.[0].display || data.text || "";
value =
data.coding?.[0].display || data.text || data.coding?.[0].code || "";
} else if (originalValuePath === "Coding") {
const data = originalValue as Coding;
value = data?.display || data?.code || "";
} else if (typeof originalValue === "object") {
console.log(`Not implemented for ${originalValue.__path__}`);
}

return value.trim();
};

Expand Down
37 changes: 37 additions & 0 deletions containers/ecr-viewer/src/app/tests/assets/BundlePatient.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,34 @@
}
}
]
},
{
"url": "http://hl7.org/fhir/StructureDefinition/patient-religion",
"valueCodeableConcept": {
"coding": [
{
"code": "Baptist",
"system": "urn:oid:2.16.840.1.113883.5.1076"
}
]
}
},
{
"url": "http://hl7.org/fhir/us/ecr/StructureDefinition/us-ph-tribal-affiliation-extension",
"extension": [
{
"url": "TribeName",
"valueCoding": {
"code": "91",
"system": "http://terminology.hl7.org/CodeSystem/v3-TribalEntityUS",
"display": "Fort Mojave Indian Tribe of Arizona, California"
}
},
{
"url": "EnrolledTribeMember",
"valueBoolean": true
}
]
}
],
"address": [
Expand All @@ -111,6 +139,15 @@
"postalCode": "93523-2800"
}
],
"maritalStatus": {
"coding": [
{
"code": "M",
"system": "urn:oid:2.16.840.1.113883.5.2",
"display": "Married"
}
]
},
"telecom": [
{
"system": "phone",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,44 @@ exports[`Snapshot test for Accordion Content Given no data, info message for emp
class="section__line_gray"
/>
</div>
<div>
<div
class="grid-row"
>
<div
class="data-title padding-right-1"
>
Religious Affiliation
</div>
<div
class="grid-col maxw7 text-pre-line p-list text-italic text-base"
>
No data
</div>
</div>
<div
class="section__line_gray"
/>
</div>
<div>
<div
class="grid-row"
>
<div
class="data-title padding-right-1"
>
Marital Status
</div>
<div
class="grid-col maxw7 text-pre-line p-list text-italic text-base"
>
No data
</div>
</div>
<div
class="section__line_gray"
/>
</div>
</div>
</div>
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
evaluateEmergencyContact,
evaluatePatientAddress,
evaluatePatientName,
evaluateDemographicsData,
} from "@/app/services/evaluateFhirDataService";
import { Bundle, Patient } from "fhir/r4";
import BundleWithMiscNotes from "@/app/tests/assets/BundleMiscNotes.json";
Expand Down Expand Up @@ -59,6 +60,7 @@ describe("evaluate value", () => {
coding: [
{
display: "Negative",
code: "N",
},
],
},
Expand All @@ -68,6 +70,61 @@ describe("evaluate value", () => {

expect(actual).toEqual("Negative");
});
it("should provide the string in the case of valueCoding", () => {
const actual = evaluateValue(
{
resourceType: "Extension",
valueCoding: {
display: "Negative",
code: "N",
},
} as any,
"value",
);

expect(actual).toEqual("Negative");
});
it("should provide the string in the case of valueBoolean", () => {
const actual = evaluateValue(
{
resourceType: "Extension",
valueBoolean: true,
} as any,
"value",
);

expect(actual).toEqual("true");
});
it("should provide the code as a fallback in the case of valueCodeableConcept", () => {
const actual = evaluateValue(
{
resourceType: "Observation",
valueCodeableConcept: {
coding: [
{
code: "N",
},
],
},
} as any,
"value",
);

expect(actual).toEqual("N");
});
it("should provide the code as a fallback in the case of valueCoding", () => {
const actual = evaluateValue(
{
resourceType: "Extension",
valueCoding: {
code: "N",
},
} as any,
"value",
);

expect(actual).toEqual("N");
});
describe("Quantity", () => {
it("should provide the value and string unit with a space inbetween", () => {
const actual = evaluateValue(
Expand Down Expand Up @@ -125,6 +182,20 @@ describe("Evaluate Patient Ethnicity", () => {
});
});

it("should return tribal affiliation if available", () => {
const actual = evaluateDemographicsData(
BundleWithPatient as unknown as Bundle,
mappings,
);
const ext = actual.availableData.filter(
(d) => d.title === "Tribal Affiliation",
);
expect(ext).toHaveLength(1);
expect(ext[0].value).toEqual(
"Fort Mojave Indian Tribe of Arizona, California",
);
});

describe("Evaluate Facility Id", () => {
it("should return the facility id", () => {
const actual = evaluateFacilityId(
Expand Down
22 changes: 22 additions & 0 deletions containers/ecr-viewer/src/app/tests/utils.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,28 @@ describe("Utils", () => {

expect(actual.availableData[0].value).toEqual("Other");
});
it("should return religion if available", () => {
const actual = evaluateSocialData(
BundleWithPatient as unknown as Bundle,
mappings,
);
const ext = actual.availableData.filter(
(d) => d.title === "Religious Affiliation",
);
expect(ext).toHaveLength(1);
expect(ext[0].value).toEqual("Baptist");
});
it("should return marital status if available", () => {
const actual = evaluateSocialData(
BundleWithPatient as unknown as Bundle,
mappings,
);
const ext = actual.availableData.filter(
(d) => d.title === "Marital Status",
);
expect(ext).toHaveLength(1);
expect(ext[0].value).toEqual("Married");
});
});

describe("Evaluate Clinical Info", () => {
Expand Down
2 changes: 1 addition & 1 deletion containers/fhir-converter/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build

# Download FHIR-Converter
RUN git clone https://github.com/skylight-hq/FHIR-Converter.git --branch v7.0-skylight-13 --single-branch /build/FHIR-Converter
RUN git clone https://github.com/skylight-hq/FHIR-Converter.git --branch v7.0-skylight-14 --single-branch /build/FHIR-Converter

WORKDIR /build/FHIR-Converter

Expand Down
Loading

0 comments on commit c69e278

Please sign in to comment.