health-data-standards 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -14,4 +14,5 @@ group :test do
14
14
  gem "tailor", '~> 1.1.2'
15
15
  gem "cane", '~> 2.3.0'
16
16
  gem 'simplecov', :require => false
17
+ gem 'webmock'
17
18
  end
@@ -12,7 +12,8 @@ require_relative 'health-data-standards/ext/string'
12
12
 
13
13
  require_relative 'health-data-standards/util/hl7_helper'
14
14
  require_relative 'health-data-standards/util/code_system_helper'
15
- require_relative 'health-data-standards/util/qrda_template_helper'
15
+ require_relative 'health-data-standards/util/hqmf_template_helper'
16
+ require_relative 'health-data-standards/util/vs_api'
16
17
 
17
18
  require_relative 'health-data-standards/export/template_helper'
18
19
  require_relative 'health-data-standards/export/view_helper'
@@ -59,6 +60,8 @@ require_relative 'health-data-standards/models/person'
59
60
  require_relative 'health-data-standards/models/organization'
60
61
  require_relative 'health-data-standards/models/address'
61
62
  require_relative 'health-data-standards/models/telecom'
63
+ require_relative 'health-data-standards/models/svs/value_set'
64
+ require_relative 'health-data-standards/models/svs/concept'
62
65
  require_relative 'health-data-standards/models/facility'
63
66
  require_relative 'health-data-standards/models/metadata/base'
64
67
  require_relative 'health-data-standards/models/metadata/author'
@@ -3,10 +3,10 @@ module HealthDataStandards
3
3
  module HTML
4
4
  include TemplateHelper
5
5
 
6
- def export(patient)
6
+ def export(patient, concept_map=nil)
7
7
  self.template_format = "html"
8
8
  self.template_subdir = "html"
9
- render(:template => 'show', :locals => {:patient => patient})
9
+ render(:template => 'show', :locals => {:patient => patient, :concept_map=>concept_map})
10
10
  end
11
11
 
12
12
  extend self
@@ -84,16 +84,16 @@ module HealthDataStandards
84
84
  return ["true","false"].include? (str || "").downcase
85
85
  end
86
86
 
87
- def decode_qrda_section(section, oid)
87
+ def decode_hqmf_section(section, oid)
88
88
  if oid
89
- HealthDataStandards::Util::QRDATemplateHelper.definition_for_template_id(oid)['definition'].pluralize.to_sym
89
+ HealthDataStandards::Util::HQMFTemplateHelper.definition_for_template_id(oid)['definition'].pluralize.to_sym
90
90
  else
91
91
  section
92
92
  end
93
93
  end
94
- def decode_qrda_status(status, oid)
94
+ def decode_hqmf_status(status, oid)
95
95
  if oid
96
- HealthDataStandards::Util::QRDATemplateHelper.definition_for_template_id(oid)['status']
96
+ HealthDataStandards::Util::HQMFTemplateHelper.definition_for_template_id(oid)['status']
97
97
  else
98
98
  status
99
99
  end
@@ -60,6 +60,7 @@ module HealthDataStandards
60
60
  facility.addresses = participant_element.xpath("./cda:addr").try(:map) {|ae| import_address(ae)}
61
61
  facility.telecoms = participant_element.xpath("./cda:telecom").try(:map) {|te| import_telecom(te)}
62
62
  facility.code = extract_code(participant_element, './cda:code')
63
+ extract_dates(participant_element.parent, facility, "time")
63
64
  encounter.facility = facility
64
65
  end
65
66
  end
@@ -108,7 +108,7 @@ module HealthDataStandards
108
108
  end
109
109
 
110
110
  def extract_dates(parent_element, entry, element_name="effectiveTime")
111
- if parent_element.at_xpath("cda:#{element_name}")
111
+ if parent_element.at_xpath("cda:#{element_name}/@value")
112
112
  entry.time = HL7Helper.timestamp_to_integer(parent_element.at_xpath("cda:#{element_name}")['value'])
113
113
  end
114
114
  if parent_element.at_xpath("cda:#{element_name}/cda:low")
@@ -17,18 +17,15 @@ module HealthDataStandards
17
17
  extract_code(encounter_element, encounter, "./gc32:admissionType", :admit_type)
18
18
  extract_code(encounter_element, encounter, "./gc32:reasonForVisit", :reason)
19
19
  extract_code(encounter_element, encounter)
20
- extract_facility(encounter_element, encounter)
21
20
  extract_free_text(encounter_element, encounter)
22
21
 
23
- encounter
24
- end
25
-
26
- def extract_facility(encounter_element, encounter)
27
- facility_element = encounter_element.xpath("./gc32:facility").first
22
+ facility_element = encounter_element.at_xpath("./gc32:facility")
28
23
  if facility_element
29
- organization = extract_organization(facility_element)
30
- encounter.facility = organization
24
+ facility = extract_facility(facility_element)
25
+ encounter.facility = facility
31
26
  end
27
+
28
+ encounter
32
29
  end
33
30
 
34
31
  end
@@ -122,6 +122,22 @@ module HealthDataStandards
122
122
 
123
123
  return organization
124
124
  end
125
+
126
+ def extract_facility(facility_element)
127
+ facility = Facility.new
128
+ facility.name = extract_node_text(facility_element.xpath("./gc32:name"))
129
+ facility.addresses = facility_element.xpath("./gc32:address").map { |addr| extract_address(addr) }
130
+ facility.telecoms = facility_element.xpath("./gc32:telecom").map { |tele| extract_telecom(tele) }
131
+ start_time = facility_element.at_xpath("./gc32:duration/gc32:start").try(:text)
132
+ if start_time
133
+ facility.start_time = Time.parse(start_time).utc.to_i
134
+ end
135
+ end_time = facility_element.at_xpath("./gc32:duration/gc32:end").try(:text)
136
+ if end_time
137
+ facility.end_time = Time.parse(end_time).utc.to_i
138
+ end
139
+ facility
140
+ end
125
141
 
126
142
  def extract_address(address_element)
127
143
  return unless address_element
@@ -1,3 +1,4 @@
1
1
  class CodedResultValue < ResultValue
2
2
  include ThingWithCodes
3
+ field :description, type: String
3
4
  end
@@ -4,6 +4,9 @@ class Facility
4
4
  field :name, type: String
5
5
  field :code, type: Hash
6
6
 
7
+ field :start_time, type: Integer
8
+ field :end_time, type: Integer
9
+
7
10
  embeds_many :addresses, as: :locatable
8
11
  embeds_many :telecoms, as: :contactable
9
12
  end
@@ -1,6 +1,7 @@
1
1
  class InsuranceProvider
2
2
  include Mongoid::Document
3
3
 
4
+ embedded_in :record, class_name: 'Record'
4
5
  embeds_one :payer, class_name: "Organization"
5
6
  embeds_many :guarantors, class_name: "Guarantor"
6
7
  embeds_one :subscriber, class_name: "Person"
@@ -1,5 +1,8 @@
1
1
  class MedicalEquipment < Entry
2
2
 
3
3
  field :manufacturer, type: String
4
-
4
+ field :anatomicalStructure, type: Hash
5
+
6
+ alias :anatomical_structure :anatomicalStructure
7
+ alias :anatomical_structure= :anatomicalStructure=
5
8
  end
@@ -1,5 +1,9 @@
1
1
  class Procedure < Entry
2
- field :site, type: Hash
2
+ field :site, type: Hash
3
+ field :incisionDateTime, type: Integer
3
4
 
4
5
  belongs_to :performer, class_name: "Provider"
6
+
7
+ alias :incision_date_time :incisionDateTime
8
+ alias :incision_date_time= :incisionDateTime=
5
9
  end
@@ -5,7 +5,6 @@ class Provider
5
5
  field :tin , type: String
6
6
  field :specialty , type: String
7
7
  field :phone , type: String
8
- field :organization, type: String
9
8
 
10
9
  validates_uniqueness_of :npi, allow_blank: true
11
10
 
@@ -37,8 +37,8 @@ class Record
37
37
  embeds_many :functional_statuses
38
38
 
39
39
  Sections = [:allergies, :care_goals, :conditions, :encounters, :immunizations, :medical_equipment,
40
- :medications, :procedures, :results, :social_history, :vital_signs, :support, :advanced_directives,
41
- :functional_statuses]
40
+ :medications, :procedures, :results, :social_history, :vital_signs, :support, :advance_directives,
41
+ :insurance_providers, :functional_statuses]
42
42
 
43
43
  embeds_many :provider_performances
44
44
 
@@ -52,6 +52,18 @@ class Record
52
52
  def over_18?
53
53
  Time.at(birthdate) < Time.now.years_ago(18)
54
54
  end
55
+
56
+ def entries_for_oid(oid)
57
+ matching_entries_by_section = Sections.map do |section|
58
+ section_entries = self.send(section)
59
+ if section_entries.present?
60
+ section_entries.find_all { |entry| entry.oid == oid }
61
+ else
62
+ []
63
+ end
64
+ end
65
+ matching_entries_by_section.flatten
66
+ end
55
67
 
56
68
  alias :clinical_trial_participant :clinicalTrialParticipant
57
69
  alias :clinical_trial_participant= :clinicalTrialParticipant=
@@ -0,0 +1,16 @@
1
+ module HealthDataStandards
2
+ module SVS
3
+
4
+ class Concept
5
+
6
+ include Mongoid::Document
7
+ field :code, type: String
8
+ field :code_system_name, type: String
9
+ field :code_system_version, type: String
10
+ field :display_name, type: String
11
+ field :code_system, type: String
12
+ scope :by_code_system_name, ->(cs){where(code_system_name: cs)}
13
+ scope :by_code_system, ->(cs){where(code_system: cs)}
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,30 @@
1
+ module HealthDataStandards
2
+ module SVS
3
+ class ValueSet
4
+
5
+ include Mongoid::Document
6
+ field :oid, type: String
7
+ field :display_name, type: String
8
+ field :version, type: String
9
+
10
+ embeds_many :concepts
11
+ scope :by_oid, ->(oid){where(:oid => oid)}
12
+
13
+ def self.load_from_xml(doc)
14
+ doc.root.add_namespace_definition("vs","urn:ihe:iti:svs:2008")
15
+ vs_element = doc.at_xpath("/vs:RetrieveValueSetResponse/vs:ValueSet")
16
+ if vs_element
17
+ vs = ValueSet.new(oid: vs_element["ID"], display_name: vs_element["displayName"], version: vs_element["version"])
18
+ concepts = vs_element.xpath("//vs:Concept").collect do |con|
19
+ Concept.new(code: con["code"],
20
+ code_system_name: con["codeSystemName"],
21
+ code_system_version: con["code_system_version"],
22
+ display_name: con["displayName"],code_system: con["codeSystem"])
23
+ end
24
+ vs.concepts = concepts
25
+ return vs
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -18,7 +18,9 @@ module HealthDataStandards
18
18
  '2.16.840.1.113883.3.88.12.80.20' => 'FDA',
19
19
  '2.16.840.1.113883.5.14' => 'HL7 ActStatus',
20
20
  '2.16.840.1.113883.6.259' => 'HL7 Healthcare Service Location',
21
- '2.16.840.1.113883.5.4' => 'HL7 Act Code'
21
+ '2.16.840.1.113883.5.4' => 'HL7 Act Code',
22
+ '2.16.840.1.113883.1.11.18877' => 'HL7 Relationship Code',
23
+ '2.16.840.1.113883.6.238' => 'CDC Race'
22
24
  }
23
25
 
24
26
  # Returns the name of a code system given an oid
@@ -0,0 +1,28 @@
1
+ module HealthDataStandards
2
+ module Util
3
+ # General helpers for working with codes and code systems
4
+ class HQMFTemplateHelper
5
+
6
+ def self.definition_for_template_id(template_id)
7
+ template_id_map[template_id]
8
+ end
9
+
10
+ def self.template_id_map
11
+ if @id_map.blank?
12
+ template_id_file = File.expand_path('../hqmf_template_oid_map.json', __FILE__)
13
+ @id_map = JSON.parse(File.read(template_id_file))
14
+ end
15
+ @id_map
16
+ end
17
+
18
+ def self.template_id_by_definition_and_status(definition, status, negation=false)
19
+ pairs = template_id_map.select {|k, v| v['definition'] == definition &&
20
+ v['status'] == status &&
21
+ v['negation'] == negation}
22
+ pairs.keys.first if pairs.present?
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+
@@ -0,0 +1,43 @@
1
+ require 'rest_client'
2
+ require 'uri'
3
+ module HealthDataStandards
4
+ module Util
5
+ class VSApi
6
+ attr_accessor :api_url, :ticket_url, :username, :password
7
+
8
+ def initialize(ticket_url, api_url,username,password)
9
+ @api_url = api_url
10
+ @ticket_url = ticket_url
11
+ @username = username
12
+ @password = password
13
+ end
14
+
15
+ def get_valueset(oid,&block)
16
+ vs = RestClient.get api_url, {:params=>{id: oid, ticket: get_ticket}}
17
+ yield oid,vs if block_given?
18
+ vs
19
+ end
20
+
21
+ def process_valuesets(oids, &block)
22
+ oids.each do |oid|
23
+ vs = get_valueset(oid)
24
+ yield oid,vs
25
+ end
26
+ end
27
+
28
+ def proxy_ticket
29
+ @proxy_ticket ||= get_proxy_ticket
30
+ end
31
+
32
+ def get_proxy_ticket
33
+ # the content type is set and the body is a string becuase the NLM service does not support urlencoded content and
34
+ # throws an error on that contnet type
35
+ RestClient.post ticket_url, {username: username, password: password}
36
+ end
37
+
38
+ def get_ticket
39
+ RestClient.post "#{ticket_url}/#{proxy_ticket}", {service: "http://umlsks.nlm.nih.gov"}
40
+ end
41
+ end
42
+ end
43
+ end
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: 2.0.0
4
+ version: 2.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -12,8 +12,24 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2012-09-24 00:00:00.000000000 Z
15
+ date: 2012-10-31 00:00:00.000000000 Z
16
16
  dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: rest-client
19
+ requirement: !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ~>
23
+ - !ruby/object:Gem::Version
24
+ version: 1.6.7
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.6.7
17
33
  - !ruby/object:Gem::Dependency
18
34
  name: erubis
19
35
  requirement: !ruby/object:Gem::Requirement
@@ -196,13 +212,16 @@ files:
196
212
  - lib/health-data-standards/models/record.rb
197
213
  - lib/health-data-standards/models/result_value.rb
198
214
  - lib/health-data-standards/models/support.rb
215
+ - lib/health-data-standards/models/svs/concept.rb
216
+ - lib/health-data-standards/models/svs/value_set.rb
199
217
  - lib/health-data-standards/models/telecom.rb
200
218
  - lib/health-data-standards/models/thing_with_codes.rb
201
219
  - lib/health-data-standards/models/treating_provider.rb
202
220
  - lib/health-data-standards/models/vital_sign.rb
203
221
  - lib/health-data-standards/util/code_system_helper.rb
204
222
  - lib/health-data-standards/util/hl7_helper.rb
205
- - lib/health-data-standards/util/qrda_template_helper.rb
223
+ - lib/health-data-standards/util/hqmf_template_helper.rb
224
+ - lib/health-data-standards/util/vs_api.rb
206
225
  - lib/health-data-standards.rb
207
226
  - templates/_address.gc32.erb
208
227
  - templates/_advance_directive.gc32.erb
@@ -273,3 +292,4 @@ signing_key:
273
292
  specification_version: 3
274
293
  summary: A library for generating and consuming various healthcare related formats.
275
294
  test_files: []
295
+ has_rdoc:
@@ -1,20 +0,0 @@
1
-
2
- module HealthDataStandards
3
- module Util
4
- # General helpers for working with codes and code systems
5
- class QRDATemplateHelper
6
-
7
- def self.definition_for_template_id(template_id)
8
- template_id_map[template_id]
9
- end
10
-
11
- def self.template_id_map
12
- template_id_file = File.expand_path('../qrda_template_oid_map.json', __FILE__)
13
- JSON.parse(File.read(template_id_file))
14
- end
15
-
16
- end
17
- end
18
- end
19
-
20
-