Class: HQMF2::FieldValueHelper

Inherits:
Object
  • Object
show all
Defined in:
lib/hqmf-parser/2.0/field_value_helper.rb

Overview

Generates field values based on understanding of the HQMF 2.1 spec

Class Method Summary collapse

Class Method Details

.any_flavor(element) ⇒ Object



99
100
101
102
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 99

def self.any_flavor(element)
  element && (element['flavorId'] == 'ANY.NONNULL' ||
              element.at_xpath('@xsi:type', HQMF2::Document::NAMESPACES) == 'ANY')
end

.check_and_set_if_any(element, field, fields) ⇒ Object

Use when checking if the element is a “ANY” type, sets the field key if it is



93
94
95
96
97
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 93

def self.check_and_set_if_any(element, field, fields)
  any = any_flavor(element)
  fields[field] = AnyValue.new if any
  any
end

.extract_template_ids(entry) ⇒ Object

Extract template ids from the given entry



168
169
170
171
172
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 168

def self.extract_template_ids(entry)
  entry.xpath('./cda:templateId/cda:item', HQMF2::Document::NAMESPACES).collect do |template_def|
    HQMF2::Utilities.attr_val(template_def, '@root')
  end
end

.handle_fields_per_criteria(criteria, fields) ⇒ Object



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 24

def self.handle_fields_per_criteria(criteria, fields)
  case criteria.name
  when 'encounterCriteria'
    parse_encounter_fields(criteria, fields)
  when 'actCriteria'
    parse_act_criteria_fields(criteria, fields)
  when 'observationCriteria'
    parse_observation_fields(criteria, fields)
  when 'procedureCriteria'
    parse_procedure_fields(criteria, fields)
  when 'supplyCriteria'
    parse_supply_fields(criteria, fields)
  when 'substanceAdministrationCriteria'
    parse_substance_administration_fields(criteria, fields)
  when 'grouperCriteria'
    parse_grouper_fields(criteria, fields)
  end
end

.handle_loc(entry, fields) ⇒ Object

If type code for this field value is LOC, handle specifics



152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 152

def self.handle_loc(entry, fields)
  loc = entry.at_xpath("./cda:participation[@typeCode='LOC']/cda:role[@classCode='SDLOC']",
                       HQMF2::Document::NAMESPACES)
  return unless loc
  # does it have an effective time?
  low = loc.at_xpath('./cda:effectiveTime/cda:low/..')
  high = loc.at_xpath('./cda:effectiveTime/cda:high/..')
  code = loc.at_xpath('./cda:code')
  # looking at the 2.4.0 measure bundle these values are set to null if they exist
  # so that is what I am doing for now
  fields['FACILITY_LOCATION_ARRIVAL_DATETIME'] = AnyValue.new if low
  fields['FACILITY_LOCATION_DEPARTURE_DATETIME'] = AnyValue.new if high
  fields['FACILITY_LOCATION'] = Coded.new(code) if code
end

.high_field_name(template_ids) ⇒ Object

Returns the proper name for the high field given the list of template ids



140
141
142
143
144
145
146
147
148
149
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 140

def self.high_field_name(template_ids)
  if template_ids.include?('2.16.840.1.113883.10.20.28.3.13')
    'REMOVAL_DATETIME'
  elsif template_ids.include?('2.16.840.1.113883.10.20.28.3.110') ||
        template_ids.include?('2.16.840.1.113883.10.20.28.3.116')
    'ABATEMENT_DATETIME'
  else
    'DISCHARGE_DATETIME'
  end
end

.low_field_name(template_ids) ⇒ Object

Returns the proper name for the low field given the list of template ids



128
129
130
131
132
133
134
135
136
137
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 128

def self.low_field_name(template_ids)
  if template_ids.include?('2.16.840.1.113883.10.20.28.3.51')
    'ACTIVE_DATETIME'
  elsif template_ids.include?('2.16.840.1.113883.10.20.28.3.110') ||
        template_ids.include?('2.16.840.1.113883.10.20.28.3.116')
    'ONSET_DATETIME'
  else
    'ADMISSION_DATETIME'
  end
end

.parse_act_criteria_fields(_entry, _fields) ⇒ Object

The “parse_”s after this point handle extraction of data criteria based on field names



176
177
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 176

def self.parse_act_criteria_fields(_entry, _fields)
end

.parse_any(element, field, fields) ⇒ Object

handle any value



87
88
89
90
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 87

def self.parse_any(element, field, fields)
  any = check_and_set_if_any(element, field, fields)
  fields[field] = DateCriteria.parse_value(element) if element && !any
end

.parse_cd(element, field, fields) ⇒ Object

The next group of “parse_” methods also first check if the value is of the “ANY” type, and only parse if it isn’t



56
57
58
59
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 56

def self.parse_cd(element, field, fields)
  any = check_and_set_if_any(element, field, fields)
  fields[field] = Coded.new(element) if element && !any
end

.parse_cs(element, field, fields) ⇒ Object



71
72
73
74
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 71

def self.parse_cs(element, field, fields)
  # Only possible result is AnyValue
  check_and_set_if_any(element, field, fields)
end

.parse_date_fields(entry, fields) ⇒ Object



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 104

def self.parse_date_fields(entry, fields)
  # handle embded date fields
  times = [{ key: 'signeddatetime', field: 'SIGNED_DATETIME', highlow: 'high' },
           { key: 'startdatetime', field:  'START_DATETIME', highlow: 'low' },
           { key: 'stopdatetime', field:  'STOP_DATETIME', highlow: 'high' },
           { key: 'recordeddatetime', field: 'RECORDED_DATETIME', highlow: 'high' }
          ]
  times.each do |e|
    date = entry.at_xpath("cda:participation[@typeCode='AUT']/cda:role/cda:id/cda:item[@extension = '#{e[:key]}']/../../../cda:time")
    fields[e[:field]] = Range.new(date, 'IVL_PQ') if date
  end

  # Special case handle effectiveTime element , by default low is start datetime
  # and high is stop datetime.  This changes for certain elements
  template_ids = extract_template_ids(entry)
  low = entry.at_xpath('./cda:effectiveTime/cda:low/..')
  high = entry.at_xpath('./cda:effectiveTime/cda:high/..')

  fields[low_field_name(template_ids)] = Range.new(low, 'IVL_PQ') if low

  fields[high_field_name(template_ids)] = Range.new(high, 'IVL_PQ') if high
end

.parse_dset_cd(element, field, fields) ⇒ Object

The next group of “parse_” methods handle extracting values for different types of criteria



45
46
47
48
49
50
51
52
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 45

def self.parse_dset_cd(element, field, fields)
  if element
    item = element.at_xpath('./cda:item')
    any = any_flavor(item) || any_flavor(element)
    fields[field] = AnyValue.new if any
    fields[field] = Coded.new(item) if item && !any
  end
end

.parse_encounter_fields(entry, fields) ⇒ Object

Ignoring line limits here as it would be hard to create the deep xPaths with these limits. rubocop:disable Metrics/LineLength



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 207

def self.parse_encounter_fields(entry, fields)
  # Added a check for Principal Diagnosis and Diagnosis. QDM 4.2 Update
  principal = entry.at_xpath("./cda:outboundRelationship[@typeCode='REFR']/cda:actCriteria/cda:code[@code='52534-5']",
                             HQMF2::Document::NAMESPACES)
  if principal
    parse_cd(
      entry.at_xpath(
        "./cda:outboundRelationship[@typeCode='REFR']/cda:actCriteria/cda:outboundRelationship[@typeCode='SUBJ']/cda:observationCriteria/cda:value",
        HQMF2::Document::NAMESPACES
      ), 'PRINCIPAL_DIAGNOSIS', fields)
  end

  diagnosis = entry.at_xpath("./cda:outboundRelationship[@typeCode='REFR']/cda:actCriteria/cda:code[@code='29308-4']",
                             HQMF2::Document::NAMESPACES)
  if diagnosis
    parse_cd(
      entry.at_xpath(
        "./cda:outboundRelationship[@typeCode='REFR']/cda:actCriteria/cda:outboundRelationship[@typeCode='SUBJ']/cda:observationCriteria/cda:value",
        HQMF2::Document::NAMESPACES
      ), 'DIAGNOSIS', fields)
  end

  parse_pq(entry.at_xpath('./cda:lengthOfStayQuantity', HQMF2::Document::NAMESPACES), 'LENGTH_OF_STAY', fields)
  parse_cd(entry.at_xpath('./cda:dischargeDispositionCode', HQMF2::Document::NAMESPACES), 'DISCHARGE_STATUS', fields)

  handle_loc(entry, fields)
end

.parse_field_values(entry) ⇒ Object



4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 4

def self.parse_field_values(entry)
  return if entry.nil?
  criteria = entry.at_xpath('./cda:actCriteria | ./cda:observationCriteria | ./cda:encounterCriteria |
                             ./cda:procedureCriteria | ./cda:supplyCriteria |
                             ./cda:substanceAdministrationCriteria | ./cda:grouperCriteria')

  return {} if criteria.nil?
  fields = {}
  # Negation is handled in the data criteria parsing class and not as a field value.
  # Not using the reasonCode element because the QDM HQMF ig states that reason is in an outbound relationship.
  # parse_dset_cd(criteria.at_xpath('./cda:reasonCode', HQMF2::Document::NAMESPACES), 'REASON', fields) unless
  # negated.
  parse_dset_cd(criteria.at_xpath('./cda:priorityCode', HQMF2::Document::NAMESPACES), 'ORDINAL', fields)
  parse_date_fields(criteria, fields)

  handle_fields_per_criteria(criteria, fields)

  fields
end

.parse_grouper_fields(_entry, _fields) ⇒ Object



248
249
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 248

def self.parse_grouper_fields(_entry, _fields)
end

.parse_ivl_int(element, field, fields) ⇒ Object



66
67
68
69
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 66

def self.parse_ivl_int(element, field, fields)
  any = check_and_set_if_any(element, field, fields)
  fields[field] = Range.new(element) if element && !any
end

.parse_observation_fields(entry, fields) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 190

def self.parse_observation_fields(entry, fields)
  parse_dset_cd(entry.at_xpath('./cda:methodCode', HQMF2::Document::NAMESPACES), 'METHOD', fields)
  parse_dset_cd(entry.at_xpath('./cda:targetSiteCode', HQMF2::Document::NAMESPACES),
                'ANATOMICAL_LOCATION_SITE', fields)
  parse_cd(entry.at_xpath("./cda:participation[@typeCode='SBJ']/cda:role[@classCode='PRS']/cda:code",
                          HQMF2::Document::NAMESPACES),
           'RELATIONSHIP', fields)
  parse_pq(entry.at_xpath("./cda:outboundRelationship[@typeCode='REFV']/cda:observationCriteria/cda:value/cda:high",
                          HQMF2::Document::NAMESPACES),
           'REFERENCE_RANGE_HIGH', fields)
  parse_pq(entry.at_xpath("./cda:outboundRelationship[@typeCode='REFV']/cda:observationCriteria/cda:value/cda:low",
                          HQMF2::Document::NAMESPACES),
           'REFERENCE_RANGE_LOW', fields)
end

.parse_pq(element, field, fields) ⇒ Object



76
77
78
79
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 76

def self.parse_pq(element, field, fields)
  any = check_and_set_if_any(element, field, fields)
  fields[field] = Range.new(element) if element && !any
end

.parse_procedure_fields(entry, fields) ⇒ Object

rubocop:enable Metrics/LineLength



237
238
239
240
241
242
243
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 237

def self.parse_procedure_fields(entry, fields)
  parse_dset_cd(entry.at_xpath('./cda:methodCode', HQMF2::Document::NAMESPACES), 'METHOD', fields)
  parse_dset_cd(entry.at_xpath('./cda:approachSiteCode', HQMF2::Document::NAMESPACES),
                'ANATOMICAL_APPROACH_SITE', fields)
  parse_dset_cd(entry.at_xpath('./cda:targetSiteCode', HQMF2::Document::NAMESPACES),
                'ANATOMICAL_LOCATION_SITE', fields)
end

.parse_substance_administration_fields(entry, fields) ⇒ Object



179
180
181
182
183
184
185
186
187
188
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 179

def self.parse_substance_administration_fields(entry, fields)
  parse_dset_cd(entry.at_xpath('./cda:methodCode', HQMF2::Document::NAMESPACES), 'METHOD', fields)
  parse_dset_cd(entry.at_xpath('./cda:approachSiteCode', HQMF2::Document::NAMESPACES),
                'ANATOMICAL_APPROACH_SITE', fields)
  parse_dset_cd(entry.at_xpath('./cda:targetSiteCode', HQMF2::Document::NAMESPACES),
                'ANATOMICAL_LOCATION_SITE', fields)
  parse_cd(entry.at_xpath('./cda:routeCode', HQMF2::Document::NAMESPACES), 'ROUTE', fields)
  parse_pq(entry.at_xpath('./cda:doseQuantity', HQMF2::Document::NAMESPACES), 'DOSE', fields)
  parse_pq(entry.at_xpath('./cda:repeatNumber', HQMF2::Document::NAMESPACES), 'REFILLS', fields)
end

.parse_supply_fields(_entry, _fields) ⇒ Object



245
246
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 245

def self.parse_supply_fields(_entry, _fields)
end

.parse_ts(element, field, fields) ⇒ Object



61
62
63
64
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 61

def self.parse_ts(element, field, fields)
  any = check_and_set_if_any(element, field, fields)
  fields[field] = Value.new(element) if element && !any
end

.parse_value(element, field, fields) ⇒ Object



81
82
83
84
# File 'lib/hqmf-parser/2.0/field_value_helper.rb', line 81

def self.parse_value(element, field, fields)
  any = check_and_set_if_any(element, field, fields)
  fields[field] = DateCriteria.parse_value(element) if element && !any
end