health-data-standards 3.0.6 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +3 -1
- data/Rakefile +2 -0
- data/lib/health-data-standards.rb +10 -0
- data/lib/health-data-standards/export/cat_3.rb +24 -0
- data/lib/health-data-standards/export/html.rb +2 -1
- data/lib/health-data-standards/import/bundle/importer.rb +178 -146
- data/lib/health-data-standards/import/cat1/diagnosis_active_importer.rb +0 -5
- data/lib/health-data-standards/import/cat1/diagnosis_inactive_importer.rb +1 -6
- data/lib/health-data-standards/import/cat1/diagnostic_study_order_importer.rb +0 -4
- data/lib/health-data-standards/import/cat1/ecog_status_importer.rb +12 -0
- data/lib/health-data-standards/import/cat1/encounter_order_importer.rb +0 -5
- data/lib/health-data-standards/import/cat1/lab_order_importer.rb +1 -5
- data/lib/health-data-standards/import/cat1/lab_result_importer.rb +18 -0
- data/lib/health-data-standards/import/cat1/medication_active_importer.rb +27 -0
- data/lib/health-data-standards/import/cat1/patient_importer.rb +54 -46
- data/lib/health-data-standards/import/cat1/procedure_performed_importer.rb +28 -0
- data/lib/health-data-standards/import/cat1/symptom_active_importer.rb +12 -0
- data/lib/health-data-standards/import/cda/condition_importer.rb +2 -0
- data/lib/health-data-standards/import/cda/encounter_importer.rb +6 -0
- data/lib/health-data-standards/import/cda/procedure_importer.rb +1 -0
- data/lib/health-data-standards/import/cda/section_importer.rb +27 -5
- data/lib/health-data-standards/models/cda_identifier.rb +17 -0
- data/lib/health-data-standards/models/cqm/aggregate_objects.rb +92 -0
- data/lib/health-data-standards/models/cqm/measure.rb +51 -30
- data/lib/health-data-standards/models/cqm/query_cache.rb +64 -0
- data/lib/health-data-standards/models/entry.rb +1 -1
- data/lib/health-data-standards/models/record.rb +28 -3
- data/lib/health-data-standards/models/svs/value_set.rb +20 -0
- data/lib/health-data-standards/tasks/bundle.rake +18 -8
- data/lib/health-data-standards/util/hqmf_template_helper.rb +6 -2
- data/lib/health-data-standards/util/hqmf_template_oid_map.json +4 -0
- data/lib/health-data-standards/util/vs_api.rb +9 -6
- data/lib/hqmf-model/data_criteria.json +10 -10
- data/lib/hqmf-parser.rb +0 -2
- data/lib/hqmf-parser/1.0/range.rb +21 -9
- data/templates/c32/show.c32.erb +1 -1
- data/templates/cat1/_2.16.840.1.113883.10.20.24.3.4.cat1.erb +1 -0
- data/templates/cat1/_2.16.840.1.113883.10.20.24.3.40.cat1.erb +2 -1
- data/templates/cat1/_2.16.840.1.113883.10.20.24.3.44.cat1.erb +1 -0
- data/templates/cat1/_2.16.840.1.113883.10.20.24.3.46.cat1.erb +1 -1
- data/templates/cat1/_2.16.840.1.113883.10.20.24.3.54.cat1.erb +16 -1
- data/templates/cat1/_2.16.840.1.113883.10.20.24.3.62.cat1.erb +1 -1
- data/templates/cat1/_2.16.840.1.113883.10.20.24.3.69.cat1.erb +7 -2
- data/templates/cat1/_2.16.840.1.113883.10.20.24.3.76.cat1.erb +2 -1
- data/templates/cat1/_medication_details.cat1.erb +4 -4
- data/templates/cat1/_record_target.cat1.erb +2 -2
- data/templates/cat1/_result_value.cat1.erb +1 -1
- data/templates/cat1/show.cat1.erb +2 -2
- data/templates/cat3/_continuous_variable_value.cat3.erb +20 -0
- data/templates/cat3/_measure_data.cat3.erb +126 -0
- data/templates/cat3/_performance_rate.cat3.erb +16 -0
- data/templates/cat3/_supplemental_data.cat3.erb +36 -0
- data/templates/cat3/show.cat3.erb +157 -0
- data/templates/ccda/show.ccda.erb +1 -1
- metadata +25 -45
- data/lib/hqmf-parser/value_sets/value_set_parser.rb +0 -241
@@ -0,0 +1,12 @@
|
|
1
|
+
module HealthDataStandards
|
2
|
+
module Import
|
3
|
+
module Cat1
|
4
|
+
class EcogStatusImporter < CDA::SectionImporter
|
5
|
+
def initialize(entry_finder=CDA::EntryFinder.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.103']"))
|
6
|
+
super(entry_finder)
|
7
|
+
@code_xpath = './cda:value'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -4,11 +4,6 @@ module HealthDataStandards
|
|
4
4
|
class EncounterOrderImporter < CDA::EncounterImporter
|
5
5
|
def initialize(entry_finder=CDA::EntryFinder.new("//cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.22']"))
|
6
6
|
super(entry_finder)
|
7
|
-
@entry_class = Encounter
|
8
|
-
end
|
9
|
-
|
10
|
-
def create_entry(entry_element, nrh = CDA::NarrativeReferenceHandler.new)
|
11
|
-
super
|
12
7
|
end
|
13
8
|
|
14
9
|
private
|
@@ -7,15 +7,11 @@ module HealthDataStandards
|
|
7
7
|
@entry_class = LabResult
|
8
8
|
end
|
9
9
|
|
10
|
-
def create_entry(entry_element, nrh = CDA::NarrativeReferenceHandler.new)
|
11
|
-
super
|
12
|
-
end
|
13
|
-
|
14
10
|
private
|
15
11
|
|
16
12
|
def extract_dates(parent_element, entry, element_name="author")
|
17
13
|
if parent_element.at_xpath("cda:#{element_name}/cda:time/@value")
|
18
|
-
entry.
|
14
|
+
entry.time = HL7Helper.timestamp_to_integer(parent_element.at_xpath("cda:#{element_name}/cda:time")['value'])
|
19
15
|
end
|
20
16
|
end
|
21
17
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module HealthDataStandards
|
2
|
+
module Import
|
3
|
+
module Cat1
|
4
|
+
class LabResultImporter < CDA::SectionImporter
|
5
|
+
def initialize(entry_finder=CDA::EntryFinder.new("//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.40']"))
|
6
|
+
super(entry_finder)
|
7
|
+
@entry_class = LabResult
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_entry(entry_element, nrh = CDA::NarrativeReferenceHandler.new)
|
11
|
+
result = super
|
12
|
+
result.end_time ||= result.start_time
|
13
|
+
result
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module HealthDataStandards
|
2
|
+
module Import
|
3
|
+
module Cat1
|
4
|
+
class MedicationActiveImporter < CDA::MedicationImporter
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
super(CDA::EntryFinder.new("//cda:substanceAdministration[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.41']"))
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_entry(entry_element, nrh = CDA::NarrativeReferenceHandler.new)
|
11
|
+
medication = super
|
12
|
+
calculate_cumulative_medication_duration(medication)
|
13
|
+
medication
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def calculate_cumulative_medication_duration(medication)
|
19
|
+
if medication.start_time.present? && medication.end_time.present?
|
20
|
+
duration_in_days = ((medication.end_time - medication.start_time) / (60*60*24)).floor + 1
|
21
|
+
medication.cumulative_medication_duration = {'scalar' => duration_in_days, 'units' => 'days'}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -13,60 +13,56 @@ module HealthDataStandards
|
|
13
13
|
def initialize
|
14
14
|
# This differs from other HDS patient importers in that sections can have multiple importers
|
15
15
|
@section_importers = {}
|
16
|
-
@section_importers[:care_goals] = [
|
17
|
-
|
18
|
-
ecog_status_importer = CDA::SectionImporter.new(CDA::EntryFinder.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.103']"))
|
19
|
-
ecog_status_importer.code_xpath = './cda:value'
|
20
|
-
symptom_active_importer = CDA::SectionImporter.new(CDA::EntryFinder.new("//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.76']"))
|
21
|
-
symptom_active_importer.code_xpath = './cda:value'
|
16
|
+
@section_importers[:care_goals] = [generate_importer(CDA::SectionImporter, "//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.1']", '2.16.840.1.113883.3.560.1.9')] #care goal
|
22
17
|
|
23
|
-
@section_importers[:conditions] = [
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
18
|
+
@section_importers[:conditions] = [generate_importer(GestationalAgeImporter, nil, '2.16.840.1.113883.3.560.1.1001'),
|
19
|
+
generate_importer(EcogStatusImporter, nil, '2.16.840.1.113883.3.560.1.1001'),
|
20
|
+
generate_importer(SymptomActiveImporter, nil, '2.16.840.1.113883.3.560.1.69', 'active'),
|
21
|
+
generate_importer(DiagnosisActiveImporter, nil, '2.16.840.1.113883.3.560.1.2', 'active'),
|
22
|
+
generate_importer(CDA::ConditionImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.54']", '2.16.840.1.113883.3.560.1.404'), # patient characteristic age
|
23
|
+
generate_importer(CDA::ConditionImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.14']", '2.16.840.1.113883.3.560.1.24', 'resolved'), #diagnosis resolved
|
24
|
+
generate_importer(DiagnosisInactiveImporter, nil, '2.16.840.1.113883.3.560.1.23', 'inactive')] #diagnosis inactive
|
30
25
|
|
31
26
|
|
32
|
-
@section_importers[:medications] = [
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
27
|
+
@section_importers[:medications] = [generate_importer(CDA::MedicationImporter, "//cda:act[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.105']/cda:entryRelationship/cda:substanceAdministration[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.41']", '2.16.840.1.113883.3.560.1.199', 'discharge'), #discharge medication active
|
28
|
+
generate_importer(MedicationActiveImporter, nil, '2.16.840.1.113883.3.560.1.13', 'active'), #medication active
|
29
|
+
generate_importer(CDA::MedicationImporter, "//cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.42']/cda:entryRelationship/cda:substanceAdministration[cda:templateId/@root='2.16.840.1.113883.10.20.22.4.16']", '2.16.840.1.113883.3.560.1.14', 'administered'), #medication administered
|
30
|
+
generate_importer(CDA::MedicationImporter, "//cda:substanceAdministration[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.47']", '2.16.840.1.113883.3.560.1.17', 'ordered'), #medication order TODO: ADD NEGATON REASON HANDLING SOMEHOW
|
31
|
+
generate_importer(MedicationDispensedImporter, nil, '2.16.840.1.113883.3.560.1.8', 'dispensed')]
|
37
32
|
|
38
|
-
@section_importers[:procedures] = [
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
33
|
+
@section_importers[:procedures] = [generate_importer(CDA::ProcedureImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.59']", '2.16.840.1.113883.3.560.1.57', 'performed'), #physical exam performed
|
34
|
+
generate_importer(CDA::ProcedureImporter, "//cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.3']", '2.16.840.1.113883.3.560.1.131'), #comm from provider to patient
|
35
|
+
generate_importer(CDA::ProcedureImporter, "//cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.31']", '2.16.840.1.113883.3.560.1.45', 'ordered'), #intervention ordered
|
36
|
+
generate_importer(CDA::ProcedureImporter, "//cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.32']", '2.16.840.1.113883.3.560.1.46', 'performed'), #intervention performed
|
37
|
+
generate_importer(CDA::ProcedureImporter, "//cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.34']", '2.16.840.1.113883.3.560.1.47'), #intervention result
|
38
|
+
generate_importer(CDA::ProcedureImporter, "//cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.4']", '2.16.840.1.113883.3.560.1.129'), #comm from provider to provider
|
39
|
+
generate_importer(CDA::ProcedureImporter, "//cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.2']", '2.16.840.1.113883.3.560.1.30'), #comm from patient to provider
|
40
|
+
generate_importer(ProcedureOrderImporter, nil, '2.16.840.1.113883.3.560.1.62', 'ordered'),
|
41
|
+
generate_importer(CDA::ProcedureImporter, "//cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.64']", '2.16.840.1.113883.3.560.1.6'),
|
42
|
+
generate_importer(CDA::ProcedureImporter, "//cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.66']", '2.16.840.1.113883.3.560.1.63'),
|
43
|
+
generate_importer(CDA::ProcedureImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.69']", '2.16.840.1.113883.3.560.1.21'),
|
44
|
+
generate_importer(CDA::ProcedureImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.18']", '2.16.840.1.113883.3.560.1.103', 'performed'), #diagnostic study performed
|
45
|
+
generate_importer(DiagnosticStudyOrderImporter, nil, '2.16.840.1.113883.3.560.1.40', 'ordered')]
|
51
46
|
|
52
|
-
@section_importers[:allergies] = [
|
53
|
-
|
54
|
-
|
55
|
-
|
47
|
+
@section_importers[:allergies] = [generate_importer(ProcedureIntoleranceImporter, nil, '2.16.840.1.113883.3.560.1.61'),
|
48
|
+
generate_importer(CDA::AllergyImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.46']", '2.16.840.1.113883.3.560.1.67'), #medication intolerance
|
49
|
+
generate_importer(CDA::AllergyImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.43']", '2.16.840.1.113883.3.560.1.7'), #medication adverse effect
|
50
|
+
generate_importer(CDA::AllergyImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.44']", '2.16.840.1.113883.3.560.1.1')] #medication allergy
|
56
51
|
|
57
|
-
@section_importers[:medical_equipment] = [
|
52
|
+
@section_importers[:medical_equipment] = [generate_importer(CDA::MedicalEquipmentImporter, "//cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.7']", '2.16.840.1.113883.3.560.1.110', 'applied')]
|
58
53
|
|
59
|
-
@section_importers[:results] = [
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
54
|
+
@section_importers[:results] = [generate_importer(LabOrderImporter, nil, '2.16.840.1.113883.3.560.1.50', 'ordered'), #lab ordered
|
55
|
+
generate_importer(CDA::ResultImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.38']", '2.16.840.1.113883.3.560.1.5', 'performed'), #lab performed
|
56
|
+
generate_importer(CDA::ResultImporter, "//cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.34']", '2.16.840.1.113883.3.560.1.47'), #intervention result
|
57
|
+
generate_importer(CDA::ResultImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.57']", '2.16.840.1.113883.3.560.1.18'), #physical exam finding
|
58
|
+
generate_importer(CDA::ResultImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.28']", '2.16.840.1.113883.3.560.1.88'), #functional status result
|
59
|
+
generate_importer(CDA::ResultImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.20']", '2.16.840.1.113883.3.560.1.111'), #diagnostic study result not done
|
60
|
+
generate_importer(LabResultImporter, nil, '2.16.840.1.113883.3.560.1.12')] #lab result
|
65
61
|
|
66
|
-
@section_importers[:encounters] = [
|
67
|
-
|
62
|
+
@section_importers[:encounters] = [generate_importer(CDA::EncounterImporter, "//cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']", '2.16.840.1.113883.3.560.1.79', 'performed'), #encounter performed
|
63
|
+
generate_importer(EncounterOrderImporter, nil, '2.16.840.1.113883.3.560.1.83', 'ordered')]
|
68
64
|
|
69
|
-
@section_importers[:social_history] = [
|
65
|
+
@section_importers[:social_history] = [generate_importer(TobaccoUseImporter, nil, '2.16.840.1.113883.3.560.1.1001', 'completed')]
|
70
66
|
|
71
67
|
end
|
72
68
|
|
@@ -76,6 +72,7 @@ module HealthDataStandards
|
|
76
72
|
import_sections(record, doc)
|
77
73
|
get_clinical_trial_participant(record, doc)
|
78
74
|
get_patient_expired(record, doc)
|
75
|
+
record.dedup_record!
|
79
76
|
record
|
80
77
|
end
|
81
78
|
|
@@ -96,7 +93,18 @@ module HealthDataStandards
|
|
96
93
|
|
97
94
|
def get_patient_expired(record, doc)
|
98
95
|
entry_elements = doc.xpath("//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.54']")
|
99
|
-
record.expired = true unless entry_elements.
|
96
|
+
record.expired = true unless entry_elements.empty?
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def generate_importer(importer_class, xpath, hqmf_oid, status=nil)
|
102
|
+
if importer_class.parent_name == "HealthDataStandards::Import::CDA"
|
103
|
+
importer = EntryPackage.new(importer_class.new(CDA::EntryFinder.new(xpath)), hqmf_oid, status)
|
104
|
+
else
|
105
|
+
importer = EntryPackage.new(importer_class.new, hqmf_oid, status)
|
106
|
+
end
|
107
|
+
importer
|
100
108
|
end
|
101
109
|
end
|
102
110
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module HealthDataStandards
|
2
|
+
module Import
|
3
|
+
module Cat1
|
4
|
+
class ProcedurePerformedImporter < CDA::SectionImporter
|
5
|
+
def initialize(entry_finder=CDA::EntryFinder.new("//cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.64']"))
|
6
|
+
super(entry_finder)
|
7
|
+
@entry_class = Procedure
|
8
|
+
@ordinality_xpath = "./cda:priorityCode"
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_entry(entry_element, nrh = CDA::NarrativeReferenceHandler.new)
|
12
|
+
procedure = super
|
13
|
+
extract_ordinality(entry_element, procedure)
|
14
|
+
procedure
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def extract_ordinality(parent_element, procedure)
|
20
|
+
ordinality_element = parent_element.at_xpath(@ordinality_xpath)
|
21
|
+
if ordinality_element
|
22
|
+
procedure.ordinality = {CodeSystemHelper.code_system_for(ordinality_element['codeSystem']) => [ordinality_element['code']]}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module HealthDataStandards
|
2
|
+
module Import
|
3
|
+
module Cat1
|
4
|
+
class SymptomActiveImporter < CDA::SectionImporter
|
5
|
+
def initialize(entry_finder=CDA::EntryFinder.new("//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.76']"))
|
6
|
+
super(entry_finder)
|
7
|
+
@code_xpath = './cda:value'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -6,12 +6,14 @@ module HealthDataStandards
|
|
6
6
|
def initialize(entry_finder=EntryFinder.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.103']/cda:entry/cda:act/cda:entryRelationship/cda:observation"))
|
7
7
|
@entry_finder = entry_finder
|
8
8
|
@code_xpath = "./cda:value"
|
9
|
+
@id_xpath = "./cda:id"
|
9
10
|
@status_xpath = "./cda:entryRelationship/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.50']/cda:value"
|
10
11
|
@ordinality_xpath = "./cda:priorityCode"
|
11
12
|
@description_xpath = "./cda:text/cda:reference[@value]"
|
12
13
|
@provider_xpath = "./cda:act[cda:templateId/@root='2.16.840.1.113883.10.20.1.27']/cda:performer"
|
13
14
|
@priority_xpath = "../cda:sequenceNumber"
|
14
15
|
@entry_class = Condition
|
16
|
+
@value_xpath = nil
|
15
17
|
end
|
16
18
|
|
17
19
|
def create_entry(entry_element, nrh = NarrativeReferenceHandler.new)
|
@@ -17,6 +17,7 @@ module HealthDataStandards
|
|
17
17
|
extract_reason(entry_element, encounter, nrh)
|
18
18
|
extract_negation(entry_element, encounter)
|
19
19
|
extract_admission(entry_element, encounter)
|
20
|
+
extract_discharge_disposition(entry_element, encounter)
|
20
21
|
encounter
|
21
22
|
end
|
22
23
|
|
@@ -54,6 +55,11 @@ module HealthDataStandards
|
|
54
55
|
def extract_admission(parent_element, encounter)
|
55
56
|
encounter.admit_type = extract_code(parent_element, "./cda:priorityCode")
|
56
57
|
end
|
58
|
+
|
59
|
+
def extract_discharge_disposition(parent_element, encounter)
|
60
|
+
encounter.discharge_time = encounter.end_time
|
61
|
+
encounter.discharge_disposition = extract_code(parent_element, "./sdtc:dischargeDispositionCode")
|
62
|
+
end
|
57
63
|
end
|
58
64
|
end
|
59
65
|
end
|
@@ -8,6 +8,7 @@ module HealthDataStandards
|
|
8
8
|
def initialize(entry_finder=EntryFinder.new("//cda:section[cda:templateId/@root!='2.16.840.1.113883.3.88.11.83.124']//cda:procedure"))
|
9
9
|
super(entry_finder)
|
10
10
|
@entry_class = Procedure
|
11
|
+
@value_xpath = nil
|
11
12
|
end
|
12
13
|
|
13
14
|
def create_entry(entry_element, nrh = NarrativeReferenceHandler.new)
|
@@ -10,11 +10,13 @@ module HealthDataStandards
|
|
10
10
|
def initialize(entry_finder)
|
11
11
|
@entry_finder = entry_finder
|
12
12
|
@code_xpath = "./cda:code"
|
13
|
+
@id_xpath = "./cda:id"
|
13
14
|
@status_xpath = nil
|
14
15
|
@priority_xpath = nil
|
15
16
|
@description_xpath = "./cda:code/cda:originalText/cda:reference[@value] | ./cda:text/cda:reference[@value]"
|
16
17
|
@check_for_usable = true
|
17
18
|
@entry_class = Entry
|
19
|
+
@value_xpath = 'cda:value'
|
18
20
|
end
|
19
21
|
|
20
22
|
# Traverses an HL7 CDA document passed in and creates an Array of Entry
|
@@ -39,9 +41,12 @@ module HealthDataStandards
|
|
39
41
|
|
40
42
|
def create_entry(entry_element, nrh = NarrativeReferenceHandler.new)
|
41
43
|
entry = @entry_class.new
|
44
|
+
extract_id(entry_element, entry)
|
42
45
|
extract_codes(entry_element, entry)
|
43
46
|
extract_dates(entry_element, entry)
|
44
|
-
|
47
|
+
if @value_xpath
|
48
|
+
extract_value(entry_element, entry)
|
49
|
+
end
|
45
50
|
entry.free_text = entry_element.at_xpath("./cda:text").try("text")
|
46
51
|
if @status_xpath
|
47
52
|
extract_status(entry_element, entry)
|
@@ -61,6 +66,16 @@ module HealthDataStandards
|
|
61
66
|
end
|
62
67
|
end
|
63
68
|
|
69
|
+
def extract_id(parent_element, entry)
|
70
|
+
id_element = parent_element.at_xpath(@id_xpath)
|
71
|
+
if id_element
|
72
|
+
identifier = CDAIdentifier.new
|
73
|
+
identifier.root = id_element['root']
|
74
|
+
identifier.extension = id_element['extension']
|
75
|
+
entry.cda_identifier = identifier
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
64
79
|
def extract_description(parent_element, entry, nrh)
|
65
80
|
code_elements = parent_element.xpath(@description_xpath)
|
66
81
|
code_elements.each do |code_element|
|
@@ -102,12 +117,19 @@ module HealthDataStandards
|
|
102
117
|
end
|
103
118
|
|
104
119
|
def extract_value(parent_element, entry)
|
105
|
-
value_element = parent_element.at_xpath(
|
120
|
+
value_element = parent_element.at_xpath(@value_xpath)
|
106
121
|
if value_element
|
107
122
|
value = value_element['value']
|
108
|
-
|
109
|
-
|
110
|
-
|
123
|
+
if value.present?
|
124
|
+
unit = value_element['unit']
|
125
|
+
entry.set_value(value.strip, unit)
|
126
|
+
elsif value_element['code'].present?
|
127
|
+
crv = CodedResultValue.new
|
128
|
+
add_code_if_present(value_element, crv)
|
129
|
+
entry.values << crv
|
130
|
+
else
|
131
|
+
value = value_element.text
|
132
|
+
unit = value_element['unit']
|
111
133
|
entry.set_value(value.strip, unit)
|
112
134
|
end
|
113
135
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CDAIdentifier
|
2
|
+
include Mongoid::Document
|
3
|
+
|
4
|
+
field :root, type: String
|
5
|
+
field :extension, type: String
|
6
|
+
embedded_in :entry
|
7
|
+
|
8
|
+
def ==(comparison_object)
|
9
|
+
if comparison_object.respond_to?(:root) && comparison_object.respond_to?(:extension)
|
10
|
+
self.root == comparison_object.root && self.extension == comparison_object.extension
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def hash
|
15
|
+
"#{root}#{extension}".hash
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module HealthDataStandards
|
2
|
+
module CQM
|
3
|
+
|
4
|
+
module PopulationSelectors
|
5
|
+
def numerator
|
6
|
+
populations.find {|pop| pop.type == 'NUMER'}
|
7
|
+
end
|
8
|
+
|
9
|
+
def denominator
|
10
|
+
populations.find {|pop| pop.type == 'DENOM'}
|
11
|
+
end
|
12
|
+
|
13
|
+
def denominator_exceptions
|
14
|
+
populations.find {|pop| pop.type == 'DENEXCEP'}
|
15
|
+
end
|
16
|
+
|
17
|
+
def denominator_exclusions
|
18
|
+
populations.find {|pop| pop.type == 'DENEX'}
|
19
|
+
end
|
20
|
+
|
21
|
+
def population_count(population_type, population_id)
|
22
|
+
population = populations.find {|pop| pop.type == population_type && pop.id == population_id}
|
23
|
+
if population
|
24
|
+
population.value
|
25
|
+
else
|
26
|
+
0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def population_id(population_type)
|
31
|
+
populations.find {|pop| pop.type == population_type}.id
|
32
|
+
end
|
33
|
+
|
34
|
+
def method_missing(method, *args, &block)
|
35
|
+
match_data = method.to_s.match(/^(.+)_count$/)
|
36
|
+
if match_data
|
37
|
+
population = self.send(match_data[1])
|
38
|
+
if population
|
39
|
+
population.value
|
40
|
+
else
|
41
|
+
0
|
42
|
+
end
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns true if there is more than one IPP or DENOM, etc.
|
49
|
+
def multiple_population_types?
|
50
|
+
population_groups = populations.group_by {|pop| pop.type}
|
51
|
+
population_groups.values.any? { |pops| pops.size > 1 }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class Population
|
56
|
+
attr_accessor :type, :value, :id
|
57
|
+
end
|
58
|
+
|
59
|
+
class Stratification
|
60
|
+
attr_accessor :id, :populations
|
61
|
+
include PopulationSelectors
|
62
|
+
|
63
|
+
def initialize
|
64
|
+
@populations = []
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class AggregateCount
|
69
|
+
attr_accessor :measure_id, :stratifications, :top_level_populations, :supplemental_data
|
70
|
+
alias :populations :top_level_populations
|
71
|
+
include PopulationSelectors
|
72
|
+
|
73
|
+
def initialize
|
74
|
+
@stratifications = []
|
75
|
+
@top_level_populations = []
|
76
|
+
end
|
77
|
+
|
78
|
+
def is_cv?
|
79
|
+
top_level_populations.any? {|pop| pop.type == 'MSRPOPL'}
|
80
|
+
end
|
81
|
+
|
82
|
+
def performance_rate
|
83
|
+
numerator_count.to_f /
|
84
|
+
(denominator_count - denominator_exclusions_count - denominator_exceptions_count)
|
85
|
+
end
|
86
|
+
|
87
|
+
def supplemental_data_for(population_type, supplemental_data_type)
|
88
|
+
supplemental_data[population_type][supplemental_data_type]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|