health-data-standards 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,14 @@
1
+ require 'ostruct'
2
+
3
+ module HealthDataStandards
4
+ module Export
5
+ class RenderingContext < OpenStruct
6
+ include TemplateHelper
7
+ include ViewHelper
8
+
9
+ def my_binding
10
+ binding
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,35 @@
1
+ module HealthDataStandards
2
+ module Export
3
+ module TemplateHelper
4
+ attr_accessor :template_format
5
+
6
+ def template_root
7
+ File.join(File.dirname(__FILE__), '..', '..', '..', 'templates')
8
+ end
9
+
10
+ def template(template_name)
11
+ File.read(File.join(template_root, "#{template_name}.#{self.template_format}.erb"))
12
+ end
13
+
14
+ def partial(partial_name)
15
+ template("_#{partial_name}")
16
+ end
17
+
18
+ def render(params)
19
+ #binding.pry
20
+ erb = nil
21
+ if params[:template]
22
+ erb = template(params[:template])
23
+ elsif params[:partial]
24
+ erb = partial(params[:partial])
25
+ end
26
+ locals = params[:locals]
27
+ locals ||= {}
28
+ rendering_context = RenderingContext.new(locals)
29
+ rendering_context.template_format = self.template_format
30
+ eruby = Erubis::EscapedEruby.new(erb)
31
+ eruby.result(rendering_context.my_binding)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ module HealthDataStandards
2
+ module Export
3
+ module ViewHelper
4
+ def code_display(entry, tag_name='code', extra_content=nil)
5
+ if entry.single_code_value?
6
+ code = entry.codes.first[1].first
7
+ code_system_oid = QME::Importer::CodeSystemHelper.oid_for_code_system(entry.codes.first[0])
8
+ "<#{tag_name} code=\"#{code}\" codeSystem=\"#{code_system_oid}\" #{extra_content}><originalText>#{ERB::Util.html_escape entry.description}</originalText></#{tag_name}>"
9
+ else
10
+ all_codes = []
11
+ entry.codes.each_pair {|key, values| values.each {|v| all_codes << {:set => key, :value => v}}}
12
+ first_code = all_codes.first
13
+ code_string = "<#{tag_name} code=\"#{first_code[:value]}\" codeSystem=\"#{QME::Importer::CodeSystemHelper.oid_for_code_system(first_code[:set])}\">\n"
14
+ code_string += "<originalText>#{ERB::Util.html_escape entry.description}</originalText>\n"
15
+ all_codes[1..-1].each do |cv|
16
+ code_string += "<translation code=\"#{cv[:value]}\" codeSystem=\"#{QME::Importer::CodeSystemHelper.oid_for_code_system(cv[:set])}\"/>\n"
17
+ end
18
+ code_string += "</#{tag_name}>"
19
+ code_string
20
+ end
21
+ end
22
+
23
+ def status_code_for(entry)
24
+ case entry.status.to_s
25
+ when 'active'
26
+ '55561003'
27
+ when 'inactive'
28
+ '73425007'
29
+ when 'resolved'
30
+ '413322009'
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,51 @@
1
+ class Entry
2
+
3
+ include Mongoid::Document
4
+
5
+ embedded_in :entry_list, polymorphic: true
6
+
7
+ field :description, type: String
8
+ field :time, type: Integer
9
+ field :start_time, type: Integer
10
+ field :end_time, type: Integer
11
+ field :status, type: Symbol
12
+ field :codes, type: Hash
13
+ field :value, type: Hash
14
+
15
+ def single_code_value?
16
+ codes.size == 1 && codes.first[1].size == 1
17
+ end
18
+
19
+ def codes_to_s
20
+ codes.map {|code_set, codes| "#{code_set}: #{codes.join(', ')}"}.join(' ')
21
+ end
22
+
23
+ def times_to_s
24
+ if start_time.present? || end_time.present?
25
+ start_string = start_time ? Time.at(start_time).to_formatted_s(:long_ordinal) : 'UNK'
26
+ end_string = end_time ? Time.at(end_time).to_formatted_s(:long_ordinal) : 'UNK'
27
+ "#{start_string} - #{end_string}"
28
+ elsif time.present?
29
+ Time.at(time).to_formatted_s(:long_ordinal)
30
+ end
31
+ end
32
+
33
+ def to_effective_time(xml)
34
+ if time.present?
35
+ xml.effectiveTime("value" => Time.at(time).utc.to_formatted_s(:number))
36
+ else
37
+ xml.effectiveTime do
38
+ if start_time.present?
39
+ xml.low("value" => Time.at(start_time).utc.to_formatted_s(:number))
40
+ else
41
+ xml.low("nullFlavor" => "UNK")
42
+ end
43
+ if end_time.present?
44
+ xml.high("value" => Time.at(end_time).utc.to_formatted_s(:number))
45
+ else
46
+ xml.high("nullFlavor" => "UNK")
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,21 @@
1
+ class Record
2
+
3
+ include Mongoid::Document
4
+
5
+ field :first, type: String
6
+ field :last, type: String
7
+ field :gender, type: String
8
+ field :birthdate, type: Integer
9
+ field :race, type: String
10
+ field :ethnicity, type: String
11
+ field :test_id, type: BSON::ObjectId
12
+
13
+ [:allergies, :care_goals, :conditions, :encounters, :immunizations, :medical_equipment,
14
+ :medications, :procedures, :results, :social_history, :vital_signs].each do |section|
15
+ embeds_many section, as: :entry_list, class_name: "Entry"
16
+ end
17
+
18
+ def over_18?
19
+ Time.at(birthdate) < Time.now.years_ago(18)
20
+ end
21
+ end
@@ -0,0 +1,57 @@
1
+ <component>
2
+ <!--Allergies/Reactions-->
3
+ <section>
4
+ <templateId root="2.16.840.1.113883.3.88.11.83.102" assigningAuthorityName="HITSP/C83"/>
5
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.3.13" assigningAuthorityName="IHE PCC"/>
6
+ <templateId root="2.16.840.1.113883.10.20.1.2" assigningAuthorityName="HL7 CCD"/>
7
+ <!--Allergies/Reactions section template-->
8
+ <code code="48765-2" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="Allergies"/>
9
+ <title>Allergies and Adverse Reactions</title>
10
+ <%== render :partial => 'narrative_block', :locals => {:entries => entries, :section => 'allergies'} %>
11
+ <% entries.each_with_index do |entry, i| -%>
12
+ <entry typeCode="DRIV">
13
+ <act classCode="ACT" moodCode="EVN">
14
+ <templateId root="2.16.840.1.113883.3.88.11.83.6"/>
15
+ <templateId root="2.16.840.1.113883.10.20.1.27"/>
16
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.5.3"/>
17
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.5.1"/>
18
+ <!--Allergy act template -->
19
+ <id root="<%= UUID.generate %>"/>
20
+ <code nullFlavor="NA"/>
21
+ <statusCode code="active"/>
22
+ <effectiveTime>
23
+ <low value="<%= Time.at(entry.time).utc.to_formatted_s(:number) %>"/>
24
+ </effectiveTime>
25
+ <entryRelationship typeCode="SUBJ" inversionInd="false">
26
+ <observation classCode="OBS" moodCode="EVN">
27
+ <templateId root="2.16.840.1.113883.10.20.1.18"/>
28
+ <templateId root="2.16.840.1.113883.10.20.1.28"/>
29
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.6"/>
30
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.5"/>
31
+ <id root="<%= UUID.generate %>"/>
32
+ <code code="416098002" codeSystem="2.16.840.1.113883.6.96" displayName="drug allergy" codeSystemName="SNOMED CT">
33
+ <originalText><reference value="#allergies-desc-<%= i %>"/></originalText>
34
+ </code>
35
+ <text>
36
+ <reference value="#allergies-desc-<%= i %>"/>
37
+ </text>
38
+ <statusCode code="completed"/>
39
+ <effectiveTime>
40
+ <low value="<%= Time.at(entry.time).utc.to_formatted_s(:number) %>"/>
41
+ </effectiveTime>
42
+ <value xsi:type="CD" nullFlavor="UNK"/>
43
+ <participant typeCode="CSM">
44
+ <participantRole classCode="MANU">
45
+ <playingEntity classCode="MMAT">
46
+ <%== render :partial => 'code_with_reference', :locals => {:entry => entry, :i => i, :section => 'allergies'} %>
47
+ <name><%= entry.description %></name>
48
+ </playingEntity>
49
+ </participantRole>
50
+ </participant>
51
+ </observation>
52
+ </entryRelationship>
53
+ </act>
54
+ </entry>
55
+ <% end -%>
56
+ </section>
57
+ </component>
@@ -0,0 +1,24 @@
1
+ <component>
2
+ <!--Plan of Care-->
3
+ <section>
4
+ <templateId root="2.16.840.1.113883.3.88.11.83.124" assigningAuthorityName="HITSP/C83"/>
5
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.3.31" assigningAuthorityName="IHE PCC"/>
6
+ <templateId root="2.16.840.1.113883.10.20.2.7" assigningAuthorityName="HL7 CCD"/>
7
+ <templateId root="2.16.840.1.113883.10.20.1.10" assigningAuthorityName="HL7 CCD"/>
8
+ <!--Plan of Care section template-->
9
+ <code code="18776-5" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="Treatment plan"/>
10
+ <%== render :partial => 'narrative_block', :locals => {:entries => entries, :section => 'plan_of_care'} %>
11
+ <% entries.each do |entry| -%>
12
+ <entry typeCode="DRIV">
13
+ <observation classCode="OBS" moodCode="RQO">
14
+ <templateId root="2.16.840.1.113883.10.20.1.25"/>
15
+ <!-- Plan of Activity activity template -->
16
+ <id root="<%= UUID.generate %>"/>
17
+ <%== code_display(entry) %>
18
+ <statusCode code="new"/>
19
+ <effectiveTime value="<%= Time.at(entry.time).utc.to_formatted_s(:number) %>"/>
20
+ </observation>
21
+ </entry>
22
+ <% end -%>
23
+ </section>
24
+ </component>
@@ -0,0 +1,8 @@
1
+ <% if entry.single_code_value?
2
+ code = entry.codes.first[1].first
3
+ code_system_oid = QME::Importer::CodeSystemHelper.oid_for_code_system(entry.codes.first[0])
4
+ -%>
5
+ <code code="<%= code %>" codeSystem="<%= code_system_oid %>">
6
+ <originalText><reference value="#<%= section %>-desc-<%= i %>"/></originalText>
7
+ </code>
8
+ <% end -%>
@@ -0,0 +1,61 @@
1
+ <component>
2
+ <!--Problems-->
3
+ <section>
4
+ <templateId root="2.16.840.1.113883.3.88.11.83.103" assigningAuthorityName="HITSP/C83"/>
5
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.3.6" assigningAuthorityName="IHE PCC"/>
6
+ <templateId root="2.16.840.1.113883.10.20.1.11" assigningAuthorityName="HL7 CCD"/>
7
+ <!--Problems section template-->
8
+ <code code="11450-4" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="Problem list"/>
9
+ <title>Problems</title>
10
+ <%== render :partial => 'narrative_block', :locals => {:entries => entries, :section => 'conditions'} %>
11
+ <% entries.each_with_index do |entry, i| -%>
12
+ <entry typeCode="DRIV">
13
+ <act classCode="ACT" moodCode="EVN">
14
+ <templateId root="2.16.840.1.113883.3.88.11.83.7" assigningAuthorityName="HITSP C83"/>
15
+ <templateId root="2.16.840.1.113883.10.20.1.27"/>
16
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.5.1" assigningAuthorityName="IHE PCC"/>
17
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.5.2" assigningAuthorityName="IHE PCC"/>
18
+ <!-- Problem act template -->
19
+ <id root="<%= UUID.generate %>"/>
20
+ <code nullFlavor="NA"/>
21
+ <% if entry.status.eql? 'resolved' -%>
22
+ <statusCode code="completed"/>
23
+ <% else -%>
24
+ <statusCode code="active"/>
25
+ <% end -%>
26
+ <effectiveTime>
27
+ <low value="<%= Time.at(entry.time).utc.to_formatted_s(:number) %>"/>
28
+ </effectiveTime>
29
+ <entryRelationship typeCode="SUBJ" inversionInd="false">
30
+ <observation classCode="OBS" moodCode="EVN">
31
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.5" assigningAuthorityName="IHE PCC"/>
32
+ <templateId root="2.16.840.1.113883.10.20.1.28" assigningAuthorityName="CCD"/>
33
+ <!--Problem observation template - NOT episode template-->
34
+ <id root="<%= UUID.generate %>"/>
35
+ <code code="64572001" displayName="Condition" codeSystem="2.16.840.1.113883.6.96" codeSystemName="SNOMED-CT"/>
36
+ <text>
37
+ <reference value="#conditions-desc-<%= i %>"/>
38
+ </text>
39
+ <statusCode code="completed"/>
40
+ <effectiveTime>
41
+ <low value="<%= Time.at(entry.time).utc.to_formatted_s(:number) %>"/>
42
+ </effectiveTime>
43
+ <%== code_display(entry, 'value', 'xsi:type="CD"') %>
44
+ <% if entry.status -%>
45
+ <entryRelationship typeCode="REFR">
46
+ <observation classCode="OBS" moodCode="EVN">
47
+ <templateId root="2.16.840.1.113883.10.20.1.50"/>
48
+ <!-- Problem status observation template -->
49
+ <code code="33999-4" codeSystem="2.16.840.1.113883.6.1" displayName="Status"/>
50
+ <statusCode code="completed"/>
51
+ <value xsi:type="CE" code="<%= status_code_for(entry) %>" codeSystem="2.16.840.1.113883.6.96"/>
52
+ </observation>
53
+ </entryRelationship>
54
+ <% end -%>
55
+ </observation>
56
+ </entryRelationship>
57
+ </act>
58
+ </entry>
59
+ <% end -%>
60
+ </section>
61
+ </component>
@@ -0,0 +1,28 @@
1
+ <component>
2
+ <!--Encounters-->
3
+ <section>
4
+ <templateId root="2.16.840.1.113883.3.88.11.83.127" assigningAuthorityName="HITSP/C83"/>
5
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.1.5.3.3" assigningAuthorityName="IHE PCC"/>
6
+ <templateId root="2.16.840.1.113883.10.20.1.3" assigningAuthorityName="HL7 CCD"/>
7
+ <!--Encounters section template-->
8
+ <code code="46240-8" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="History of encounters"/>
9
+ <title>Encounters</title>
10
+ <%== render :partial => 'narrative_block', :locals => {:entries => entries, :section => 'encounters'} %>
11
+ <% entries.each_with_index do |entry, i| -%>
12
+ <entry typeCode="DRIV">
13
+ <encounter classCode="ENC" moodCode="EVN">
14
+ <templateId root="2.16.840.1.113883.3.88.11.83.16" assigningAuthorityName="HITSP C83"/>
15
+ <templateId root="2.16.840.1.113883.10.20.1.21" assigningAuthorityName="CCD"/>
16
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.14" assigningAuthorityName="IHE PCC"/>
17
+ <!-- Encounter activity template -->
18
+ <id root="<%= UUID.generate %>"/>
19
+ <%== render :partial => 'code_with_reference', :locals => {:entry => entry, :i => i, :section => 'encounters'} %>
20
+ <text>
21
+ <reference value="#encounters-desc-<%= i %>"/>
22
+ </text>
23
+ <effectiveTime value="<%= Time.at(entry.time).utc.to_formatted_s(:number) %>"/>
24
+ </encounter>
25
+ </entry>
26
+ <% end -%>
27
+ </section>
28
+ </component>
@@ -0,0 +1,41 @@
1
+ <component>
2
+ <!--Immunizations-->
3
+ <section>
4
+ <templateId root="2.16.840.1.113883.3.88.11.83.117" assigningAuthorityName="HITSP/C83"/>
5
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.3.23" assigningAuthorityName="IHE PCC"/>
6
+ <templateId root="2.16.840.1.113883.10.20.1.6" assigningAuthorityName="HL7 CCD"/>
7
+ <!--Immunizations section template-->
8
+ <code code="11369-6" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" displayName="History of immunizations"/>
9
+ <title>Immunizations</title>
10
+ <%== render :partial => 'narrative_block', :locals => {:entries => entries, :section => 'immunizations'} %>
11
+ <% entries.each_with_index do |entry, i| -%>
12
+ <entry typeCode="DRIV">
13
+ <substanceAdministration classCode="SBADM" moodCode="EVN" negationInd="false">
14
+ <templateId root="2.16.840.1.113883.10.20.1.24"/>
15
+ <templateId root="2.16.840.1.113883.3.88.11.83.13" />
16
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.12"/>
17
+ <!-- Medication activity template -->
18
+ <id root="<%= UUID.generate %>"/>
19
+ <code code='IMMUNIZ' codeSystem='2.16.840.1.113883.5.4' codeSystemName='ActCode'/>
20
+ <text>
21
+ <reference value="#immunizations-desc-<%= i %>"/>
22
+ </text>
23
+ <statusCode code="completed"/>
24
+ <effectiveTime value="<%= Time.at(entry.time).utc.to_formatted_s(:number) %>"/>
25
+ <doseQuantity nullFlavor="UNK"/>
26
+ <consumable>
27
+ <manufacturedProduct>
28
+ <templateId root="2.16.840.1.113883.10.20.1.53"/>
29
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.7.2"/>
30
+ <!-- Product template -->
31
+ <manufacturedMaterial>
32
+ <%== render :partial => 'code_with_reference', :locals => {:entry => entry, :i => i, :section => 'immunizations'} %>
33
+ <name><%= entry.description %></name>
34
+ </manufacturedMaterial>
35
+ </manufacturedProduct>
36
+ </consumable>
37
+ </substanceAdministration>
38
+ </entry>
39
+ <% end -%>
40
+ </section>
41
+ </component>
@@ -0,0 +1,34 @@
1
+ <component>
2
+ <!--Medical Equipment - Not C32-->
3
+ <section>
4
+ <templateId root="2.16.840.1.113883.3.88.11.83.128" assigningAuthorityName="HITSP/C83"/>
5
+ <templateId root="2.16.840.1.113883.10.20.1.7" assigningAuthorityName="CCD"/>
6
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.1.5.3.5" assigningAuthorityName="IHE PCC"/>
7
+ <!-- Medical equipment section template -->
8
+ <code code="46264-8" codeSystem="2.16.840.1.113883.6.1"/>
9
+ <title>Medical Equipment</title>
10
+ <%== render :partial => 'narrative_block', :locals => {:entries => entries, :section => 'medical_equipment'} %>
11
+ <% entries.each_with_index do |entry, i| -%>
12
+ <entry typeCode="DRIV">
13
+ <supply classCode="SPLY" moodCode="EVN">
14
+ <templateId root="2.16.840.1.113883.10.20.1.34"/>
15
+ <!-- Supply activity template -->
16
+ <id root="<%= UUID.generate %>"/>
17
+ <statusCode code="completed"/>
18
+ <effectiveTime value="<%= Time.at(entry.time).utc.to_formatted_s(:number) %>"/>
19
+ <participant typeCode="DEV">
20
+ <participantRole classCode="MANU">
21
+ <templateId root="2.16.840.1.113883.10.20.1.52"/>
22
+ <!-- Product instance template -->
23
+ <addr/>
24
+ <telecom/>
25
+ <playingDevice>
26
+ <%== code_display(entry) %>
27
+ </playingDevice>
28
+ </participantRole>
29
+ </participant>
30
+ </supply>
31
+ </entry>
32
+ <% end -%>
33
+ </section>
34
+ </component>
@@ -0,0 +1,40 @@
1
+ <component>
2
+ <!--Medications-->
3
+ <section>
4
+ <templateId root="2.16.840.1.113883.10.20.1.8" assigningAuthorityName="HL7 SDTC CCD"/>
5
+ <templateId root="2.16.840.1.113883.3.88.11.83.112" assigningAuthorityName="HITSP"/>
6
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.3.19" assigningAuthorityName="IHE"/>
7
+ <code code="10160-0" displayName="History of medication use" codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC"/>
8
+ <title>Medications - Prescription and Non-Prescription</title>
9
+ <%== render :partial => 'narrative_block', :locals => {:entries => entries, :section => 'medications'} %>
10
+ <% entries.each_with_index do |entry, i| -%>
11
+ <entry>
12
+ <!--CCD Medication activity - Required-->
13
+ <substanceAdministration classCode="SBADM" moodCode="EVN">
14
+ <templateId root="2.16.840.1.113883.10.20.1.24" assigningAuthorityName="HL7 SDTC CCD"/>
15
+ <templateId root="2.16.840.1.113883.3.88.11.83.8"/>
16
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.7"/>
17
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.7.1"/>
18
+ <id root="<%= UUID.generate %>"/>
19
+ <statusCode code="completed"/>
20
+ <effectiveTime xsi:type="IVL_TS">
21
+ <low value="<%= Time.at(entry.time).utc.to_formatted_s(:number) %>"/>
22
+ <high nullFlavor="UNK"/>
23
+ </effectiveTime>
24
+ <consumable>
25
+ <!--CCD Product - Required-->
26
+ <manufacturedProduct classCode="MANU">
27
+ <templateId root="2.16.840.1.113883.10.20.1.53" assigningAuthorityName="HL7 SDTC CCD"/>
28
+ <templateId root="2.16.840.1.113883.3.88.11.83.8.2"/>
29
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.4.7.2"/>
30
+ <manufacturedMaterial>
31
+ <%== render :partial => 'code_with_reference', :locals => {:entry => entry, :i => i, :section => 'medications'} %>
32
+ <name><%= entry.description %></name>
33
+ </manufacturedMaterial>
34
+ </manufacturedProduct>
35
+ </consumable>
36
+ </substanceAdministration>
37
+ </entry>
38
+ <% end -%>
39
+ </section>
40
+ </component>