health-data-standards 3.4.1 → 3.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d4e79e25acfb493189be91192e6ef4ade10519d
4
- data.tar.gz: dae82bf68ad4ffe2abec94a1fa7cf9e7e6ab8a68
3
+ metadata.gz: 72d97569e429961540cbae76560562aa8c1fd626
4
+ data.tar.gz: 1894a2c0e5b89a085a4cccd2f1993f48d70e4418
5
5
  SHA512:
6
- metadata.gz: 2633fc1119b6c03e9bd3a7a4c40cb9493bd9b1a35d0f62f5fc14138cae6bf9f01ecab534072c1fb72d71a955fd16645b39e53ae22a6435d24cc44335ad145553
7
- data.tar.gz: 0734aeecdfa317f96a663bf1c7cb9599c2f3d2162a793bd842d3db9c440f524212618fa571b3587b7acb92aeadb1bdb57344d27d94828dcc7e5e3312be58d518
6
+ metadata.gz: 2d9dc3a22e22ba92ffee3f70386e3761ed69740b3f68cf1f3197647cd71e38cd502c309c3c0e20a21553f6c15a22cff08cf6f44bb97ae6221bdbdd65e2a82445
7
+ data.tar.gz: 40b9f38d66d27c7f01ac2c6dffc489e58845e20ab865d25a262b164135a6bc5f85524e23e19264239f84cc77c0bf20c60b06d9f357f8f583a1e0ec5de87ad400
data/README.md CHANGED
@@ -25,6 +25,19 @@ Please try to follow the [GitHub Coding Style Guides](https://github.com/stylegu
25
25
  Change Log
26
26
  ==========
27
27
 
28
+ 3.4.2 - February 28, 2014
29
+
30
+ * Provider improvements
31
+ ** Providers are now exported in QRDA Cat I if they exist on the Record object
32
+ ** Provider identifiers are now represented with CDAIdentifiers
33
+ ** Provider import will now import any type of identifier
34
+ ** Providers can now be arranged in a hierarchy
35
+ ** When importing providers from a clincial document, matching to existing providers in MongoDB has been improved to matching on any type of identifier
36
+ * QRDA Cat I importer now imports procedure values regardless of whether the template has them at the root level or nested in an entryRelationship
37
+ * Bug fix - Result importer will no longer double import result values
38
+ * QRDA Cat I importer now imports encounter order end times
39
+ * Bug fix - QRDA Cat I importer now properly imports condition and procedure ordinaltiy
40
+
28
41
  3.4.1 - January 24, 2014
29
42
 
30
43
  * Fix for JRuby - Nokogiri is now fixed to version 1.6.0 exactly. Version 1.6.1 was breaking the CCR part of the test suite under JRuby. Nokogiri 1.6.0 works properly across Ruby 1.9.3, Ruby 2.0.0 and JRuby 1.7.9
@@ -1,6 +1,7 @@
1
1
  require 'erubis'
2
2
  require 'active_support'
3
3
  require 'mongoid'
4
+ require 'mongoid/tree'
4
5
  require 'uuid'
5
6
  require 'builder'
6
7
  require 'csv'
@@ -78,6 +78,11 @@ module HealthDataStandards
78
78
 
79
79
  record = Record.update_or_create(patient_data)
80
80
  record.provider_performances = providers
81
+ providers.each do |prov|
82
+ prov.provider.ancestors.each do |ancestor|
83
+ record.provider_performances.push(ProviderPerformance.new(start_date: prov.start_date, end_date: prov.end_date, provider: ancestor))
84
+ end
85
+ end
81
86
  record.save
82
87
 
83
88
  {status: 'success', message: 'patient imported', status_code: 201, record: record}
@@ -164,6 +164,14 @@ module HealthDataStandards
164
164
  end
165
165
 
166
166
  contents.each do |document|
167
+ if name == "by_patient"
168
+ # Set the patient_id to the actual _id of
169
+ # newly created patient record
170
+ medical_record_id = document['value']['medical_record_id']
171
+ if patient = Record.by_patient_id(medical_record_id).first
172
+ document['value']['patient_id'] = patient.id
173
+ end
174
+ end
167
175
  document['bundle_id'] = bundle.id
168
176
  Mongoid.default_session[collection].insert(document)
169
177
  end
@@ -11,6 +11,7 @@ module HealthDataStandards
11
11
  def extract_dates(parent_element, entry, element_name="author")
12
12
  if parent_element.at_xpath("cda:#{element_name}/cda:time/@value")
13
13
  entry.start_time = HL7Helper.timestamp_to_integer(parent_element.at_xpath("cda:#{element_name}/cda:time")['value'])
14
+ entry.end_time = HL7Helper.timestamp_to_integer(parent_element.at_xpath("cda:#{element_name}/cda:time")['value'])
14
15
  end
15
16
  end
16
17
  end
@@ -24,10 +24,18 @@ module HealthDataStandards
24
24
  extract_reason_description(reason_element, reason, nrh)
25
25
  extract_status(reason_element, reason)
26
26
  extract_dates(reason_element, reason)
27
+ extract_workaround_codes(reason_element, reason)
27
28
  encounter.reason = reason
28
29
  end
29
30
  end
30
31
 
32
+ def extract_workaround_codes(parent_element, entry)
33
+ value = parent_element.at_xpath("./cda:value")
34
+ entry['code'] = value['code']
35
+ entry['code_system'] = CodeSystemHelper.code_system_for(value['codeSystem'])
36
+ entry['codeSystemName'] = CodeSystemHelper.code_system_for(value['codeSystem'])
37
+ end
38
+
31
39
  def extract_admit_time(parent_element, encounter)
32
40
  encounter.admit_time = encounter.start_time
33
41
  end
@@ -40,7 +40,7 @@ module HealthDataStandards
40
40
  generate_importer(ProcedureOrderImporter, nil, '2.16.840.1.113883.3.560.1.62', 'ordered'),
41
41
  generate_importer(ProcedurePerformedImporter, "//cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.64']", '2.16.840.1.113883.3.560.1.6'),
42
42
  generate_importer(CDA::ProcedureImporter, "//cda:procedure[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.66']", '2.16.840.1.113883.3.560.1.63'),
43
- generate_importer(CDA::ProcedureImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.69']", '2.16.840.1.113883.3.560.1.21'),
43
+ generate_importer(CDA::ProcedureImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.69']", '2.16.840.1.113883.3.560.1.21'), #risk category assessment
44
44
  generate_importer(CDA::ProcedureImporter, "//cda:observation[cda:templateId/@root = '2.16.840.1.113883.10.20.24.3.18']", '2.16.840.1.113883.3.560.1.103', 'performed'), #diagnostic study performed
45
45
  generate_importer(DiagnosticStudyOrderImporter, nil, '2.16.840.1.113883.3.560.1.40', 'ordered')]
46
46
 
@@ -37,7 +37,7 @@ module HealthDataStandards
37
37
  def extract_ordinality(parent_element, entry)
38
38
  ordinality_element = parent_element.at_xpath(@ordinality_xpath)
39
39
  if ordinality_element
40
- entry.ordinality = {CodeSystemHelper.code_system_for(ordinality_element['codeSystem']) => [ordinality_element['code']]}
40
+ entry.ordinality = {"code" => ordinality_element['code'], "code_system" => CodeSystemHelper.code_system_for(ordinality_element['codeSystem']), "codeSystemName" => CodeSystemHelper.code_system_for(ordinality_element['codeSystem']), CodeSystemHelper.code_system_for(ordinality_element['codeSystem']) => [ordinality_element['code']]}
41
41
  end
42
42
  end
43
43
 
@@ -31,7 +31,7 @@ module HealthDataStandards
31
31
  def extract_anatomical_structure(entry_element, entry)
32
32
  site = entry_element.at_xpath(@anatomical_xpath)
33
33
  if site
34
- entry.anatomical_structure = {CodeSystemHelper.code_system_for(site['codeSystem']) => [site['code']]}
34
+ entry.anatomical_structure = {"code" => site['code'], "code_system" => CodeSystemHelper.code_system_for(site['codeSystem']), "codeSystemName" => CodeSystemHelper.code_system_for(site['codeSystem']), CodeSystemHelper.code_system_for(site['codeSystem']) => [site['code']]}
35
35
  end
36
36
  end
37
37
  end
@@ -8,7 +8,7 @@ module HealthDataStandards
8
8
  def initialize(entry_finder=EntryFinder.new("//cda:section[cda:templateId/@root!='2.16.840.1.113883.3.88.11.83.124']//cda:procedure"))
9
9
  super(entry_finder)
10
10
  @entry_class = Procedure
11
- @value_xpath = ".//cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.87']/cda:value"
11
+ @value_xpath = "./cda:value | ./cda:entryRelationship[@typeCode='REFR']/cda:observation/cda:value"
12
12
  @ordinality_xpath = "./cda:priorityCode"
13
13
  end
14
14
 
@@ -27,7 +27,7 @@ module HealthDataStandards
27
27
  def extract_ordinality(parent_element, procedure)
28
28
  ordinality_element = parent_element.at_xpath(@ordinality_xpath)
29
29
  if ordinality_element
30
- procedure.ordinality = {CodeSystemHelper.code_system_for(ordinality_element['codeSystem']) => [ordinality_element['code']]}
30
+ procedure.ordinality = {"code" => ordinality_element['code'], "code_system" => CodeSystemHelper.code_system_for(ordinality_element['codeSystem']), "codeSystemName" => CodeSystemHelper.code_system_for(ordinality_element['codeSystem']), CodeSystemHelper.code_system_for(ordinality_element['codeSystem']) => [ordinality_element['code']]}
31
31
  end
32
32
  end
33
33
 
@@ -31,7 +31,14 @@ module HealthDataStandards
31
31
  def extract_provider_data(performer, use_dates=true, entity_path="./cda:assignedEntity")
32
32
  provider = {}
33
33
  entity = performer.xpath(entity_path)
34
-
34
+
35
+ cda_idents = []
36
+ entity.xpath("./cda:id").each do |cda_ident|
37
+ ident_root = cda_ident['root']
38
+ ident_extension = cda_ident['extension']
39
+ cda_idents.push(CDAIdentifier.new(root: ident_root, extension: ident_extension)) if ident_root.present?
40
+ end
41
+
35
42
  name = entity.at_xpath("./cda:assignedPerson/cda:name")
36
43
  provider[:title] = extract_data(name, "./cda:prefix")
37
44
  provider[:given_name] = extract_data(name, "./cda:given[1]")
@@ -51,7 +58,8 @@ module HealthDataStandards
51
58
  provider[:telecoms] = performer.xpath("./cda:assignedEntity/cda:telecom").try(:map) {|te| import_telecom(te)}
52
59
 
53
60
  provider[:npi] = npi if Provider.valid_npi?(npi)
54
-
61
+ provider[:cda_identifiers] = cda_idents
62
+
55
63
  provider
56
64
  end
57
65
 
@@ -9,7 +9,6 @@ module HealthDataStandards
9
9
 
10
10
  def create_entry(entry_element, nrh = NarrativeReferenceHandler.new)
11
11
  result = super
12
- extract_value(entry_element, result)
13
12
  extract_interpretation(entry_element, result)
14
13
  extract_reference_range(entry_element, result)
15
14
  extract_negation(entry_element, result)
@@ -160,12 +160,12 @@ module HealthDataStandards
160
160
  unless negation_indicator.nil?
161
161
  entry.negation_ind = negation_indicator.eql?('true')
162
162
  if entry.negation_ind
163
- negation_reason_element = parent_element.at_xpath("./cda:entryRelationship[@typeCode='RSON']/cda:act[cda:templateId/@root='2.16.840.1.113883.10.20.1.27']/cda:code")
163
+ negation_reason_element = parent_element.at_xpath("./cda:entryRelationship[@typeCode='RSON']/cda:observation[cda:templateId/@root='2.16.840.1.113883.10.20.24.3.88']/cda:value | ./cda:entryRelationship[@typeCode='RSON']/cda:act[cda:templateId/@root='2.16.840.1.113883.10.20.1.27']/cda:code")
164
164
  if negation_reason_element
165
165
  code_system_oid = negation_reason_element['codeSystem']
166
166
  code = negation_reason_element['code']
167
167
  code_system = HealthDataStandards::Util::CodeSystemHelper.code_system_for(code_system_oid)
168
- entry.negation_reason = {'code' => code, 'codeSystem' => code_system}
168
+ entry.negation_reason = {'code' => code, 'code_system' => code_system, 'codeSystem' => code_system}
169
169
  end
170
170
  end
171
171
  end
@@ -6,13 +6,19 @@ module ProviderImportUtils
6
6
  end
7
7
 
8
8
  def find_or_create_provider(provider_hash)
9
- provider = Provider.where(npi: provider_hash[:npi]).first if provider_hash[:npi] && !provider_hash[:npi].empty?
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]
12
12
  provider = Provider.create(provider_hash)
13
+ provider.npi = provider_hash[:npi]
13
14
  else
14
15
  provider ||= Provider.resolve_provider(provider_hash) if Provider.respond_to? :resolve_provider
15
-
16
+
17
+ ident_roots = provider_hash[:cda_identifiers].map {|ident| ident.root}
18
+ ident_extensions = provider_hash[:cda_identifiers].map {|ident| ident.extension}
19
+ unless ident_roots.size == 0
20
+ provider ||= Provider.in("cda_identifiers.root" => ident_roots).and.in("cda_identifiers.extension" => ident_extensions).first
21
+ end
16
22
  provider_query = {:title => provider_hash[:title],
17
23
  :given_name => provider_hash[:given_name],
18
24
  :family_name=> provider_hash[:family_name],
@@ -3,7 +3,7 @@ class CDAIdentifier
3
3
 
4
4
  field :root, type: String
5
5
  field :extension, type: String
6
- embedded_in :entry
6
+ embedded_in :cda_identifiable, polymorphic: true
7
7
 
8
8
  def ==(comparison_object)
9
9
  if comparison_object.respond_to?(:root) && comparison_object.respond_to?(:extension)
@@ -6,7 +6,7 @@ class Entry
6
6
  # embedded_in :entry_list, polymorphic: true
7
7
 
8
8
  embedded_in :record
9
- embeds_one :cda_identifier, class_name: "CDAIdentifier"
9
+ embeds_one :cda_identifier, class_name: "CDAIdentifier", as: :cda_identifiable
10
10
  embeds_many :values, class_name: "ResultValue"
11
11
 
12
12
  field :description, type: String
@@ -1,15 +1,43 @@
1
1
  class Provider
2
2
  include Personable
3
+ include Mongoid::Tree
3
4
 
4
- field :npi , type: String
5
- field :tin , type: String
5
+ NPI_OID = '2.16.840.1.113883.4.6'
6
+ TAX_ID_OID = '2.16.840.1.113883.4.2'
7
+
6
8
  field :specialty , type: String
7
9
  field :phone , type: String
8
10
 
9
11
  validates_uniqueness_of :npi, allow_blank: true
10
12
 
11
13
  embeds_one :organization
14
+ embeds_many :cda_identifiers, class_name: "CDAIdentifier", as: :cda_identifiable
15
+
16
+ scope :by_npi, ->(an_npi){ where("cda_identifiers.root" => NPI_OID, "cda_identifiers.extension" => an_npi)}
17
+
18
+ def npi=(an_npi)
19
+ cda_id_npi = self.cda_identifiers.where(root: NPI_OID).first
20
+ if cda_id_npi
21
+ cda_id_npi.extension = an_npi
22
+ cda_id_npi.save!
23
+ else
24
+ self.cda_identifiers << CDAIdentifier.new(root: NPI_OID, extension: an_npi)
25
+ end
26
+ end
12
27
 
28
+ def npi
29
+ cda_id_npi = self.cda_identifiers.where(root: NPI_OID).first
30
+ cda_id_npi ? cda_id_npi.extension : nil
31
+ end
32
+
33
+ def tin=(a_tin)
34
+ self.cda_identifiers << CDAIdentifier.new(root: TAX_ID_OID, extension: a_tin)
35
+ end
36
+
37
+ def tin
38
+ cda_id_tin = self.cda_identifiers.where(root: TAX_ID_OID).first
39
+ cda_id_tin ? cda_id_tin.extension : nil
40
+ end
13
41
 
14
42
  def records(effective_date=nil)
15
43
  Record.by_provider(self, effective_date)
@@ -85,6 +85,12 @@ class Record
85
85
  matching_entries_by_section.flatten
86
86
  end
87
87
 
88
+ def entries
89
+ Sections.map do |section|
90
+ self.send(section)
91
+ end.flatten
92
+ end
93
+
88
94
  memoize :entries_for_oid
89
95
 
90
96
  alias :clinical_trial_participant :clinicalTrialParticipant
@@ -0,0 +1,57 @@
1
+ <documentationOf typeCode="DOC">
2
+ <serviceEvent classCode="PCPR"> <!-- care provision -->
3
+ <% if patient.provider_performances.empty? -%>
4
+ <!-- No provider data found in the patient record
5
+ putting in a fake provider -->
6
+ <effectiveTime>
7
+ <low value="20020716"/>
8
+ <high value="<%= Time.now.utc.to_formatted_s(:number) %>"/>
9
+ </effectiveTime>
10
+ <!-- You can include multiple performers, each with an NPI, TIN, CCN. -->
11
+ <performer typeCode="PRF">
12
+ <time>
13
+ <low value="20020716"/>
14
+ <high value="<%= Time.now.utc.to_formatted_s(:number) %>"/>
15
+ </time>
16
+ <assignedEntity>
17
+ <!-- This is the provider NPI -->
18
+ <id root="2.16.840.1.113883.4.6" extension="111111111" />
19
+ <representedOrganization>
20
+ <!-- This is the organization TIN -->
21
+ <id root="2.16.840.1.113883.4.2" extension="1234567" />
22
+ <!-- This is the organization CCN -->
23
+ <id root="2.16.840.1.113883.4.336" extension="54321" />
24
+ </representedOrganization>
25
+ </assignedEntity>
26
+ </performer>
27
+ <% else -%>
28
+ <% patient.provider_performances.each do |pp| -%>
29
+ <effectiveTime>
30
+ <low <%= value_or_null_flavor(pp.start_date) %>/>
31
+ <high <%= value_or_null_flavor(pp.end_date) %>/>
32
+ </effectiveTime>
33
+ <!-- You can include multiple performers, each with an NPI, TIN, CCN. -->
34
+ <performer typeCode="PRF">
35
+ <time>
36
+ <low <%= value_or_null_flavor(pp.start_date) %>/>
37
+ <high <%= value_or_null_flavor(pp.end_date) %>/>
38
+ </time>
39
+ <assignedEntity>
40
+ <% pp.provider.cda_identifiers.each do |cda_id| -%>
41
+ <% unless cda_id.root.eql? '2.16.840.1.113883.4.2' -%>
42
+ <id root="<%= cda_id.root %>" extension="<%= cda_id.extension %>" />
43
+ <% end -%>
44
+ <% end -%>
45
+ <representedOrganization>
46
+ <% pp.provider.cda_identifiers.each do |cda_id| -%>
47
+ <% if cda_id.root.eql?('2.16.840.1.113883.4.2') -%>
48
+ <id root="2.16.840.1.113883.4.2" extension="<%= cda_id.extension %>" />
49
+ <% end -%>
50
+ <% end -%>
51
+ </representedOrganization>
52
+ </assignedEntity>
53
+ </performer>
54
+ <% end -%>
55
+ <% end -%>
56
+ </serviceEvent>
57
+ </documentationOf>
@@ -86,35 +86,7 @@
86
86
  </representedOrganization>
87
87
  </assignedEntity>
88
88
  </legalAuthenticator>
89
-
90
- <!-- TODO: This is where the provider information will go.
91
- It is currently hard coded, but should be replaced with the providers
92
- and the time over which they are performing. -->
93
- <documentationOf typeCode="DOC">
94
- <serviceEvent classCode="PCPR"> <!-- care provision -->
95
- <effectiveTime>
96
- <low value="20020716"/>
97
- <high value="<%= Time.now.utc.to_formatted_s(:number) %>"/>
98
- </effectiveTime>
99
- <!-- You can include multiple performers, each with an NPI, TIN, CCN. -->
100
- <performer typeCode="PRF">
101
- <time>
102
- <low value="20020716"/>
103
- <high value="<%= Time.now.utc.to_formatted_s(:number) %>"/>
104
- </time>
105
- <assignedEntity>
106
- <!-- This is the provider NPI -->
107
- <id root="2.16.840.1.113883.4.6" extension="111111111" />
108
- <representedOrganization>
109
- <!-- This is the organization TIN -->
110
- <id root="2.16.840.1.113883.4.2" extension="1234567" />
111
- <!-- This is the organization CCN -->
112
- <id root="2.16.840.1.113883.4.336" extension="54321" />
113
- </representedOrganization>
114
- </assignedEntity>
115
- </performer>
116
- </serviceEvent>
117
- </documentationOf>
89
+ <%== render :partial => 'providers', :locals => {:patient => patient} %>
118
90
  <component>
119
91
  <structuredBody>
120
92
  <%== render :partial => 'measures', :locals => {:measures => measures} %>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: health-data-standards
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.4.1
4
+ version: 3.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Gregorowicz
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2014-01-24 00:00:00.000000000 Z
15
+ date: 2014-02-28 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rest-client
@@ -56,6 +56,20 @@ dependencies:
56
56
  - - ~>
57
57
  - !ruby/object:Gem::Version
58
58
  version: 3.1.4
59
+ - !ruby/object:Gem::Dependency
60
+ name: mongoid-tree
61
+ requirement: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 1.0.4
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ~>
71
+ - !ruby/object:Gem::Version
72
+ version: 1.0.4
59
73
  - !ruby/object:Gem::Dependency
60
74
  name: activesupport
61
75
  requirement: !ruby/object:Gem::Requirement
@@ -455,6 +469,7 @@ files:
455
469
  - templates/cat1/_medication_details.cat1.erb
456
470
  - templates/cat1/_ordinality.cat1.erb
457
471
  - templates/cat1/_patient_data.cat1.erb
472
+ - templates/cat1/_providers.cat1.erb
458
473
  - templates/cat1/_reason.cat1.erb
459
474
  - templates/cat1/_record_target.cat1.erb
460
475
  - templates/cat1/_reporting_parameters.cat1.erb