quality-measure-engine 1.0.4 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,8 +2,6 @@ require "bundler/setup"
2
2
 
3
3
  require 'resque/job_with_status'
4
4
 
5
- require_relative 'qme/ext/string'
6
-
7
5
  require_relative 'qme/database_access'
8
6
  require_relative 'qme/quality_measure'
9
7
 
@@ -13,20 +11,19 @@ require_relative 'qme/map/measure_calculation_job'
13
11
 
14
12
  require_relative 'qme/quality_report'
15
13
 
14
+ require_relative 'qme/randomizer/random_patient_creator'
16
15
  require_relative 'qme/randomizer/patient_randomizer'
17
16
  require_relative 'qme/randomizer/patient_randomization_job'
18
17
 
19
18
  require 'singleton'
19
+ require 'health-data-standards'
20
20
 
21
- require_relative 'qme/importer/entry'
22
- require_relative 'qme/importer/property_matcher'
23
- require_relative 'qme/importer/patient_importer'
24
- require_relative 'qme/importer/code_system_helper'
25
- require_relative 'qme/importer/hl7_helper'
21
+ require_relative 'qme/ext/record'
26
22
 
27
- require_relative 'qme/importer/section_importer'
23
+ require_relative 'qme/importer/property_matcher'
28
24
  require_relative 'qme/importer/generic_importer'
29
25
  require_relative 'qme/importer/provider_importer'
26
+ require_relative 'qme/importer/measure_properties_generator'
30
27
 
31
28
  require 'json'
32
29
  require 'mongo'
@@ -28,7 +28,7 @@ namespace :patient do
28
28
  QME::QualityMeasure.all.each_value do |measure_def|
29
29
  measure_id = measure_def['id']
30
30
  if !processed_measures[measure_id]
31
- QME::Importer::PatientImporter.instance.add_measure(measure_id, QME::Importer::GenericImporter.new(measure_def))
31
+ QME::Importer::MeasurePropertiesGenerator.instance.add_measure(measure_id, QME::Importer::GenericImporter.new(measure_def))
32
32
  processed_measures[measure_id]=true
33
33
  end
34
34
  end
@@ -37,8 +37,8 @@ namespace :patient do
37
37
  template = templates[rand(templates.length)]
38
38
  generator = QME::Randomizer::Patient.new(template)
39
39
  json = JSON.parse(generator.get())
40
- patient_record = QME::Importer::PatientImporter.instance.parse_hash(json)
41
- loader.save('records', patient_record)
40
+ patient_record = QME::Randomizer::RandomPatientCreator.parse_hash(json)
41
+ patient_record.save!
42
42
  end
43
43
  end
44
44
 
metadata CHANGED
@@ -1,171 +1,165 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: quality-measure-engine
3
- version: !ruby/object:Gem::Version
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
4
5
  prerelease:
5
- version: 1.0.4
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Marc Hadley
9
9
  - Andy Gregorowicz
10
10
  - Rob Dingwell
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
-
15
- date: 2011-12-16 00:00:00 -05:00
14
+ date: 2012-01-31 00:00:00.000000000 -05:00
16
15
  default_executable:
17
- dependencies:
18
- - !ruby/object:Gem::Dependency
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
19
18
  name: mongo
20
- prerelease: false
21
- requirement: &id001 !ruby/object:Gem::Requirement
19
+ requirement: &2151835920 !ruby/object:Gem::Requirement
22
20
  none: false
23
- requirements:
21
+ requirements:
24
22
  - - ~>
25
- - !ruby/object:Gem::Version
26
- version: "1.3"
23
+ - !ruby/object:Gem::Version
24
+ version: '1.3'
27
25
  type: :runtime
28
- version_requirements: *id001
29
- - !ruby/object:Gem::Dependency
30
- name: rubyzip
31
26
  prerelease: false
32
- requirement: &id002 !ruby/object:Gem::Requirement
27
+ version_requirements: *2151835920
28
+ - !ruby/object:Gem::Dependency
29
+ name: rubyzip
30
+ requirement: &2151831040 !ruby/object:Gem::Requirement
33
31
  none: false
34
- requirements:
32
+ requirements:
35
33
  - - ~>
36
- - !ruby/object:Gem::Version
34
+ - !ruby/object:Gem::Version
37
35
  version: 0.9.4
38
36
  type: :runtime
39
- version_requirements: *id002
40
- - !ruby/object:Gem::Dependency
41
- name: nokogiri
42
37
  prerelease: false
43
- requirement: &id003 !ruby/object:Gem::Requirement
38
+ version_requirements: *2151831040
39
+ - !ruby/object:Gem::Dependency
40
+ name: nokogiri
41
+ requirement: &2151826060 !ruby/object:Gem::Requirement
44
42
  none: false
45
- requirements:
43
+ requirements:
46
44
  - - ~>
47
- - !ruby/object:Gem::Version
45
+ - !ruby/object:Gem::Version
48
46
  version: 1.4.4
49
47
  type: :runtime
50
- version_requirements: *id003
51
- - !ruby/object:Gem::Dependency
52
- name: resque
53
48
  prerelease: false
54
- requirement: &id004 !ruby/object:Gem::Requirement
49
+ version_requirements: *2151826060
50
+ - !ruby/object:Gem::Dependency
51
+ name: resque
52
+ requirement: &2151821480 !ruby/object:Gem::Requirement
55
53
  none: false
56
- requirements:
54
+ requirements:
57
55
  - - ~>
58
- - !ruby/object:Gem::Version
56
+ - !ruby/object:Gem::Version
59
57
  version: 1.15.0
60
58
  type: :runtime
61
- version_requirements: *id004
62
- - !ruby/object:Gem::Dependency
63
- name: resque-status
64
59
  prerelease: false
65
- requirement: &id005 !ruby/object:Gem::Requirement
60
+ version_requirements: *2151821480
61
+ - !ruby/object:Gem::Dependency
62
+ name: resque-status
63
+ requirement: &2151818440 !ruby/object:Gem::Requirement
66
64
  none: false
67
- requirements:
65
+ requirements:
68
66
  - - ~>
69
- - !ruby/object:Gem::Version
67
+ - !ruby/object:Gem::Version
70
68
  version: 0.2.3
71
69
  type: :runtime
72
- version_requirements: *id005
73
- - !ruby/object:Gem::Dependency
74
- name: jsonschema
75
70
  prerelease: false
76
- requirement: &id006 !ruby/object:Gem::Requirement
71
+ version_requirements: *2151818440
72
+ - !ruby/object:Gem::Dependency
73
+ name: jsonschema
74
+ requirement: &2151815160 !ruby/object:Gem::Requirement
77
75
  none: false
78
- requirements:
76
+ requirements:
79
77
  - - ~>
80
- - !ruby/object:Gem::Version
78
+ - !ruby/object:Gem::Version
81
79
  version: 2.0.0
82
80
  type: :development
83
- version_requirements: *id006
84
- - !ruby/object:Gem::Dependency
85
- name: rspec
86
81
  prerelease: false
87
- requirement: &id007 !ruby/object:Gem::Requirement
82
+ version_requirements: *2151815160
83
+ - !ruby/object:Gem::Dependency
84
+ name: rspec
85
+ requirement: &2151812380 !ruby/object:Gem::Requirement
88
86
  none: false
89
- requirements:
87
+ requirements:
90
88
  - - ~>
91
- - !ruby/object:Gem::Version
89
+ - !ruby/object:Gem::Version
92
90
  version: 2.5.0
93
91
  type: :development
94
- version_requirements: *id007
95
- - !ruby/object:Gem::Dependency
96
- name: awesome_print
97
92
  prerelease: false
98
- requirement: &id008 !ruby/object:Gem::Requirement
93
+ version_requirements: *2151812380
94
+ - !ruby/object:Gem::Dependency
95
+ name: awesome_print
96
+ requirement: &2151808480 !ruby/object:Gem::Requirement
99
97
  none: false
100
- requirements:
98
+ requirements:
101
99
  - - ~>
102
- - !ruby/object:Gem::Version
103
- version: "0.3"
100
+ - !ruby/object:Gem::Version
101
+ version: '0.3'
104
102
  type: :development
105
- version_requirements: *id008
106
- - !ruby/object:Gem::Dependency
107
- name: roo
108
103
  prerelease: false
109
- requirement: &id009 !ruby/object:Gem::Requirement
104
+ version_requirements: *2151808480
105
+ - !ruby/object:Gem::Dependency
106
+ name: roo
107
+ requirement: &2151800000 !ruby/object:Gem::Requirement
110
108
  none: false
111
- requirements:
109
+ requirements:
112
110
  - - ~>
113
- - !ruby/object:Gem::Version
111
+ - !ruby/object:Gem::Version
114
112
  version: 1.9.3
115
113
  type: :development
116
- version_requirements: *id009
117
- - !ruby/object:Gem::Dependency
118
- name: builder
119
114
  prerelease: false
120
- requirement: &id010 !ruby/object:Gem::Requirement
115
+ version_requirements: *2151800000
116
+ - !ruby/object:Gem::Dependency
117
+ name: builder
118
+ requirement: &2151803680 !ruby/object:Gem::Requirement
121
119
  none: false
122
- requirements:
120
+ requirements:
123
121
  - - ~>
124
- - !ruby/object:Gem::Version
122
+ - !ruby/object:Gem::Version
125
123
  version: 3.0.0
126
124
  type: :development
127
- version_requirements: *id010
128
- - !ruby/object:Gem::Dependency
129
- name: spreadsheet
130
125
  prerelease: false
131
- requirement: &id011 !ruby/object:Gem::Requirement
126
+ version_requirements: *2151803680
127
+ - !ruby/object:Gem::Dependency
128
+ name: spreadsheet
129
+ requirement: &2151912800 !ruby/object:Gem::Requirement
132
130
  none: false
133
- requirements:
131
+ requirements:
134
132
  - - ~>
135
- - !ruby/object:Gem::Version
133
+ - !ruby/object:Gem::Version
136
134
  version: 0.6.5.2
137
135
  type: :development
138
- version_requirements: *id011
139
- - !ruby/object:Gem::Dependency
140
- name: google-spreadsheet-ruby
141
136
  prerelease: false
142
- requirement: &id012 !ruby/object:Gem::Requirement
137
+ version_requirements: *2151912800
138
+ - !ruby/object:Gem::Dependency
139
+ name: google-spreadsheet-ruby
140
+ requirement: &2152185860 !ruby/object:Gem::Requirement
143
141
  none: false
144
- requirements:
142
+ requirements:
145
143
  - - ~>
146
- - !ruby/object:Gem::Version
144
+ - !ruby/object:Gem::Version
147
145
  version: 0.1.2
148
146
  type: :development
149
- version_requirements: *id012
150
- description: A library for extracting quality measure information from HITSP C32's and ASTM CCR's
147
+ prerelease: false
148
+ version_requirements: *2152185860
149
+ description: A library for extracting quality measure information from HITSP C32's
150
+ and ASTM CCR's
151
151
  email: talk@projectpophealth.org
152
152
  executables: []
153
-
154
153
  extensions: []
155
-
156
154
  extra_rdoc_files: []
157
-
158
- files:
155
+ files:
159
156
  - lib/qme/database_access.rb
160
- - lib/qme/ext/string.rb
161
- - lib/qme/importer/code_system_helper.rb
157
+ - lib/qme/ext/record.rb
162
158
  - lib/qme/importer/entry.rb
163
159
  - lib/qme/importer/generic_importer.rb
164
- - lib/qme/importer/hl7_helper.rb
165
- - lib/qme/importer/patient_importer.rb
160
+ - lib/qme/importer/measure_properties_generator.rb
166
161
  - lib/qme/importer/property_matcher.rb
167
162
  - lib/qme/importer/provider_importer.rb
168
- - lib/qme/importer/section_importer.rb
169
163
  - lib/qme/map/map_reduce_builder.rb
170
164
  - lib/qme/map/map_reduce_executor.rb
171
165
  - lib/qme/map/measure_calculation_job.rb
@@ -177,6 +171,7 @@ files:
177
171
  - lib/qme/quality_report.rb
178
172
  - lib/qme/randomizer/patient_randomization_job.rb
179
173
  - lib/qme/randomizer/patient_randomizer.rb
174
+ - lib/qme/randomizer/random_patient_creator.rb
180
175
  - lib/qme_test.rb
181
176
  - lib/quality-measure-engine.rb
182
177
  - lib/tasks/fixtures.rake
@@ -192,30 +187,27 @@ files:
192
187
  has_rdoc: true
193
188
  homepage: http://github.com/pophealth/quality-measure-engine
194
189
  licenses: []
195
-
196
190
  post_install_message:
197
191
  rdoc_options: []
198
-
199
- require_paths:
192
+ require_paths:
200
193
  - lib
201
- required_ruby_version: !ruby/object:Gem::Requirement
194
+ required_ruby_version: !ruby/object:Gem::Requirement
202
195
  none: false
203
- requirements:
204
- - - ">="
205
- - !ruby/object:Gem::Version
206
- version: "0"
207
- required_rubygems_version: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - ! '>='
198
+ - !ruby/object:Gem::Version
199
+ version: '0'
200
+ required_rubygems_version: !ruby/object:Gem::Requirement
208
201
  none: false
209
- requirements:
210
- - - ">="
211
- - !ruby/object:Gem::Version
212
- version: "0"
202
+ requirements:
203
+ - - ! '>='
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
213
206
  requirements: []
214
-
215
207
  rubyforge_project:
216
208
  rubygems_version: 1.6.2
217
209
  signing_key:
218
210
  specification_version: 3
219
- summary: A library for extracting quality measure information from HITSP C32's and ASTM CCR's
211
+ summary: A library for extracting quality measure information from HITSP C32's and
212
+ ASTM CCR's
220
213
  test_files: []
221
-
@@ -1,5 +0,0 @@
1
- class String
2
- def to_boolean
3
- ['1', 'true', 't'].include?(self.downcase)
4
- end
5
- end
@@ -1,41 +0,0 @@
1
- module QME
2
- module Importer
3
- # General helpers for working with codes and code systems
4
- class CodeSystemHelper
5
- CODE_SYSTEMS = {
6
- '2.16.840.1.113883.6.1' => 'LOINC',
7
- '2.16.840.1.113883.6.96' => 'SNOMED-CT',
8
- '2.16.840.1.113883.6.12' => 'CPT',
9
- #'2.16.840.1.113883.3.88.12.80.32' => 'CPT',
10
- '2.16.840.1.113883.6.88' => 'RxNorm',
11
- '2.16.840.1.113883.6.103' => 'ICD-9-CM',
12
- '2.16.840.1.113883.6.104' => 'ICD-9-CM',
13
- '2.16.840.1.113883.6.90' => 'ICD-10-CM',
14
- '2.16.840.1.113883.6.14' => 'HCPCS',
15
- '2.16.840.1.113883.6.59' => 'CVX',
16
- '2.16.840.1.113883.6.238' => 'CDC-RE'
17
- }
18
-
19
- # Returns the name of a code system given an oid
20
- # @param [String] oid of a code system
21
- # @return [String] the name of the code system as described in the measure definition JSON
22
- def self.code_system_for(oid)
23
- CODE_SYSTEMS[oid] || "Unknown"
24
- end
25
-
26
- # Returns the oid for a code system given a codesystem name
27
- # @param [String] the name of the code system
28
- # @return [String] the oid of the code system
29
- def self.oid_for_code_system(code_system)
30
- CODE_SYSTEMS.invert[code_system]
31
- end
32
-
33
- # Returns the whole map of OIDs to code systems
34
- # @terurn [Hash] oids as keys, code system names as values
35
- def self.code_systems
36
- CODE_SYSTEMS
37
- end
38
- end
39
- end
40
- end
41
-
@@ -1,27 +0,0 @@
1
- module QME
2
- module Importer
3
-
4
- # General helpers for working with HL7 data types
5
- class HL7Helper
6
-
7
- # Converts an HL7 timestamp into an Integer
8
- # @param [String] timestamp the HL7 timestamp. Expects YYYYMMDD format
9
- # @return [Integer] Date in seconds since the epoch
10
- def self.timestamp_to_integer(timestamp)
11
- if timestamp && timestamp.length >= 4
12
- year = timestamp[0..3].to_i
13
- month = timestamp.length >= 6 ? timestamp[4..5].to_i : 1
14
- day = timestamp.length >= 8 ? timestamp[6..7].to_i : 1
15
- hour = timestamp.length >= 10 ? timestamp[8..9].to_i : 0
16
- min = timestamp.length >= 12 ? timestamp[10..11].to_i : 0
17
- sec = timestamp.length >= 14 ? timestamp[12..13].to_i : 0
18
-
19
- Time.gm(year, month, day, hour, min, sec).to_i
20
- else
21
- nil
22
- end
23
-
24
- end
25
- end
26
- end
27
- end
@@ -1,228 +0,0 @@
1
- module QME
2
- module Importer
3
-
4
- # This class is the central location for taking a HITSP C32 XML document and converting it
5
- # into the processed form we store in MongoDB. The class does this by running each measure
6
- # independently on the XML document
7
- #
8
- # This class is a Singleton. It should be accessed by calling PatientImporter.instance
9
- class PatientImporter
10
-
11
- include Singleton
12
-
13
- # Creates a new PatientImporter with the following XPath expressions used to find content in
14
- # a HITSP C32:
15
- #
16
- # Encounter entries
17
- # //cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.127']/cda:entry/cda:encounter
18
- #
19
- # Procedure entries
20
- # //cda:procedure[cda:templateId/@root='2.16.840.1.113883.10.20.1.29']
21
- #
22
- # Result entries - There seems to be some confusion around the correct templateId, so the code checks for both
23
- # //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']
24
- #
25
- # Vital sign entries
26
- # //cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.14']
27
- #
28
- # Medication entries
29
- # //cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.112']/cda:entry/cda:substanceAdministration
30
- #
31
- # Codes for medications are found in the substanceAdministration with the following relative XPath
32
- # ./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code
33
- #
34
- # Condition entries
35
- # //cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.103']/cda:entry/cda:act/cda:entryRelationship/cda:observation
36
- #
37
- # Codes for conditions are determined by examining the value child element as opposed to the code child element
38
- #
39
- # Social History entries (non-C32 section, specified in the HL7 CCD)
40
- # //cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.19']
41
- #
42
- # Care Goal entries(non-C32 section, specified in the HL7 CCD)
43
- # //cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.25']
44
- #
45
- # Allergy entries
46
- # //cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.18']
47
- #
48
- # Immunization entries
49
- # //cda:substanceAdministration[cda:templateId/@root='2.16.840.1.113883.10.20.1.24']
50
- #
51
- # Codes for immunizations are found in the substanceAdministration with the following relative XPath
52
- # ./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code
53
- def initialize (check_usable = true)
54
- @measure_importers = {}
55
- @section_importers = {}
56
- @id_map = {}
57
- @section_importers[:encounters] = SectionImporter.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.127']/cda:entry/cda:encounter")
58
- @section_importers[:procedures] = SectionImporter.new("//cda:procedure[cda:templateId/@root='2.16.840.1.113883.10.20.1.29']")
59
- @section_importers[:results] = SectionImporter.new("//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']")
60
- @section_importers[:vital_signs] = SectionImporter.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.14']")
61
- @section_importers[:medications] = SectionImporter.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.112']/cda:entry/cda:substanceAdministration",
62
- "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code",
63
- nil,
64
- "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code/cda:originalText/cda:reference[@value]")
65
- @section_importers[:conditions] = SectionImporter.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.103']/cda:entry/cda:act/cda:entryRelationship/cda:observation",
66
- "./cda:value",
67
- "./cda:entryRelationship/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.50']/cda:value",
68
- "./cda:text/cda:reference[@value]")
69
- @section_importers[:social_history] = SectionImporter.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.19']")
70
- @section_importers[:care_goals] = SectionImporter.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.25']")
71
- @section_importers[:medical_equipment] = SectionImporter.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.128']/cda:entry/cda:supply",
72
- "./cda:participant/cda:participantRole/cda:playingDevice/cda:code")
73
- @section_importers[:allergies] = SectionImporter.new("//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.1.18']",
74
- "./cda:participant/cda:participantRole/cda:playingEntity/cda:code")
75
- @section_importers[:immunizations] = SectionImporter.new("//cda:section[cda:templateId/@root='2.16.840.1.113883.3.88.11.83.117']/cda:entry/cda:substanceAdministration",
76
- "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code",
77
- nil,
78
- "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code/cda:originalText/cda:reference[@value]" )
79
- end
80
-
81
- def build_id_map(doc)
82
- id_map = {}
83
- path = "//*[@ID]"
84
- ids = doc.xpath(path)
85
- ids.each do |id|
86
- tag = id['ID']
87
- value = id.content
88
- id_map[tag] = value
89
- end
90
- return id_map
91
- end
92
-
93
- # @param [boolean] value for check_usable_entries...importer uses true, stats uses false
94
- def check_usable(check_usable_entries)
95
- @section_importers.each_pair do |section, importer|
96
- importer.check_for_usable = check_usable_entries
97
- end
98
- end
99
-
100
- # Parses a HITSP C32 document and returns a Hash of of the patient.
101
- #
102
- # @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
103
- # will have the "cda" namespace registered to "urn:hl7-org:v3"
104
- # @return [Hash] a representation of the patient that can be inserted into MongoDB
105
- def parse_c32(doc)
106
- c32_patient = {}
107
- entries = create_c32_hash(doc)
108
- get_demographics(c32_patient, doc)
109
- process_events(c32_patient, entries)
110
- end
111
-
112
- # Parses a patient hash containing demographic and event information
113
- #
114
- # @param [Hash] patient_hash patient data
115
- # @return [Hash] a representation of the patient that can be inserted into MongoDB
116
- def parse_hash(patient_hash)
117
- patient_record = {}
118
- patient_record['first'] = patient_hash['first']
119
- patient_record['patient_id'] = patient_hash['patient_id']
120
- patient_record['last'] = patient_hash['last']
121
- patient_record['gender'] = patient_hash['gender']
122
- patient_record['patient_id'] = patient_hash['patient_id']
123
- patient_record['birthdate'] = patient_hash['birthdate']
124
- patient_record['race'] = patient_hash['race']
125
- patient_record['ethnicity'] = patient_hash['ethnicity']
126
- patient_record['languages'] = patient_hash['languages']
127
- patient_record['addresses'] = patient_hash['addresses']
128
- event_hash = {}
129
- patient_hash['events'].each do |key, value|
130
- event_hash[key.intern] = parse_events(value)
131
- end
132
- process_events(patient_record, event_hash)
133
- end
134
-
135
- # Adds the entries and denormalized measure information to the patient_record.
136
- # Each Entry will be converted to a Hash and stored in an Array under the appropriate
137
- # section key, such as medications. Measure information is listed under the measures
138
- # key which has a Hash value. The Hash has the measure id as a key, and the denormalized
139
- # measure information as a value
140
- #
141
- # @param patient_record - Hash with basic patient demographic information
142
- # @entries - Hash of entries with section names a keys and an Array of Entry values
143
- def process_events(patient_record, entries)
144
- patient_record['measures'] = {}
145
- @measure_importers.each_pair do |measure_id, importer|
146
- patient_record['measures'][measure_id] = importer.parse(entries)
147
- end
148
-
149
- entries.each_pair do |key, value|
150
- patient_record[key] = value.map do |e|
151
- if e.usable?
152
- e.to_hash
153
- else
154
- nil
155
- end
156
- end.compact
157
- end
158
-
159
- patient_record
160
- end
161
-
162
- # Parses a list of event hashes into an array of Entry objects
163
- #
164
- # @param [Array] event_list list of event hashes
165
- # @return [Array] array of Entry objects
166
- def parse_events(event_list)
167
- event_list.collect do |event|
168
- if event.class==String.class
169
- # skip String elements in the event list, patient randomization templates
170
- # introduce String elements to simplify tailing-comma handling when generating
171
- # JSON using ERb
172
- nil
173
- else
174
- QME::Importer::Entry.from_event_hash(event)
175
- end
176
- end.compact
177
- end
178
-
179
- # Adds a measure to run on a C32 that is passed in
180
- #
181
- # @param [MeasureBase] measure an Class that can extract information from a C32 that is necessary
182
- # to calculate the measure
183
- def add_measure(measure_id, importer)
184
- @measure_importers[measure_id] = importer
185
- end
186
-
187
- # Create a simple representation of the patient from a HITSP C32
188
- #
189
- # @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
190
- # will have the "cda" namespace registered to "urn:hl7-org:v3"
191
- # @return [Hash] a represnetation of the patient with symbols as keys for each section
192
- def create_c32_hash(doc, check_usable_entries = true)
193
- c32_patient = {}
194
- id_map = build_id_map(doc)
195
- @section_importers.each_pair do |section, importer|
196
- importer.check_for_usable = check_usable_entries
197
- c32_patient[section] = importer.create_entries(doc,id_map)
198
- end
199
- c32_patient
200
- end
201
-
202
- # Inspects a C32 document and populates the patient Hash with first name, last name
203
- # birth date and gender.
204
- #
205
- # @param [Hash] patient A hash that is used to represent the patient
206
- # @param [Nokogiri::XML::Node] doc The C32 document parsed by Nokogiri
207
- def get_demographics(patient, doc)
208
- patient['first'] = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:name/cda:given').text
209
- patient['last'] = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:name/cda:family').text
210
- birthdate_in_hl7ts_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:birthTime')
211
- birthdate_in_hl7ts = birthdate_in_hl7ts_node['value']
212
- patient['birthdate'] = HL7Helper.timestamp_to_integer(birthdate_in_hl7ts)
213
- gender_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:administrativeGenderCode')
214
- patient['gender'] = gender_node['code']
215
- race_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:raceCode')
216
- patient['race'] = race_node['code'] if race_node
217
- ethnicity_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient/cda:ethnicGroupCode')
218
- patient['ethnicity'] = ethnicity_node['code'] if ethnicity_node
219
-
220
- languages = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:patient').search('languageCommunication').map {|lc| lc.at_xpath('cda:languageCode')['code'] }
221
- patient['languages'] = languages unless languages.empty?
222
-
223
- id_node = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole/cda:id')
224
- patient['patient_id'] = id_node['extension']
225
- end
226
- end
227
- end
228
- end