health-data-standards 3.4.6 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -2
- data/README.md +4 -0
- data/lib/health-data-standards.rb +1 -0
- data/lib/health-data-standards/export/cat_1.rb +4 -4
- data/lib/health-data-standards/export/helper/scooped_view_helper.rb +16 -16
- data/lib/health-data-standards/export/qrda/hqmf-qrda-oids.json +6 -0
- data/lib/health-data-standards/export/view_helper.rb +8 -1
- data/lib/health-data-standards/import/bulk_record_importer.rb +45 -13
- data/lib/health-data-standards/import/bundle/importer.rb +2 -4
- data/lib/health-data-standards/import/cda/provider_importer.rb +2 -2
- data/lib/health-data-standards/import/green_c32/section_importer.rb +2 -2
- data/lib/health-data-standards/import/provider_import_utils.rb +2 -2
- data/lib/health-data-standards/models/cda_identifier.rb +1 -0
- data/lib/health-data-standards/models/cqm/bundle.rb +4 -1
- data/lib/health-data-standards/models/cqm/measure.rb +40 -25
- data/lib/health-data-standards/models/cqm/patient_cache.rb +61 -60
- data/lib/health-data-standards/models/encounter.rb +4 -12
- data/lib/health-data-standards/models/entry.rb +4 -8
- data/lib/health-data-standards/models/facility.rb +1 -0
- data/lib/health-data-standards/models/fulfillment_history.rb +6 -18
- data/lib/health-data-standards/models/guarantor.rb +1 -0
- data/lib/health-data-standards/models/lab_result.rb +2 -6
- data/lib/health-data-standards/models/medical_equipment.rb +2 -7
- data/lib/health-data-standards/models/medication.rb +11 -31
- data/lib/health-data-standards/models/metadata/link_info.rb +1 -0
- data/lib/health-data-standards/models/order_information.rb +5 -13
- data/lib/health-data-standards/models/organization.rb +1 -0
- data/lib/health-data-standards/models/procedure.rb +1 -4
- data/lib/health-data-standards/models/provider.rb +2 -1
- data/lib/health-data-standards/models/provider_performance.rb +1 -0
- data/lib/health-data-standards/models/qrda/legal_authenticator.rb +1 -0
- data/lib/health-data-standards/models/qrda/organization.rb +2 -0
- data/lib/health-data-standards/models/record.rb +7 -7
- data/lib/health-data-standards/models/result_value.rb +1 -0
- data/lib/health-data-standards/models/svs/concept.rb +1 -0
- data/lib/health-data-standards/models/svs/value_set.rb +1 -0
- data/lib/health-data-standards/models/telecom.rb +1 -0
- data/lib/health-data-standards/models/transfer.rb +1 -0
- data/lib/health-data-standards/tasks/bundle.rake +3 -3
- data/lib/health-data-standards/util/vs_api.rb +2 -2
- data/lib/hqmf-generator/attribute.xml.erb +9 -11
- data/lib/hqmf-generator/characteristic_criteria.xml.erb +5 -5
- data/lib/hqmf-generator/code.xml.erb +6 -2
- data/lib/hqmf-generator/condition_criteria.xml.erb +4 -5
- data/lib/hqmf-generator/derivation.xml.erb +6 -6
- data/lib/hqmf-generator/description.xml.erb +1 -1
- data/lib/hqmf-generator/document.xml.erb +46 -11
- data/lib/hqmf-generator/encounter_criteria.xml.erb +4 -5
- data/lib/hqmf-generator/field.xml.erb +13 -1
- data/lib/hqmf-generator/grouper_criteria.xml.erb +17 -0
- data/lib/hqmf-generator/hqmf-generator.rb +75 -8
- data/lib/hqmf-generator/local_variable.xml.erb +1 -0
- data/lib/hqmf-generator/measure_observation_definition.xml.erb +25 -0
- data/lib/hqmf-generator/observation_criteria.xml.erb +4 -5
- data/lib/hqmf-generator/population_criteria.xml.erb +2 -3
- data/lib/hqmf-generator/precondition.xml.erb +2 -2
- data/lib/hqmf-generator/precondition_cv.xml.erb +8 -0
- data/lib/hqmf-generator/procedure_criteria.xml.erb +4 -5
- data/lib/hqmf-generator/reference.xml.erb +2 -2
- data/lib/hqmf-generator/source.xml.erb +2 -2
- data/lib/hqmf-generator/specific_occurrence.xml.erb +4 -5
- data/lib/hqmf-generator/subset.xml.erb +16 -3
- data/lib/hqmf-generator/substance_criteria.xml.erb +4 -5
- data/lib/hqmf-generator/supply_criteria.xml.erb +4 -5
- data/lib/hqmf-generator/temporal_relationship.xml.erb +1 -1
- data/lib/hqmf-generator/value.xml.erb +35 -9
- data/lib/hqmf-generator/variable_criteria.xml.erb +2 -3
- data/lib/hqmf-model/attribute.rb +36 -8
- data/lib/hqmf-model/data_criteria.json +38 -204
- data/lib/hqmf-model/data_criteria.rb +40 -16
- data/lib/hqmf-model/document.rb +61 -2
- data/lib/hqmf-model/population_criteria.rb +11 -7
- data/lib/hqmf-model/precondition.rb +1 -1
- data/lib/hqmf-model/types.rb +91 -8
- data/lib/hqmf-parser/1.0/attribute.rb +55 -2
- data/lib/hqmf-parser/1.0/document.rb +10 -23
- data/lib/hqmf-parser/1.0/population_criteria.rb +2 -2
- data/lib/hqmf-parser/1.0/range.rb +0 -1
- data/lib/hqmf-parser/2.0/data_criteria.rb +90 -21
- data/lib/hqmf-parser/2.0/document.rb +122 -7
- data/lib/hqmf-parser/2.0/population_criteria.rb +18 -6
- data/lib/hqmf-parser/2.0/precondition.rb +4 -1
- data/lib/hqmf-parser/2.0/types.rb +36 -15
- data/lib/hqmf-parser/converter/pass1/document_converter.rb +4 -56
- data/lib/hqmf-parser/converter/pass1/population_criteria_converter.rb +24 -8
- data/lib/hqmf-parser/converter/pass1/precondition_extractor.rb +15 -2
- data/lib/hqmf-parser/converter/pass2/comparison_converter.rb +1 -1
- data/lib/hqmf-parser/parser.rb +64 -41
- data/templates/cat1/_2.16.840.1.113883.10.20.22.4.85.cat1.erb +0 -1
- data/templates/cat1/_address.cat1.erb +9 -0
- data/templates/cat1/_author.cat1.erb +28 -0
- data/templates/cat1/_id.cat1.erb +1 -0
- data/templates/cat1/_organization.cat1.erb +8 -0
- data/templates/cat1/_patient_data.cat1.erb +0 -3
- data/templates/cat1/_telecom.cat1.erb +1 -0
- data/templates/cat1/show.cat1.erb +96 -58
- metadata +115 -66
- checksums.yaml +0 -7
@@ -5,16 +5,28 @@ module HQMF2
|
|
5
5
|
|
6
6
|
include HQMF2::Utilities
|
7
7
|
|
8
|
-
attr_reader :preconditions, :id, :hqmf_id, :title, :
|
9
|
-
|
8
|
+
attr_reader :preconditions, :id, :hqmf_id, :title, :aggregator, :comments
|
9
|
+
#need to do this to allow for setting the type to OBSERV for
|
10
|
+
attr_accessor :type
|
10
11
|
# Create a new population criteria from the supplied HQMF entry
|
11
12
|
# @param [Nokogiri::XML::Element] the HQMF entry
|
12
13
|
def initialize(entry, doc)
|
13
14
|
@doc = doc
|
14
15
|
@entry = entry
|
15
|
-
@hqmf_id = attr_val('./*/cda:id/@extension')
|
16
|
+
@hqmf_id = attr_val('./*/cda:id/@extension') || attr_val('./*/cda:typeId/@extension')
|
16
17
|
@title = attr_val('./*/cda:code/cda:displayName/@value')
|
17
18
|
@type = attr_val('./*/cda:code/@code')
|
19
|
+
@aggregator = nil
|
20
|
+
@comments = @entry.xpath("./*/cda:text/cda:xml/cda:qdmUserComments/cda:item/text()", HQMF2::Document::NAMESPACES)
|
21
|
+
.map{ |v| v.content }
|
22
|
+
obs_test = attr_val('./cda:measureObservationDefinition/@classCode')
|
23
|
+
if !@title && obs_test.to_s == "OBS"
|
24
|
+
@title = attr_val('../cda:code/cda:displayName/@value')
|
25
|
+
@aggregator = attr_val('./cda:measureObservationDefinition/cda:methodCode/cda:item/@code')
|
26
|
+
end
|
27
|
+
if(!@hqmf_id) # The id extension is not required, if it's not provided use the code
|
28
|
+
@hqmf_id = @type
|
29
|
+
end
|
18
30
|
@preconditions = @entry.xpath('./*/cda:precondition[not(@nullFlavor)]', HQMF2::Document::NAMESPACES).collect do |precondition|
|
19
31
|
Precondition.new(precondition, @doc)
|
20
32
|
end
|
@@ -34,7 +46,7 @@ module HQMF2
|
|
34
46
|
# @return [String] conjunction code
|
35
47
|
def conjunction_code
|
36
48
|
case @type
|
37
|
-
when HQMF::PopulationCriteria::IPP, HQMF::PopulationCriteria::DENOM, HQMF::PopulationCriteria::NUMER
|
49
|
+
when HQMF::PopulationCriteria::IPP, HQMF::PopulationCriteria::DENOM, HQMF::PopulationCriteria::NUMER,HQMF::PopulationCriteria::MSRPOPL
|
38
50
|
HQMF::Precondition::ALL_TRUE
|
39
51
|
when HQMF::PopulationCriteria::DENEXCEP, HQMF::PopulationCriteria::DENEX
|
40
52
|
HQMF::Precondition::AT_LEAST_ONE_TRUE
|
@@ -45,9 +57,9 @@ module HQMF2
|
|
45
57
|
|
46
58
|
def to_model
|
47
59
|
mps = preconditions.collect {|p| p.to_model}
|
48
|
-
HQMF::PopulationCriteria.new(id, hqmf_id, type, mps, title)
|
60
|
+
HQMF::PopulationCriteria.new(id, hqmf_id, type, mps, title, aggregator, comments)
|
49
61
|
end
|
50
62
|
|
51
63
|
end
|
52
64
|
|
53
|
-
end
|
65
|
+
end
|
@@ -13,6 +13,9 @@ module HQMF2
|
|
13
13
|
Precondition.new(precondition, @doc)
|
14
14
|
end
|
15
15
|
reference_def = @entry.at_xpath('./*/cda:id', HQMF2::Document::NAMESPACES)
|
16
|
+
if !reference_def
|
17
|
+
reference_def = @entry.at_xpath('./cda:join/cda:templateId/cda:item', HQMF2::Document::NAMESPACES)
|
18
|
+
end
|
16
19
|
if reference_def
|
17
20
|
@reference = Reference.new(reference_def)
|
18
21
|
end
|
@@ -41,4 +44,4 @@ module HQMF2
|
|
41
44
|
end
|
42
45
|
end
|
43
46
|
|
44
|
-
end
|
47
|
+
end
|
@@ -20,20 +20,16 @@ module HQMF2
|
|
20
20
|
|
21
21
|
attr_reader :type, :unit, :value
|
22
22
|
|
23
|
-
def initialize(entry, default_type='PQ')
|
23
|
+
def initialize(entry, default_type='PQ', force_inclusive=false)
|
24
24
|
@entry = entry
|
25
25
|
@type = attr_val('./@xsi:type') || default_type
|
26
26
|
@unit = attr_val('./@unit')
|
27
27
|
@value = attr_val('./@value')
|
28
|
+
@force_inclusive = force_inclusive
|
28
29
|
end
|
29
30
|
|
30
31
|
def inclusive?
|
31
|
-
|
32
|
-
when 'false'
|
33
|
-
false
|
34
|
-
else
|
35
|
-
true
|
36
|
-
end
|
32
|
+
attr_val("../@#{@entry.name}Closed") == 'true' || @force_inclusive
|
37
33
|
end
|
38
34
|
|
39
35
|
def derived?
|
@@ -67,9 +63,9 @@ module HQMF2
|
|
67
63
|
@type = type
|
68
64
|
@entry = entry
|
69
65
|
if @entry
|
70
|
-
@low = optional_value(
|
71
|
-
@high = optional_value(
|
72
|
-
@width = optional_value(
|
66
|
+
@low = optional_value("#{default_element_name}/cda:low", default_bounds_type)
|
67
|
+
@high = optional_value("#{default_element_name}/cda:high", default_bounds_type)
|
68
|
+
@width = optional_value("#{default_element_name}/cda:width", 'PQ')
|
73
69
|
end
|
74
70
|
end
|
75
71
|
|
@@ -81,7 +77,11 @@ module HQMF2
|
|
81
77
|
lm = low ? low.to_model : nil
|
82
78
|
hm = high ? high.to_model : nil
|
83
79
|
wm = width ? width.to_model : nil
|
84
|
-
|
80
|
+
model_type = type
|
81
|
+
if @entry.at_xpath('./cda:uncertainRange', HQMF2::Document::NAMESPACES)
|
82
|
+
model_type = 'IVL_PQ'
|
83
|
+
end
|
84
|
+
HQMF::Range.new(model_type, lm, hm, wm)
|
85
85
|
end
|
86
86
|
|
87
87
|
private
|
@@ -94,6 +94,17 @@ module HQMF2
|
|
94
94
|
nil
|
95
95
|
end
|
96
96
|
end
|
97
|
+
|
98
|
+
def default_element_name
|
99
|
+
case type
|
100
|
+
when 'IVL_PQ'
|
101
|
+
'.'
|
102
|
+
when 'IVL_TS'
|
103
|
+
'cda:phase'
|
104
|
+
else
|
105
|
+
'cda:uncertainRange'
|
106
|
+
end
|
107
|
+
end
|
97
108
|
|
98
109
|
def default_bounds_type
|
99
110
|
case type
|
@@ -141,7 +152,7 @@ module HQMF2
|
|
141
152
|
end
|
142
153
|
|
143
154
|
def title
|
144
|
-
attr_val('
|
155
|
+
attr_val('./*/@value')
|
145
156
|
end
|
146
157
|
|
147
158
|
def value
|
@@ -171,8 +182,18 @@ module HQMF2
|
|
171
182
|
@entry = entry
|
172
183
|
@type = attr_val('./cda:subsetCode/@code')
|
173
184
|
value_def = @entry.at_xpath('./*/cda:repeatNumber', HQMF2::Document::NAMESPACES)
|
185
|
+
if !value_def
|
186
|
+
value_def = @entry.at_xpath('./*/cda:value', HQMF2::Document::NAMESPACES)
|
187
|
+
end
|
174
188
|
if value_def
|
175
|
-
|
189
|
+
value_type = value_def.at_xpath('./@xsi:type', HQMF2::Document::NAMESPACES)
|
190
|
+
if String.try_convert(value_type) == "ANY"
|
191
|
+
@value = HQMF2::AnyValue.new()
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
if value_def && !@value
|
196
|
+
@value = HQMF2::Range.new(value_def, 'IVL_PQ')
|
176
197
|
end
|
177
198
|
end
|
178
199
|
|
@@ -193,7 +214,7 @@ module HQMF2
|
|
193
214
|
@reference = Reference.new(@entry.at_xpath('./*/cda:id', HQMF2::Document::NAMESPACES))
|
194
215
|
range_def = @entry.at_xpath('./cda:pauseQuantity', HQMF2::Document::NAMESPACES)
|
195
216
|
if range_def
|
196
|
-
@range = HQMF2::Range.new(range_def, '
|
217
|
+
@range = HQMF2::Range.new(range_def, 'PQ')
|
197
218
|
end
|
198
219
|
end
|
199
220
|
|
@@ -220,4 +241,4 @@ module HQMF2
|
|
220
241
|
end
|
221
242
|
end
|
222
243
|
|
223
|
-
end
|
244
|
+
end
|
@@ -9,9 +9,9 @@ module HQMF
|
|
9
9
|
title = json[:title]
|
10
10
|
description = json[:description]
|
11
11
|
|
12
|
+
# TODO: Investigate why we never use json[:attributes]
|
12
13
|
metadata = json[:metadata]
|
13
14
|
metadata.keys.each {|key| metadata[key.to_s] = metadata[key]; metadata.delete(key.to_sym)}
|
14
|
-
|
15
15
|
id = metadata["NQF_ID_NUMBER"][:value] if metadata["NQF_ID_NUMBER"]
|
16
16
|
emeasure_id = metadata['EMEASURE_IDENTIFIER'][:value] if metadata['EMEASURE_IDENTIFIER']
|
17
17
|
attributes = parse_attributes(metadata)
|
@@ -45,73 +45,21 @@ module HQMF
|
|
45
45
|
|
46
46
|
doc = HQMF::Document.new(id, hqmf_id, hqmf_set_id, hqmf_version_number, cms_id, title, description, population_criteria, data_criteria, source_data_criteria, attributes, measure_period, populations)
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
HQMF::DocumentConverter.validate(doc, codes)
|
48
|
+
HQMF::DocumentConverter.validate(doc, codes) if codes
|
51
49
|
|
52
50
|
doc
|
53
51
|
|
54
52
|
end
|
55
53
|
|
56
54
|
private
|
57
|
-
|
55
|
+
|
58
56
|
def self.parse_attributes(metadata)
|
59
57
|
attributes = []
|
60
58
|
metadata.keys.each do |key|
|
61
|
-
|
62
|
-
code = attribute_hash[:code]
|
63
|
-
value = attribute_hash[:value]
|
64
|
-
unit = attribute_hash[:unit]
|
65
|
-
name = attribute_hash[:name]
|
66
|
-
attributes << HQMF::Attribute.new(key,code,value,unit,name)
|
59
|
+
attributes << HQMF::Attribute.from_json(metadata[key])
|
67
60
|
end
|
68
61
|
attributes
|
69
62
|
end
|
70
|
-
|
71
|
-
|
72
|
-
# patient characteristics data criteria such as GENDER require looking at the codes to determine if the
|
73
|
-
# measure is interested in Males or Females. This process is awkward, and thus is done as a separate
|
74
|
-
# step after the document has been converted.
|
75
|
-
def self.backfill_patient_characteristics_with_codes(doc, codes)
|
76
|
-
|
77
|
-
[].concat(doc.all_data_criteria).concat(doc.source_data_criteria).each do |data_criteria|
|
78
|
-
if (data_criteria.type == :characteristic and !data_criteria.property.nil?)
|
79
|
-
if (codes)
|
80
|
-
value_set = codes[data_criteria.code_list_id]
|
81
|
-
puts "\tno value set for unknown patient characteristic: #{data_criteria.id}" unless value_set
|
82
|
-
else
|
83
|
-
puts "\tno code set to back fill: #{data_criteria.title}"
|
84
|
-
next
|
85
|
-
end
|
86
|
-
|
87
|
-
if (data_criteria.property == :gender)
|
88
|
-
key = value_set.keys[0]
|
89
|
-
data_criteria.value = HQMF::Coded.new('CD','Administrative Sex',value_set[key].first)
|
90
|
-
else
|
91
|
-
data_criteria.inline_code_list = value_set
|
92
|
-
end
|
93
|
-
|
94
|
-
elsif (data_criteria.type == :characteristic)
|
95
|
-
if (codes)
|
96
|
-
value_set = codes[data_criteria.code_list_id]
|
97
|
-
if (value_set)
|
98
|
-
# this is looking for a birthdate characteristic that is set as a generic characteristic but points to a loinc code set
|
99
|
-
if (value_set['LOINC'] and value_set['LOINC'].first == '21112-8')
|
100
|
-
data_criteria.definition = 'patient_characteristic_birthdate'
|
101
|
-
end
|
102
|
-
# this is looking for a gender characteristic that is set as a generic characteristic
|
103
|
-
gender_key = (value_set.keys.select {|set| set == 'Administrative Sex' || set == 'AdministrativeSex'}).first
|
104
|
-
if (gender_key and ['M','F'].include? value_set[gender_key].first)
|
105
|
-
data_criteria.definition = 'patient_characteristic_gender'
|
106
|
-
data_criteria.value = HQMF::Coded.new('CD','Gender',value_set[gender_key].first)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
63
|
|
116
64
|
def self.parse_measure_period(json)
|
117
65
|
|
@@ -29,6 +29,8 @@ module HQMF
|
|
29
29
|
observs = @population_criteria_by_id.select {|key, value| value.type == HQMF::PopulationCriteria::OBSERV}
|
30
30
|
excls = @population_criteria_by_id.select {|key, value| value.type == HQMF::PopulationCriteria::DENEX}
|
31
31
|
denexcs = @population_criteria_by_id.select {|key, value| value.type == HQMF::PopulationCriteria::DENEXCEP}
|
32
|
+
|
33
|
+
stratifications = @population_criteria_by_id.values.select {|value| value.type == HQMF::PopulationCriteria::STRAT}
|
32
34
|
|
33
35
|
if (ipps.size<=1 and denoms.size<=1 and nums.size<=1 and excls.size<=1 and denexcs.size<=1 and msrpopls.size<=1 and observs.size<=1 )
|
34
36
|
sub_measure = {}
|
@@ -70,22 +72,38 @@ module HQMF
|
|
70
72
|
reference = @population_criteria_by_id[reference_id] if reference_id
|
71
73
|
if (reference)
|
72
74
|
criteria = @population_criteria_by_key[sub[reference.type]]
|
73
|
-
value
|
74
|
-
value = nil if (sub[reference.type] != reference.id and criteria.stratification_id.nil?)
|
75
|
+
value = nil if (sub[reference.type] != reference.id)
|
75
76
|
end
|
76
77
|
end
|
77
78
|
end
|
78
79
|
keep << value if (value)
|
79
80
|
end
|
80
81
|
|
81
|
-
|
82
|
+
@sub_measures = keep
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
# add stratifications if we have them
|
87
|
+
if (stratifications.size > 0)
|
88
|
+
strat_subs = []
|
89
|
+
@sub_measures.each do |sub|
|
90
|
+
stratifications.each do |stratification|
|
91
|
+
new_sub = sub.dup
|
92
|
+
new_sub[HQMF::PopulationCriteria::STRAT] = stratification.id
|
93
|
+
new_sub['stratification'] = stratification.hqmf_id
|
94
|
+
strat_subs << new_sub
|
95
|
+
end
|
96
|
+
end
|
97
|
+
@sub_measures.concat strat_subs
|
98
|
+
end
|
99
|
+
|
100
|
+
if (@sub_measures.length > 1)
|
101
|
+
@sub_measures.each_with_index do |sub, i|
|
82
102
|
sub['title'] = "Population #{i+1}"
|
83
103
|
sub['id'] = "Population#{i+1}"
|
84
104
|
end
|
85
|
-
|
86
|
-
@sub_measures = keep
|
87
|
-
|
88
105
|
end
|
106
|
+
|
89
107
|
end
|
90
108
|
|
91
109
|
# source are things like exceptions or exclusions, target are IPP, or denom
|
@@ -151,8 +169,6 @@ module HQMF
|
|
151
169
|
title = population_criteria[:title]
|
152
170
|
|
153
171
|
criteria = HQMF::Converter::SimplePopulationCriteria.new(key, hqmf_id, type, preconditions, title)
|
154
|
-
# mark the 2.0 simple population criteria as a stratification... this allows us to create the cartesian product for this in the populations
|
155
|
-
criteria.stratification_id = population_criteria[:stratification_id]
|
156
172
|
|
157
173
|
@population_criteria_by_id[id] = criteria
|
158
174
|
@population_reference[key] = reference
|
@@ -47,15 +47,19 @@ module HQMF
|
|
47
47
|
# if we reference the measurement period, then we want to check if the reference is to the start or end of the measurement period
|
48
48
|
# if we SBS of the END of the measurement period, we want to convert that to SBE of the measurement period
|
49
49
|
if target_id == HQMF::Document::MEASURE_PERIOD_ID
|
50
|
-
references_start = {'SBS'=>'SBE','SAS'=>'SAE','EBS'=>'EBE','EAS'=>'EAE'}
|
51
|
-
references_end = {'EBE'=>'EBS','EAE'=>'EAS','SBE'=>'SBS','SAE'=>'SAS'}
|
50
|
+
references_start = {'SBS'=>'SBE','SAS'=>'SAE','EBS'=>'EBE','EAS'=>'EAE','SCW'=>'SCWE'}
|
51
|
+
references_end = {'EBE'=>'EBS','EAE'=>'EAS','SBE'=>'SBS','SAE'=>'SAS','ECW'=>'ECWS'}
|
52
52
|
if data_criteria_converter.measure_period_v1_keys[:measure_start] == restriction[:target_id] and references_end[type]
|
53
53
|
# before or after the END of the measurement period START. Convert to before or after the START of the measurement period.
|
54
54
|
# SAE of MPS => SAS of MP
|
55
|
+
# ends concurrent with measurement period START. Convert to concurrent with START of measurement period.
|
56
|
+
# ECW of MPS => ECWS
|
55
57
|
type = references_end[type]
|
56
58
|
elsif data_criteria_converter.measure_period_v1_keys[:measure_end] == restriction[:target_id] and references_start[type]
|
57
59
|
# before or after the START of the measurement period END. Convert to before or after the END of the measurement period.
|
58
60
|
# SBS of MPE => SBE of MP
|
61
|
+
# starts concurrent with measurement period END. Convert to concurrent with END of measurement period.
|
62
|
+
# SCW of MPE => SCWE
|
59
63
|
type = references_start[type]
|
60
64
|
end
|
61
65
|
end
|
@@ -132,6 +136,15 @@ module HQMF
|
|
132
136
|
container = HQMF::Converter::SimpleRestriction.new(operator, nil, [comparison_precondition])
|
133
137
|
else
|
134
138
|
container = HQMF::Converter::SimpleRestriction.new(operator, target_id)
|
139
|
+
# handle transitive restrictions... this is where we are adding a field to a target of a timing restriction
|
140
|
+
if (restrictions && !restrictions.empty? && children.nil?)
|
141
|
+
children = []
|
142
|
+
restrictions.each do |child|
|
143
|
+
comparison_precondition = HQMF::Converter::SimplePrecondition.new(nil,[child],HQMF::Reference.new(target_id),nil, false)
|
144
|
+
comparison_precondition.klass = HQMF::Converter::SimplePrecondition::COMPARISON
|
145
|
+
children << comparison_precondition
|
146
|
+
end
|
147
|
+
end
|
135
148
|
container.preconditions = children
|
136
149
|
end
|
137
150
|
|
@@ -62,7 +62,7 @@ module HQMF
|
|
62
62
|
restriction.converted=true
|
63
63
|
when 'SUBJ'
|
64
64
|
new_data_criteria.field_values ||= {}
|
65
|
-
new_data_criteria.field_values[operator.field_value_key] = operator.value
|
65
|
+
new_data_criteria.field_values[operator.field_value_key] = operator.value || HQMF::AnyValue.new
|
66
66
|
restriction.converted=true
|
67
67
|
else
|
68
68
|
puts "\tOperator is unknown: #{operator.type}"
|
data/lib/hqmf-parser/parser.rb
CHANGED
@@ -4,49 +4,72 @@ module HQMF
|
|
4
4
|
HQMF_VERSION_1 = "1.0"
|
5
5
|
HQMF_VERSION_2 = "2.0"
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
HQMF::Counter.instance.reset()
|
10
|
-
case version
|
11
|
-
when HQMF_VERSION_1
|
12
|
-
puts("\tCodes not passed in, cannot backfill properties like gender") unless codes
|
13
|
-
HQMF::DocumentConverter.convert(HQMF1::Document.new(hqmf_contents).to_json, codes)
|
14
|
-
when HQMF_VERSION_2
|
15
|
-
HQMF2::Document.new(hqmf_contents).to_model
|
16
|
-
else
|
17
|
-
raise "Unsupported HQMF version specified: #{version}"
|
7
|
+
class V2Parser
|
8
|
+
def initialize
|
18
9
|
end
|
10
|
+
|
11
|
+
def parse(xml_contents, codes=nil)
|
12
|
+
HQMF::Counter.instance.reset()
|
13
|
+
HQMF2::Document.new(xml_contents).to_model
|
14
|
+
end
|
15
|
+
|
16
|
+
def parse_fileds(xml_contents)
|
17
|
+
result = {}
|
18
|
+
doc = HQMF2::Document.parse(xml_contents)
|
19
|
+
type = doc.at_xpath('/cda:QualityMeasureDocument/cda:code/@code').value
|
20
|
+
if type == '57024-2'
|
21
|
+
id = doc.at_xpath('cda:QualityMeasureDocument/cda:id/@extension', HQMF2::Document::NAMESPACES).value.upcase
|
22
|
+
set_id = doc.at_xpath('cda:QualityMeasureDocument/cda:setId/@extension').value.upcase
|
23
|
+
version_number = doc.at_xpath('cda:QualityMeasureDocument/cda:versionNumber/@value').value.to_i
|
24
|
+
title = doc.at_xpath('cda:QualityMeasureDocument/cda:title/@value').inner_text
|
25
|
+
description = doc.at_xpath('cda:QualityMeasureDocument/cda:text/@value').inner_text
|
26
|
+
result= {'id' => id, 'set_id' => set_id, 'version' => version_number, 'title' => title, 'description' => description}
|
27
|
+
end
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
def version
|
32
|
+
HQMF_VERSION_2
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.valid?(xml_contents)
|
36
|
+
doc = HQMF2::Document.parse(xml_contents)
|
37
|
+
!doc.at_xpath("/cda:QualityMeasureDocument/cda:typeId[@root='2.16.840.1.113883.1.3' and @extension='POQM_MT000001UV03']").nil?
|
38
|
+
end
|
39
|
+
|
19
40
|
end
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
41
|
+
|
42
|
+
class V1Parser
|
43
|
+
|
44
|
+
def parse(xml_contents, codes=nil)
|
45
|
+
HQMF::Counter.instance.reset()
|
46
|
+
HQMF::DocumentConverter.convert(HQMF1::Document.new(xml_contents).to_json, codes)
|
47
|
+
end
|
48
|
+
|
49
|
+
def version
|
50
|
+
HQMF_VERSION_1
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_fields(xml_contents)
|
54
|
+
doc = HQMF1::Document.parse(xml_contents)
|
55
|
+
type = doc.at_xpath('//cda:code/@code').value
|
56
|
+
result = {}
|
57
|
+
if type == '57024-2'
|
58
|
+
id = doc.at_xpath('//cda:id/@root').value.upcase
|
59
|
+
set_id = doc.at_xpath('//cda:setId/@root').value.upcase
|
60
|
+
version_number = doc.at_xpath('//cda:versionNumber/@value').value.to_i
|
61
|
+
title = doc.at_xpath('cda:QualityMeasureDocument/cda:title').inner_text
|
62
|
+
description = doc.at_xpath('cda:QualityMeasureDocument/cda:text').inner_text
|
63
|
+
result = {'id' => id, 'set_id' => set_id, 'version' => version_number, 'title' => title, 'description' => description}
|
64
|
+
end
|
65
|
+
result
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.valid?(xml_contents)
|
69
|
+
doc = HQMF1::Document.parse(xml_contents)
|
70
|
+
!doc.at_xpath("/cda:QualityMeasureDocument/cda:typeId[@root='2.16.840.1.113883.1.3' and @extension='POQM_HD000001']").nil?
|
71
|
+
end
|
72
|
+
|
50
73
|
end
|
51
74
|
|
52
75
|
end
|