cqm-parsers 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +29 -0
  3. data/README.md +21 -0
  4. data/Rakefile +19 -0
  5. data/lib/ext/code.rb +10 -0
  6. data/lib/ext/data_element.rb +24 -0
  7. data/lib/hqmf-model/attribute.rb +63 -0
  8. data/lib/hqmf-model/data_criteria.rb +467 -0
  9. data/lib/hqmf-model/document.rb +253 -0
  10. data/lib/hqmf-model/population_criteria.rb +102 -0
  11. data/lib/hqmf-model/precondition.rb +94 -0
  12. data/lib/hqmf-model/types.rb +457 -0
  13. data/lib/hqmf-model/utilities.rb +52 -0
  14. data/lib/hqmf-parser.rb +116 -0
  15. data/lib/hqmf-parser/1.0/attribute.rb +121 -0
  16. data/lib/hqmf-parser/1.0/comparison.rb +34 -0
  17. data/lib/hqmf-parser/1.0/data_criteria.rb +92 -0
  18. data/lib/hqmf-parser/1.0/document.rb +195 -0
  19. data/lib/hqmf-parser/1.0/expression.rb +60 -0
  20. data/lib/hqmf-parser/1.0/observation.rb +61 -0
  21. data/lib/hqmf-parser/1.0/population_criteria.rb +75 -0
  22. data/lib/hqmf-parser/1.0/precondition.rb +90 -0
  23. data/lib/hqmf-parser/1.0/range.rb +76 -0
  24. data/lib/hqmf-parser/1.0/restriction.rb +162 -0
  25. data/lib/hqmf-parser/1.0/utilities.rb +55 -0
  26. data/lib/hqmf-parser/2.0/data_criteria.rb +372 -0
  27. data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_base_extract.rb +80 -0
  28. data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_definition_from_template_or_type_extract.rb +201 -0
  29. data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_post_processing.rb +85 -0
  30. data/lib/hqmf-parser/2.0/data_criteria_helpers/dc_specific_occurrences_and_source_data_criteria_extract.rb +117 -0
  31. data/lib/hqmf-parser/2.0/document.rb +304 -0
  32. data/lib/hqmf-parser/2.0/document_helpers/doc_population_helper.rb +173 -0
  33. data/lib/hqmf-parser/2.0/document_helpers/doc_utilities.rb +131 -0
  34. data/lib/hqmf-parser/2.0/field_value_helper.rb +251 -0
  35. data/lib/hqmf-parser/2.0/population_criteria.rb +134 -0
  36. data/lib/hqmf-parser/2.0/precondition.rb +73 -0
  37. data/lib/hqmf-parser/2.0/source_data_criteria_helper.rb +112 -0
  38. data/lib/hqmf-parser/2.0/types.rb +448 -0
  39. data/lib/hqmf-parser/2.0/utilities.rb +45 -0
  40. data/lib/hqmf-parser/2.0/value_set_helper.rb +104 -0
  41. data/lib/hqmf-parser/converter/pass1/data_criteria_converter.rb +257 -0
  42. data/lib/hqmf-parser/converter/pass1/document_converter.rb +133 -0
  43. data/lib/hqmf-parser/converter/pass1/population_criteria_converter.rb +185 -0
  44. data/lib/hqmf-parser/converter/pass1/precondition_converter.rb +173 -0
  45. data/lib/hqmf-parser/converter/pass1/precondition_extractor.rb +201 -0
  46. data/lib/hqmf-parser/converter/pass1/simple_data_criteria.rb +26 -0
  47. data/lib/hqmf-parser/converter/pass1/simple_operator.rb +89 -0
  48. data/lib/hqmf-parser/converter/pass1/simple_population_criteria.rb +10 -0
  49. data/lib/hqmf-parser/converter/pass1/simple_precondition.rb +51 -0
  50. data/lib/hqmf-parser/converter/pass1/simple_restriction.rb +64 -0
  51. data/lib/hqmf-parser/converter/pass2/comparison_converter.rb +112 -0
  52. data/lib/hqmf-parser/converter/pass2/operator_converter.rb +102 -0
  53. data/lib/hqmf-parser/cql/data_criteria.rb +57 -0
  54. data/lib/hqmf-parser/cql/data_criteria_helpers/dc_definition_from_template_or_type_extract.rb +79 -0
  55. data/lib/hqmf-parser/cql/data_criteria_helpers/dc_post_processing.rb +43 -0
  56. data/lib/hqmf-parser/cql/document.rb +78 -0
  57. data/lib/hqmf-parser/cql/document_helpers/doc_population_helper.rb +124 -0
  58. data/lib/hqmf-parser/cql/value_set_helper.rb +103 -0
  59. data/lib/hqmf-parser/parser.rb +100 -0
  60. data/lib/qrda-export/catI-r5/qrda1_r5.rb +125 -0
  61. data/lib/qrda-export/helper/cat_1_view_helper.rb +142 -0
  62. data/lib/qrda-export/helper/code_system_helper.rb +77 -0
  63. data/lib/qrda-export/helper/date_helper.rb +81 -0
  64. data/lib/qrda-import/base-importers/demographics_importer.rb +47 -0
  65. data/lib/qrda-import/base-importers/medication_importer.rb +22 -0
  66. data/lib/qrda-import/base-importers/section_importer.rb +196 -0
  67. data/lib/qrda-import/cda_identifier.rb +19 -0
  68. data/lib/qrda-import/data-element-importers/adverse_event_importer.rb +23 -0
  69. data/lib/qrda-import/data-element-importers/allergy_intolerance_importer.rb +21 -0
  70. data/lib/qrda-import/data-element-importers/assessment_performed_importer.rb +23 -0
  71. data/lib/qrda-import/data-element-importers/communication_from_patient_to_provider_importer.rb +18 -0
  72. data/lib/qrda-import/data-element-importers/communication_from_provider_to_patient_importer.rb +18 -0
  73. data/lib/qrda-import/data-element-importers/communication_from_provider_to_provider_importer.rb +20 -0
  74. data/lib/qrda-import/data-element-importers/device_applied_importer.rb +23 -0
  75. data/lib/qrda-import/data-element-importers/device_order_importer.rb +18 -0
  76. data/lib/qrda-import/data-element-importers/diagnosis_importer.rb +23 -0
  77. data/lib/qrda-import/data-element-importers/diagnostic_study_order_importer.rb +20 -0
  78. data/lib/qrda-import/data-element-importers/diagnostic_study_performed_importer.rb +30 -0
  79. data/lib/qrda-import/data-element-importers/encounter_order_importer.rb +20 -0
  80. data/lib/qrda-import/data-element-importers/encounter_performed_importer.rb +41 -0
  81. data/lib/qrda-import/data-element-importers/immunization_administered_importer.rb +18 -0
  82. data/lib/qrda-import/data-element-importers/intervention_order_importer.rb +18 -0
  83. data/lib/qrda-import/data-element-importers/intervention_performed_importer.rb +22 -0
  84. data/lib/qrda-import/data-element-importers/laboratory_test_order_importer.rb +20 -0
  85. data/lib/qrda-import/data-element-importers/laboratory_test_performed_importer.rb +28 -0
  86. data/lib/qrda-import/data-element-importers/medication_active_importer.rb +17 -0
  87. data/lib/qrda-import/data-element-importers/medication_administered_importer.rb +17 -0
  88. data/lib/qrda-import/data-element-importers/medication_discharge_importer.rb +19 -0
  89. data/lib/qrda-import/data-element-importers/medication_dispensed_importer.rb +19 -0
  90. data/lib/qrda-import/data-element-importers/medication_order_importer.rb +16 -0
  91. data/lib/qrda-import/data-element-importers/patient_characteristic_expired.rb +21 -0
  92. data/lib/qrda-import/data-element-importers/physical_exam_performed_importer.rb +26 -0
  93. data/lib/qrda-import/data-element-importers/procedure_order_importer.rb +26 -0
  94. data/lib/qrda-import/data-element-importers/procedure_performed_importer.rb +34 -0
  95. data/lib/qrda-import/data-element-importers/substance_administered_importer.rb +16 -0
  96. data/lib/qrda-import/entry_finder.rb +20 -0
  97. data/lib/qrda-import/entry_package.rb +16 -0
  98. data/lib/qrda-import/narrative_reference_handler.rb +33 -0
  99. data/lib/qrda-import/patient_importer.rb +105 -0
  100. data/lib/util/code_system_helper.rb +76 -0
  101. data/lib/util/counter.rb +20 -0
  102. data/lib/util/hqmf_template_helper.rb +39 -0
  103. metadata +340 -0
@@ -0,0 +1,100 @@
1
+ module HQMF
2
+ class Parser
3
+
4
+ HQMF_VERSION_1 = "1.0"
5
+ HQMF_VERSION_2 = "2.0"
6
+
7
+ # HQMF v2 Parser for measures that use QDM for measure logic
8
+ class V2Parser
9
+ def initialize
10
+ end
11
+
12
+ def parse(xml_contents, codes=nil)
13
+ HQMF::Counter.instance.reset()
14
+ HQMF2::Document.new(xml_contents).to_model
15
+ end
16
+
17
+ def parse_fields(xml_contents)
18
+ result = {}
19
+ doc = HQMF2::Document.parse(xml_contents)
20
+ type = doc.at_xpath('/cda:QualityMeasureDocument/cda:code/@code').value
21
+ if type == '57024-2'
22
+ id = doc.at_xpath('cda:QualityMeasureDocument/cda:id/@extension', HQMF2::Document::NAMESPACES).value.upcase
23
+ set_id = doc.at_xpath('cda:QualityMeasureDocument/cda:setId/@extension').value.upcase
24
+ version_number = doc.at_xpath('cda:QualityMeasureDocument/cda:versionNumber/@value').value.to_i
25
+ title = doc.at_xpath('cda:QualityMeasureDocument/cda:title/@value').inner_text
26
+ description = doc.at_xpath('cda:QualityMeasureDocument/cda:text/@value').inner_text
27
+ result= {'id' => id, 'set_id' => set_id, 'version' => version_number, 'title' => title, 'description' => description}
28
+ end
29
+ result
30
+ end
31
+
32
+ def version
33
+ HQMF_VERSION_2
34
+ end
35
+
36
+ def self.valid?(xml_contents)
37
+ doc = HQMF2::Document.parse(xml_contents)
38
+ !doc.at_xpath("/cda:QualityMeasureDocument/cda:typeId[@root='2.16.840.1.113883.1.3' and @extension='POQM_HD000001UV02']").nil?
39
+ end
40
+
41
+ end
42
+
43
+ # HQMF v2 Parser for measures that use CQL for measure logic
44
+ class V2CQLParser < V2Parser
45
+
46
+ def parse(xml_contents, codes=nil)
47
+ HQMF::Counter.instance.reset()
48
+ HQMF2CQL::Document.new(xml_contents).to_model
49
+ end
50
+
51
+ def self.valid?(xml_contents)
52
+ doc = HQMF2::Document.parse(xml_contents)
53
+ hqmf2 = !doc.at_xpath("/cda:QualityMeasureDocument/cda:typeId[@root='2.16.840.1.113883.1.3' and @extension='POQM_HD000001UV02']").nil?
54
+ cql = !doc.at_xpath("/cda:QualityMeasureDocument/cda:relatedDocument/cda:expressionDocument/cda:text[@mediaType='application/cql']").nil?
55
+ if !cql
56
+ # The media type changed for MAT version 5.3
57
+ cql = !doc.at_xpath("/cda:QualityMeasureDocument/cda:relatedDocument/cda:expressionDocument/cda:text[@mediaType='text/cql']").nil?
58
+ end
59
+ hqmf2 && cql
60
+ end
61
+
62
+ end
63
+
64
+ # HQMF v1 Parser for measures that use QDM for measure logic
65
+ class V1Parser
66
+
67
+ def parse(xml_contents, codes=nil)
68
+ HQMF::Counter.instance.reset()
69
+ HQMF::DocumentConverter.convert(HQMF1::Document.new(xml_contents).to_json, codes)
70
+ end
71
+
72
+ def version
73
+ HQMF_VERSION_1
74
+ end
75
+
76
+ def parse_fields(xml_contents)
77
+ doc = HQMF1::Document.parse(xml_contents)
78
+ type = doc.at_xpath('//cda:code/@code').value
79
+ result = {}
80
+ if type == '57024-2'
81
+ id = doc.at_xpath('//cda:id/@root').value.upcase
82
+ set_id = doc.at_xpath('//cda:setId/@root').value.upcase
83
+ version_number = doc.at_xpath('//cda:versionNumber/@value').value.to_i
84
+ title = doc.at_xpath('cda:QualityMeasureDocument/cda:title').inner_text
85
+ description = doc.at_xpath('cda:QualityMeasureDocument/cda:text').inner_text
86
+ result = {'id' => id, 'set_id' => set_id, 'version' => version_number, 'title' => title, 'description' => description}
87
+ end
88
+ result
89
+ end
90
+
91
+ def self.valid?(xml_contents)
92
+ doc = HQMF1::Document.parse(xml_contents)
93
+ !doc.at_xpath("/cda:QualityMeasureDocument/cda:typeId[@root='2.16.840.1.113883.1.3' and @extension='POQM_HD000001']").nil?
94
+ end
95
+
96
+ end
97
+
98
+ end
99
+
100
+ end
@@ -0,0 +1,125 @@
1
+ require 'mustache'
2
+ class Qrda1R5 < Mustache
3
+ include Qrda::Export::Helper::DateHelper
4
+ include Qrda::Export::Helper::Cat1ViewHelper
5
+
6
+ self.template_path = __dir__
7
+
8
+ def initialize(patient, measures, options = {})
9
+ @patient = patient
10
+ @measures = measures
11
+ @provider = options[:provider]
12
+ @performance_period_start = options[:start_time]
13
+ @performance_period_end = options[:end_time]
14
+ @submission_program = options[:submission_program]
15
+ @insurance_provider = JSON.parse(@patient.extendedData.insurance_providers) if @patient.extendedData && @patient.extendedData['insurance_providers']
16
+ end
17
+
18
+ def adverse_event
19
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.10.20.28.3.120').to_json)
20
+ end
21
+
22
+ def allergy_intolerance
23
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.10.20.28.3.119').to_json)
24
+ end
25
+
26
+ def assessment_performed
27
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.10.20.28.3.117').to_json)
28
+ end
29
+
30
+ def communication_from_patient_to_provider
31
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.3.560.1.30').to_json)
32
+ end
33
+
34
+ def communication_from_provider_to_patient
35
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.31','2.16.840.1.113883.3.560.1.131'] }).to_json)
36
+ end
37
+
38
+ def communication_from_provider_to_provider
39
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.29','2.16.840.1.113883.3.560.1.129'] }).to_json)
40
+ end
41
+
42
+ def diagnosis
43
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.10.20.28.3.110').to_json)
44
+ end
45
+
46
+ def device_ordered
47
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.37','2.16.840.1.113883.3.560.1.137'] }).to_json)
48
+ end
49
+
50
+ def device_applied
51
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.10','2.16.840.1.113883.3.560.1.110'] }).to_json)
52
+ end
53
+
54
+ def diagnostic_study_ordered
55
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.40','2.16.840.1.113883.3.560.1.140'] }).to_json)
56
+ end
57
+
58
+ def diagnostic_study_performed
59
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.103','2.16.840.1.113883.3.560.1.3'] }).to_json)
60
+ end
61
+
62
+ def encounter_ordered
63
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.3.560.1.83').to_json)
64
+ end
65
+
66
+ def encounter_performed
67
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.3.560.1.79').to_json)
68
+ end
69
+
70
+ def immunization_aministered
71
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.10.20.28.3.112'] }).to_json)
72
+ end
73
+
74
+ def intervention_ordered
75
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.45','2.16.840.1.113883.3.560.1.145'] }).to_json)
76
+ end
77
+
78
+ def intervention_performed
79
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.46','2.16.840.1.113883.3.560.1.146'] }).to_json)
80
+ end
81
+
82
+ def lab_test_performed
83
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.3.560.1.5').to_json)
84
+ end
85
+
86
+ def lab_test_ordered
87
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.50','2.16.840.1.113883.3.560.1.150'] }).to_json)
88
+ end
89
+
90
+ def medication_active
91
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.3.560.1.13').to_json)
92
+ end
93
+
94
+ def medication_administered
95
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.14','2.16.840.1.113883.3.560.1.64','2.16.840.1.113883.3.560.1.114'] }).to_json)
96
+ end
97
+
98
+ def medication_discharge
99
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.199','2.16.840.1.113883.3.560.1.200'] }).to_json)
100
+ end
101
+
102
+ def medication_dispensed
103
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.3.560.1.8').to_json)
104
+ end
105
+
106
+ def medication_ordered
107
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.78','2.16.840.1.113883.3.560.1.17'] }).to_json)
108
+ end
109
+
110
+ def patient_characteristic_expired
111
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.10.20.28.3.57').to_json)
112
+ end
113
+
114
+ def physical_exam_performed
115
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.57','2.16.840.1.113883.3.560.1.157'] }).to_json)
116
+ end
117
+
118
+ def procedure_ordered
119
+ JSON.parse(@patient.dataElements.where(hqmfOid: '2.16.840.1.113883.3.560.1.62').to_json)
120
+ end
121
+
122
+ def procedure_performed
123
+ JSON.parse(@patient.dataElements.where(hqmfOid: { '$in' => ['2.16.840.1.113883.3.560.1.6','2.16.840.1.113883.3.560.1.106'] }).to_json)
124
+ end
125
+ end
@@ -0,0 +1,142 @@
1
+ module Qrda
2
+ module Export
3
+ module Helper
4
+ module Cat1ViewHelper
5
+ def random_id
6
+ UUID.generate
7
+ end
8
+
9
+ def as_id
10
+ self['$oid']
11
+ end
12
+
13
+ def object_id
14
+ self[:_id]['$oid']
15
+ end
16
+
17
+ def submission_program
18
+ @submission_program
19
+ end
20
+
21
+ def provider
22
+ JSON.parse(@provider.to_json) if @provider
23
+ end
24
+
25
+ def provider_addresses
26
+ @provider['addresses']
27
+ end
28
+
29
+ def provider_street
30
+ self['street'].join('')
31
+ end
32
+
33
+ def provider_npi
34
+ @provider['cda_identifiers'].map { |cda| cda['extension'] if cda['root'] == '2.16.840.1.113883.4.6' }.compact.first
35
+ end
36
+
37
+ def provider_tin
38
+ @provider['cda_identifiers'].map { |cda| cda['extension'] if cda['root'] == '2.16.840.1.113883.4.2' }.compact.first
39
+ end
40
+
41
+ def provider_ccn
42
+ @provider['cda_identifiers'].map { |cda| cda['extension'] if cda['root'] == '2.16.840.1.113883.4.336' }.compact.first
43
+ end
44
+
45
+ def provider_type_code
46
+ @provider['specialty']
47
+ end
48
+
49
+ def mrn
50
+ @patient.extendedData['medical_record_number']
51
+ end
52
+
53
+ def given_name
54
+ @patient.givenNames.join(' ')
55
+ end
56
+
57
+ def family_name
58
+ @patient.familyName
59
+ end
60
+
61
+ def birthdate
62
+ @patient.birthDatetime.to_formatted_s(:number)
63
+ end
64
+
65
+ def gender
66
+ @patient.dataElements.where(hqmfOid: '2.16.840.1.113883.10.20.28.3.55').first.dataElementCodes.first['code']
67
+ end
68
+
69
+ def race
70
+ @patient.dataElements.where(hqmfOid: '2.16.840.1.113883.10.20.28.3.59').first.dataElementCodes.first['code']
71
+ end
72
+
73
+ def ethnic_group
74
+ @patient.dataElements.where(hqmfOid: '2.16.840.1.113883.10.20.28.3.56').first.dataElementCodes.first['code']
75
+ end
76
+
77
+ def insurance_provider
78
+ @insurance_provider
79
+ end
80
+
81
+ def insurance_provider_code_and_code_system
82
+ "code=\"#{self['codes'].values.first[0]}\" codeSystem=\"#{code_system_oid(self['codes'].keys.first)}\" codeSystemName=\"#{self['codes'].keys.first}\""
83
+ end
84
+
85
+ def measures
86
+ @measures.only(:hqmf_id, :hqmf_set_id, :description).as_json
87
+ end
88
+
89
+ def negation_ind
90
+ self[:negationRationale].nil? ? "" : "negationInd=\"true\""
91
+ end
92
+
93
+ def negated
94
+ self[:negationRationale].nil? ? false : true
95
+ end
96
+
97
+ def multiple_codes?
98
+ self[:dataElementCodes].size > 1
99
+ end
100
+
101
+ def code_system_oid(name)
102
+ Qrda::Export::Helper::CodeSystemHelper.oid_for_code_system(name)
103
+ end
104
+
105
+ def code_and_codesystem
106
+ "code=\"#{self['code']}\" codeSystem=\"#{code_system_oid(self['codeSystem'])}\" codeSystemName=\"#{self['codeSystem']}\""
107
+ end
108
+
109
+ def primary_code_and_codesystem
110
+ "code=\"#{self[:dataElementCodes][0]['code']}\" codeSystem=\"#{code_system_oid(self[:dataElementCodes][0]['codeSystem'])}\" codeSystemName=\"#{self[:dataElementCodes][0]['codeSystem']}\""
111
+ end
112
+
113
+ def translation_codes_and_codesystem_list
114
+ translation_list = ""
115
+ self[:dataElementCodes].each_with_index do |_dec, index|
116
+ next if index.zero?
117
+ translation_list += "<translation code=\"#{self[:dataElementCodes][index]['code']}\" codeSystem=\"#{code_system_oid(self[:dataElementCodes][index]['codeSystem'])}\" codeSystemName=\"#{self[:dataElementCodes][index]['codeSystem']}\"/>"
118
+ end
119
+ translation_list
120
+ end
121
+
122
+ def result_value
123
+ return "<value xsi:type=\"CD\" nullFlavor=\"UNK\"/>" unless self['result']
124
+ result_string = if self['result'].is_a? Array
125
+ result_value_as_string(self['result'][0])
126
+ elsif self['result'].is_a? Hash
127
+ result_value_as_string(self['result'])
128
+ elsif !self['result'].nil?
129
+ "<value xsi:type=\"PQ\" value=\"#{self['result']}\" unit=\"1\"/>"
130
+ end
131
+ result_string
132
+ end
133
+
134
+ def result_value_as_string(result)
135
+ return "<value xsi:type=\"CD\" nullFlavor=\"UNK\"/>" unless result
136
+ return "<value xsi:type=\"CD\" code=\"#{result['code']}\" codeSystem=\"#{code_system_oid(result['codeSystem'])}\" codeSystemName=\"#{result['codeSystem']}\"/>" if result['code']
137
+ return "<value xsi:type=\"PQ\" value=\"#{result['value']}\" unit=\"#{result['unit']}\"/>" if result['unit']
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,77 @@
1
+ module Qrda
2
+ module Export
3
+ module Helper
4
+ # General helpers for working with codes and code systems
5
+ class CodeSystemHelper
6
+ CODE_SYSTEMS = {
7
+ '2.16.840.1.113883.6.1' => 'LOINC',
8
+ '2.16.840.1.113883.6.96' => 'SNOMED-CT',
9
+ '2.16.840.1.113883.6.12' => 'CPT',
10
+ '2.16.840.1.113883.6.88' => 'RxNorm',
11
+ '2.16.840.1.113883.6.103' => 'ICD-9-CM',
12
+ '2.16.840.1.113883.6.104' => 'ICD-9-PCS',
13
+ '2.16.840.1.113883.6.4' => 'ICD-10-PCS',
14
+ '2.16.840.1.113883.6.90' => 'ICD-10-CM',
15
+ '2.16.840.1.113883.6.14' => 'HCP',
16
+ '2.16.840.1.113883.6.285' => 'HCPCS',
17
+ '2.16.840.1.113883.5.2' => "HL7 Marital Status",
18
+ '2.16.840.1.113883.12.292' => 'CVX',
19
+ '2.16.840.1.113883.5.83' => 'HITSP C80 Observation Status',
20
+ '2.16.840.1.113883.3.26.1.1' => 'NCI Thesaurus',
21
+ '2.16.840.1.113883.3.88.12.80.20' => 'FDA',
22
+ "2.16.840.1.113883.4.9" => "UNII",
23
+ "2.16.840.1.113883.6.69" => "NDC",
24
+ '2.16.840.1.113883.5.14' => 'HL7 ActStatus',
25
+ '2.16.840.1.113883.6.259' => 'HL7 Healthcare Service Location',
26
+ '2.16.840.1.113883.12.112' => 'DischargeDisposition',
27
+ '2.16.840.1.113883.5.4' => 'HL7 Act Code',
28
+ '2.16.840.1.113883.1.11.18877' => 'HL7 Relationship Code',
29
+ '2.16.840.1.113883.6.238' => 'CDC Race',
30
+ '2.16.840.1.113883.6.177' => 'NLM MeSH',
31
+ '2.16.840.1.113883.5.1076' => "Religious Affiliation",
32
+ '2.16.840.1.113883.1.11.19717' => "HL7 ActNoImmunicationReason",
33
+ '2.16.840.1.113883.3.88.12.80.33' => "NUBC",
34
+ '2.16.840.1.113883.1.11.78' => "HL7 Observation Interpretation",
35
+ '2.16.840.1.113883.3.221.5' => "Source of Payment Typology",
36
+ '2.16.840.1.113883.6.13' => 'CDT',
37
+ '2.16.840.1.113883.18.2' => 'AdministrativeSex'
38
+ }
39
+
40
+ CODE_SYSTEM_ALIASES = {
41
+ 'FDA SPL' => 'NCI Thesaurus',
42
+ 'HSLOC' => 'HL7 Healthcare Service Location',
43
+ 'SOP' => "Source of Payment Typology"
44
+ }
45
+
46
+ # Some old OID are still around in data, this hash maps retired OID values to
47
+ # the new value
48
+ OID_ALIASES = {
49
+ '2.16.840.1.113883.6.59' => '2.16.840.1.113883.12.292' # CVX
50
+ }
51
+
52
+ # Returns the name of a code system given an oid
53
+ # @param [String] oid of a code system
54
+ # @return [String] the name of the code system as described in the measure definition JSON
55
+ def self.code_system_for(oid)
56
+ oid = OID_ALIASES[oid] if OID_ALIASES[oid]
57
+ CODE_SYSTEMS[oid] || "Unknown"
58
+ end
59
+
60
+ # Returns the oid for a code system given a codesystem name
61
+ # @param [String] the name of the code system
62
+ # @return [String] the oid of the code system
63
+ def self.oid_for_code_system(code_system)
64
+ code_system = CODE_SYSTEM_ALIASES[code_system] if CODE_SYSTEM_ALIASES[code_system]
65
+ CODE_SYSTEMS.invert[code_system]
66
+ end
67
+
68
+ # Returns the whole map of OIDs to code systems
69
+ # @terurn [Hash] oids as keys, code system names as values
70
+ def self.code_systems
71
+ CODE_SYSTEMS
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
@@ -0,0 +1,81 @@
1
+ module Qrda
2
+ module Export
3
+ module Helper
4
+ module DateHelper
5
+ def value_or_null_flavor(time)
6
+ # this is a bit of a hack for a defineded undefined date
7
+ if time && DateTime.parse(time).year < 3000
8
+ "value='#{DateTime.parse(time).utc.to_formatted_s(:number)}'"
9
+ else
10
+ "nullFlavor='UNK'"
11
+ end
12
+ end
13
+
14
+ def performance_period_start
15
+ @performance_period_start.to_formatted_s(:number)
16
+ end
17
+
18
+ def performance_period_end
19
+ @performance_period_end.to_formatted_s(:number)
20
+ end
21
+
22
+ def author_time
23
+ "<time #{value_or_null_flavor(self['authorDatetime'])}/>"
24
+ end
25
+
26
+ def author_effective_time
27
+ "<effectiveTime #{value_or_null_flavor(self['authorDatetime'])}/>"
28
+ end
29
+
30
+ def expired_date_time
31
+ "<effectiveTime>"\
32
+ "<low #{value_or_null_flavor(self['expiredDatetime'])}/>"\
33
+ "</effectiveTime>"
34
+ end
35
+
36
+ def prevalence_period
37
+ "<effectiveTime>"\
38
+ "<low #{value_or_null_flavor(self['prevalencePeriod']['low'])}/>"\
39
+ "<high #{value_or_null_flavor(self['prevalencePeriod']['high'])}/>"\
40
+ "</effectiveTime>"
41
+ end
42
+
43
+ def relevant_period
44
+ "<effectiveTime>"\
45
+ "<low #{value_or_null_flavor(self['relevantPeriod']['low'])}/>"\
46
+ "<high #{value_or_null_flavor(self['relevantPeriod']['high'])}/>"\
47
+ "</effectiveTime>"
48
+ end
49
+
50
+ def insurance_provider_period
51
+ start_time = self['start_time'] ? DateTime.strptime(self['start_time'].to_s, '%s').to_s : nil
52
+ end_time = self['end_time'] ? DateTime.strptime(self['end_time'].to_s, '%s').to_s : nil
53
+ "<effectiveTime>"\
54
+ "<low #{value_or_null_flavor(start_time)}/>"\
55
+ "<high #{value_or_null_flavor(end_time)}/>"\
56
+ "</effectiveTime>"
57
+ end
58
+
59
+ def medication_duration_effective_time
60
+ "<effectiveTime xsi:type=\"IVL_TS\">"\
61
+ "<low #{value_or_null_flavor(self['relevantPeriod']['low'])}/>"\
62
+ "<high #{value_or_null_flavor(self['relevantPeriod']['high'])}/>"\
63
+ "</effectiveTime>"
64
+ end
65
+
66
+ def facility_period
67
+ "<low #{value_or_null_flavor(self['locationPeriod']['low'])}/>"\
68
+ "<high #{value_or_null_flavor(self['locationPeriod']['high'])}/>"
69
+ end
70
+
71
+ def incision_datetime
72
+ "<effectiveTime #{value_or_null_flavor(self['incisionDatetime'])}/>"
73
+ end
74
+
75
+ def completed_prevalence_period
76
+ self['prevalencePeriod']['high'] ? true : false
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end