cqm-parsers 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +5 -4
- data/README.md +3 -0
- data/Rakefile +0 -1
- data/lib/hqmf-model/data_criteria.json +27 -0
- data/lib/hqmf-model/data_criteria.rb +41 -4
- data/lib/hqmf-model/types.rb +37 -0
- data/lib/hqmf-parser/2.0/document.rb +1 -1
- data/lib/hqmf-parser/2.0/document_helpers/doc_population_helper.rb +36 -12
- data/lib/hqmf-parser/2.0/value_set_helper.rb +2 -2
- data/lib/hqmf-parser/cql/document_helpers/doc_population_helper.rb +45 -1
- data/lib/hqmf-parser/cql/value_set_helper.rb +5 -2
- data/lib/qrda-export/catI-r5/qrda_header/_record_target.mustache +0 -1
- data/lib/qrda-export/catI-r5/qrda_templates/assessment_performed.mustache +3 -3
- data/lib/qrda-export/catI-r5/qrda_templates/encounter_ordered.mustache +0 -1
- data/lib/qrda-export/catI-r5/qrda_templates/encounter_performed.mustache +0 -1
- data/lib/qrda-import/base-importers/medication_importer.rb +1 -0
- data/lib/qrda-import/base-importers/section_importer.rb +2 -2
- data/lib/qrda-import/data-element-importers/adverse_event_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/allergy_intolerance_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/assessment_performed_importer.rb +2 -1
- data/lib/qrda-import/data-element-importers/communication_from_patient_to_provider_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/communication_from_provider_to_patient_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/communication_from_provider_to_provider_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/device_applied_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/device_order_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/diagnosis_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/diagnostic_study_order_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/diagnostic_study_performed_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/encounter_order_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/encounter_performed_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/intervention_order_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/intervention_performed_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/laboratory_test_order_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/laboratory_test_performed_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/patient_characteristic_expired.rb +1 -0
- data/lib/qrda-import/data-element-importers/physical_exam_performed_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/procedure_order_importer.rb +1 -0
- data/lib/qrda-import/data-element-importers/procedure_performed_importer.rb +1 -0
- data/lib/util/code_system_helper.rb +2 -1
- data/lib/util/hqmfr2cql_template_oid_map.json +13 -13
- data/lib/util/vsac_api.rb +299 -0
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1b1bca119f15302832fea054a9bcc5ad90736bfe3ad898ec05410ba9932c4fa6
|
4
|
+
data.tar.gz: 94776039cbf7dadafc0b8bf2308cca80b60e298a5291494d3d63d2ade0f852d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 476c7290726a10f52dfb3f65a066516f755d7913be15c74783d5fbc836a2718c7cf65b9580ef309368ec4bdb45d9d6d175881b190660eb94f12d9ed6b2eeed08
|
7
|
+
data.tar.gz: 14d8e37e7fe9c737df8175192d935e3b908a53fa4511ccff107772108ef055375091241206fa964a5c430dcb944b5ce7b05b1bd94b52a5860a902d212843b0ca
|
data/Gemfile
CHANGED
@@ -1,8 +1,7 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
gemspec :development_group => :test
|
4
4
|
|
5
|
-
gem 'mustache'
|
6
5
|
gem 'cqm-models', '~> 0.8.4'
|
7
6
|
gem 'mongoid', '~> 5.0.0'
|
8
7
|
|
@@ -18,12 +17,14 @@ end
|
|
18
17
|
|
19
18
|
group :test do
|
20
19
|
gem 'factory_girl', '~> 4.1.0'
|
21
|
-
gem
|
22
|
-
gem
|
20
|
+
gem 'tailor', '~> 1.1.2'
|
21
|
+
gem 'cane', '~> 2.3.0'
|
22
|
+
gem 'codecov'
|
23
23
|
gem 'simplecov', :require => false
|
24
24
|
gem 'webmock'
|
25
25
|
gem 'minitest', '~> 5.3'
|
26
26
|
gem 'minitest-reporters'
|
27
27
|
gem 'awesome_print', :require => 'ap'
|
28
28
|
gem 'simplexml_parser', :git => 'https://github.com/projecttacoma/simplexml_parser.git', :branch => 'master'
|
29
|
+
gem 'vcr'
|
29
30
|
end
|
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -647,6 +647,15 @@
|
|
647
647
|
"hard_status":false,
|
648
648
|
"patient_api_function":"communications",
|
649
649
|
"not_supported":false},
|
650
|
+
"communication_performed":{
|
651
|
+
"title":"communication, performed",
|
652
|
+
"category":"communications",
|
653
|
+
"definition":"communication",
|
654
|
+
"status":"performed",
|
655
|
+
"sub_category":"",
|
656
|
+
"hard_status":false,
|
657
|
+
"patient_api_function":"communications",
|
658
|
+
"not_supported":false},
|
650
659
|
"device":{
|
651
660
|
"title":"device",
|
652
661
|
"category":"devices",
|
@@ -1007,6 +1016,15 @@
|
|
1007
1016
|
"hard_status":false,
|
1008
1017
|
"patient_api_function":"encounters",
|
1009
1018
|
"not_supported":false},
|
1019
|
+
"assessment_ordered":{
|
1020
|
+
"title":"assessment order",
|
1021
|
+
"category":"assessments",
|
1022
|
+
"definition":"assessment",
|
1023
|
+
"status":"ordered",
|
1024
|
+
"sub_category":"",
|
1025
|
+
"hard_status":false,
|
1026
|
+
"patient_api_function":"assessments",
|
1027
|
+
"not_supported":false},
|
1010
1028
|
"assessment_performed":{
|
1011
1029
|
"title":"assessment performed",
|
1012
1030
|
"category":"assessments",
|
@@ -1042,5 +1060,14 @@
|
|
1042
1060
|
"sub_category":"",
|
1043
1061
|
"hard_status":false,
|
1044
1062
|
"patient_api_function":"allergies",
|
1063
|
+
"not_supported":false},
|
1064
|
+
"participation":{
|
1065
|
+
"title":"participation",
|
1066
|
+
"category":"participations",
|
1067
|
+
"definition":"participation",
|
1068
|
+
"status":"",
|
1069
|
+
"sub_category":"",
|
1070
|
+
"hard_status":false,
|
1071
|
+
"patient_api_function":"participations",
|
1045
1072
|
"not_supported":false}
|
1046
1073
|
}
|
@@ -24,24 +24,35 @@ module HQMF
|
|
24
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
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
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: :
|
27
|
+
FIELDS = {'ABATEMENT_DATETIME' => {title:'Abatement Datetime', coded_entry_method: :end_date, field_type: :timestamp}, # ABATEMENT_DATETIME is no longer used.
|
28
|
+
'ACTIVE_DATETIME' => {title:'Active Date/Time', coded_entry_method: :active_datetime, field_type: :timestamp},
|
29
|
+
# ADMISSION_DATETIME is no longer used.
|
29
30
|
'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
31
|
# QDM 5.0 addition. This is the same as FACILITY_LOCATION.
|
31
32
|
# 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
33
|
'ADMISSION_SOURCE' => {title:'Admission Source', coded_entry_method: :admission_source, field_type: :value},
|
34
|
+
# ANATOMICAL_APPROACH_SITE is no longer used.
|
33
35
|
'ANATOMICAL_APPROACH_SITE' => {title:'Anatomical Approach Site', coded_entry_method: :anatomical_approach, field_type: :value},
|
34
36
|
'ANATOMICAL_LOCATION_SITE' => {title:'Anatomical Location Site', coded_entry_method: :anatomical_location, field_type: :value},
|
37
|
+
# ANATOMICAL_STRUCTURE is no longer used.
|
35
38
|
'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},
|
39
|
+
# Added in QDM 5.4
|
40
|
+
'CATEGORY' => {title:'Category', coded_entry_method: :category, field_type: :value},
|
36
41
|
'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
42
|
# TODO: Determine actual code and code_system for component attribute
|
38
43
|
'COMPONENT' => {title: 'Component', coded_entry_method: :components, field_type: :value},
|
44
|
+
# CUMULATIVE_MEDICATION_DURATION is no longer used.
|
39
45
|
'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
46
|
# MISSING Date - The date that the patient passed away. - Patient Characteristic Expired
|
47
|
+
# Could not find a code and code_system for this data criteria (days supplied) in HQMF QDM IG v3
|
48
|
+
'DAYS_SUPPLIED' => {title:'Days Supplied', coded_entry_method: :days_supplied, field_type: :value},
|
41
49
|
'DIAGNOSIS' => {title:'Diagnosis', coded_entry_method: :diagnosis, field_type: :value},
|
50
|
+
# DISCHARGE_DATETIME is no longer used.
|
42
51
|
'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
52
|
# 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.
|
53
|
+
# DISCHARGE_STATUS is no longer used.
|
44
54
|
'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},
|
55
|
+
'DISPENSER_IDENTIFIER' => {title:'Dispenser Identifier', coded_entry_method: :dispenser_identifier, field_type: :value},
|
45
56
|
# 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
57
|
'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
58
|
'FACILITY_LOCATION' => {title:'Facility Location', coded_entry_method: :facility, code: 'SDLOC', field_type: :value},
|
@@ -49,49 +60,72 @@ module HQMF
|
|
49
60
|
'FACILITY_LOCATION_ARRIVAL_DATETIME' => {title:'Location Period Start Date/Time', coded_entry_method: :facility_arrival, code: 'SDLOC_ARRIVAL', field_type: :nested_timestamp},
|
50
61
|
'FACILITY_LOCATION_DEPARTURE_DATETIME' => {title:'Location Period End Date/Time', coded_entry_method: :facility_departure, code: 'SDLOC_DEPARTURE', field_type: :nested_timestamp},
|
51
62
|
'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},
|
63
|
+
# HEALTH_RECORD_FIELD is no longer used.
|
52
64
|
'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
65
|
'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},
|
66
|
+
# LATERALITY is no longer used.
|
54
67
|
'LATERALITY' => {title:'Laterality', coded_entry_method: :laterality, code: '272741003', code_system:'2.16.840.1.113883.6.96', template_id: '', field_type: :value},
|
55
68
|
'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},
|
69
|
+
# Added in QDM 5.4
|
70
|
+
'MEDIUM' => {title:'Medium', coded_entry_method: :medium, field_type: :value},
|
56
71
|
'METHOD' => {title:'Method', coded_entry_method: :method, template_id: '', field_type: :value},
|
57
72
|
# Negation Rationale isn't encoded
|
73
|
+
# ONSET_AGE is no longer used.
|
58
74
|
'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},
|
75
|
+
# ONSET_DATETIME is no longer used.
|
59
76
|
'ONSET_DATETIME' => {title:'Onset Datetime', coded_entry_method: :start_date, field_type: :timestamp},
|
77
|
+
# ORDINAL is no longer used.
|
60
78
|
'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
79
|
'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},
|
80
|
+
# PATIENT_PREFERENCE is no longer used.
|
62
81
|
'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},
|
82
|
+
'PRESCRIBER_IDENTIFIER' => {title:'Prescriber Identifier', coded_entry_method: :prescriber_identifier, field_type: :value},
|
63
83
|
'PRINCIPAL_DIAGNOSIS' => {title:'Principal Diagnosis', coded_entry_method: :principal_diagnosis, field_type: :value},
|
84
|
+
# PROVIDER_PREFERENCE is no longer used.
|
64
85
|
'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},
|
86
|
+
# RADIATION_DOSAGE is no longer used.
|
65
87
|
'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},
|
88
|
+
# RADIATION_DURATION is no longer used.
|
66
89
|
'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},
|
90
|
+
# REACTION is no longer used.
|
67
91
|
'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
92
|
'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},
|
93
|
+
# Added in QDM 5.4
|
94
|
+
'RECIPIENT' => {title:'Recipient', coded_entry_method: :recipient, field_type: :value},
|
95
|
+
# RECORDED_DATETIME is no longer used.
|
69
96
|
'RECORDED_DATETIME' => {title:'Recorded Datetime', coded_entry_method: :start_date, field_type: :timestamp},
|
70
97
|
'REFERENCE_RANGE_HIGH' => {title:'Reference Range - High', coded_entry_method: :reference_range_high, field_type: :value},
|
71
98
|
'REFERENCE_RANGE_LOW' => {title:'Reference Range - Low', coded_entry_method: :reference_range_low, field_type: :value},
|
72
99
|
'REFILLS' => {title:'Refills', coded_entry_method: :refills, field_type: :value},
|
73
100
|
'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
101
|
'RELATIONSHIP' => {title:'Relationship', coded_entry_method: :relationship_to_patient, field_type: :value},
|
102
|
+
# REMOVAL_DATETIME is no longer used.
|
75
103
|
'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
104
|
# Result isn't encoded
|
77
105
|
# 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
106
|
'RESULT_DATETIME' => {title:'Result Date/Time', coded_entry_method: :result_date_time, field_type: :timestamp},
|
79
107
|
'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},
|
108
|
+
# Added in QDM 5.4
|
109
|
+
'SENDER' => {title:'Sender', coded_entry_method: :sender, field_type: :value},
|
110
|
+
'SETTING' => {title:'Setting', coded_entry_method: :setting, field_type: :value},
|
80
111
|
'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},
|
112
|
+
# SIGNED_DATETIME is no longer used.
|
81
113
|
'SIGNED_DATETIME' => {title:'Signed Date/Time', coded_entry_method: :signed_date_time, field_type: :timestamp},
|
114
|
+
# START_DATETIME is no longer used.
|
82
115
|
'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
116
|
# 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
117
|
'STATUS' => {title: 'Status', coded_entry_method: :qdm_status, code: '33999-4', code_system:'2.16.840.1.113883.6.1', field_type: :value},
|
118
|
+
# STOP_DATETIME is no longer used.
|
85
119
|
'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
120
|
# 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
121
|
'SUPPLY' => {title:'Supply', coded_entry_method: :supply, field_type: :value},
|
88
122
|
'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
123
|
|
91
124
|
# Custom field values
|
92
125
|
# QDM 5.3 Update: "Related To" replaces Fulfills. We are keeping the fulfills code and only make changes to the UI.
|
93
126
|
'FLFS' => {title:'Related To', coded_entry_method: :fulfills, code: 'FLFS', field_type: :reference},
|
94
127
|
'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},
|
128
|
+
# TRANSFER_FROM, TRANSFER_FROM_DATETIME, TRANSFER_TO, and TRANSFER_TO_DATETIME are no longer used.
|
95
129
|
'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
130
|
'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
131
|
'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},
|
@@ -455,6 +489,10 @@ module HQMF
|
|
455
489
|
value = HQMF::Collection.from_json(json)
|
456
490
|
when 'FAC'
|
457
491
|
value = Facility.new(json)
|
492
|
+
when 'ID'
|
493
|
+
value = HQMF::Identifier.from_json(json)
|
494
|
+
when 'RT'
|
495
|
+
value = HQMF::Ratio.from_json(json)
|
458
496
|
else
|
459
497
|
raise "Unknown value type [#{type}]"
|
460
498
|
end
|
@@ -463,5 +501,4 @@ module HQMF
|
|
463
501
|
|
464
502
|
|
465
503
|
end
|
466
|
-
|
467
504
|
end
|
data/lib/hqmf-model/types.rb
CHANGED
@@ -453,5 +453,42 @@ module HQMF
|
|
453
453
|
check_equality(self,other)
|
454
454
|
end
|
455
455
|
end
|
456
|
+
|
457
|
+
class Ratio
|
458
|
+
include HQMF::Conversion::Utilities
|
459
|
+
attr_accessor :type, :numerator, :denominator
|
460
|
+
|
461
|
+
# @param [String] type
|
462
|
+
# @param [Value] numerator
|
463
|
+
# @param [Value] denominator
|
464
|
+
def initialize(type, numerator, denominator)
|
465
|
+
@type = type || 'RT'
|
466
|
+
@numerator = numerator
|
467
|
+
@denominator = denominator
|
468
|
+
end
|
469
|
+
|
470
|
+
def self.from_json(json)
|
471
|
+
type = json["type"] if json["type"]
|
472
|
+
numerator = json["numerator"] if json["numerator"]
|
473
|
+
denominator = json["denominator"] if json["denominator"]
|
474
|
+
HQMF::Ratio.new(type, numerator, denominator)
|
475
|
+
end
|
476
|
+
|
477
|
+
def numerator?
|
478
|
+
@numerator
|
479
|
+
end
|
480
|
+
|
481
|
+
def denominator?
|
482
|
+
@denominator
|
483
|
+
end
|
484
|
+
|
485
|
+
def to_json
|
486
|
+
build_hash(self, [:type, :numerator, :denominator])
|
487
|
+
end
|
488
|
+
|
489
|
+
def ==(other)
|
490
|
+
check_equality(self, other)
|
491
|
+
end
|
492
|
+
end
|
456
493
|
|
457
494
|
end
|
@@ -192,7 +192,7 @@ module HQMF2
|
|
192
192
|
value_obj = handle_attribute_value(attribute, value) if attribute.at_xpath('./cda:value', NAMESPACES)
|
193
193
|
|
194
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')
|
195
|
+
@cms_id = "CMS#{value}v#{@hqmf_version_number.to_i}" if (!name.nil?) && ((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
|
@@ -32,24 +32,17 @@ module HQMF2
|
|
32
32
|
# Returns the population descriptions and criteria found in this document
|
33
33
|
def extract_populations_and_criteria
|
34
34
|
has_observation = extract_observations
|
35
|
-
document_populations =
|
36
|
-
HQMF2::Document::NAMESPACES)
|
37
|
-
# Sort the populations based on the id/extension, since the populations may be out of order; there doesn't seem to
|
38
|
-
# be any other way that order is indicated in the HQMF
|
39
|
-
document_populations = document_populations.sort_by do |pop|
|
40
|
-
pop.at_xpath('cda:id/@extension', HQMF2::Document::NAMESPACES).try(:value)
|
41
|
-
end
|
35
|
+
document_populations = get_document_populations
|
42
36
|
number_of_populations = document_populations.length
|
43
37
|
document_populations.each_with_index do |population_def, population_index|
|
44
38
|
population = {}
|
45
39
|
handle_base_populations(population_def, population)
|
46
40
|
|
47
|
-
id_def = population_def
|
48
|
-
|
49
|
-
|
50
|
-
population
|
41
|
+
id_def = get_id_def(population_def)
|
42
|
+
add_id_to_population(id_def, population, population_index)
|
43
|
+
add_title_to_population(population_def, population)
|
44
|
+
add_observ_to_population(has_observation, population)
|
51
45
|
|
52
|
-
population['OBSERV'] = 'OBSERV' if has_observation
|
53
46
|
@populations << population
|
54
47
|
handle_stratifications(population_def, number_of_populations, population, id_def, population_index)
|
55
48
|
end
|
@@ -59,6 +52,37 @@ module HQMF2
|
|
59
52
|
[@populations, @population_criteria]
|
60
53
|
end
|
61
54
|
|
55
|
+
def get_document_populations
|
56
|
+
document_populations = @doc.xpath('cda:QualityMeasureDocument/cda:component/cda:populationCriteriaSection',
|
57
|
+
HQMF2::Document::NAMESPACES)
|
58
|
+
# Sort the populations based on the id/extension, since the populations may be out of order; there doesn't seem to
|
59
|
+
# be any other way that order is indicated in the HQMF
|
60
|
+
document_populations.sort_by do |pop|
|
61
|
+
pop.at_xpath('cda:id/@extension', HQMF2::Document::NAMESPACES).try(:value)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_id_def(population_def)
|
66
|
+
population_def.at_xpath('cda:id/@extension', HQMF2::Document::NAMESPACES)
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_title_def(population_def)
|
70
|
+
population_def.at_xpath('cda:title/@value', HQMF2::Document::NAMESPACES)
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_id_to_population(id_def, population, population_index)
|
74
|
+
population['id'] = id_def ? id_def.value : "Population#{population_index}"
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_title_to_population(population_def, population)
|
78
|
+
title_def = get_title_def(population_def)
|
79
|
+
population['title'] = title_def ? title_def.value : "Population #{population_index}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_observ_to_population(has_observation, population)
|
83
|
+
population['OBSERV'] = 'OBSERV' if has_observation
|
84
|
+
end
|
85
|
+
|
62
86
|
# Extracts the measure observations, will return true if one exists
|
63
87
|
def extract_observations
|
64
88
|
has_observation = false
|
@@ -92,8 +92,8 @@ module HQMF2
|
|
92
92
|
'2.16.840.1.113883.10.20.28.3.117' => { valueset_path: './*/cda:code', result_path: './*/cda:value' },
|
93
93
|
'2.16.840.1.113883.10.20.28.3.118' => { valueset_path: './*/cda:code', result_path: nil },
|
94
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
|
-
|
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
|
+
'2.16.840.1.113883.10.20.28.3.130' => { valueset_path: './*/cda:value', result_path: nil }
|
97
97
|
}
|
98
98
|
# rubocop:enable Metrics/LineLength
|
99
99
|
|
@@ -40,7 +40,11 @@ module HQMF2CQL
|
|
40
40
|
# The at_xpath(...).values returns an array of a single element.
|
41
41
|
# The match returns an array and since we don't want the double quotes we take the second element
|
42
42
|
cql_define_function[:function_name] = entry.at_xpath("*/cda:measureObservationDefinition/cda:value/cda:expression").values.first.match('\\"([A-Za-z0-9 ]+)\\"')[1]
|
43
|
-
|
43
|
+
# The criteria_reference_id is the id of the measurePopulationCriteria that should be used for this observation function
|
44
|
+
measure_population_id = entry.at_xpath("*/cda:measureObservationDefinition/cda:component/cda:criteriaReference/cda:id").attributes['root'].value
|
45
|
+
# Get the name of the parameter to the observation function within the measurePopulationCriteria section
|
46
|
+
cql_define_function[:parameter] = @doc.at_xpath("cda:QualityMeasureDocument/cda:component/cda:populationCriteriaSection/cda:component/cda:measurePopulationCriteria/cda:id[@root = \"#{measure_population_id}\"]/../cda:precondition/cda:criteriaReference/cda:id").attributes['extension'].value.match('\\"([A-Za-z0-9 ]+)\\"')[1]
|
47
|
+
|
44
48
|
@observations << cql_define_function
|
45
49
|
end
|
46
50
|
end
|
@@ -120,5 +124,45 @@ module HQMF2CQL
|
|
120
124
|
end
|
121
125
|
end
|
122
126
|
|
127
|
+
# Returns the population descriptions and criteria found in this document
|
128
|
+
def extract_populations_and_criteria
|
129
|
+
has_observation = extract_observations
|
130
|
+
document_populations = get_document_populations
|
131
|
+
number_of_populations = document_populations.length
|
132
|
+
document_populations.each_with_index do |population_def, population_index|
|
133
|
+
population = {}
|
134
|
+
handle_base_populations(population_def, population)
|
135
|
+
|
136
|
+
id_def = get_id_def(population_def)
|
137
|
+
add_id_to_population(id_def, population, population_index)
|
138
|
+
add_title_to_population(population_def, population)
|
139
|
+
add_observ_to_population(has_observation, population)
|
140
|
+
|
141
|
+
add_supplemental_data_elements_to_population(population_def, population)
|
142
|
+
|
143
|
+
@populations << population
|
144
|
+
handle_stratifications(population_def, number_of_populations, population, id_def, population_index)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Push in the stratification populations after the unstratified populations
|
148
|
+
@populations.concat(@stratifications)
|
149
|
+
[@populations, @population_criteria]
|
150
|
+
end
|
151
|
+
|
152
|
+
def add_supplemental_data_elements_to_population(population_def, population)
|
153
|
+
begin
|
154
|
+
supplemental_data_elements_def = population_def.xpath('cda:component/cql-ext:supplementalDataElement')
|
155
|
+
rescue Nokogiri::XML::XPath::SyntaxError
|
156
|
+
# Older fixtures without SDEs don't have the cql-ext namespace
|
157
|
+
return
|
158
|
+
end
|
159
|
+
|
160
|
+
supplemental_data_elements = []
|
161
|
+
supplemental_data_elements_def.each do |sde_def|
|
162
|
+
cql_definition_name = sde_def.at_xpath('cda:precondition/cda:criteriaReference/cda:id').attribute('extension').to_s.match(/"([^"]*)"/)[1]
|
163
|
+
supplemental_data_elements << cql_definition_name
|
164
|
+
end
|
165
|
+
population['supplemental_data_elements'] = supplemental_data_elements
|
166
|
+
end
|
123
167
|
end
|
124
168
|
end
|
@@ -75,7 +75,7 @@ module HQMF2CQL
|
|
75
75
|
'2.16.840.1.113883.10.20.28.4.75' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='ADMM']/cda:playingMaterial[@classCode='MAT' and @determinerCode='KIND']/cda:code", result_path: nil },
|
76
76
|
'2.16.840.1.113883.10.20.28.4.76' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='ADMM']/cda:playingMaterial[@classCode='MAT' and @determinerCode='KIND']/cda:code", result_path: nil },
|
77
77
|
'2.16.840.1.113883.10.20.28.4.77' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='ADMM']/cda:playingMaterial[@classCode='MAT' and @determinerCode='KIND']/cda:code", result_path: nil },
|
78
|
-
'2.16.840.1.113883.10.20.28.4.78' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='
|
78
|
+
'2.16.840.1.113883.10.20.28.4.78' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='ADMM']/cda:playingMaterial[@classCode='MAT' and @determinerCode='KIND']/cda:code", result_path: nil },
|
79
79
|
'2.16.840.1.113883.10.20.28.4.79' => { valueset_path: './*/cda:value', result_path: nil },
|
80
80
|
'2.16.840.1.113883.10.20.28.4.80' => { valueset_path: './*/cda:value', result_path: nil },
|
81
81
|
'2.16.840.1.113883.10.20.28.4.81' => { valueset_path: './*/cda:value', result_path: nil },
|
@@ -92,7 +92,10 @@ module HQMF2CQL
|
|
92
92
|
'2.16.840.1.113883.10.20.28.4.117' => { valueset_path: './*/cda:code', result_path: './*/cda:value' },
|
93
93
|
'2.16.840.1.113883.10.20.28.4.118' => { valueset_path: './*/cda:code', result_path: nil },
|
94
94
|
'2.16.840.1.113883.10.20.28.4.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.4.120' => { 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.4.120' => { valueset_path: "./*/cda:participation[@typeCode='CSM']/cda:role[@classCode='MANU']/cda:playingEntity[@classCode='MMAT']/cda:code", result_path: nil },
|
96
|
+
'2.16.840.1.113883.10.20.28.4.130' => { valueset_path: './*/cda:value', result_path: nil },
|
97
|
+
'2.16.840.1.113883.10.20.28.4.131' => { valueset_path: './*/cda:code', result_path: nil },
|
98
|
+
'2.16.840.1.113883.10.20.28.4.132' => { valueset_path: "./*/cda:outboundRelationship[@typeCode='RSON']/cda:observationCriteria/cda:value", result_path: nil }
|
96
99
|
}
|
97
100
|
# rubocop:enable Metrics/LineLength
|
98
101
|
|
@@ -9,12 +9,12 @@
|
|
9
9
|
{{#relevantPeriod}}
|
10
10
|
{{{relevant_period}}}
|
11
11
|
{{/relevantPeriod}}
|
12
|
+
{{#result}}
|
13
|
+
{{{result_value}}}
|
14
|
+
{{/result}}
|
12
15
|
{{#authorDatetime}}
|
13
16
|
{{> qrda_templates/template_partials/_author}}
|
14
17
|
{{/authorDatetime}}
|
15
|
-
{{#result}}
|
16
|
-
{{> qrda_templates/template_partials/_results}}
|
17
|
-
{{/result}}
|
18
18
|
{{#negationRationale}}
|
19
19
|
{{> qrda_templates/template_partials/_reason}}
|
20
20
|
{{/negationRationale}}
|
@@ -1,7 +1,6 @@
|
|
1
1
|
<entry>
|
2
2
|
<act classCode="ACT" moodCode="RQO" {{{negation_ind}}}>
|
3
3
|
<templateId root="2.16.840.1.113883.10.20.24.3.132" extension="2017-08-01"/>
|
4
|
-
<id root="1.3.6.1.4.1.115" extension="{{object_id}}"/>
|
5
4
|
<code code="ENC" codeSystem="2.16.840.1.113883.5.6" displayName="Encounter" codeSystemName="ActClass"/>
|
6
5
|
<entryRelationship typeCode="SUBJ">
|
7
6
|
<encounter classCode="ENC" moodCode="RQO">
|
@@ -2,7 +2,6 @@
|
|
2
2
|
<act classCode="ACT" moodCode="EVN">
|
3
3
|
<!--Encounter performed Act -->
|
4
4
|
<templateId extension="2017-08-01" root="2.16.840.1.113883.10.20.24.3.133"/>
|
5
|
-
<id extension="{{object_id}}" root="1.3.6.1.4.1.115"/>
|
6
5
|
<code code="ENC" codeSystem="2.16.840.1.113883.5.6" codeSystemName="ActClass" displayName="Encounter"/>
|
7
6
|
<entryRelationship typeCode="SUBJ">
|
8
7
|
<encounter classCode="ENC" moodCode="EVN">
|
@@ -4,6 +4,7 @@ module QRDA
|
|
4
4
|
|
5
5
|
def initialize(entry_finder = nil)
|
6
6
|
super(entry_finder)
|
7
|
+
@id_xpath = './cda:id'
|
7
8
|
@code_xpath = "./cda:consumable/cda:manufacturedProduct/cda:manufacturedMaterial/cda:code"
|
8
9
|
@relevant_period_xpath = "./cda:effectiveTime"
|
9
10
|
@author_datetime_xpath = "./cda:author/cda:time"
|
@@ -38,8 +38,8 @@ module QRDA
|
|
38
38
|
|
39
39
|
def create_entry(entry_element, _nrh = NarrativeReferenceHandler.new)
|
40
40
|
entry = @entry_class.new
|
41
|
-
@entry_id_map[extract_id(entry_element,
|
42
|
-
@entry_id_map[extract_id(entry_element,
|
41
|
+
@entry_id_map[extract_id(entry_element, @id_xpath).value] ||= []
|
42
|
+
@entry_id_map[extract_id(entry_element, @id_xpath).value] << entry.id
|
43
43
|
entry.dataElementCodes = extract_codes(entry_element, @code_xpath)
|
44
44
|
extract_dates(entry_element, entry)
|
45
45
|
if @result_xpath
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class AdverseEventImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.146']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:entryRelationship/cda:observation/cda:value'
|
7
8
|
@author_datetime_xpath = './cda:author/cda:time'
|
8
9
|
@relevant_period_xpath = './cda:effectiveTime'
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class AllergyIntoleranceImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.147']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:participant/cda:participantRole/cda:playingEntity/cda:code'
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
9
|
@prevalence_period_xpath = "./cda:effectiveTime"
|
@@ -3,9 +3,10 @@ module QRDA
|
|
3
3
|
class AssessmentPerformedImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.144']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
|
-
@result_xpath = "./cda:value
|
9
|
+
@result_xpath = "./cda:value"
|
9
10
|
@method_xpath = './cda:methodCode'
|
10
11
|
@components_xpath = "./cda:entryRelationship/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.149']"
|
11
12
|
@entry_class = QDM::AssessmentPerformed
|
data/lib/qrda-import/data-element-importers/communication_from_patient_to_provider_importer.rb
CHANGED
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class CommunicationFromPatientToProviderImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.2']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
9
|
@entry_class = QDM::CommunicationFromPatientToProvider
|
data/lib/qrda-import/data-element-importers/communication_from_provider_to_patient_importer.rb
CHANGED
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class CommunicationFromProviderToPatientImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.3']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
9
|
@entry_class = QDM::CommunicationFromProviderToPatient
|
data/lib/qrda-import/data-element-importers/communication_from_provider_to_provider_importer.rb
CHANGED
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class CommunicationFromProviderToProviderImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.4']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
9
|
@related_to_xpath = "./sdtc:inFulfillmentOf1/sdtc:actReference"
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class DeviceAppliedImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.7']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:participant/cda:participantRole/cda:playingDevice/cda:code'
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
9
|
@relevant_period_xpath = "./cda:effectiveTime"
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class DeviceOrderImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.130']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:entryRelationship/cda:supply/cda:id'
|
6
7
|
@code_xpath = "./cda:entryRelationship/cda:supply[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.9']/cda:participant/cda:participantRole/cda:playingDevice/cda:code"
|
7
8
|
@author_datetime_xpath = "./cda:entryRelationship/cda:supply[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.9']/cda:author/cda:time"
|
8
9
|
@entry_class = QDM::DeviceOrder
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class DiagnosisImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.137']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:entryRelationship/cda:observation/cda:id'
|
6
7
|
@code_xpath = "./cda:entryRelationship/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.135']/cda:value"
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
9
|
@prevalence_period_xpath = "./cda:entryRelationship/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.135']/cda:effectiveTime"
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class DiagnosticStudyOrderImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.17']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
9
|
@method_xpath = './cda:methodCode'
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class DiagnosticStudyPerformedImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.18']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@relevant_period_xpath = "./cda:effectiveTime"
|
8
9
|
@author_datetime_xpath = "./cda:author/cda:time"
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class EncounterOrderImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.132']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:entryRelationship/cda:encounter/cda:id'
|
6
7
|
@code_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.22']/cda:code"
|
7
8
|
@author_datetime_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.22']/cda:author/cda:time"
|
8
9
|
@facility_location_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.22']/cda:participant[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.100']/cda:participantRole[@classCode='SDLOC']/cda:code"
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class EncounterPerformedImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.133']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:entryRelationship/cda:encounter/cda:id'
|
6
7
|
@code_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']/cda:code"
|
7
8
|
@relevant_period_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']/cda:effectiveTime"
|
8
9
|
@author_datetime_xpath = "./cda:entryRelationship/cda:encounter[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.23']/cda:author/cda:time"
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class InterventionOrderImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.31']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
9
|
@entry_class = QDM::InterventionOrder
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class InterventionPerformedImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:act[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.32']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@relevant_period_xpath = "./cda:effectiveTime"
|
8
9
|
@author_datetime_xpath = "./cda:author/cda:time"
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class LaboratoryTestOrderImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.37']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
9
|
@method_xpath = './cda:methodCode'
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class LaboratoryTestPerformedImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.38']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@relevant_period_xpath = "./cda:effectiveTime"
|
8
9
|
@author_datetime_xpath = "./cda:author/cda:time"
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class PatientCharacteristicExpired < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.54']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:value'
|
7
8
|
@expired_datetime_xpath = './cda:effectiveTime/cda:low'
|
8
9
|
@cause = "./cda:entryRelationship/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.22.4.4']/cda:value"
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class PhysicalExamPerformedImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.59']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = "./cda:code"
|
7
8
|
@relevant_period_xpath = "./cda:effectiveTime"
|
8
9
|
@author_datetime_xpath = "./cda:author/cda:time"
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class ProcedureOrderImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.63']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = './cda:code'
|
7
8
|
@author_datetime_xpath = "./cda:author/cda:time"
|
8
9
|
@method_xpath = './cda:methodCode'
|
@@ -3,6 +3,7 @@ module QRDA
|
|
3
3
|
class ProcedurePerformedImporter < SectionImporter
|
4
4
|
def initialize(entry_finder = QRDA::Cat1::EntryFinder.new("./cda:entry/cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.64']"))
|
5
5
|
super(entry_finder)
|
6
|
+
@id_xpath = './cda:id'
|
6
7
|
@code_xpath = "./cda:code"
|
7
8
|
@relevant_period_xpath = "./cda:effectiveTime"
|
8
9
|
@author_datetime_xpath = "./cda:author/cda:time"
|
@@ -34,7 +34,8 @@ module HQMF
|
|
34
34
|
'2.16.840.1.113883.1.11.78' => "HL7 Observation Interpretation",
|
35
35
|
'2.16.840.1.113883.3.221.5' => "Source of Payment Typology",
|
36
36
|
'2.16.840.1.113883.6.13' => 'CDT',
|
37
|
-
'2.16.840.1.113883.18.2' => 'AdministrativeSex'
|
37
|
+
'2.16.840.1.113883.18.2' => 'AdministrativeSex',
|
38
|
+
'2.16.840.1.113883.5.1' => 'AdministrativeGender'
|
38
39
|
}
|
39
40
|
|
40
41
|
CODE_SYSTEM_ALIASES = {
|
@@ -219,18 +219,6 @@
|
|
219
219
|
"definition":"care_goal",
|
220
220
|
"status":"",
|
221
221
|
"negation":false},
|
222
|
-
"2.16.840.1.113883.10.20.28.4.8":{
|
223
|
-
"definition":"communication_from_patient_to_provider",
|
224
|
-
"status":"",
|
225
|
-
"negation":false},
|
226
|
-
"2.16.840.1.113883.10.20.28.4.9":{
|
227
|
-
"definition":"communication_from_provider_to_patient",
|
228
|
-
"status":"",
|
229
|
-
"negation":false},
|
230
|
-
"2.16.840.1.113883.10.20.28.4.10":{
|
231
|
-
"definition":"communication_from_provider_to_provider",
|
232
|
-
"status":"",
|
233
|
-
"negation":false},
|
234
222
|
"2.16.840.1.113883.10.20.28.4.13":{
|
235
223
|
"definition":"device",
|
236
224
|
"status":"applied",
|
@@ -371,6 +359,10 @@
|
|
371
359
|
"definition":"transfer_to",
|
372
360
|
"status":"",
|
373
361
|
"negation":false},
|
362
|
+
"2.16.840.1.113883.10.20.28.4.131":{
|
363
|
+
"definition":"assessment",
|
364
|
+
"status":"ordered",
|
365
|
+
"negation":false},
|
374
366
|
"2.16.840.1.113883.10.20.28.4.117":{
|
375
367
|
"definition":"assessment",
|
376
368
|
"status":"performed",
|
@@ -386,5 +378,13 @@
|
|
386
378
|
"2.16.840.1.113883.10.20.28.4.119": {
|
387
379
|
"definition":"allergy_intolerance",
|
388
380
|
"status":"",
|
389
|
-
"negation":false}
|
381
|
+
"negation":false},
|
382
|
+
"2.16.840.1.113883.10.20.28.4.130": {
|
383
|
+
"definition":"participation",
|
384
|
+
"status":"",
|
385
|
+
"negation":false},
|
386
|
+
"2.16.840.1.113883.10.20.28.4.132": {
|
387
|
+
"definition":"communication",
|
388
|
+
"status":"performed",
|
389
|
+
"negation":true}
|
390
390
|
}
|
@@ -0,0 +1,299 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Util
|
5
|
+
module VSAC
|
6
|
+
# Generic VSAC related exception.
|
7
|
+
class VSACError < StandardError
|
8
|
+
end
|
9
|
+
|
10
|
+
# Error represnting a not found response from the API. Includes OID for reporting to user.
|
11
|
+
class VSNotFoundError < VSACError
|
12
|
+
attr_reader :oid
|
13
|
+
def initialize(oid)
|
14
|
+
super("Value Set (#{oid}) was not found.")
|
15
|
+
@oid = oid
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Error represnting a program not found response from the API.
|
20
|
+
class VSACProgramNotFoundError < VSACError
|
21
|
+
attr_reader :oid
|
22
|
+
def initialize(program)
|
23
|
+
super("VSAC Program #{program} does not exist.")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Error represnting a response from the API that had no concepts.
|
28
|
+
class VSEmptyError < VSACError
|
29
|
+
attr_reader :oid
|
30
|
+
def initialize(oid)
|
31
|
+
super("Value Set (#{oid}) is empty.")
|
32
|
+
@oid = oid
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Raised when the ticket granting ticket has expired.
|
37
|
+
class VSACTicketExpiredError < VSACError
|
38
|
+
def initialize
|
39
|
+
super('VSAC session expired. Please re-enter credentials and try again.')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Raised when the user credentials were invalid.
|
44
|
+
class VSACInvalidCredentialsError < VSACError
|
45
|
+
def initialize
|
46
|
+
super('VSAC ULMS credentials are invalid.')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Raised when a call requiring auth is attempted when no ticket_granting_ticket or credentials were provided.
|
51
|
+
class VSACNoCredentialsError < VSACError
|
52
|
+
def initialize
|
53
|
+
super('VSAC ULMS credentials were not provided.')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Raised when the arguments passed in are bad.
|
58
|
+
class VSACArgumentError < VSACError
|
59
|
+
end
|
60
|
+
|
61
|
+
class VSACAPI
|
62
|
+
# The default program to use for get_program_details and get_program_release_names calls.
|
63
|
+
# This can be overriden by providing a :program in the config or by the single optional parameter for those
|
64
|
+
# methods.
|
65
|
+
DEFAULT_PROGRAM = "CMS eCQM"
|
66
|
+
|
67
|
+
# This is the value of the service parameter passed when getting a ticket. This never changes.
|
68
|
+
TICKET_SERVICE_PARAM = "http://umlsks.nlm.nih.gov"
|
69
|
+
|
70
|
+
# The ticket granting that will be obtained if needed. Accessible so it may be stored in user session.
|
71
|
+
# Is a hash of the :ticket and time it :expires.
|
72
|
+
attr_reader :ticket_granting_ticket
|
73
|
+
|
74
|
+
##
|
75
|
+
# Creates a new VSACAPI. If credentials were provided they are checked now. If no credentials
|
76
|
+
# are provided then the API can still be used for utility methods.
|
77
|
+
#
|
78
|
+
# Options for the API are passed in as a hash.
|
79
|
+
# * config -
|
80
|
+
def initialize(options)
|
81
|
+
# check that :config exists and has needed fields
|
82
|
+
raise VSACArgumentError.new("Required param :config is missing or empty.") if options[:config].nil?
|
83
|
+
symbolized_config = options[:config].symbolize_keys
|
84
|
+
unless check_config symbolized_config
|
85
|
+
raise VSACArgumentError.new("Required param :config is missing required URLs.")
|
86
|
+
end
|
87
|
+
@config = symbolized_config
|
88
|
+
|
89
|
+
# if a ticket_granting_ticket was passed in, check it and raise errors if found
|
90
|
+
# username and password will be ignored
|
91
|
+
if !options[:ticket_granting_ticket].nil?
|
92
|
+
provided_ticket_granting_ticket = options[:ticket_granting_ticket]
|
93
|
+
if provided_ticket_granting_ticket[:ticket].nil? || provided_ticket_granting_ticket[:expires].nil?
|
94
|
+
raise VSACArgumentError.new("Optional param :ticket_granting_ticket is missing :ticket or :expires")
|
95
|
+
end
|
96
|
+
|
97
|
+
# check if it has expired
|
98
|
+
if Time.now > provided_ticket_granting_ticket[:expires]
|
99
|
+
raise VSACTicketExpiredError.new
|
100
|
+
end
|
101
|
+
|
102
|
+
# ticket granting ticket looks good
|
103
|
+
@ticket_granting_ticket = { ticket: provided_ticket_granting_ticket[:ticket],
|
104
|
+
expires: provided_ticket_granting_ticket[:expires] }
|
105
|
+
|
106
|
+
# if username and password were provided use them to get a ticket granting ticket
|
107
|
+
elsif !options[:username].nil? && !options[:password].nil?
|
108
|
+
@ticket_granting_ticket = get_ticket_granting_ticket(options[:username], options[:password])
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
##
|
113
|
+
# Gets the list of profiles. This may be used without credentials.
|
114
|
+
#
|
115
|
+
# Returns a list of profile names. These are kept in the order that VSAC provides them in.
|
116
|
+
def get_profile_names
|
117
|
+
profiles_response = RestClient.get("#{@config[:utility_url]}/profiles")
|
118
|
+
profiles = []
|
119
|
+
|
120
|
+
# parse xml response and get text content of each profile element
|
121
|
+
doc = Nokogiri::XML(profiles_response)
|
122
|
+
profile_list = doc.at_xpath("/ProfileList")
|
123
|
+
profile_list.xpath("//profile").each do |profile|
|
124
|
+
profiles << profile.text
|
125
|
+
end
|
126
|
+
|
127
|
+
return profiles
|
128
|
+
end
|
129
|
+
|
130
|
+
##
|
131
|
+
# Gets the list of programs. This may be used without credentials.
|
132
|
+
#
|
133
|
+
# Returns a list of program names. These are kept in the order that VSAC provides them in.
|
134
|
+
def get_program_names
|
135
|
+
programs_response = RestClient.get("#{@config[:utility_url]}/programs")
|
136
|
+
program_names = []
|
137
|
+
|
138
|
+
# parse json response and return the names of the programs
|
139
|
+
programs_info = JSON.parse(programs_response)['Program']
|
140
|
+
programs_info.each do |program|
|
141
|
+
program_names << program['name']
|
142
|
+
end
|
143
|
+
|
144
|
+
return program_names
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Gets the details for a program. This may be used without credentials.
|
149
|
+
#
|
150
|
+
# Optional parameter program is the program to request from the API. If it is not provided it will look for
|
151
|
+
# a :program in the config passed in during construction. If there is no :program in the config it will use
|
152
|
+
# the DEFAULT_PROGRAM constant for the program.
|
153
|
+
#
|
154
|
+
# Returns the JSON parsed response for program details.
|
155
|
+
def get_program_details(program = nil)
|
156
|
+
# if no program was provided use the one in the config or default in constant
|
157
|
+
if program.nil?
|
158
|
+
program = @config.fetch(:program, DEFAULT_PROGRAM)
|
159
|
+
end
|
160
|
+
|
161
|
+
begin
|
162
|
+
# parse json response and return it
|
163
|
+
return JSON.parse(RestClient.get("#{@config[:utility_url]}/program/#{ERB::Util.url_encode(program)}"))
|
164
|
+
rescue RestClient::ResourceNotFound
|
165
|
+
raise VSACProgramNotFoundError.new(program)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
##
|
170
|
+
# Gets the latest profile for a program. This is a separate call from the program details call. It returns JSON
|
171
|
+
# with only the name of the latest profile and the timestamp of the request. ex:
|
172
|
+
# {
|
173
|
+
# "name": "eCQM Update 2018-05-04",
|
174
|
+
# "requestTime": "2018-05-21 03:39:04 PM"
|
175
|
+
# }
|
176
|
+
#
|
177
|
+
# Optional parameter program is the program to request from the API. If it is not provided it will look for
|
178
|
+
# a :program in the config passed in during construction. If there is no :program in the config it will use
|
179
|
+
# the DEFAULT_PROGRAM constant for the program.
|
180
|
+
#
|
181
|
+
# Returns the name of the latest profile for the given program.
|
182
|
+
def get_latest_profile_for_program(program = nil)
|
183
|
+
# if no program was provided use the one in the config or default in constant
|
184
|
+
if program.nil?
|
185
|
+
program = @config.fetch(:program, DEFAULT_PROGRAM)
|
186
|
+
end
|
187
|
+
|
188
|
+
begin
|
189
|
+
# parse json response and return it
|
190
|
+
parsed_response = JSON.parse(RestClient.get("#{@config[:utility_url]}/program/#{ERB::Util.url_encode(program)}/latest%20profile"))
|
191
|
+
|
192
|
+
# As of 5/17/18 VSAC does not return 404 when an invalid profile is provided. It just doesnt fill the name
|
193
|
+
# attribute in the 200 response. We need to check this.
|
194
|
+
raise VSACProgramNotFoundError.new(program) if parsed_response['name'].nil?
|
195
|
+
return parsed_response['name']
|
196
|
+
|
197
|
+
# keeping this rescue block in case the API is changed to return 404 for invalid profile
|
198
|
+
rescue RestClient::ResourceNotFound
|
199
|
+
raise VSACProgramNotFoundError.new(program)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
##
|
204
|
+
# Gets the releases for a program. This may be used without credentials.
|
205
|
+
#
|
206
|
+
# Optional parameter program is the program to request from the API. If it is not provided it will look for
|
207
|
+
# a :program in the config passed in during construction. If there is no :program in the config it will use
|
208
|
+
# the DEFAULT_PROGRAM constant for the program.
|
209
|
+
#
|
210
|
+
# Returns a list of release names in a program. These are kept in the order that VSAC provides them in.
|
211
|
+
def get_program_release_names(program = nil)
|
212
|
+
program_details = get_program_details(program)
|
213
|
+
releases = []
|
214
|
+
|
215
|
+
# pull just the release names out
|
216
|
+
program_details['release'].each do |release|
|
217
|
+
releases << release['name']
|
218
|
+
end
|
219
|
+
|
220
|
+
return releases
|
221
|
+
end
|
222
|
+
|
223
|
+
##
|
224
|
+
# Gets a valueset. This requires credentials.
|
225
|
+
#
|
226
|
+
def get_valueset(oid, options = {})
|
227
|
+
# base parameter oid is always needed
|
228
|
+
params = { id: oid }
|
229
|
+
|
230
|
+
# release parameter, should be used moving forward
|
231
|
+
unless options[:release].nil?
|
232
|
+
params[:release] = options[:release]
|
233
|
+
end
|
234
|
+
|
235
|
+
# profile parameter, may be needed for getting draft value sets
|
236
|
+
if !options[:profile].nil?
|
237
|
+
params[:profile] = options[:profile]
|
238
|
+
unless options[:include_draft].nil?
|
239
|
+
params[:includeDraft] = !options[:include_draft].nil? ? 'yes' : 'no'
|
240
|
+
end
|
241
|
+
else
|
242
|
+
unless options[:include_draft].nil?
|
243
|
+
raise VSACArgumentError.new("Option :include_draft requires :profile to be provided.")
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# version parameter, rarely used
|
248
|
+
unless options[:version].nil?
|
249
|
+
params[:version] = options[:version]
|
250
|
+
end
|
251
|
+
|
252
|
+
# get a new service ticket
|
253
|
+
params[:ticket] = get_ticket
|
254
|
+
|
255
|
+
# run request
|
256
|
+
begin
|
257
|
+
return RestClient.get("#{@config[:content_url]}/RetrieveMultipleValueSets", params: params)
|
258
|
+
rescue RestClient::ResourceNotFound
|
259
|
+
raise VSNotFoundError.new(oid)
|
260
|
+
rescue RestClient::InternalServerError
|
261
|
+
raise VSACError.new("Server error response from VSAC for (#{oid}).")
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
private
|
266
|
+
|
267
|
+
def get_ticket
|
268
|
+
# if there is no ticket granting ticket then we should raise an error
|
269
|
+
raise VSACNoCredentialsError.new unless @ticket_granting_ticket
|
270
|
+
# if the ticket granting ticket has expired, throw an error
|
271
|
+
raise VSACTicketExpiredError.new if Time.now > @ticket_granting_ticket[:expires]
|
272
|
+
|
273
|
+
# attempt to get a ticket
|
274
|
+
begin
|
275
|
+
ticket = RestClient.post("#{@config[:auth_url]}/Ticket/#{@ticket_granting_ticket[:ticket]}", service: TICKET_SERVICE_PARAM)
|
276
|
+
return ticket.to_s
|
277
|
+
rescue RestClient::Unauthorized
|
278
|
+
@ticket_granting_ticket[:expires] = Time.now
|
279
|
+
raise VSACTicketExpiredError.new
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
def get_ticket_granting_ticket(username, password)
|
284
|
+
ticket = RestClient.post("#{@config[:auth_url]}/Ticket", username: username, password: password)
|
285
|
+
return { ticket: String.new(ticket), expires: Time.now + 8.hours }
|
286
|
+
rescue RestClient::Unauthorized
|
287
|
+
raise VSACInvalidCredentialsError.new
|
288
|
+
end
|
289
|
+
|
290
|
+
# Checks to ensure the API config has all necessary fields
|
291
|
+
def check_config(config)
|
292
|
+
return !config.nil? &&
|
293
|
+
!config[:auth_url].nil? &&
|
294
|
+
!config[:content_url].nil? &&
|
295
|
+
!config[:utility_url].nil?
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cqm-parsers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- The MITRE Corporation
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mustache
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rest-client
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -376,6 +390,7 @@ files:
|
|
376
390
|
- lib/util/hqmf_template_oid_map.json
|
377
391
|
- lib/util/hqmfr2_template_oid_map.json
|
378
392
|
- lib/util/hqmfr2cql_template_oid_map.json
|
393
|
+
- lib/util/vsac_api.rb
|
379
394
|
homepage: https://github.com/projecttacoma/cqm-parsers
|
380
395
|
licenses:
|
381
396
|
- Apache-2.0
|
@@ -396,7 +411,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
396
411
|
version: '0'
|
397
412
|
requirements: []
|
398
413
|
rubyforge_project:
|
399
|
-
rubygems_version: 2.
|
414
|
+
rubygems_version: 2.7.7
|
400
415
|
signing_key:
|
401
416
|
specification_version: 4
|
402
417
|
summary: A library for parsing HQMF documents.
|