health-data-standards 3.7.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|