health-data-standards 3.7.0 → 4.0.0
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 +4 -4
- data/lib/health-data-standards.rb +3 -0
- data/lib/health-data-standards/export/helper/html_view_helper.rb +12 -12
- data/lib/health-data-standards/import/bulk_record_importer.rb +4 -4
- data/lib/health-data-standards/import/cda/encounter_importer.rb +2 -2
- data/lib/health-data-standards/models/admission_source.rb +11 -0
- data/lib/health-data-standards/models/adverse_event.rb +6 -0
- data/lib/health-data-standards/models/allergy.rb +2 -1
- data/lib/health-data-standards/models/assessment.rb +1 -0
- data/lib/health-data-standards/models/care_goal.rb +0 -1
- data/lib/health-data-standards/models/component.rb +14 -0
- data/lib/health-data-standards/models/encounter.rb +10 -13
- data/lib/health-data-standards/models/entry.rb +1 -1
- data/lib/health-data-standards/models/facility.rb +3 -2
- data/lib/health-data-standards/models/lab_result.rb +10 -4
- data/lib/health-data-standards/models/medication.rb +3 -0
- data/lib/health-data-standards/models/procedure.rb +7 -2
- data/lib/health-data-standards/models/record.rb +6 -2
- data/lib/health-data-standards/models/transfer.rb +0 -5
- data/lib/health-data-standards/util/hqmf_template_helper.rb +3 -2
- data/lib/health-data-standards/util/hqmfr2_template_oid_map.json +8 -0
- data/lib/health-data-standards/util/hqmfr2cql_template_oid_map.json +390 -0
- data/lib/health-data-standards/util/vs_api.rb +3 -3
- data/lib/hqmf-model/data_criteria.json +19 -1
- data/lib/hqmf-model/data_criteria.rb +31 -7
- data/lib/hqmf-model/document.rb +11 -2
- data/lib/hqmf-model/types.rb +31 -5
- data/lib/hqmf-parser.rb +7 -0
- data/lib/hqmf-parser/2.0/data_criteria.rb +4 -1
- data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_base_extract.rb +1 -1
- data/lib/hqmf-parser/2.0/document.rb +4 -4
- data/lib/hqmf-parser/2.0/document_helpers/doc_population_helper.rb +0 -2
- data/lib/hqmf-parser/2.0/population_criteria.rb +2 -2
- data/lib/hqmf-parser/2.0/value_set_helper.rb +4 -1
- data/lib/hqmf-parser/cql/data_criteria.rb +57 -0
- data/lib/hqmf-parser/cql/data_criteria_helpers/dc_definition_from_template_or_type_extract.rb +79 -0
- data/lib/hqmf-parser/cql/data_criteria_helpers/dc_post_processing.rb +43 -0
- data/lib/hqmf-parser/cql/document.rb +78 -0
- data/lib/hqmf-parser/cql/document_helpers/doc_population_helper.rb +124 -0
- data/lib/hqmf-parser/cql/value_set_helper.rb +103 -0
- data/lib/hqmf-parser/parser.rb +24 -1
- metadata +11 -1
@@ -66,13 +66,13 @@ module HealthDataStandards
|
|
66
66
|
def get_valueset(oid, options = {}, &block)
|
67
67
|
version = options.fetch(:version, nil)
|
68
68
|
include_draft = options.fetch(:include_draft, false)
|
69
|
-
profile = options.fetch(:profile,
|
69
|
+
profile = options.fetch(:profile, nil)
|
70
70
|
effective_date = options.fetch(:effective_date, nil)
|
71
71
|
program_name = options.fetch(:program, nil)
|
72
72
|
params = { id: oid, ticket: get_ticket }
|
73
73
|
params[:version] = version if version
|
74
|
-
params[:includeDraft] = 'yes' if include_draft
|
75
|
-
params[:profile] = profile if
|
74
|
+
params[:includeDraft] = 'yes' if profile && include_draft
|
75
|
+
params[:profile] = profile if profile
|
76
76
|
params[:effectiveDate] = effective_date if effective_date
|
77
77
|
params[:programType] = program_name if program_name
|
78
78
|
begin
|
@@ -157,7 +157,7 @@
|
|
157
157
|
"status":"",
|
158
158
|
"sub_category":"payer",
|
159
159
|
"hard_status":false,
|
160
|
-
"patient_api_function":"",
|
160
|
+
"patient_api_function":"allProblems",
|
161
161
|
"property":"payer",
|
162
162
|
"not_supported":false},
|
163
163
|
"patient_characteristic_race":{
|
@@ -1024,5 +1024,23 @@
|
|
1024
1024
|
"sub_category":"",
|
1025
1025
|
"hard_status":false,
|
1026
1026
|
"patient_api_function":"assessments",
|
1027
|
+
"not_supported":false},
|
1028
|
+
"adverse_event":{
|
1029
|
+
"title":"adverse event",
|
1030
|
+
"category":"adverse_events",
|
1031
|
+
"definition":"adverse_event",
|
1032
|
+
"status":"",
|
1033
|
+
"sub_category":"",
|
1034
|
+
"hard_status":false,
|
1035
|
+
"patient_api_function":"adverseEvents",
|
1036
|
+
"not_supported":false},
|
1037
|
+
"allergy_intolerance":{
|
1038
|
+
"title":"allergy/intolerance",
|
1039
|
+
"category":"allergies_intolerances",
|
1040
|
+
"definition":"allergy_intolerance",
|
1041
|
+
"status":"",
|
1042
|
+
"sub_category":"",
|
1043
|
+
"hard_status":false,
|
1044
|
+
"patient_api_function":"allergies",
|
1027
1045
|
"not_supported":false}
|
1028
1046
|
}
|
@@ -27,19 +27,27 @@ module HQMF
|
|
27
27
|
FIELDS = {'ABATEMENT_DATETIME' => {title:'Abatement Datetime', coded_entry_method: :end_date, field_type: :timestamp},
|
28
28
|
'ACTIVE_DATETIME' => {title:'Active Date/Time', coded_entry_method: :active_date_time, field_type: :timestamp},
|
29
29
|
'ADMISSION_DATETIME' => {title:'Admission Date/Time', coded_entry_method: :admit_time, code: '399423000', code_system:'2.16.840.1.113883.6.96', field_type: :timestamp},
|
30
|
+
# QDM 5.0 addition. This is the same as FACILITY_LOCATION.
|
31
|
+
# TODO: (LDY 10/5/2016) this is a new attribute from QDM 5.0. We do not yet have the code or template_id for this. This should be updated when we do.
|
32
|
+
'ADMISSION_SOURCE' => {title:'Admission Source', coded_entry_method: :admission_source, field_type: :value},
|
30
33
|
'ANATOMICAL_APPROACH_SITE' => {title:'Anatomical Approach Site', coded_entry_method: :anatomical_approach, field_type: :value},
|
31
34
|
'ANATOMICAL_LOCATION_SITE' => {title:'Anatomical Location Site', coded_entry_method: :anatomical_location, field_type: :value},
|
32
35
|
'ANATOMICAL_STRUCTURE' => {title:'Anatomical Structure', coded_entry_method: :anatomical_structure, code: '91723000', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1000.2', field_type: :value},
|
33
36
|
'CAUSE' => {title:'Cause', coded_entry_method: :cause_of_death, code: '42752001', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1017.2', field_type: :value},
|
37
|
+
# TODO: Determine actual code and code_system for component attribute
|
38
|
+
'COMPONENT' => {title: 'Component', coded_entry_method: :components, field_type: :value},
|
34
39
|
'CUMULATIVE_MEDICATION_DURATION' => {title:'Cumulative Medication Duration', coded_entry_method: :cumulative_medication_duration, code: '261773006', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1001.3', field_type: :value},
|
35
40
|
# MISSING Date - The date that the patient passed away. - Patient Characteristic Expired
|
36
41
|
'DIAGNOSIS' => {title:'Diagnosis', coded_entry_method: :diagnosis, field_type: :value},
|
37
42
|
'DISCHARGE_DATETIME' => {title:'Discharge Date/Time', coded_entry_method: :discharge_time, code: '442864001', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1025.1', field_type: :timestamp},
|
38
|
-
|
39
|
-
'
|
43
|
+
# TODO: (LDY 10/5/2016) this changed from "discharge status" to "discharge disposition". likely there is a code and template id change necessary. these are not yet known.
|
44
|
+
'DISCHARGE_STATUS' => {title:'Discharge Disposition', coded_entry_method: :discharge_disposition, code: '309039003', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1003.2', field_type: :value},
|
45
|
+
# TODO: (LDY 10/4/2016) this changed from "dose" to "dosage". it's possible that there's another code associated with this. this code was not available at the time of this change.
|
46
|
+
'DOSE' => {title:'Dosage', coded_entry_method: :dose, code: '398232005', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1004.1', field_type: :value},
|
40
47
|
'FACILITY_LOCATION' => {title:'Facility Location', coded_entry_method: :facility, code: 'SDLOC', field_type: :value},
|
41
|
-
'
|
42
|
-
'
|
48
|
+
# TODO: (LDY 10/5/2016) this changed from 'facility arrival/departure' to 'location period'. likely there is a code and template id change necessary. these are not yet known.
|
49
|
+
'FACILITY_LOCATION_ARRIVAL_DATETIME' => {title:'Location Period Start Date/Time', coded_entry_method: :facility_arrival, code: 'SDLOC_ARRIVAL', field_type: :nested_timestamp},
|
50
|
+
'FACILITY_LOCATION_DEPARTURE_DATETIME' => {title:'Location Period End Date/Time', coded_entry_method: :facility_departure, code: 'SDLOC_DEPARTURE', field_type: :nested_timestamp},
|
43
51
|
'FREQUENCY' => {title:'Frequency', coded_entry_method: :administration_timing, code: '307430002', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1006.1', field_type: :value},
|
44
52
|
'HEALTH_RECORD_FIELD' => {title: 'Health Record Field', coded_entry_method: :health_record_field, code: '395676008', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.10.20.28.3.102:2014-11-24', field_type: :value},
|
45
53
|
'INCISION_DATETIME' => {title:'Incision Date/Time', coded_entry_method: :incision_time, code: '34896006', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.10.20.24.3.89', field_type: :timestamp},
|
@@ -59,13 +67,15 @@ module HQMF
|
|
59
67
|
'REACTION'=> {title:'Reaction', coded_entry_method: :reaction, code: '263851003', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.10.20.24.3.85', field_type: :value},
|
60
68
|
'REASON' => {title:'Reason', coded_entry_method: :reason, code: '410666004', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.10.20.24.3.88', field_type: :value},
|
61
69
|
'RECORDED_DATETIME' => {title:'Recorded Datetime', coded_entry_method: :start_date, field_type: :timestamp},
|
62
|
-
'REFERENCE_RANGE_HIGH' => {title:'Reference Range High', coded_entry_method: :reference_range_high, field_type: :value},
|
63
|
-
'REFERENCE_RANGE_LOW' => {title:'Reference Range Low', coded_entry_method: :reference_range_low, field_type: :value},
|
70
|
+
'REFERENCE_RANGE_HIGH' => {title:'Reference Range - High', coded_entry_method: :reference_range_high, field_type: :value},
|
71
|
+
'REFERENCE_RANGE_LOW' => {title:'Reference Range - Low', coded_entry_method: :reference_range_low, field_type: :value},
|
64
72
|
'REFILLS' => {title:'Refills', coded_entry_method: :refills, field_type: :value},
|
65
73
|
'RELATED_TO' => {title:'Related To', coded_entry_method: :related_to, code: 'REL', codeSystem: '2.16.840.1.113883.1.11.11603', field_type: :value},
|
66
74
|
'RELATIONSHIP' => {title:'Relationship', coded_entry_method: :relationship_to_patient, field_type: :value},
|
67
75
|
'REMOVAL_DATETIME' => {title:'Removal Date/Time', coded_entry_method: :removal_time, code: '118292001', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1032.1', field_type: :timestamp},
|
68
76
|
# Result isn't encoded
|
77
|
+
# TODO: (LDY 10/4/2016) RESULT_DATETIME is a new attribute in QDM 5.0. We do not yet have codes/template information for this.
|
78
|
+
'RESULT_DATETIME' => {title:'Result Date/Time', coded_entry_method: :result_date_time, field_type: :timestamp},
|
69
79
|
'ROUTE' => {title:'Route', coded_entry_method: :route, code: '263513008', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1020.2', field_type: :value},
|
70
80
|
'SEVERITY' => {title:'Severity', coded_entry_method: :severity, code: 'SEV', code_system:'2.16.840.1.113883.5.4', template_id: '2.16.840.1.113883.10.20.22.4.8', field_type: :value},
|
71
81
|
'SIGNED_DATETIME' => {title:'Signed Date/Time', coded_entry_method: :signed_date_time, field_type: :timestamp},
|
@@ -73,11 +83,14 @@ module HQMF
|
|
73
83
|
# STATUS is referenced in the code as `qdm_status` because entry/Record already has a `status`/`status_code` field which has a different meaning
|
74
84
|
'STATUS' => {title: 'Status', coded_entry_method: :qdm_status, code: '33999-4', code_system:'2.16.840.1.113883.6.1', field_type: :value},
|
75
85
|
'STOP_DATETIME' => {title:'Stop Date/Time', coded_entry_method: :end_date, code: '397898000', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1026.1', field_type: :timestamp},
|
86
|
+
# TODO: (LDY 10/4/2016) SUPPLY is a new attribute in QDM 5.0. We do not yet have codes/template information for this.
|
87
|
+
'SUPPLY' => {title:'Supply', coded_entry_method: :supply, field_type: :value},
|
76
88
|
'TARGET_OUTCOME' => {title:'Target Outcome', coded_entry_method: :target_outcome, code: '385676005', code_system:'2.16.840.1.113883.6.96', template_id: '', field_type: :value},
|
77
89
|
# MISSING Time - The time that the patient passed away
|
78
90
|
|
79
91
|
# Custom field values
|
80
|
-
|
92
|
+
# QDM 5.3 Update: "Related To" replaces Fulfills. We are keeping the fulfills code and only make changes to the UI.
|
93
|
+
'FLFS' => {title:'Related To', coded_entry_method: :fulfills, code: 'FLFS', field_type: :reference},
|
81
94
|
'SOURCE' => {title:'Source', coded_entry_method: :source, code: '260753009', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.2001.2', field_type: :value},
|
82
95
|
'TRANSFER_FROM' => {title:'Transfer From', coded_entry_method: :transfer_from, code: 'TRANSFER_FROM', template_id: '2.16.840.1.113883.10.20.24.3.81', field_type: :value},
|
83
96
|
'TRANSFER_FROM_DATETIME' => {title:'Transfer From Date/Time', coded_entry_method: :transfer_from_time, code: 'ORG_TIME', template_id: '2.16.840.1.113883.10.20.24.3.81', field_type: :nested_timestamp},
|
@@ -431,6 +444,17 @@ module HQMF
|
|
431
444
|
when 'ACT'
|
432
445
|
# Currentlty forcing this as the SimpleXML reresentation contains a fulfills for these types
|
433
446
|
value = HQMF::TypedReference.new(json["reference"], 'FLFS', '')
|
447
|
+
when 'CMP'
|
448
|
+
# For ResultComponent, json will have a value or "" for referenceRangeLow_value, for Component, will be nil
|
449
|
+
if json['referenceRangeLow_value']
|
450
|
+
value = ResultComponent.new(json)
|
451
|
+
else
|
452
|
+
value = Component.new(json)
|
453
|
+
end
|
454
|
+
when 'COL'
|
455
|
+
value = HQMF::Collection.from_json(json)
|
456
|
+
when 'FAC'
|
457
|
+
value = Facility.new(json)
|
434
458
|
else
|
435
459
|
raise "Unknown value type [#{type}]"
|
436
460
|
end
|
data/lib/hqmf-model/document.rb
CHANGED
@@ -9,7 +9,7 @@ module HQMF
|
|
9
9
|
|
10
10
|
include HQMF::Conversion::Utilities
|
11
11
|
|
12
|
-
attr_reader :id, :title, :description, :measure_period, :attributes, :populations, :source_data_criteria, :hqmf_id, :hqmf_set_id, :hqmf_version_number, :cms_id
|
12
|
+
attr_reader :id, :title, :description, :measure_period, :attributes, :populations, :source_data_criteria, :hqmf_id, :hqmf_set_id, :hqmf_version_number, :cms_id, :populations_cql_map, :cql_measure_library, :observations
|
13
13
|
|
14
14
|
# Create a new HQMF::Document which can be converted to JavaScript
|
15
15
|
# @param [String] id
|
@@ -24,7 +24,7 @@ module HQMF
|
|
24
24
|
# @param [Array#Attribute] attributes
|
25
25
|
# @param [Array#Hash] populations
|
26
26
|
# @param [Range] measure_period
|
27
|
-
def initialize(id, hqmf_id, hqmf_set_id, hqmf_version_number, cms_id, title, description, population_criteria, data_criteria, source_data_criteria, attributes, measure_period, populations=nil)
|
27
|
+
def initialize(id, hqmf_id, hqmf_set_id, hqmf_version_number, cms_id, title, description, population_criteria, data_criteria, source_data_criteria, attributes, measure_period, populations=nil, populations_cql_map=nil, cql_measure_library=nil, observations=nil)
|
28
28
|
@id = id
|
29
29
|
@hqmf_id = hqmf_id
|
30
30
|
@hqmf_set_id = hqmf_set_id
|
@@ -46,6 +46,9 @@ module HQMF
|
|
46
46
|
}
|
47
47
|
]
|
48
48
|
@measure_period = measure_period
|
49
|
+
@populations_cql_map = populations_cql_map
|
50
|
+
@cql_measure_library = cql_measure_library
|
51
|
+
@observations = observations
|
49
52
|
end
|
50
53
|
|
51
54
|
# Create a new HQMF::Document from a JSON hash keyed with symbols
|
@@ -104,6 +107,12 @@ module HQMF
|
|
104
107
|
|
105
108
|
json[:populations] = @populations
|
106
109
|
|
110
|
+
json[:populations_cql_map] = @populations_cql_map
|
111
|
+
|
112
|
+
json[:observations] = @observations
|
113
|
+
|
114
|
+
json[:cql_measure_library] = @cql_measure_library
|
115
|
+
|
107
116
|
json[:measure_period] = @measure_period.to_json
|
108
117
|
|
109
118
|
json
|
data/lib/hqmf-model/types.rb
CHANGED
@@ -155,7 +155,6 @@ module HQMF
|
|
155
155
|
class Coded
|
156
156
|
include HQMF::Conversion::Utilities
|
157
157
|
attr_reader :type, :system, :code, :code_list_id, :title, :null_flavor, :original_text
|
158
|
-
|
159
158
|
# Create a new HQMF::Coded
|
160
159
|
# @param [String] type
|
161
160
|
# @param [String] system
|
@@ -285,9 +284,7 @@ module HQMF
|
|
285
284
|
|
286
285
|
def self.from_json(json)
|
287
286
|
type = json["type"] if json["type"]
|
288
|
-
|
289
|
-
value = HQMF::DataCriteria.convert_value(json["value"]) if json["value"]
|
290
|
-
|
287
|
+
value = HQMF::DataCriteria.convert_value(json["value"]) if json["value"]
|
291
288
|
HQMF::SubsetOperator.new(type,value)
|
292
289
|
end
|
293
290
|
|
@@ -428,4 +425,33 @@ module HQMF
|
|
428
425
|
end
|
429
426
|
end
|
430
427
|
|
431
|
-
|
428
|
+
class Collection
|
429
|
+
include HQMF::Conversion::Utilities
|
430
|
+
attr_accessor :type, :values
|
431
|
+
|
432
|
+
def initialize(type, values)
|
433
|
+
@type = type || 'COL'
|
434
|
+
@values = values || []
|
435
|
+
end
|
436
|
+
|
437
|
+
def self.from_json(json)
|
438
|
+
json = json.with_indifferent_access
|
439
|
+
values = []
|
440
|
+
type = json['type']
|
441
|
+
json['values'].each { |value| values.push(HQMF::DataCriteria.convert_value(value))}
|
442
|
+
HQMF::Collection.new(type, values)
|
443
|
+
end
|
444
|
+
|
445
|
+
def to_json
|
446
|
+
json = build_hash(self, [:type])
|
447
|
+
json[:values] = []
|
448
|
+
@values.each {|value| json[:values] << value.to_json }
|
449
|
+
json
|
450
|
+
end
|
451
|
+
|
452
|
+
def ==(other)
|
453
|
+
check_equality(self,other)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
end
|
data/lib/hqmf-parser.rb
CHANGED
@@ -36,6 +36,13 @@ require_relative 'hqmf-parser/2.0/data_criteria'
|
|
36
36
|
require_relative 'hqmf-parser/2.0/population_criteria'
|
37
37
|
require_relative 'hqmf-parser/2.0/precondition'
|
38
38
|
|
39
|
+
require_relative 'hqmf-parser/cql/document'
|
40
|
+
require_relative 'hqmf-parser/cql/data_criteria_helpers/dc_definition_from_template_or_type_extract'
|
41
|
+
require_relative 'hqmf-parser/cql/document_helpers/doc_population_helper'
|
42
|
+
require_relative 'hqmf-parser/cql/data_criteria_helpers/dc_post_processing'
|
43
|
+
require_relative 'hqmf-parser/cql/data_criteria'
|
44
|
+
require_relative 'hqmf-parser/cql/value_set_helper'
|
45
|
+
|
39
46
|
require_relative 'hqmf-model/data_criteria.rb'
|
40
47
|
require_relative 'hqmf-model/document.rb'
|
41
48
|
require_relative 'hqmf-model/population_criteria.rb'
|
@@ -148,7 +148,10 @@ module HQMF2
|
|
148
148
|
# not give us the correct SDC data when we are trying to recreate since we are looping back through
|
149
149
|
# the same data criteria before it has finished processing: See: DocUtilities.extract_source_data_criteria
|
150
150
|
def clone
|
151
|
-
|
151
|
+
# Using 'self.class.new' in order to allow this DataCriteria class as
|
152
|
+
# well as any future new extending DataCriteria classes to use this clone
|
153
|
+
# function.
|
154
|
+
other = self.class.new(@entry, @data_criteria_references, @occurrences_map)
|
152
155
|
other.instance_variable_set(:@id, @id)
|
153
156
|
other.instance_variable_set(:@original_id, @original_id)
|
154
157
|
other.instance_variable_set(:@property, @property)
|
@@ -67,7 +67,7 @@ module HQMF2
|
|
67
67
|
|
68
68
|
# Extract the negation (and the negation_code_list_id if appropriate)
|
69
69
|
def extract_negation
|
70
|
-
negation = (attr_val('./*/@actionNegationInd') == 'true')
|
70
|
+
negation = (attr_val('./*/@actionNegationInd').to_s.downcase == 'true')
|
71
71
|
negation_code_list_id = nil
|
72
72
|
if negation
|
73
73
|
res = @entry.at_xpath('./*/cda:outboundRelationship/*/cda:code[@code="410666004"]/../cda:value/@valueSet',
|
@@ -191,8 +191,8 @@ module HQMF2
|
|
191
191
|
value_obj = nil
|
192
192
|
value_obj = handle_attribute_value(attribute, value) if attribute.at_xpath('./cda:value', NAMESPACES)
|
193
193
|
|
194
|
-
# Handle the cms_id
|
195
|
-
@cms_id = "CMS#{value}v#{@hqmf_version_number.to_i}" if name.include? 'eMeasure Identifier'
|
194
|
+
# Handle the cms_id - changed to eCQM in MAT 5.4 (QDM 5.3)
|
195
|
+
@cms_id = "CMS#{value}v#{@hqmf_version_number.to_i}" if (name.include? 'eMeasure Identifier') || (name.include? 'eCQM Identifier')
|
196
196
|
|
197
197
|
HQMF::Attribute.new(id, code, value, nil, name, id_obj, code_obj, value_obj)
|
198
198
|
end
|
@@ -283,7 +283,7 @@ module HQMF2
|
|
283
283
|
end
|
284
284
|
end
|
285
285
|
end
|
286
|
-
|
286
|
+
|
287
287
|
# For specific occurrence data criteria, make sure the source data criteria reference points
|
288
288
|
# to the correct source data criteria.
|
289
289
|
def handle_specific_source_data_criteria_reference(criteria)
|
@@ -299,6 +299,6 @@ module HQMF2
|
|
299
299
|
original_sdc.instance_variable_set(:@code_list_id, criteria.code_list_id)
|
300
300
|
end
|
301
301
|
end
|
302
|
-
|
302
|
+
|
303
303
|
end
|
304
304
|
end
|
@@ -51,7 +51,6 @@ module HQMF2
|
|
51
51
|
|
52
52
|
population['OBSERV'] = 'OBSERV' if has_observation
|
53
53
|
@populations << population
|
54
|
-
|
55
54
|
handle_stratifications(population_def, number_of_populations, population, id_def, population_index)
|
56
55
|
end
|
57
56
|
|
@@ -116,7 +115,6 @@ module HQMF2
|
|
116
115
|
# Skip this Stratification if any precondition doesn't contain any preconditions
|
117
116
|
next unless PopulationCriteria.new(criteria_def, @document, @id_generator)
|
118
117
|
.preconditions.all? { |prcn| prcn.preconditions.length > 0 }
|
119
|
-
|
120
118
|
index = number_of_populations + ((population_index - 1) * criteria_def.xpath('./*/cda:precondition').length) +
|
121
119
|
criteria_def_index
|
122
120
|
criteria_id = HQMF::PopulationCriteria::STRAT
|
@@ -34,7 +34,7 @@ module HQMF2
|
|
34
34
|
else
|
35
35
|
# Extract the data criteria this population references
|
36
36
|
dc = handle_observation_criteria
|
37
|
-
@preconditions = [Precondition.new(id_generator.next_id, nil, nil, false, HQMF2::Reference.new(dc.id))]
|
37
|
+
@preconditions = [Precondition.new(id_generator.next_id, nil, nil, false, HQMF2::Reference.new(dc.id))] if dc
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
@@ -76,7 +76,7 @@ module HQMF2
|
|
76
76
|
dc = parse_parts_to_dc(parts)
|
77
77
|
@doc.add_data_criteria(dc)
|
78
78
|
# Update reference_ids with any newly referenced data criteria
|
79
|
-
dc.children_criteria.each { |cc| @doc.add_reference_id(cc) } unless dc
|
79
|
+
dc.children_criteria.each { |cc| @doc.add_reference_id(cc) } unless dc&.children_criteria.nil?
|
80
80
|
dc
|
81
81
|
end
|
82
82
|
|
@@ -90,7 +90,10 @@ module HQMF2
|
|
90
90
|
'2.16.840.1.113883.10.20.28.3.115' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role/cda:playingMaterial[@classCode='MMAT']/cda:code", result_path: nil },
|
91
91
|
'2.16.840.1.113883.10.20.28.3.116' => { valueset_path: './*/cda:value', result_path: nil },
|
92
92
|
'2.16.840.1.113883.10.20.28.3.117' => { valueset_path: './*/cda:code', result_path: './*/cda:value' },
|
93
|
-
'2.16.840.1.113883.10.20.28.3.118' => { valueset_path: './*/cda:code', result_path: nil }
|
93
|
+
'2.16.840.1.113883.10.20.28.3.118' => { valueset_path: './*/cda:code', result_path: nil },
|
94
|
+
'2.16.840.1.113883.10.20.28.3.119' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingEntity[@classCode='MMAT']/cda:code", result_path: nil },
|
95
|
+
'2.16.840.1.113883.10.20.28.3.120' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingEntity[@classCode='MMAT']/cda:code", result_path: nil }
|
96
|
+
|
94
97
|
}
|
95
98
|
# rubocop:enable Metrics/LineLength
|
96
99
|
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module HQMF2CQL
|
2
|
+
# Represents a data criteria specification
|
3
|
+
class DataCriteria < HQMF2::DataCriteria
|
4
|
+
include HQMF2CQL::DataCriteriaPostProcessing, HQMF2CQL::DataCriteriaTypeAndDefinitionExtraction
|
5
|
+
|
6
|
+
# Get the title of the criteria, provides a human readable description
|
7
|
+
# @return [String] the title of this data criteria
|
8
|
+
def title
|
9
|
+
disp_value = attr_val("#{@code_list_xpath}/cda:displayName/@value")
|
10
|
+
# Attempt to pull display value from the localVariableName for
|
11
|
+
# MAT 5.3+ exports that appear to no longer include displayName for
|
12
|
+
# code entries.
|
13
|
+
# NOTE: A long term replacement for this and for other portions of the
|
14
|
+
# parsing process should involve reaching out to VSAC for oid information
|
15
|
+
# pulled from the CQL, and then to use that information while parsing.
|
16
|
+
unless disp_value.present?
|
17
|
+
# Grab the localVariableName from the XML
|
18
|
+
disp_value = attr_val('./cda:localVariableName/@value')
|
19
|
+
# Grab everything before the first underscore
|
20
|
+
disp_value = disp_value.partition('_').first unless disp_value.nil?
|
21
|
+
end
|
22
|
+
@title || disp_value || @description || id # allow defined titles to take precedence
|
23
|
+
end
|
24
|
+
|
25
|
+
# Generate the title and description used when producing the model
|
26
|
+
def retrieve_title_and_description_for_model
|
27
|
+
# remove * Value Set from title
|
28
|
+
title_match = title.match(/(.*) \w+ [Vv]alue [Ss]et/)
|
29
|
+
@title = title_match[1] if title_match && title_match.length > 1
|
30
|
+
|
31
|
+
@description = "#{@description}: #{title}"
|
32
|
+
end
|
33
|
+
|
34
|
+
# In certain situations it is necessary to have a negated data criterion
|
35
|
+
# copied to a "positive" form.
|
36
|
+
def make_criterion_positive
|
37
|
+
@negation = false
|
38
|
+
|
39
|
+
# Remove negation from description
|
40
|
+
# sometimes "Not Done" used: "Communication: From Provider To Patient, Not Done"
|
41
|
+
# should transform to "Communication: From Provider To Patient"
|
42
|
+
@description.gsub!(', Not Done', '')
|
43
|
+
|
44
|
+
# sometimes just "Not" used: "Encounter, Not Performed"
|
45
|
+
# should transform to "Encounter, Performed"
|
46
|
+
@description.gsub!(', Not', ',')
|
47
|
+
|
48
|
+
@source_data_criteria = 'Derived from ' + @source_data_criteria
|
49
|
+
|
50
|
+
# Looking to remove the word 'Not'. Using lookahead and lookbehind in the regex
|
51
|
+
# criterion.id = criterion.id.gsub(/(?<=[a-z])Not(?=[A-Z])/, '') + '_spoof'
|
52
|
+
@id = @id.gsub(/(?<=[a-z])Not(?=[A-Z])/, '') + '_spoofed'
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module HQMF2CQL
|
2
|
+
# Extracts the type, and modifies the data criteria, based on the template id or definition
|
3
|
+
module DataCriteriaTypeAndDefinitionExtraction
|
4
|
+
extend HQMF2::DataCriteriaTypeAndDefinitionExtraction
|
5
|
+
|
6
|
+
def extract_definition_from_template_or_type
|
7
|
+
# Try to determine what kind of data criteria we are dealing with
|
8
|
+
# First we look for a template id and if we find one just use the definition
|
9
|
+
# status and negation associated with that
|
10
|
+
# If no template id or not one we recognize then try to determine type from
|
11
|
+
# the definition element.
|
12
|
+
extract_definition_from_type unless extract_definition_from_template_id
|
13
|
+
end
|
14
|
+
|
15
|
+
# Given a template id, derive (if available) the definition for the template.
|
16
|
+
# The definitions are stored in hqmf-model/data_criteria.json.
|
17
|
+
def extract_definition_from_template_id
|
18
|
+
found = false
|
19
|
+
|
20
|
+
@template_ids.each do |template_id|
|
21
|
+
# NOTE! (Adam 6/14): The following logic should absolutely be changed
|
22
|
+
# when Bonnie CQL support goes production. The "try this then try
|
23
|
+
# that" approach is an artifact of the template oids changing as of
|
24
|
+
# MAT 5.3; we want to support measures exported using 5.3, but also
|
25
|
+
# measures that were exported using previous versions of the MAT.
|
26
|
+
|
27
|
+
# Try a lookup using the newer template oids.
|
28
|
+
defs = HQMF::DataCriteria.definition_for_template_id(template_id, 'r2cql')
|
29
|
+
|
30
|
+
# If the new template oids didn't work, try a lookup using the older
|
31
|
+
# template oids.
|
32
|
+
defs = HQMF::DataCriteria.definition_for_template_id(template_id, 'r2') unless defs
|
33
|
+
|
34
|
+
if defs
|
35
|
+
@definition = defs['definition']
|
36
|
+
@status = defs['status'].length > 0 ? defs['status'] : nil
|
37
|
+
found ||= true
|
38
|
+
else
|
39
|
+
found ||= handle_known_template_id(template_id)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
found
|
44
|
+
end
|
45
|
+
|
46
|
+
# Extract the definition (sometimes status, sometimes other elements) of the data criteria based on the type
|
47
|
+
def extract_definition_from_type
|
48
|
+
if @entry.at_xpath('./cda:grouperCriteria')
|
49
|
+
@definition ||= 'derived'
|
50
|
+
return
|
51
|
+
end
|
52
|
+
# See if we can find a match for the entry definition value and status.
|
53
|
+
entry_type = attr_val('./*/cda:definition/*/cda:id/@extension')
|
54
|
+
handle_entry_type(entry_type)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Generate the definition and/or status from the entry type in most cases.
|
58
|
+
# If the entry type is nil, and the value is a specific occurrence, more parsing may be necessary.
|
59
|
+
def handle_entry_type(entry_type)
|
60
|
+
# settings is required to trigger exceptions, which set the definition
|
61
|
+
HQMF::DataCriteria.get_settings_for_definition(entry_type, @status)
|
62
|
+
@definition = entry_type
|
63
|
+
rescue
|
64
|
+
# if no exact match then try a string match just using entry definition value
|
65
|
+
case entry_type
|
66
|
+
when 'Medication', 'Medications'
|
67
|
+
@definition = 'medication'
|
68
|
+
@status = 'active' unless @status
|
69
|
+
when 'RX'
|
70
|
+
@definition = 'medication'
|
71
|
+
@status = 'dispensed' unless @status
|
72
|
+
when nil
|
73
|
+
definition_for_nil_entry
|
74
|
+
else
|
75
|
+
@definition = extract_definition_from_entry_type(entry_type)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|