health-data-standards 3.4.6 → 3.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/Gemfile +2 -2
  2. data/README.md +4 -0
  3. data/lib/health-data-standards.rb +1 -0
  4. data/lib/health-data-standards/export/cat_1.rb +4 -4
  5. data/lib/health-data-standards/export/helper/scooped_view_helper.rb +16 -16
  6. data/lib/health-data-standards/export/qrda/hqmf-qrda-oids.json +6 -0
  7. data/lib/health-data-standards/export/view_helper.rb +8 -1
  8. data/lib/health-data-standards/import/bulk_record_importer.rb +45 -13
  9. data/lib/health-data-standards/import/bundle/importer.rb +2 -4
  10. data/lib/health-data-standards/import/cda/provider_importer.rb +2 -2
  11. data/lib/health-data-standards/import/green_c32/section_importer.rb +2 -2
  12. data/lib/health-data-standards/import/provider_import_utils.rb +2 -2
  13. data/lib/health-data-standards/models/cda_identifier.rb +1 -0
  14. data/lib/health-data-standards/models/cqm/bundle.rb +4 -1
  15. data/lib/health-data-standards/models/cqm/measure.rb +40 -25
  16. data/lib/health-data-standards/models/cqm/patient_cache.rb +61 -60
  17. data/lib/health-data-standards/models/encounter.rb +4 -12
  18. data/lib/health-data-standards/models/entry.rb +4 -8
  19. data/lib/health-data-standards/models/facility.rb +1 -0
  20. data/lib/health-data-standards/models/fulfillment_history.rb +6 -18
  21. data/lib/health-data-standards/models/guarantor.rb +1 -0
  22. data/lib/health-data-standards/models/lab_result.rb +2 -6
  23. data/lib/health-data-standards/models/medical_equipment.rb +2 -7
  24. data/lib/health-data-standards/models/medication.rb +11 -31
  25. data/lib/health-data-standards/models/metadata/link_info.rb +1 -0
  26. data/lib/health-data-standards/models/order_information.rb +5 -13
  27. data/lib/health-data-standards/models/organization.rb +1 -0
  28. data/lib/health-data-standards/models/procedure.rb +1 -4
  29. data/lib/health-data-standards/models/provider.rb +2 -1
  30. data/lib/health-data-standards/models/provider_performance.rb +1 -0
  31. data/lib/health-data-standards/models/qrda/legal_authenticator.rb +1 -0
  32. data/lib/health-data-standards/models/qrda/organization.rb +2 -0
  33. data/lib/health-data-standards/models/record.rb +7 -7
  34. data/lib/health-data-standards/models/result_value.rb +1 -0
  35. data/lib/health-data-standards/models/svs/concept.rb +1 -0
  36. data/lib/health-data-standards/models/svs/value_set.rb +1 -0
  37. data/lib/health-data-standards/models/telecom.rb +1 -0
  38. data/lib/health-data-standards/models/transfer.rb +1 -0
  39. data/lib/health-data-standards/tasks/bundle.rake +3 -3
  40. data/lib/health-data-standards/util/vs_api.rb +2 -2
  41. data/lib/hqmf-generator/attribute.xml.erb +9 -11
  42. data/lib/hqmf-generator/characteristic_criteria.xml.erb +5 -5
  43. data/lib/hqmf-generator/code.xml.erb +6 -2
  44. data/lib/hqmf-generator/condition_criteria.xml.erb +4 -5
  45. data/lib/hqmf-generator/derivation.xml.erb +6 -6
  46. data/lib/hqmf-generator/description.xml.erb +1 -1
  47. data/lib/hqmf-generator/document.xml.erb +46 -11
  48. data/lib/hqmf-generator/encounter_criteria.xml.erb +4 -5
  49. data/lib/hqmf-generator/field.xml.erb +13 -1
  50. data/lib/hqmf-generator/grouper_criteria.xml.erb +17 -0
  51. data/lib/hqmf-generator/hqmf-generator.rb +75 -8
  52. data/lib/hqmf-generator/local_variable.xml.erb +1 -0
  53. data/lib/hqmf-generator/measure_observation_definition.xml.erb +25 -0
  54. data/lib/hqmf-generator/observation_criteria.xml.erb +4 -5
  55. data/lib/hqmf-generator/population_criteria.xml.erb +2 -3
  56. data/lib/hqmf-generator/precondition.xml.erb +2 -2
  57. data/lib/hqmf-generator/precondition_cv.xml.erb +8 -0
  58. data/lib/hqmf-generator/procedure_criteria.xml.erb +4 -5
  59. data/lib/hqmf-generator/reference.xml.erb +2 -2
  60. data/lib/hqmf-generator/source.xml.erb +2 -2
  61. data/lib/hqmf-generator/specific_occurrence.xml.erb +4 -5
  62. data/lib/hqmf-generator/subset.xml.erb +16 -3
  63. data/lib/hqmf-generator/substance_criteria.xml.erb +4 -5
  64. data/lib/hqmf-generator/supply_criteria.xml.erb +4 -5
  65. data/lib/hqmf-generator/temporal_relationship.xml.erb +1 -1
  66. data/lib/hqmf-generator/value.xml.erb +35 -9
  67. data/lib/hqmf-generator/variable_criteria.xml.erb +2 -3
  68. data/lib/hqmf-model/attribute.rb +36 -8
  69. data/lib/hqmf-model/data_criteria.json +38 -204
  70. data/lib/hqmf-model/data_criteria.rb +40 -16
  71. data/lib/hqmf-model/document.rb +61 -2
  72. data/lib/hqmf-model/population_criteria.rb +11 -7
  73. data/lib/hqmf-model/precondition.rb +1 -1
  74. data/lib/hqmf-model/types.rb +91 -8
  75. data/lib/hqmf-parser/1.0/attribute.rb +55 -2
  76. data/lib/hqmf-parser/1.0/document.rb +10 -23
  77. data/lib/hqmf-parser/1.0/population_criteria.rb +2 -2
  78. data/lib/hqmf-parser/1.0/range.rb +0 -1
  79. data/lib/hqmf-parser/2.0/data_criteria.rb +90 -21
  80. data/lib/hqmf-parser/2.0/document.rb +122 -7
  81. data/lib/hqmf-parser/2.0/population_criteria.rb +18 -6
  82. data/lib/hqmf-parser/2.0/precondition.rb +4 -1
  83. data/lib/hqmf-parser/2.0/types.rb +36 -15
  84. data/lib/hqmf-parser/converter/pass1/document_converter.rb +4 -56
  85. data/lib/hqmf-parser/converter/pass1/population_criteria_converter.rb +24 -8
  86. data/lib/hqmf-parser/converter/pass1/precondition_extractor.rb +15 -2
  87. data/lib/hqmf-parser/converter/pass2/comparison_converter.rb +1 -1
  88. data/lib/hqmf-parser/parser.rb +64 -41
  89. data/templates/cat1/_2.16.840.1.113883.10.20.22.4.85.cat1.erb +0 -1
  90. data/templates/cat1/_address.cat1.erb +9 -0
  91. data/templates/cat1/_author.cat1.erb +28 -0
  92. data/templates/cat1/_id.cat1.erb +1 -0
  93. data/templates/cat1/_organization.cat1.erb +8 -0
  94. data/templates/cat1/_patient_data.cat1.erb +0 -3
  95. data/templates/cat1/_telecom.cat1.erb +1 -0
  96. data/templates/cat1/show.cat1.erb +96 -58
  97. metadata +115 -66
  98. checksums.yaml +0 -7
data/Gemfile CHANGED
@@ -16,8 +16,8 @@ group :test do
16
16
  gem 'simplecov', :require => false
17
17
  gem 'webmock'
18
18
 
19
- gem "minitest", "~> 4.0"
20
- gem 'turn', :require => false
19
+ gem "minitest", "~> 5.3"
20
+ gem 'minitest-reporters'
21
21
  gem 'awesome_print', :require => 'ap'
22
22
 
23
23
  end
data/README.md CHANGED
@@ -25,6 +25,10 @@ Please try to follow the [GitHub Coding Style Guides](https://github.com/stylegu
25
25
  Change Log
26
26
  ==========
27
27
 
28
+ 4.0.0 - Not yet released
29
+
30
+ * Upgrading to mongoid 4
31
+
28
32
  3.4.6 - May 15, 2014
29
33
 
30
34
  * QRDA Cat I export now exports medical record number if present
@@ -9,6 +9,7 @@ require 'nokogiri'
9
9
  require 'ostruct'
10
10
  require 'log4r'
11
11
  require 'memoist'
12
+ require 'protected_attributes'
12
13
 
13
14
  # Freedom patches
14
15
  require_relative 'health-data-standards/ext/symbol'
@@ -9,10 +9,10 @@ module HealthDataStandards
9
9
  end
10
10
 
11
11
  @@vs_map = nil
12
- def export(patient, measures, start_date, end_date)
13
- @rendering_context.render(:template => 'show', :locals => {:patient => patient, :measures => measures,
14
- :start_date => start_date, :end_date => end_date})
12
+ def export(patient, measures, start_date, end_date, header=nil)
13
+ @rendering_context.render(:template => 'show', :locals => {:patient => patient, :measures => measures,
14
+ :start_date => start_date, :end_date => end_date, :header => header})
15
15
  end
16
16
  end
17
17
  end
18
- end
18
+ end
@@ -12,7 +12,7 @@ module HealthDataStandards
12
12
  bundle_id_to_use = bundle_id
13
13
  else
14
14
  latest_bundle_id = HealthDataStandards::CQM::Bundle.latest_bundle_id
15
- bundle_id_to_use = Moped::BSON::ObjectId.from_string(latest_bundle_id) if latest_bundle_id
15
+ bundle_id_to_use = BSON::ObjectId.from_string(latest_bundle_id) if latest_bundle_id
16
16
  end
17
17
  VS_MAP[bundle_id_to_use] ||= Hash[ValueSet.where({bundle_id: bundle_id_to_use}).map{ |p| [p.oid, p.code_set_map] }]
18
18
  end
@@ -24,13 +24,13 @@ module HealthDataStandards
24
24
  all_data_criteria = measures.map {|measure| measure.all_data_criteria}.flatten
25
25
  mapped_data_criteria = {}
26
26
  all_data_criteria.each do |data_criteria|
27
- data_criteria_oid = HQMFTemplateHelper.template_id_by_definition_and_status(data_criteria.definition,
27
+ data_criteria_oid = HQMFTemplateHelper.template_id_by_definition_and_status(data_criteria.definition,
28
28
  (data_criteria.status || ""),
29
29
  data_criteria.negation)
30
30
  value_set_oid = data_criteria.code_list_id
31
31
  dc = {'data_criteria_oid' => data_criteria_oid, 'value_set_oid' => value_set_oid}
32
32
  mapping = mapped_data_criteria[dc] ||= {'result_oids' => [], 'field_oids' =>{}, 'data_criteria' => data_criteria}
33
-
33
+
34
34
  if data_criteria.field_values
35
35
  data_criteria.field_values.each_pair do |field,descr|
36
36
  if descr && descr.type == "CD"
@@ -53,7 +53,7 @@ module HealthDataStandards
53
53
  def entry_matches_criteria(entry, data_criteria_info_list)
54
54
  data_criteria_info_list.each do |data_criteria_info|
55
55
  data_criteria = data_criteria_info['data_criteria']
56
- data_criteria_oid = HQMFTemplateHelper.template_id_by_definition_and_status(data_criteria.definition,
56
+ data_criteria_oid = HQMFTemplateHelper.template_id_by_definition_and_status(data_criteria.definition,
57
57
  data_criteria.status || '',
58
58
  data_criteria.negation)
59
59
  if entry.respond_to?(:oid) && (entry.oid == data_criteria_oid)
@@ -67,13 +67,13 @@ module HealthDataStandards
67
67
  end
68
68
  end
69
69
  end
70
-
70
+
71
71
  false
72
72
  end
73
-
73
+
74
74
  # Find all of the entries on a patient that match the given data criteria
75
75
  def entries_for_data_criteria(data_criteria, patient)
76
- data_criteria_oid = HQMFTemplateHelper.template_id_by_definition_and_status(data_criteria.definition,
76
+ data_criteria_oid = HQMFTemplateHelper.template_id_by_definition_and_status(data_criteria.definition,
77
77
  data_criteria.status || '',
78
78
  data_criteria.negation)
79
79
  HealthDataStandards.logger.warn("Looking for dc [#{data_criteria_oid}]")
@@ -90,21 +90,21 @@ module HealthDataStandards
90
90
  entries.concat patient.entries_for_oid(data_criteria_oid)
91
91
 
92
92
  case data_criteria_oid
93
- when '2.16.840.1.113883.3.560.1.5'
93
+ when '2.16.840.1.113883.3.560.1.5'
94
94
  #special case handling for Lab Test: Performed being implicitly available through a Lab Test: Result
95
95
  entries.concat patient.entries_for_oid('2.16.840.1.113883.3.560.1.12')
96
96
  when '2.16.840.1.113883.3.560.1.12'
97
- entries.concat patient.entries_for_oid('2.16.840.1.113883.3.560.1.5')
98
- when '2.16.840.1.113883.3.560.1.6'
97
+ entries.concat patient.entries_for_oid('2.16.840.1.113883.3.560.1.5')
98
+ when '2.16.840.1.113883.3.560.1.6'
99
99
  entries.concat patient.entries_for_oid('2.16.840.1.113883.3.560.1.63')
100
- when '2.16.840.1.113883.3.560.1.63'
100
+ when '2.16.840.1.113883.3.560.1.63'
101
101
  entries.concat patient.entries_for_oid('2.16.840.1.113883.3.560.1.6')
102
- when '2.16.840.1.113883.3.560.1.3'
102
+ when '2.16.840.1.113883.3.560.1.3'
103
103
  entries.concat patient.entries_for_oid('2.16.840.1.113883.3.560.1.11')
104
- when '2.16.840.1.113883.3.560.1.11'
104
+ when '2.16.840.1.113883.3.560.1.11'
105
105
  entries.concat patient.entries_for_oid('2.16.840.1.113883.3.560.1.3')
106
106
  end
107
-
107
+
108
108
  codes = (value_set_map(patient["bundle_id"])[data_criteria.code_list_id] || [])
109
109
  if codes.empty?
110
110
  HealthDataStandards.logger.warn("No codes for #{data_criteria.code_list_id}")
@@ -129,7 +129,7 @@ module HealthDataStandards
129
129
 
130
130
  def handle_clinical_trial_participant(patient)
131
131
  if patient.clinical_trial_participant
132
- [{dummy_entry: true}]
132
+ [Entry.new]
133
133
  else
134
134
  []
135
135
  end
@@ -149,4 +149,4 @@ module HealthDataStandards
149
149
  end
150
150
  end
151
151
  end
152
- end
152
+ end
@@ -611,6 +611,12 @@
611
611
  "qrda_name": "Communication from Provider to Provider",
612
612
  "qrda_oid": "2.16.840.1.113883.10.20.24.3.4"
613
613
  },
614
+ {
615
+ "hqmf_name": "Communication: From Patient to Provider not done",
616
+ "hqmf_oid": "2.16.840.1.113883.3.560.1.130",
617
+ "qrda_name": "Communication from Patient to Provider",
618
+ "qrda_oid": "2.16.840.1.113883.10.20.24.3.2"
619
+ },
614
620
  {
615
621
  "hqmf_name": "Risk Category Assessment not done",
616
622
  "hqmf_oid": "2.16.840.1.113883.3.560.1.121",
@@ -66,6 +66,7 @@ module HealthDataStandards
66
66
  end
67
67
 
68
68
  def convert_field_to_hash(field, codes)
69
+ codes = codes[0] if codes.is_a? Array
69
70
  if (codes.is_a? Hash)
70
71
  clean_hash = {}
71
72
 
@@ -96,7 +97,13 @@ module HealthDataStandards
96
97
  elsif codes['scalar']
97
98
  return "#{codes['scalar']} #{codes['units']}"
98
99
  else
99
- return codes.map {|hashcode_set, hashcodes| "#{hashcode_set}: #{(hashcodes.respond_to? :join) ? hashcodes.join(', ') : hashcodes.to_s}"}.join(' ')
100
+ return codes.map do |hashcode_set, hashcodes|
101
+ if hashcodes.is_a? Hash
102
+ "#{hashcode_set}: #{convert_field_to_hash(hashcode_set, hashcodes)}"
103
+ else
104
+ "#{hashcode_set}: #{(hashcodes.respond_to? :join) ? hashcodes.join(', ') : hashcodes.to_s}"
105
+ end
106
+ end.join(' ')
100
107
  end
101
108
 
102
109
  clean_hash
@@ -10,20 +10,44 @@ module HealthDataStandards
10
10
  BulkRecordImporter.import_file(file,File.new(file).read,failed_dir)
11
11
  end
12
12
  end
13
-
14
- def self.import_archive(file, failed_dir=nil)
15
- begin
13
+
14
+ def self.import_archive(file, failed_dir=nil)
15
+ begin
16
16
  failed_dir ||=File.join(File.dirname(file))
17
+
18
+ patient_id_list = nil
19
+
17
20
  Zip::ZipFile.open(file.path) do |zipfile|
18
21
  zipfile.entries.each do |entry|
22
+ if entry.name
23
+ if entry.name.split("/").last == "patient_manifest.txt"
24
+ patient_id_list = zipfile.read(entry.name)
25
+ next
26
+ end
27
+ end
19
28
  next if entry.directory?
20
29
  data = zipfile.read(entry.name)
21
30
  BulkRecordImporter.import_file(entry.name,data,failed_dir)
22
31
  end
23
32
  end
33
+
34
+ missing_patients = []
35
+
36
+ #if there was a patient manifest, theres a patient id list we need to load
37
+ if patient_id_list
38
+ patient_id_list.split("\n").each do |id|
39
+ patient = Record.where(:medical_record_number => id).first
40
+ if patient == nil
41
+ missing_patients << id
42
+ end
43
+ end
44
+ end
45
+
46
+ missing_patients
47
+
24
48
  rescue
25
49
  FileUtils.mkdir_p(failed_dir)
26
- File.cp(file,File.join(failed_dir,file))
50
+ FileUtils.cp(file,File.join(failed_dir,File.basename(file)))
27
51
  File.open(File.join(failed_dir,"#{file}.error")) do |f|
28
52
  f.puts($!.message)
29
53
  f.puts($!.backtrace)
@@ -54,15 +78,22 @@ module HealthDataStandards
54
78
 
55
79
  def self.import_json(data,provider_map = {})
56
80
  json = JSON.parse(data,:max_nesting=>100)
57
- Record.update_or_create(Record.new(json))
81
+ record = Record.update_or_create(Record.new(json))
82
+ providers = record.provider_performances
83
+ providers.each do |prov|
84
+ prov.provider.ancestors.each do |ancestor|
85
+ record.provider_performances.push(ProviderPerformance.new(start_date: prov.start_date, end_date: prov.end_date, provider: ancestor))
86
+ end
87
+ end
88
+ record.save!
58
89
  end
59
-
90
+
60
91
  def self.import(xml_data, provider_map = {})
61
92
  doc = Nokogiri::XML(xml_data)
62
-
93
+
63
94
  providers = []
64
95
  root_element_name = doc.root.name
65
-
96
+
66
97
  if root_element_name == 'ClinicalDocument'
67
98
  doc.root.add_namespace_definition('cda', 'urn:hl7-org:v3')
68
99
  doc.root.add_namespace_definition('sdtc', 'urn:hl7-org:sdtc')
@@ -77,9 +108,11 @@ module HealthDataStandards
77
108
  STDERR.puts("Unable to determinate document template/type of CDA document")
78
109
  return {status: 'error', message: "Document templateId does not identify it as a C32 or CCDA", status_code: 400}
79
110
  end
80
-
111
+
112
+ record = Record.update_or_create(patient_data)
113
+
81
114
  begin
82
- providers = CDA::ProviderImporter.instance.extract_providers(doc)
115
+ providers = CDA::ProviderImporter.instance.extract_providers(doc, record)
83
116
  rescue Exception => e
84
117
  STDERR.puts "error extracting providers"
85
118
  end
@@ -87,11 +120,10 @@ module HealthDataStandards
87
120
  return {status: 'error', message: 'Unknown XML Format', status_code: 400}
88
121
  end
89
122
 
90
- record = Record.update_or_create(patient_data)
91
123
  record.provider_performances = providers
92
- providers.each do |prov|
124
+ providers.each do |prov|
93
125
  prov.provider.ancestors.each do |ancestor|
94
- record.provider_performances.push(ProviderPerformance.new(start_date: prov.start_date, end_date: prov.end_date, provider: ancestor))
126
+ record.provider_performances.push(ProviderPerformance.new(start_date: prov.start_date, end_date: prov.end_date, provider: ancestor))
95
127
  end
96
128
  end
97
129
  record.save
@@ -75,7 +75,7 @@ module HealthDataStandards
75
75
  Mongoid.default_session['system.js'].find('_id' => name).upsert(
76
76
  {
77
77
  "_id" => name,
78
- "value" => Moped::BSON::Code.new(fn)
78
+ "value" => BSON::Code.new(fn)
79
79
  }
80
80
  )
81
81
  end
@@ -140,14 +140,12 @@ module HealthDataStandards
140
140
 
141
141
  def self.unpack_and_store_valuesets(zip, bundle)
142
142
  entries = zip.glob(SOURCE_ROOTS[:valuesets])
143
- bulk = []
144
143
  entries.each_with_index do |entry, index|
145
144
  vs = HealthDataStandards::SVS::ValueSet.new(unpack_json(entry))
146
145
  vs['bundle_id'] = bundle.id
147
- bulk << vs
146
+ HealthDataStandards::SVS::ValueSet.collection.insert(vs.as_document)
148
147
  report_progress('Value Sets', (index*100/entries.length)) if index%10 == 0
149
148
  end
150
- HealthDataStandards::SVS::ValueSet.collection.insert(bulk.map {|vs| vs.as_document})
151
149
  puts "\rLoading: Value Sets Complete "
152
150
  end
153
151
 
@@ -18,11 +18,11 @@ module HealthDataStandards
18
18
  # @param [Nokogiri::XML::Document] doc It is expected that the root node of this document
19
19
  # will have the "cda" namespace registered to "urn:hl7-org:v3"
20
20
  # @return [Array] an array of providers found in the document
21
- def extract_providers(doc)
21
+ def extract_providers(doc, patient=nil)
22
22
  performers = doc.xpath("//cda:documentationOf/cda:serviceEvent/cda:performer")
23
23
  performers.map do |performer|
24
24
  provider_perf = extract_provider_data(performer, true)
25
- ProviderPerformance.new(start_date: provider_perf.delete(:start), end_date: provider_perf.delete(:end), provider: find_or_create_provider(provider_perf))
25
+ ProviderPerformance.new(start_date: provider_perf.delete(:start), end_date: provider_perf.delete(:end), provider: find_or_create_provider(provider_perf, patient))
26
26
  end
27
27
  end
28
28
 
@@ -36,7 +36,7 @@ module HealthDataStandards
36
36
  codes.merge!(build_code(trans))
37
37
  end
38
38
 
39
- entry.send("#{attribute}=", codes)
39
+ entry.write_attribute(attribute, codes)
40
40
  end
41
41
 
42
42
  def extract_description(element, entry)
@@ -71,7 +71,7 @@ module HealthDataStandards
71
71
 
72
72
  return unless datetime && datetime['value']
73
73
 
74
- entry.send("#{attribute}=", Time.parse(datetime['value']).utc.to_i)
74
+ entry.write_attribute(attribute, Time.parse(datetime['value']).utc.to_i)
75
75
  end
76
76
 
77
77
  def extract_interval(element, entry, element_name="effectiveTime")
@@ -5,7 +5,7 @@ module ProviderImportUtils
5
5
  find_or_create_provider(provider_data)
6
6
  end
7
7
 
8
- def find_or_create_provider(provider_hash)
8
+ def find_or_create_provider(provider_hash, patient=nil)
9
9
  provider = Provider.by_npi(provider_hash[:npi]).first if provider_hash[:npi] && !provider_hash[:npi].empty?
10
10
  unless provider
11
11
  if provider_hash[:npi]
@@ -22,7 +22,7 @@ module ProviderImportUtils
22
22
  :family_name=> provider_hash[:family_name],
23
23
  :specialty => provider_hash[:specialty]}
24
24
  provider ||= Provider.where(provider_query).first
25
- provider ||= Provider.resolve_provider(provider_hash)
25
+ provider ||= Provider.resolve_provider(provider_hash, patient)
26
26
  provider ||= Provider.create(provider_hash)
27
27
  end
28
28
  end
@@ -1,5 +1,6 @@
1
1
  class CDAIdentifier
2
2
  include Mongoid::Document
3
+ include Mongoid::Attributes::Dynamic
3
4
 
4
5
  field :root, type: String
5
6
  field :extension, type: String
@@ -4,11 +4,14 @@ module HealthDataStandards
4
4
  class Bundle
5
5
  include Mongoid::Document
6
6
  include Mongoid::Timestamps
7
+ include Mongoid::Attributes::Dynamic
7
8
  store_in collection: 'bundles'
8
9
  field :title, type: String
10
+ field :name, type: String
9
11
  field :version, type: String
10
12
  field :license, type: String
11
13
  field :extensions, type: Array
14
+ field :measures, type: Array
12
15
  field :effective_date
13
16
  field :measure_period_start
14
17
  field :records, type: Array
@@ -16,7 +19,7 @@ module HealthDataStandards
16
19
 
17
20
  validates_presence_of :version
18
21
 
19
- scope :active, where(active: true)
22
+ scope :active, -> {where(active: true)}
20
23
 
21
24
  def self.latest_bundle_id
22
25
  desc(:exported).first.try(:_id)
@@ -7,9 +7,12 @@ module HealthDataStandards
7
7
  MSRPOPL = 'MSRPOPL'
8
8
 
9
9
  store_in collection: 'measures'
10
- field :id, type: String
10
+ field :id, as: :id, type: String
11
11
  field :sub_id, type: String
12
+ field :cms_id, type: String
12
13
  field :name, type: String
14
+ field :title, type: String
15
+ field :description, type: String
13
16
  field :subtitle, type: String
14
17
  field :short_subtitle, type: String
15
18
  field :hqmf_id, type: String
@@ -29,12 +32,15 @@ module HealthDataStandards
29
32
  field :populations, type: Array
30
33
  field :preconditions, type: Hash
31
34
  field :hqmf_document, type: Hash
32
-
35
+ field :map_fn, type: String
36
+ field :continuous_variable, type: Boolean
37
+ field :episode_of_care, type: Boolean
38
+ field :aggregator, type: String
33
39
  embeds_many :prefilters
34
40
 
35
41
  scope :top_level_by_type , ->(type){where({"type"=> type}).any_of({"sub_id" => nil}, {"sub_id" => "a"})}
36
- scope :top_level , any_of({"sub_id" => nil}, {"sub_id" => "a"})
37
- scope :order_by_id_sub_id, order_by([["id", :asc],["sub_id", :asc]])
42
+ scope :top_level , ->{any_of({"sub_id" => nil}, {"sub_id" => "a"})}
43
+ scope :order_by_id_sub_id, ->{order_by([["id", :asc],["sub_id", :asc]])}
38
44
 
39
45
  index oids: 1
40
46
  index hqmf_id: 1
@@ -46,28 +52,37 @@ module HealthDataStandards
46
52
  validates_presence_of :id
47
53
  validates_presence_of :name
48
54
 
49
- def self.categories
55
+ def self.categories(measure_properties = [])
56
+ measure_properties = Array(measure_properties).map(&:to_s) | %w(
57
+ name description nqf_id cms_id hqmf_id continuous_variable episode_of_care
58
+ )
50
59
  pipeline = []
51
- pipeline << {'$group' => {_id: "$id",
52
- name: {"$first" => "$name"},
53
- description: {"$first" => "$description"},
54
- subs: {'$push' => {"sub_id" => "$sub_id", "short_subtitle" => "$short_subtitle"}},
55
- sub_ids: {'$push' => "$sub_id"},
56
- nqf_id: {"$first" => "$nqf_id"},
57
- cms_id: {"$first" => "$cms_id"},
58
- continuous_variable: {"$first" => "$continuous_variable"},
59
- category: {'$first' => "$category"}}}
60
-
61
- pipeline << {'$group' => {_id: "$category",
62
- measures: {'$push' => {"id" => "$_id",
63
- 'name' => "$name",
64
- 'description' => "$description",
65
- 'subs' => "$subs",
66
- 'sub_ids' => "$sub_ids",
67
- 'nqf_id' => "$nqf_id",
68
- 'cms_id' => "$cms_id",
69
- 'continuous_variable' => "$continuous_variable"
70
- }}}}
60
+
61
+ pipeline << {'$group' => measure_properties.inject({
62
+ '_id' => "$id",
63
+ 'subs' => {'$push' => {"sub_id" => "$sub_id", "short_subtitle" => "$short_subtitle"}},
64
+ 'sub_ids' => {'$push' => "$sub_id"},
65
+ 'category' => {'$first' => "$category"}
66
+ }) do |h, prop|
67
+ h[prop] = {"$first" => "$#{prop}"}
68
+ h
69
+ end
70
+ }
71
+
72
+ pipeline << {'$group' => {
73
+ _id: "$category",
74
+ measures: {
75
+ '$push' => measure_properties.inject({
76
+ 'id' => "$_id",
77
+ 'hqmf_id' => "$_id",
78
+ 'subs' => "$subs",
79
+ 'sub_ids' => "$sub_ids"
80
+ }) do |h, prop|
81
+ h[prop] = "$#{prop}"
82
+ h
83
+ end
84
+ }
85
+ }}
71
86
 
72
87
  pipeline << {'$project' => {'category' => '$_id', 'measures' => 1, '_id' => 0}}
73
88