cqm-reports 4.1.4 → 4.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0216ff9df831482810cabde27398288b568998fab528e5fbf75803a841c99a0
4
- data.tar.gz: 62219cfad2abf3ea311d2e69c44f121e4bc8bea4df4235c5bab7196a17c825c3
3
+ metadata.gz: efcfad7887472c241b0ffe9023f2ec6f81939bfb36c39122d1709ff1ded59863
4
+ data.tar.gz: fa28e9ad1bfd43e9291195514cf5fb7e0e2d89e949815c7ada233fa59a6a21a9
5
5
  SHA512:
6
- metadata.gz: 107e0fd97f6278f9e537acc10551dfe5a83e649e83ffe5445858560978c419ccb18fa2e98e82195f9d7d98e89d6fd5cf0a98c30391d1e915a476dddbf369277b
7
- data.tar.gz: 324e145f33405855bbf397dcf9b6614db6101013ec272d858d21858c7a3ae54b242eefab722512c32fa19f74f97612c81e7669089e9e988fffdc86b84b753604
6
+ metadata.gz: 92fe0a0c7c505a2e0131b6b58d9496ed0ca3cff7db904b34f59abc975d50c0b9389b53c12c5833c71679178676e8e9b0597cf09891b0a4314106b368102d0e81
7
+ data.tar.gz: c09988ba8ee0d8e2fafd32391fee2597b66c5da931c7f50b4035590afe9b7265f5eb5ead9cca7de01172a3ca460d94c8f2d13d4037def410b91670b086889bd0
@@ -169,10 +169,10 @@
169
169
  {{/recorder}}
170
170
  {{#referenceRange}}
171
171
  <div class="div-head-row">
172
- <div class="div-table-head--no-border"><span class="criteria-heading">Reference Range Start:</span> {{{low}}}</div>
172
+ <div class="div-table-head--no-border"><span class="criteria-heading">Reference Range Start:</span> {{#low}}{{format_time}}{{/low}}</div>
173
173
  </div>
174
174
  <div class="div-head-row">
175
- <div class="div-table-head--no-border"><span class="criteria-heading">Reference Range End:</span> {{{high}}}</div>
175
+ <div class="div-table-head--no-border"><span class="criteria-heading">Reference Range End:</span> {{#high}}{{format_time}}{{/high}}</div>
176
176
  </div>
177
177
  {{/referenceRange}}
178
178
  {{#refills}}
@@ -2,77 +2,77 @@
2
2
  <div class="div-table-body">
3
3
  {{#relevantPeriod}}
4
4
  <div class="div-head-row">
5
- <div class="div-table-head--no-border"><span class="criteria-heading">Relevant Period Start:</span> {{{low}}}</div>
5
+ <div class="div-table-head--no-border"><span class="criteria-heading">Relevant Period Start:</span> {{#low}}{{format_time}}{{/low}}</div>
6
6
  </div>
7
7
  {{#end_time?}}
8
8
  <div class="div-head-row">
9
- <div class="div-table-head--no-border"><span class="criteria-heading">Relevant Period End:</span> {{{high}}}</div>
9
+ <div class="div-table-head--no-border"><span class="criteria-heading">Relevant Period End:</span> {{#high}}{{format_time}}{{/high}}</div>
10
10
  </div>
11
11
  {{/end_time?}}
12
12
  {{/relevantPeriod}}
13
13
  {{#relevantDatetime}}
14
14
  <div class="div-head-row">
15
- <div class="div-table-head--no-border"><span class="criteria-heading">Relevant Date/Time:</span> {{{relevantDatetime}}}</div>
15
+ <div class="div-table-head--no-border"><span class="criteria-heading">Relevant Date/Time:</span> {{#relevantDatetime}}{{format_time}}{{/relevantDatetime}}</div>
16
16
  </div>
17
17
  {{/relevantDatetime}}
18
18
  {{#prevalencePeriod}}
19
19
  <div class="div-head-row">
20
- <div class="div-table-head--no-border"><span class="criteria-heading">Prevalence Period Start:</span> {{{low}}}</div>
20
+ <div class="div-table-head--no-border"><span class="criteria-heading">Prevalence Period Start:</span> {{#low}}{{format_time}}{{/low}}</div>
21
21
  </div>
22
22
  {{#end_time?}}
23
23
  <div class="div-head-row">
24
- <div class="div-table-head--no-border"><span class="criteria-heading">Prevalence Period End:</span> {{{high}}}</div>
24
+ <div class="div-table-head--no-border"><span class="criteria-heading">Prevalence Period End:</span> {{#high}}{{format_time}}{{/high}}</div>
25
25
  </div>
26
26
  {{/end_time?}}
27
27
  {{/prevalencePeriod}}
28
28
  {{#participationPeriod}}
29
29
  <div class="div-head-row">
30
- <div class="div-table-head--no-border"><span class="criteria-heading">Participation Period Start:</span> {{{low}}}</div>
30
+ <div class="div-table-head--no-border"><span class="criteria-heading">Participation Period Start:</span> {{#low}}{{format_time}}{{/low}}</div>
31
31
  </div>
32
32
  {{#end_time?}}
33
33
  <div class="div-head-row">
34
- <div class="div-table-head--no-border"><span class="criteria-heading">Participation Period End:</span> {{{high}}}</div>
34
+ <div class="div-table-head--no-border"><span class="criteria-heading">Participation Period End:</span> {{#high}}{{format_time}}{{/high}}</div>
35
35
  </div>
36
36
  {{/end_time?}}
37
37
  {{/participationPeriod}}
38
38
  {{#authorDatetime}}
39
39
  <div class="div-head-row">
40
- <div class="div-table-head--no-border"><span class="criteria-heading">Author Date/Time:</span> {{{authorDatetime}}}</div>
40
+ <div class="div-table-head--no-border"><span class="criteria-heading">Author Date/Time:</span> {{#authorDatetime}}{{format_time}}{{/authorDatetime}}</div>
41
41
  </div>
42
42
  {{/authorDatetime}}
43
43
  {{#resultDatetime}}
44
44
  <div class="div-head-row">
45
- <div class="div-table-head--no-border"><span class="criteria-heading">Result Date/Time:</span> {{{resultDatetime}}}</div>
45
+ <div class="div-table-head--no-border"><span class="criteria-heading">Result Date/Time:</span> {{#resultDatetime}}{{format_time}}{{/resultDatetime}}</div>
46
46
  </div>
47
47
  {{/resultDatetime}}
48
48
  {{#activeDatetime}}
49
49
  <div class="div-head-row">
50
- <div class="div-table-head--no-border"><span class="criteria-heading">Active Date/Time:</span> {{{activeDatetime}}}</div>
50
+ <div class="div-table-head--no-border"><span class="criteria-heading">Active Date/Time:</span> {{#activeDatetime}}{{format_time}}{{/activeDatetime}}</div>
51
51
  </div>
52
52
  {{/activeDatetime}}
53
53
  {{#incisionDatetime}}
54
54
  <div class="div-head-row">
55
- <div class="div-table-head--no-border"><span class="criteria-heading">Incision Date/Time:</span> {{{incisionDatetime}}}</div>
55
+ <div class="div-table-head--no-border"><span class="criteria-heading">Incision Date/Time:</span> {{#incisionDatetime}}{{format_time}}{{/incisionDatetime}}</div>
56
56
  </div>
57
57
  {{/incisionDatetime}}
58
58
  {{#receivedDatetime}}
59
59
  <div class="div-head-row">
60
- <div class="div-table-head--no-border"><span class="criteria-heading">Received Date/Time:</span> {{{receivedDatetime}}}</div>
60
+ <div class="div-table-head--no-border"><span class="criteria-heading">Received Date/Time:</span> {{#receivedDatetime}}{{format_time}}{{/receivedDatetime}}</div>
61
61
  </div>
62
62
  {{/receivedDatetime}}
63
63
  {{#sentDatetime}}
64
64
  <div class="div-head-row">
65
- <div class="div-table-head--no-border"><span class="criteria-heading">Sent Date/Time:</span> {{{sentDatetime}}}</div>
65
+ <div class="div-table-head--no-border"><span class="criteria-heading">Sent Date/Time:</span> {{#sentDatetime}}{{format_time}}{{/sentDatetime}}</div>
66
66
  </div>
67
67
  {{/sentDatetime}}
68
68
  {{#birthDatetime}}
69
69
  <div class="div-head-row">
70
- <div class="div-table-head--no-border"><span class="criteria-heading">Birth Date/Time:</span> {{{birthDatetime}}}</div>
70
+ <div class="div-table-head--no-border"><span class="criteria-heading">Birth Date/Time:</span> {{#birthDatetime}}{{format_time}}{{/birthDatetime}}</div>
71
71
  </div>
72
72
  {{/birthDatetime}}
73
73
  {{#expiredDatetime}}
74
74
  <div class="div-head-row">
75
- <div class="div-table-head--no-border"><span class="criteria-heading">Expired Date/Time:</span> {{{expiredDatetime}}}</div>
75
+ <div class="div-table-head--no-border"><span class="criteria-heading">Expired Date/Time:</span> {{#expiredDatetime}}{{format_time}}{{/expiredDatetime}}</div>
76
76
  </div>
77
77
  {{/expiredDatetime}}
78
78
  </div>
@@ -22,9 +22,9 @@
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>
25
- <div class="div-table-head">{{{birthdate}}}</div>
25
+ <div class="div-table-head">{{#birthdate}}{{format_time}}{{/birthdate}}</div>
26
26
  <div class="div-table-head patient_narr_th panel-heading"><span class="td_label">Date of expiration</span></div>
27
- <div class="div-table-head">{{{expiration}}}</div>
27
+ <div class="div-table-head">{{#expiration}}{{format_time}}{{/expiration}}</div>
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>
@@ -1,4 +1,5 @@
1
1
  require 'mustache'
2
+ require 'time'
2
3
  class QdmPatient < Mustache
3
4
  include Qrda::Export::Helper::PatientViewHelper
4
5
  include HQMF::Util::EntityHelper
@@ -130,7 +131,7 @@ class QdmPatient < Mustache
130
131
 
131
132
  # Checks to see if the result is a DateTime value, String, or Numeric
132
133
  begin
133
- DateTime.parse(self['result'])
134
+ DateTime.iso8601(self['result'])
134
135
  rescue ArgumentError, TypeError
135
136
  # If the value is not numeric, just print out the result
136
137
  self['result'].is_a?(Numeric) ? trimed_value(self['result']) : self['result']
@@ -151,4 +152,17 @@ class QdmPatient < Mustache
151
152
  def end_time?
152
153
  self['high'] && DateTime.parse(self['high']).year < 3000
153
154
  end
155
+
156
+ def format_time
157
+ str = render('{{.}}').to_s.strip # current section value
158
+ return "" if str.empty? || str == "null"
159
+ convert_iso_timestamp_to_human_readable(str)
160
+ rescue ArgumentError, TypeError => _e
161
+ str
162
+ end
163
+
164
+ def convert_iso_timestamp_to_human_readable(iso)
165
+ t = Time.parse(iso).in_time_zone
166
+ t.strftime('%B %e, %Y %l:%M%P')
167
+ end
154
168
  end
@@ -8,14 +8,20 @@
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
- {{#ry2026_submission?}}
12
- <!-- QRDA Category I Report - CMS (V9) -->
13
- <templateId root="2.16.840.1.113883.10.20.24.1.3" extension="2025-03-01"/>
14
- {{/ry2026_submission?}}
15
- {{^ry2026_submission?}}
16
- <!-- QRDA Category I Report - CMS (V8) -->
17
- <templateId root="2.16.840.1.113883.10.20.24.1.3" extension="2022-02-01"/>
18
- {{/ry2026_submission?}}
11
+ {{#ry2027_submission?}}
12
+ <!-- QRDA Category I Report - CMS (V10) -->
13
+ <templateId root="2.16.840.1.113883.10.20.24.1.3" extension="2026-05-01"/>
14
+ {{/ry2027_submission?}}
15
+ {{^ry2027_submission?}}
16
+ {{#ry2026_submission?}}
17
+ <!-- QRDA Category I Report - CMS (V9) -->
18
+ <templateId root="2.16.840.1.113883.10.20.24.1.3" extension="2025-03-01"/>
19
+ {{/ry2026_submission?}}
20
+ {{^ry2026_submission?}}
21
+ <!-- QRDA Category I Report - CMS (V8) -->
22
+ <templateId root="2.16.840.1.113883.10.20.24.1.3" extension="2022-02-01"/>
23
+ {{/ry2026_submission?}}
24
+ {{/ry2027_submission?}}
19
25
  <!-- This is the globally unique identifier for this QRDA document -->
20
26
  <id root="{{random_id}}"/>
21
27
  <!-- QRDA document type code -->
@@ -21,14 +21,19 @@ class Qrda1R5 < Mustache
21
21
  @performance_period_end = options[:end_time]
22
22
  @submission_program = options[:submission_program]
23
23
  @ry2026_submission = options[:ry2026_submission]
24
+ @ry2027_submission = options[:ry2027_submission]
24
25
  @medicare_beneficiary_identifier = options[:medicare_beneficiary_identifier]
25
26
  @hicn = options[:hicn]
26
27
  @authoring_system = options[:authoring_system]
27
28
  end
28
29
 
29
- # use 2026 template ids if 2026 submission is specified as true, or if it unspecified
30
+ # use 2027 template ids if 2027 submission is specified as true, or if it unspecified
31
+ def ry2027_submission?
32
+ @ry2027_submission || @ry2027_submission.nil?
33
+ end
34
+
30
35
  def ry2026_submission?
31
- @ry2026_submission || @ry2026_submission.nil?
36
+ @ry2026_submission
32
37
  end
33
38
 
34
39
  def authoring_system
@@ -72,7 +72,7 @@ module Qrda
72
72
  result_value_as_string(self['result'])
73
73
  elsif self['result'].is_a? String
74
74
  begin
75
- DateTime.parse self['result']
75
+ DateTime.iso8601 self['result']
76
76
  "<value xsi:type=\"TS\" #{value_or_null_flavor(self['result'])}/>"
77
77
  rescue StandardError
78
78
  "<value xsi:type=\"ST\">#{self['result']}</value>"
@@ -173,11 +173,11 @@ module QRDA
173
173
  def extract_frequency_in_hours(parent_element, frequency_xpath)
174
174
  # Need to go get low, high and institutionspecified
175
175
  low = parent_element.at_xpath("#{frequency_xpath}/@value").value.to_i if parent_element.at_xpath("#{frequency_xpath}/@value")
176
- low = parent_element.at_xpath("#{frequency_xpath}/cda:period/cda:low/@value").value.to_i if parent_element.at_xpath("#{frequency_xpath}/cda:period/cda:low/@value")
176
+ low = parent_element.at_xpath("#{frequency_xpath}/cda:low/@value").value.to_i if parent_element.at_xpath("#{frequency_xpath}/cda:low/@value")
177
177
  unit = parent_element.at_xpath("#{frequency_xpath}/@unit").value if parent_element.at_xpath("#{frequency_xpath}/@unit")
178
- unit = parent_element.at_xpath("#{frequency_xpath}/cda:period/cda:low/@unit").value if parent_element.at_xpath("#{frequency_xpath}/cda:period/cda:low/@unit")
179
- high = parent_element.at_xpath("#{frequency_xpath}/cda:period/cda:high/@value").value.to_i if parent_element.at_xpath("#{frequency_xpath}/cda:period/cda:high/@value")
180
- institution_specified = parent_element.at_xpath("#{frequency_xpath}/@institutionSpecified") || false
178
+ unit = parent_element.at_xpath("#{frequency_xpath}/cda:low/@unit").value if parent_element.at_xpath("#{frequency_xpath}/cda:low/@unit")
179
+ high = parent_element.at_xpath("#{frequency_xpath}/cda:high/@value").value.to_i if parent_element.at_xpath("#{frequency_xpath}/cda:high/@value")
180
+ institution_specified = parent_element.at_xpath(frequency_xpath.to_s)&.parent&.at_xpath('@institutionSpecified')&.value == 'true'
181
181
  # Expected units are H (hours) and D (days)
182
182
  if unit && unit.upcase == 'D'
183
183
  low = low * 24 if low
@@ -217,7 +217,7 @@ module QRDA
217
217
  qrda_type = @entry_class.to_s.split("::")[1]
218
218
  @warnings << ValidationError.new(message: "Value with string type found. When possible, it's best practice to use a coded value or scalar. Located in element with QRDA type: #{qrda_type} #{id_str}",
219
219
  location: value_element.path)
220
- return value_element.text
220
+ return Regexp.escape(value_element.text)
221
221
  end
222
222
  end
223
223
 
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.1.4
4
+ version: 4.1.6
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: 2025-06-09 00:00:00.000000000 Z
11
+ date: 2026-06-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cqm-models