cqm-reports 3.1.1 → 3.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +1 -1
- data/lib/html-export/qdm-patient/data_element/_data_element_codes.mustache +1 -1
- data/lib/html-export/qdm-patient/qdm_patient.mustache +8 -8
- data/lib/html-export/qdm-patient/qdm_patient.rb +19 -1
- data/lib/qrda-export/catI-r5/qrda_header/_record_target.mustache +1 -1
- data/lib/qrda-export/catI-r5/qrda_templates/communication_performed.mustache +0 -1
- data/lib/qrda-export/catI-r5/qrda_templates/laboratory_test_performed.mustache +4 -0
- data/lib/qrda-export/catI-r5/qrda_templates/physical_exam_performed.mustache +4 -0
- data/lib/qrda-export/catI-r5/qrda_templates/template_partials/_reaction_observation.mustache +1 -1
- data/lib/qrda-export/catI-r5/qrda_templates/template_partials/_reason.mustache +0 -1
- data/lib/qrda-export/catIII-r2-1/_continuous_variable_value.mustache +5 -5
- data/lib/qrda-export/catIII-r2-1/_header.mustache +7 -1
- data/lib/qrda-export/catIII-r2-1/_measure_data.mustache +0 -2
- data/lib/qrda-export/catIII-r2-1/_stratification.mustache +3 -5
- data/lib/qrda-export/catIII-r2-1/qrda3_r21.rb +7 -5
- data/lib/qrda-export/helper/aggregate_object_helper.rb +14 -18
- data/lib/qrda-export/helper/date_helper.rb +2 -2
- data/lib/qrda-import/base-importers/demographics_importer.rb +8 -7
- data/lib/qrda-import/base-importers/section_importer.rb +17 -3
- data/lib/qrda-import/data-element-importers/encounter_performed_importer.rb +11 -1
- data/lib/qrda-import/patient_importer.rb +12 -6
- metadata +20 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e0ceaca18d15bf285ae1a74d6c9844a5fa3226377857da71f654dad0185945f6
|
4
|
+
data.tar.gz: dff07718975472430f917e25772df47078df534fccbe985d37c37630c7c9f641
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c881930baa2fd8835a9e043278592e390c83acddaf43cef5eba5ce5dd37333151b0d7bdc418c90958a05ea6f9f36319d93df07cce09f7a27bb63428be3f36609
|
7
|
+
data.tar.gz: 6159a2125f19038c9524c2085a2a0e660a032ff31f4e0ea308f28ad8918febba2b54f2f7d695c78e87f40ff19699ec43828dc72555eb73216e979317b5afa81d
|
data/Gemfile
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
<div class="div-table-body">
|
3
3
|
{{#dataElementCodes}}
|
4
4
|
<div class="div-head-row">
|
5
|
-
<div class="div-table-head--no-border"><span class="criteria-heading">{{{code_system_name}}}:</span> {{code}}</div>
|
5
|
+
<div class="div-table-head--no-border"><span class="criteria-heading">{{{code_system_name}}}:</span> {{code}}{{{code_description}}}</div>
|
6
6
|
</div>
|
7
7
|
{{/dataElementCodes}}
|
8
8
|
</div>
|
@@ -3,7 +3,7 @@
|
|
3
3
|
<head>
|
4
4
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
5
5
|
{{#patient}}
|
6
|
-
<title>Cypress Certification Patient Test Record: {{
|
6
|
+
<title>Cypress Certification Patient Test Record: {{given_name}} {{familyName}}</title>
|
7
7
|
{{/patient}}
|
8
8
|
{{#include_style?}}
|
9
9
|
{{> _header_css}}
|
@@ -11,14 +11,14 @@
|
|
11
11
|
</head>
|
12
12
|
<body>
|
13
13
|
{{#patient}}
|
14
|
-
<h1 class="h1center">Cypress Certification Patient Test Record: {{
|
14
|
+
<h1 class="h1center">Cypress Certification Patient Test Record: {{given_name}} {{familyName}}</h1>
|
15
15
|
<div class="div-table">
|
16
16
|
<div class="div-table-body">
|
17
17
|
<div class="div-head-row patient_narr_tr panel panel-default patient-details">
|
18
18
|
<div class="div-table-head patient_narr_th panel-heading"><span class="td_label">Patient</span></div>
|
19
|
-
<div class="div-table-head">{{
|
19
|
+
<div class="div-table-head">{{given_name}} {{familyName}}</div>
|
20
20
|
<div class="div-table-head patient_narr_th panel-heading"><span class="td_label">Sex</span></div>
|
21
|
-
<div class="div-table-head">{{{gender}}}</div>
|
21
|
+
<div class="div-table-head">{{{gender}}}{{#demographic_code_description}}gender{{/demographic_code_description}}</div>
|
22
22
|
</div>
|
23
23
|
<div class="div-head-row patient_narr_tr panel panel-default patient-details">
|
24
24
|
<div class="div-table-head patient_narr_th panel-heading"><span class="td_label">Date of birth</span></div>
|
@@ -28,13 +28,13 @@
|
|
28
28
|
</div>
|
29
29
|
<div class="div-head-row patient_narr_tr panel panel-default patient-details">
|
30
30
|
<div class="div-table-head patient_narr_th panel-heading"><span class="td_label">Race</span></div>
|
31
|
-
<div class="div-table-head">{{{race}}}</div>
|
31
|
+
<div class="div-table-head">{{{race}}}{{#demographic_code_description}}race{{/demographic_code_description}}</div>
|
32
32
|
<div class="div-table-head patient_narr_th panel-heading"><span class="td_label">Ethnicity</span></div>
|
33
|
-
<div class="div-table-head">{{{ethnic_group}}}</div>
|
34
|
-
</div>
|
33
|
+
<div class="div-table-head">{{{ethnic_group}}}{{#demographic_code_description}}ethnic_group{{/demographic_code_description}}</div>
|
34
|
+
</div>
|
35
35
|
<div class="div-head-row patient_narr_tr panel panel-default patient-details">
|
36
36
|
<div class="div-table-head patient_narr_th panel-heading"><span class="td_label">Insurance Providers</span></div>
|
37
|
-
<div class="div-table-head">{{{payer}}}</div>
|
37
|
+
<div class="div-table-head">{{{payer}}}{{#demographic_code_description}}payer{{/demographic_code_description}}</div>
|
38
38
|
<div class="div-table-head patient_narr_th panel-heading"><span class="td_label">Patient IDs</span></div>
|
39
39
|
<div class="div-table-head">{{{mrn}}} Cypress</div>
|
40
40
|
</div>
|
@@ -91,13 +91,31 @@ class QdmPatient < Mustache
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def code_for_element(element)
|
94
|
-
"#{element['code']} (#{HQMF::Util::CodeSystemHelper.code_system_for(element['system'])})"
|
94
|
+
"#{element['code']} (#{HQMF::Util::CodeSystemHelper.code_system_for(element['system'])})#{code_description(element)}"
|
95
95
|
end
|
96
96
|
|
97
97
|
def code_system_name
|
98
98
|
HQMF::Util::CodeSystemHelper.code_system_for(self['system'])
|
99
99
|
end
|
100
100
|
|
101
|
+
def code_description(element = self)
|
102
|
+
has_descriptions = @patient.respond_to?(:code_description_hash) && !@patient.code_description_hash.empty?
|
103
|
+
# mongo keys cannot contain '.', so replace all '.', key example: '21112-8:2_16_840_1_113883_6_1'
|
104
|
+
return " - #{@patient.code_description_hash["#{element['code']}:#{element['system']}".tr('.', '_')]}" if has_descriptions
|
105
|
+
# no code description available
|
106
|
+
""
|
107
|
+
end
|
108
|
+
|
109
|
+
def demographic_code_description(code)
|
110
|
+
# only have code, don't need code system
|
111
|
+
has_descriptions = code && @patient.respond_to?(:code_description_hash) && !@patient.code_description_hash.empty?
|
112
|
+
if has_descriptions
|
113
|
+
key = @patient.code_description_hash.keys.detect { |k| k.starts_with?("#{send(code)}:") }
|
114
|
+
return " - #{@patient.code_description_hash[key]}"
|
115
|
+
end
|
116
|
+
""
|
117
|
+
end
|
118
|
+
|
101
119
|
def result_string
|
102
120
|
return unit_string if self['value']
|
103
121
|
return code_code_system_string if self['code']
|
@@ -48,7 +48,6 @@
|
|
48
48
|
<entryRelationship typeCode="REFR">
|
49
49
|
<observation classCode="OBS" moodCode="EVN">
|
50
50
|
<templateId root="2.16.840.1.113883.10.20.24.3.88" extension="2017-08-01"/>
|
51
|
-
<id root="1.3.6.1.4.1.115" extension="{{object_id}}" />
|
52
51
|
<code code="77301-0" codeSystem="2.16.840.1.113883.6.1" displayName="reason" codeSystemName="LOINC"/>
|
53
52
|
<statusCode code="completed"/>
|
54
53
|
<!-- QDM Attribute: Code -->
|
@@ -41,5 +41,9 @@
|
|
41
41
|
<!-- QDM Attribute: Components -->
|
42
42
|
{{> qrda_templates/template_partials/_component}}
|
43
43
|
{{/components}}
|
44
|
+
{{#encounter_id}}
|
45
|
+
<!-- QDM Attribute: relatedTo -->
|
46
|
+
{{> qrda_templates/template_partials/_related_to}}
|
47
|
+
{{/encounter_id}}
|
44
48
|
</observation>
|
45
49
|
</entry>
|
@@ -48,5 +48,9 @@
|
|
48
48
|
<!-- QDM Attribute: Components -->
|
49
49
|
{{> qrda_templates/template_partials/_component}}
|
50
50
|
{{/components}}
|
51
|
+
{{#encounter_id}}
|
52
|
+
<!-- QDM Attribute: relatedTo -->
|
53
|
+
{{> qrda_templates/template_partials/_related_to}}
|
54
|
+
{{/encounter_id}}
|
51
55
|
</observation>
|
52
56
|
</entry>
|
data/lib/qrda-export/catI-r5/qrda_templates/template_partials/_reaction_observation.mustache
CHANGED
@@ -4,6 +4,6 @@
|
|
4
4
|
<id root="4adc1020-7b14-11db-9fe1-0800200c9a64" />
|
5
5
|
<code code="ASSERTION" codeSystem="2.16.840.1.113883.5.4" />
|
6
6
|
<statusCode code="completed" />
|
7
|
-
{{>
|
7
|
+
<value xsi:type="CD" {{> _code}}/>
|
8
8
|
</observation>
|
9
9
|
</entryRelationship>
|
@@ -1,7 +1,6 @@
|
|
1
1
|
<entryRelationship typeCode="RSON">
|
2
2
|
<observation classCode="OBS" moodCode="EVN">
|
3
3
|
<templateId root="2.16.840.1.113883.10.20.24.3.88" extension="2017-08-01"/>
|
4
|
-
<id root="1.3.6.1.4.1.115" extension="{{random_id}}" />
|
5
4
|
<code code="77301-0" codeSystem="2.16.840.1.113883.6.1" displayName="reason" codeSystemName="LOINC"/>
|
6
5
|
{{#relevantPeriod}}
|
7
6
|
{{{relevant_period}}}
|
@@ -2,16 +2,16 @@
|
|
2
2
|
<observation classCode="OBS" moodCode="EVN">
|
3
3
|
<templateId root="2.16.840.1.113883.10.20.27.3.2"/>
|
4
4
|
<code nullFlavor="OTH">
|
5
|
-
<originalText>
|
5
|
+
<originalText>Other</originalText>
|
6
6
|
</code>
|
7
7
|
<statusCode code="completed"/>
|
8
|
-
<value xsi:type="
|
9
|
-
<methodCode code="
|
8
|
+
<value xsi:type="REAL" value="{{value}}"/>
|
9
|
+
<methodCode code="{{method}}" displayName="{{method}}" codeSystem="2.16.840.1.113883.5.84" codeSystemName="ObservationMethod"/>
|
10
10
|
<reference typeCode="REFR">
|
11
11
|
<!-- reference to the relevant measure observation in the eMeasure -->
|
12
12
|
<externalObservation classCode="OBS" moodCode="EVN">
|
13
|
-
<id root="{{
|
13
|
+
<id root="{{hqmf_id}}"/>
|
14
14
|
</externalObservation>
|
15
15
|
</reference>
|
16
16
|
</observation>
|
17
|
-
</entryRelationship>
|
17
|
+
</entryRelationship>
|
@@ -3,8 +3,14 @@
|
|
3
3
|
<typeId root="2.16.840.1.113883.1.3" extension="POCD_HD000040"/>
|
4
4
|
<!-- US Realm Header Template Id -->
|
5
5
|
<templateId root="2.16.840.1.113883.10.20.27.1.1" extension="2017-06-01"/>
|
6
|
-
|
6
|
+
{{#ry2022_submission?}}
|
7
|
+
<!-- QRDA Category III Report - CMS (V6) -->
|
8
|
+
<templateId root="2.16.840.1.113883.10.20.27.1.2" extension="2021-07-01"/>
|
9
|
+
{{/ry2022_submission?}}
|
10
|
+
{{^ry2022_submission?}}
|
11
|
+
<!-- QRDA Category III Report - CMS (V5) -->
|
7
12
|
<templateId root="2.16.840.1.113883.10.20.27.1.2" extension="2020-05-01"/>
|
13
|
+
{{/ry2022_submission?}}
|
8
14
|
<!-- This is the globally unique identifier for this QRDA document -->
|
9
15
|
<id root="{{random_id}}"/>
|
10
16
|
<!-- QRDA III document type code -->
|
@@ -27,11 +27,9 @@
|
|
27
27
|
{{> _supplemental_data}}
|
28
28
|
{{/population_supplemental_data}}
|
29
29
|
{{/supplemental_data}}
|
30
|
-
{{#msrpopl?}}
|
31
30
|
{{#population_observation}}
|
32
31
|
{{> _continuous_variable_value}}
|
33
32
|
{{/population_observation}}
|
34
|
-
{{/msrpopl?}}
|
35
33
|
<reference typeCode="REFR">
|
36
34
|
<externalObservation classCode="OBS" moodCode="EVN">
|
37
35
|
<id root="{{id}}"/>
|
@@ -15,11 +15,9 @@
|
|
15
15
|
<methodCode code="COUNT" displayName="Count" codeSystem="2.16.840.1.113883.5.84" codeSystemName="ObservationMethod"/>
|
16
16
|
</observation>
|
17
17
|
</entryRelationship>
|
18
|
-
{{#
|
19
|
-
{{
|
20
|
-
|
21
|
-
{{/stratification_observation}}
|
22
|
-
{{/msrpopl?}}
|
18
|
+
{{#stratification_observation}}
|
19
|
+
{{> _continuous_variable_value}}
|
20
|
+
{{/stratification_observation}}
|
23
21
|
<reference typeCode="REFR">
|
24
22
|
<externalObservation classCode="OBS" moodCode="EVN">
|
25
23
|
<id root="{{id}}"/>
|
@@ -27,6 +27,7 @@ class Qrda3R21 < Mustache
|
|
27
27
|
@performance_period_start = options[:start_time]
|
28
28
|
@performance_period_end = options[:end_time]
|
29
29
|
@submission_program = options[:submission_program]
|
30
|
+
@ry2022_submission = options[:ry2022_submission]
|
30
31
|
end
|
31
32
|
|
32
33
|
def agg_results(measure_id, cache_entries, population_sets)
|
@@ -58,14 +59,11 @@ class Qrda3R21 < Mustache
|
|
58
59
|
end
|
59
60
|
|
60
61
|
def stratification_observation
|
61
|
-
|
62
|
-
stratification_observation = @measure_result_hash[self['measure_id']].aggregate_count.populations.find {|p| p.type == "OBSERV"}.stratifications.find {|s| s.id == self['id'] }
|
63
|
-
stratification_observation.id = observation.id
|
64
|
-
stratification_observation
|
62
|
+
self['observation']
|
65
63
|
end
|
66
64
|
|
67
65
|
def population_observation
|
68
|
-
|
66
|
+
self['observation']
|
69
67
|
end
|
70
68
|
|
71
69
|
def supplemental_template_ids
|
@@ -90,6 +88,10 @@ class Qrda3R21 < Mustache
|
|
90
88
|
@submission_program == 'CPCPLUS'
|
91
89
|
end
|
92
90
|
|
91
|
+
def ry2022_submission?
|
92
|
+
@ry2022_submission
|
93
|
+
end
|
94
|
+
|
93
95
|
def payer_code?
|
94
96
|
self['type'] == 'PAYER'
|
95
97
|
end
|
@@ -57,23 +57,24 @@ module Qrda
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
class Population
|
60
|
-
attr_accessor :type, :value, :id, :stratifications, :supplemental_data
|
60
|
+
attr_accessor :type, :value, :id, :stratifications, :supplemental_data, :observation
|
61
61
|
|
62
62
|
def initialize
|
63
63
|
@stratifications = []
|
64
64
|
end
|
65
65
|
|
66
|
-
def add_stratification(id,value)
|
67
|
-
stratifications << Stratification.new(id,value) unless stratifications.find {|st| st.id == id}
|
66
|
+
def add_stratification(id,value,observation)
|
67
|
+
stratifications << Stratification.new(id,value,observation) unless stratifications.find {|st| st.id == id}
|
68
68
|
end
|
69
69
|
|
70
70
|
end
|
71
71
|
|
72
72
|
class Stratification
|
73
|
-
attr_accessor :id, :value
|
74
|
-
def initialize(id,value)
|
73
|
+
attr_accessor :id, :value, :observation
|
74
|
+
def initialize(id,value, observation)
|
75
75
|
@id = id
|
76
76
|
@value = value
|
77
|
+
@observation = observation
|
77
78
|
end
|
78
79
|
|
79
80
|
end
|
@@ -107,15 +108,17 @@ module Qrda
|
|
107
108
|
def add_entry(cache_entry, population_sets)
|
108
109
|
population_set = population_sets.where(population_set_id: cache_entry.pop_set_hash[:population_set_id]).first
|
109
110
|
entry_populations = []
|
110
|
-
%w[IPP DENOM NUMER NUMEX DENEX DENEXCEP MSRPOPL MSRPOPLEX
|
111
|
-
next unless population_set.populations[pop_code]
|
111
|
+
%w[IPP DENOM NUMER NUMEX DENEX DENEXCEP MSRPOPL MSRPOPLEX].each do |pop_code|
|
112
|
+
next unless population_set.populations[pop_code]
|
112
113
|
|
113
114
|
population = create_population_from_population_set(pop_code, population_set, cache_entry)
|
114
115
|
if cache_entry.pop_set_hash[:stratification_id]
|
115
116
|
strat_id = population_set.stratifications.where(stratification_id: cache_entry.pop_set_hash[:stratification_id]).first&.hqmf_id
|
116
|
-
|
117
|
+
observation = cache_entry['observations'][pop_code] if cache_entry['observations'] && cache_entry['observations'][pop_code]
|
118
|
+
population.add_stratification(strat_id,cache_entry[pop_code], observation)
|
117
119
|
else
|
118
120
|
population.value = cache_entry[pop_code]
|
121
|
+
population.observation = cache_entry['observations'][pop_code] if cache_entry['observations'] && cache_entry['observations'][pop_code]
|
119
122
|
population.supplemental_data = cache_entry.supplemental_data[pop_code]
|
120
123
|
end
|
121
124
|
entry_populations << population if population
|
@@ -128,19 +131,12 @@ module Qrda
|
|
128
131
|
end
|
129
132
|
|
130
133
|
def create_population_from_population_set(pop_code, population_set, cache_entry)
|
131
|
-
population = if pop_code
|
132
|
-
populations.find { |pop| pop.id == population_set.observations&.first&.hqmf_id }
|
133
|
-
elsif pop_code != 'STRAT'
|
134
|
-
populations.find { |pop| pop.id == population_set.populations[pop_code]&.hqmf_id }
|
135
|
-
end
|
134
|
+
population = populations.find { |pop| pop.id == population_set.populations[pop_code]&.hqmf_id } if pop_code != 'STRAT'
|
136
135
|
return population unless population.nil? && !cache_entry.pop_set_hash[:stratification_id]
|
136
|
+
|
137
137
|
population = Population.new
|
138
138
|
population.type = pop_code
|
139
|
-
population.id =
|
140
|
-
population_set.observations&.first&.hqmf_id
|
141
|
-
else
|
142
|
-
population_set.populations[pop_code]&.hqmf_id
|
143
|
-
end
|
139
|
+
population.id = population_set.populations[pop_code]&.hqmf_id
|
144
140
|
populations << population
|
145
141
|
population
|
146
142
|
end
|
@@ -101,7 +101,7 @@ module Qrda
|
|
101
101
|
end
|
102
102
|
|
103
103
|
def relevant_date_period_or_null_flavor
|
104
|
-
return relevant_period if self['relevantPeriod']
|
104
|
+
return relevant_period if self['relevantPeriod'] && (self['relevantPeriod']['low'] || self['relevantPeriod']['high'])
|
105
105
|
return relevant_date_time_value if self['relevantDatetime']
|
106
106
|
"<effectiveTime nullFlavor='UNK'/>"
|
107
107
|
end
|
@@ -128,4 +128,4 @@ module Qrda
|
|
128
128
|
end
|
129
129
|
end
|
130
130
|
end
|
131
|
-
end
|
131
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module QRDA
|
2
2
|
module Cat1
|
3
3
|
module DemographicsImporter
|
4
|
-
def get_demographics(patient, doc)
|
4
|
+
def get_demographics(patient, doc, codes)
|
5
5
|
patient_role_element = doc.at_xpath('/cda:ClinicalDocument/cda:recordTarget/cda:patientRole')
|
6
6
|
patient_element = patient_role_element.at_xpath('./cda:patient')
|
7
7
|
patient.givenNames = [patient_element.at_xpath('cda:name/cda:given').text]
|
@@ -9,28 +9,29 @@ module QRDA
|
|
9
9
|
patient.qdmPatient.birthDatetime = DateTime.parse(patient_element.at_xpath('cda:birthTime')['value'])
|
10
10
|
pcbd = QDM::PatientCharacteristicBirthdate.new
|
11
11
|
pcbd.birthDatetime = patient.qdmPatient.birthDatetime
|
12
|
-
pcbd.dataElementCodes = [
|
12
|
+
pcbd.dataElementCodes = [QDM::Code.new('21112-8', '2.16.840.1.113883.6.1')]
|
13
|
+
codes.add("21112-8:2.16.840.1.113883.6.1")
|
13
14
|
patient.qdmPatient.dataElements << pcbd
|
14
15
|
|
15
16
|
pcs = QDM::PatientCharacteristicSex.new
|
16
17
|
code_element = patient_element.at_xpath('cda:administrativeGenderCode')
|
17
|
-
pcs.dataElementCodes = [code_if_present(code_element)]
|
18
|
+
pcs.dataElementCodes = [code_if_present(code_element, codes)]
|
18
19
|
patient.qdmPatient.dataElements << pcs unless pcs.dataElementCodes.compact.blank?
|
19
20
|
|
20
21
|
pcr = QDM::PatientCharacteristicRace.new
|
21
22
|
code_element = patient_element.at_xpath('cda:raceCode')
|
22
|
-
pcr.dataElementCodes = [code_if_present(code_element)]
|
23
|
+
pcr.dataElementCodes = [code_if_present(code_element, codes)]
|
23
24
|
patient.qdmPatient.dataElements << pcr unless pcr.dataElementCodes.compact.blank?
|
24
25
|
|
25
26
|
pce = QDM::PatientCharacteristicEthnicity.new
|
26
27
|
code_element = patient_element.at_xpath('cda:ethnicGroupCode')
|
27
|
-
pce.dataElementCodes = [code_if_present(code_element)]
|
28
|
+
pce.dataElementCodes = [code_if_present(code_element, codes)]
|
28
29
|
patient.qdmPatient.dataElements << pce unless pce.dataElementCodes.compact.blank?
|
29
30
|
end
|
30
31
|
|
31
|
-
def code_if_present(code_element)
|
32
|
+
def code_if_present(code_element, codes)
|
32
33
|
return unless code_element && code_element['code'] && code_element['codeSystem']
|
33
|
-
|
34
|
+
codes.add("#{code_element['code']}:#{code_element['codeSystem']}")
|
34
35
|
QDM::Code.new(code_element['code'], code_element['codeSystem'])
|
35
36
|
end
|
36
37
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module QRDA
|
2
2
|
module Cat1
|
3
3
|
class SectionImporter
|
4
|
-
attr_accessor :check_for_usable, :status_xpath, :code_xpath, :warnings
|
4
|
+
attr_accessor :check_for_usable, :status_xpath, :code_xpath, :warnings, :codes, :codes_modifiers
|
5
5
|
|
6
6
|
def initialize(entry_finder)
|
7
7
|
@entry_finder = entry_finder
|
@@ -10,6 +10,8 @@ module QRDA
|
|
10
10
|
@check_for_usable = true
|
11
11
|
@entry_class = QDM::DataElement
|
12
12
|
@warnings = []
|
13
|
+
@codes = Set.new
|
14
|
+
@codes_modifiers = {}
|
13
15
|
end
|
14
16
|
|
15
17
|
# Traverses an HL7 CDA document passed in and creates an Array of Entry
|
@@ -81,6 +83,7 @@ module QRDA
|
|
81
83
|
|
82
84
|
def code_if_present(code_element)
|
83
85
|
return unless code_element && code_element['code'] && code_element['codeSystem']
|
86
|
+
@codes.add("#{code_element['code']}:#{code_element['codeSystem']}")
|
84
87
|
QDM::Code.new(code_element['code'], code_element['codeSystem'])
|
85
88
|
end
|
86
89
|
|
@@ -94,7 +97,9 @@ module QRDA
|
|
94
97
|
end
|
95
98
|
|
96
99
|
def extract_interval(parent_element, interval_xpath)
|
97
|
-
|
100
|
+
# nil if the time interval does not exist
|
101
|
+
return nil unless time_interval_exists(parent_element, interval_xpath)
|
102
|
+
|
98
103
|
if parent_element.at_xpath("#{interval_xpath}/@value")
|
99
104
|
low_time = DateTime.parse(parent_element.at_xpath(interval_xpath)['value'])
|
100
105
|
high_time = DateTime.parse(parent_element.at_xpath(interval_xpath)['value'])
|
@@ -131,6 +136,14 @@ module QRDA
|
|
131
136
|
QDM::Interval.new(low_time, high_time).shift_dates(0)
|
132
137
|
end
|
133
138
|
|
139
|
+
def time_interval_exists(parent_element, interval_xpath)
|
140
|
+
# false if the time interval does not exist
|
141
|
+
return false unless parent_element.at_xpath(interval_xpath)
|
142
|
+
# false if the time element exists but has a null Flavor
|
143
|
+
return false if parent_element.at_xpath(interval_xpath)['nullFlavor']
|
144
|
+
true
|
145
|
+
end
|
146
|
+
|
134
147
|
def extract_time(parent_element, datetime_xpath)
|
135
148
|
DateTime.parse(parent_element.at_xpath(datetime_xpath)['value']) if parent_element.at_xpath("#{datetime_xpath}/@value")
|
136
149
|
end
|
@@ -145,6 +158,7 @@ module QRDA
|
|
145
158
|
# If a Direct Reference Code isn't found, return nil
|
146
159
|
return nil unless key
|
147
160
|
# If a Direct Reference Code is found, return that code
|
161
|
+
@codes.add("#{key}:#{value[:code_system]}")
|
148
162
|
QDM::Code.new(key, value[:code_system])
|
149
163
|
end
|
150
164
|
|
@@ -258,7 +272,7 @@ module QRDA
|
|
258
272
|
participant_element = facility_location_element.at_xpath("./cda:participantRole[@classCode='SDLOC']/cda:code")
|
259
273
|
facility_location.code = code_if_present(participant_element)
|
260
274
|
facility_location.locationPeriod = extract_interval(facility_location_element, './cda:time')
|
261
|
-
facility_locations << facility_location
|
275
|
+
facility_locations << facility_location if facility_location.code
|
262
276
|
end
|
263
277
|
facility_locations
|
264
278
|
end
|
@@ -21,15 +21,25 @@ module QRDA
|
|
21
21
|
encounter_performed.facilityLocations = extract_facility_locations(entry_element)
|
22
22
|
encounter_performed.diagnoses = extract_diagnoses(entry_element)
|
23
23
|
if encounter_performed&.relevantPeriod&.low && encounter_performed&.relevantPeriod&.high
|
24
|
-
los = encounter_performed.relevantPeriod.high - encounter_performed.relevantPeriod.low
|
24
|
+
los = encounter_performed.relevantPeriod.high.to_date - encounter_performed.relevantPeriod.low.to_date
|
25
25
|
encounter_performed.lengthOfStay = QDM::Quantity.new(los.to_i, 'd')
|
26
26
|
end
|
27
27
|
encounter_performed.participant = extract_entity(entry_element, "./cda:entryRelationship/cda:encounter//cda:participant[@typeCode='PRF']")
|
28
|
+
extract_modifier_code(encounter_performed, entry_element)
|
28
29
|
encounter_performed
|
29
30
|
end
|
30
31
|
|
31
32
|
private
|
32
33
|
|
34
|
+
def extract_modifier_code(encounter_performed, entry_element)
|
35
|
+
code_element = entry_element.at_xpath(@code_xpath)
|
36
|
+
return unless code_element
|
37
|
+
|
38
|
+
qualifier_name = code_element.at_xpath('./cda:qualifier/cda:name')
|
39
|
+
qualifier_value = code_element.at_xpath('./cda:qualifier/cda:value')
|
40
|
+
codes_modifiers[encounter_performed.id] = { name: code_if_present(qualifier_name), value: code_if_present(qualifier_value), xpath_location: entry_element.path } if qualifier_value || qualifier_name
|
41
|
+
end
|
42
|
+
|
33
43
|
def extract_diagnoses(parent_element)
|
34
44
|
diagnosis_elements = parent_element.xpath(@diagnosis_xpath)
|
35
45
|
diagnosis_list = []
|
@@ -59,19 +59,21 @@ module QRDA
|
|
59
59
|
@data_element_importers << SubstanceOrderImporter.new
|
60
60
|
@data_element_importers << SubstanceRecommendedImporter.new
|
61
61
|
@data_element_importers << SymptomImporter.new
|
62
|
-
end
|
62
|
+
end
|
63
63
|
|
64
64
|
def parse_cat1(doc)
|
65
65
|
patient = CQM::Patient.new
|
66
66
|
warnings = []
|
67
|
+
codes = Set.new
|
68
|
+
codes_modifiers = {}
|
67
69
|
entry_id_map = {}
|
68
|
-
import_data_elements(patient, doc, entry_id_map, warnings)
|
70
|
+
import_data_elements(patient, doc, entry_id_map, codes, codes_modifiers, warnings)
|
69
71
|
normalize_references(patient, entry_id_map)
|
70
|
-
get_demographics(patient, doc)
|
71
|
-
[patient, warnings]
|
72
|
+
get_demographics(patient, doc, codes)
|
73
|
+
[patient, warnings, codes, codes_modifiers]
|
72
74
|
end
|
73
75
|
|
74
|
-
def import_data_elements(patient, doc, entry_id_map, warnings = [])
|
76
|
+
def import_data_elements(patient, doc, entry_id_map, codes = Set.new, codes_modifiers = {}, warnings = [])
|
75
77
|
context = doc.xpath("/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section[cda:templateId/@root = '2.16.840.1.113883.10.20.24.2.1']")
|
76
78
|
nrh = NarrativeReferenceHandler.new
|
77
79
|
nrh.build_id_map(doc)
|
@@ -109,8 +111,12 @@ module QRDA
|
|
109
111
|
patient.qdmPatient.dataElements << new_data_elements
|
110
112
|
entry_id_map.merge!(id_map)
|
111
113
|
warnings.concat(importer.warnings)
|
112
|
-
|
114
|
+
codes.merge(importer.codes)
|
115
|
+
codes_modifiers.merge!(importer.codes_modifiers)
|
116
|
+
# reset warnings and codes after they're captured so that the importer can be re-used
|
113
117
|
importer.warnings = []
|
118
|
+
importer.codes_modifiers = {}
|
119
|
+
importer.codes = Set.new
|
114
120
|
end
|
115
121
|
end
|
116
122
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cqm-reports
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.1.
|
4
|
+
version: 3.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- The MITRE Corporation
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cqm-models
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 3.0
|
19
|
+
version: '3.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 3.0
|
26
|
+
version: '3.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: cqm-validators
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 3.0
|
33
|
+
version: '3.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 3.0
|
40
|
+
version: '3.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: mustache
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,16 +84,22 @@ dependencies:
|
|
84
84
|
name: nokogiri
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - "
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.8.5
|
90
|
+
- - "<"
|
88
91
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
92
|
+
version: 1.12.0
|
90
93
|
type: :runtime
|
91
94
|
prerelease: false
|
92
95
|
version_requirements: !ruby/object:Gem::Requirement
|
93
96
|
requirements:
|
94
|
-
- - "
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: 1.8.5
|
100
|
+
- - "<"
|
95
101
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
102
|
+
version: 1.12.0
|
97
103
|
- !ruby/object:Gem::Dependency
|
98
104
|
name: uuid
|
99
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -343,7 +349,7 @@ homepage: https://github.com/projecttacoma/cqm-reports
|
|
343
349
|
licenses:
|
344
350
|
- Apache-2.0
|
345
351
|
metadata: {}
|
346
|
-
post_install_message:
|
352
|
+
post_install_message:
|
347
353
|
rdoc_options: []
|
348
354
|
require_paths:
|
349
355
|
- lib
|
@@ -358,9 +364,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
358
364
|
- !ruby/object:Gem::Version
|
359
365
|
version: '0'
|
360
366
|
requirements: []
|
361
|
-
|
362
|
-
|
363
|
-
signing_key:
|
367
|
+
rubygems_version: 3.1.4
|
368
|
+
signing_key:
|
364
369
|
specification_version: 4
|
365
370
|
summary: A library for import and export of reports for use with electronic Clinical
|
366
371
|
Quality Measures (eCQMs).
|