cqm-parsers 0.1.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 +7 -0
- data/Gemfile +29 -0
- data/README.md +21 -0
- data/Rakefile +19 -0
- data/lib/ext/code.rb +10 -0
- data/lib/ext/data_element.rb +24 -0
- data/lib/hqmf-model/attribute.rb +63 -0
- data/lib/hqmf-model/data_criteria.rb +467 -0
- data/lib/hqmf-model/document.rb +253 -0
- data/lib/hqmf-model/population_criteria.rb +102 -0
- data/lib/hqmf-model/precondition.rb +94 -0
- data/lib/hqmf-model/types.rb +457 -0
- data/lib/hqmf-model/utilities.rb +52 -0
- data/lib/hqmf-parser.rb +116 -0
- data/lib/hqmf-parser/1.0/attribute.rb +121 -0
- data/lib/hqmf-parser/1.0/comparison.rb +34 -0
- data/lib/hqmf-parser/1.0/data_criteria.rb +92 -0
- data/lib/hqmf-parser/1.0/document.rb +195 -0
- data/lib/hqmf-parser/1.0/expression.rb +60 -0
- data/lib/hqmf-parser/1.0/observation.rb +61 -0
- data/lib/hqmf-parser/1.0/population_criteria.rb +75 -0
- data/lib/hqmf-parser/1.0/precondition.rb +90 -0
- data/lib/hqmf-parser/1.0/range.rb +76 -0
- data/lib/hqmf-parser/1.0/restriction.rb +162 -0
- data/lib/hqmf-parser/1.0/utilities.rb +55 -0
- data/lib/hqmf-parser/2.0/data_criteria.rb +372 -0
- data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_base_extract.rb +80 -0
- data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_definition_from_template_or_type_extract.rb +201 -0
- data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_post_processing.rb +85 -0
- data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_specific_occurrences_and_source_data_criteria_extract.rb +117 -0
- data/lib/hqmf-parser/2.0/document.rb +304 -0
- data/lib/hqmf-parser/2.0/document_helpers/doc_population_helper.rb +173 -0
- data/lib/hqmf-parser/2.0/document_helpers/doc_utilities.rb +131 -0
- data/lib/hqmf-parser/2.0/field_value_helper.rb +251 -0
- data/lib/hqmf-parser/2.0/population_criteria.rb +134 -0
- data/lib/hqmf-parser/2.0/precondition.rb +73 -0
- data/lib/hqmf-parser/2.0/source_data_criteria_helper.rb +112 -0
- data/lib/hqmf-parser/2.0/types.rb +448 -0
- data/lib/hqmf-parser/2.0/utilities.rb +45 -0
- data/lib/hqmf-parser/2.0/value_set_helper.rb +104 -0
- data/lib/hqmf-parser/converter/pass1/data_criteria_converter.rb +257 -0
- data/lib/hqmf-parser/converter/pass1/document_converter.rb +133 -0
- data/lib/hqmf-parser/converter/pass1/population_criteria_converter.rb +185 -0
- data/lib/hqmf-parser/converter/pass1/precondition_converter.rb +173 -0
- data/lib/hqmf-parser/converter/pass1/precondition_extractor.rb +201 -0
- data/lib/hqmf-parser/converter/pass1/simple_data_criteria.rb +26 -0
- data/lib/hqmf-parser/converter/pass1/simple_operator.rb +89 -0
- data/lib/hqmf-parser/converter/pass1/simple_population_criteria.rb +10 -0
- data/lib/hqmf-parser/converter/pass1/simple_precondition.rb +51 -0
- data/lib/hqmf-parser/converter/pass1/simple_restriction.rb +64 -0
- data/lib/hqmf-parser/converter/pass2/comparison_converter.rb +112 -0
- data/lib/hqmf-parser/converter/pass2/operator_converter.rb +102 -0
- 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 +100 -0
- data/lib/qrda-export/catI-r5/qrda1_r5.rb +125 -0
- data/lib/qrda-export/helper/cat_1_view_helper.rb +142 -0
- data/lib/qrda-export/helper/code_system_helper.rb +77 -0
- data/lib/qrda-export/helper/date_helper.rb +81 -0
- data/lib/qrda-import/base-importers/demographics_importer.rb +47 -0
- data/lib/qrda-import/base-importers/medication_importer.rb +22 -0
- data/lib/qrda-import/base-importers/section_importer.rb +196 -0
- data/lib/qrda-import/cda_identifier.rb +19 -0
- data/lib/qrda-import/data-element-importers/adverse_event_importer.rb +23 -0
- data/lib/qrda-import/data-element-importers/allergy_intolerance_importer.rb +21 -0
- data/lib/qrda-import/data-element-importers/assessment_performed_importer.rb +23 -0
- data/lib/qrda-import/data-element-importers/communication_from_patient_to_provider_importer.rb +18 -0
- data/lib/qrda-import/data-element-importers/communication_from_provider_to_patient_importer.rb +18 -0
- data/lib/qrda-import/data-element-importers/communication_from_provider_to_provider_importer.rb +20 -0
- data/lib/qrda-import/data-element-importers/device_applied_importer.rb +23 -0
- data/lib/qrda-import/data-element-importers/device_order_importer.rb +18 -0
- data/lib/qrda-import/data-element-importers/diagnosis_importer.rb +23 -0
- data/lib/qrda-import/data-element-importers/diagnostic_study_order_importer.rb +20 -0
- data/lib/qrda-import/data-element-importers/diagnostic_study_performed_importer.rb +30 -0
- data/lib/qrda-import/data-element-importers/encounter_order_importer.rb +20 -0
- data/lib/qrda-import/data-element-importers/encounter_performed_importer.rb +41 -0
- data/lib/qrda-import/data-element-importers/immunization_administered_importer.rb +18 -0
- data/lib/qrda-import/data-element-importers/intervention_order_importer.rb +18 -0
- data/lib/qrda-import/data-element-importers/intervention_performed_importer.rb +22 -0
- data/lib/qrda-import/data-element-importers/laboratory_test_order_importer.rb +20 -0
- data/lib/qrda-import/data-element-importers/laboratory_test_performed_importer.rb +28 -0
- data/lib/qrda-import/data-element-importers/medication_active_importer.rb +17 -0
- data/lib/qrda-import/data-element-importers/medication_administered_importer.rb +17 -0
- data/lib/qrda-import/data-element-importers/medication_discharge_importer.rb +19 -0
- data/lib/qrda-import/data-element-importers/medication_dispensed_importer.rb +19 -0
- data/lib/qrda-import/data-element-importers/medication_order_importer.rb +16 -0
- data/lib/qrda-import/data-element-importers/patient_characteristic_expired.rb +21 -0
- data/lib/qrda-import/data-element-importers/physical_exam_performed_importer.rb +26 -0
- data/lib/qrda-import/data-element-importers/procedure_order_importer.rb +26 -0
- data/lib/qrda-import/data-element-importers/procedure_performed_importer.rb +34 -0
- data/lib/qrda-import/data-element-importers/substance_administered_importer.rb +16 -0
- data/lib/qrda-import/entry_finder.rb +20 -0
- data/lib/qrda-import/entry_package.rb +16 -0
- data/lib/qrda-import/narrative_reference_handler.rb +33 -0
- data/lib/qrda-import/patient_importer.rb +105 -0
- data/lib/util/code_system_helper.rb +76 -0
- data/lib/util/counter.rb +20 -0
- data/lib/util/hqmf_template_helper.rb +39 -0
- metadata +340 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 6f44d77fe47f440f802946c4fc454de11d4fd69e
|
|
4
|
+
data.tar.gz: e1f87b52ea314452ade5bfd6c4ef5cc17c819384
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6feea91c08a04843dfad7119461b608986650fea25f69723a186397dc378727d0c5689e53ae56405f0762bb2f2320a12ee0f27c6b9b37c7243cc5b56760b7cb2
|
|
7
|
+
data.tar.gz: 1ed3943b864ec0c33c1041bf1c27d402e960e7f850eb5a494d6d84cc9217eb1ae266a339c6d83e1d200a235070f793ee1cc174b5b21996def39a04f910af0451
|
data/Gemfile
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
source "https://rubygems.org"
|
|
2
|
+
|
|
3
|
+
gemspec :development_group => :test
|
|
4
|
+
|
|
5
|
+
gem 'mustache'
|
|
6
|
+
gem 'cqm-models', '~> 0.8.2'
|
|
7
|
+
gem 'mongoid', '~> 5.0.0'
|
|
8
|
+
|
|
9
|
+
group :development, :test do
|
|
10
|
+
gem 'bundler-audit'
|
|
11
|
+
gem 'rubocop', '~> 0.52.1', require: false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
group :development do
|
|
15
|
+
gem 'rake'
|
|
16
|
+
gem 'byebug', '~> 6.0.2', platforms: [:ruby_20, :ruby_21, :ruby_22, :ruby_23]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
group :test do
|
|
20
|
+
gem 'factory_girl', '~> 4.1.0'
|
|
21
|
+
gem "tailor", '~> 1.1.2'
|
|
22
|
+
gem "cane", '~> 2.3.0'
|
|
23
|
+
gem 'simplecov', :require => false
|
|
24
|
+
gem 'webmock'
|
|
25
|
+
gem 'minitest', '~> 5.3'
|
|
26
|
+
gem 'minitest-reporters'
|
|
27
|
+
gem 'awesome_print', :require => 'ap'
|
|
28
|
+
gem 'simplexml_parser', :git => 'https://github.com/projecttacoma/simplexml_parser.git', :branch => 'master'
|
|
29
|
+
end
|
data/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
cqm-parsers
|
|
2
|
+
===========
|
|
3
|
+
|
|
4
|
+
This project contains libraries for parsing HQMF documents.
|
|
5
|
+
|
|
6
|
+
License
|
|
7
|
+
=======
|
|
8
|
+
|
|
9
|
+
Copyright 2018 The MITRE Corporation
|
|
10
|
+
|
|
11
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
+
you may not use this file except in compliance with the License.
|
|
13
|
+
You may obtain a copy of the License at
|
|
14
|
+
|
|
15
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
+
|
|
17
|
+
Unless required by applicable law or agreed to in writing, software
|
|
18
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
+
See the License for the specific language governing permissions and
|
|
21
|
+
limitations under the License.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'rake/testtask'
|
|
2
|
+
require 'cane/rake_task'
|
|
3
|
+
require "simplecov"
|
|
4
|
+
|
|
5
|
+
import 'lib/tasks/hqmf.rake'
|
|
6
|
+
|
|
7
|
+
Rake::TestTask.new(:test_unit) do |t|
|
|
8
|
+
t.libs << "test"
|
|
9
|
+
t.test_files = FileList['test/**/*_test.rb']
|
|
10
|
+
t.verbose = false
|
|
11
|
+
t.warning = false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
task :test => [:test_unit] do
|
|
17
|
+
|
|
18
|
+
system("open coverage/index.html")
|
|
19
|
+
end
|
data/lib/ext/code.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module QDM
|
|
2
|
+
class DataElement
|
|
3
|
+
def merge!(other)
|
|
4
|
+
# ensure they're the same category (e.g. 'encounter')
|
|
5
|
+
return unless category == other.category
|
|
6
|
+
|
|
7
|
+
# ensure they're the same status (e.g. 'performed'), and that they both have a status set (or that they both don't)
|
|
8
|
+
return if respond_to?(:qdmStatus) && !other.respond_to?(:qdmStatus)
|
|
9
|
+
return if !respond_to?(:qdmStatus) && other.respond_to?(:qdmStatus)
|
|
10
|
+
return if respond_to?(:qdmStatus) && other.respond_to?(:qdmStatus) && qdmStatus != other.qdmStatus
|
|
11
|
+
|
|
12
|
+
# iterate over non-code fields
|
|
13
|
+
fields.each_key do |field|
|
|
14
|
+
next if field[0] == '_' || %w[dataElementCodes category qdmVersion qdmStatus].include?(field)
|
|
15
|
+
|
|
16
|
+
if send(field).nil?
|
|
17
|
+
send(field + '=', other.send(field))
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
self.dataElementCodes = dataElementCodes.concat(other.dataElementCodes).uniq
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module HQMF
|
|
2
|
+
class Attribute
|
|
3
|
+
include HQMF::Conversion::Utilities
|
|
4
|
+
attr_reader :id,:code,:value,:unit,:name,:id_obj,:code_obj,:value_obj
|
|
5
|
+
# @param [String] id
|
|
6
|
+
# @param [String] code
|
|
7
|
+
# @param [String] value
|
|
8
|
+
# @param [String] unit
|
|
9
|
+
# @param [String] name
|
|
10
|
+
# @param [HQMF::Identifier] id_obj
|
|
11
|
+
# @param [HQMF::Coded] code_obj
|
|
12
|
+
# @param [Object] value_obj
|
|
13
|
+
def initialize(id,code,value,unit,name,id_obj=nil,code_obj=nil,value_obj=nil)
|
|
14
|
+
@id = id
|
|
15
|
+
@code = code
|
|
16
|
+
@value = value
|
|
17
|
+
@unit = unit
|
|
18
|
+
@name = name
|
|
19
|
+
# enhanced model
|
|
20
|
+
@id_obj = id_obj
|
|
21
|
+
@code_obj = code_obj
|
|
22
|
+
@value_obj = value_obj
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.from_json(json)
|
|
26
|
+
json = json.with_indifferent_access
|
|
27
|
+
|
|
28
|
+
id = json["id"] if json["id"]
|
|
29
|
+
code = json["code"] if json["code"]
|
|
30
|
+
value = json["value"] if json["value"]
|
|
31
|
+
unit = json["unit"] if json["unit"]
|
|
32
|
+
name = json["name"] if json["name"]
|
|
33
|
+
# enhanced model
|
|
34
|
+
id_obj = HQMF::Identifier::from_json(json["id_obj"]) if json["id_obj"]
|
|
35
|
+
code_obj = HQMF::Coded::from_json(json["code_obj"]) if json["code_obj"]
|
|
36
|
+
value_obj = nil
|
|
37
|
+
if (json["value_obj"])
|
|
38
|
+
json_value = json["value_obj"].with_indifferent_access
|
|
39
|
+
case json_value["type"]
|
|
40
|
+
when 'II'
|
|
41
|
+
value_obj = HQMF::Identifier::from_json(json_value)
|
|
42
|
+
when 'CD'
|
|
43
|
+
value_obj = HQMF::Coded::from_json(json_value)
|
|
44
|
+
when 'ED'
|
|
45
|
+
value_obj = HQMF::ED::from_json(json_value)
|
|
46
|
+
else
|
|
47
|
+
value_obj = json_value["value"].nil? ? HQMF::AnyValue::from_json(json_value) : HQMF::GenericValueContainer::from_json(json_value)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
HQMF::Attribute.new(id,code,value,unit,name,id_obj,code_obj,value_obj)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def to_json
|
|
55
|
+
json = build_hash(self, [:id,:code,:value,:unit,:name])
|
|
56
|
+
json[:id_obj] = @id_obj.to_json if @id_obj
|
|
57
|
+
json[:code_obj] = @code_obj.to_json if @code_obj
|
|
58
|
+
json[:value_obj] = @value_obj.to_json if @value_obj
|
|
59
|
+
json
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
module HQMF
|
|
2
|
+
# Represents a data criteria specification
|
|
3
|
+
class DataCriteria
|
|
4
|
+
|
|
5
|
+
include HQMF::Conversion::Utilities
|
|
6
|
+
|
|
7
|
+
SOURCE_DATA_CRITERIA_TEMPLATE_ID = '2.16.840.1.113883.3.100.1.1'
|
|
8
|
+
SOURCE_DATA_CRITERIA_TEMPLATE_TITLE = 'Source data criteria'
|
|
9
|
+
|
|
10
|
+
XPRODUCT = 'XPRODUCT'
|
|
11
|
+
UNION = 'UNION'
|
|
12
|
+
INTERSECT = 'INTERSECT'
|
|
13
|
+
|
|
14
|
+
SATISFIES_ALL = 'satisfies_all'
|
|
15
|
+
SATISFIES_ANY = 'satisfies_any'
|
|
16
|
+
VARIABLE = 'variable'
|
|
17
|
+
|
|
18
|
+
# An object containing metadata information for all attributes that are used within the measure data criteria being parsed.
|
|
19
|
+
#
|
|
20
|
+
# fields include:
|
|
21
|
+
# `title`: The QDM human readable title for the attribute.
|
|
22
|
+
# `coded_entry_method`: this appears to be a way that fields here are referenced within Bonnie.
|
|
23
|
+
# `field_type`: The type of whatever will be stored for this attribute. This will often be `:timestamp` or `:value`.
|
|
24
|
+
# `code`: The code for the entry. This should be included to make HQMF generation work properly. This is whatever code is dictated in the HQMF. For Diagnosis, this is in [HQMF QDM IG](http://www.hl7.org/implement/standards/product_brief.cfm?product_id=346) vol 2 page 155 and is `29308-4`.
|
|
25
|
+
# `code_system`: This is the oid for whatever code system contains `code`. For Diagnosis, this is LOINC: `2.16.840.1.113883.6.1`. This is also located at (http://www.hl7.org/implement/standards/product_brief.cfm?product_id=346) vol 2 page 155.
|
|
26
|
+
# `template_id`: These appear to be related to HQMFr1 template ids. These appear to be dangerously out of date. Don't use.
|
|
27
|
+
FIELDS = {'ABATEMENT_DATETIME' => {title:'Abatement Datetime', coded_entry_method: :end_date, field_type: :timestamp},
|
|
28
|
+
'ACTIVE_DATETIME' => {title:'Active Date/Time', coded_entry_method: :active_date_time, field_type: :timestamp},
|
|
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},
|
|
33
|
+
'ANATOMICAL_APPROACH_SITE' => {title:'Anatomical Approach Site', coded_entry_method: :anatomical_approach, field_type: :value},
|
|
34
|
+
'ANATOMICAL_LOCATION_SITE' => {title:'Anatomical Location Site', coded_entry_method: :anatomical_location, field_type: :value},
|
|
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},
|
|
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},
|
|
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},
|
|
40
|
+
# MISSING Date - The date that the patient passed away. - Patient Characteristic Expired
|
|
41
|
+
'DIAGNOSIS' => {title:'Diagnosis', coded_entry_method: :diagnosis, field_type: :value},
|
|
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},
|
|
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},
|
|
47
|
+
'FACILITY_LOCATION' => {title:'Facility Location', coded_entry_method: :facility, code: 'SDLOC', field_type: :value},
|
|
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},
|
|
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},
|
|
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},
|
|
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},
|
|
54
|
+
'LATERALITY' => {title:'Laterality', coded_entry_method: :laterality, code: '272741003', code_system:'2.16.840.1.113883.6.96', template_id: '', field_type: :value},
|
|
55
|
+
'LENGTH_OF_STAY' => {title:'Length of Stay', coded_entry_method: :length_of_stay, code: '183797002', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1029.3', field_type: :value},
|
|
56
|
+
'METHOD' => {title:'Method', coded_entry_method: :method, template_id: '', field_type: :value},
|
|
57
|
+
# Negation Rationale isn't encoded
|
|
58
|
+
'ONSET_AGE' => {title:'Onset Age', coded_entry_method: :onset_age, code: '445518008', code_system:'2.16.840.1.113883.6.96', template_id: '', field_type: :value},
|
|
59
|
+
'ONSET_DATETIME' => {title:'Onset Datetime', coded_entry_method: :start_date, field_type: :timestamp},
|
|
60
|
+
'ORDINAL' => {title:'Ordinality', coded_entry_method: :ordinality, code: '117363000', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1012.2', field_type: :value}, # previous
|
|
61
|
+
'ORDINALITY' => {title:'Ordinality', coded_entry_method: :ordinality, code: '117363000', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1012.2', field_type: :value},
|
|
62
|
+
'PATIENT_PREFERENCE' => {title:'Patient Preference', coded_entry_method: :patient_preference, code: 'PAT', code_system: '2.16.840.1.113883.5.8', template_id: '2.16.840.1.113883.10.20.24.3.83', field_type: :value},
|
|
63
|
+
'PRINCIPAL_DIAGNOSIS' => {title:'Principal Diagnosis', coded_entry_method: :principal_diagnosis, field_type: :value},
|
|
64
|
+
'PROVIDER_PREFERENCE' => {title:'Provider Preference', coded_entry_method: :provider_preference, code: '103323008', code_system: '2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.10.20.24.3.84', field_type: :value},
|
|
65
|
+
'RADIATION_DOSAGE' => {title:'Radiation Dosage', coded_entry_method: :radiation_dose, code: '228815006', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.10.20.24.3.91', field_type: :value},
|
|
66
|
+
'RADIATION_DURATION' => {title:'Radiation Duration', coded_entry_method: :radiation_duration, code: '306751006', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.10.20.24.3.91', field_type: :value},
|
|
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},
|
|
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},
|
|
69
|
+
'RECORDED_DATETIME' => {title:'Recorded Datetime', coded_entry_method: :start_date, field_type: :timestamp},
|
|
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},
|
|
72
|
+
'REFILLS' => {title:'Refills', coded_entry_method: :refills, field_type: :value},
|
|
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},
|
|
74
|
+
'RELATIONSHIP' => {title:'Relationship', coded_entry_method: :relationship_to_patient, field_type: :value},
|
|
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},
|
|
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},
|
|
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},
|
|
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},
|
|
81
|
+
'SIGNED_DATETIME' => {title:'Signed Date/Time', coded_entry_method: :signed_date_time, field_type: :timestamp},
|
|
82
|
+
'START_DATETIME' => {title:'Start Date/Time', coded_entry_method: :start_date, code: '398201009', code_system:'2.16.840.1.113883.6.96', template_id: '2.16.840.1.113883.3.560.1.1027.1', field_type: :timestamp},
|
|
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
|
|
84
|
+
'STATUS' => {title: 'Status', coded_entry_method: :qdm_status, code: '33999-4', code_system:'2.16.840.1.113883.6.1', field_type: :value},
|
|
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},
|
|
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},
|
|
89
|
+
# MISSING Time - The time that the patient passed away
|
|
90
|
+
|
|
91
|
+
# Custom field values
|
|
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},
|
|
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},
|
|
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},
|
|
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},
|
|
97
|
+
'TRANSFER_TO' => {title:'Transfer To', coded_entry_method: :transfer_to, code: 'TRANSFER_TO', template_id: '2.16.840.1.113883.10.20.24.3.82', field_type: :value},
|
|
98
|
+
'TRANSFER_TO_DATETIME' => {title:'Transfer To Date/Time', coded_entry_method: :transfer_to_time, code: 'DST_TIME', template_id: '2.16.840.1.113883.10.20.24.3.82', field_type: :nested_timestamp}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# maps attribute codes to the attribute keys
|
|
102
|
+
VALUE_FIELDS = {'399423000' => 'ADMISSION_DATETIME',
|
|
103
|
+
'42752001' => 'CAUSE',
|
|
104
|
+
'261773006' => 'CUMULATIVE_MEDICATION_DURATION',
|
|
105
|
+
'363819003' => 'CUMULATIVE_MEDICATION_DURATION', # previous
|
|
106
|
+
'442864001' => 'DISCHARGE_DATETIME',
|
|
107
|
+
'309039003' => 'DISCHARGE_STATUS',
|
|
108
|
+
'398232005' => 'DOSE',
|
|
109
|
+
'SDLOC' => 'FACILITY_LOCATION',
|
|
110
|
+
'SDLOC_ARRIVAL' => 'FACILITY_LOCATION_ARRIVAL_DATETIME',
|
|
111
|
+
'SDLOC_DEPARTURE' => 'FACILITY_LOCATION_DEPARTURE_DATETIME',
|
|
112
|
+
'307430002' => 'FREQUENCY',
|
|
113
|
+
'260864003' => 'FREQUENCY', # previous
|
|
114
|
+
'395676008' => 'HEALTH_RECORD_FIELD',
|
|
115
|
+
'34896006' => 'INCISION_DATETIME',
|
|
116
|
+
'272741003' => 'LATERALITY',
|
|
117
|
+
'183797002' => 'LENGTH_OF_STAY',
|
|
118
|
+
'445518008' => 'ONSET_AGE',
|
|
119
|
+
'117363000' => 'ORDINALITY',
|
|
120
|
+
'PAT' => 'PATIENT_PREFERENCE',
|
|
121
|
+
'103323008' => 'PROVIDER_PREFERENCE',
|
|
122
|
+
'228815006' => 'RADIATION_DOSAGE',
|
|
123
|
+
'306751006' => 'RADIATION_DURATION',
|
|
124
|
+
'263851003' => 'REACTION',
|
|
125
|
+
'410666004' => 'REASON',
|
|
126
|
+
'REL' => 'RELATED_TO',
|
|
127
|
+
'118292001' => 'REMOVAL_DATETIME',
|
|
128
|
+
'263513008' => 'ROUTE',
|
|
129
|
+
'SEV' => 'SEVERITY',
|
|
130
|
+
'398201009' => 'START_DATETIME',
|
|
131
|
+
'33999-4' => 'STATUS',
|
|
132
|
+
'397898000' => 'STOP_DATETIME',
|
|
133
|
+
'385676005' => 'TARGET_OUTCOME',
|
|
134
|
+
|
|
135
|
+
# Custom field values
|
|
136
|
+
'91723000' => 'ANATOMICAL_STRUCTURE',
|
|
137
|
+
'FLFS' => 'FLFS',
|
|
138
|
+
'260753009' => 'SOURCE',
|
|
139
|
+
'TRANSFER_FROM' => 'TRANSFER_FROM',
|
|
140
|
+
'ORG_TIME' => 'TRANSFER_FROM_DATETIME',
|
|
141
|
+
'TRANSFER_TO' => 'TRANSFER_TO',
|
|
142
|
+
'DST_TIME' => 'TRANSFER_TO_DATETIME'
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
attr_reader :title, :description, :code_list_id, :derivation_operator , :specific_occurrence, :specific_occurrence_const, :source_data_criteria, :variable
|
|
148
|
+
attr_accessor :id, :value, :field_values, :children_criteria, :effective_time, :status, :temporal_references, :subset_operators, :definition, :inline_code_list, :negation_code_list_id, :negation, :display_name, :comments
|
|
149
|
+
|
|
150
|
+
# Create a new data criteria instance
|
|
151
|
+
# @param [String] id
|
|
152
|
+
# @param [String] title
|
|
153
|
+
# @param [String] display_name
|
|
154
|
+
# @param [String] description
|
|
155
|
+
# @param [String] code_list_id
|
|
156
|
+
# @param [String] negation_code_list_id
|
|
157
|
+
# @param [List<String>] children_criteria (ids of children data criteria)
|
|
158
|
+
# @param [String] derivation_operator
|
|
159
|
+
# @param [String] definition
|
|
160
|
+
# @param [String] status
|
|
161
|
+
# @param [Value|Range|Coded] value
|
|
162
|
+
# @param [Hash<String,Value|Range|Coded>] field_values
|
|
163
|
+
# @param [Range] effective_time
|
|
164
|
+
# @param [Hash<String,[String]>] inline_code_list
|
|
165
|
+
# @param [boolean] negation
|
|
166
|
+
# @param [String] negation_code_list_id
|
|
167
|
+
# @param [List<TemporalReference>] temporal_references
|
|
168
|
+
# @param [List<SubsetOperator>] subset_operators
|
|
169
|
+
# @param [String] specific_occurrence
|
|
170
|
+
# @param [String] specific_occurrence_const
|
|
171
|
+
# @param [String] source_data_criteria (id for the source data criteria, important for specific occurrences)
|
|
172
|
+
# @param [String] user comments for the criteria
|
|
173
|
+
# @param [Boolean] variable defines if the element is a QDM variable
|
|
174
|
+
def initialize(id, title, display_name, description, code_list_id, children_criteria, derivation_operator, definition, status, value, field_values, effective_time, inline_code_list, negation, negation_code_list_id, temporal_references, subset_operators, specific_occurrence, specific_occurrence_const, source_data_criteria=nil, comments=nil, variable=false)
|
|
175
|
+
|
|
176
|
+
status = normalize_status(definition, status)
|
|
177
|
+
@settings = HQMF::DataCriteria.get_settings_for_definition(definition, status)
|
|
178
|
+
|
|
179
|
+
@id = id
|
|
180
|
+
@title = title
|
|
181
|
+
@description = description
|
|
182
|
+
@code_list_id = code_list_id
|
|
183
|
+
@negation_code_list_id = negation_code_list_id
|
|
184
|
+
@children_criteria = children_criteria
|
|
185
|
+
@derivation_operator = derivation_operator
|
|
186
|
+
@definition = definition
|
|
187
|
+
@status = status
|
|
188
|
+
@value = value
|
|
189
|
+
@field_values = field_values
|
|
190
|
+
@effective_time = effective_time
|
|
191
|
+
@inline_code_list = inline_code_list
|
|
192
|
+
@negation = negation
|
|
193
|
+
@negation_code_list_id = negation_code_list_id
|
|
194
|
+
@temporal_references = temporal_references
|
|
195
|
+
@subset_operators = subset_operators
|
|
196
|
+
@specific_occurrence = specific_occurrence
|
|
197
|
+
@specific_occurrence_const = specific_occurrence_const
|
|
198
|
+
@source_data_criteria = source_data_criteria || id
|
|
199
|
+
@comments = comments
|
|
200
|
+
@variable = variable
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# create a new data criteria given a category and sub_category. A sub category can either be a status or a sub category
|
|
204
|
+
def self.create_from_category(id, title, description, code_list_id, category, sub_category=nil, negation=false, negation_code_list_id=nil)
|
|
205
|
+
settings = HQMF::DataCriteria.get_settings_for_definition(category, sub_category)
|
|
206
|
+
HQMF::DataCriteria.new(id, title, nil, description, code_list_id, nil, nil, settings['definition'], settings['status'], nil, nil, nil, nil, negation, negation_code_list_id, nil, nil, nil,nil)
|
|
207
|
+
end
|
|
208
|
+
def type
|
|
209
|
+
@settings['category'].to_sym
|
|
210
|
+
end
|
|
211
|
+
def property
|
|
212
|
+
@settings['property'].to_sym unless @settings['property'].nil?
|
|
213
|
+
end
|
|
214
|
+
def patient_api_function
|
|
215
|
+
@settings['patient_api_function'].to_sym unless @settings['patient_api_function'].empty?
|
|
216
|
+
end
|
|
217
|
+
def hard_status
|
|
218
|
+
@settings['hard_status']
|
|
219
|
+
end
|
|
220
|
+
def update_copy(hard_status, title, description, derivation_operator, definition)
|
|
221
|
+
@settings['hard_status'] = hard_status
|
|
222
|
+
@title = title
|
|
223
|
+
@description = description
|
|
224
|
+
@derivation_operator = derivation_operator
|
|
225
|
+
@definition = definition
|
|
226
|
+
end
|
|
227
|
+
def definition=(definition)
|
|
228
|
+
@definition = definition
|
|
229
|
+
@settings = HQMF::DataCriteria.get_settings_for_definition(@definition, @status)
|
|
230
|
+
end
|
|
231
|
+
def status=(status)
|
|
232
|
+
@status = status
|
|
233
|
+
@settings = HQMF::DataCriteria.get_settings_for_definition(@definition, @status)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Create a new data criteria instance from a JSON hash keyed with symbols
|
|
237
|
+
def self.from_json(id, json)
|
|
238
|
+
|
|
239
|
+
title = json["title"] if json["title"]
|
|
240
|
+
display_name = json["display_name"] if json["display_name"]
|
|
241
|
+
description = json["description"] if json["description"]
|
|
242
|
+
code_list_id = json["code_list_id"] if json["code_list_id"]
|
|
243
|
+
children_criteria = json["children_criteria"] if json["children_criteria"]
|
|
244
|
+
derivation_operator = json["derivation_operator"] if json["derivation_operator"]
|
|
245
|
+
definition = json["definition"] if json["definition"]
|
|
246
|
+
status = json["status"] if json["status"]
|
|
247
|
+
value = convert_value(json["value"]) if json["value"]
|
|
248
|
+
field_values = json["field_values"].inject({}){|memo,(k,v)| memo[k.to_s] = convert_value(v); memo} if json["field_values"]
|
|
249
|
+
effective_time = HQMF::Range.from_json(json["effective_time"]) if json["effective_time"]
|
|
250
|
+
inline_code_list = json["inline_code_list"].inject({}){|memo,(k,v)| memo[k.to_s] = v; memo} if json["inline_code_list"]
|
|
251
|
+
negation = json["negation"] || false
|
|
252
|
+
negation_code_list_id = json['negation_code_list_id'] if json['negation_code_list_id']
|
|
253
|
+
temporal_references = json["temporal_references"].map {|reference| HQMF::TemporalReference.from_json(reference)} if json["temporal_references"]
|
|
254
|
+
subset_operators = json["subset_operators"].map {|operator| HQMF::SubsetOperator.from_json(operator)} if json["subset_operators"]
|
|
255
|
+
specific_occurrence = json['specific_occurrence'] if json['specific_occurrence']
|
|
256
|
+
specific_occurrence_const = json['specific_occurrence_const'] if json['specific_occurrence_const']
|
|
257
|
+
source_data_criteria = json['source_data_criteria'] if json['source_data_criteria']
|
|
258
|
+
comments = json['comments'] if json['comments']
|
|
259
|
+
variable = json['variable'] || false
|
|
260
|
+
|
|
261
|
+
HQMF::DataCriteria.new(id, title, display_name, description, code_list_id, children_criteria, derivation_operator, definition, status, value, field_values,
|
|
262
|
+
effective_time, inline_code_list, negation, negation_code_list_id, temporal_references, subset_operators,specific_occurrence,specific_occurrence_const,source_data_criteria, comments, variable)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def is_same_type?(criteria)
|
|
266
|
+
return @definition == criteria.definition && @hard_status == criteria.hard_status &&
|
|
267
|
+
@negation == criteria.negation && all_code_set_oids.sort == criteria.all_code_set_oids.sort
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def to_json
|
|
271
|
+
json = base_json
|
|
272
|
+
{self.id.to_s.to_sym => json}
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def base_json
|
|
276
|
+
x = nil
|
|
277
|
+
json = build_hash(self, [:title,:display_name,:description,:code_list_id,:children_criteria, :derivation_operator, :property, :type, :definition, :status, :hard_status, :negation, :negation_code_list_id,:specific_occurrence,:specific_occurrence_const,:source_data_criteria,:variable])
|
|
278
|
+
json[:children_criteria] = @children_criteria unless @children_criteria.nil? || @children_criteria.empty?
|
|
279
|
+
json[:value] = ((@value.is_a? String) ? @value : @value.to_json) if @value
|
|
280
|
+
json[:field_values] = @field_values.inject({}) {|memo,(k,v)| memo[k] = (!v.nil? ? v.to_json : nil); memo} if @field_values
|
|
281
|
+
json[:effective_time] = @effective_time.to_json if @effective_time
|
|
282
|
+
json[:inline_code_list] = @inline_code_list if @inline_code_list
|
|
283
|
+
json[:temporal_references] = x if x = json_array(@temporal_references)
|
|
284
|
+
json[:subset_operators] = x if x = json_array(@subset_operators)
|
|
285
|
+
json[:comments] = @comments if @comments
|
|
286
|
+
json
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def has_temporal(temporal_reference)
|
|
290
|
+
@temporal_references.reduce(false) {|found, item| found ||= item == temporal_reference }
|
|
291
|
+
end
|
|
292
|
+
def has_subset(subset_operator)
|
|
293
|
+
@subset_operators.reduce(false) {|found, item| found ||= item == subset_operator }
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
def self.statuses_by_definition
|
|
297
|
+
settings_file = File.expand_path('../data_criteria.json', __FILE__)
|
|
298
|
+
settings_map = JSON.parse(File.read(settings_file))
|
|
299
|
+
all_defs = (settings_map.map {|key, value| {category: value['category'],definition:value['definition'],status:(value['status'].empty? ? nil : value['status']), sub_category: value['sub_category'],title:value['title']} unless value['not_supported']}).compact
|
|
300
|
+
by_categories = {}
|
|
301
|
+
all_defs.each do |definition|
|
|
302
|
+
by_categories[definition[:category]]||={}
|
|
303
|
+
status = definition[:status]
|
|
304
|
+
def_key = definition[:definition]
|
|
305
|
+
if status.nil? and definition[:sub_category] and !definition[:sub_category].empty?
|
|
306
|
+
status = definition[:sub_category]
|
|
307
|
+
def_key = def_key.gsub("_#{status}",'')
|
|
308
|
+
end
|
|
309
|
+
by_categories[definition[:category]][def_key]||={category:def_key,statuses:[]}
|
|
310
|
+
by_categories[definition[:category]][def_key][:statuses] << status unless status.nil?
|
|
311
|
+
end
|
|
312
|
+
status_by_category = {}
|
|
313
|
+
by_categories.each {|key, value| status_by_category[key] = value.values}
|
|
314
|
+
status_by_category.delete('derived')
|
|
315
|
+
status_by_category.delete('variable')
|
|
316
|
+
status_by_category.delete('measurement_period')
|
|
317
|
+
status_by_category.values.flatten
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
def referenced_data_criteria(document)
|
|
321
|
+
referenced = []
|
|
322
|
+
if (@children_criteria)
|
|
323
|
+
@children_criteria.each do |id|
|
|
324
|
+
dc = document.data_criteria(id)
|
|
325
|
+
referenced << id
|
|
326
|
+
referenced.concat(dc.referenced_data_criteria(document))
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
if (@temporal_references)
|
|
330
|
+
@temporal_references.each do |tr|
|
|
331
|
+
id = tr.reference.id
|
|
332
|
+
if (id != HQMF::Document::MEASURE_PERIOD_ID)
|
|
333
|
+
dc = document.data_criteria(id)
|
|
334
|
+
referenced << id
|
|
335
|
+
referenced.concat(dc.referenced_data_criteria(document))
|
|
336
|
+
end
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
referenced
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
def all_code_set_oids
|
|
343
|
+
|
|
344
|
+
# root oid
|
|
345
|
+
referenced_oids = [code_list_id]
|
|
346
|
+
|
|
347
|
+
# value oid
|
|
348
|
+
referenced_oids << value.code_list_id if value != nil and value.type == 'CD'
|
|
349
|
+
|
|
350
|
+
# negation oid
|
|
351
|
+
referenced_oids << negation_code_list_id if negation_code_list_id != nil
|
|
352
|
+
|
|
353
|
+
# field oids
|
|
354
|
+
if field_values != nil
|
|
355
|
+
referenced_oids.concat (field_values.map {|key,field| field.code_list_id if field != nil and field.type == 'CD'})
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
referenced_oids
|
|
359
|
+
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def self.get_settings_map
|
|
363
|
+
return @settings_map if @settings_map
|
|
364
|
+
settings_file = File.expand_path('../data_criteria.json', __FILE__)
|
|
365
|
+
@settings_map = JSON.parse(File.read(settings_file))
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def self.get_settings_for_definition(definition, status)
|
|
369
|
+
settings_file = File.expand_path('../data_criteria.json', __FILE__)
|
|
370
|
+
settings_map = get_settings_map
|
|
371
|
+
key = definition + ((status.nil? || status.empty?) ? '' : "_#{status}")
|
|
372
|
+
settings = settings_map[key]
|
|
373
|
+
|
|
374
|
+
raise "data criteria is not supported #{key}" if settings.nil? || settings["not_supported"]
|
|
375
|
+
|
|
376
|
+
settings
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def self.definition_for_template_id(template_id, version='r1')
|
|
380
|
+
get_template_id_map(version)[template_id]
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def self.template_id_for_definition(definition, status, negation, version="r1")
|
|
384
|
+
# in r2 negation uses the same template as a positive assertion
|
|
385
|
+
negation = false if version == "r2"
|
|
386
|
+
get_template_id_map(version).key({'definition' => definition, 'status' => status || '', 'negation' => negation})
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def self.title_for_template_id(template_id, version='r1')
|
|
390
|
+
value = get_template_id_map(version)[template_id]
|
|
391
|
+
if value
|
|
392
|
+
settings = self.get_settings_for_definition(value['definition'], value['status'])
|
|
393
|
+
if settings
|
|
394
|
+
settings['title']
|
|
395
|
+
else
|
|
396
|
+
'Unknown data criteria'
|
|
397
|
+
end
|
|
398
|
+
else
|
|
399
|
+
'Unknown template id'
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
def self.get_template_id_map(version="r1")
|
|
404
|
+
read_template_id_map(version)
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
private
|
|
408
|
+
|
|
409
|
+
def self.read_template_id_map(version)
|
|
410
|
+
HQMF::Util::HQMFTemplateHelper.template_id_map(version)
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def normalize_status(definition, status)
|
|
414
|
+
return status if status.nil?
|
|
415
|
+
case status.downcase
|
|
416
|
+
when 'completed', 'complete'
|
|
417
|
+
case definition
|
|
418
|
+
when 'diagnosis'
|
|
419
|
+
'active'
|
|
420
|
+
else
|
|
421
|
+
'performed'
|
|
422
|
+
end
|
|
423
|
+
when 'order'
|
|
424
|
+
'ordered'
|
|
425
|
+
else
|
|
426
|
+
status.downcase
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def self.convert_value(json)
|
|
431
|
+
return nil unless json.present?
|
|
432
|
+
type = json["type"]
|
|
433
|
+
case type
|
|
434
|
+
when 'TS', 'PQ'
|
|
435
|
+
value = HQMF::Value.from_json(json)
|
|
436
|
+
when 'IVL_PQ', 'IVL_TS'
|
|
437
|
+
value = HQMF::Range.from_json(json)
|
|
438
|
+
when 'CD'
|
|
439
|
+
value = HQMF::Coded.from_json(json)
|
|
440
|
+
when 'ANYNonNull'
|
|
441
|
+
value = HQMF::AnyValue.from_json(json)
|
|
442
|
+
when 'FLFS'
|
|
443
|
+
value = HQMF::TypedReference.from_json(json)
|
|
444
|
+
when 'ACT'
|
|
445
|
+
# Currentlty forcing this as the SimpleXML reresentation contains a fulfills for these types
|
|
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)
|
|
458
|
+
else
|
|
459
|
+
raise "Unknown value type [#{type}]"
|
|
460
|
+
end
|
|
461
|
+
value
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
end
|