health-data-standards 0.8.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/health-data-standards/export/ccr.rb +1 -1
- data/lib/health-data-standards/export/csv.rb +6 -1
- data/lib/health-data-standards/export/green_c32/entry.rb +1 -1
- data/lib/health-data-standards/export/green_c32/record.rb +15 -0
- data/lib/health-data-standards/export/template_helper.rb +0 -2
- data/lib/health-data-standards/export/view_helper.rb +28 -2
- data/lib/health-data-standards/import/c32/allergy_importer.rb +12 -8
- data/lib/health-data-standards/import/c32/care_goal_importer.rb +39 -0
- data/lib/health-data-standards/import/c32/condition_importer.rb +10 -4
- data/lib/health-data-standards/import/c32/encounter_importer.rb +16 -10
- data/lib/health-data-standards/import/c32/immunization_importer.rb +2 -2
- data/lib/health-data-standards/import/c32/insurance_provider_importer.rb +42 -0
- data/lib/health-data-standards/import/c32/medical_equipment_importer.rb +45 -0
- data/lib/health-data-standards/import/c32/medication_importer.rb +35 -48
- data/lib/health-data-standards/import/c32/organization_importer.rb +1 -1
- data/lib/health-data-standards/import/c32/patient_importer.rb +3 -3
- data/lib/health-data-standards/import/c32/procedure_importer.rb +12 -8
- data/lib/health-data-standards/import/c32/result_importer.rb +11 -14
- data/lib/health-data-standards/import/c32/section_importer.rb +60 -29
- data/lib/health-data-standards/import/ccda/allergy_importer.rb +20 -0
- data/lib/health-data-standards/import/ccda/care_goal_importer.rb +13 -0
- data/lib/health-data-standards/import/ccda/condition_importer.rb +20 -0
- data/lib/health-data-standards/import/ccda/encounter_importer.rb +18 -0
- data/lib/health-data-standards/import/ccda/immunization_importer.rb +16 -0
- data/lib/health-data-standards/import/ccda/insurance_provider_importer.rb +14 -0
- data/lib/health-data-standards/import/ccda/medical_equipment_importer.rb +16 -0
- data/lib/health-data-standards/import/ccda/medication_importer.rb +19 -0
- data/lib/health-data-standards/import/ccda/patient_importer.rb +29 -0
- data/lib/health-data-standards/import/ccda/procedure_importer.rb +17 -0
- data/lib/health-data-standards/import/ccda/result_importer.rb +13 -0
- data/lib/health-data-standards/import/ccda/vital_sign_importer.rb +12 -0
- data/lib/health-data-standards/import/ccr/patient_importer.rb +16 -3
- data/lib/health-data-standards/import/green_c32/advance_directive_importer.rb +14 -0
- data/lib/health-data-standards/import/green_c32/allergy_importer.rb +1 -1
- data/lib/health-data-standards/import/green_c32/care_goal_importer.rb +26 -0
- data/lib/health-data-standards/import/green_c32/condition_importer.rb +0 -6
- data/lib/health-data-standards/import/green_c32/encounter_importer.rb +1 -6
- data/lib/health-data-standards/import/green_c32/immunization_importer.rb +1 -1
- data/lib/health-data-standards/import/green_c32/medical_equipment_importer.rb +24 -0
- data/lib/health-data-standards/import/green_c32/medication_importer.rb +1 -1
- data/lib/health-data-standards/import/green_c32/procedure_importer.rb +2 -10
- data/lib/health-data-standards/import/green_c32/section_importer.rb +36 -5
- data/lib/health-data-standards/import/green_c32/social_history_importer.rb +1 -6
- data/lib/health-data-standards/import/green_c32/support_importer.rb +22 -0
- data/lib/health-data-standards/models/allergy.rb +1 -1
- data/lib/health-data-standards/models/condition.rb +3 -1
- data/lib/health-data-standards/models/encounter.rb +1 -3
- data/lib/health-data-standards/models/entry.rb +23 -21
- data/lib/health-data-standards/models/guarantor.rb +10 -0
- data/lib/health-data-standards/models/insurance_provider.rb +17 -0
- data/lib/health-data-standards/models/medical_equipment.rb +5 -0
- data/lib/health-data-standards/models/medication.rb +0 -2
- data/lib/health-data-standards/models/person.rb +4 -0
- data/lib/health-data-standards/models/personable.rb +13 -0
- data/lib/health-data-standards/models/procedure.rb +0 -2
- data/lib/health-data-standards/models/provider.rb +1 -6
- data/lib/health-data-standards/models/record.rb +11 -5
- data/lib/health-data-standards/models/support.rb +18 -0
- data/lib/health-data-standards.rb +28 -2
- data/templates/_advance_directive.gc32.erb +8 -0
- data/templates/_allergy.gc32.erb +17 -7
- data/templates/_care_goal.gc32.erb +8 -0
- data/templates/_condition.gc32.erb +4 -6
- data/templates/_conditions.c32.erb +3 -0
- data/templates/_encounter.gc32.erb +1 -7
- data/templates/_entry.gc32.erb +14 -0
- data/templates/_immunization.gc32.erb +4 -2
- data/templates/_insurance_provider.gc32.erb +0 -0
- data/templates/_medical_equipment.c32.erb +6 -0
- data/templates/_medical_equipment.gc32.erb +7 -0
- data/templates/_medication.gc32.erb +26 -14
- data/templates/_medications_no_current.c32.erb +26 -6
- data/templates/_name.gc32.erb +11 -0
- data/templates/_narrative_block.c32.erb +1 -1
- data/templates/_procedure.gc32.erb +6 -4
- data/templates/_result.gc32.erb +2 -8
- data/templates/_results.c32.erb +8 -2
- data/templates/_social_history.gc32.erb +3 -1
- data/templates/_support.gc32.erb +14 -0
- data/templates/_vital_sign.gc32.erb +2 -7
- data/templates/_vital_signs.c32.erb +8 -2
- data/templates/record.gc32.erb +81 -0
- data/templates/show.c32.erb +1 -1
- metadata +48 -16
- data/lib/health-data-standards/models/comment.rb +0 -2
- data/lib/health-data-standards/models/social_history.rb +0 -3
data/Rakefile
CHANGED
@@ -10,7 +10,7 @@ end
|
|
10
10
|
|
11
11
|
Cane::RakeTask.new(:quality) do |cane|
|
12
12
|
cane.abc_max = 45
|
13
|
-
cane.add_threshold 'coverage/covered_percent', :>=, 97
|
13
|
+
# cane.add_threshold 'coverage/covered_percent', :>=, 97
|
14
14
|
cane.style_measure = 120
|
15
15
|
cane.no_style = true
|
16
16
|
cane.no_doc = true
|
@@ -17,7 +17,12 @@ module HealthDataStandards
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def extract_patient_data(patient)
|
20
|
-
|
20
|
+
race = ''
|
21
|
+
ethnicity = ''
|
22
|
+
race = patient.race['name'] || patient.race if !patient.race.nil?
|
23
|
+
ethnicity = patient.ethnicity['name'] || patient.ethnicity if !patient.ethnicity.nil?
|
24
|
+
|
25
|
+
[patient.patient_id, patient.first, patient.last, patient.gender, race, ethnicity, Time.at(patient.birthdate).strftime('%m/%d/%Y')]
|
21
26
|
end
|
22
27
|
|
23
28
|
extend self
|
@@ -6,7 +6,7 @@ module HealthDataStandards
|
|
6
6
|
|
7
7
|
def export(object, object_type)
|
8
8
|
self.template_format = "gc32"
|
9
|
-
render(partial: object_type, locals: {object_type => object})
|
9
|
+
render(partial: object_type, locals: {object_type => object, type: object_type})
|
10
10
|
end
|
11
11
|
extend self
|
12
12
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module HealthDataStandards
|
2
|
+
module Export
|
3
|
+
module GreenC32
|
4
|
+
module Record
|
5
|
+
include TemplateHelper
|
6
|
+
|
7
|
+
def export(object)
|
8
|
+
self.template_format = "gc32"
|
9
|
+
render(template: "record", locals: {record: object})
|
10
|
+
end
|
11
|
+
extend self
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -25,6 +25,19 @@ module HealthDataStandards
|
|
25
25
|
code_string
|
26
26
|
end
|
27
27
|
|
28
|
+
def gc32_effective_time(entry)
|
29
|
+
if entry.time
|
30
|
+
"<effectiveTime value=\"#{Time.at(entry.time)}\" />"
|
31
|
+
elsif entry.start_time || entry.end_time
|
32
|
+
time = "<effectiveTime>"
|
33
|
+
time += "<start value=\"#{Time.at(entry.start_time)}\" />" if entry.start_time
|
34
|
+
time += "<end value=\"#{Time.at(entry.end_time)}\" />" if entry.end_time
|
35
|
+
time += "</effectiveTime>"
|
36
|
+
else
|
37
|
+
"<effectiveTime />"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
28
41
|
def status_code_for(entry)
|
29
42
|
case entry.status.to_s.downcase
|
30
43
|
when 'active'
|
@@ -35,7 +48,8 @@ module HealthDataStandards
|
|
35
48
|
'413322009'
|
36
49
|
end
|
37
50
|
end
|
38
|
-
|
51
|
+
|
52
|
+
|
39
53
|
def value_or_null_flavor(time)
|
40
54
|
if time
|
41
55
|
return "value='#{Time.at(time).utc.to_formatted_s(:number)}'"
|
@@ -51,7 +65,19 @@ module HealthDataStandards
|
|
51
65
|
end
|
52
66
|
|
53
67
|
def time_if_not_nil(*args)
|
54
|
-
args.compact.map {|t| Time.at(t)}.first
|
68
|
+
args.compact.map {|t| Time.at(t).utc}.first
|
69
|
+
end
|
70
|
+
|
71
|
+
def is_num?(str)
|
72
|
+
Float(str || "")
|
73
|
+
rescue ArgumentError
|
74
|
+
false
|
75
|
+
else
|
76
|
+
true
|
77
|
+
end
|
78
|
+
|
79
|
+
def is_bool?(str)
|
80
|
+
return ["true","false"].include? (str || "").downcase
|
55
81
|
end
|
56
82
|
end
|
57
83
|
end
|
@@ -6,7 +6,11 @@ module HealthDataStandards
|
|
6
6
|
def initialize
|
7
7
|
@entry_xpath = "//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.18']"
|
8
8
|
@code_xpath = "./cda:participant/cda:participantRole/cda:playingEntity/cda:code"
|
9
|
-
@description_xpath = "./cda:code/cda:originalText/cda:reference[@value] | ./cda:text/cda:reference[@value]
|
9
|
+
@description_xpath = "./cda:code/cda:originalText/cda:reference[@value] | ./cda:text/cda:reference[@value]"
|
10
|
+
@type_xpath = "./cda:code"
|
11
|
+
@reaction_xpath = "./cda:entryRelationship[@typeCode='MFST']/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.54']/cda:value"
|
12
|
+
@severity_xpath = "./cda:entryRelationship[@typeCode='SUBJ']/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.55']/cda:value"
|
13
|
+
@status_xpath = "./cda:entryRelationship[@typeCode='REFR']/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.39']/cda:value"
|
10
14
|
@id_map = {}
|
11
15
|
end
|
12
16
|
|
@@ -25,17 +29,17 @@ module HealthDataStandards
|
|
25
29
|
extract_codes(entry_element, allergy)
|
26
30
|
extract_dates(entry_element, allergy)
|
27
31
|
extract_description(entry_element, allergy, id_map)
|
28
|
-
|
29
|
-
allergy.
|
30
|
-
|
31
|
-
|
32
|
-
allergy.severity = extract_code(entry_element,
|
33
|
-
|
34
|
-
|
32
|
+
|
33
|
+
allergy.status = extract_status(entry_element, allergy)
|
34
|
+
allergy.type = extract_code(entry_element, @type_xpath)
|
35
|
+
allergy.reaction = extract_code(entry_element, @reaction_xpath)
|
36
|
+
allergy.severity = extract_code(entry_element, @severity_xpath)
|
37
|
+
|
35
38
|
allergy_list << allergy
|
36
39
|
end
|
37
40
|
allergy_list
|
38
41
|
end
|
42
|
+
|
39
43
|
end
|
40
44
|
end
|
41
45
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module HealthDataStandards
|
2
|
+
module Import
|
3
|
+
module C32
|
4
|
+
class CareGoalImporter < SectionImporter
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@entry_xpath = "//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.124']/cda:entry/cda:*[cda:templateId/@root='2.16.840.1.113883.10.20.1.25']"
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_entries(doc, id_map = {})
|
11
|
+
goal_list = []
|
12
|
+
goal_elements = doc.xpath(@entry_xpath)
|
13
|
+
goal_elements.each do |goal_element|
|
14
|
+
|
15
|
+
importer = case goal_element.name
|
16
|
+
when "observation" then ResultImporter.new
|
17
|
+
when "supply" then MedicalEquipment.new
|
18
|
+
when "substanceAdministration" then MedicationImporter.new
|
19
|
+
when "encounter" then EncounterImporter.new
|
20
|
+
when "procedure" then ProcedureImporter.new
|
21
|
+
else SectionImporter.new(nil) #don't need entry xpath, since we already have the entry
|
22
|
+
end
|
23
|
+
|
24
|
+
entry = importer.create_entry(goal_element, id_map={})
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
if @check_for_usable
|
29
|
+
goal_list << entry if entry.usable?
|
30
|
+
else
|
31
|
+
goal_list << entry
|
32
|
+
end
|
33
|
+
end
|
34
|
+
goal_list
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -7,7 +7,10 @@ module HealthDataStandards
|
|
7
7
|
@entry_xpath = "//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.103']/cda:entry/cda:act/cda:entryRelationship/cda:observation"
|
8
8
|
@code_xpath = "./cda:value"
|
9
9
|
@status_xpath = "./cda:entryRelationship/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.50']/cda:value"
|
10
|
+
@priority_xpath = "./cda:priorityCode"
|
10
11
|
@description_xpath = "./cda:text/cda:reference[@value]"
|
12
|
+
@provider_xpath = "./cda:act[cda:templateId/@root='2.16.840.1.113883.10.20.1.27']/cda:performer"
|
13
|
+
@cod_xpath = "./cda:entryRelationship[@typeCode='CAUS']/cda:observation/cda:code[@code='419620001']"
|
11
14
|
end
|
12
15
|
|
13
16
|
def create_entries(doc, id_map = {})
|
@@ -21,12 +24,15 @@ module HealthDataStandards
|
|
21
24
|
extract_codes(entry_element, condition)
|
22
25
|
extract_dates(entry_element, condition)
|
23
26
|
extract_status(entry_element, condition)
|
27
|
+
extract_priority(entry_element, condition)
|
24
28
|
extract_description(entry_element, condition, id_map)
|
25
|
-
extract_cause_of_death(entry_element, condition)
|
29
|
+
extract_cause_of_death(entry_element, condition) if @cod_xpath
|
26
30
|
extract_type(entry_element, condition)
|
27
31
|
|
28
|
-
|
29
|
-
|
32
|
+
if @provider_xpath
|
33
|
+
entry_element.xpath(@provider_xpath).each do |provider_element|
|
34
|
+
condition.treating_provider << import_actor(provider_element)
|
35
|
+
end
|
30
36
|
end
|
31
37
|
|
32
38
|
condition_list << condition
|
@@ -38,7 +44,7 @@ module HealthDataStandards
|
|
38
44
|
private
|
39
45
|
|
40
46
|
def extract_cause_of_death(entry_element, condition)
|
41
|
-
cod = entry_element.at_xpath(
|
47
|
+
cod = entry_element.at_xpath(@cod_xpath)
|
42
48
|
condition.cause_of_death = cod.present?
|
43
49
|
end
|
44
50
|
|
@@ -8,7 +8,8 @@ module HealthDataStandards
|
|
8
8
|
@entry_xpath = "//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.127']/cda:entry/cda:encounter"
|
9
9
|
@code_xpath = "./cda:code"
|
10
10
|
@status_xpath = "./cda:statusCode"
|
11
|
-
@description_xpath = "./cda:code/cda:originalText/cda:reference[@value] | ./cda:text/cda:reference[@value]
|
11
|
+
@description_xpath = "./cda:code/cda:originalText/cda:reference[@value] | ./cda:text/cda:reference[@value]"
|
12
|
+
@reason_xpath = "./cda:entryRelationship[@typeCode='RSON']/cda:act"
|
12
13
|
@check_for_usable = true # Pilot tools will set this to false
|
13
14
|
@id_map = {}
|
14
15
|
end
|
@@ -23,22 +24,27 @@ module HealthDataStandards
|
|
23
24
|
encounter_list = []
|
24
25
|
entry_elements = doc.xpath(@entry_xpath)
|
25
26
|
entry_elements.each do |entry_element|
|
26
|
-
encounter =
|
27
|
-
extract_codes(entry_element, encounter)
|
28
|
-
extract_dates(entry_element, encounter)
|
29
|
-
extract_description(entry_element, encounter, id_map)
|
27
|
+
encounter = create_entry(entry_element, id_map={})
|
30
28
|
if @check_for_usable
|
31
29
|
encounter_list << encounter if encounter.usable?
|
32
30
|
else
|
33
31
|
encounter_list << encounter
|
34
32
|
end
|
35
|
-
extract_performer(entry_element, encounter)
|
36
|
-
extract_facility(entry_element, encounter)
|
37
|
-
extract_reason(entry_element, encounter, id_map)
|
38
|
-
extract_admission(entry_element, encounter)
|
39
33
|
end
|
40
34
|
encounter_list
|
41
35
|
end
|
36
|
+
|
37
|
+
def create_entry(entry_element, id_map={})
|
38
|
+
encounter = Encounter.new
|
39
|
+
extract_codes(entry_element, encounter)
|
40
|
+
extract_dates(entry_element, encounter)
|
41
|
+
extract_description(entry_element, encounter, id_map)
|
42
|
+
extract_performer(entry_element, encounter)
|
43
|
+
extract_facility(entry_element, encounter)
|
44
|
+
extract_reason(entry_element, encounter, id_map)
|
45
|
+
extract_admission(entry_element, encounter)
|
46
|
+
encounter
|
47
|
+
end
|
42
48
|
|
43
49
|
private
|
44
50
|
|
@@ -58,7 +64,7 @@ module HealthDataStandards
|
|
58
64
|
end
|
59
65
|
|
60
66
|
def extract_reason(parent_element, encounter, id_map)
|
61
|
-
reason_element = parent_element.at_xpath(
|
67
|
+
reason_element = parent_element.at_xpath(@reason_xpath)
|
62
68
|
if reason_element
|
63
69
|
reason = Entry.new
|
64
70
|
extract_codes(reason_element, reason)
|
@@ -7,7 +7,7 @@ module HealthDataStandards
|
|
7
7
|
@entry_xpath = "//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.117']/cda:entry/cda:substanceAdministration"
|
8
8
|
@code_xpath = "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code"
|
9
9
|
@description_xpath = "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code/cda:originalText/cda:reference[@value]"
|
10
|
-
@
|
10
|
+
@refusal_reason_xpath = "./cda:entryRelationship[@typeCode='RSON']/cda:act[cda:templateId/@root='2.16.840.1.113883.10.20.1.27']/cda:code"
|
11
11
|
@check_for_usable = true # Pilot tools will set this to false
|
12
12
|
end
|
13
13
|
|
@@ -42,7 +42,7 @@ module HealthDataStandards
|
|
42
42
|
unless negation_indicator.nil?
|
43
43
|
immunization.refusal_ind = negation_indicator.eql?('true')
|
44
44
|
if immunization.refusal_ind
|
45
|
-
refusal_reason_element = parent_element.at_xpath(@
|
45
|
+
refusal_reason_element = parent_element.at_xpath(@refusal_reason_xpath)
|
46
46
|
if refusal_reason_element
|
47
47
|
immunization.refusal_reason = {'code' => refusal_reason_element['code'],
|
48
48
|
'codeSystem' => 'HL7 No Immunization Reason'}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module HealthDataStandards
|
2
|
+
module Import
|
3
|
+
module C32
|
4
|
+
class InsuranceProviderImporter < SectionImporter
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@entry_xpath = "//cda:act[cda:templateId/@root='2.16.840.1.113883.10.20.1.26']"
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_entries(doc, id_map={})
|
11
|
+
doc.xpath(@entry_xpath).map do |payer_element|
|
12
|
+
ip = InsuranceProvider.new
|
13
|
+
ip.type = extract_code(payer_element, "./cda:code")
|
14
|
+
ip.payer = import_organization(payer_element.at_xpath("./cda:performer/cda:assignedEntity"))
|
15
|
+
ip.guarantors = extract_guarantors(payer_element.xpath("./cda:performer/cda:assignedEntity"))
|
16
|
+
ip.subscriber = import_person(payer_element.at_xpath("./cda:participant[@typeCode='HLD']/cda:participantRole"))
|
17
|
+
member_info_element = payer_element.at_xpath("cda:participant[@typeCode='COV']")
|
18
|
+
extract_dates(member_info_element, ip, "time")
|
19
|
+
name = payer_element.at_xpath("./cda:entryRelationship[@typeCode='REFR']/cda:act[@classCode='ACT' and @moodCode='DEF']/cda:text")
|
20
|
+
ip.name = name.try(:text)
|
21
|
+
patient_element = member_info_element.at_xpath("./cda:participantRole[@classCode='PAT']")
|
22
|
+
ip.member_id = patient_element.at_xpath("./cda:id")
|
23
|
+
ip.relationship = extract_code(patient_element, "./cda:code")
|
24
|
+
ip.financial_responsibility_type = extract_code(payer_element, "./cda:performer/cda:assignedEntity/cda:code")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def extract_guarantors(guarantor_elements)
|
29
|
+
guarantor_elements.map do |guarantor_element|
|
30
|
+
guarantor = Guarantor.new
|
31
|
+
guarantor.person = import_person(guarantor_element.at_xpath("./cda:assignedPerson"))
|
32
|
+
guarantor.organization = import_organization(guarantor_element.at_xpath("./cda:representedOrganization"))
|
33
|
+
extract_dates(guarantor_element, guarantor, element_name="time")
|
34
|
+
guarantor
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module HealthDataStandards
|
2
|
+
module Import
|
3
|
+
module C32
|
4
|
+
class MedicalEquipmentImporter < SectionImporter
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@entry_xpath = "//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.128']/cda:entry/cda:supply"
|
8
|
+
@code_xpath = "./cda:participant/cda:participantRole/cda:playingDevice/cda:code"
|
9
|
+
@description_xpath = "./cda:code/cda:originalText/cda:reference[@value] | ./cda:text/cda:reference[@value]"
|
10
|
+
@check_for_usable = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def create_entries(doc,id_map = {})
|
14
|
+
entry_list = []
|
15
|
+
entry_elements = doc.xpath(@entry_xpath)
|
16
|
+
entry_elements.each do |entry_element|
|
17
|
+
entry = create_entry(entry_element, id_map)
|
18
|
+
if @check_for_usable
|
19
|
+
entry_list << entry if entry.usable?
|
20
|
+
else
|
21
|
+
entry_list << entry
|
22
|
+
end
|
23
|
+
end
|
24
|
+
entry_list
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_entry(entry_element, id_map={})
|
28
|
+
entry = MedicalEquipment.new
|
29
|
+
extract_codes(entry_element, entry)
|
30
|
+
extract_dates(entry_element, entry)
|
31
|
+
extract_value(entry_element, entry)
|
32
|
+
|
33
|
+
extract_description(entry_element, entry, id_map)
|
34
|
+
extract_manufacturer(entry_element, entry)
|
35
|
+
entry
|
36
|
+
end
|
37
|
+
|
38
|
+
def extract_manufacturer(entry_element, entry)
|
39
|
+
manufacturer = entry_element.at_xpath("./cda:participant/cda:participantRole/cda:scopingEntity/cda:desc").try(:inner_text)
|
40
|
+
entry.manufacturer = manufacturer.strip if manufacturer
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -16,57 +16,42 @@ module HealthDataStandards
|
|
16
16
|
@entry_xpath = "//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.112']/cda:entry/cda:substanceAdministration"
|
17
17
|
@code_xpath = "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code"
|
18
18
|
@description_xpath = "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code/cda:originalText/cda:reference[@value]"
|
19
|
-
|
19
|
+
@type_of_med_xpath = "./cda:entryRelationship[@typeCode='SUBJ']/cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.8.1']/cda:code"
|
20
|
+
@indication_xpath = "./cda:entryRelationship[@typeCode='RSON']/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.28']/cda:code"
|
21
|
+
@vehicle_xpath = "cda:participant/cda:participantRole[cda:code/@code='412307009' and cda:code/@codeSystem='2.16.840.1.113883.6.96']/cda:playingEntity/cda:code"
|
22
|
+
@fill_number_xpath = "./cda:entryRelationship[@typeCode='COMP']/cda:sequenceNumber/@value"
|
20
23
|
@check_for_usable = true # Pilot tools will set this to false
|
21
24
|
end
|
22
|
-
|
23
|
-
# Traverses that HITSP C32 document passed in using XPath and creates an Array of Entry
|
24
|
-
# objects based on what it finds
|
25
|
-
# @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
|
26
|
-
# will have the "cda" namespace registered to "urn:hl7-org:v3"
|
27
|
-
# measure definition
|
28
|
-
# @return [Array] will be a list of Entry objects
|
29
|
-
def create_entries(doc,id_map = {})
|
30
|
-
medication_list = []
|
31
|
-
entry_elements = doc.xpath(@entry_xpath)
|
32
|
-
entry_elements.each do |entry_element|
|
33
|
-
medication = Medication.new
|
34
|
-
extract_codes(entry_element, medication)
|
35
|
-
extract_dates(entry_element, medication)
|
36
|
-
extract_description(entry_element, medication, id_map)
|
37
|
-
|
38
|
-
if medication.description.present?
|
39
|
-
medication.free_text_sig = medication.description
|
40
|
-
end
|
41
|
-
|
42
|
-
extract_administration_timing(entry_element, medication)
|
43
|
-
|
44
|
-
medication.route = extract_code(entry_element, "./cda:routeCode")
|
45
|
-
medication.dose = extract_scalar(entry_element, "./cda:doseQuantity")
|
46
|
-
medication.site = extract_code(entry_element, "./cda:approachSiteCode", 'SNOMED-CT')
|
47
|
-
|
48
|
-
extract_dose_restriction(entry_element, medication)
|
49
25
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
extract_order_information(entry_element, medication)
|
60
|
-
|
61
|
-
extract_fulfillment_history(entry_element, medication)
|
62
|
-
|
63
|
-
if @check_for_usable
|
64
|
-
medication_list << medication if medication.usable?
|
65
|
-
else
|
66
|
-
medication_list << medication
|
67
|
-
end
|
26
|
+
def create_entry(entry_element, id_map={})
|
27
|
+
medication = Medication.new
|
28
|
+
extract_codes(entry_element, medication)
|
29
|
+
extract_dates(entry_element, medication)
|
30
|
+
extract_description(entry_element, medication, id_map)
|
31
|
+
|
32
|
+
if medication.description.present?
|
33
|
+
medication.free_text = medication.description
|
68
34
|
end
|
69
|
-
|
35
|
+
|
36
|
+
extract_administration_timing(entry_element, medication)
|
37
|
+
|
38
|
+
medication.route = extract_code(entry_element, "./cda:routeCode")
|
39
|
+
medication.dose = extract_scalar(entry_element, "./cda:doseQuantity")
|
40
|
+
medication.site = extract_code(entry_element, "./cda:approachSiteCode", 'SNOMED-CT')
|
41
|
+
|
42
|
+
extract_dose_restriction(entry_element, medication)
|
43
|
+
|
44
|
+
medication.product_form = extract_code(entry_element, "./cda:administrationUnitCode", 'NCI Thesaurus')
|
45
|
+
medication.delivery_method = extract_code(entry_element, "./cda:code", 'SNOMED-CT')
|
46
|
+
medication.type_of_medication = extract_code(entry_element, @type_of_med_xpath, 'SNOMED-CT') if @type_of_med_xpath
|
47
|
+
medication.indication = extract_code(entry_element, @indication_xpath, 'SNOMED-CT')
|
48
|
+
medication.vehicle = extract_code(entry_element, @vehicle_xpath, 'SNOMED-CT')
|
49
|
+
|
50
|
+
extract_order_information(entry_element, medication)
|
51
|
+
|
52
|
+
extract_fulfillment_history(entry_element, medication)
|
53
|
+
|
54
|
+
medication
|
70
55
|
end
|
71
56
|
|
72
57
|
private
|
@@ -84,7 +69,8 @@ module HealthDataStandards
|
|
84
69
|
hl7_timestamp = fh_element.at_xpath('./cda:effectiveTime').try(:[], 'value')
|
85
70
|
fulfillment_history.dispense_date = HL7Helper.timestamp_to_integer(hl7_timestamp) if hl7_timestamp
|
86
71
|
fulfillment_history.quantity_dispensed = extract_scalar(fh_element, "./cda:quantity")
|
87
|
-
|
72
|
+
fill_number = fh_element.at_xpath(@fill_number_xpath).try(:text)
|
73
|
+
fulfillment_history.fill_number = fill_number.to_i if fill_number
|
88
74
|
medication.fulfillmentHistory << fulfillment_history
|
89
75
|
end
|
90
76
|
end
|
@@ -128,6 +114,7 @@ module HealthDataStandards
|
|
128
114
|
medication.dose_restriction = dr
|
129
115
|
end
|
130
116
|
end
|
117
|
+
|
131
118
|
end
|
132
119
|
end
|
133
120
|
end
|
@@ -11,7 +11,7 @@ module HealthDataStandards
|
|
11
11
|
def extract_organization(org_element)
|
12
12
|
return unless org_element
|
13
13
|
org = Organization.new
|
14
|
-
org.name = org_element.at_xpath("./name").try(:text)
|
14
|
+
org.name = org_element.at_xpath("./cda:name | ./cda:representedOrganization/cda:name").try(:text)
|
15
15
|
org.addresses = org_element.xpath("./cda:addr").map { |addr| import_address(addr) }
|
16
16
|
org.telecoms = org_element.xpath("./cda:telecom").map { |tele| import_telecom(tele) }
|
17
17
|
org
|
@@ -61,11 +61,11 @@ module HealthDataStandards
|
|
61
61
|
@section_importers[:medications] = MedicationImporter.new
|
62
62
|
@section_importers[:conditions] = ConditionImporter.new
|
63
63
|
@section_importers[:social_history] = SectionImporter.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.19']")
|
64
|
-
@section_importers[:care_goals] =
|
65
|
-
@section_importers[:medical_equipment] =
|
66
|
-
"./cda:participant/cda:participantRole/cda:playingDevice/cda:code")
|
64
|
+
@section_importers[:care_goals] = CareGoalImporter.new
|
65
|
+
@section_importers[:medical_equipment] = MedicalEquipmentImporter.new
|
67
66
|
@section_importers[:allergies] = AllergyImporter.new
|
68
67
|
@section_importers[:immunizations] = ImmunizationImporter.new
|
68
|
+
@section_importers[:insurance_providers] = InsuranceProviderImporter.new
|
69
69
|
end
|
70
70
|
|
71
71
|
def build_id_map(doc)
|
@@ -6,9 +6,8 @@ module HealthDataStandards
|
|
6
6
|
class ProcedureImporter < SectionImporter
|
7
7
|
|
8
8
|
def initialize
|
9
|
-
@entry_xpath = "//cda:
|
9
|
+
@entry_xpath = "//cda:section[cda:templateId/@root='2.16.840.1.113883.10.20.1.12']/cda:entry/cda:procedure"
|
10
10
|
@code_xpath = "./cda:code"
|
11
|
-
@status_xpath = "./cda:statusCode"
|
12
11
|
@description_xpath = "./cda:code/cda:originalText/cda:reference[@value] | ./cda:text/cda:reference[@value] "
|
13
12
|
@check_for_usable = true # Pilot tools will set this to false
|
14
13
|
end
|
@@ -23,20 +22,25 @@ module HealthDataStandards
|
|
23
22
|
procedure_list = []
|
24
23
|
entry_elements = doc.xpath(@entry_xpath)
|
25
24
|
entry_elements.each do |entry_element|
|
26
|
-
procedure =
|
27
|
-
extract_codes(entry_element, procedure)
|
28
|
-
extract_dates(entry_element, procedure)
|
29
|
-
extract_description(entry_element, procedure, id_map)
|
25
|
+
procedure = create_entry(entry_element, id_map)
|
30
26
|
if @check_for_usable
|
31
27
|
procedure_list << procedure if procedure.usable?
|
32
28
|
else
|
33
29
|
procedure_list << procedure
|
34
30
|
end
|
35
|
-
extract_performer(entry_element, procedure)
|
36
|
-
extract_site(entry_element, procedure)
|
37
31
|
end
|
38
32
|
procedure_list
|
39
33
|
end
|
34
|
+
|
35
|
+
def create_entry(entry_element, id_map={})
|
36
|
+
procedure = Procedure.new
|
37
|
+
extract_codes(entry_element, procedure)
|
38
|
+
extract_dates(entry_element, procedure)
|
39
|
+
extract_description(entry_element, procedure, id_map)
|
40
|
+
extract_performer(entry_element, procedure)
|
41
|
+
extract_site(entry_element, procedure)
|
42
|
+
procedure
|
43
|
+
end
|
40
44
|
|
41
45
|
private
|
42
46
|
|
@@ -5,7 +5,6 @@ module HealthDataStandards
|
|
5
5
|
def initialize
|
6
6
|
@entry_xpath = "//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.15.1'] | //cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.15']"
|
7
7
|
@code_xpath = "./cda:code"
|
8
|
-
@status_xpath = "./cda:statusCode"
|
9
8
|
@description_xpath = "./cda:code/cda:originalText/cda:reference[@value] | ./cda:text/cda:reference[@value] "
|
10
9
|
@check_for_usable = true # Pilot tools will set this to false
|
11
10
|
end
|
@@ -20,13 +19,7 @@ module HealthDataStandards
|
|
20
19
|
result_list = []
|
21
20
|
entry_elements = doc.xpath(@entry_xpath)
|
22
21
|
entry_elements.each do |entry_element|
|
23
|
-
result =
|
24
|
-
extract_codes(entry_element, result)
|
25
|
-
extract_dates(entry_element, result)
|
26
|
-
extract_value(entry_element, result)
|
27
|
-
extract_status(entry_element, result)
|
28
|
-
extract_description(entry_element, result, id_map)
|
29
|
-
extract_interpretation(entry_element, result)
|
22
|
+
result = create_entry(entry_element, id_map)
|
30
23
|
if @check_for_usable
|
31
24
|
result_list << result if result.usable?
|
32
25
|
else
|
@@ -35,6 +28,16 @@ module HealthDataStandards
|
|
35
28
|
end
|
36
29
|
result_list
|
37
30
|
end
|
31
|
+
|
32
|
+
def create_entry(entry_element, id_map={})
|
33
|
+
result = LabResult.new
|
34
|
+
extract_codes(entry_element, result)
|
35
|
+
extract_dates(entry_element, result)
|
36
|
+
extract_value(entry_element, result)
|
37
|
+
extract_description(entry_element, result, id_map)
|
38
|
+
extract_interpretation(entry_element, result)
|
39
|
+
result
|
40
|
+
end
|
38
41
|
|
39
42
|
private
|
40
43
|
def extract_interpretation(parent_element, result)
|
@@ -46,12 +49,6 @@ module HealthDataStandards
|
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
49
|
-
def extract_status(parent_element, result)
|
50
|
-
status_code_element = parent_element.at_xpath(@status_xpath)
|
51
|
-
if status_code_element
|
52
|
-
result.status = status_code_element['code']
|
53
|
-
end
|
54
|
-
end
|
55
52
|
end
|
56
53
|
end
|
57
54
|
end
|