cqm-reports 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +0 -2
  3. data/lib/html-export/qdm-patient/data_element/_data_element_other_fields.mustache +1 -1
  4. data/lib/html-export/qdm-patient/qdm_patient.rb +24 -7
  5. data/lib/qrda-export/catI-r5/_header.mustache +1 -2
  6. data/lib/qrda-export/catI-r5/qrda1_r5.mustache +2 -2
  7. data/lib/qrda-export/catI-r5/qrda1_r5.rb +12 -0
  8. data/lib/qrda-export/catI-r5/qrda_header/_participant.mustache +3 -2
  9. data/lib/qrda-export/catI-r5/qrda_header/_record_target.mustache +9 -0
  10. data/lib/qrda-export/catI-r5/qrda_templates/encounter_performed.mustache +49 -56
  11. data/lib/qrda-export/catI-r5/qrda_templates/medication_discharge.mustache +1 -1
  12. data/lib/qrda-export/catI-r5/qrda_templates/medication_dispensed.mustache +1 -1
  13. data/lib/qrda-export/catI-r5/qrda_templates/medication_order.mustache +1 -1
  14. data/lib/qrda-export/catI-r5/qrda_templates/template_partials/_medication_details.mustache +1 -1
  15. data/lib/qrda-export/catI-r52/qrda1_r52.rb +258 -0
  16. data/lib/qrda-export/catI-r52/qrda_header/_participant.mustache +8 -0
  17. data/lib/qrda-export/catI-r52/qrda_header/_record_target.mustache +65 -0
  18. data/lib/qrda-export/catI-r52/qrda_templates/medication_order.mustache +70 -0
  19. data/lib/qrda-export/catIII/_header.mustache +2 -4
  20. data/lib/qrda-export/catIII/qrda_header/_participant_ehr.mustache +4 -1
  21. data/lib/qrda-export/catIII-r2-1/qrda_header/_participant_ehr.mustache +9 -0
  22. data/lib/qrda-export/helper/cat1_view_helper.rb +23 -5
  23. data/lib/qrda-export/helper/view_helper.rb +9 -1
  24. data/lib/qrda-import/base-importers/section_importer.rb +31 -4
  25. data/lib/qrda-import/data-element-importers/encounter_performed_importer.rb +12 -12
  26. data/lib/qrda-import/data-element-importers/medication_discharge_importer.rb +1 -1
  27. data/lib/qrda-import/data-element-importers/medication_dispensed_importer.rb +1 -1
  28. data/lib/qrda-import/data-element-importers/medication_order_importer.rb +1 -1
  29. data/lib/qrda-import/data-element-importers/substance_order_importer.rb +1 -1
  30. data/lib/qrda-import/data-element-importers/substance_recommended_importer.rb +1 -1
  31. data/lib/qrda-import/patient_importer.rb +22 -6
  32. metadata +10 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cda8f93792d0efa4c3e4347bd922e32396791952a09ea37d35b2e00daa3284bf
4
- data.tar.gz: 062b473dc79d294fa478b50c132c090ad0e4305679d7e834abce9f6f2ca0e0a2
3
+ metadata.gz: b0938369271d07282db5933dda15b47f0cbe346abbeff4a6004a23fcce61e680
4
+ data.tar.gz: 4ff25f7dfda32510cccb638966ab51eb76cb04c7ab31778fb2e95bc0cba88a2c
5
5
  SHA512:
6
- metadata.gz: e67430b3bcb829fc2561a6afb33b2621e727d21fdb388663de0b9d145bed201c39ab5e42385676c918897f88164e13644a869bdd04f23c0a2d64c179a99f5455
7
- data.tar.gz: ebfb491113755df26743265723641db1775ce7d53642e455c0d50a91d512974eb53bcd1f0c111284e80641cf5917e7b875f9be6877fd5728ebae9d00fd93d0e3
6
+ metadata.gz: 3c3c6bd90513f5f83610596a4789a30b0995569efcf7e6598a48f385a00d7cc869265c4f7f6b77c24c3130153df714ad3858d55e4b97f88168282d833e4a2961
7
+ data.tar.gz: 750f9df81d0cb2c633dbecc2b6be45a77c580dd7bc53defe6cc27ad592e0588cbebd563f3382e7d193f2cfcdf038728f3e01eee1f9fdbb2fc07e3a11f049afdb
data/Gemfile CHANGED
@@ -2,8 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec :development_group => :test
4
4
 
5
- gem 'mongoid', '~> 6.4.2'
6
-
7
5
  gem 'protected_attributes_continued'
8
6
 
9
7
  group :development, :test do
@@ -49,7 +49,7 @@
49
49
  {{/daysSupplied}}
50
50
  {{#diagnoses}}
51
51
  <div class="div-head-row">
52
- <div class="div-table-head--no-border"><span class="criteria-heading">Diagnosis{{{diagnosis_rank_string}}}:</span> {{{nested_code_string}}}</div>
52
+ <div class="div-table-head--no-border"><span class="criteria-heading">Diagnosis:</span> {{{nested_code_string}}} {{{diagnosis_string}}}</div>
53
53
  </div>
54
54
  {{/diagnoses}}
55
55
  {{#dischargeDisposition}}
@@ -10,6 +10,7 @@ class QdmPatient < Mustache
10
10
  @patient = patient
11
11
  @qdmPatient = patient.qdmPatient
12
12
  @patient_addresses = patient['addresses']
13
+ @patient_email = patient['email']
13
14
  @patient_telecoms = patient['telecoms']
14
15
  end
15
16
 
@@ -35,6 +36,7 @@ class QdmPatient < Mustache
35
36
  def patient_telecoms
36
37
  @patient_telecoms ||= [CQM::Telecom.new(use: 'HP', value: '555-555-2003')]
37
38
  # create formatted telecoms
39
+ @patient_telecoms << CQM::Telecom.new(use: 'HP', value: @patient_email) if @patient_email
38
40
  @patient_telecoms.map { |telecom| "(#{telecom['use']}) #{telecom['value']}" }.join("<br>")
39
41
  end
40
42
 
@@ -52,8 +54,14 @@ class QdmPatient < Mustache
52
54
  end
53
55
 
54
56
  def unit_string
55
- return "#{self['value']} " if !self['unit'] || self['unit'] == '1'
56
- "#{self['value']} #{self['unit']}"
57
+ return trimed_value(self['value']).to_s if !self['unit'] || self['unit'] == '1'
58
+ "#{trimed_value(self['value'])} #{self['unit']}"
59
+ end
60
+
61
+ def trimed_value(number)
62
+ i = number.to_i
63
+ f = number.to_f
64
+ i == f ? i : f
57
65
  end
58
66
 
59
67
  def entity_string
@@ -83,7 +91,7 @@ class QdmPatient < Mustache
83
91
  end
84
92
 
85
93
  def identifier_for_element(identifier)
86
- "#{identifier['value']} (#{identifier['namingSystem']})"
94
+ identifier ? "#{identifier['value']} (#{identifier['namingSystem']})" : ''
87
95
  end
88
96
 
89
97
  def code_code_system_string
@@ -91,7 +99,7 @@ class QdmPatient < Mustache
91
99
  end
92
100
 
93
101
  def code_for_element(element)
94
- "#{element['code']} (#{HQMF::Util::CodeSystemHelper.code_system_for(element['system'])})#{code_description(element)}"
102
+ element ? "#{element['code']} (#{HQMF::Util::CodeSystemHelper.code_system_for(element['system'])})#{code_description(element)}" : ''
95
103
  end
96
104
 
97
105
  def code_system_name
@@ -120,15 +128,24 @@ class QdmPatient < Mustache
120
128
  return unit_string if self['value']
121
129
  return code_code_system_string if self['code']
122
130
 
123
- self['result']
131
+ # Checks to see if the result is a DateTime value, String, or Numeric
132
+ begin
133
+ DateTime.parse(self['result'])
134
+ rescue ArgumentError, TypeError
135
+ # If the value is not numeric, just print out the result
136
+ self['result'].is_a?(Numeric) ? trimed_value(self['result']) : self['result']
137
+ end
124
138
  end
125
139
 
126
140
  def nested_code_string
127
141
  code_for_element(self['code'])
128
142
  end
129
143
 
130
- def diagnosis_rank_string
131
- " (rank: #{self['rank']})" if self['rank']
144
+ def diagnosis_string
145
+ dx_string = ''
146
+ dx_string += "</br>&nbsp; rank: #{self['rank']}" if self['rank']
147
+ dx_string += "</br>&nbsp; presentOnAdmissionIndicator: #{self['presentOnAdmissionIndicator']['code']}" if self['presentOnAdmissionIndicator']
148
+ dx_string
132
149
  end
133
150
 
134
151
  def end_time?
@@ -8,8 +8,7 @@
8
8
  <!-- QDM-based QRDA templateId -->
9
9
  <templateId root="2.16.840.1.113883.10.20.24.1.2" extension="2021-08-01"/>
10
10
  <!-- CMS QRDA templateId -->
11
- <!-- TODO: THIS will also change -->
12
- <templateId root="2.16.840.1.113883.10.20.24.1.3" extension="2020-02-01"/>
11
+ <templateId root="2.16.840.1.113883.10.20.24.1.3" extension="2022-02-01"/>
13
12
  <!-- This is the globally unique identifier for this QRDA document -->
14
13
  <id root="{{random_id}}"/>
15
14
  <!-- QRDA document type code -->
@@ -13,8 +13,8 @@
13
13
  <templateId root="2.16.840.1.113883.10.20.17.2.4"/>
14
14
  <!-- This is the templateId for Patient Data QDM section -->
15
15
  <templateId extension="2021-08-01" root="2.16.840.1.113883.10.20.24.2.1"/>
16
- <!-- TODO: This will also change -->
17
- <templateId extension="2020-02-01" root="2.16.840.1.113883.10.20.24.2.1.1"/>
16
+ <!-- Patient Data Section QDM (V8) CMS -->
17
+ <templateId extension="2022-02-01" root="2.16.840.1.113883.10.20.24.2.1.1"/>
18
18
  <code code="55188-7" codeSystem="2.16.840.1.113883.6.1"/>
19
19
  <title>Patient Data</title>
20
20
  <text/>
@@ -16,9 +16,12 @@ class Qrda1R5 < Mustache
16
16
  @provider = options[:provider]
17
17
  @patient_address_option = options[:patient_addresses]
18
18
  @patient_telecom_option = options[:patient_telecoms]
19
+ @patient_email_option = options[:patient_email]
19
20
  @performance_period_start = options[:start_time]
20
21
  @performance_period_end = options[:end_time]
21
22
  @submission_program = options[:submission_program]
23
+ @medicare_beneficiary_identifier = options[:medicare_beneficiary_identifier]
24
+ @hicn = options[:hicn]
22
25
  end
23
26
 
24
27
  def patient_addresses
@@ -41,6 +44,15 @@ class Qrda1R5 < Mustache
41
44
  JSON.parse(@patient_telecom_option.to_json)
42
45
  end
43
46
 
47
+ def patient_email
48
+ return unless @patient_email_option
49
+ telecom_email = [CQM::Telecom.new(
50
+ use: 'HP',
51
+ value: @patient_email_option
52
+ )]
53
+ JSON.parse(telecom_email.to_json)
54
+ end
55
+
44
56
  def patient_characteristic_payer
45
57
  JSON.parse(@qdmPatient.get_data_elements('patient_characteristic', 'payer').to_json)
46
58
  end
@@ -1,7 +1,8 @@
1
1
  <participant typeCode="DEV">
2
2
  <associatedEntity classCode="RGPR">
3
3
  <!-- CMS EHR Certification Number (formerly known as Office of the
4
- National Coordinator Certification Number) -->
5
- <id extension="123456789" root="2.16.840.1.113883.3.2074.1"/>
4
+ National Coordinator Certification Number). Note, this is a test
5
+ file, and the provided ID is not for a certified product set. -->
6
+ <id extension="0015CPV4ZTB4WBU" root="2.16.840.1.113883.3.2074.1"/>
6
7
  </associatedEntity>
7
8
  </participant>
@@ -1,6 +1,12 @@
1
1
  <recordTarget>
2
2
  <patientRole>
3
3
  <id extension="{{mrn}}" root="1.3.6.1.4.1.115" />
4
+ {{#medicare_beneficiary_identifier}}
5
+ <id extension="{{medicare_beneficiary_identifier}}" root="2.16.840.1.113883.4.927" />
6
+ {{/medicare_beneficiary_identifier}}
7
+ {{#hicn}}
8
+ <id extension="{{hicn}}" root="2.16.840.1.113883.4.572" />
9
+ {{/hicn}}
4
10
  {{#patient_addresses}}
5
11
  <addr use="{{use}}">
6
12
  {{#street}}
@@ -15,6 +21,9 @@
15
21
  {{#patient_telecoms}}
16
22
  <telecom use="{{use}}" value="tel:{{value}}"/>
17
23
  {{/patient_telecoms}}
24
+ {{#patient_email}}
25
+ <telecom use="{{use}}" value="mailto:{{value}}"/>
26
+ {{/patient_email}}
18
27
  <patient>
19
28
  {{#patient}}
20
29
  <name>
@@ -1,58 +1,51 @@
1
1
  <entry>
2
- <act classCode="ACT" moodCode="EVN">
3
- <!--Encounter performed Act -->
4
- <templateId extension="2021-08-01" root="2.16.840.1.113883.10.20.24.3.133"/>
5
- <code code="ENC" codeSystem="2.16.840.1.113883.5.6" codeSystemName="ActClass" displayName="Encounter"/>
6
- <entryRelationship typeCode="SUBJ">
7
- <encounter classCode="ENC" moodCode="EVN">
8
- <!-- Encounter activities template -->
9
- <templateId extension="2015-08-01" root="2.16.840.1.113883.10.20.22.4.49"/>
10
- <!-- Encounter performed template -->
11
- <templateId extension="2021-08-01" root="2.16.840.1.113883.10.20.24.3.23"/>
12
- <id extension="{{object_id}}" root="1.3.6.1.4.1.115"/>
13
- <!-- QDM Attribute: Code -->
14
- {{> _codes}}
15
- <text>{{description}}</text>
16
- <statusCode code="completed"/>
17
- {{#relevantPeriod}}
18
- <!-- QDM Attribute: Relevant Period -->
19
- {{{relevant_period}}}
20
- {{/relevantPeriod}}
21
- {{#dischargeDisposition}}
22
- <!-- QDM Attribute: Discharge Disposition -->
23
- <sdtc:dischargeDispositionCode {{> _code}}/>
24
- {{/dischargeDisposition}}
25
- {{#authorDatetime}}
26
- <!-- QDM Attribute: Author dateTime -->
27
- {{> qrda_templates/template_partials/_author}}
28
- {{/authorDatetime}}
29
- {{#facilityLocations}}
30
- <!-- QDM Attribute: Facility Locations -->
31
- {{> qrda_templates/template_partials/_facility_location}}
32
- {{/facilityLocations}}
33
- {{#admissionSource}}
34
- <!-- QDM Attribute: Admission Source -->
35
- {{> qrda_templates/template_partials/_admission_source}}
36
- {{/admissionSource}}
37
- {{#participant}}
38
- <!-- QDM Attribute: Participant -->
39
- <participant typeCode="PRF">
40
- {{> qrda_templates/template_partials/_entity}}
41
- </participant>
42
- {{/participant}}
43
- {{#clazz}}
44
- <!-- QDM Attribute: Class -->
45
- {{> qrda_templates/template_partials/_encounter_class}}
46
- {{/clazz}}
47
- {{#diagnoses}}
48
- <!-- QDM Attribute: Diagnoses -->
49
- {{> qrda_templates/template_partials/_encounter_diagnosis_qdm}}
50
- {{/diagnoses}}
51
- {{#relatedTo}}
52
- <!-- QDM Attribute: relatedTo -->
53
- {{> qrda_templates/template_partials/_related_to}}
54
- {{/relatedTo}}
55
- </encounter>
56
- </entryRelationship>
57
- </act>
2
+ <encounter classCode="ENC" moodCode="EVN">
3
+ <!-- Encounter activities template -->
4
+ <templateId extension="2015-08-01" root="2.16.840.1.113883.10.20.22.4.49"/>
5
+ <!-- Encounter performed template -->
6
+ <templateId extension="2021-08-01" root="2.16.840.1.113883.10.20.24.3.23"/>
7
+ <id extension="{{object_id}}" root="1.3.6.1.4.1.115"/>
8
+ <!-- QDM Attribute: Code -->
9
+ {{> _codes}}
10
+ <text>{{description}}</text>
11
+ <statusCode code="completed"/>
12
+ {{#relevantPeriod}}
13
+ <!-- QDM Attribute: Relevant Period -->
14
+ {{{relevant_period}}}
15
+ {{/relevantPeriod}}
16
+ {{#dischargeDisposition}}
17
+ <!-- QDM Attribute: Discharge Disposition -->
18
+ <sdtc:dischargeDispositionCode {{> _code}}/>
19
+ {{/dischargeDisposition}}
20
+ {{#authorDatetime}}
21
+ <!-- QDM Attribute: Author dateTime -->
22
+ {{> qrda_templates/template_partials/_author}}
23
+ {{/authorDatetime}}
24
+ {{#facilityLocations}}
25
+ <!-- QDM Attribute: Facility Locations -->
26
+ {{> qrda_templates/template_partials/_facility_location}}
27
+ {{/facilityLocations}}
28
+ {{#admissionSource}}
29
+ <!-- QDM Attribute: Admission Source -->
30
+ {{> qrda_templates/template_partials/_admission_source}}
31
+ {{/admissionSource}}
32
+ {{#participant}}
33
+ <!-- QDM Attribute: Participant -->
34
+ <participant typeCode="PRF">
35
+ {{> qrda_templates/template_partials/_entity}}
36
+ </participant>
37
+ {{/participant}}
38
+ {{#clazz}}
39
+ <!-- QDM Attribute: Class -->
40
+ {{> qrda_templates/template_partials/_encounter_class}}
41
+ {{/clazz}}
42
+ {{#diagnoses}}
43
+ <!-- QDM Attribute: Diagnoses -->
44
+ {{> qrda_templates/template_partials/_encounter_diagnosis_qdm}}
45
+ {{/diagnoses}}
46
+ {{#relatedTo}}
47
+ <!-- QDM Attribute: relatedTo -->
48
+ {{> qrda_templates/template_partials/_related_to}}
49
+ {{/relatedTo}}
50
+ </encounter>
58
51
  </entry>
@@ -61,7 +61,7 @@
61
61
  {{/daysSupplied}}
62
62
  {{#supply}}
63
63
  <!-- QDM Attribute: Supply -->
64
- <entryRelationship typeCode="REFR">
64
+ <entryRelationship typeCode="COMP">
65
65
  {{> qrda_templates/template_partials/_medication_supply_request}}
66
66
  </entryRelationship>
67
67
  {{/supply}}
@@ -69,7 +69,7 @@
69
69
  </entryRelationship>
70
70
  {{#supply}}
71
71
  <!-- QDM Attribute: Supply -->
72
- <entryRelationship typeCode="REFR">
72
+ <entryRelationship typeCode="COMP">
73
73
  {{> qrda_templates/template_partials/_medication_supply_request}}
74
74
  </entryRelationship>
75
75
  {{/supply}}
@@ -62,7 +62,7 @@
62
62
  {{/daysSupplied}}
63
63
  {{#supply}}
64
64
  <!-- QDM Attribute: Supply -->
65
- <entryRelationship typeCode="REFR">
65
+ <entryRelationship typeCode="COMP">
66
66
  {{> qrda_templates/template_partials/_medication_supply_request}}
67
67
  </entryRelationship>
68
68
  {{/supply}}
@@ -17,7 +17,7 @@
17
17
  {{^negated}}
18
18
  {{#refills}}
19
19
  <!-- QDM Attribute: Refills -->
20
- <repeatNumber value="{{.}}"/>
20
+ <repeatNumber value="{{{refills_as_repeat_number}}}"/>
21
21
  {{/refills}}
22
22
  {{/negated}}
23
23
  {{#route}}
@@ -0,0 +1,258 @@
1
+ require 'mustache'
2
+ class Qrda1R52 < Mustache
3
+ include Qrda::Export::Helper::DateHelper
4
+ include Qrda::Export::Helper::ViewHelper
5
+ include Qrda::Export::Helper::Cat1ViewHelper
6
+ include Qrda::Export::Helper::PatientViewHelper
7
+ include Qrda::Export::Helper::FrequencyHelper
8
+ include HQMF::Util::EntityHelper
9
+
10
+ self.template_path = __dir__
11
+
12
+ def initialize(patient, measures, options = {})
13
+ @patient = patient
14
+ @qdmPatient = patient.qdmPatient
15
+ @measures = measures
16
+ @provider = options[:provider]
17
+ @patient_address_option = options[:patient_addresses]
18
+ @patient_telecom_option = options[:patient_telecoms]
19
+ @patient_email_option = options[:patient_email]
20
+ @performance_period_start = options[:start_time]
21
+ @performance_period_end = options[:end_time]
22
+ @submission_program = options[:submission_program]
23
+ @medicare_beneficiary_identifier = options[:medicare_beneficiary_identifier]
24
+ end
25
+
26
+ def patient_addresses
27
+ @patient_address_option ||= [CQM::Address.new(
28
+ use: 'HP',
29
+ street: ['202 Burlington Rd.'],
30
+ city: 'Bedford',
31
+ state: 'MA',
32
+ zip: '01730',
33
+ country: 'US'
34
+ )]
35
+ JSON.parse(@patient_address_option.to_json)
36
+ end
37
+
38
+ def patient_telecoms
39
+ @patient_telecom_option ||= [CQM::Telecom.new(
40
+ use: 'HP',
41
+ value: '555-555-2003'
42
+ )]
43
+ JSON.parse(@patient_telecom_option.to_json)
44
+ end
45
+
46
+ def patient_email
47
+ return unless @patient_email_option
48
+ telecom_email = [CQM::Telecom.new(
49
+ use: 'HP',
50
+ value: @patient_email_option
51
+ )]
52
+ JSON.parse(telecom_email.to_json)
53
+ end
54
+
55
+ def patient_characteristic_payer
56
+ JSON.parse(@qdmPatient.get_data_elements('patient_characteristic', 'payer').to_json)
57
+ end
58
+
59
+ def patient_characteristic_birthdate
60
+ JSON.parse(@qdmPatient.get_data_elements('patient_characteristic', 'birthdate').to_json)
61
+ end
62
+
63
+ def patient_characteristic_sex
64
+ JSON.parse(@qdmPatient.get_data_elements('patient_characteristic', 'gender').to_json)
65
+ end
66
+
67
+ def patient_characteristic_race
68
+ JSON.parse(@qdmPatient.get_data_elements('patient_characteristic', 'race').to_json)
69
+ end
70
+
71
+ def patient_characteristic_ethnicity
72
+ JSON.parse(@qdmPatient.get_data_elements('patient_characteristic', 'ethnicity').to_json)
73
+ end
74
+
75
+ def adverse_event
76
+ JSON.parse(@qdmPatient.get_data_elements('adverse_event', nil).to_json)
77
+ end
78
+
79
+ def allergy_intolerance
80
+ JSON.parse(@qdmPatient.get_data_elements('allergy', 'intolerance').to_json)
81
+ end
82
+
83
+ def assessment_order
84
+ JSON.parse(@qdmPatient.get_data_elements('assessment', 'order').to_json)
85
+ end
86
+
87
+ def assessment_performed
88
+ JSON.parse(@qdmPatient.get_data_elements('assessment', 'performed').to_json)
89
+ end
90
+
91
+ def assessment_recommended
92
+ JSON.parse(@qdmPatient.get_data_elements('assessment', 'recommended').to_json)
93
+ end
94
+
95
+ def communication_performed
96
+ JSON.parse(@qdmPatient.get_data_elements('communication', 'performed').to_json)
97
+ end
98
+
99
+ def diagnosis
100
+ JSON.parse(@qdmPatient.get_data_elements('condition', nil).to_json)
101
+ end
102
+
103
+ def device_applied
104
+ JSON.parse(@qdmPatient.get_data_elements('device', 'applied').to_json)
105
+ end
106
+
107
+ def device_order
108
+ JSON.parse(@qdmPatient.get_data_elements('device', 'order').to_json)
109
+ end
110
+
111
+ def device_recommended
112
+ JSON.parse(@qdmPatient.get_data_elements('device', 'recommended').to_json)
113
+ end
114
+
115
+ def diagnostic_study_order
116
+ JSON.parse(@qdmPatient.get_data_elements('diagnostic_study', 'order').to_json)
117
+ end
118
+
119
+ def diagnostic_study_performed
120
+ JSON.parse(@qdmPatient.get_data_elements('diagnostic_study', 'performed').to_json)
121
+ end
122
+
123
+ def diagnostic_study_recommended
124
+ JSON.parse(@qdmPatient.get_data_elements('diagnostic_study', 'recommended').to_json)
125
+ end
126
+
127
+ def encounter_order
128
+ JSON.parse(@qdmPatient.get_data_elements('encounter', 'order').to_json)
129
+ end
130
+
131
+ def encounter_performed
132
+ JSON.parse(@qdmPatient.get_data_elements('encounter', 'performed').to_json)
133
+ end
134
+
135
+ def encounter_recommended
136
+ JSON.parse(@qdmPatient.get_data_elements('encounter', 'recommended').to_json)
137
+ end
138
+
139
+ def family_history
140
+ JSON.parse(@qdmPatient.get_data_elements('family_history', nil).to_json)
141
+ end
142
+
143
+ def immunization_administered
144
+ JSON.parse(@qdmPatient.get_data_elements('immunization', 'administered').to_json)
145
+ end
146
+
147
+ def immunization_order
148
+ JSON.parse(@qdmPatient.get_data_elements('immunization', 'order').to_json)
149
+ end
150
+
151
+ def intervention_order
152
+ JSON.parse(@qdmPatient.get_data_elements('intervention', 'order').to_json)
153
+ end
154
+
155
+ def intervention_performed
156
+ JSON.parse(@qdmPatient.get_data_elements('intervention', 'performed').to_json)
157
+ end
158
+
159
+ def intervention_recommended
160
+ JSON.parse(@qdmPatient.get_data_elements('intervention', 'recommended').to_json)
161
+ end
162
+
163
+ def laboratory_test_order
164
+ JSON.parse(@qdmPatient.get_data_elements('laboratory_test', 'order').to_json)
165
+ end
166
+
167
+ def laboratory_test_performed
168
+ JSON.parse(@qdmPatient.get_data_elements('laboratory_test', 'performed').to_json)
169
+ end
170
+
171
+ def laboratory_test_recommended
172
+ JSON.parse(@qdmPatient.get_data_elements('laboratory_test', 'recommended').to_json)
173
+ end
174
+
175
+ def medication_active
176
+ JSON.parse(@qdmPatient.get_data_elements('medication', 'active').to_json)
177
+ end
178
+
179
+ def medication_administered
180
+ JSON.parse(@qdmPatient.get_data_elements('medication', 'administered').to_json) + JSON.parse(@qdmPatient.get_data_elements('substance', 'administered').to_json)
181
+ end
182
+
183
+ def medication_discharge
184
+ JSON.parse(@qdmPatient.get_data_elements('medication', 'discharge').to_json)
185
+ end
186
+
187
+ def medication_dispensed
188
+ JSON.parse(@qdmPatient.get_data_elements('medication', 'dispensed').to_json)
189
+ end
190
+
191
+ def medication_order
192
+ JSON.parse(@qdmPatient.get_data_elements('medication', 'order').to_json)
193
+ end
194
+
195
+ def patient_care_experience
196
+ JSON.parse(@qdmPatient.dataElements.where(hqmfOid: { '$in' => HQMF::Util::HQMFTemplateHelper.get_all_hqmf_oids('patient_care_experience', '') }).to_json)
197
+ end
198
+
199
+ def patient_characteristic_clinical_trial_participant
200
+ JSON.parse(@qdmPatient.get_data_elements('patient_characteristic', 'clinical_trial_participant').to_json)
201
+ end
202
+
203
+ def patient_characteristic_expired
204
+ JSON.parse(@qdmPatient.get_data_elements('patient_characteristic', 'expired').to_json)
205
+ end
206
+
207
+ def physical_exam_order
208
+ JSON.parse(@qdmPatient.get_data_elements('physical_exam', 'order').to_json)
209
+ end
210
+
211
+ def physical_exam_performed
212
+ JSON.parse(@qdmPatient.get_data_elements('physical_exam', 'performed').to_json)
213
+ end
214
+
215
+ def physical_exam_recommended
216
+ JSON.parse(@qdmPatient.get_data_elements('physical_exam', 'recommended').to_json)
217
+ end
218
+
219
+ def procedure_order
220
+ JSON.parse(@qdmPatient.get_data_elements('procedure', 'order').to_json)
221
+ end
222
+
223
+ def procedure_performed
224
+ JSON.parse(@qdmPatient.get_data_elements('procedure', 'performed').to_json)
225
+ end
226
+
227
+ def procedure_recommended
228
+ JSON.parse(@qdmPatient.get_data_elements('procedure', 'recommended').to_json)
229
+ end
230
+
231
+ def program_participation
232
+ JSON.parse(@qdmPatient.get_data_elements('participation', nil).to_json)
233
+ end
234
+
235
+ def provider_care_experience
236
+ JSON.parse(@qdmPatient.dataElements.where(hqmfOid: { '$in' => HQMF::Util::HQMFTemplateHelper.get_all_hqmf_oids('provider_care_experience', '') }).to_json)
237
+ end
238
+
239
+ def related_person
240
+ JSON.parse(@qdmPatient.get_data_elements('related_person', nil).to_json)
241
+ end
242
+
243
+ def substance_administered
244
+ JSON.parse(@qdmPatient.get_data_elements('substance', 'administered').to_json)
245
+ end
246
+
247
+ def substance_order
248
+ JSON.parse(@qdmPatient.get_data_elements('substance', 'order').to_json)
249
+ end
250
+
251
+ def substance_recommended
252
+ JSON.parse(@qdmPatient.get_data_elements('substance', 'recommended').to_json)
253
+ end
254
+
255
+ def symptom
256
+ JSON.parse(@qdmPatient.get_data_elements('symptom', nil).to_json)
257
+ end
258
+ end
@@ -0,0 +1,8 @@
1
+ <participant typeCode="DEV">
2
+ <associatedEntity classCode="RGPR">
3
+ <!-- CMS EHR Certification Number (formerly known as Office of the
4
+ National Coordinator Certification Number). Note, this is a test
5
+ file, and the provided ID is not for a certified product set. -->
6
+ <id extension="0015CPV4ZTB4WBU" root="2.16.840.1.113883.3.2074.1"/>
7
+ </associatedEntity>
8
+ </participant>
@@ -0,0 +1,65 @@
1
+ <recordTarget>
2
+ <patientRole>
3
+ <id extension="{{mrn}}" root="1.3.6.1.4.1.115" />
4
+ {{#medicare_beneficiary_identifier}}
5
+ <id extension="{{medicare_beneficiary_identifier}}" root="2.16.840.1.113883.4.927" />
6
+ {{/medicare_beneficiary_identifier}}
7
+ {{#patient_addresses}}
8
+ <addr use="{{use}}">
9
+ {{#street}}
10
+ <streetAddressLine>{{.}}</streetAddressLine>
11
+ {{/street}}
12
+ <city>{{city}}</city>
13
+ <state>{{state}}</state>
14
+ <postalCode>{{zip}}</postalCode>
15
+ <country>{{country}}</country>
16
+ </addr>
17
+ {{/patient_addresses}}
18
+ {{#patient_telecoms}}
19
+ <telecom use="{{use}}" value="tel:{{value}}"/>
20
+ {{/patient_telecoms}}
21
+ {{#patient_email}}
22
+ <telecom use="{{use}}" value="mailto:{{value}}"/>
23
+ {{/patient_email}}
24
+ <patient>
25
+ {{#patient}}
26
+ <name>
27
+ <given>{{given_name}}</given>
28
+ <family>{{familyName}}</family>
29
+ </name>
30
+ {{/patient}}
31
+ {{#patient_characteristic_sex}}
32
+ {{#dataElementCodes}}
33
+ <administrativeGenderCode {{> _code}}/>
34
+ {{/dataElementCodes}}
35
+ {{/patient_characteristic_sex}}
36
+ {{^patient_characteristic_sex}}
37
+ <administrativeGenderCode nullFlavor="UNK"/>
38
+ {{/patient_characteristic_sex}}
39
+ {{#patient_characteristic_birthdate}}
40
+ {{{birth_date_time}}}
41
+ {{/patient_characteristic_birthdate}}
42
+ {{#patient_characteristic_race}}
43
+ {{#dataElementCodes}}
44
+ <raceCode {{> _code}}/>
45
+ {{/dataElementCodes}}
46
+ {{/patient_characteristic_race}}
47
+ {{^patient_characteristic_race}}
48
+ <raceCode nullFlavor="UNK"/>
49
+ {{/patient_characteristic_race}}
50
+ {{#patient_characteristic_ethnicity}}
51
+ {{#dataElementCodes}}
52
+ <ethnicGroupCode {{> _code}}/>
53
+ {{/dataElementCodes}}
54
+ {{/patient_characteristic_ethnicity}}
55
+ {{^patient_characteristic_ethnicity}}
56
+ <ethnicGroupCode nullFlavor="UNK"/>
57
+ {{/patient_characteristic_ethnicity}}
58
+ <languageCommunication>
59
+ <templateId root="2.16.840.1.113883.3.88.11.83.2" assigningAuthorityName="HITSP/C83"/>
60
+ <templateId root="1.3.6.1.4.1.19376.1.5.3.1.2.1" assigningAuthorityName="IHE/PCC"/>
61
+ <languageCode code="eng"/>
62
+ </languageCommunication>
63
+ </patient>
64
+ </patientRole>
65
+ </recordTarget>
@@ -0,0 +1,70 @@
1
+ <entry>
2
+ <!--Medication Order -->
3
+ <substanceAdministration classCode="SBADM" moodCode="RQO" {{{negation_ind}}}>
4
+ <templateId root="2.16.840.1.113883.10.20.22.4.42" extension="2014-06-09"/>
5
+ <!-- Medication, Order template -->
6
+ <templateId root="2.16.840.1.113883.10.20.24.3.47" extension="2019-12-01"/>
7
+ <id root="1.3.6.1.4.1.115" extension="{{object_id}}"/>
8
+ <text>{{description}}</text>
9
+ <statusCode code="active"/>
10
+ {{#relevantPeriod}}
11
+ <!-- QDM Attribute: Relevant Period -->
12
+ {{{medication_duration_effective_time}}}
13
+ {{/relevantPeriod}}
14
+ {{^relevantPeriod}}
15
+ {{#authorDatetime}}
16
+ <!-- QDM Attribute: Relevant Period -->
17
+ {{{medication_duration_author_effective_time}}}
18
+ {{/authorDatetime}}
19
+ {{/relevantPeriod}}
20
+ {{> qrda_templates/template_partials/_medication_details}}
21
+ <consumable>
22
+ <manufacturedProduct classCode="MANU">
23
+ <!-- Medication Information (consolidation) template -->
24
+ <templateId root="2.16.840.1.113883.10.20.22.4.23" extension="2014-06-09"/>
25
+ <id root="{{random_id}}"/>
26
+ <manufacturedMaterial>
27
+ <!-- QDM Attribute: Code -->
28
+ {{> _codes}}
29
+ </manufacturedMaterial>
30
+ </manufacturedProduct>
31
+ </consumable>
32
+ {{#authorDatetime}}
33
+ <!-- QDM Attribute: Author dateTime -->
34
+ {{> qrda_templates/template_partials/_author}}
35
+ {{/authorDatetime}}
36
+ {{#setting}}
37
+ <participant typeCode="LOC">
38
+ <participantRole>
39
+ <!-- QDM Attribute: Setting -->
40
+ <code {{> _code}}/>
41
+ </participantRole>
42
+ </participant>
43
+ {{/setting}}
44
+ {{#prescriber}}
45
+ <!-- QDM Attribute: Prescriber -->
46
+ <participant typeCode="PRF">
47
+ {{> qrda_templates/template_partials/_entity}}
48
+ </participant>
49
+ {{/prescriber}}
50
+ {{#reason}}
51
+ <!-- QDM Attribute: Reason -->
52
+ {{> qrda_templates/template_partials/_reason}}
53
+ {{/reason}}
54
+ {{#negationRationale}}
55
+ <!-- QDM Attribute: Negation Rationale -->
56
+ {{> qrda_templates/template_partials/_reason}}
57
+ {{/negationRationale}}
58
+ {{#daysSupplied}}
59
+ <entryRelationship typeCode="REFR">
60
+ {{> qrda_templates/template_partials/_days_supplied}}
61
+ </entryRelationship>
62
+ {{/daysSupplied}}
63
+ {{#supply}}
64
+ <!-- QDM Attribute: Supply -->
65
+ <entryRelationship typeCode="COMP">
66
+ {{> qrda_templates/template_partials/_medication_supply_request}}
67
+ </entryRelationship>
68
+ {{/supply}}
69
+ </substanceAdministration>
70
+ </entry>
@@ -3,10 +3,8 @@
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="2020-12-01"/>
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?}}
6
+ <!-- QRDA Category III Report - CMS (V7) -->
7
+ <templateId root="2.16.840.1.113883.10.20.27.1.2" extension="2022-12-01"/>
10
8
  <!-- This is the globally unique identifier for this QRDA document -->
11
9
  <id root="{{random_id}}"/>
12
10
  <!-- QRDA III document type code -->
@@ -1,6 +1,9 @@
1
1
  <participant typeCode="DEV">
2
2
  <associatedEntity classCode="RGPR">
3
- <id root="2.16.840.1.113883.3.2074.1" extension="12345abcde67890"/>
3
+ <!-- CMS EHR Certification Number (formerly known as Office of the
4
+ National Coordinator Certification Number). Note, this is a test
5
+ file, and the provided ID is not for a certified product set. -->
6
+ <id root="2.16.840.1.113883.3.2074.1" extension="0015CPV4ZTB4WBU"/>
4
7
  <code code="129465004" displayName="medical record, device" codeSystem="2.16.840.1.113883.6.96" codeSystemName="SNOMED-CT"/>
5
8
  </associatedEntity>
6
9
  </participant>
@@ -0,0 +1,9 @@
1
+ <participant typeCode="DEV">
2
+ <associatedEntity classCode="RGPR">
3
+ <!-- CMS EHR Certification Number (formerly known as Office of the
4
+ National Coordinator Certification Number). Note, this is a test
5
+ file, and the provided ID is not for a certified product set. -->
6
+ <id root="2.16.840.1.113883.3.2074.1" extension="0015CPV4ZTB4WBU"/>
7
+ <code code="129465004" displayName="medical record, device" codeSystem="2.16.840.1.113883.6.96" codeSystemName="SNOMED-CT"/>
8
+ </associatedEntity>
9
+ </participant>
@@ -55,22 +55,30 @@ module Qrda
55
55
  self['value'].to_f
56
56
  end
57
57
 
58
+ def refills_as_repeat_number
59
+ self['refills'] + 1
60
+ end
61
+
58
62
  def dose_quantity_value
59
- return "<doseQuantity value=\"#{value_as_float}\" unit=\"#{self['unit']}\"/>" if self['unit']
63
+ return "<doseQuantity value=\"#{value_as_float}\" unit=\"#{self['unit']}\"/>" if self['unit'] && self['unit'] != ''
60
64
  "<doseQuantity value=\"#{value_as_float}\" />"
61
65
  end
62
66
 
63
67
  def result_value
64
68
  return "<value xsi:type=\"CD\" nullFlavor=\"UNK\"/>" unless self['result']
65
-
66
69
  result_string = if self['result'].is_a? Array
67
70
  result_value_as_string(self['result'][0])
68
71
  elsif self['result'].is_a? Hash
69
72
  result_value_as_string(self['result'])
70
73
  elsif self['result'].is_a? String
71
- "<value xsi:type=\"ST\">#{self['result']}</value>"
74
+ begin
75
+ DateTime.parse self['result']
76
+ "<value xsi:type=\"TS\" #{value_or_null_flavor(self['result'])}/>"
77
+ rescue StandardError
78
+ "<value xsi:type=\"ST\">#{self['result']}</value>"
79
+ end
72
80
  elsif !self['result'].nil?
73
- "<value xsi:type=\"PQ\" value=\"#{self['result']}\" unit=\"1\"/>"
81
+ integer_or_pq(self['result'])
74
82
  end
75
83
  result_string
76
84
  end
@@ -79,7 +87,17 @@ module Qrda
79
87
  return "<value xsi:type=\"CD\" nullFlavor=\"UNK\"/>" unless result
80
88
  oid = result['system'] || result['codeSystem']
81
89
  return "<value xsi:type=\"CD\" code=\"#{result['code']}\" codeSystem=\"#{oid}\" codeSystemName=\"#{HQMF::Util::CodeSystemHelper.code_system_for(oid)}\"/>" if result['code']
82
- return "<value xsi:type=\"PQ\" value=\"#{result['value']}\" unit=\"#{result['unit']}\"/>" if result['unit']
90
+ return integer_or_pq(result['value'], result['unit']) if result['unit'] && result['unit'] != ''
91
+ end
92
+
93
+ def integer_or_pq(number, unit = nil)
94
+ i = number.to_i
95
+ f = number.to_f
96
+ if i == f
97
+ unit ? "<value xsi:type=\"PQ\" value=\"#{i}\" unit=\"#{unit}\"/>" : "<value xsi:type=\"INT\" value=\"#{i}\"/>"
98
+ else
99
+ unit ? "<value xsi:type=\"PQ\" value=\"#{f}\" unit=\"#{unit}\"/>" : "<value xsi:type=\"REAL\" value=\"#{f}\"/>"
100
+ end
83
101
  end
84
102
 
85
103
  def authordatetime_or_dispenserid?
@@ -4,7 +4,7 @@ module Qrda
4
4
  module Helper
5
5
  module ViewHelper
6
6
  def measures
7
- @measures.only(:hqmf_id, :hqmf_set_id, :description).as_json
7
+ @measures.as_json
8
8
  end
9
9
 
10
10
  def random_id
@@ -22,6 +22,14 @@ module Qrda
22
22
  def submission_program
23
23
  @submission_program
24
24
  end
25
+
26
+ def medicare_beneficiary_identifier
27
+ @medicare_beneficiary_identifier
28
+ end
29
+
30
+ def hicn
31
+ @hicn
32
+ end
25
33
  end
26
34
  end
27
35
  end
@@ -47,8 +47,8 @@ module QRDA
47
47
  entry_qrda_id = extract_id(entry_element, @id_xpath)
48
48
  # Create a hash to map all of entry.ids to the same QRDA ids. This will be used to merge QRDA entries
49
49
  # that represent the same event.
50
- @entry_id_map["#{entry_qrda_id.value}_#{entry_qrda_id.namingSystem}"] ||= []
51
- @entry_id_map["#{entry_qrda_id.value}_#{entry_qrda_id.namingSystem}"] << entry.id
50
+ @entry_id_map["#{entry_qrda_id.value}***#{entry_qrda_id.namingSystem}"] ||= []
51
+ @entry_id_map["#{entry_qrda_id.value}***#{entry_qrda_id.namingSystem}"] << entry.id
52
52
  entry.dataElementCodes = extract_codes(entry_element, @code_xpath)
53
53
  extract_dates(entry_element, entry)
54
54
  if @result_xpath
@@ -77,7 +77,12 @@ module QRDA
77
77
  code_list << code_if_present(code_element)
78
78
  translations = code_element.xpath('cda:translation')
79
79
  translations.each do |translation|
80
- code_list << code_if_present(translation)
80
+ translation_code = code_if_present(translation)
81
+ next unless translation_code
82
+
83
+ code_list << translation_code
84
+ @warnings << ValidationError.new(message: "Translation code #{translation_code.system}:#{translation_code.code} may not be used for eCQM calculation by a receiving system. Ensure that the root code includes a code from the eCQM valueset.",
85
+ location: coded_element.path)
81
86
  end
82
87
  end
83
88
  code_list.compact
@@ -193,7 +198,14 @@ module QRDA
193
198
  return unless value_element && !value_element['nullFlavor']
194
199
  value = value_element['value']
195
200
  if value.present?
196
- return value.strip.to_f if (value_element['unit'] == "1" || value_element['unit'].nil?)
201
+ if ['TS'].include? value_element.at_xpath("@xsi:type")&.value
202
+ begin
203
+ return DateTime.parse(value_element['value'])
204
+ rescue StandardError
205
+ return nil
206
+ end
207
+ end
208
+ return value.strip.to_f if unitless?(value_element)
197
209
 
198
210
  return QDM::Quantity.new(value.strip.to_f, value_element['unit'])
199
211
  elsif value_element['code'].present?
@@ -208,6 +220,12 @@ module QRDA
208
220
  end
209
221
  end
210
222
 
223
+ def unitless?(value_element)
224
+ return true if value_element['unit'].nil?
225
+ return true if value_element['unit'] == '1'
226
+ return true if value_element['unit'][0] == '{' && value_element['unit'][-1] == '}'
227
+ end
228
+
211
229
  def extract_reason(parent_element)
212
230
  return unless @reason_xpath
213
231
  reason_element = parent_element.xpath(@reason_xpath)
@@ -254,6 +272,15 @@ module QRDA
254
272
  QDM::Quantity.new(scalar_element['value'].to_f, scalar_element['unit'])
255
273
  end
256
274
 
275
+ def extract_refills(parent_element, repeat_number_xpath)
276
+ repeat_number_element = parent_element.at_xpath(repeat_number_xpath)
277
+ return unless repeat_number_element && repeat_number_element['value'].present?
278
+
279
+ # Refills is the Repeat Number - 1
280
+ repeat_number = repeat_number_element['value'].to_i
281
+ repeat_number.positive? ? repeat_number - 1 : 0
282
+ end
283
+
257
284
  def extract_components(parent_element)
258
285
  component_elements = parent_element.xpath(@components_xpath)
259
286
  components = []
@@ -1,18 +1,18 @@
1
1
  module QRDA
2
2
  module Cat1
3
3
  class EncounterPerformedImporter < SectionImporter
4
- def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.133']"))
4
+ def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']"))
5
5
  super(entry_finder)
6
- @id_xpath = './cda:entryRelationship/cda:encounter/cda:id'
7
- @code_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']/cda:code"
8
- @relevant_period_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']/cda:effectiveTime"
9
- @author_datetime_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']/cda:author[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.155']/cda:time"
10
- @admission_source_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']/cda:participant/cda:participantRole[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.151']/cda:code"
11
- @discharge_disposition_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']/sdtc:dischargeDispositionCode"
12
- @facility_locations_xpath = "./cda:entryRelationship/cda:encounter/cda:participant[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.100']"
13
- @clazz_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']/cda:entryRelationship/cda:act[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.171']/cda:code"
14
- @diagnosis_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']/cda:entryRelationship/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.168']"
15
- @related_to_xpath = "./cda:entryRelationship/cda:encounter/sdtc:inFulfillmentOf1/sdtc:actReference"
6
+ @id_xpath = './cda:id'
7
+ @code_xpath = "./cda:code"
8
+ @relevant_period_xpath = "./cda:effectiveTime"
9
+ @author_datetime_xpath = "./cda:author[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.155']/cda:time"
10
+ @admission_source_xpath = "./cda:participant/cda:participantRole[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.151']/cda:code"
11
+ @discharge_disposition_xpath = "./sdtc:dischargeDispositionCode"
12
+ @facility_locations_xpath = "./cda:participant[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.100']"
13
+ @clazz_xpath = "./cda:entryRelationship/cda:act[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.171']/cda:code"
14
+ @diagnosis_xpath = "./cda:entryRelationship/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.168']"
15
+ @related_to_xpath = "./sdtc:inFulfillmentOf1/sdtc:actReference"
16
16
  @entry_class = QDM::EncounterPerformed
17
17
  end
18
18
 
@@ -27,7 +27,7 @@ module QRDA
27
27
  los = encounter_performed.relevantPeriod.high.to_date - encounter_performed.relevantPeriod.low.to_date
28
28
  encounter_performed.lengthOfStay = QDM::Quantity.new(los.to_i, 'd')
29
29
  end
30
- entity = extract_entity(entry_element, "./cda:entryRelationship/cda:encounter//cda:participant[@typeCode='PRF']")
30
+ entity = extract_entity(entry_element, "./cda:participant[@typeCode='PRF']")
31
31
  encounter_performed.participant.concat(entity) if entity
32
32
  extract_modifier_code(encounter_performed, entry_element)
33
33
  encounter_performed.relatedTo = extract_related_to(entry_element)
@@ -18,7 +18,7 @@ module QRDA
18
18
 
19
19
  def create_entry(entry_element, nrh = NarrativeReferenceHandler.new)
20
20
  medication_discharge = super
21
- medication_discharge.refills = extract_scalar(entry_element, @refills_xpath)&.value
21
+ medication_discharge.refills = extract_refills(entry_element, @refills_xpath)
22
22
  medication_discharge.dosage = extract_scalar(entry_element, @dosage_xpath)
23
23
  medication_discharge.supply = extract_scalar(entry_element, @supply_xpath)
24
24
  medication_discharge.frequency = frequency_as_coded_value(entry_element, @frequency_xpath)
@@ -19,7 +19,7 @@ module QRDA
19
19
 
20
20
  def create_entry(entry_element, nrh = NarrativeReferenceHandler.new)
21
21
  medication_dispensed = super
22
- medication_dispensed.refills = extract_scalar(entry_element, @refills_xpath)&.value
22
+ medication_dispensed.refills = extract_refills(entry_element, @refills_xpath)
23
23
  medication_dispensed.dosage = extract_scalar(entry_element, @dosage_xpath)
24
24
  medication_dispensed.supply = extract_scalar(entry_element, @supply_xpath)
25
25
  medication_dispensed.frequency = frequency_as_coded_value(entry_element, @frequency_xpath)
@@ -25,7 +25,7 @@ module QRDA
25
25
  medication_order.dosage = extract_scalar(entry_element, @dosage_xpath)
26
26
  medication_order.supply = extract_scalar(entry_element, @supply_xpath)
27
27
  medication_order.frequency = frequency_as_coded_value(entry_element, @frequency_xpath)
28
- medication_order.refills = extract_scalar(entry_element, @refills_xpath)&.value
28
+ medication_order.refills = extract_refills(entry_element, @refills_xpath)
29
29
  medication_order.route = code_if_present(entry_element.at_xpath(@route_xpath))
30
30
  medication_order.setting = code_if_present(entry_element.at_xpath(@setting_xpath))
31
31
  medication_order.daysSupplied = extract_scalar(entry_element, @days_supplied_xpath)&.value
@@ -21,7 +21,7 @@ module QRDA
21
21
  substance_order.dosage = extract_scalar(entry_element, @dosage_xpath)
22
22
  substance_order.supply = extract_scalar(entry_element, @supply_xpath)
23
23
  substance_order.frequency = frequency_as_coded_value(entry_element, @frequency_xpath)
24
- substance_order.refills = extract_scalar(entry_element, @refills_xpath)&.value
24
+ substance_order.refills = extract_refills(entry_element, @refills_xpath)
25
25
  substance_order.route = code_if_present(entry_element.at_xpath(@route_xpath))
26
26
  substance_order.reason = extract_reason(entry_element)
27
27
  substance_order
@@ -18,7 +18,7 @@ module QRDA
18
18
  substance_recommended = super
19
19
  substance_recommended.dosage = extract_scalar(entry_element, @dosage_xpath)
20
20
  substance_recommended.frequency = frequency_as_coded_value(entry_element, @frequency_xpath)
21
- substance_recommended.refills = extract_scalar(entry_element, @refills_xpath)&.value
21
+ substance_recommended.refills = extract_refills(entry_element, @refills_xpath)
22
22
  substance_recommended.route = code_if_present(entry_element.at_xpath(@route_xpath))
23
23
  substance_recommended.reason = extract_reason(entry_element)
24
24
  entity = extract_entity(entry_element, "./cda:participant[@typeCode='PRF']")
@@ -67,7 +67,7 @@ module QRDA
67
67
  codes_modifiers = {}
68
68
  entry_id_map = {}
69
69
  import_data_elements(patient, doc, entry_id_map, codes, codes_modifiers, warnings)
70
- normalize_references(patient, entry_id_map)
70
+ normalize_references(patient, entry_id_map, warnings)
71
71
  get_demographics(patient, doc, codes)
72
72
  [patient, warnings, codes, codes_modifiers]
73
73
  end
@@ -80,9 +80,19 @@ module QRDA
80
80
  data_elements, id_map = importer.create_entries(context, nrh)
81
81
  new_data_elements = []
82
82
 
83
- id_map.each_value do |elem_ids|
84
- elem_id = elem_ids.first
83
+ id_map.each_pair do |key, elem_ids|
84
+ split_id = key.split('***')
85
+ id_string = "#{split_id[1]}(root), #{split_id[0]}(extension)"
86
+ warnings << ValidationError.new(message: "Two or more entries share the Id: #{id_string}.") if elem_ids.length > 1
87
+ elem_id = elem_ids.last
85
88
  data_element = data_elements.find { |de| de.id == elem_id }
89
+
90
+ # If a data_element isn't returned, there was an issue parsing the template, provide a warning
91
+ if data_element.nil?
92
+ warnings << ValidationError.new(message: "Error parsing template with Id: #{id_string}.")
93
+ next
94
+ end
95
+
86
96
  # Keep the first element with a shared ID
87
97
  new_data_elements << data_element
88
98
 
@@ -94,7 +104,7 @@ module QRDA
94
104
  unique_element_keys << key_elements_for_determining_encounter_uniqueness(data_element)
95
105
 
96
106
  # Loop through all other data elements with the same id
97
- elem_ids[1,elem_ids.length].each do |dup_id|
107
+ elem_ids[0,elem_ids.length - 1].each do |dup_id|
98
108
  dup_element = data_elements.find { |de| de.id == dup_id }
99
109
  dup_element_keys = key_elements_for_determining_encounter_uniqueness(dup_element)
100
110
  # See if a previously selected data element shared all of the keys files
@@ -134,13 +144,19 @@ module QRDA
134
144
  record.deathdate = DateTime.parse(entry_elements.at_xpath("./cda:effectiveTime/cda:low")['value']).to_i
135
145
  end
136
146
 
137
- def normalize_references(patient, entry_id_map)
147
+ def normalize_references(patient, entry_id_map, warnings)
138
148
  patient.qdmPatient.dataElements.each do |data_element|
139
149
  next unless data_element.respond_to?(:relatedTo) && data_element.relatedTo
140
150
 
141
151
  relations_to_add = []
142
152
  data_element.relatedTo.each do |related_to|
143
- relations_to_add += entry_id_map["#{related_to['value']}_#{related_to['namingSystem']}"]
153
+ relation_to_add = entry_id_map["#{related_to['value']}***#{related_to['namingSystem']}"]
154
+ # Add the relation if it can be found, otherwise return a warning
155
+ relations_to_add += relation_to_add unless relation_to_add.nil?
156
+ if relation_to_add.nil?
157
+ id_warning_str = "Related To Id: #{related_to['namingSystem']}(root), #{related_to['value']}(extension) cannot be found in QRDA file."
158
+ warnings << ValidationError.new(message: id_warning_str)
159
+ end
144
160
  end
145
161
  data_element.relatedTo = relations_to_add.map(&:to_s)
146
162
  end
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: 4.0.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - The MITRE Corporation
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-12-17 00:00:00.000000000 Z
11
+ date: 2023-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cqm-models
@@ -89,7 +89,7 @@ dependencies:
89
89
  version: 1.8.5
90
90
  - - "<"
91
91
  - !ruby/object:Gem::Version
92
- version: 1.13.0
92
+ version: 1.15.0
93
93
  type: :runtime
94
94
  prerelease: false
95
95
  version_requirements: !ruby/object:Gem::Requirement
@@ -99,7 +99,7 @@ dependencies:
99
99
  version: 1.8.5
100
100
  - - "<"
101
101
  - !ruby/object:Gem::Version
102
- version: 1.13.0
102
+ version: 1.15.0
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: uuid
105
105
  requirement: !ruby/object:Gem::Requirement
@@ -263,6 +263,11 @@ files:
263
263
  - lib/qrda-export/catI-r5/qrda_templates/template_partials/_results.mustache
264
264
  - lib/qrda-export/catI-r5/qrda_templates/template_partials/_severity.mustache
265
265
  - lib/qrda-export/catI-r5/qrda_templates/template_partials/_status.mustache
266
+ - lib/qrda-export/catI-r52/qrda1_r52.rb
267
+ - lib/qrda-export/catI-r52/qrda_header/_participant.mustache
268
+ - lib/qrda-export/catI-r52/qrda_header/_record_target.mustache
269
+ - lib/qrda-export/catI-r52/qrda_templates/medication_order.mustache
270
+ - lib/qrda-export/catIII-r2-1/qrda_header/_participant_ehr.mustache
266
271
  - lib/qrda-export/catIII/_continuous_variable_value.mustache
267
272
  - lib/qrda-export/catIII/_header.mustache
268
273
  - lib/qrda-export/catIII/_measure_data.mustache
@@ -365,7 +370,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
365
370
  - !ruby/object:Gem::Version
366
371
  version: '0'
367
372
  requirements: []
368
- rubygems_version: 3.0.2
373
+ rubygems_version: 3.1.4
369
374
  signing_key:
370
375
  specification_version: 4
371
376
  summary: A library for import and export of reports for use with electronic Clinical