quality-measure-engine 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +1 -1
- data/js/map_reduce_utils.js +29 -1
- data/lib/quality-measure-engine.rb +0 -1
- metadata +26 -27
- data/lib/qme/importer/provider_importer.rb +0 -97
data/Gemfile
CHANGED
@@ -7,7 +7,7 @@ gem 'bson_ext', '1.5.1', :platforms => :mri
|
|
7
7
|
gem 'rake'
|
8
8
|
#gem 'pry', :require => true
|
9
9
|
#gem 'health-data-standards', :git => 'https://github.com/projectcypress/health-data-standards.git', :branch => 'master'
|
10
|
-
gem 'health-data-standards', '0.7.
|
10
|
+
gem 'health-data-standards', '0.7.1'
|
11
11
|
|
12
12
|
group :test do
|
13
13
|
gem 'cover_me', '>= 1.0.0.rc5', :platforms => :ruby_19
|
data/js/map_reduce_utils.js
CHANGED
@@ -116,7 +116,35 @@ function() {
|
|
116
116
|
values = normalize(values);
|
117
117
|
return _.select(values, function(value) { return value<=max && value>=min; });
|
118
118
|
}
|
119
|
-
|
119
|
+
|
120
|
+
// calculates the earliest birthdate for a maximum age given a target date.
|
121
|
+
// calculation is inclusive of the full year for the target age
|
122
|
+
// returns: (earliest birthdate that will reach by not exceed the age by the target date)
|
123
|
+
// age: integer in years
|
124
|
+
// effective_date: end of the measurement period, in seconds
|
125
|
+
root.earliestBirthdayForThisAge = function(age, effective_date) {
|
126
|
+
return calculateDateForAge(age, effective_date, true);
|
127
|
+
}
|
128
|
+
// calculates the latest birthdate for a minimum age given a target date
|
129
|
+
// returns: (latest birthdate that will reach the age by the target date)
|
130
|
+
// age: integer in years
|
131
|
+
// effective_date: end of the measurement period, in seconds
|
132
|
+
root.latestBirthdayForThisAge = function(age, effective_date) {
|
133
|
+
return calculateDateForAge(age, effective_date, false);
|
134
|
+
}
|
135
|
+
// returns birth date for an age value given a specific date
|
136
|
+
// age: integer in years
|
137
|
+
// effective_date: end of the measurement period, in seconds
|
138
|
+
// is_inclusive: boolean for including or excluding age
|
139
|
+
root.calculateDateForAge = function(age, effective_date, is_inclusive) {
|
140
|
+
var earliest_birthdate = new Date(effective_date*1000);
|
141
|
+
var difference = age;
|
142
|
+
if (is_inclusive) difference += 1;
|
143
|
+
earliest_birthdate.setFullYear(earliest_birthdate.getFullYear()-difference);
|
144
|
+
return earliest_birthdate.getTime()/1000;
|
145
|
+
}
|
146
|
+
|
147
|
+
|
120
148
|
root.map = function(record, population, denominator, numerator, exclusion) {
|
121
149
|
var value = {population: false, denominator: false, numerator: false,
|
122
150
|
exclusions: false, antinumerator: false, patient_id: record._id,
|
@@ -22,7 +22,6 @@ require_relative 'qme/ext/record'
|
|
22
22
|
|
23
23
|
require_relative 'qme/importer/property_matcher'
|
24
24
|
require_relative 'qme/importer/generic_importer'
|
25
|
-
require_relative 'qme/importer/provider_importer'
|
26
25
|
require_relative 'qme/importer/measure_properties_generator'
|
27
26
|
|
28
27
|
require 'json'
|
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: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,12 +11,12 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2012-
|
14
|
+
date: 2012-02-17 00:00:00.000000000 -05:00
|
15
15
|
default_executable:
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: mongo
|
19
|
-
requirement: &
|
19
|
+
requirement: &2157284660 !ruby/object:Gem::Requirement
|
20
20
|
none: false
|
21
21
|
requirements:
|
22
22
|
- - ~>
|
@@ -24,10 +24,10 @@ dependencies:
|
|
24
24
|
version: '1.3'
|
25
25
|
type: :runtime
|
26
26
|
prerelease: false
|
27
|
-
version_requirements: *
|
27
|
+
version_requirements: *2157284660
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rubyzip
|
30
|
-
requirement: &
|
30
|
+
requirement: &2157272260 !ruby/object:Gem::Requirement
|
31
31
|
none: false
|
32
32
|
requirements:
|
33
33
|
- - ~>
|
@@ -35,10 +35,10 @@ dependencies:
|
|
35
35
|
version: 0.9.4
|
36
36
|
type: :runtime
|
37
37
|
prerelease: false
|
38
|
-
version_requirements: *
|
38
|
+
version_requirements: *2157272260
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: nokogiri
|
41
|
-
requirement: &
|
41
|
+
requirement: &2157271520 !ruby/object:Gem::Requirement
|
42
42
|
none: false
|
43
43
|
requirements:
|
44
44
|
- - ~>
|
@@ -46,10 +46,10 @@ dependencies:
|
|
46
46
|
version: 1.4.4
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
|
-
version_requirements: *
|
49
|
+
version_requirements: *2157271520
|
50
50
|
- !ruby/object:Gem::Dependency
|
51
51
|
name: resque
|
52
|
-
requirement: &
|
52
|
+
requirement: &2157270840 !ruby/object:Gem::Requirement
|
53
53
|
none: false
|
54
54
|
requirements:
|
55
55
|
- - ~>
|
@@ -57,10 +57,10 @@ dependencies:
|
|
57
57
|
version: 1.15.0
|
58
58
|
type: :runtime
|
59
59
|
prerelease: false
|
60
|
-
version_requirements: *
|
60
|
+
version_requirements: *2157270840
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: resque-status
|
63
|
-
requirement: &
|
63
|
+
requirement: &2157270100 !ruby/object:Gem::Requirement
|
64
64
|
none: false
|
65
65
|
requirements:
|
66
66
|
- - ~>
|
@@ -68,10 +68,10 @@ dependencies:
|
|
68
68
|
version: 0.2.3
|
69
69
|
type: :runtime
|
70
70
|
prerelease: false
|
71
|
-
version_requirements: *
|
71
|
+
version_requirements: *2157270100
|
72
72
|
- !ruby/object:Gem::Dependency
|
73
73
|
name: jsonschema
|
74
|
-
requirement: &
|
74
|
+
requirement: &2157269380 !ruby/object:Gem::Requirement
|
75
75
|
none: false
|
76
76
|
requirements:
|
77
77
|
- - ~>
|
@@ -79,10 +79,10 @@ dependencies:
|
|
79
79
|
version: 2.0.0
|
80
80
|
type: :development
|
81
81
|
prerelease: false
|
82
|
-
version_requirements: *
|
82
|
+
version_requirements: *2157269380
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rspec
|
85
|
-
requirement: &
|
85
|
+
requirement: &2157268580 !ruby/object:Gem::Requirement
|
86
86
|
none: false
|
87
87
|
requirements:
|
88
88
|
- - ~>
|
@@ -90,10 +90,10 @@ dependencies:
|
|
90
90
|
version: 2.5.0
|
91
91
|
type: :development
|
92
92
|
prerelease: false
|
93
|
-
version_requirements: *
|
93
|
+
version_requirements: *2157268580
|
94
94
|
- !ruby/object:Gem::Dependency
|
95
95
|
name: awesome_print
|
96
|
-
requirement: &
|
96
|
+
requirement: &2157268080 !ruby/object:Gem::Requirement
|
97
97
|
none: false
|
98
98
|
requirements:
|
99
99
|
- - ~>
|
@@ -101,10 +101,10 @@ dependencies:
|
|
101
101
|
version: '0.3'
|
102
102
|
type: :development
|
103
103
|
prerelease: false
|
104
|
-
version_requirements: *
|
104
|
+
version_requirements: *2157268080
|
105
105
|
- !ruby/object:Gem::Dependency
|
106
106
|
name: roo
|
107
|
-
requirement: &
|
107
|
+
requirement: &2157267620 !ruby/object:Gem::Requirement
|
108
108
|
none: false
|
109
109
|
requirements:
|
110
110
|
- - ~>
|
@@ -112,10 +112,10 @@ dependencies:
|
|
112
112
|
version: 1.9.3
|
113
113
|
type: :development
|
114
114
|
prerelease: false
|
115
|
-
version_requirements: *
|
115
|
+
version_requirements: *2157267620
|
116
116
|
- !ruby/object:Gem::Dependency
|
117
117
|
name: builder
|
118
|
-
requirement: &
|
118
|
+
requirement: &2157267100 !ruby/object:Gem::Requirement
|
119
119
|
none: false
|
120
120
|
requirements:
|
121
121
|
- - ~>
|
@@ -123,10 +123,10 @@ dependencies:
|
|
123
123
|
version: 3.0.0
|
124
124
|
type: :development
|
125
125
|
prerelease: false
|
126
|
-
version_requirements: *
|
126
|
+
version_requirements: *2157267100
|
127
127
|
- !ruby/object:Gem::Dependency
|
128
128
|
name: spreadsheet
|
129
|
-
requirement: &
|
129
|
+
requirement: &2157266420 !ruby/object:Gem::Requirement
|
130
130
|
none: false
|
131
131
|
requirements:
|
132
132
|
- - ~>
|
@@ -134,10 +134,10 @@ dependencies:
|
|
134
134
|
version: 0.6.5.2
|
135
135
|
type: :development
|
136
136
|
prerelease: false
|
137
|
-
version_requirements: *
|
137
|
+
version_requirements: *2157266420
|
138
138
|
- !ruby/object:Gem::Dependency
|
139
139
|
name: google-spreadsheet-ruby
|
140
|
-
requirement: &
|
140
|
+
requirement: &2157265900 !ruby/object:Gem::Requirement
|
141
141
|
none: false
|
142
142
|
requirements:
|
143
143
|
- - ~>
|
@@ -145,7 +145,7 @@ dependencies:
|
|
145
145
|
version: 0.1.2
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
|
-
version_requirements: *
|
148
|
+
version_requirements: *2157265900
|
149
149
|
description: A library for extracting quality measure information from HITSP C32's
|
150
150
|
and ASTM CCR's
|
151
151
|
email: talk@projectpophealth.org
|
@@ -159,7 +159,6 @@ files:
|
|
159
159
|
- lib/qme/importer/generic_importer.rb
|
160
160
|
- lib/qme/importer/measure_properties_generator.rb
|
161
161
|
- lib/qme/importer/property_matcher.rb
|
162
|
-
- lib/qme/importer/provider_importer.rb
|
163
162
|
- lib/qme/map/map_reduce_builder.rb
|
164
163
|
- lib/qme/map/map_reduce_executor.rb
|
165
164
|
- lib/qme/map/measure_calculation_job.rb
|
@@ -1,97 +0,0 @@
|
|
1
|
-
require "date"
|
2
|
-
require "date/delta"
|
3
|
-
|
4
|
-
module QME
|
5
|
-
module Importer
|
6
|
-
class ProviderImporter
|
7
|
-
include Singleton
|
8
|
-
|
9
|
-
# Extract Healthcare Providers from C32
|
10
|
-
#
|
11
|
-
# @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
|
12
|
-
# will have the "cda" namespace registered to "urn:hl7-org:v3"
|
13
|
-
# @return [Array] an array of providers found in the document
|
14
|
-
def extract_providers(doc, use_encounters=false)
|
15
|
-
|
16
|
-
|
17
|
-
xpath_base = use_encounters ? "//cda:encounter/cda:performer" : "//cda:documentationOf/cda:serviceEvent/cda:performer"
|
18
|
-
|
19
|
-
performers = doc.xpath(xpath_base)
|
20
|
-
|
21
|
-
providers = performers.map do |performer|
|
22
|
-
provider = {}
|
23
|
-
entity = performer.xpath(performer, "./cda:assignedEntity")
|
24
|
-
name = entity.xpath("./cda:assignedPerson/cda:name")
|
25
|
-
provider[:title] = extract_data(name, "./cda:prefix")
|
26
|
-
provider[:given_name] = extract_data(name, "./cda:given[1]")
|
27
|
-
provider[:family_name] = extract_data(name, "./cda:family")
|
28
|
-
provider[:phone] = extract_data(entity, "./cda:telecom/@value") { |text| text.gsub("tel:", "") }
|
29
|
-
provider[:organization] = extract_data(entity, "./cda:representedOrganization/cda:name")
|
30
|
-
provider[:specialty] = extract_data(entity, "./cda:code/@code")
|
31
|
-
time = performer.xpath(performer, "./cda:time")
|
32
|
-
provider[:start] = extract_date(time, "./cda:low/@value")
|
33
|
-
provider[:end] = extract_date(time, "./cda:high/@value")
|
34
|
-
# NIST sample C32s use different OID for NPI vs C83, support both
|
35
|
-
npi = extract_data(entity, "./cda:id[@root='2.16.840.1.113883.4.6' or @root='2.16.840.1.113883.3.72.5.2']/@extension")
|
36
|
-
if ProviderImporter::valid_npi?(npi)
|
37
|
-
provider[:npi] = npi
|
38
|
-
else
|
39
|
-
puts "Warning: Invalid NPI (#{npi})"
|
40
|
-
end
|
41
|
-
provider
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
private
|
46
|
-
|
47
|
-
def extract_date(subject,query)
|
48
|
-
date = extract_data(subject,query)
|
49
|
-
date ? Date.parse(date).to_time.to_i : nil
|
50
|
-
end
|
51
|
-
|
52
|
-
# Returns nil if result is an empty string, block allows text munging of result if there is one
|
53
|
-
def extract_data(subject, query)
|
54
|
-
result = subject.xpath(query).text
|
55
|
-
if result == ""
|
56
|
-
nil
|
57
|
-
elsif block_given?
|
58
|
-
yield(result)
|
59
|
-
else
|
60
|
-
result
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# validate the NPI, should be 10 or 15 digits total with the final digit being a
|
65
|
-
# checksum using the Luhn algorithm with additional special handling as described in
|
66
|
-
# https://www.cms.gov/NationalProvIdentStand/Downloads/NPIcheckdigit.pdf
|
67
|
-
def self.valid_npi?(npi)
|
68
|
-
return false if npi.length != 10 and npi.length != 15
|
69
|
-
return false if npi.gsub(/\d/, '').length > 0 # npi must be all digits
|
70
|
-
return false if npi.length == 15 and (npi =~ /^80840/)==nil # 15 digit npi must start with 80840
|
71
|
-
|
72
|
-
# checksum is always calculated as if 80840 prefix is present
|
73
|
-
if npi.length==10
|
74
|
-
npi = '80840'+npi
|
75
|
-
end
|
76
|
-
|
77
|
-
return luhn_checksum(npi[0,14])==npi[14]
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.luhn_checksum(num)
|
81
|
-
double = {'0' => 0, '1' => 2, '2' => 4, '3' => 6, '4' => 8, '5' => 1, '6' => 3, '7' => 5, '8' => 7, '9' => 9}
|
82
|
-
sum = 0
|
83
|
-
num.reverse!
|
84
|
-
num.split("").each_with_index do |char, i|
|
85
|
-
if (i%2)==0
|
86
|
-
sum+=double[char]
|
87
|
-
else
|
88
|
-
sum+=char.to_i
|
89
|
-
end
|
90
|
-
end
|
91
|
-
sum = (9*sum)%10
|
92
|
-
|
93
|
-
return sum.to_s
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|