cqm-reports 2.0.4 → 2.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 +5 -5
- data/Gemfile +0 -1
- data/README.md +27 -0
- data/lib/cqm_report.rb +1 -4
- data/lib/qrda-export/catI-r5/_header.mustache +2 -2
- data/lib/qrda-export/catI-r5/qrda1_r5.mustache +2 -2
- data/lib/qrda-export/catI-r5/qrda1_r5.rb +24 -2
- data/lib/qrda-export/catI-r5/qrda_header/_record_target.mustache +24 -11
- data/lib/qrda-export/catI-r5/qrda_templates/allergy_intolerance.mustache +1 -6
- data/lib/qrda-export/catI-r5/qrda_templates/communication_performed.mustache +2 -2
- data/lib/qrda-export/catI-r5/qrda_templates/diagnosis.mustache +1 -6
- data/lib/qrda-export/catI-r5/qrda_templates/immunization_administered.mustache +7 -2
- data/lib/qrda-export/catI-r5/qrda_templates/medication_discharge.mustache +0 -2
- data/lib/qrda-export/catI-r5/qrda_templates/substance_recommended.mustache +1 -0
- data/lib/qrda-export/catI-r5/qrda_templates/symptom.mustache +1 -6
- data/lib/qrda-export/catI-r5/qrda_templates/template_partials/_medication_supply_request.mustache +1 -1
- data/lib/qrda-export/helper/cat1_view_helper.rb +2 -0
- data/lib/qrda-import/base-importers/demographics_importer.rb +3 -3
- data/lib/qrda-import/base-importers/section_importer.rb +44 -10
- data/lib/qrda-import/data-element-importers/diagnostic_study_performed_importer.rb +1 -1
- data/lib/qrda-import/data-element-importers/encounter_performed_importer.rb +10 -0
- data/lib/qrda-import/data-element-importers/immunization_order_importer.rb +1 -1
- data/lib/qrda-import/patient_importer.rb +85 -63
- metadata +18 -6
- data/lib/ext/code.rb +0 -11
- data/lib/ext/data_element.rb +0 -24
- data/lib/qrda-import/entry_package.rb +0 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: e8ef5e1f1c6d14646a8d523109b41d9d9609503c
|
|
4
|
+
data.tar.gz: 1ccc64f200b387965a3271501cb933e795435cba
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 62af1b280c4701bed265910f768bb6d19be6f087bd028b022b9cdfbd4b02fae834252fc1ed0798e6555b4e978962f9e4d237d27c9528523cc5c6ba89d8ace2e1
|
|
7
|
+
data.tar.gz: 71cc7d395c9af17f8d946e28ac108f25142c9d2e4e6028e4799e8297fb8a5fc47f1b898939554cbd7616494320ec9d79c8caa489fc8bda0b60f3eb4050f8d69f
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -18,6 +18,33 @@ Starting with version **2.0.0** released on 6/20/2019, cqm-reports versioning ha
|
|
|
18
18
|
|
|
19
19
|
For the versions available, see [tags on this repository](https://github.com/projecttacoma/cqm-validators/tags).
|
|
20
20
|
|
|
21
|
+
=======
|
|
22
|
+
Importing QRDA
|
|
23
|
+
==========
|
|
24
|
+
|
|
25
|
+
A QRDA document can be imported into a CQM::Patient (defined in [cqm-models](https://github.com/projecttacoma/cqm-models)) using the following commands.
|
|
26
|
+
|
|
27
|
+
doc = Nokogiri::XML(file)
|
|
28
|
+
patient, warnings = QRDA::Cat1::PatientImporter.instance.parse_cat1(doc)
|
|
29
|
+
|
|
30
|
+
Exporting QRDA Category I
|
|
31
|
+
==========
|
|
32
|
+
|
|
33
|
+
Exporting a QRDA document from a CQM::Patient (defined in [cqm-models](https://github.com/projecttacoma/cqm-models)) using the following command.
|
|
34
|
+
|
|
35
|
+
Qrda1R5.new(patient, measures, options).render
|
|
36
|
+
* patient is a [CQM::Patient](https://github.com/projecttacoma/cqm-models/blob/master/app/models/cqm/patient.rb)
|
|
37
|
+
* measures is an array of [CQM::Measure](https://github.com/projecttacoma/cqm-models/blob/master/app/models/cqm/measure.rb)
|
|
38
|
+
* options is a hash that can be used to pass in:
|
|
39
|
+
* provider
|
|
40
|
+
* patient_addresses
|
|
41
|
+
* patient_telecoms
|
|
42
|
+
* start_time
|
|
43
|
+
* end_time
|
|
44
|
+
* submission_program
|
|
45
|
+
|
|
46
|
+
QRDA export requires the [mustache](https://github.com/mustache/mustache) gem
|
|
47
|
+
|
|
21
48
|
## License
|
|
22
49
|
|
|
23
50
|
Copyright 2019 The MITRE Corporation
|
data/lib/cqm_report.rb
CHANGED
|
@@ -18,7 +18,6 @@ require_relative 'html-export/qdm-patient/qdm_patient.rb'
|
|
|
18
18
|
require_relative 'qrda-export/catI-r5/qrda1_r5.rb'
|
|
19
19
|
require_relative 'qrda-export/catIII-r2-1/qrda3_r21.rb'
|
|
20
20
|
|
|
21
|
-
require_relative 'qrda-import/entry_package.rb'
|
|
22
21
|
require_relative 'qrda-import/cda_identifier.rb'
|
|
23
22
|
require_relative 'qrda-import/narrative_reference_handler.rb'
|
|
24
23
|
require_relative 'qrda-import/entry_finder.rb'
|
|
@@ -72,6 +71,4 @@ require_relative 'qrda-import/data-element-importers/substance_administered_impo
|
|
|
72
71
|
require_relative 'qrda-import/data-element-importers/substance_order_importer.rb'
|
|
73
72
|
require_relative 'qrda-import/data-element-importers/substance_recommended_importer.rb'
|
|
74
73
|
require_relative 'qrda-import/data-element-importers/symptom_importer.rb'
|
|
75
|
-
require_relative 'qrda-import/patient_importer.rb'
|
|
76
|
-
require_relative 'ext/data_element.rb'
|
|
77
|
-
require_relative 'ext/code.rb'
|
|
74
|
+
require_relative 'qrda-import/patient_importer.rb'
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
<!-- QRDA templateId -->
|
|
7
7
|
<templateId root="2.16.840.1.113883.10.20.24.1.1" extension="2017-08-01"/>
|
|
8
8
|
<!-- QDM-based QRDA templateId -->
|
|
9
|
-
<templateId root="2.16.840.1.113883.10.20.24.1.2" extension="
|
|
9
|
+
<templateId root="2.16.840.1.113883.10.20.24.1.2" extension="2018-10-01"/>
|
|
10
10
|
<!-- CMS QRDA templateId -->
|
|
11
|
-
<templateId root="2.16.840.1.113883.10.20.24.1.3" extension="
|
|
11
|
+
<templateId root="2.16.840.1.113883.10.20.24.1.3" extension="2019-02-01"/>
|
|
12
12
|
<!-- This is the globally unique identifier for this QRDA document -->
|
|
13
13
|
<id root="{{random_id}}"/>
|
|
14
14
|
<!-- QRDA document type code -->
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
<!-- This is the templateId for Patient Data section -->
|
|
13
13
|
<templateId root="2.16.840.1.113883.10.20.17.2.4"/>
|
|
14
14
|
<!-- This is the templateId for Patient Data QDM section -->
|
|
15
|
-
<templateId extension="
|
|
16
|
-
<templateId extension="
|
|
15
|
+
<templateId extension="2018-10-01" root="2.16.840.1.113883.10.20.24.2.1"/>
|
|
16
|
+
<templateId extension="2019-02-01" root="2.16.840.1.113883.10.20.24.2.1.1"/>
|
|
17
17
|
<code code="55188-7" codeSystem="2.16.840.1.113883.6.1"/>
|
|
18
18
|
<title>Patient Data</title>
|
|
19
19
|
<text/>
|
|
@@ -13,11 +13,33 @@ class Qrda1R5 < Mustache
|
|
|
13
13
|
@qdmPatient = patient.qdmPatient
|
|
14
14
|
@measures = measures
|
|
15
15
|
@provider = options[:provider]
|
|
16
|
+
@patient_address_option = options[:patient_addresses]
|
|
17
|
+
@patient_telecom_option = options[:patient_telecoms]
|
|
16
18
|
@performance_period_start = options[:start_time]
|
|
17
19
|
@performance_period_end = options[:end_time]
|
|
18
20
|
@submission_program = options[:submission_program]
|
|
19
21
|
end
|
|
20
22
|
|
|
23
|
+
def patient_addresses
|
|
24
|
+
@patient_address_option ||= [CQM::Address.new(
|
|
25
|
+
use: 'HP',
|
|
26
|
+
street: ['202 Burlington Rd.'],
|
|
27
|
+
city: 'Bedford',
|
|
28
|
+
state: 'MA',
|
|
29
|
+
zip: '01730',
|
|
30
|
+
country: 'US'
|
|
31
|
+
)]
|
|
32
|
+
JSON.parse(@patient_address_option.to_json)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def patient_telecoms
|
|
36
|
+
@patient_telecom_option ||= [CQM::Telecom.new(
|
|
37
|
+
use: 'HP',
|
|
38
|
+
value: '555-555-2003'
|
|
39
|
+
)]
|
|
40
|
+
JSON.parse(@patient_telecom_option.to_json)
|
|
41
|
+
end
|
|
42
|
+
|
|
21
43
|
def patient_characteristic_payer
|
|
22
44
|
JSON.parse(@qdmPatient.get_data_elements('patient_characteristic', 'payer').to_json)
|
|
23
45
|
end
|
|
@@ -173,7 +195,7 @@ class Qrda1R5 < Mustache
|
|
|
173
195
|
def physical_exam_order
|
|
174
196
|
JSON.parse(@qdmPatient.get_data_elements('physical_exam', 'order').to_json)
|
|
175
197
|
end
|
|
176
|
-
|
|
198
|
+
|
|
177
199
|
def physical_exam_performed
|
|
178
200
|
JSON.parse(@qdmPatient.get_data_elements('physical_exam', 'performed').to_json)
|
|
179
201
|
end
|
|
@@ -213,7 +235,7 @@ class Qrda1R5 < Mustache
|
|
|
213
235
|
def substance_recommended
|
|
214
236
|
JSON.parse(@qdmPatient.get_data_elements('substance', 'recommended').to_json)
|
|
215
237
|
end
|
|
216
|
-
|
|
238
|
+
|
|
217
239
|
def symptom
|
|
218
240
|
JSON.parse(@qdmPatient.get_data_elements('symptom', nil).to_json)
|
|
219
241
|
end
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
<recordTarget>
|
|
2
2
|
<patientRole>
|
|
3
3
|
<id extension="{{mrn}}" root="1.3.6.1.4.1.115" />
|
|
4
|
-
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
{{#patient_addresses}}
|
|
5
|
+
<addr use="{{use}}">
|
|
6
|
+
{{#street}}
|
|
7
|
+
<streetAddressLine>{{.}}</streetAddressLine>
|
|
8
|
+
{{/street}}
|
|
9
|
+
<city>{{city}}</city>
|
|
10
|
+
<state>{{state}}</state>
|
|
11
|
+
<postalCode>{{zip}}</postalCode>
|
|
12
|
+
<country>{{country}}</country>
|
|
13
|
+
</addr>
|
|
14
|
+
{{/patient_addresses}}
|
|
15
|
+
{{#patient_telecoms}}
|
|
16
|
+
<telecom use="{{use}}" value="tel:{{value}}"/>
|
|
17
|
+
{{/patient_telecoms}}
|
|
12
18
|
<patient>
|
|
13
19
|
{{#patient}}
|
|
14
20
|
<name>
|
|
@@ -21,6 +27,9 @@
|
|
|
21
27
|
<administrativeGenderCode {{> _code}}/>
|
|
22
28
|
{{/dataElementCodes}}
|
|
23
29
|
{{/patient_characteristic_sex}}
|
|
30
|
+
{{^patient_characteristic_sex}}
|
|
31
|
+
<administrativeGenderCode nullFlavor="UNK"/>
|
|
32
|
+
{{/patient_characteristic_sex}}
|
|
24
33
|
{{#patient_characteristic_birthdate}}
|
|
25
34
|
{{{birth_date_time}}}
|
|
26
35
|
{{/patient_characteristic_birthdate}}
|
|
@@ -29,16 +38,20 @@
|
|
|
29
38
|
<raceCode {{> _code}}/>
|
|
30
39
|
{{/dataElementCodes}}
|
|
31
40
|
{{/patient_characteristic_race}}
|
|
41
|
+
{{^patient_characteristic_race}}
|
|
42
|
+
<raceCode nullFlavor="UNK"/>
|
|
43
|
+
{{/patient_characteristic_race}}
|
|
32
44
|
{{#patient_characteristic_ethnicity}}
|
|
33
45
|
{{#dataElementCodes}}
|
|
34
46
|
<ethnicGroupCode {{> _code}}/>
|
|
35
47
|
{{/dataElementCodes}}
|
|
36
48
|
{{/patient_characteristic_ethnicity}}
|
|
49
|
+
{{^patient_characteristic_ethnicity}}
|
|
50
|
+
<ethnicGroupCode nullFlavor="UNK"/>
|
|
51
|
+
{{/patient_characteristic_ethnicity}}
|
|
37
52
|
<languageCommunication>
|
|
38
|
-
<templateId root="2.16.840.1.113883.3.88.11.83.2" assigningAuthorityName="HITSP/C83"/>
|
|
39
|
-
<templateId root="1.3.6.1.4.1.19376.1.5.3.1.2.1" assigningAuthorityName="IHE/PCC"/>
|
|
40
53
|
<languageCode code="eng"/>
|
|
41
54
|
</languageCommunication>
|
|
42
55
|
</patient>
|
|
43
56
|
</patientRole>
|
|
44
|
-
</recordTarget>
|
|
57
|
+
</recordTarget>
|
|
@@ -6,13 +6,8 @@
|
|
|
6
6
|
<templateId root="2.16.840.1.113883.10.20.24.3.147" extension="2017-08-01"/>
|
|
7
7
|
<id root="1.3.6.1.4.1.115" extension="{{object_id}}"/>
|
|
8
8
|
<code code="ASSERTION" codeSystem="2.16.840.1.113883.5.4"/>
|
|
9
|
-
{{#prevalencePeriod}}
|
|
10
|
-
{{#completed_prevalence_period}}
|
|
11
9
|
<statusCode code="completed" />
|
|
12
|
-
{{
|
|
13
|
-
{{^completed_prevalence_period}}
|
|
14
|
-
<statusCode code="active" />
|
|
15
|
-
{{/completed_prevalence_period}}
|
|
10
|
+
{{#prevalencePeriod}}
|
|
16
11
|
<!-- QDM Attribute: Prevalence Period -->
|
|
17
12
|
{{{prevalence_period}}}
|
|
18
13
|
{{/prevalencePeriod}}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
{{/category}}
|
|
9
9
|
{{^category}}
|
|
10
10
|
<!-- QDM Attribute: Category -->
|
|
11
|
-
<code nullFlavor="
|
|
11
|
+
<code nullFlavor="NA"/>
|
|
12
12
|
{{/category}}
|
|
13
13
|
<statusCode code="completed"/>
|
|
14
14
|
{{#relevantPeriod}}
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
{{/negationRationale}}
|
|
49
49
|
<entryRelationship typeCode="REFR">
|
|
50
50
|
<observation classCode="OBS" moodCode="EVN">
|
|
51
|
-
<templateId root="2.16.840.1.113883.10.20.24.3.88" extension="
|
|
51
|
+
<templateId root="2.16.840.1.113883.10.20.24.3.88" extension="2017-08-01"/>
|
|
52
52
|
<id root="1.3.6.1.4.1.115" extension="{{object_id}}" />
|
|
53
53
|
<code code="77301-0" codeSystem="2.16.840.1.113883.6.1" displayName="reason" codeSystemName="LOINC"/>
|
|
54
54
|
<statusCode code="completed"/>
|
|
@@ -25,13 +25,8 @@
|
|
|
25
25
|
<code code="29308-4" codeSystem="2.16.840.1.113883.6.1">
|
|
26
26
|
<translation code="282291009" codeSystem="2.16.840.1.113883.6.96"/>
|
|
27
27
|
</code>
|
|
28
|
-
{{#prevalencePeriod}}
|
|
29
|
-
{{#completed_prevalence_period}}
|
|
30
28
|
<statusCode code="completed" />
|
|
31
|
-
{{
|
|
32
|
-
{{^completed_prevalence_period}}
|
|
33
|
-
<statusCode code="active" />
|
|
34
|
-
{{/completed_prevalence_period}}
|
|
29
|
+
{{#prevalencePeriod}}
|
|
35
30
|
<!-- QDM Attribute: Prevalence Period -->
|
|
36
31
|
{{{prevalence_period}}}
|
|
37
32
|
{{/prevalencePeriod}}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
<entry>
|
|
2
|
-
|
|
2
|
+
{{#negated}}
|
|
3
|
+
<substanceAdministration classCode="SBADM" moodCode="EVN" {{{negation_ind}}}>
|
|
4
|
+
{{/negated}}
|
|
5
|
+
{{^negated}}
|
|
6
|
+
<substanceAdministration classCode="SBADM" moodCode="EVN" negationInd="false">
|
|
7
|
+
{{/negated}}
|
|
3
8
|
<!-- C-CDA R2 Immunization Activity -->
|
|
4
|
-
<templateId root="2.16.840.1.113883.10.20.22.4.52" extension="
|
|
9
|
+
<templateId root="2.16.840.1.113883.10.20.22.4.52" extension="2015-08-01"/>
|
|
5
10
|
<!-- Immunization Administered -->
|
|
6
11
|
<templateId root="2.16.840.1.113883.10.20.24.3.140" extension="2017-08-01"/>
|
|
7
12
|
<id root="1.3.6.1.4.1.115" extension="{{object_id}}"/>
|
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|
<substanceAdministration moodCode="EVN" classCode="SBADM">
|
|
10
10
|
<!-- Medication Activity (consolidation) template -->
|
|
11
11
|
<templateId root="2.16.840.1.113883.10.20.22.4.16" extension="2014-06-09"/>
|
|
12
|
-
<!-- Medication, Active template -->
|
|
13
|
-
<templateId root="2.16.840.1.113883.10.20.24.3.41" extension="2016-02-01"/>
|
|
14
12
|
<id root="1.3.6.1.4.1.115" extension="{{object_id}}"/>
|
|
15
13
|
<text>{{description}}</text>
|
|
16
14
|
<statusCode code="active"/>
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
<templateId root="2.16.840.1.113883.10.20.24.3.75" extension="2017-08-01"/>
|
|
7
7
|
<id root="1.3.6.1.4.1.115" extension="{{object_id}}"/>
|
|
8
8
|
<statusCode code="active"/>
|
|
9
|
+
{{{author_effective_time}}}
|
|
9
10
|
{{> qrda_templates/template_partials/_medication_details}}
|
|
10
11
|
<consumable>
|
|
11
12
|
<manufacturedProduct classCode="MANU">
|
|
@@ -25,13 +25,8 @@
|
|
|
25
25
|
<code code="75325-1" codeSystem="2.16.840.1.113883.6.1">
|
|
26
26
|
<translation code="418799008" displayName="Symptom" codeSystem="2.16.840.1.113883.6.96"/>
|
|
27
27
|
</code>
|
|
28
|
-
{{#prevalencePeriod}}
|
|
29
|
-
{{#completed_prevalence_period}}
|
|
30
28
|
<statusCode code="completed" />
|
|
31
|
-
{{
|
|
32
|
-
{{^completed_prevalence_period}}
|
|
33
|
-
<statusCode code="active" />
|
|
34
|
-
{{/completed_prevalence_period}}
|
|
29
|
+
{{#prevalencePeriod}}
|
|
35
30
|
<!-- QDM Attribute: Prevalence Period -->
|
|
36
31
|
{{{prevalence_period}}}
|
|
37
32
|
{{/prevalencePeriod}}
|
data/lib/qrda-export/catI-r5/qrda_templates/template_partials/_medication_supply_request.mustache
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<supply classCode="SPLY" moodCode="RQO">
|
|
2
2
|
<!-- Medication Supply Request (V2) template -->
|
|
3
|
-
<templateId root="2.16.840.1.113883.10.20.24.3.99" extension="
|
|
3
|
+
<templateId root="2.16.840.1.113883.10.20.24.3.99" extension="2015-04-05"/>
|
|
4
4
|
<!-- Conforms to C-CDA R2 Planned Supply (V2) template-->
|
|
5
5
|
<templateId root="2.16.840.1.113883.10.20.22.4.43" extension="2014-06-09" />
|
|
6
6
|
<id root="{{random_id}}"/>
|
|
@@ -67,6 +67,8 @@ module Qrda
|
|
|
67
67
|
result_value_as_string(self['result'][0])
|
|
68
68
|
elsif self['result'].is_a? Hash
|
|
69
69
|
result_value_as_string(self['result'])
|
|
70
|
+
elsif self['result'].is_a? String
|
|
71
|
+
"<value xsi:type=\"ST\">#{self['result']}</value>"
|
|
70
72
|
elsif !self['result'].nil?
|
|
71
73
|
"<value xsi:type=\"PQ\" value=\"#{self['result']}\" unit=\"1\"/>"
|
|
72
74
|
end
|
|
@@ -15,17 +15,17 @@ module QRDA
|
|
|
15
15
|
pcs = QDM::PatientCharacteristicSex.new
|
|
16
16
|
code_element = patient_element.at_xpath('cda:administrativeGenderCode')
|
|
17
17
|
pcs.dataElementCodes = [code_if_present(code_element)]
|
|
18
|
-
patient.qdmPatient.dataElements << pcs
|
|
18
|
+
patient.qdmPatient.dataElements << pcs unless pcs.dataElementCodes.compact.blank?
|
|
19
19
|
|
|
20
20
|
pcr = QDM::PatientCharacteristicRace.new
|
|
21
21
|
code_element = patient_element.at_xpath('cda:raceCode')
|
|
22
22
|
pcr.dataElementCodes = [code_if_present(code_element)]
|
|
23
|
-
patient.qdmPatient.dataElements << pcr
|
|
23
|
+
patient.qdmPatient.dataElements << pcr unless pcr.dataElementCodes.compact.blank?
|
|
24
24
|
|
|
25
25
|
pce = QDM::PatientCharacteristicEthnicity.new
|
|
26
26
|
code_element = patient_element.at_xpath('cda:ethnicGroupCode')
|
|
27
27
|
pce.dataElementCodes = [code_if_present(code_element)]
|
|
28
|
-
patient.qdmPatient.dataElements << pce
|
|
28
|
+
patient.qdmPatient.dataElements << pce unless pce.dataElementCodes.compact.blank?
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def code_if_present(code_element)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module QRDA
|
|
2
2
|
module Cat1
|
|
3
3
|
class SectionImporter
|
|
4
|
-
attr_accessor :check_for_usable, :status_xpath, :code_xpath
|
|
4
|
+
attr_accessor :check_for_usable, :status_xpath, :code_xpath, :warnings, :codes_modifiers
|
|
5
5
|
|
|
6
6
|
def initialize(entry_finder)
|
|
7
7
|
@entry_finder = entry_finder
|
|
@@ -9,6 +9,8 @@ module QRDA
|
|
|
9
9
|
@entry_id_map = {}
|
|
10
10
|
@check_for_usable = true
|
|
11
11
|
@entry_class = QDM::DataElement
|
|
12
|
+
@warnings = []
|
|
13
|
+
@codes_modifiers = {}
|
|
12
14
|
end
|
|
13
15
|
|
|
14
16
|
# Traverses an HL7 CDA document passed in and creates an Array of Entry
|
|
@@ -41,7 +43,7 @@ module QRDA
|
|
|
41
43
|
# This is the id found in the QRDA file
|
|
42
44
|
entry_qrda_id = extract_id(entry_element, @id_xpath)
|
|
43
45
|
# Create a hash to map all of entry.ids to the same QRDA ids. This will be used to merge QRDA entries
|
|
44
|
-
# that represent the same event.
|
|
46
|
+
# that represent the same event.
|
|
45
47
|
@entry_id_map["#{entry_qrda_id.value}_#{entry_qrda_id.namingSystem}"] ||= []
|
|
46
48
|
@entry_id_map["#{entry_qrda_id.value}_#{entry_qrda_id.namingSystem}"] << entry.id
|
|
47
49
|
entry.dataElementCodes = extract_codes(entry_element, @code_xpath)
|
|
@@ -90,6 +92,7 @@ module QRDA
|
|
|
90
92
|
end
|
|
91
93
|
|
|
92
94
|
def extract_interval(parent_element, interval_xpath)
|
|
95
|
+
return nil unless parent_element.at_xpath(interval_xpath)
|
|
93
96
|
if parent_element.at_xpath("#{interval_xpath}/@value")
|
|
94
97
|
low_time = DateTime.parse(parent_element.at_xpath(interval_xpath)['value'])
|
|
95
98
|
high_time = DateTime.parse(parent_element.at_xpath(interval_xpath)['value'])
|
|
@@ -108,6 +111,21 @@ module QRDA
|
|
|
108
111
|
low_time = Time.parse(parent_element.at_xpath("#{interval_xpath}/cda:center")['value'])
|
|
109
112
|
high_time = Time.parse(parent_element.at_xpath("#{interval_xpath}/cda:center")['value'])
|
|
110
113
|
end
|
|
114
|
+
if low_time && high_time && low_time > high_time
|
|
115
|
+
# pass warning: current code continues as expected, but adds warning
|
|
116
|
+
id_attr = parent_element.at_xpath(".//cda:id")&.attributes
|
|
117
|
+
id_str = id_attr ? "and id: #{id_attr['root']&.value}(root), #{id_attr['extension']&.value}(extension)" : ""
|
|
118
|
+
qrda_type = @entry_class.to_s.split("::")[1]
|
|
119
|
+
@warnings << ValidationError.new(message: "Interval with low time after high time. Located in element with QRDA type: #{qrda_type} #{id_str}",
|
|
120
|
+
location: parent_element.path)
|
|
121
|
+
end
|
|
122
|
+
if low_time.nil? && high_time.nil?
|
|
123
|
+
id_attr = parent_element.at_xpath(".//cda:id")&.attributes
|
|
124
|
+
id_str = id_attr ? "and id: #{id_attr['root']&.value}(root), #{id_attr['extension']&.value}(extension)" : ""
|
|
125
|
+
qrda_type = @entry_class.to_s.split("::")[1]
|
|
126
|
+
@warnings << ValidationError.new(message: "Interval with nullFlavor low time and nullFlavor high time. Located in element with QRDA type: #{qrda_type} #{id_str}",
|
|
127
|
+
location: parent_element.path)
|
|
128
|
+
end
|
|
111
129
|
QDM::Interval.new(low_time, high_time).shift_dates(0)
|
|
112
130
|
end
|
|
113
131
|
|
|
@@ -150,12 +168,11 @@ module QRDA
|
|
|
150
168
|
parent_element.xpath(@result_xpath).each do |elem|
|
|
151
169
|
result << extract_result_value(elem)
|
|
152
170
|
end
|
|
153
|
-
result.size > 1 ? result : result.first
|
|
171
|
+
result.size > 1 ? result : result.first
|
|
154
172
|
end
|
|
155
173
|
|
|
156
174
|
def extract_result_value(value_element)
|
|
157
175
|
return unless value_element && !value_element['nullFlavor']
|
|
158
|
-
|
|
159
176
|
value = value_element['value']
|
|
160
177
|
if value.present?
|
|
161
178
|
return value.strip.to_f if (value_element['unit'] == "1" || value_element['unit'].nil?)
|
|
@@ -163,6 +180,13 @@ module QRDA
|
|
|
163
180
|
return QDM::Quantity.new(value.strip.to_f, value_element['unit'])
|
|
164
181
|
elsif value_element['code'].present?
|
|
165
182
|
return code_if_present(value_element)
|
|
183
|
+
elsif value_element.text.present?
|
|
184
|
+
id_attr = value_element.parent.at_xpath(".//cda:id")&.attributes
|
|
185
|
+
id_str = id_attr ? "and id: #{id_attr['root']&.value}(root), #{id_attr['extension']&.value}(extension)" : ""
|
|
186
|
+
qrda_type = @entry_class.to_s.split("::")[1]
|
|
187
|
+
@warnings << ValidationError.new(message: "Value with string type found. When possible, it's best practice to use a coded value or scalar. Located in element with QRDA type: #{qrda_type} #{id_str}",
|
|
188
|
+
location: value_element.path)
|
|
189
|
+
return value_element.text
|
|
166
190
|
end
|
|
167
191
|
end
|
|
168
192
|
|
|
@@ -172,16 +196,16 @@ module QRDA
|
|
|
172
196
|
negation_indicator = parent_element['negationInd']
|
|
173
197
|
# Return and do not set reason attribute if the entry is negated
|
|
174
198
|
return nil if negation_indicator.eql?('true')
|
|
175
|
-
|
|
176
|
-
reason_element.blank? ? nil : code_if_present(reason_element.first)
|
|
199
|
+
|
|
200
|
+
reason_element.blank? ? nil : code_if_present(reason_element.first)
|
|
177
201
|
end
|
|
178
202
|
|
|
179
203
|
def extract_negation(parent_element, entry)
|
|
180
204
|
negation_element = parent_element.xpath("./cda:entryRelationship[@typeCode='RSON']/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.88']/cda:value")
|
|
181
205
|
negation_indicator = parent_element['negationInd']
|
|
182
206
|
# Return and do not set negationRationale attribute if the entry is not negated
|
|
183
|
-
return unless negation_indicator.eql?('true')
|
|
184
|
-
|
|
207
|
+
return unless negation_indicator.eql?('true')
|
|
208
|
+
|
|
185
209
|
entry.negationRationale = code_if_present(negation_element.first) unless negation_element.blank?
|
|
186
210
|
extract_negated_code(parent_element, entry)
|
|
187
211
|
end
|
|
@@ -189,8 +213,18 @@ module QRDA
|
|
|
189
213
|
def extract_negated_code(parent_element, entry)
|
|
190
214
|
code_elements = parent_element.xpath(@code_xpath)
|
|
191
215
|
code_elements.each do |code_element|
|
|
192
|
-
if code_element['nullFlavor'] == 'NA'
|
|
193
|
-
|
|
216
|
+
if code_element['nullFlavor'] == 'NA'
|
|
217
|
+
if code_element['sdtc:valueSet']
|
|
218
|
+
entry.dataElementCodes = [{ code: code_element['sdtc:valueSet'], codeSystemOid: '1.2.3.4.5.6.7.8.9.10' }]
|
|
219
|
+
else
|
|
220
|
+
# negated code is nullFlavored with no valueset
|
|
221
|
+
entry.dataElementCodes = [{ code: "NA", codeSystemOid: '1.2.3.4.5.6.7.8.9.10' }]
|
|
222
|
+
id_attr = parent_element.at_xpath(".//cda:id")&.attributes
|
|
223
|
+
id_str = id_attr ? "and id: #{id_attr['root']&.value}(root), #{id_attr['extension']&.value}(extension)" : ""
|
|
224
|
+
qrda_type = @entry_class.to_s.split("::")[1]
|
|
225
|
+
@warnings << ValidationError.new(message: "Negated code element contains nullFlavor code but no valueset. Located in element with QRDA type: #{qrda_type} #{id_str}.",
|
|
226
|
+
location: parent_element.path)
|
|
227
|
+
end
|
|
194
228
|
end
|
|
195
229
|
end
|
|
196
230
|
end
|
|
@@ -20,7 +20,7 @@ module QRDA
|
|
|
20
20
|
def create_entry(entry_element, nrh = NarrativeReferenceHandler.new)
|
|
21
21
|
diagnostic_study_performed = super
|
|
22
22
|
diagnostic_study_performed.resultDatetime = extract_time(entry_element, @result_datetime_xpath)
|
|
23
|
-
diagnostic_study_performed.resultDatetime ||= extract_interval(entry_element, @result_datetime_xpath)
|
|
23
|
+
diagnostic_study_performed.resultDatetime ||= extract_interval(entry_element, @result_datetime_xpath)&.low
|
|
24
24
|
diagnostic_study_performed.status = code_if_present(entry_element.at_xpath(@status_xpath))
|
|
25
25
|
diagnostic_study_performed.method = code_if_present(entry_element.at_xpath(@method_xpath))
|
|
26
26
|
diagnostic_study_performed.facilityLocation = extract_facility_locations(entry_element)[0]
|
|
@@ -26,11 +26,21 @@ module QRDA
|
|
|
26
26
|
los = encounter_performed.relevantPeriod.high - encounter_performed.relevantPeriod.low
|
|
27
27
|
encounter_performed.lengthOfStay = QDM::Quantity.new(los.to_i, 'd')
|
|
28
28
|
end
|
|
29
|
+
extract_modifier_code(encounter_performed, entry_element)
|
|
29
30
|
encounter_performed
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
private
|
|
33
34
|
|
|
35
|
+
def extract_modifier_code(encounter_performed, entry_element)
|
|
36
|
+
code_element = entry_element.at_xpath(@code_xpath)
|
|
37
|
+
return unless code_element
|
|
38
|
+
|
|
39
|
+
qualifier_name = code_element.at_xpath('./cda:qualifier/cda:name')
|
|
40
|
+
qualifier_value = code_element.at_xpath('./cda:qualifier/cda:value')
|
|
41
|
+
codes_modifiers[encounter_performed.id] = { name: code_if_present(qualifier_name), value: code_if_present(qualifier_value), xpath_location: entry_element.path } if qualifier_value || qualifier_name
|
|
42
|
+
end
|
|
43
|
+
|
|
34
44
|
def extract_diagnoses(parent_element)
|
|
35
45
|
diagnosis_elements = parent_element.xpath(@diagnosis_xpath)
|
|
36
46
|
diagnosis_list = []
|
|
@@ -16,7 +16,7 @@ module QRDA
|
|
|
16
16
|
|
|
17
17
|
def create_entry(entry_element, nrh = NarrativeReferenceHandler.new)
|
|
18
18
|
immunization_order = super
|
|
19
|
-
immunization_order.activeDatetime = extract_interval(entry_element, @active_datetime_xpath)
|
|
19
|
+
immunization_order.activeDatetime = extract_interval(entry_element, @active_datetime_xpath)&.low
|
|
20
20
|
immunization_order.dosage = extract_scalar(entry_element, @dosage_xpath)
|
|
21
21
|
immunization_order.supply = extract_scalar(entry_element, @supply_xpath)
|
|
22
22
|
immunization_order.route = code_if_present(entry_element.at_xpath(@route_xpath))
|
|
@@ -12,89 +12,117 @@ module QRDA
|
|
|
12
12
|
def initialize
|
|
13
13
|
# This differs from other HDS patient importers in that sections can have multiple importers
|
|
14
14
|
@data_element_importers = []
|
|
15
|
-
@data_element_importers <<
|
|
16
|
-
@data_element_importers <<
|
|
17
|
-
@data_element_importers <<
|
|
18
|
-
@data_element_importers <<
|
|
19
|
-
@data_element_importers <<
|
|
20
|
-
@data_element_importers <<
|
|
21
|
-
@data_element_importers <<
|
|
22
|
-
@data_element_importers <<
|
|
23
|
-
@data_element_importers <<
|
|
24
|
-
@data_element_importers <<
|
|
25
|
-
@data_element_importers <<
|
|
26
|
-
@data_element_importers <<
|
|
27
|
-
@data_element_importers <<
|
|
28
|
-
@data_element_importers <<
|
|
29
|
-
@data_element_importers <<
|
|
30
|
-
@data_element_importers <<
|
|
31
|
-
@data_element_importers <<
|
|
32
|
-
@data_element_importers <<
|
|
33
|
-
@data_element_importers <<
|
|
34
|
-
@data_element_importers <<
|
|
35
|
-
@data_element_importers <<
|
|
36
|
-
@data_element_importers <<
|
|
37
|
-
@data_element_importers <<
|
|
38
|
-
@data_element_importers <<
|
|
39
|
-
@data_element_importers <<
|
|
40
|
-
@data_element_importers <<
|
|
41
|
-
@data_element_importers <<
|
|
42
|
-
@data_element_importers <<
|
|
43
|
-
@data_element_importers <<
|
|
44
|
-
@data_element_importers <<
|
|
45
|
-
@data_element_importers <<
|
|
46
|
-
@data_element_importers <<
|
|
47
|
-
@data_element_importers <<
|
|
48
|
-
@data_element_importers <<
|
|
49
|
-
@data_element_importers <<
|
|
50
|
-
@data_element_importers <<
|
|
51
|
-
@data_element_importers <<
|
|
52
|
-
@data_element_importers <<
|
|
53
|
-
@data_element_importers <<
|
|
54
|
-
@data_element_importers <<
|
|
55
|
-
@data_element_importers <<
|
|
56
|
-
@data_element_importers <<
|
|
57
|
-
@data_element_importers <<
|
|
58
|
-
@data_element_importers <<
|
|
59
|
-
@data_element_importers <<
|
|
60
|
-
@data_element_importers <<
|
|
15
|
+
@data_element_importers << AdverseEventImporter.new
|
|
16
|
+
@data_element_importers << AllergyIntoleranceImporter.new
|
|
17
|
+
@data_element_importers << AssessmentOrderImporter.new
|
|
18
|
+
@data_element_importers << AssessmentPerformedImporter.new
|
|
19
|
+
@data_element_importers << AssessmentRecommendedImporter.new
|
|
20
|
+
@data_element_importers << CommunicationPerformedImporter.new
|
|
21
|
+
@data_element_importers << DeviceAppliedImporter.new
|
|
22
|
+
@data_element_importers << DeviceOrderImporter.new
|
|
23
|
+
@data_element_importers << DeviceRecommendedImporter.new
|
|
24
|
+
@data_element_importers << DiagnosisImporter.new
|
|
25
|
+
@data_element_importers << DiagnosticStudyOrderImporter.new
|
|
26
|
+
@data_element_importers << DiagnosticStudyPerformedImporter.new
|
|
27
|
+
@data_element_importers << DiagnosticStudyRecommendedImporter.new
|
|
28
|
+
@data_element_importers << EncounterOrderImporter.new
|
|
29
|
+
@data_element_importers << EncounterPerformedImporter.new
|
|
30
|
+
@data_element_importers << EncounterRecommendedImporter.new
|
|
31
|
+
@data_element_importers << FamilyHistoryImporter.new
|
|
32
|
+
@data_element_importers << ImmunizationAdministeredImporter.new
|
|
33
|
+
@data_element_importers << ImmunizationOrderImporter.new
|
|
34
|
+
@data_element_importers << InterventionOrderImporter.new
|
|
35
|
+
@data_element_importers << InterventionPerformedImporter.new
|
|
36
|
+
@data_element_importers << InterventionRecommendedImporter.new
|
|
37
|
+
@data_element_importers << LaboratoryTestOrderImporter.new
|
|
38
|
+
@data_element_importers << LaboratoryTestPerformedImporter.new
|
|
39
|
+
@data_element_importers << LaboratoryTestRecommendedImporter.new
|
|
40
|
+
@data_element_importers << MedicationActiveImporter.new
|
|
41
|
+
@data_element_importers << MedicationAdministeredImporter.new
|
|
42
|
+
@data_element_importers << MedicationDischargeImporter.new
|
|
43
|
+
@data_element_importers << MedicationDispensedImporter.new
|
|
44
|
+
@data_element_importers << MedicationOrderImporter.new
|
|
45
|
+
@data_element_importers << PatientCareExperienceImporter.new
|
|
46
|
+
@data_element_importers << PatientCharacteristicClinicalTrialParticipantImporter.new
|
|
47
|
+
@data_element_importers << PatientCharacteristicExpiredImporter.new
|
|
48
|
+
@data_element_importers << PatientCharacteristicPayerImporter.new
|
|
49
|
+
@data_element_importers << PhysicalExamOrderImporter.new
|
|
50
|
+
@data_element_importers << PhysicalExamPerformedImporter.new
|
|
51
|
+
@data_element_importers << PhysicalExamRecommendedImporter.new
|
|
52
|
+
@data_element_importers << ProcedureOrderImporter.new
|
|
53
|
+
@data_element_importers << ProcedurePerformedImporter.new
|
|
54
|
+
@data_element_importers << ProcedureRecommendedImporter.new
|
|
55
|
+
@data_element_importers << ProviderCareExperienceImporter.new
|
|
56
|
+
@data_element_importers << ProviderCharacteristicImporter.new
|
|
57
|
+
@data_element_importers << SubstanceAdministeredImporter.new
|
|
58
|
+
@data_element_importers << SubstanceOrderImporter.new
|
|
59
|
+
@data_element_importers << SubstanceRecommendedImporter.new
|
|
60
|
+
@data_element_importers << SymptomImporter.new
|
|
61
61
|
end
|
|
62
62
|
|
|
63
63
|
def parse_cat1(doc)
|
|
64
64
|
patient = CQM::Patient.new
|
|
65
|
+
warnings = []
|
|
66
|
+
codes_modifiers = {}
|
|
65
67
|
entry_id_map = {}
|
|
66
|
-
import_data_elements(patient, doc, entry_id_map)
|
|
68
|
+
import_data_elements(patient, doc, entry_id_map, codes_modifiers, warnings)
|
|
67
69
|
normalize_references(patient, entry_id_map)
|
|
68
70
|
get_demographics(patient, doc)
|
|
69
|
-
patient
|
|
71
|
+
[patient, warnings, codes_modifiers]
|
|
70
72
|
end
|
|
71
73
|
|
|
72
|
-
def import_data_elements(patient, doc, entry_id_map)
|
|
74
|
+
def import_data_elements(patient, doc, entry_id_map, codes_modifiers, warnings = [])
|
|
73
75
|
context = doc.xpath("/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section[cda:templateId/@root = '2.16.840.1.113883.10.20.24.2.1']")
|
|
74
76
|
nrh = NarrativeReferenceHandler.new
|
|
75
77
|
nrh.build_id_map(doc)
|
|
76
|
-
@data_element_importers.each do |
|
|
77
|
-
data_elements, id_map =
|
|
78
|
+
@data_element_importers.each do |importer|
|
|
79
|
+
data_elements, id_map = importer.create_entries(context, nrh)
|
|
78
80
|
new_data_elements = []
|
|
79
81
|
|
|
80
82
|
id_map.each_value do |elem_ids|
|
|
81
|
-
|
|
82
83
|
elem_id = elem_ids.first
|
|
83
84
|
data_element = data_elements.find { |de| de.id == elem_id }
|
|
85
|
+
# Keep the first element with a shared ID
|
|
86
|
+
new_data_elements << data_element
|
|
84
87
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
88
|
+
# Encounters require elements beyond id for uniqueness
|
|
89
|
+
next unless data_element._type == 'QDM::EncounterPerformed'
|
|
90
|
+
unique_element_keys = []
|
|
91
|
+
# Add key_elements_for_determining_encounter_uniqueness to array, this is used to determine if other
|
|
92
|
+
# elements with the same ID should be considered as unique
|
|
93
|
+
unique_element_keys << key_elements_for_determining_encounter_uniqueness(data_element)
|
|
89
94
|
|
|
90
|
-
|
|
95
|
+
# Loop through all other data elements with the same id
|
|
96
|
+
elem_ids[1,elem_ids.length].each do |dup_id|
|
|
97
|
+
dup_element = data_elements.find { |de| de.id == dup_id }
|
|
98
|
+
dup_element_keys = key_elements_for_determining_encounter_uniqueness(dup_element)
|
|
99
|
+
# See if a previously selected data element shared all of the keys files
|
|
100
|
+
# If all key fields match, move on.
|
|
101
|
+
next if unique_element_keys.include?(dup_element_keys)
|
|
102
|
+
# If all key fields don't match, keep element
|
|
103
|
+
new_data_elements << dup_element
|
|
104
|
+
# Add to list of unique element keys
|
|
105
|
+
unique_element_keys << dup_element_keys
|
|
106
|
+
end
|
|
91
107
|
end
|
|
92
108
|
|
|
93
109
|
patient.qdmPatient.dataElements << new_data_elements
|
|
94
110
|
entry_id_map.merge!(id_map)
|
|
111
|
+
warnings.concat(importer.warnings)
|
|
112
|
+
codes_modifiers.merge!(importer.codes_modifiers)
|
|
113
|
+
# reset warnings after they're captured so that the importer can be re-used
|
|
114
|
+
importer.warnings = []
|
|
115
|
+
importer.codes_modifiers = {}
|
|
95
116
|
end
|
|
96
117
|
end
|
|
97
118
|
|
|
119
|
+
def key_elements_for_determining_encounter_uniqueness(encounter)
|
|
120
|
+
codes = encounter.codes.collect { |dec| "#{dec.code}_#{dec.codeSystemOid}" }.sort.to_s
|
|
121
|
+
admission_date_time = encounter&.relevantPeriod&.low.to_s
|
|
122
|
+
discharge_date_time = encounter&.relevantPeriod&.high.to_s
|
|
123
|
+
"#{codes}#{admission_date_time}#{discharge_date_time}"
|
|
124
|
+
end
|
|
125
|
+
|
|
98
126
|
def get_patient_expired(record, doc)
|
|
99
127
|
entry_elements = doc.xpath("/cda:ClinicalDocument/cda:component/cda:structuredBody/cda:component/cda:section[cda:templateId/@root = '2.16.840.1.113883.10.20.24.2.1']/cda:entry/cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.54']")
|
|
100
128
|
return unless entry_elements.empty?
|
|
@@ -117,12 +145,6 @@ module QRDA
|
|
|
117
145
|
end
|
|
118
146
|
end
|
|
119
147
|
end
|
|
120
|
-
|
|
121
|
-
private
|
|
122
|
-
|
|
123
|
-
def generate_importer(importer_class)
|
|
124
|
-
EntryPackage.new(importer_class.new)
|
|
125
|
-
end
|
|
126
148
|
end
|
|
127
149
|
end
|
|
128
150
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cqm-reports
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0
|
|
4
|
+
version: 2.1.0
|
|
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: 2020-09-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: cqm-models
|
|
@@ -24,6 +24,20 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: 2.0.0
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: cqm-validators
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 2.0.0
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 2.0.0
|
|
27
41
|
- !ruby/object:Gem::Dependency
|
|
28
42
|
name: mustache
|
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -147,8 +161,6 @@ files:
|
|
|
147
161
|
- README.md
|
|
148
162
|
- Rakefile
|
|
149
163
|
- lib/cqm_report.rb
|
|
150
|
-
- lib/ext/code.rb
|
|
151
|
-
- lib/ext/data_element.rb
|
|
152
164
|
- lib/html-export/qdm-patient/_header_css.mustache
|
|
153
165
|
- lib/html-export/qdm-patient/_javascript.mustache
|
|
154
166
|
- lib/html-export/qdm-patient/data_element/_data_element.mustache
|
|
@@ -308,7 +320,6 @@ files:
|
|
|
308
320
|
- lib/qrda-import/data-element-importers/substance_recommended_importer.rb
|
|
309
321
|
- lib/qrda-import/data-element-importers/symptom_importer.rb
|
|
310
322
|
- lib/qrda-import/entry_finder.rb
|
|
311
|
-
- lib/qrda-import/entry_package.rb
|
|
312
323
|
- lib/qrda-import/narrative_reference_handler.rb
|
|
313
324
|
- lib/qrda-import/patient_importer.rb
|
|
314
325
|
- lib/util/code_system_helper.rb
|
|
@@ -338,7 +349,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
338
349
|
- !ruby/object:Gem::Version
|
|
339
350
|
version: '0'
|
|
340
351
|
requirements: []
|
|
341
|
-
|
|
352
|
+
rubyforge_project:
|
|
353
|
+
rubygems_version: 2.6.14
|
|
342
354
|
signing_key:
|
|
343
355
|
specification_version: 4
|
|
344
356
|
summary: A library for import and export of reports for use with electronic Clinical
|
data/lib/ext/code.rb
DELETED
data/lib/ext/data_element.rb
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
module QDM
|
|
2
|
-
class DataElement
|
|
3
|
-
def merge!(other)
|
|
4
|
-
# ensure they're the same category (e.g. 'encounter')
|
|
5
|
-
return unless qdmCategory == other.qdmCategory
|
|
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 qdmCategory 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
|