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.
Files changed (56) hide show
  1. data/README.md +3 -1
  2. data/Rakefile +2 -0
  3. data/lib/health-data-standards.rb +10 -0
  4. data/lib/health-data-standards/export/cat_3.rb +24 -0
  5. data/lib/health-data-standards/export/html.rb +2 -1
  6. data/lib/health-data-standards/import/bundle/importer.rb +178 -146
  7. data/lib/health-data-standards/import/cat1/diagnosis_active_importer.rb +0 -5
  8. data/lib/health-data-standards/import/cat1/diagnosis_inactive_importer.rb +1 -6
  9. data/lib/health-data-standards/import/cat1/diagnostic_study_order_importer.rb +0 -4
  10. data/lib/health-data-standards/import/cat1/ecog_status_importer.rb +12 -0
  11. data/lib/health-data-standards/import/cat1/encounter_order_importer.rb +0 -5
  12. data/lib/health-data-standards/import/cat1/lab_order_importer.rb +1 -5
  13. data/lib/health-data-standards/import/cat1/lab_result_importer.rb +18 -0
  14. data/lib/health-data-standards/import/cat1/medication_active_importer.rb +27 -0
  15. data/lib/health-data-standards/import/cat1/patient_importer.rb +54 -46
  16. data/lib/health-data-standards/import/cat1/procedure_performed_importer.rb +28 -0
  17. data/lib/health-data-standards/import/cat1/symptom_active_importer.rb +12 -0
  18. data/lib/health-data-standards/import/cda/condition_importer.rb +2 -0
  19. data/lib/health-data-standards/import/cda/encounter_importer.rb +6 -0
  20. data/lib/health-data-standards/import/cda/procedure_importer.rb +1 -0
  21. data/lib/health-data-standards/import/cda/section_importer.rb +27 -5
  22. data/lib/health-data-standards/models/cda_identifier.rb +17 -0
  23. data/lib/health-data-standards/models/cqm/aggregate_objects.rb +92 -0
  24. data/lib/health-data-standards/models/cqm/measure.rb +51 -30
  25. data/lib/health-data-standards/models/cqm/query_cache.rb +64 -0
  26. data/lib/health-data-standards/models/entry.rb +1 -1
  27. data/lib/health-data-standards/models/record.rb +28 -3
  28. data/lib/health-data-standards/models/svs/value_set.rb +20 -0
  29. data/lib/health-data-standards/tasks/bundle.rake +18 -8
  30. data/lib/health-data-standards/util/hqmf_template_helper.rb +6 -2
  31. data/lib/health-data-standards/util/hqmf_template_oid_map.json +4 -0
  32. data/lib/health-data-standards/util/vs_api.rb +9 -6
  33. data/lib/hqmf-model/data_criteria.json +10 -10
  34. data/lib/hqmf-parser.rb +0 -2
  35. data/lib/hqmf-parser/1.0/range.rb +21 -9
  36. data/templates/c32/show.c32.erb +1 -1
  37. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.4.cat1.erb +1 -0
  38. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.40.cat1.erb +2 -1
  39. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.44.cat1.erb +1 -0
  40. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.46.cat1.erb +1 -1
  41. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.54.cat1.erb +16 -1
  42. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.62.cat1.erb +1 -1
  43. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.69.cat1.erb +7 -2
  44. data/templates/cat1/_2.16.840.1.113883.10.20.24.3.76.cat1.erb +2 -1
  45. data/templates/cat1/_medication_details.cat1.erb +4 -4
  46. data/templates/cat1/_record_target.cat1.erb +2 -2
  47. data/templates/cat1/_result_value.cat1.erb +1 -1
  48. data/templates/cat1/show.cat1.erb +2 -2
  49. data/templates/cat3/_continuous_variable_value.cat3.erb +20 -0
  50. data/templates/cat3/_measure_data.cat3.erb +126 -0
  51. data/templates/cat3/_performance_rate.cat3.erb +16 -0
  52. data/templates/cat3/_supplemental_data.cat3.erb +36 -0
  53. data/templates/cat3/show.cat3.erb +157 -0
  54. data/templates/ccda/show.ccda.erb +1 -1
  55. metadata +25 -45
  56. data/lib/hqmf-parser/value_sets/value_set_parser.rb +0 -241
@@ -6,10 +6,6 @@ module HealthDataStandards
6
6
  super(entry_finder)
7
7
  @entry_class = Procedure
8
8
  end
9
-
10
- def create_entry(entry_element, nrh = CDA::NarrativeReferenceHandler.new)
11
- super
12
- end
13
9
 
14
10
  private
15
11
 
@@ -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.start_time = HL7Helper.timestamp_to_integer(parent_element.at_xpath("cda:#{element_name}/cda:time")['value'])
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] = [EntryPackage.new(CDA::SectionImporter.new(CDA::EntryFinder.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.1']")), '2.16.840.1.113883.3.560.1.9')].compact #care goal
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] = [EntryPackage.new(GestationalAgeImporter.new, '2.16.840.1.113883.3.560.1.1001'),
24
- EntryPackage.new(ecog_status_importer, '2.16.840.1.113883.3.560.1.1001'),
25
- EntryPackage.new(symptom_active_importer, '2.16.840.1.113883.3.560.1.69', 'active'),
26
- EntryPackage.new(DiagnosisActiveImporter.new, '2.16.840.1.113883.3.560.1.2', 'active'),
27
- EntryPackage.new(CDA::ConditionImporter.new(CDA::EntryFinder.new("//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
28
- EntryPackage.new(CDA::ConditionImporter.new(CDA::EntryFinder.new("//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
29
- EntryPackage.new(DiagnosisInactiveImporter.new, '2.16.840.1.113883.3.560.1.23', 'inactive')].compact #diagnosis inactive
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] = [EntryPackage.new(CDA::MedicationImporter.new(CDA::EntryFinder.new("//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
33
- EntryPackage.new(CDA::MedicationImporter.new(CDA::EntryFinder.new("//cda:substanceAdministration[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.41']")), '2.16.840.1.113883.3.560.1.13', 'active'), #medication active
34
- EntryPackage.new(CDA::MedicationImporter.new(CDA::EntryFinder.new("//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
35
- EntryPackage.new(CDA::MedicationImporter.new(CDA::EntryFinder.new("//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
36
- EntryPackage.new(MedicationDispensedImporter.new, '2.16.840.1.113883.3.560.1.8', 'dispensed')].compact
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] = [EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//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
39
- EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//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
40
- EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//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
41
- EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//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
42
- EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//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
43
- EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//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
44
- EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//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
45
- EntryPackage.new(ProcedureOrderImporter.new, '2.16.840.1.113883.3.560.1.62', 'ordered'),
46
- EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.64']")), '2.16.840.1.113883.3.560.1.6'),
47
- EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.66']")), '2.16.840.1.113883.3.560.1.63'),
48
- EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.69']")), '2.16.840.1.113883.3.560.1.21'),
49
- EntryPackage.new(CDA::ProcedureImporter.new(CDA::EntryFinder.new("//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
50
- EntryPackage.new(DiagnosticStudyOrderImporter.new, '2.16.840.1.113883.3.560.1.40', 'ordered')].compact
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] = [EntryPackage.new(ProcedureIntoleranceImporter.new, '2.16.840.1.113883.3.560.1.61'),
53
- EntryPackage.new(CDA::AllergyImporter.new(CDA::EntryFinder.new("//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
54
- EntryPackage.new(CDA::AllergyImporter.new(CDA::EntryFinder.new("//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
55
- EntryPackage.new(CDA::AllergyImporter.new(CDA::EntryFinder.new("//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.44']")), '2.16.840.1.113883.3.560.1.1')].compact #medication allergy
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] = [EntryPackage.new(CDA::MedicalEquipmentImporter.new(CDA::EntryFinder.new("//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')].compact
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] = [EntryPackage.new(LabOrderImporter.new, '2.16.840.1.113883.3.560.1.50', 'ordered'), #lab ordered
60
- EntryPackage.new(CDA::ResultImporter.new(CDA::EntryFinder.new("//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
61
- EntryPackage.new(CDA::ResultImporter.new(CDA::EntryFinder.new("//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
62
- EntryPackage.new(CDA::ResultImporter.new(CDA::EntryFinder.new("//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
63
- EntryPackage.new(CDA::ResultImporter.new(CDA::EntryFinder.new("//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
64
- EntryPackage.new(CDA::ResultImporter.new(CDA::EntryFinder.new("//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.20']")), '2.16.840.1.113883.3.560.1.111')].compact #diagnostic study result not done
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] = [EntryPackage.new(CDA::EncounterImporter.new(CDA::EntryFinder.new("//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
67
- EntryPackage.new(EncounterOrderImporter.new, '2.16.840.1.113883.3.560.1.83', 'ordered')].compact
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] = [EntryPackage.new(TobaccoUseImporter.new, '2.16.840.1.113883.3.560.1.1001', 'completed')].compact
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.nil?
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
- extract_value(entry_element, entry)
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('cda:value')
120
+ value_element = parent_element.at_xpath(@value_xpath)
106
121
  if value_element
107
122
  value = value_element['value']
108
- unit = value_element['unit']
109
- value ||= value_element.text
110
- if value
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