health-data-standards 3.0.6 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
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