quality-measure-engine 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +1 -1
- data/Gemfile +3 -1
- data/Gemfile.lock +15 -2
- data/lib/qme/bundle/bundle.rb +14 -0
- data/lib/qme/bundle/eh_measure_sheet.rb +114 -0
- data/lib/qme/bundle/eh_patient_importer.rb +21 -0
- data/lib/qme/bundle/importer.rb +3 -10
- data/lib/qme/tasks/bundle.rake +82 -3
- data/lib/qme/version.rb +1 -1
- data/lib/quality-measure-engine.rb +3 -0
- data/quality-measure-engine.gemspec +2 -0
- data/test/fixtures/bundles/just_measure_0002.zip +0 -0
- data/test/fixtures/delayed_backend_mongoid_jobs/queued_job.json +4 -7
- data/test/fixtures/eh_patient_sheets/results_matrix_eh.xlsx +0 -0
- data/test/fixtures/measures/0142.json +19 -0
- data/test/fixtures/measures/0495a.json +23 -0
- data/test/fixtures/measures/0495b.json +24 -0
- data/test/fixtures/records/barry_berry.json +1 -0
- data/test/fixtures/records/billy_jones_ipp.json +1 -0
- data/test/fixtures/records/jill_jones_denominator.json +1 -0
- data/test/unit/qme/bundle/eh_measure_sheet_test.rb +37 -0
- data/test/unit/qme/bundle/eh_patient_importer_test.rb +20 -0
- data/test/unit/qme/quality_report_test.rb +1 -0
- metadata +48 -2
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
quality-measure-engine (2.
|
4
|
+
quality-measure-engine (2.1.0)
|
5
5
|
delayed_job_mongoid (~> 2.0.0)
|
6
6
|
mongoid (~> 3.0.9)
|
7
7
|
moped (~> 1.2.7)
|
8
|
+
nokogiri (~> 1.5.5)
|
9
|
+
rubyXL (~> 1.2.10)
|
8
10
|
rubyzip (~> 0.9.9)
|
9
11
|
|
10
12
|
GEM
|
@@ -38,6 +40,7 @@ GEM
|
|
38
40
|
i18n (~> 0.6)
|
39
41
|
multi_json (~> 1.0)
|
40
42
|
arel (3.0.2)
|
43
|
+
binding_of_caller (0.6.8)
|
41
44
|
builder (3.0.4)
|
42
45
|
coderay (1.0.8)
|
43
46
|
delayed_job (3.0.3)
|
@@ -48,6 +51,7 @@ GEM
|
|
48
51
|
erubis (2.7.0)
|
49
52
|
hike (1.2.1)
|
50
53
|
i18n (0.6.1)
|
54
|
+
interception (0.3)
|
51
55
|
journey (1.0.4)
|
52
56
|
json (1.7.5)
|
53
57
|
mail (2.4.4)
|
@@ -64,7 +68,8 @@ GEM
|
|
64
68
|
tzinfo (~> 0.3.22)
|
65
69
|
moped (1.2.7)
|
66
70
|
multi_json (1.3.6)
|
67
|
-
|
71
|
+
nokogiri (1.5.5)
|
72
|
+
origin (1.0.10)
|
68
73
|
polyglot (0.3.3)
|
69
74
|
pry (0.9.10)
|
70
75
|
coderay (~> 1.0.5)
|
@@ -72,6 +77,11 @@ GEM
|
|
72
77
|
slop (~> 3.3.1)
|
73
78
|
pry-nav (0.2.2)
|
74
79
|
pry (~> 0.9.10)
|
80
|
+
pry-rescue (0.12)
|
81
|
+
interception (>= 0.3)
|
82
|
+
pry
|
83
|
+
pry-stack_explorer (0.4.7)
|
84
|
+
binding_of_caller (~> 0.6.8)
|
75
85
|
rack (1.4.1)
|
76
86
|
rack-cache (1.2)
|
77
87
|
rack (>= 0.4)
|
@@ -97,6 +107,7 @@ GEM
|
|
97
107
|
rake (0.9.2.2)
|
98
108
|
rdoc (3.12)
|
99
109
|
json (~> 1.4)
|
110
|
+
rubyXL (1.2.10)
|
100
111
|
rubyzip (0.9.9)
|
101
112
|
simplecov (0.7.1)
|
102
113
|
multi_json (~> 1.0)
|
@@ -121,6 +132,8 @@ DEPENDENCIES
|
|
121
132
|
minitest (~> 4.1.0)
|
122
133
|
pry
|
123
134
|
pry-nav
|
135
|
+
pry-rescue
|
136
|
+
pry-stack_explorer
|
124
137
|
quality-measure-engine!
|
125
138
|
rails (~> 3.2.8)
|
126
139
|
simplecov (~> 0.7.1)
|
data/lib/qme/bundle/bundle.rb
CHANGED
@@ -30,5 +30,19 @@ module QME
|
|
30
30
|
def self.entry_key(original, extension)
|
31
31
|
original.split('/').last.gsub(".#{extension}", '')
|
32
32
|
end
|
33
|
+
|
34
|
+
def self.unpack_bundle_contents(zip)
|
35
|
+
bundle_contents = { bundle: nil, measures: {}, patients: {}, extensions: {}, results: {} }
|
36
|
+
Zip::ZipFile.open(zip.path) do |zipfile|
|
37
|
+
zipfile.entries.each do |entry|
|
38
|
+
bundle_contents[:bundle] = zipfile.read(entry.name) if entry.name.include? "bundle"
|
39
|
+
bundle_contents[:measures][Bundle.entry_key(entry.name, "json")] = zipfile.read(entry.name) if entry.name.match /^measures.*\.json$/
|
40
|
+
bundle_contents[:patients][Bundle.entry_key(entry.name, "json")] = zipfile.read(entry.name) if entry.name.match /^patients.*\.json$/ # Only need to import one of the formats
|
41
|
+
bundle_contents[:extensions][Bundle.entry_key(entry.name,"js")] = zipfile.read(entry.name) if entry.name.match /^library_functions.*\.js/
|
42
|
+
bundle_contents[:results][Bundle.entry_key(entry.name,"json")] = zipfile.read(entry.name) if entry.name.match /^results.*\.json/
|
43
|
+
end
|
44
|
+
end
|
45
|
+
bundle_contents
|
46
|
+
end
|
33
47
|
end
|
34
48
|
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module QME
|
2
|
+
module Bundle
|
3
|
+
class EHMeasureSheet
|
4
|
+
attr_reader :query_cache_document, :patient_cache_documents,
|
5
|
+
:patient_updates
|
6
|
+
|
7
|
+
def initialize(db, sheet, effective_date=nil)
|
8
|
+
@db = db
|
9
|
+
@sheet = sheet
|
10
|
+
@effective_date = effective_date
|
11
|
+
@patient_cache_documents = []
|
12
|
+
@patient_updates = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def parse
|
16
|
+
qc_document = {}
|
17
|
+
measure_info = extract_measure_info
|
18
|
+
qc_document['population_ids'] = measure_info
|
19
|
+
measure_doc = @db['measures'].where('population_ids' => measure_info).first
|
20
|
+
measure_ids = measure_doc.slice('sub_id', 'nqf_id')
|
21
|
+
measure_ids['measure_id'] = measure_doc['hqmf_id']
|
22
|
+
qc_document.merge!(measure_ids)
|
23
|
+
extract_patients(measure_ids)
|
24
|
+
|
25
|
+
qc_document['population'] = extract_data_from_cell("C#{@population_totals_row}")
|
26
|
+
qc_document['considered'] = @population_totals_row - 3 # header row, blank row and totals row
|
27
|
+
if cv_measure?
|
28
|
+
qc_document['msrpopl'] = extract_data_from_cell("E#{@population_totals_row}")
|
29
|
+
else
|
30
|
+
qc_document['denominator'] = extract_data_from_cell("D#{@population_totals_row}")
|
31
|
+
qc_document['numerator'] = extract_data_from_cell("E#{@population_totals_row}")
|
32
|
+
qc_document['antinumerator'] = qc_document['denominator'] - qc_document['numerator']
|
33
|
+
qc_document['exclusions'] = extract_data_from_cell("F#{@population_totals_row}")
|
34
|
+
qc_document['denexcep'] = extract_data_from_cell("G#{@population_totals_row}")
|
35
|
+
end
|
36
|
+
|
37
|
+
qc_document['test_id'] = nil
|
38
|
+
qc_document['filters'] = nil
|
39
|
+
qc_document['execution_time'] = 0
|
40
|
+
qc_document['effective_date'] = @effective_date
|
41
|
+
|
42
|
+
@query_cache_document = qc_document
|
43
|
+
end
|
44
|
+
|
45
|
+
def extract_patients(measure_ids)
|
46
|
+
row = 2
|
47
|
+
medical_record_number = extract_data_from_cell("B#{row}")
|
48
|
+
while medical_record_number.present?
|
49
|
+
patient_document = extract_patient(row, medical_record_number.to_s)
|
50
|
+
patient_document.merge!(measure_ids)
|
51
|
+
@patient_cache_documents << {'value' => patient_document}
|
52
|
+
@patient_updates << {'medical_record_number' => medical_record_number.to_s,
|
53
|
+
'measure_id' => measure_ids['measure_id']}
|
54
|
+
row = row + 1
|
55
|
+
medical_record_number = extract_data_from_cell("B#{row}")
|
56
|
+
end
|
57
|
+
|
58
|
+
@population_totals_row = row + 1
|
59
|
+
end
|
60
|
+
|
61
|
+
def extract_measure_info
|
62
|
+
measure_info = {}
|
63
|
+
measure_info['IPP'] = extract_data_from_cell('I5')
|
64
|
+
if cv_measure?
|
65
|
+
measure_info['MSRPOPL'] = extract_data_from_cell('I10')
|
66
|
+
measure_info['stratification'] = extract_data_from_cell('I11') if extract_data_from_cell('I11').present?
|
67
|
+
else
|
68
|
+
measure_info['DENOM'] = extract_data_from_cell('I6')
|
69
|
+
measure_info['NUMER'] = extract_data_from_cell('I7')
|
70
|
+
measure_info['DENEXCEP'] = extract_data_from_cell('I8') if extract_data_from_cell('I8').present?
|
71
|
+
measure_info['DENEX'] = extract_data_from_cell('I9') if extract_data_from_cell('I9').present?
|
72
|
+
measure_info['stratification'] = extract_data_from_cell('I11') if extract_data_from_cell('I11').present?
|
73
|
+
end
|
74
|
+
|
75
|
+
measure_info
|
76
|
+
end
|
77
|
+
|
78
|
+
def extract_patient(row, medical_record_number)
|
79
|
+
record = @db['records'].where('medical_record_number' => medical_record_number).first
|
80
|
+
patient_document = record.slice('first', 'last', 'gender', 'birthdate', 'race',
|
81
|
+
'ethnicity', 'languages')
|
82
|
+
patient_document['medical_record_id'] = medical_record_number
|
83
|
+
patient_document['patient_id'] = record['_id'].to_s
|
84
|
+
patient_document['population'] = extract_data_from_cell("C#{row}") || 0
|
85
|
+
if cv_measure?
|
86
|
+
patient_document['values'] = [extract_data_from_cell("E#{row}")]
|
87
|
+
else
|
88
|
+
patient_document['denominator'] = extract_data_from_cell("D#{row}") || 0
|
89
|
+
patient_document['numerator'] = extract_data_from_cell("E#{row}") || 0
|
90
|
+
patient_document['exclusions'] = extract_data_from_cell("F#{row}") || 0
|
91
|
+
patient_document['denexcep'] = extract_data_from_cell("G#{row}") || 0
|
92
|
+
patient_document['antinumerator'] = patient_document['denominator'] - patient_document['numerator']
|
93
|
+
|
94
|
+
end
|
95
|
+
patient_document['test_id'] = nil
|
96
|
+
patient_document['effective_date'] = @effective_date
|
97
|
+
|
98
|
+
patient_document
|
99
|
+
end
|
100
|
+
|
101
|
+
def cv_measure?
|
102
|
+
extract_data_from_cell('E1').eql?('MSRPOPL')
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
def extract_data_from_cell(cell_name)
|
108
|
+
row, column = RubyXL::Parser.convert_to_index(cell_name)
|
109
|
+
@sheet.sheet_data[row][column].try(:value)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module QME
|
2
|
+
module Bundle
|
3
|
+
class EHPatientImporter
|
4
|
+
def self.load(db, spreadsheet, effective_date=nil)
|
5
|
+
spreadsheet.worksheets.each do |worksheet|
|
6
|
+
ms = EHMeasureSheet.new(db, worksheet, effective_date)
|
7
|
+
ms.parse
|
8
|
+
qc_document = ms.query_cache_document
|
9
|
+
db['query_cache'].insert(qc_document)
|
10
|
+
ms.patient_cache_documents.each do |pcd|
|
11
|
+
db['patient_cache'].insert(pcd)
|
12
|
+
end
|
13
|
+
ms.patient_updates.each do |patient_update|
|
14
|
+
db['records'].find('medical_record_number' => patient_update['medical_record_number']).update(
|
15
|
+
'$push' => {'measure_ids' => patient_update['measure_id']})
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/qme/bundle/importer.rb
CHANGED
@@ -18,16 +18,7 @@ module QME
|
|
18
18
|
Bundle.drop_collections(@db) if delete_existing
|
19
19
|
|
20
20
|
# Unpack content from the bundle.
|
21
|
-
bundle_contents =
|
22
|
-
Zip::ZipFile.open(zip.path) do |zipfile|
|
23
|
-
zipfile.entries.each do |entry|
|
24
|
-
bundle_contents[:bundle] = zipfile.read(entry.name) if entry.name.include? "bundle"
|
25
|
-
bundle_contents[:measures][Bundle.entry_key(entry.name, "json")] = zipfile.read(entry.name) if entry.name.match /^measures.*\.json$/
|
26
|
-
bundle_contents[:patients][Bundle.entry_key(entry.name, "json")] = zipfile.read(entry.name) if entry.name.match /^patients.*\.json$/ # Only need to import one of the formats
|
27
|
-
bundle_contents[:extensions][Bundle.entry_key(entry.name,"js")] = zipfile.read(entry.name) if entry.name.match /^library_functions/
|
28
|
-
bundle_contents[:results][Bundle.entry_key(entry.name,"json")] = zipfile.read(entry.name) if entry.name.match /^results/
|
29
|
-
end
|
30
|
-
end
|
21
|
+
bundle_contents = QME::Bundle.unpack_bundle_contents(zip)
|
31
22
|
|
32
23
|
# Store all JS libraries.
|
33
24
|
bundle_contents[:extensions].each do |key, contents|
|
@@ -63,6 +54,8 @@ module QME
|
|
63
54
|
contents = JSON.parse(contents, {:max_nesting => 100})
|
64
55
|
contents.each {|document| @db[collection].insert(document)}
|
65
56
|
end
|
57
|
+
|
58
|
+
bundle_contents
|
66
59
|
end
|
67
60
|
end
|
68
61
|
end
|
data/lib/qme/tasks/bundle.rake
CHANGED
@@ -4,11 +4,90 @@ db_name = ENV['DB_NAME'] || 'test'
|
|
4
4
|
|
5
5
|
namespace :bundle do
|
6
6
|
desc 'Import a quality bundle into the database.'
|
7
|
-
task :import, :bundle_path, :delete_existing
|
7
|
+
task :import, [:bundle_path, :delete_existing] => [:environment] do |task, args|
|
8
8
|
raise "The path to the measures zip file must be specified" unless args.bundle_path
|
9
9
|
|
10
10
|
bundle = File.open(args.bundle_path)
|
11
11
|
importer = QME::Bundle::Importer.new(db_name)
|
12
|
-
importer.import(bundle, args.delete_existing)
|
12
|
+
bundle_contents = importer.import(bundle, args.delete_existing == "true")
|
13
|
+
|
14
|
+
puts "Successfully imported bundle at: #{args.bundle_path}"
|
15
|
+
puts "\t Imported into environment: #{Rails.env.upcase}" if defined? Rails
|
16
|
+
puts "\t Measures Loaded: #{bundle_contents[:measures].count}"
|
17
|
+
puts "\t Test Patients Loaded: #{bundle_contents[:patients].count}"
|
18
|
+
puts "\t Extensions Loaded: #{bundle_contents[:extensions].count}"
|
19
|
+
|
13
20
|
end
|
14
|
-
|
21
|
+
|
22
|
+
# this task is most likely temporary. Once Bonnie can handle both EP and EH measures together, this would no longer be required.
|
23
|
+
desc 'Merge two bundles into one.'
|
24
|
+
task :merge, [:bundle_one,:bundle_two] do |t, args|
|
25
|
+
raise "Two bundle zip file paths to be merged must be specified" unless args.bundle_one && args.bundle_two
|
26
|
+
|
27
|
+
tmpdir = Dir.mktmpdir
|
28
|
+
['measures','patients','library_functions','results', 'sources'].each do |dir|
|
29
|
+
|
30
|
+
FileUtils.mkdir_p(File.join(tmpdir, 'output', dir))
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
|
36
|
+
({'one'=>args.bundle_one,'two'=>args.bundle_two}).each do |key, source|
|
37
|
+
Zip::ZipFile.open(source) do |zip_file|
|
38
|
+
zip_file.each do |f|
|
39
|
+
f_path=File.join(tmpdir, key, f.name)
|
40
|
+
FileUtils.mkdir_p(File.dirname(f_path))
|
41
|
+
zip_file.extract(f, f_path) unless File.exist?(f_path)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
['measures','patients','library_functions', 'sources'].each do |dir|
|
48
|
+
['one','two'].each do |key|
|
49
|
+
FileUtils.mv(Dir.glob(File.join(tmpdir,key,dir,'*')), File.join(tmpdir,'output',dir))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
Dir.glob(File.join(tmpdir,'one','results','*.json')).each do |result_path_one|
|
54
|
+
json_one = JSON.parse(File.new(result_path_one).read)
|
55
|
+
result_filename = Pathname.new(result_path_one).basename.to_s
|
56
|
+
json_two = JSON.parse(File.new(File.join(tmpdir,'two','results',result_filename)).read)
|
57
|
+
File.open(File.join(tmpdir,'output','results',result_filename), 'w') {|f| f.write(JSON.pretty_generate(json_one + json_two)) }
|
58
|
+
end
|
59
|
+
|
60
|
+
json_one = JSON.parse(File.new(File.join(tmpdir,'one','bundle.json')).read)
|
61
|
+
json_two = JSON.parse(File.new(File.join(tmpdir,'two','bundle.json')).read)
|
62
|
+
json_out = {}
|
63
|
+
|
64
|
+
['title','effective_date','version','license','exported'].each do |key|
|
65
|
+
json_out[key] = json_one[key]
|
66
|
+
end
|
67
|
+
|
68
|
+
['measures','patients','extensions'].each do |key|
|
69
|
+
json_out[key] = (json_one[key] + json_two[key]).uniq
|
70
|
+
end
|
71
|
+
|
72
|
+
File.open(File.join(tmpdir,'output','bundle.json'), 'w') {|f| f.write(JSON.pretty_generate(json_out)) }
|
73
|
+
date_string = Time.now.strftime("%Y-%m-%d")
|
74
|
+
|
75
|
+
out_zip = File.join('tmp','bundles',"bundle-merged-#{date_string}.zip")
|
76
|
+
FileUtils.remove_entry_secure out_zip if File.exists?(out_zip)
|
77
|
+
Zip::ZipFile.open(out_zip, 'w') do |zipfile|
|
78
|
+
path = File.join(tmpdir,'output')
|
79
|
+
Dir[File.join(path,'**','**')].each do |file|
|
80
|
+
zipfile.add(file.sub(path+'/',''),file)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
puts "wrote merged bundle to: #{out_zip}"
|
85
|
+
|
86
|
+
ensure
|
87
|
+
FileUtils.remove_entry_secure tmpdir
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
data/lib/qme/version.rb
CHANGED
@@ -3,6 +3,7 @@ require "bundler/setup"
|
|
3
3
|
require 'moped'
|
4
4
|
require 'delayed_job_mongoid'
|
5
5
|
require 'zip/zip'
|
6
|
+
require 'rubyXL'
|
6
7
|
|
7
8
|
require "qme/version"
|
8
9
|
require 'qme/database_access'
|
@@ -14,6 +15,8 @@ require 'qme/map/measure_calculation_job'
|
|
14
15
|
|
15
16
|
require 'qme/quality_report'
|
16
17
|
|
18
|
+
require 'qme/bundle/eh_measure_sheet'
|
19
|
+
require 'qme/bundle/eh_patient_importer'
|
17
20
|
require 'qme/bundle/bundle'
|
18
21
|
require 'qme/bundle/importer'
|
19
22
|
|
@@ -21,6 +21,8 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.add_dependency 'mongoid', '~> 3.0.9'
|
22
22
|
gem.add_dependency 'rubyzip', '~> 0.9.9'
|
23
23
|
gem.add_dependency 'delayed_job_mongoid', '~> 2.0.0'
|
24
|
+
gem.add_dependency 'nokogiri', '~> 1.5.5'
|
25
|
+
gem.add_dependency 'rubyXL', '~> 1.2.10'
|
24
26
|
|
25
27
|
gem.add_development_dependency "minitest", "~> 4.1.0"
|
26
28
|
gem.add_development_dependency "simplecov", "~> 0.7.1"
|
Binary file
|
@@ -1,9 +1,6 @@
|
|
1
1
|
{
|
2
|
-
_id: "508aeff07042f9f88900000d",
|
3
|
-
priority: 0,
|
4
|
-
attempts: 0,
|
5
|
-
handler: "--- !ruby/object:QME::MapReduce::MeasureCalculationJob\ntest_id: \nmeasure_id: test2\nsub_id: b\neffective_date: 1284854400\nfilters: \n"
|
6
|
-
run_at: ISODate("2012-10-26T20:17:52+00:00"),
|
7
|
-
updated_at: ISODate("2012-10-26T20:17:52+00:00"),
|
8
|
-
created_at: ISODate("2012-10-26T20:17:52+00:00")
|
2
|
+
"_id": "508aeff07042f9f88900000d",
|
3
|
+
"priority": 0,
|
4
|
+
"attempts": 0,
|
5
|
+
"handler": "--- !ruby/object:QME::MapReduce::MeasureCalculationJob\ntest_id: \nmeasure_id: test2\nsub_id: b\neffective_date: 1284854400\nfilters: \n"
|
9
6
|
}
|
Binary file
|
@@ -0,0 +1,19 @@
|
|
1
|
+
{
|
2
|
+
"id": "8A4D92B2-3887-5DF3-0139-0D01C6626E46",
|
3
|
+
"nqf_id": "0142",
|
4
|
+
"hqmf_id": "8A4D92B2-3887-5DF3-0139-0D01C6626E46",
|
5
|
+
"hqmf_set_id": "BB481284-30DD-4383-928C-82385BBF1B17",
|
6
|
+
"hqmf_version_number": 1,
|
7
|
+
"endorser": null,
|
8
|
+
"name": "Aspirin Prescribed at Discharge",
|
9
|
+
"description": "Acute myocardial infarction (AMI) patients who are prescribed aspirin at hospital discharge",
|
10
|
+
"type": "eh",
|
11
|
+
"category": "Miscellaneous",
|
12
|
+
"steward": null,
|
13
|
+
"population_ids": {
|
14
|
+
"IPP": "EDD90083-3417-4221-B3B9-52C4E5FAFAF4",
|
15
|
+
"DENOM": "193A17EC-66B4-4C44-9302-192556C78454",
|
16
|
+
"NUMER": "C224FC7D-B0C3-4A7F-BB9C-4480C3095F9F",
|
17
|
+
"DENEX": "FCE06869-6ADE-4A43-9A28-098D808A55BD"
|
18
|
+
}
|
19
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
{
|
2
|
+
"id": "8A4D92B2-3887-5DF3-0139-0C4E41594C98",
|
3
|
+
"nqf_id": "0495",
|
4
|
+
"hqmf_id": "8A4D92B2-3887-5DF3-0139-0C4E41594C98",
|
5
|
+
"hqmf_set_id": "9A033274-3D9B-11E1-8634-00237D5BF174",
|
6
|
+
"hqmf_version_number": 1,
|
7
|
+
"endorser": null,
|
8
|
+
"name": "Median Time from ED Arrival to ED Departure for Admitted ED Patients",
|
9
|
+
"description": "Median time from emergency department arrival to time of departure from the emergency room for patients admitted to the facility from the emergency department.",
|
10
|
+
"type": "eh",
|
11
|
+
"category": "Miscellaneous",
|
12
|
+
"steward": null,
|
13
|
+
"denominator": null,
|
14
|
+
"numerator": null,
|
15
|
+
"exclusions": null,
|
16
|
+
"sub_id": "a",
|
17
|
+
"subtitle": "Population 1",
|
18
|
+
"short_subtitle": "Population 1",
|
19
|
+
"population_ids": {
|
20
|
+
"IPP": "FA8BE62B-09FB-4B01-8CA8-E3CF1F9A16F6",
|
21
|
+
"MSRPOPL": "F3441A34-7FEA-4DAB-9907-A19885CFF92F"
|
22
|
+
}
|
23
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
{
|
2
|
+
"id": "8A4D92B2-3887-5DF3-0139-0C4E41594C98",
|
3
|
+
"nqf_id": "0495",
|
4
|
+
"hqmf_id": "8A4D92B2-3887-5DF3-0139-0C4E41594C98",
|
5
|
+
"hqmf_set_id": "9A033274-3D9B-11E1-8634-00237D5BF174",
|
6
|
+
"hqmf_version_number": 1,
|
7
|
+
"endorser": null,
|
8
|
+
"name": "Median Time from ED Arrival to ED Departure for Admitted ED Patients",
|
9
|
+
"description": "Median time from emergency department arrival to time of departure from the emergency room for patients admitted to the facility from the emergency department.",
|
10
|
+
"type": "eh",
|
11
|
+
"category": "Miscellaneous",
|
12
|
+
"steward": null,
|
13
|
+
"denominator": null,
|
14
|
+
"numerator": null,
|
15
|
+
"exclusions": null,
|
16
|
+
"sub_id": "b",
|
17
|
+
"subtitle": "Population 2",
|
18
|
+
"short_subtitle": "Population 2",
|
19
|
+
"population_ids": {
|
20
|
+
"IPP": "FA8BE62B-09FB-4B01-8CA8-E3CF1F9A16F6",
|
21
|
+
"MSRPOPL": "F3441A34-7FEA-4DAB-9907-A19885CFF92F",
|
22
|
+
"stratification": "1509C6DA-2465-4571-A6D4-AD634BE49BE6"
|
23
|
+
}
|
24
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EHMeasureSheetTest < MiniTest::Unit::TestCase
|
4
|
+
include QME::DatabaseAccess
|
5
|
+
|
6
|
+
def setup
|
7
|
+
collection_fixtures(get_db(), 'measures')
|
8
|
+
collection_fixtures(get_db(), 'records', '_id')
|
9
|
+
@workbook = RubyXL::Parser.parse(File.join('test', 'fixtures', 'eh_patient_sheets', 'results_matrix_eh.xlsx'))
|
10
|
+
sheet = @workbook.worksheets[0]
|
11
|
+
@ms = QME::Bundle::EHMeasureSheet.new(get_db(), sheet, 12345000)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_extract_measure_info
|
15
|
+
measure_info = @ms.extract_measure_info
|
16
|
+
assert_equal 'EDD90083-3417-4221-B3B9-52C4E5FAFAF4', measure_info['IPP']
|
17
|
+
assert_equal '193A17EC-66B4-4C44-9302-192556C78454', measure_info['DENOM']
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_query_cache_document
|
21
|
+
@ms.parse
|
22
|
+
qcd = @ms.query_cache_document
|
23
|
+
assert_equal '0142', qcd['nqf_id']
|
24
|
+
assert_equal 4, qcd['population']
|
25
|
+
assert_equal 12345000, qcd['effective_date']
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_patient_cache_documents
|
29
|
+
@ms.parse
|
30
|
+
pcd = @ms.patient_cache_documents.first
|
31
|
+
assert_equal 1, pcd['value']['population']
|
32
|
+
assert_equal 0, pcd['value']['numerator']
|
33
|
+
assert_equal 1, pcd['value']['antinumerator']
|
34
|
+
assert_equal '1234', pcd['value']['medical_record_id']
|
35
|
+
assert_equal 12345000, pcd['value']['effective_date']
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class EHPatientImporterTest < MiniTest::Unit::TestCase
|
4
|
+
include QME::DatabaseAccess
|
5
|
+
|
6
|
+
def setup
|
7
|
+
get_db['query_cache'].drop()
|
8
|
+
get_db['patient_cache'].drop()
|
9
|
+
collection_fixtures(get_db(), 'measures')
|
10
|
+
collection_fixtures(get_db(), 'records', '_id')
|
11
|
+
@workbook = RubyXL::Parser.parse(File.join('test', 'fixtures', 'eh_patient_sheets', 'results_matrix_eh.xlsx'))
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_load
|
15
|
+
assert_equal 0, get_db['query_cache'].find().count
|
16
|
+
QME::Bundle::EHPatientImporter.load(get_db, @workbook)
|
17
|
+
assert_equal 3, get_db['query_cache'].find().count
|
18
|
+
assert_equal 12, get_db['patient_cache'].find().count
|
19
|
+
end
|
20
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quality-measure-engine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2012-
|
15
|
+
date: 2012-11-14 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: moped
|
@@ -78,6 +78,38 @@ dependencies:
|
|
78
78
|
- - ~>
|
79
79
|
- !ruby/object:Gem::Version
|
80
80
|
version: 2.0.0
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: nokogiri
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ~>
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 1.5.5
|
89
|
+
type: :runtime
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
92
|
+
none: false
|
93
|
+
requirements:
|
94
|
+
- - ~>
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 1.5.5
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubyXL
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ~>
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 1.2.10
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
109
|
+
requirements:
|
110
|
+
- - ~>
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: 1.2.10
|
81
113
|
- !ruby/object:Gem::Dependency
|
82
114
|
name: minitest
|
83
115
|
requirement: !ruby/object:Gem::Requirement
|
@@ -141,6 +173,8 @@ files:
|
|
141
173
|
- README.md
|
142
174
|
- Rakefile
|
143
175
|
- lib/qme/bundle/bundle.rb
|
176
|
+
- lib/qme/bundle/eh_measure_sheet.rb
|
177
|
+
- lib/qme/bundle/eh_patient_importer.rb
|
144
178
|
- lib/qme/bundle/importer.rb
|
145
179
|
- lib/qme/database_access.rb
|
146
180
|
- lib/qme/map/map_reduce_builder.rb
|
@@ -155,6 +189,10 @@ files:
|
|
155
189
|
- quality-measure-engine.gemspec
|
156
190
|
- test/fixtures/bundles/just_measure_0002.zip
|
157
191
|
- test/fixtures/delayed_backend_mongoid_jobs/queued_job.json
|
192
|
+
- test/fixtures/eh_patient_sheets/results_matrix_eh.xlsx
|
193
|
+
- test/fixtures/measures/0142.json
|
194
|
+
- test/fixtures/measures/0495a.json
|
195
|
+
- test/fixtures/measures/0495b.json
|
158
196
|
- test/fixtures/measures/measure_metadata.json
|
159
197
|
- test/fixtures/records/barry_berry.json
|
160
198
|
- test/fixtures/records/billy_jones_ipp.json
|
@@ -162,6 +200,8 @@ files:
|
|
162
200
|
- test/fixtures/records/jill_jones_denominator.json
|
163
201
|
- test/simplecov_setup.rb
|
164
202
|
- test/test_helper.rb
|
203
|
+
- test/unit/qme/bundle/eh_measure_sheet_test.rb
|
204
|
+
- test/unit/qme/bundle/eh_patient_importer_test.rb
|
165
205
|
- test/unit/qme/map/map_reduce_builder_test.rb
|
166
206
|
- test/unit/qme/map/map_reduce_executor_test.rb
|
167
207
|
- test/unit/qme/map/measure_calculation_job_test.rb
|
@@ -195,6 +235,10 @@ summary: This library can run JavaScript based clinical quality measures on a re
|
|
195
235
|
test_files:
|
196
236
|
- test/fixtures/bundles/just_measure_0002.zip
|
197
237
|
- test/fixtures/delayed_backend_mongoid_jobs/queued_job.json
|
238
|
+
- test/fixtures/eh_patient_sheets/results_matrix_eh.xlsx
|
239
|
+
- test/fixtures/measures/0142.json
|
240
|
+
- test/fixtures/measures/0495a.json
|
241
|
+
- test/fixtures/measures/0495b.json
|
198
242
|
- test/fixtures/measures/measure_metadata.json
|
199
243
|
- test/fixtures/records/barry_berry.json
|
200
244
|
- test/fixtures/records/billy_jones_ipp.json
|
@@ -202,6 +246,8 @@ test_files:
|
|
202
246
|
- test/fixtures/records/jill_jones_denominator.json
|
203
247
|
- test/simplecov_setup.rb
|
204
248
|
- test/test_helper.rb
|
249
|
+
- test/unit/qme/bundle/eh_measure_sheet_test.rb
|
250
|
+
- test/unit/qme/bundle/eh_patient_importer_test.rb
|
205
251
|
- test/unit/qme/map/map_reduce_builder_test.rb
|
206
252
|
- test/unit/qme/map/map_reduce_executor_test.rb
|
207
253
|
- test/unit/qme/map/measure_calculation_job_test.rb
|