Skip to content

Commit bf17c1a

Browse files
fix: Invalid template reference, bug when device manufacturer name contains quotes, bug caused by multiple CarePlan activities (#90)
1 parent 9435231 commit bf17c1a

File tree

7 files changed

+257
-6
lines changed

7 files changed

+257
-6
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
{% if med %}
3737
{% assign medId = med | to_json_string | generate_uuid -%}
3838
{% assign fullMedId = medId | prepend: 'MedicationRequest/' %}
39-
{% include 'Reference/CarePlan/ActivityReference' ID: carePlanId, REF: fullMedId -%}
39+
{% include 'Reference/CarePlan/Activity_Reference' ID: carePlanId, REF: fullMedId -%}
4040
{% include 'Resource/MedicationRequest' medicationRequest: med, ID: medId, intent: "plan" -%}
4141
{% include 'Reference/MedicationRequest/Subject' ID: medId, REF: fullPatientId -%}
4242

data/Templates/eCR/Resource/_CarePlan.liquid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
{% capture time %}{% include 'Utils/EffectiveTime' effectiveTime: act.effectiveTime, timeType: "scheduled" %}{% endcapture %}
4848
{{ time | replace_first: "DateTime", "String" }}
4949
}
50-
}
50+
},
5151
{% endif %}
5252
{% endfor %}
5353
]

data/Templates/eCR/Resource/_Device.liquid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
{% include 'DataType/Identifier' Identifier: id -%}
1111
{% endfor -%}
1212
],
13-
"manufacturer":"{{ author.assignedAuthoringDevice.manufacturerModelName._ }}",
13+
"manufacturer":"{{ author.assignedAuthoringDevice.manufacturerModelName._ | escape_special_chars }}",
1414
"version":
1515
[
1616
{

data/Templates/eCR/Resource/_Device2.liquid

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
{% else -%}
1717
{ {% include 'DataType/CodeableConcept' CodeableConcept: deviceEntry.participant.participantRole.playingDevice.code -%} },
1818
{% endif -%}
19-
"manufacturer":"{{deviceEntry.participant.participantRole.scopingEntity.desc._}}",
19+
"manufacturer":"{{deviceEntry.participant.participantRole.scopingEntity.desc._ | escape_special_chars}}",
2020
"deviceName": [{
2121
"name": "{{ deviceName }}",
2222
}],

src/Microsoft.Health.Fhir.Liquid.Converter.UnitTests/Templates/eCR/Resource/CarePlan.cs

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public void CarePlan_AllFields_Act()
2929
Hash.FromAnonymousObject(
3030
new {
3131
id = new { root = "ab1791b0-5c71-11db-b0de-0800200c9a54", },
32-
entry = new {
32+
entry = new {
3333
act = new {
3434
id = new { root = "ab1791b0-5c71-11db-b0de-0800200c9a55", },
3535
moodCode = "RQO",
@@ -86,7 +86,7 @@ public void CarePlan_AllFields_Encounter()
8686
Hash.FromAnonymousObject(
8787
new {
8888
id = new { root = "ab1791b0-5c71-11db-b0de-0800200c9a54", },
89-
entry = new {
89+
entry = new {
9090
encounter = new {
9191
id = new { root = "ab1791b0-5c71-11db-b0de-0800200c9a55", },
9292
moodCode = "ARQ",
@@ -124,5 +124,76 @@ public void CarePlan_AllFields_Encounter()
124124
Assert.Equal(CarePlan.CarePlanActivityKind.Appointment, detail.Kind);
125125
Assert.Equal("Why not", detail.ReasonCode.First().Coding.First().Code);
126126
}
127+
128+
[Fact]
129+
public void CarePlan_AllFields_MultipleEntries()
130+
{
131+
var attributes = new Dictionary<string, object>
132+
{
133+
{ "ID", "1234" },
134+
{ "patientReference", "Patient/4566" },
135+
{
136+
"carePlan",
137+
Hash.FromAnonymousObject(
138+
new {
139+
id = new { root = "ab1791b0-5c71-11db-b0de-0800200c9a54", },
140+
entry = new object[] {
141+
new {
142+
act = new {
143+
id = new { root = "ab1791b0-5c71-11db-b0de-0800200c9a55", },
144+
moodCode = "RQO",
145+
code = new
146+
{
147+
originalText = new
148+
{
149+
_ = "Colonoscopy",
150+
},
151+
},
152+
effectiveTime = new {
153+
value = "20201101"
154+
},
155+
entryRelationship = new object[] {
156+
new {
157+
typeCode = "RSON",
158+
observation = new { value = new { code = "Why not" } },
159+
},
160+
new {
161+
typeCode = "RSON",
162+
observation = new { value = new { code = "Couldn't hurt" } },
163+
},
164+
},
165+
}
166+
},
167+
new {
168+
act = new {
169+
id = new { root = "ab1791b0-5c71-11db-b0de-0800200c9a56", },
170+
moodCode = "RQO",
171+
code = new
172+
{
173+
originalText = new
174+
{
175+
_ = "Esophagogastroduodenoscopy",
176+
},
177+
},
178+
effectiveTime = new {
179+
value = "20201101"
180+
},
181+
entryRelationship = new object[] {
182+
new {
183+
typeCode = "RSON",
184+
observation = new { value = new { code = "Another one" } },
185+
},
186+
},
187+
}
188+
},
189+
}
190+
}
191+
)
192+
},
193+
};
194+
var actualFhir = GetFhirObjectFromTemplate<CarePlan>(ECRPath, attributes);
195+
196+
Assert.Equal(2, actualFhir.Activity.Count());
197+
}
127198
}
128199
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
4+
using DotLiquid;
5+
using Hl7.Fhir.Model;
6+
using Xunit;
7+
using Microsoft.Health.Fhir.Liquid.Converter.Parsers;
8+
using System;
9+
10+
namespace Microsoft.Health.Fhir.Liquid.Converter.UnitTests
11+
{
12+
public class DeviceTests : BaseECRLiquidTests
13+
{
14+
private static readonly string ECRPath = Path.Join(
15+
TestConstants.ECRTemplateDirectory,
16+
"Resource",
17+
"_Device.liquid"
18+
);
19+
20+
[Fact]
21+
public void Device_AllFields()
22+
{
23+
var xmlStr = @"
24+
<assignedAuthor>
25+
<id root=""4bc8554b-gb7e-4b08-06fe-40c2af85afdb""/>
26+
<addr>
27+
<streetAddressLine nullFlavor=""NI""/>
28+
<city nullFlavor=""NI""/>
29+
<state nullFlavor=""NI""/>
30+
<postalCode nullFlavor=""NI""/>
31+
<country nullFlavor=""NI""/>
32+
</addr>
33+
<telecom nullFlavor=""NI""/>
34+
<assignedAuthoringDevice>
35+
<manufacturerModelName>""Some_EHR""</manufacturerModelName>
36+
<softwareName>2025.9</softwareName>
37+
</assignedAuthoringDevice>
38+
</assignedAuthor>
39+
";
40+
41+
var parsed = new CcdaDataParser().Parse(xmlStr) as Dictionary<string, object>;
42+
var attributes = new Dictionary<string, object>
43+
{
44+
{ "author", parsed["assignedAuthor"]},
45+
{ "ID", "1234" },
46+
};
47+
48+
var actualFhir = GetFhirObjectFromTemplate<Device>(ECRPath, attributes);
49+
50+
Assert.Equal(ResourceType.Device.ToString(), actualFhir.TypeName);
51+
Assert.NotNull(actualFhir.Id);
52+
Assert.NotEmpty(actualFhir.Identifier);
53+
Assert.Equal("\"Some_EHR\"", actualFhir.Manufacturer);
54+
Assert.Equal("2025.9", actualFhir.Version.First().Value);
55+
Assert.Equal("http://hl7.org/fhir/device-category" ,actualFhir.Property.First().Type.Coding.First().System);
56+
Assert.Equal("software", actualFhir.Property.First().Type.Coding.First().Code);
57+
Assert.Equal("software", actualFhir.Property.First().Type.Coding.First().Display);
58+
}
59+
}
60+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
using System.Collections.Generic;
2+
using System.IO;
3+
using System.Linq;
4+
using DotLiquid;
5+
using Hl7.Fhir.Model;
6+
using Xunit;
7+
using Microsoft.Health.Fhir.Liquid.Converter.Parsers;
8+
using System;
9+
using Hl7.Fhir.Serialization;
10+
11+
namespace Microsoft.Health.Fhir.Liquid.Converter.UnitTests
12+
{
13+
public class Device2Tests : BaseECRLiquidTests
14+
{
15+
private static readonly string ECRPath = Path.Join(
16+
TestConstants.ECRTemplateDirectory,
17+
"Resource",
18+
"_Device2.liquid"
19+
);
20+
21+
[Fact]
22+
public void Device2_CodeInRoot()
23+
{
24+
var xmlStr = @"
25+
<supply classCode=""SPLY"" moodCode=""EVN"">
26+
<id root=""cf75f5be-1da0-4256-8276-94b7fc73f9f9"" />
27+
<code code=""87405001"" displayName=""cane"" codeSystem=""2.16.840.1.113883.6.96""
28+
codeSystemName=""SNOMED CT"">
29+
<originalText>Upper GI Prosthesis</originalText>
30+
</code>
31+
<participant typeCode=""PRD"">
32+
<participantRole classCode=""MANU"">
33+
<scopingEntity>
34+
<desc>""Good Health Durable Medical Equipment""</desc>
35+
</scopingEntity>
36+
</participantRole>
37+
</participant>
38+
</supply>
39+
";
40+
41+
var parsed = new CcdaDataParser().Parse(xmlStr) as Dictionary<string, object>;
42+
var attributes = new Dictionary<string, object>
43+
{
44+
{ "deviceEntry", parsed["supply"]},
45+
{ "ID", "1234" },
46+
};
47+
48+
var actualFhir = GetFhirObjectFromTemplate<Device>(ECRPath, attributes);
49+
50+
Assert.Equal(ResourceType.Device.ToString(), actualFhir.TypeName);
51+
Assert.NotNull(actualFhir.Id);
52+
Assert.NotEmpty(actualFhir.Identifier);
53+
Assert.Equal("87405001", actualFhir.Type.Coding.First().Code);
54+
Assert.Equal("http://snomed.info/sct", actualFhir.Type.Coding.First().System);
55+
Assert.Equal("cane", actualFhir.Type.Coding.First().Display);
56+
Assert.Equal("\"Good Health Durable Medical Equipment\"", actualFhir.Manufacturer);
57+
Assert.Equal("", actualFhir.DeviceName.First().Name);
58+
}
59+
60+
[Fact]
61+
public void Device2_CodeInPlayingDevice()
62+
{
63+
var xmlStr = @"
64+
<supply classCode=""SPLY"" moodCode=""EVN"">
65+
<id root=""cf75f5be-1da0-4256-8276-94b7fc73f9f9"" />
66+
<participant typeCode=""PRD"">
67+
<participantRole classCode=""MANU"">
68+
<playingDevice>
69+
<code code=""87405001"" displayName=""cane"" codeSystem=""2.16.840.1.113883.6.96""
70+
codeSystemName=""SNOMED CT"">
71+
<originalText>Upper GI Prosthesis</originalText>
72+
</code>
73+
</playingDevice>
74+
<scopingEntity>
75+
<desc>""Good Health Durable Medical Equipment""</desc>
76+
</scopingEntity>
77+
</participantRole>
78+
</participant>
79+
</supply>
80+
";
81+
82+
var parsed = new CcdaDataParser().Parse(xmlStr) as Dictionary<string, object>;
83+
var attributes = new Dictionary<string, object>
84+
{
85+
{ "deviceEntry", parsed["supply"]},
86+
{ "ID", "1234" },
87+
};
88+
89+
var actualFhir = GetFhirObjectFromTemplate<Device>(ECRPath, attributes);
90+
91+
Assert.Equal(ResourceType.Device.ToString(), actualFhir.TypeName);
92+
Assert.NotNull(actualFhir.Id);
93+
Assert.NotEmpty(actualFhir.Identifier);
94+
Assert.Equal("87405001", actualFhir.Type.Coding.First().Code);
95+
Assert.Equal("http://snomed.info/sct", actualFhir.Type.Coding.First().System);
96+
Assert.Equal("cane", actualFhir.Type.Coding.First().Display);
97+
Assert.Equal("\"Good Health Durable Medical Equipment\"", actualFhir.Manufacturer);
98+
Assert.Equal("", actualFhir.DeviceName.First().Name);
99+
}
100+
101+
[Fact]
102+
public void Device2_DeviceNameOnly()
103+
{
104+
var attributes = new Dictionary<string, object>
105+
{
106+
{ "ID", "1234" },
107+
{ "deviceName", "cane" },
108+
};
109+
110+
var actualFhir = GetFhirObjectFromTemplate<Device>(ECRPath, attributes);
111+
112+
Assert.Equal(ResourceType.Device.ToString(), actualFhir.TypeName);
113+
Assert.NotNull(actualFhir.Id);
114+
Assert.Empty(actualFhir.Identifier);
115+
Assert.Empty(actualFhir.Type.Coding);
116+
Assert.Equal("", actualFhir.Manufacturer);
117+
Assert.Equal("cane", actualFhir.DeviceName.First().Name);
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)