cqm-validators 0.1.0 → 2.0.2
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.
- checksums.yaml +5 -5
- data/.github/PULL_REQUEST_TEMPLATE.md +23 -0
- data/.gitignore +3 -1
- data/.overcommit.yml +18 -0
- data/.rubocop.yml +68 -0
- data/.simplecov +12 -0
- data/.travis.yml +20 -0
- data/Gemfile +11 -3
- data/README.md +20 -6
- data/Rakefile +8 -6
- data/config/mongoid.yml +6 -0
- data/cqm_validators.gemspec +23 -14
- data/lib/base_validator.rb +20 -20
- data/lib/cqm_validators.rb +4 -2
- data/lib/cqm_validators/version.rb +3 -1
- data/lib/data_validator.rb +74 -79
- data/lib/measure_validator.rb +104 -107
- data/lib/performance_rate_validator.rb +43 -63
- data/lib/qrda_qdm_template_validator.rb +164 -311
- data/lib/reported_result_extractor.rb +137 -139
- data/lib/schema_validator.rb +20 -19
- data/lib/schematron/c_processor.rb +19 -19
- data/lib/schematron/java_processor.rb +66 -68
- data/lib/schematron/qrda/{cat_1_r4/HL7 QRDA Category I STU 4.sch → cat_1_r5_1/HL7 QRDA Category I STU 5.1.sch } +1684 -2082
- data/lib/schematron/qrda/{cat_1_r3_1 → cat_1_r5_1}/voc.xml +1223 -1228
- data/lib/schematron_validator.rb +31 -32
- data/lib/validation_error.rb +11 -9
- data/lib/validators.rb +40 -106
- data/notice.md +9 -0
- metadata +97 -36
- data/lib/schematron/qrda/cat_1/HL7_CDAR2_QRDA_Category_I_2_12_16.sch +0 -4693
- data/lib/schematron/qrda/cat_1/voc.xml +0 -1177
- data/lib/schematron/qrda/cat_1_r2/QRDA Category I Release 2.sch +0 -4069
- data/lib/schematron/qrda/cat_1_r2/voc.xml +0 -1065
- data/lib/schematron/qrda/cat_1_r3_1/HL7 QRDA Category I STU 3.1.sch +0 -3573
- data/lib/schematron/qrda/cat_1_r3_1/HL7 QRDA Category III STU 1.1.sch +0 -464
- data/lib/schematron/qrda/cat_1_r3_1/QRDA Category I STU Release 3.1.sch +0 -5394
- data/lib/schematron/qrda/cat_1_r4/voc.xml +0 -1186
- data/lib/schematron/qrda/cat_3/QRDA Category III.sch +0 -675
- data/lib/schematron/qrda/cat_3/voc.xml +0 -21
- data/lib/schematron/qrda/cat_3_r1_1/HL7 QRDA Category III STU 1.1.sch +0 -528
- data/lib/schematron/qrda/cat_3_r1_1/voc.xml +0 -8
- data/lib/schematron/qrda/cat_3_r2/HL7 QRDA Category III STU 2.sch +0 -677
- data/lib/schematron/qrda/cat_3_r2/voc.xml +0 -1186
data/lib/measure_validator.rb
CHANGED
@@ -1,130 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CqmValidators
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
def validate(file, data={})
|
4
|
+
class MeasureValidator
|
5
|
+
include BaseValidator
|
6
|
+
|
7
|
+
def initialize(template_oid)
|
8
|
+
@template_oid = template_oid
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate(file, data = {})
|
11
12
|
@errors = []
|
12
13
|
@doc = get_document(file)
|
13
14
|
@doc.root.add_namespace_definition('cda', 'urn:hl7-org:v3')
|
14
|
-
measure_ids =
|
15
|
+
measure_ids = CQM::Measure.pluck(:hqmf_id)
|
15
16
|
doc_measure_ids = @doc.xpath(measure_selector).map(&:value).map(&:upcase)
|
16
|
-
#list of all of the set ids in the QRDA
|
17
|
+
# list of all of the set ids in the QRDA
|
17
18
|
doc_neutral_ids = @doc.xpath(neutral_measure_selector).map(&:value).map(&:upcase).sort
|
18
|
-
#list of all of the setids in the QRDA that are also in the bundle, includes duplicates if code appears twice in document
|
19
|
-
bundle_neutral_ids =
|
19
|
+
# list of all of the setids in the QRDA that are also in the bundle, includes duplicates if code appears twice in document
|
20
|
+
bundle_neutral_ids = CQM::Measure.distinct(:hqmf_set_id)
|
20
21
|
doc_bundle_neutral_ids = doc_neutral_ids - (doc_neutral_ids - bundle_neutral_ids)
|
21
22
|
validate_measure_ids(doc_measure_ids, measure_ids, data)
|
22
23
|
validate_set_ids(doc_neutral_ids, doc_bundle_neutral_ids, data)
|
23
|
-
if validate_no_repeating_measure_population_ids(data)
|
24
|
-
|
25
|
-
end
|
26
|
-
|
24
|
+
validate_measure_ids_set_ids_usage(doc_bundle_neutral_ids, doc_measure_ids, data) if validate_no_repeating_measure_population_ids(data)
|
25
|
+
|
27
26
|
@errors
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# returns true if there are no repeating measures, check to see that the measure id usage is correct
|
32
|
+
def validate_no_repeating_measure_population_ids(data = {})
|
33
|
+
no_duplicate_measures = true
|
34
|
+
doc_population_ids = @doc.xpath(measure_population_selector).map(&:value).map(&:upcase).sort
|
35
|
+
duplicates = doc_population_ids.group_by { |e| e }.select { |_k, v| v.size > 1 }.map(&:first)
|
36
|
+
duplicates.each do |duplicate|
|
37
|
+
begin
|
38
|
+
measure_id = @doc.xpath(find_measure_node_for_population(duplicate)).at_xpath("cda:reference/cda:externalDocument/cda:id[./@root='2.16.840.1.113883.4.738']/@extension")
|
39
|
+
@errors << build_error("Population #{duplicate} for Measure #{measure_id.value} reported more than once", '/', data[:file_name])
|
40
|
+
rescue
|
41
|
+
@errors << build_error("Population #{duplicate} for reported more than once", '/', data[:file_name])
|
28
42
|
end
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
doc_population_ids = @doc.xpath(measure_population_selector).map(&:value).map(&:upcase).sort
|
36
|
-
duplicates = doc_population_ids.group_by{ |e| e }.select { |k, v| v.size > 1 }.map(&:first)
|
37
|
-
duplicates.each do |duplicate|
|
38
|
-
begin
|
39
|
-
measureId = @doc.xpath(find_measure_node_for_population(duplicate)).at_xpath("cda:reference/cda:externalDocument/cda:id[./@root='2.16.840.1.113883.4.738']/@extension")
|
40
|
-
@errors << build_error("Population #{duplicate} for Measure #{measureId.value} reported more than once", "/", data[:file_name])
|
41
|
-
rescue
|
42
|
-
@errors << build_error("Population #{duplicate} for reported more than once", "/", data[:file_name])
|
43
|
-
end
|
44
|
-
noDuplicateMeasures = false
|
45
|
-
end
|
46
|
-
return noDuplicateMeasures
|
47
|
-
end
|
48
|
-
|
49
|
-
def validate_measure_ids(doc_measure_ids, measure_ids, data={})
|
43
|
+
no_duplicate_measures = false
|
44
|
+
end
|
45
|
+
no_duplicate_measures
|
46
|
+
end
|
47
|
+
|
48
|
+
def validate_measure_ids(doc_measure_ids, measure_ids, data = {})
|
50
49
|
(doc_measure_ids - measure_ids).map do |hqmf_id|
|
51
|
-
@errors << build_error("Invalid HQMF ID Found: #{hqmf_id}",
|
50
|
+
@errors << build_error("Invalid HQMF ID Found: #{hqmf_id}", '/', data[:file_name])
|
52
51
|
end
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
#an error will be returned for all of the setids that are in the QRDA that aren't in the bundle
|
52
|
+
end
|
53
|
+
|
54
|
+
def validate_set_ids(doc_neutral_ids, doc_bundle_neutral_ids, data = {})
|
55
|
+
# an error will be returned for all of the setids that are in the QRDA that aren't in the bundle
|
57
56
|
(doc_neutral_ids - doc_bundle_neutral_ids).map do |hqmf_set_id|
|
58
|
-
@errors << build_error("Invalid HQMF Set ID Found: #{hqmf_set_id}",
|
57
|
+
@errors << build_error("Invalid HQMF Set ID Found: #{hqmf_set_id}", '/', data[:file_name])
|
59
58
|
end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
#for each of the setIds that are in the bundle, check that they are for the correct measure id
|
59
|
+
end
|
60
|
+
|
61
|
+
# does not work if the same measure is reported more than once, nested under the repeating measures test
|
62
|
+
def validate_measure_ids_set_ids_usage(doc_bundle_neutral_ids, doc_measure_ids, data = {})
|
63
|
+
# for each of the setIds that are in the bundle, check that they are for the correct measure id
|
65
64
|
entries_start_position = @doc.xpath(first_entry)
|
66
|
-
previous =
|
65
|
+
previous = ''
|
67
66
|
index = 1
|
68
67
|
doc_bundle_neutral_ids.each do |hqmf_set_id|
|
69
|
-
#selects the measure id that is in the same entry as the set id
|
70
|
-
#iterates through multiple instances of the same setId
|
71
|
-
if previous == hqmf_set_id
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
measure_id_entry = doc_measure_ids[(@doc.xpath(location_of_set_id(hqmf_set_id,index)) - entries_start_position)]
|
68
|
+
# selects the measure id that is in the same entry as the set id
|
69
|
+
# iterates through multiple instances of the same setId
|
70
|
+
index = if previous == hqmf_set_id
|
71
|
+
index + 1
|
72
|
+
else
|
73
|
+
1
|
74
|
+
end
|
75
|
+
measure_id_entry = doc_measure_ids[(@doc.xpath(location_of_set_id(hqmf_set_id, index)) - entries_start_position)]
|
77
76
|
previous = hqmf_set_id
|
78
|
-
#queries database to see if there is a measure with the combindation of setId and measureId
|
79
|
-
if
|
80
|
-
@errors << build_error("Invalid HQMF Set ID Found: #{hqmf_set_id} for HQMF ID: #{measure_id_entry}",
|
77
|
+
# queries database to see if there is a measure with the combindation of setId and measureId
|
78
|
+
if CQM::Measure.where(hqmf_id: measure_id_entry, hqmf_set_id: hqmf_set_id).empty?
|
79
|
+
@errors << build_error("Invalid HQMF Set ID Found: #{hqmf_set_id} for HQMF ID: #{measure_id_entry}", '/', data[:file_name])
|
81
80
|
end
|
82
81
|
end
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
"count(//cda:entry[cda:organizer[./cda:templateId[@root='#{@template_oid}']]"
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
"count(//cda:entry[cda:organizer[./cda:templateId[@root='#{@template_oid}']]"
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
"/cda:
|
116
|
-
"/cda:
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
"/cda:
|
123
|
-
"/cda:
|
124
|
-
"
|
125
|
-
"/cda:externalObservation/cda:id[@root[contains(translate(.,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLOMNOPQRSTUVWXYZ')" +
|
82
|
+
end
|
83
|
+
|
84
|
+
def measure_selector
|
85
|
+
'/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section/cda:entry' \
|
86
|
+
"/cda:organizer[./cda:templateId[@root='#{@template_oid}']]/cda:reference[@typeCode='REFR']" \
|
87
|
+
"/cda:externalDocument[@classCode='DOC']/cda:id[@root='2.16.840.1.113883.4.738']/@extension"
|
88
|
+
end
|
89
|
+
|
90
|
+
# finds all of the setIds in the QRDA document
|
91
|
+
def neutral_measure_selector
|
92
|
+
'/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section/cda:entry' \
|
93
|
+
"/cda:organizer[./cda:templateId[@root='#{@template_oid}']]/cda:reference[@typeCode='REFR']" \
|
94
|
+
"/cda:externalDocument[@classCode='DOC']/cda:setId/@root"
|
95
|
+
end
|
96
|
+
|
97
|
+
# finds the node index of the first entry element in the measure template
|
98
|
+
def first_entry
|
99
|
+
"count(//cda:entry[cda:organizer[./cda:templateId[@root='#{@template_oid}']]" \
|
100
|
+
"/cda:reference[@typeCode='REFR']/cda:externalDocument[@classCode='DOC']" \
|
101
|
+
"/cda:id[@root='2.16.840.1.113883.4.738']][1]/preceding-sibling::*)+1"
|
102
|
+
end
|
103
|
+
|
104
|
+
# finds the node index of the extry that the specified setId is in, index is used if the same setId appears twice
|
105
|
+
def location_of_set_id(set_id, index)
|
106
|
+
"count(//cda:entry[cda:organizer[./cda:templateId[@root='#{@template_oid}']]" \
|
107
|
+
"/cda:reference[@typeCode='REFR']/cda:externalDocument[@classCode='DOC']" \
|
108
|
+
"/cda:setId[@root[contains(translate(.,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLOMNOPQRSTUVWXYZ')" \
|
109
|
+
",'#{set_id}')]]][#{index}]/preceding-sibling::*)+1"
|
110
|
+
end
|
111
|
+
|
112
|
+
def measure_population_selector
|
113
|
+
'/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section/cda:entry' \
|
114
|
+
"/cda:organizer[./cda:templateId[@root='2.16.840.1.113883.10.20.27.3.1']]/cda:component" \
|
115
|
+
"/cda:observation[./cda:templateId[@root='2.16.840.1.113883.10.20.27.3.5']]/cda:reference" \
|
116
|
+
'/cda:externalObservation/cda:id/@root'
|
117
|
+
end
|
118
|
+
|
119
|
+
def find_measure_node_for_population(id)
|
120
|
+
'/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section/cda:entry' \
|
121
|
+
"/cda:organizer[ ./cda:templateId[@root='2.16.840.1.113883.10.20.27.3.1']" \
|
122
|
+
"and ./cda:component/cda:observation[./cda:templateId[@root='2.16.840.1.113883.10.20.27.3.5']]/cda:reference" \
|
123
|
+
"/cda:externalObservation/cda:id[@root[contains(translate(.,'abcdefghijklmnopqrstuvwxyz','ABCDEFGHIJKLOMNOPQRSTUVWXYZ')" \
|
126
124
|
",'#{id.upcase}')]]]"
|
127
|
-
|
128
|
-
|
125
|
+
end
|
126
|
+
end
|
129
127
|
end
|
130
|
-
|
@@ -1,92 +1,72 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'reported_result_extractor'
|
2
4
|
module CqmValidators
|
3
5
|
class PerformanceRateValidator
|
4
6
|
include ReportedResultExtractor
|
5
7
|
include BaseValidator
|
6
|
-
|
7
|
-
|
8
|
-
def initialize()
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
9
|
+
def initialize; end
|
13
10
|
|
14
11
|
# Nothing to see here - Move along
|
15
12
|
def validate(file, data = {})
|
16
|
-
|
13
|
+
errors_list = []
|
17
14
|
document = get_document(file)
|
18
|
-
|
15
|
+
document.root.add_namespace_definition('cda', 'urn:hl7-org:v3')
|
16
|
+
# grab measure IDs from QRDA file
|
19
17
|
measure_ids = document.xpath(measure_selector).map(&:value).map(&:upcase)
|
20
18
|
measure_ids.each do |measure_id|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
errorsList << error
|
30
|
-
end
|
31
|
-
end
|
19
|
+
measure = CQM::Measure.where(hqmf_id: measure_id).first
|
20
|
+
measure.population_sets.each do |population_set|
|
21
|
+
reported_result, = extract_results_by_ids(measure, population_set.population_set_id, document)
|
22
|
+
# only check performace rate when there is one
|
23
|
+
next if reported_result['PR'].nil?
|
24
|
+
|
25
|
+
error = check_performance_rates(reported_result, population_set, measure.hqmf_id, data)
|
26
|
+
errors_list << error unless error.nil?
|
32
27
|
end
|
33
28
|
end
|
34
|
-
|
29
|
+
errors_list
|
35
30
|
end
|
36
31
|
|
37
32
|
def calculate_performance_rates(reported_result)
|
38
|
-
#Just in case a measure does not report these populations
|
33
|
+
# Just in case a measure does not report these populations
|
39
34
|
denex = 0
|
40
35
|
denexcep = 0
|
41
36
|
denom = 0
|
42
37
|
numer = 0
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
denom = denom - denex - denexcep
|
56
|
-
pr = 0
|
57
|
-
if denom == 0
|
58
|
-
pr = "NA"
|
59
|
-
else
|
60
|
-
pr = numer / denom.to_f
|
61
|
-
end
|
62
|
-
return pr
|
38
|
+
denex = reported_result['DENEX'] unless reported_result['DENEX'].nil?
|
39
|
+
denexcep = reported_result['DENEXCEP'] unless reported_result['DENEXCEP'].nil?
|
40
|
+
denom = reported_result['DENOM'] unless reported_result['DENOM'].nil?
|
41
|
+
numer = reported_result['NUMER'] unless reported_result['NUMER'].nil?
|
42
|
+
denom = denom - denex - denexcep
|
43
|
+
pr = if denom.zero?
|
44
|
+
'NA'
|
45
|
+
else
|
46
|
+
numer / denom.to_f
|
47
|
+
end
|
48
|
+
pr
|
63
49
|
end
|
64
50
|
|
65
|
-
def check_performance_rates(reported_result,
|
51
|
+
def check_performance_rates(reported_result, population_set, _measure_id, data = {})
|
66
52
|
expected = calculate_performance_rates(reported_result)
|
67
|
-
|
68
|
-
if expected ==
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
return build_error("Reported Performance Rate SHALL not have a precision greater than .000001 ", "/", data[:file_name])
|
78
|
-
elsif (reported_result['PR']['value'].to_f - expected.round(6)).abs > 0.0000001
|
79
|
-
return build_error("Reported Performance Rate of #{reported_result['PR']['value']} for Numerator #{_ids['NUMER']} does not match expected value of #{expected.round(6)}.", "/", data[:file_name])
|
80
|
-
end
|
81
|
-
end
|
53
|
+
numer_id = population_set.populations.NUMER.hqmf_id
|
54
|
+
if expected == 'NA' && reported_result['PR']['nullFlavor'] != 'NA'
|
55
|
+
build_error("Reported Performance Rate for Numerator #{numer_id} should be NA", '/', data[:file_name])
|
56
|
+
elsif expected != 'NA' && reported_result['PR']['nullFlavor'] == 'NA'
|
57
|
+
build_error("Reported Performance Rate for Numerator #{numer_id} should not be NA", '/', data[:file_name])
|
58
|
+
elsif expected != 'NA' && reported_result['PR']['value'].split('.', 2).last.size > 6
|
59
|
+
build_error('Reported Performance Rate SHALL not have a precision greater than .000001 ', '/', data[:file_name])
|
60
|
+
elsif expected != 'NA' && (reported_result['PR']['value'].to_f - expected.round(6)).abs > 0.0000001
|
61
|
+
build_error("Reported Performance Rate of #{reported_result['PR']['value']} for Numerator #{numer_id} does not match expected"\
|
62
|
+
" value of #{expected.round(6)}.", '/', data[:file_name])
|
82
63
|
end
|
83
64
|
end
|
84
65
|
|
85
66
|
def measure_selector
|
86
|
-
|
87
|
-
|
67
|
+
'/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section/cda:entry' \
|
68
|
+
"/cda:organizer[./cda:templateId[@root='2.16.840.1.113883.10.20.27.3.1']]/cda:reference[@typeCode='REFR']" \
|
88
69
|
"/cda:externalDocument[@classCode='DOC']/cda:id[@root='2.16.840.1.113883.4.738']/@extension"
|
89
70
|
end
|
90
|
-
|
91
|
-
|
92
|
-
end
|
71
|
+
end
|
72
|
+
end
|
@@ -1,320 +1,173 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module CqmValidators
|
2
|
-
|
3
|
-
|
4
|
+
class QrdaQdmTemplateValidator
|
5
|
+
include BaseValidator
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
'2.16.840.1.113883.10.20.24.3.59' => '2016-02-01',
|
127
|
-
'2.16.840.1.113883.10.20.24.3.55' => nil,
|
128
|
-
'2.16.840.1.113883.10.20.24.3.60' => '2016-02-01',
|
129
|
-
'2.16.840.1.113883.10.20.24.3.61' => '2016-02-01',
|
130
|
-
'2.16.840.1.113883.10.20.24.3.62' => '2016-02-01',
|
131
|
-
'2.16.840.1.113883.10.20.24.3.63' => '2016-02-01',
|
132
|
-
'2.16.840.1.113883.10.20.24.3.64' => '2016-02-01',
|
133
|
-
'2.16.840.1.113883.10.20.24.3.65' => '2016-02-01',
|
134
|
-
'2.16.840.1.113883.10.20.24.3.67' => '2016-02-01',
|
135
|
-
'2.16.840.1.113883.10.20.24.3.69' => '2016-02-01',
|
136
|
-
'2.16.840.1.113883.10.20.24.3.75' => '2016-02-01',
|
137
|
-
'2.16.840.1.113883.10.20.24.3.138' => nil,
|
138
|
-
'2.16.840.1.113883.10.20.24.3.141' => nil,
|
139
|
-
'2.16.840.1.113883.10.20.24.3.142' => nil
|
140
|
-
}
|
141
|
-
# Hash of templateIds/extensions specified in the Patient Data Section QDM for QRDA R4
|
142
|
-
QRDA_CAT_1_R4_QDM_OIDS = {
|
143
|
-
'2.16.840.1.113883.10.20.24.3.1' => '2016-02-01',
|
144
|
-
'2.16.840.1.113883.10.20.24.3.2' => '2016-02-01',
|
145
|
-
'2.16.840.1.113883.10.20.24.3.3' => '2016-02-01',
|
146
|
-
'2.16.840.1.113883.10.20.24.3.4' => '2016-02-01',
|
147
|
-
'2.16.840.1.113883.10.20.24.3.5' => '2016-02-01',
|
148
|
-
'2.16.840.1.113883.10.20.24.3.6' => '2016-02-01',
|
149
|
-
'2.16.840.1.113883.10.20.24.3.7' => '2016-02-01',
|
150
|
-
'2.16.840.1.113883.10.20.24.3.8' => '2016-02-01',
|
151
|
-
'2.16.840.1.113883.10.20.24.3.130' => nil,
|
152
|
-
'2.16.840.1.113883.10.20.24.3.131' => nil,
|
153
|
-
'2.16.840.1.113883.10.20.24.3.137' => '2016-08-01',
|
154
|
-
'2.16.840.1.113883.10.20.24.3.15' => '2016-02-01',
|
155
|
-
'2.16.840.1.113883.10.20.24.3.16' => '2016-02-01',
|
156
|
-
'2.16.840.1.113883.10.20.24.3.17' => '2016-02-01',
|
157
|
-
'2.16.840.1.113883.10.20.24.3.18' => '2016-02-01',
|
158
|
-
'2.16.840.1.113883.10.20.24.3.19' => '2016-02-01',
|
159
|
-
'2.16.840.1.113883.10.20.24.3.105' => '2016-02-01',
|
160
|
-
'2.16.840.1.113883.10.20.24.3.21' => '2016-02-01',
|
161
|
-
'2.16.840.1.113883.10.20.24.3.132' => nil,
|
162
|
-
'2.16.840.1.113883.10.20.24.3.133' => nil,
|
163
|
-
'2.16.840.1.113883.10.20.24.3.134' => nil,
|
164
|
-
'2.16.840.1.113883.10.20.24.3.12' => '2016-02-01',
|
165
|
-
'2.16.840.1.113883.10.20.24.3.140' => nil,
|
166
|
-
'2.16.840.1.113883.10.20.24.3.143' => nil,
|
167
|
-
'2.16.840.1.113883.10.20.24.3.29' => '2016-02-01',
|
168
|
-
'2.16.840.1.113883.10.20.24.3.30' => '2016-02-01',
|
169
|
-
'2.16.840.1.113883.10.20.24.3.31' => '2016-02-01',
|
170
|
-
'2.16.840.1.113883.10.20.24.3.32' => '2016-02-01',
|
171
|
-
'2.16.840.1.113883.10.20.24.3.33' => '2016-02-01',
|
172
|
-
'2.16.840.1.113883.10.20.24.3.35' => '2016-02-01',
|
173
|
-
'2.16.840.1.113883.10.20.24.3.36' => '2016-02-01',
|
174
|
-
'2.16.840.1.113883.10.20.24.3.37' => '2016-02-01',
|
175
|
-
'2.16.840.1.113883.10.20.24.3.38' => '2016-02-01',
|
176
|
-
'2.16.840.1.113883.10.20.24.3.39' => '2016-02-01',
|
177
|
-
'2.16.840.1.113883.10.20.24.3.41' => '2016-02-01',
|
178
|
-
'2.16.840.1.113883.10.20.24.3.42' => '2016-02-01',
|
179
|
-
'2.16.840.1.113883.10.20.24.3.43' => '2016-02-01',
|
180
|
-
'2.16.840.1.113883.10.20.24.3.44' => '2016-02-01',
|
181
|
-
'2.16.840.1.113883.10.20.24.3.139' => nil,
|
182
|
-
'2.16.840.1.113883.10.20.24.3.46' => '2016-02-01',
|
183
|
-
'2.16.840.1.113883.10.20.24.3.47' => '2016-02-01',
|
184
|
-
'2.16.840.1.113883.10.20.24.3.48' => '2016-02-01',
|
185
|
-
'2.16.840.1.113883.10.20.24.3.51' => '2016-02-01',
|
186
|
-
'2.16.840.1.113883.10.20.24.3.54' => '2016-02-01',
|
187
|
-
'2.16.840.1.113883.10.20.24.3.103' => '2016-02-01',
|
188
|
-
'2.16.840.1.113883.10.20.24.3.58' => '2016-02-01',
|
189
|
-
'2.16.840.1.113883.10.20.24.3.59' => '2016-02-01',
|
190
|
-
'2.16.840.1.113883.10.20.24.3.55' => nil,
|
191
|
-
'2.16.840.1.113883.10.20.24.3.60' => '2016-02-01',
|
192
|
-
'2.16.840.1.113883.10.20.24.3.61' => '2016-02-01',
|
193
|
-
'2.16.840.1.113883.10.20.24.3.62' => '2016-02-01',
|
194
|
-
'2.16.840.1.113883.10.20.24.3.63' => '2016-02-01',
|
195
|
-
'2.16.840.1.113883.10.20.24.3.64' => '2016-02-01',
|
196
|
-
'2.16.840.1.113883.10.20.24.3.65' => '2016-02-01',
|
197
|
-
'2.16.840.1.113883.10.20.24.3.67' => '2016-02-01',
|
198
|
-
'2.16.840.1.113883.10.20.24.3.75' => '2016-02-01',
|
199
|
-
'2.16.840.1.113883.10.20.24.3.138' => '2016-08-01',
|
200
|
-
'2.16.840.1.113883.10.20.24.3.141' => nil,
|
201
|
-
'2.16.840.1.113883.10.20.24.3.142' => nil,
|
202
|
-
'2.16.840.1.113883.10.20.24.3.144' => '2016-08-01',
|
203
|
-
'2.16.840.1.113883.10.20.24.3.145' => '2016-08-01'
|
204
|
-
}
|
205
|
-
# Hash of templateIds/extensions specified in the Patient Data Section QDM for QRDA R4
|
206
|
-
QRDA_CAT_1_R5_QDM_OIDS = {
|
207
|
-
'2.16.840.1.113883.10.20.24.3.1' => '2017-08-01',
|
208
|
-
'2.16.840.1.113883.10.20.24.3.2' => '2017-08-01',
|
209
|
-
'2.16.840.1.113883.10.20.24.3.3' => '2017-08-01',
|
210
|
-
'2.16.840.1.113883.10.20.24.3.4' => '2017-08-01',
|
211
|
-
# '2.16.840.1.113883.10.20.24.3.5' => '2016-02-01', Removed
|
212
|
-
# '2.16.840.1.113883.10.20.24.3.6' => '2016-02-01', Removed
|
213
|
-
'2.16.840.1.113883.10.20.24.3.7' => '2017-08-01',
|
214
|
-
# '2.16.840.1.113883.10.20.24.3.8' => '2016-02-01',
|
215
|
-
'2.16.840.1.113883.10.20.24.3.130' => '2017-08-01',
|
216
|
-
'2.16.840.1.113883.10.20.24.3.131' => '2017-08-01',
|
217
|
-
'2.16.840.1.113883.10.20.24.3.137' => '2017-08-01',
|
218
|
-
# '2.16.840.1.113883.10.20.24.3.15' => '2016-02-01', Removed
|
219
|
-
# '2.16.840.1.113883.10.20.24.3.16' => '2016-02-01', Removed
|
220
|
-
'2.16.840.1.113883.10.20.24.3.17' => '2017-08-01',
|
221
|
-
'2.16.840.1.113883.10.20.24.3.18' => '2017-08-01',
|
222
|
-
'2.16.840.1.113883.10.20.24.3.19' => '2017-08-01',
|
223
|
-
'2.16.840.1.113883.10.20.24.3.105' => '2016-02-01',
|
224
|
-
# '2.16.840.1.113883.10.20.24.3.21' => '2016-02-01', Removed
|
225
|
-
'2.16.840.1.113883.10.20.24.3.132' => '2017-08-01',
|
226
|
-
'2.16.840.1.113883.10.20.24.3.133' => '2017-08-01',
|
227
|
-
'2.16.840.1.113883.10.20.24.3.134' => '2017-08-01',
|
228
|
-
'2.16.840.1.113883.10.20.24.3.12' => '2017-08-01',
|
229
|
-
'2.16.840.1.113883.10.20.24.3.140' => '2017-08-01',
|
230
|
-
'2.16.840.1.113883.10.20.24.3.143' => '2017-08-01',
|
231
|
-
# '2.16.840.1.113883.10.20.24.3.29' => '2016-02-01', Removed
|
232
|
-
# '2.16.840.1.113883.10.20.24.3.30' => '2016-02-01', Removed
|
233
|
-
'2.16.840.1.113883.10.20.24.3.31' => '2017-08-01',
|
234
|
-
'2.16.840.1.113883.10.20.24.3.32' => '2017-08-01',
|
235
|
-
'2.16.840.1.113883.10.20.24.3.33' => '2017-08-01',
|
236
|
-
# '2.16.840.1.113883.10.20.24.3.35' => '2016-02-01', Removed
|
237
|
-
# '2.16.840.1.113883.10.20.24.3.36' => '2016-02-01', Removed
|
238
|
-
'2.16.840.1.113883.10.20.24.3.37' => '2017-08-01',
|
239
|
-
'2.16.840.1.113883.10.20.24.3.38' => '2017-08-01',
|
240
|
-
'2.16.840.1.113883.10.20.24.3.39' => '2017-08-01',
|
241
|
-
'2.16.840.1.113883.10.20.24.3.41' => '2017-08-01',
|
242
|
-
'2.16.840.1.113883.10.20.24.3.42' => '2017-08-01',
|
243
|
-
# '2.16.840.1.113883.10.20.24.3.43' => '2016-02-01', Removed
|
244
|
-
# '2.16.840.1.113883.10.20.24.3.44' => '2016-02-01', Removed
|
245
|
-
'2.16.840.1.113883.10.20.24.3.139' => '2017-08-01',
|
246
|
-
# '2.16.840.1.113883.10.20.24.3.46' => '2016-02-01', Removed
|
247
|
-
'2.16.840.1.113883.10.20.24.3.47' => '2017-08-01',
|
248
|
-
'2.16.840.1.113883.10.20.24.3.48' => '2017-08-01',
|
249
|
-
'2.16.840.1.113883.10.20.24.3.51' => '2017-08-01',
|
250
|
-
'2.16.840.1.113883.10.20.24.3.54' => '2016-02-01',
|
251
|
-
'2.16.840.1.113883.10.20.24.3.103' => '2017-08-01',
|
252
|
-
'2.16.840.1.113883.10.20.24.3.58' => '2017-08-01',
|
253
|
-
'2.16.840.1.113883.10.20.24.3.59' => '2017-08-01',
|
254
|
-
'2.16.840.1.113883.10.20.24.3.55' => nil,
|
255
|
-
'2.16.840.1.113883.10.20.24.3.60' => '2017-08-01',
|
256
|
-
# '2.16.840.1.113883.10.20.24.3.61' => '2016-02-01', Removed
|
257
|
-
# '2.16.840.1.113883.10.20.24.3.62' => '2016-02-01', Removed
|
258
|
-
'2.16.840.1.113883.10.20.24.3.63' => '2017-08-01',
|
259
|
-
'2.16.840.1.113883.10.20.24.3.64' => '2017-08-01',
|
260
|
-
'2.16.840.1.113883.10.20.24.3.65' => '2017-08-01',
|
261
|
-
'2.16.840.1.113883.10.20.24.3.67' => '2017-08-01',
|
262
|
-
'2.16.840.1.113883.10.20.24.3.75' => '2017-08-01',
|
263
|
-
'2.16.840.1.113883.10.20.24.3.138' => '2017-08-01',
|
264
|
-
# '2.16.840.1.113883.10.20.24.3.141' => nil, Removed
|
265
|
-
# '2.16.840.1.113883.10.20.24.3.142' => nil, Removed
|
266
|
-
'2.16.840.1.113883.10.20.24.3.144' => '2017-08-01',
|
267
|
-
'2.16.840.1.113883.10.20.24.3.145' => '2017-08-01',
|
268
|
-
'2.16.840.1.113883.10.20.24.3.146' => '2017-08-01',
|
269
|
-
'2.16.840.1.113883.10.20.24.3.147' => '2017-08-01',
|
270
|
-
'2.16.840.1.113883.10.20.24.3.114' => '2017-08-01',
|
271
|
-
'2.16.840.1.113883.10.20.24.3.154' => '2017-08-01'
|
272
|
-
}
|
273
|
-
|
274
|
-
def initialize(qrda_version)
|
275
|
-
@name = 'QRDA QDM Template Validator'
|
276
|
-
@templateshash = case qrda_version
|
277
|
-
when 'r3' then QRDA_CAT_1_R3_QDM_OIDS
|
278
|
-
when 'r3_1' then QRDA_CAT_1_R3_1_QDM_OIDS
|
279
|
-
when 'r4' then QRDA_CAT_1_R4_QDM_OIDS
|
280
|
-
when 'r5' then QRDA_CAT_1_R5_QDM_OIDS
|
281
|
-
end
|
282
|
-
end
|
7
|
+
# Hash of templateIds/extensions specified in the Patient Data Section QDM for QRDA R5
|
8
|
+
QRDA_CAT_1_R5_QDM_OIDS = {
|
9
|
+
'2.16.840.1.113883.10.20.24.3.1' => '2017-08-01',
|
10
|
+
'2.16.840.1.113883.10.20.24.3.2' => '2017-08-01',
|
11
|
+
'2.16.840.1.113883.10.20.24.3.3' => '2017-08-01',
|
12
|
+
'2.16.840.1.113883.10.20.24.3.4' => '2017-08-01',
|
13
|
+
# '2.16.840.1.113883.10.20.24.3.5' => '2016-02-01', Removed
|
14
|
+
# '2.16.840.1.113883.10.20.24.3.6' => '2016-02-01', Removed
|
15
|
+
'2.16.840.1.113883.10.20.24.3.7' => '2017-08-01',
|
16
|
+
# '2.16.840.1.113883.10.20.24.3.8' => '2016-02-01',
|
17
|
+
'2.16.840.1.113883.10.20.24.3.130' => '2017-08-01',
|
18
|
+
'2.16.840.1.113883.10.20.24.3.131' => '2017-08-01',
|
19
|
+
'2.16.840.1.113883.10.20.24.3.137' => '2017-08-01',
|
20
|
+
# '2.16.840.1.113883.10.20.24.3.15' => '2016-02-01', Removed
|
21
|
+
# '2.16.840.1.113883.10.20.24.3.16' => '2016-02-01', Removed
|
22
|
+
'2.16.840.1.113883.10.20.24.3.17' => '2017-08-01',
|
23
|
+
'2.16.840.1.113883.10.20.24.3.18' => '2017-08-01',
|
24
|
+
'2.16.840.1.113883.10.20.24.3.19' => '2017-08-01',
|
25
|
+
'2.16.840.1.113883.10.20.24.3.105' => '2016-02-01',
|
26
|
+
# '2.16.840.1.113883.10.20.24.3.21' => '2016-02-01', Removed
|
27
|
+
'2.16.840.1.113883.10.20.24.3.132' => '2017-08-01',
|
28
|
+
'2.16.840.1.113883.10.20.24.3.133' => '2017-08-01',
|
29
|
+
'2.16.840.1.113883.10.20.24.3.134' => '2017-08-01',
|
30
|
+
'2.16.840.1.113883.10.20.24.3.12' => '2017-08-01',
|
31
|
+
'2.16.840.1.113883.10.20.24.3.140' => '2017-08-01',
|
32
|
+
'2.16.840.1.113883.10.20.24.3.143' => '2017-08-01',
|
33
|
+
# '2.16.840.1.113883.10.20.24.3.29' => '2016-02-01', Removed
|
34
|
+
# '2.16.840.1.113883.10.20.24.3.30' => '2016-02-01', Removed
|
35
|
+
'2.16.840.1.113883.10.20.24.3.31' => '2017-08-01',
|
36
|
+
'2.16.840.1.113883.10.20.24.3.32' => '2017-08-01',
|
37
|
+
'2.16.840.1.113883.10.20.24.3.33' => '2017-08-01',
|
38
|
+
# '2.16.840.1.113883.10.20.24.3.35' => '2016-02-01', Removed
|
39
|
+
# '2.16.840.1.113883.10.20.24.3.36' => '2016-02-01', Removed
|
40
|
+
'2.16.840.1.113883.10.20.24.3.37' => '2017-08-01',
|
41
|
+
'2.16.840.1.113883.10.20.24.3.38' => '2017-08-01',
|
42
|
+
'2.16.840.1.113883.10.20.24.3.39' => '2017-08-01',
|
43
|
+
'2.16.840.1.113883.10.20.24.3.41' => '2017-08-01',
|
44
|
+
'2.16.840.1.113883.10.20.24.3.42' => '2017-08-01',
|
45
|
+
# '2.16.840.1.113883.10.20.24.3.43' => '2016-02-01', Removed
|
46
|
+
# '2.16.840.1.113883.10.20.24.3.44' => '2016-02-01', Removed
|
47
|
+
'2.16.840.1.113883.10.20.24.3.139' => '2017-08-01',
|
48
|
+
# '2.16.840.1.113883.10.20.24.3.46' => '2016-02-01', Removed
|
49
|
+
'2.16.840.1.113883.10.20.24.3.47' => '2017-08-01',
|
50
|
+
'2.16.840.1.113883.10.20.24.3.48' => '2017-08-01',
|
51
|
+
'2.16.840.1.113883.10.20.24.3.51' => '2017-08-01',
|
52
|
+
'2.16.840.1.113883.10.20.24.3.54' => '2016-02-01',
|
53
|
+
'2.16.840.1.113883.10.20.24.3.103' => '2017-08-01',
|
54
|
+
'2.16.840.1.113883.10.20.24.3.58' => '2017-08-01',
|
55
|
+
'2.16.840.1.113883.10.20.24.3.59' => '2017-08-01',
|
56
|
+
'2.16.840.1.113883.10.20.24.3.55' => nil,
|
57
|
+
'2.16.840.1.113883.10.20.24.3.60' => '2017-08-01',
|
58
|
+
# '2.16.840.1.113883.10.20.24.3.61' => '2016-02-01', Removed
|
59
|
+
# '2.16.840.1.113883.10.20.24.3.62' => '2016-02-01', Removed
|
60
|
+
'2.16.840.1.113883.10.20.24.3.63' => '2017-08-01',
|
61
|
+
'2.16.840.1.113883.10.20.24.3.64' => '2017-08-01',
|
62
|
+
'2.16.840.1.113883.10.20.24.3.65' => '2017-08-01',
|
63
|
+
'2.16.840.1.113883.10.20.24.3.67' => '2017-08-01',
|
64
|
+
'2.16.840.1.113883.10.20.24.3.75' => '2017-08-01',
|
65
|
+
'2.16.840.1.113883.10.20.24.3.138' => '2017-08-01',
|
66
|
+
# '2.16.840.1.113883.10.20.24.3.141' => nil, Removed
|
67
|
+
# '2.16.840.1.113883.10.20.24.3.142' => nil, Removed
|
68
|
+
'2.16.840.1.113883.10.20.24.3.144' => '2017-08-01',
|
69
|
+
'2.16.840.1.113883.10.20.24.3.145' => '2017-08-01',
|
70
|
+
'2.16.840.1.113883.10.20.24.3.146' => '2017-08-01',
|
71
|
+
'2.16.840.1.113883.10.20.24.3.147' => '2017-08-01',
|
72
|
+
'2.16.840.1.113883.10.20.24.3.114' => '2017-08-01',
|
73
|
+
'2.16.840.1.113883.10.20.24.3.154' => '2017-08-01'
|
74
|
+
}.freeze
|
75
|
+
# Hash of templateIds/extensions specified in the Patient Data Section QDM for QRDA R5.1
|
76
|
+
QRDA_CAT_1_R5_1_QDM_OIDS = {
|
77
|
+
'2.16.840.1.113883.10.20.24.3.1' => '2017-08-01',
|
78
|
+
# '2.16.840.1.113883.10.20.24.3.2' => '2017-08-01', Removed
|
79
|
+
# '2.16.840.1.113883.10.20.24.3.3' => '2017-08-01', Removed
|
80
|
+
# '2.16.840.1.113883.10.20.24.3.4' => '2017-08-01', Removed
|
81
|
+
'2.16.840.1.113883.10.20.24.3.7' => '2018-10-01',
|
82
|
+
'2.16.840.1.113883.10.20.24.3.130' => '2017-08-01',
|
83
|
+
'2.16.840.1.113883.10.20.24.3.131' => '2017-08-01',
|
84
|
+
'2.16.840.1.113883.10.20.24.3.137' => '2017-08-01',
|
85
|
+
'2.16.840.1.113883.10.20.24.3.17' => '2017-08-01',
|
86
|
+
'2.16.840.1.113883.10.20.24.3.18' => '2017-08-01',
|
87
|
+
'2.16.840.1.113883.10.20.24.3.19' => '2017-08-01',
|
88
|
+
'2.16.840.1.113883.10.20.24.3.105' => '2018-10-01',
|
89
|
+
'2.16.840.1.113883.10.20.24.3.132' => '2017-08-01',
|
90
|
+
'2.16.840.1.113883.10.20.24.3.133' => '2017-08-01',
|
91
|
+
'2.16.840.1.113883.10.20.24.3.134' => '2017-08-01',
|
92
|
+
'2.16.840.1.113883.10.20.24.3.12' => '2017-08-01',
|
93
|
+
'2.16.840.1.113883.10.20.24.3.140' => '2017-08-01',
|
94
|
+
'2.16.840.1.113883.10.20.24.3.143' => '2017-08-01',
|
95
|
+
'2.16.840.1.113883.10.20.24.3.31' => '2017-08-01',
|
96
|
+
'2.16.840.1.113883.10.20.24.3.32' => '2017-08-01',
|
97
|
+
'2.16.840.1.113883.10.20.24.3.33' => '2017-08-01',
|
98
|
+
'2.16.840.1.113883.10.20.24.3.37' => '2017-08-01',
|
99
|
+
'2.16.840.1.113883.10.20.24.3.38' => '2017-08-01',
|
100
|
+
'2.16.840.1.113883.10.20.24.3.39' => '2017-08-01',
|
101
|
+
'2.16.840.1.113883.10.20.24.3.41' => '2017-08-01',
|
102
|
+
'2.16.840.1.113883.10.20.24.3.42' => '2017-08-01',
|
103
|
+
'2.16.840.1.113883.10.20.24.3.139' => '2018-10-01',
|
104
|
+
'2.16.840.1.113883.10.20.24.3.47' => '2018-10-01',
|
105
|
+
'2.16.840.1.113883.10.20.24.3.48' => '2017-08-01',
|
106
|
+
'2.16.840.1.113883.10.20.24.3.51' => '2017-08-01',
|
107
|
+
'2.16.840.1.113883.10.20.24.3.54' => '2016-02-01',
|
108
|
+
'2.16.840.1.113883.10.20.24.3.103' => '2017-08-01',
|
109
|
+
'2.16.840.1.113883.10.20.24.3.58' => '2017-08-01',
|
110
|
+
'2.16.840.1.113883.10.20.24.3.59' => '2017-08-01',
|
111
|
+
'2.16.840.1.113883.10.20.24.3.55' => nil,
|
112
|
+
'2.16.840.1.113883.10.20.24.3.60' => '2017-08-01',
|
113
|
+
'2.16.840.1.113883.10.20.24.3.63' => '2018-10-01',
|
114
|
+
'2.16.840.1.113883.10.20.24.3.64' => '2018-10-01',
|
115
|
+
'2.16.840.1.113883.10.20.24.3.65' => '2018-10-01',
|
116
|
+
'2.16.840.1.113883.10.20.24.3.67' => '2017-08-01',
|
117
|
+
'2.16.840.1.113883.10.20.24.3.75' => '2017-08-01',
|
118
|
+
'2.16.840.1.113883.10.20.24.3.138' => '2017-08-01',
|
119
|
+
'2.16.840.1.113883.10.20.24.3.144' => '2017-08-01',
|
120
|
+
'2.16.840.1.113883.10.20.24.3.145' => '2017-08-01',
|
121
|
+
'2.16.840.1.113883.10.20.24.3.146' => '2017-08-01',
|
122
|
+
'2.16.840.1.113883.10.20.24.3.147' => '2017-08-01',
|
123
|
+
'2.16.840.1.113883.10.20.24.3.114' => '2017-08-01',
|
124
|
+
'2.16.840.1.113883.10.20.24.3.154' => '2017-08-01',
|
125
|
+
'2.16.840.1.113883.10.20.24.3.156' => '2018-10-01',
|
126
|
+
'2.16.840.1.113883.10.20.24.3.158' => '2018-10-01'
|
127
|
+
}.freeze
|
283
128
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
def validate(file, data={})
|
292
|
-
@errors = []
|
293
|
-
# if validator does not support the qrda version specified, no checks are made
|
294
|
-
unless @templateshash.nil?
|
295
|
-
@doc = get_document(file)
|
296
|
-
@doc.root.add_namespace_definition('cda', 'urn:hl7-org:v3')
|
297
|
-
extract_entries.each do |entry|
|
298
|
-
# each entry is evaluated separetly.
|
299
|
-
entry_value_for_qrda_version(entry, data)
|
300
|
-
end
|
301
|
-
end
|
302
|
-
@errors
|
303
|
-
end
|
129
|
+
def initialize(qrda_version)
|
130
|
+
@name = 'QRDA QDM Template Validator'
|
131
|
+
@templateshash = case qrda_version
|
132
|
+
when 'r5' then QRDA_CAT_1_R5_QDM_OIDS
|
133
|
+
when 'r5_1' then QRDA_CAT_1_R5_1_QDM_OIDS
|
134
|
+
end
|
135
|
+
end
|
304
136
|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
137
|
+
# Validates that a QRDA Cat I file's Patient Data Section QDM (V3) contains entries that conform
|
138
|
+
# to the QDM approach to QRDA. In contrast to a QRDA Framework Patient Data Section that requires
|
139
|
+
# but does not specify the structured entries, the Patient Data Section QDM contained entry templates
|
140
|
+
# have specific requirements to align the quality measure data element type with its corresponding NQF
|
141
|
+
# QDM HQMF pattern, its referenced value set and potential QDM attributes.
|
142
|
+
# The result will be an Array of execution errors indicating use of templates that are not valid for the
|
143
|
+
# specified QRDA version
|
144
|
+
def validate(file, data = {})
|
145
|
+
@errors = []
|
146
|
+
# if validator does not support the qrda version specified, no checks are made
|
147
|
+
unless @templateshash.nil?
|
148
|
+
@doc = get_document(file)
|
149
|
+
@doc.root.add_namespace_definition('cda', 'urn:hl7-org:v3')
|
150
|
+
extract_entries.each do |entry|
|
151
|
+
# each entry is evaluated separetly.
|
152
|
+
entry_value_for_qrda_version(entry, data)
|
312
153
|
end
|
313
154
|
end
|
155
|
+
@errors
|
156
|
+
end
|
314
157
|
|
315
|
-
|
316
|
-
|
317
|
-
|
158
|
+
def entry_value_for_qrda_version(entry, data = {})
|
159
|
+
# an entry may have multiple templateIds
|
160
|
+
tids = entry.xpath('./*/cda:templateId')
|
161
|
+
# an entry only needs one valid templateId to be acceptable
|
162
|
+
unless tids.map { |tid| @templateshash.key?(tid['root']) && @templateshash[tid['root']] == tid['extension'] }.include? true
|
163
|
+
msg = "#{tids.map { |tid| "#{tid['root']}:#{tid['extension']}" }} are not valid Patient Data Section QDM entries for this QRDA Version"
|
164
|
+
@errors << build_error(msg, entry.path, data[:file_name])
|
318
165
|
end
|
319
166
|
end
|
320
|
-
|
167
|
+
|
168
|
+
# returns a list of the patient data entries
|
169
|
+
def extract_entries
|
170
|
+
@doc.xpath('//cda:component/cda:section[cda:templateId/@root="2.16.840.1.113883.10.20.24.2.1"]/cda:entry')
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|