health-data-standards 2.0.0 → 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.
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
-