Skip to content

Commit ec31b65

Browse files
authored
fix: Encounter Diagnosis (#101)
* first pass, encounter diagnosis bug * update validation num errors (increased) -- see PR notes * update snapshot tests * If encounter has same ID as encompassing encounter, dont create dup Encounter resource * encounter diagnoses conditions should only come from encounter * forgot to rm a line * update snapshot tests * no longer makes dup encounter facility location resource if ids are the same
1 parent 5d16398 commit ec31b65

File tree

12 files changed

+2852
-37
lines changed

12 files changed

+2852
-37
lines changed

data/Templates/eCR/EICR.liquid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
{% include 'Section/Result' -%}
3333
{% include 'Section/SocialHistory' -%}
3434
{% include 'Section/VitalSign' -%}
35+
{% include 'Section/Encounter' -%}
3536
{% include 'Section/PlanOfTreatment' -%}
3637
{% include 'Section/AdmissionMedication' -%}
3738
{% include 'Section/Procedure' -%}

data/Templates/eCR/Entry/Encounter/_entry.liquid

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
{% assign encounterId = entry | to_json_string | generate_uuid -%}
2-
{% include 'Resource/Encounter' encounter: entry.encounter, ID: encounterId -%}
3-
{% include 'Reference/Encounter/Subject' ID: encounterId, REF: fullPatientId -%}
1+
{% comment %} If encounter has same ID as encompassing encounter, don't create Encounter resource (duplicate) {% endcomment %}
2+
{% if entry.encounter.id.extension != encompassingEncounterId.extension or entry.encounter.id.root != encompassingEncounterId.root %}
3+
{% assign encounterId = entry | to_json_string | generate_uuid -%}
4+
{% include 'Resource/Encounter' encounter: entry.encounter, ID: encounterId -%}
5+
{% include 'Reference/Encounter/Subject' ID: encounterId, REF: fullPatientId -%}
6+
{% endif %}
47

58
{% if entry.encounter.performer.assignedEntity -%}
69
{% assign entity = entry.encounter.performer.assignedEntity %}

data/Templates/eCR/Entry/Encounter/_entry_encounter_entryRelationship_act_entryRelationship.liquid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
{% include 'Resource/Condition' conditionEntry: entryRelationship.observation, ID: observationId -%}
44
{% include 'Reference/Condition/Subject' ID: observationId, REF: fullPatientId -%}
55
{% assign fullObservationId = observationId | prepend: 'Condition/' -%}
6-
{% include 'Reference/Encounter/Diagnosis_Condition' ID: encounterId, -%}
6+
{% include 'Reference/Encounter/Diagnosis_Condition' ID: encounterId, REF: fullObservationId -%}
77
{% endif -%}
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
{% if participant.typeCode == 'LOC' -%}
22
{% assign templateIdString = participant.participantRole.templateId | to_json_string -%}
33
{% if templateIdString contains '"2.16.840.1.113883.10.20.22.4.32"'-%}
4-
{% assign locationId = participant.participantRole | to_json_string | generate_uuid -%}
5-
{% include 'Resource/Location' location: participant.participantRole, ID: locationId -%}
6-
{% assign fullLocationId = locationId | prepend: 'Location/' -%}
7-
{% include 'Reference/Encounter/Location_Location' ID: encounterId, REF: fullLocationId -%}
4+
{% comment %} If location has same ID as encompassing encounter facility, don't create Location resource (duplicate) {% endcomment %}
5+
{% if participant.participantRole.id.root != facilityId.root or participant.participantRole.id.extension != facilityId.extension %}
6+
{% assign locationId = participant.participantRole | to_json_string | generate_uuid -%}
7+
{% include 'Resource/Location' location: participant.participantRole, ID: locationId -%}
8+
{% assign fullLocationId = locationId | prepend: 'Location/' -%}
9+
{% include 'Reference/Encounter/Location_Location' ID: encounterId, REF: fullLocationId -%}
10+
{% endif %}
811
{% endif -%}
912
{% endif -%}

data/Templates/eCR/Entry/Problem/_entry_act_entryRelationship.liquid

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,6 @@
44
{% assign conditionId = probRelationship.observation | to_json_string | generate_uuid -%}
55
{% include 'Resource/Condition' conditionEntry: probRelationship.observation, ID: conditionId, text: text, relatedEntries: relatedEntries -%}
66
{% include 'Reference/Condition/Subject' ID: conditionId, REF: fullPatientId -%}
7-
{% assign isDiagnosis = diagnoses[probRelationship.observation.value.code] %}
8-
{% if isDiagnosis -%}
9-
{% assign fullConditionId = conditionId | prepend: 'Condition/' -%}
10-
{% include 'Reference/Encounter/Diagnosis_Condition' ID: encounterId, REF: fullConditionId -%}
11-
{% endif -%}
127
{% endif -%}
138
{% endif -%}
149
{% endif -%}

data/Templates/eCR/Header.liquid

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,42 @@
1-
{% evaluate practitionerId using 'Utils/GenerateId' obj: msg.ClinicalDocument.componentOf.encompassingEncounter.responsibleParty.assignedEntity -%}
21
{% assign compositionId = msg.ClinicalDocument | to_json_string | generate_uuid -%}
2+
{% evaluate practitionerId using 'Utils/GenerateId' obj: msg.ClinicalDocument.componentOf.encompassingEncounter.responsibleParty.assignedEntity -%}
33
{% include 'Resource/Composition' composition: msg.ClinicalDocument, practitionerId: practitionerId, ID: compositionId -%}
44
{% include 'Reference/Composition/Subject' ID: compositionId, REF: fullPatientId -%}
55

66
{% if msg.ClinicalDocument.relatedDocument -%}
77
{% include 'Reference/Composition/RelatesTo_TargetReference' ID: compositionId, relatedDOC: msg.ClinicalDocument.relatedDocument -%}
88
{% endif -%}
99

10-
{% if msg.ClinicalDocument.componentOf.encompassingEncounter -%}
11-
{% assign encounterId = msg.ClinicalDocument.componentOf.encompassingEncounter | to_json_string | generate_uuid -%}
12-
{% include 'Resource/Encounter' encounter: msg.ClinicalDocument.componentOf.encompassingEncounter, ID: encounterId -%}
13-
{% assign encounterSection = msg | get_first_ccda_sections_by_template_id: '2.16.840.1.113883.10.20.22.2.22.1' %}
14-
{% assign encounterEntries = encounterSection.2_16_840_1_113883_10_20_22_2_22_1.entry | to_array %}
15-
{% assign diagnoses = encounterEntries | get_diagnosis_dictionary %}
10+
11+
12+
{% comment %} Encompassing Encounter {% endcomment %}
13+
{% assign encompassingEncounter = msg.ClinicalDocument.componentOf.encompassingEncounter %}
14+
{% if encompassingEncounter -%}
15+
{% assign encounterId = encompassingEncounter | to_json_string | generate_uuid -%}
16+
{% assign encompassingEncounterId = encompassingEncounter.id %}
17+
{% include 'Resource/Encounter' encounter: encompassingEncounter, ID: encounterId -%}
18+
1619
{% include 'Reference/Encounter/Subject' ID: encounterId, REF: fullPatientId -%}
1720
{% assign fullEncounterId = encounterId | prepend: 'Encounter/' -%}
1821
{% include 'Reference/Composition/Encounter' ID: compositionId, REF: fullEncounterId -%}
19-
{% if msg.ClinicalDocument.componentOf.encompassingEncounter.location.healthCareFacility -%}
20-
{% assign locationId = msg.ClinicalDocument.componentOf.encompassingEncounter.location.healthCareFacility | to_json_string | generate_uuid -%}
21-
{% include 'Resource/LocationHealthCareFacility' location: msg.ClinicalDocument.componentOf.encompassingEncounter.location.healthCareFacility ID: locationId -%}
22+
{% comment %} Encompassing Encounter - Facility / Service Provider {% endcomment %}
23+
{% if encompassingEncounter.location.healthCareFacility -%}
24+
{% assign locationId = encompassingEncounter.location.healthCareFacility | to_json_string | generate_uuid -%}
25+
{% assign facilityId = encompassingEncounter.location.healthCareFacility.id %}
26+
{% include 'Resource/LocationHealthCareFacility' location: encompassingEncounter.location.healthCareFacility ID: locationId -%}
2227
{% assign fullLocationId = locationId | prepend: 'Location/' -%}
23-
{% include 'Reference/Encounter/Location_Location' ID: encounterId, REF: fullLocationId, LOC: msg.ClinicalDocument.componentOf.encompassingEncounter.location.healthCareFacility -%}
24-
{% if msg.ClinicalDocument.componentOf.encompassingEncounter.location.healthCareFacility.serviceProviderOrganization -%}
25-
{% assign serviceProviderId = msg.ClinicalDocument.componentOf.encompassingEncounter.location.healthCareFacility.serviceProviderOrganization | to_json_string | generate_uuid -%}
26-
{% include 'Resource/Organization' organization: msg.ClinicalDocument.componentOf.encompassingEncounter.location.healthCareFacility.serviceProviderOrganization ID: serviceProviderId -%}
28+
{% include 'Reference/Encounter/Location_Location' ID: encounterId, REF: fullLocationId, LOC: encompassingEncounter.location.healthCareFacility -%}
29+
{% if encompassingEncounter.location.healthCareFacility.serviceProviderOrganization -%}
30+
{% assign serviceProviderId = encompassingEncounter.location.healthCareFacility.serviceProviderOrganization | to_json_string | generate_uuid -%}
31+
{% include 'Resource/Organization' organization: encompassingEncounter.location.healthCareFacility.serviceProviderOrganization ID: serviceProviderId -%}
2732
{% assign fullServiceProviderId = serviceProviderId | prepend: 'Organization/' -%}
2833
{% include 'Reference/Encounter/ServiceProvider' ID: encounterId, REF: fullServiceProviderId -%}
2934
{% endif -%}
3035
{% endif -%}
3136
{% endif -%}
3237

33-
{% assign responsibleParty = msg.ClinicalDocument.componentOf.encompassingEncounter.responsibleParty.assignedEntity -%}
38+
{% comment %} Encompassing Encounter - Responsible Party {% endcomment %}
39+
{% assign responsibleParty = encompassingEncounter.responsibleParty.assignedEntity -%}
3440
{% if responsibleParty -%}
3541
{% include 'Resource/PractitionerResponsibleParty' practitioner: responsibleParty ID: practitionerId -%}
3642
{% assign fullPractitionerId = practitionerId | prepend: 'Practitioner/' -%}
@@ -49,7 +55,8 @@
4955
{% endif %}
5056
{% endif -%}
5157

52-
{% assign encounterParticipants = msg.ClinicalDocument.componentOf.encompassingEncounter.encounterParticipant | to_array -%}
58+
{% comment %} Encompassing Encounter - Practitioner {% endcomment %}
59+
{% assign encounterParticipants = encompassingEncounter.encounterParticipant | to_array -%}
5360
{% for encounterParticipant in encounterParticipants -%}
5461
{% if encounterParticipant.assignedEntity -%}
5562
{% assign encounterParticipantId = encounterParticipant | to_json_string | generate_uuid %}
@@ -71,8 +78,8 @@
7178
{% endif -%}
7279
{% endfor -%}
7380

81+
{% comment %} Reportability Response {% endcomment %}
7482
{% if msg.ClinicalDocument.section.code.code and msg.ClinicalDocument.section.code.code == "88085-6" -%}
75-
{% comment %} Reportability Response {% endcomment %}
7683
{% assign sectionId = msg.ClinicalDocument.section | to_json_string | generate_uuid -%}
7784
{% assign entries = msg.ClinicalDocument.section.entry | to_array -%}
7885
{% for entry in entries -%}

src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/BaseConvertDataFunctionalTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -239,11 +239,11 @@ public static IEnumerable<object[]> GetDataForEcr()
239239
// 4. whether the file should fail at parsing or validation when testing if valid (if it is fully valid, "validation" is what should be there)
240240
// 5. The number of expected failures at the step in (4) for the numFailures parameter
241241
// ]
242-
new[] { @"EICR", @"eCR_full.xml", @"eCR_full-expected.json", "validation", "4" },
243-
new[] { @"EICR", @"eCR_RR_combined_3_1.xml", @"eCR_RR_combined_3_1-expected.json", "validation", "10" },
244-
new[] { @"EICR", @"eCR_EveEverywoman.xml", @"eCR_EveEverywoman-expected.json", "validation", "32" },
245-
new[] { @"EICR", @"eicr04152020.xml", @"eicr04152020-expected.json", "validation", "15" },
246-
new[] { @"EICR", @"CDAR2_IG_PHCASERPT_R2_D2_SAMPLE.xml", @"CDAR2_IG_PHCASERPT_R2_D2_SAMPLE-expected.json", "validation", "15" },
242+
new[] { @"EICR", @"eCR_full.xml", @"eCR_full-expected.json", "validation", "5" },
243+
new[] { @"EICR", @"eCR_RR_combined_3_1.xml", @"eCR_RR_combined_3_1-expected.json", "validation", "13" },
244+
new[] { @"EICR", @"eCR_EveEverywoman.xml", @"eCR_EveEverywoman-expected.json", "validation", "34" },
245+
new[] { @"EICR", @"eicr04152020.xml", @"eicr04152020-expected.json", "validation", "16" },
246+
new[] { @"EICR", @"CDAR2_IG_PHCASERPT_R2_D2_SAMPLE.xml", @"CDAR2_IG_PHCASERPT_R2_D2_SAMPLE-expected.json", "validation", "17" },
247247
};
248248
return data.Select(item => new[]
249249
{

src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/TestData/Expected/eCR/EICR/CDAR2_IG_PHCASERPT_R2_D2_SAMPLE-expected.json

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,6 +2713,117 @@
27132713
}
27142714
}
27152715
},
2716+
{
2717+
"fullUrl": "urn:uuid:60f4995b-0f6c-b4e8-c29a-c36542e2b2a8",
2718+
"resource": {
2719+
"resourceType": "Encounter",
2720+
"id": "60f4995b-0f6c-b4e8-c29a-c36542e2b2a8",
2721+
"status": "finished",
2722+
"class": {
2723+
"code": "99213",
2724+
"system": "http://www.ama-assn.org/go/cpt",
2725+
"display": "Office outpatient visit 15 minutes"
2726+
},
2727+
"identifier": [
2728+
{
2729+
"system": "urn:ietf:rfc:3986",
2730+
"value": "urn:uuid:2a620155-9d11-439e-92b3-5d9815ff4de8"
2731+
}
2732+
],
2733+
"period": {
2734+
"start": "2018-11-07"
2735+
},
2736+
"subject": {
2737+
"reference": "Patient/f238f1ae-2f55-cd21-5c90-5e68a10af8ce"
2738+
},
2739+
"diagnosis": [
2740+
{
2741+
"condition": {
2742+
"reference": "Condition/63cd2d6d-0c98-bfb5-d095-6ce01717a8e8"
2743+
}
2744+
},
2745+
{
2746+
"condition": {
2747+
"reference": "Condition/f1a6114a-a5b8-a264-43d1-e8bd0a205c3b"
2748+
}
2749+
}
2750+
]
2751+
}
2752+
},
2753+
{
2754+
"fullUrl": "urn:uuid:63cd2d6d-0c98-bfb5-d095-6ce01717a8e8",
2755+
"resource": {
2756+
"resourceType": "Condition",
2757+
"id": "63cd2d6d-0c98-bfb5-d095-6ce01717a8e8",
2758+
"identifier": [
2759+
{
2760+
"system": "urn:ietf:rfc:3986",
2761+
"value": "urn:uuid:db734647-fc99-424c-a864-7e3cda82e705"
2762+
}
2763+
],
2764+
"category": [
2765+
{
2766+
"coding": [
2767+
{
2768+
"code": "problem-item-list",
2769+
"display": "Problem List Item",
2770+
"system": "http://hl7.org/fhir/us/core/ValueSet/us-core-condition-category"
2771+
}
2772+
]
2773+
}
2774+
],
2775+
"code": {
2776+
"coding": [
2777+
{
2778+
"code": "27836007",
2779+
"system": "http://snomed.info/sct",
2780+
"display": "Pertussis (disorder)"
2781+
}
2782+
]
2783+
},
2784+
"onsetDateTime": "2018-11-07",
2785+
"subject": {
2786+
"reference": "Patient/f238f1ae-2f55-cd21-5c90-5e68a10af8ce"
2787+
}
2788+
}
2789+
},
2790+
{
2791+
"fullUrl": "urn:uuid:f1a6114a-a5b8-a264-43d1-e8bd0a205c3b",
2792+
"resource": {
2793+
"resourceType": "Condition",
2794+
"id": "f1a6114a-a5b8-a264-43d1-e8bd0a205c3b",
2795+
"identifier": [
2796+
{
2797+
"system": "urn:ietf:rfc:3986",
2798+
"value": "urn:uuid:db734647-fc99-424c-a864-7e3cda82e704"
2799+
}
2800+
],
2801+
"category": [
2802+
{
2803+
"coding": [
2804+
{
2805+
"code": "problem-item-list",
2806+
"display": "Problem List Item",
2807+
"system": "http://hl7.org/fhir/us/core/ValueSet/us-core-condition-category"
2808+
}
2809+
]
2810+
}
2811+
],
2812+
"code": {
2813+
"coding": [
2814+
{
2815+
"code": "282291009",
2816+
"system": "http://snomed.info/sct",
2817+
"display": "A non-trigger code diagnosis (disorder)"
2818+
}
2819+
]
2820+
},
2821+
"onsetDateTime": "2018-11-07",
2822+
"subject": {
2823+
"reference": "Patient/f238f1ae-2f55-cd21-5c90-5e68a10af8ce"
2824+
}
2825+
}
2826+
},
27162827
{
27172828
"fullUrl": "urn:uuid:cb80de39-1dcf-4c6a-417a-bd959b762dc2",
27182829
"resource": {

src/Microsoft.Health.Fhir.Liquid.Converter.FunctionalTests/TestData/Expected/eCR/EICR/eCR_EveEverywoman-expected.json

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3914,6 +3914,117 @@
39143914
}
39153915
}
39163916
},
3917+
{
3918+
"fullUrl": "urn:uuid:85744e06-7bb7-62ca-a543-0357159d4f87",
3919+
"resource": {
3920+
"resourceType": "Encounter",
3921+
"id": "85744e06-7bb7-62ca-a543-0357159d4f87",
3922+
"status": "finished",
3923+
"class": {
3924+
"code": "99213",
3925+
"system": "http://www.ama-assn.org/go/cpt",
3926+
"display": "Office outpatient visit 15 minutes"
3927+
},
3928+
"identifier": [
3929+
{
3930+
"system": "urn:ietf:rfc:3986",
3931+
"value": "urn:uuid:2a620155-9d11-439e-92b3-5d9815ff4de8"
3932+
}
3933+
],
3934+
"period": {
3935+
"start": "2020-11-07"
3936+
},
3937+
"subject": {
3938+
"reference": "Patient/f238f1ae-2f55-cd21-5c90-5e68a10af8ce"
3939+
},
3940+
"diagnosis": [
3941+
{
3942+
"condition": {
3943+
"reference": "Condition/607e2d2f-19cf-79dd-31dc-275476eb4399"
3944+
}
3945+
},
3946+
{
3947+
"condition": {
3948+
"reference": "Condition/350d4497-d22c-8e23-ba25-657f671b8ada"
3949+
}
3950+
}
3951+
]
3952+
}
3953+
},
3954+
{
3955+
"fullUrl": "urn:uuid:607e2d2f-19cf-79dd-31dc-275476eb4399",
3956+
"resource": {
3957+
"resourceType": "Condition",
3958+
"id": "607e2d2f-19cf-79dd-31dc-275476eb4399",
3959+
"identifier": [
3960+
{
3961+
"system": "urn:ietf:rfc:3986",
3962+
"value": "urn:uuid:db734647-fc99-424c-a864-7e3cda82e705"
3963+
}
3964+
],
3965+
"category": [
3966+
{
3967+
"coding": [
3968+
{
3969+
"code": "problem-item-list",
3970+
"display": "Problem List Item",
3971+
"system": "http://hl7.org/fhir/us/core/ValueSet/us-core-condition-category"
3972+
}
3973+
]
3974+
}
3975+
],
3976+
"code": {
3977+
"coding": [
3978+
{
3979+
"code": "27836007",
3980+
"system": "http://snomed.info/sct",
3981+
"display": "Pertussis (disorder)"
3982+
}
3983+
]
3984+
},
3985+
"onsetDateTime": "2020-11-07",
3986+
"subject": {
3987+
"reference": "Patient/f238f1ae-2f55-cd21-5c90-5e68a10af8ce"
3988+
}
3989+
}
3990+
},
3991+
{
3992+
"fullUrl": "urn:uuid:350d4497-d22c-8e23-ba25-657f671b8ada",
3993+
"resource": {
3994+
"resourceType": "Condition",
3995+
"id": "350d4497-d22c-8e23-ba25-657f671b8ada",
3996+
"identifier": [
3997+
{
3998+
"system": "urn:ietf:rfc:3986",
3999+
"value": "urn:uuid:db734647-fc99-424c-a864-7e3cda82e704"
4000+
}
4001+
],
4002+
"category": [
4003+
{
4004+
"coding": [
4005+
{
4006+
"code": "problem-item-list",
4007+
"display": "Problem List Item",
4008+
"system": "http://hl7.org/fhir/us/core/ValueSet/us-core-condition-category"
4009+
}
4010+
]
4011+
}
4012+
],
4013+
"code": {
4014+
"coding": [
4015+
{
4016+
"code": "282291009",
4017+
"system": "http://snomed.info/sct",
4018+
"display": "A non-trigger code diagnosis (disorder)"
4019+
}
4020+
]
4021+
},
4022+
"onsetDateTime": "2020-11-07",
4023+
"subject": {
4024+
"reference": "Patient/f238f1ae-2f55-cd21-5c90-5e68a10af8ce"
4025+
}
4026+
}
4027+
},
39174028
{
39184029
"fullUrl": "urn:uuid:49200334-0c15-5a04-bf2c-b96a087ec490",
39194030
"resource": {

0 commit comments

Comments
 (0)