roqua-healthy 1.0.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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.document +3 -0
  3. data/.gitignore +8 -0
  4. data/.rspec +1 -0
  5. data/.rubocop.yml +31 -0
  6. data/.yardopts +1 -0
  7. data/ChangeLog.md +10 -0
  8. data/Gemfile +8 -0
  9. data/Guardfile +11 -0
  10. data/LICENSE.txt +20 -0
  11. data/README.md +31 -0
  12. data/Rakefile +33 -0
  13. data/bin/get +8 -0
  14. data/bin/get_old_mirth_processing_result +6 -0
  15. data/bin/get_xml_for_patient +6 -0
  16. data/bin/parse_local_xml +9 -0
  17. data/healthy.gemspec +42 -0
  18. data/lib/roqua/healthy/a19/address_parser.rb +46 -0
  19. data/lib/roqua/healthy/a19/cdis_name_parser.rb +23 -0
  20. data/lib/roqua/healthy/a19/correct_patient_check.rb +18 -0
  21. data/lib/roqua/healthy/a19/fetcher.rb +61 -0
  22. data/lib/roqua/healthy/a19/name_parser.rb +52 -0
  23. data/lib/roqua/healthy/a19/response_parser.rb +27 -0
  24. data/lib/roqua/healthy/a19/response_validator.rb +45 -0
  25. data/lib/roqua/healthy/a19/transformer.rb +102 -0
  26. data/lib/roqua/healthy/a19.rb +25 -0
  27. data/lib/roqua/healthy/errors.rb +16 -0
  28. data/lib/roqua/healthy/message_cleaner.rb +44 -0
  29. data/lib/roqua/healthy/version.rb +6 -0
  30. data/lib/roqua/healthy.rb +14 -0
  31. data/lib/roqua-healthy.rb +1 -0
  32. data/spec/fixtures/cdis_gerda_geit.xml +181 -0
  33. data/spec/fixtures/cdis_jan_fictief.xml +177 -0
  34. data/spec/fixtures/cdis_piet_fictief.xml +177 -0
  35. data/spec/fixtures/comez_patient.xml +259 -0
  36. data/spec/fixtures/medo_patient.xml +101 -0
  37. data/spec/fixtures/oru-requests/spsy1218j.hl7 +82 -0
  38. data/spec/fixtures/oru-requests/spsy1218o.hl7 +76 -0
  39. data/spec/fixtures/oru-requests/spsy1218o2.hl7 +77 -0
  40. data/spec/fixtures/oru-requests/spsy411o.hl7 +73 -0
  41. data/spec/fixtures/oru-requests/spsy411o2.hl7 +71 -0
  42. data/spec/fixtures/oru-requests/spsyl.hl7 +71 -0
  43. data/spec/fixtures/oru-responses/xmcare_nack.hl7 +5 -0
  44. data/spec/fixtures/user_patient.xml +251 -0
  45. data/spec/fixtures/user_patient_with_gsm_and_email.xml +281 -0
  46. data/spec/fixtures/user_patient_with_maiden_name.xml +251 -0
  47. data/spec/fixtures/xmcare_impersonating_cdis.xml +245 -0
  48. data/spec/fixtures/xmcare_patient.xml +252 -0
  49. data/spec/fixtures/xmcare_patient_email_in_field_number_four.xml +245 -0
  50. data/spec/fixtures/xmcare_patient_not_found.xml +93 -0
  51. data/spec/fixtures/xmcare_patient_with_maiden_name.xml +252 -0
  52. data/spec/fixtures/xmcare_patient_without_birthdate.xml +250 -0
  53. data/spec/fixtures/xmcare_timeout_waiting_for_ack.xml +4 -0
  54. data/spec/healthy_spec.rb +7 -0
  55. data/spec/integration/cdis_spec.rb +72 -0
  56. data/spec/integration/comez_spec.rb +26 -0
  57. data/spec/integration/medo_spec.rb +26 -0
  58. data/spec/integration/mirth_spec.rb +17 -0
  59. data/spec/integration/user_spec.rb +72 -0
  60. data/spec/integration/xmcare_spec.rb +127 -0
  61. data/spec/spec_helper.rb +29 -0
  62. data/spec/support/fixtures.rb +14 -0
  63. data/spec/unit/a19/address_parser_spec.rb +132 -0
  64. data/spec/unit/a19/correct_patient_check_spec.rb +22 -0
  65. data/spec/unit/a19/fetcher_spec.rb +54 -0
  66. data/spec/unit/a19_spec.rb +4 -0
  67. data/spec/unit/message_cleaner_spec.rb +47 -0
  68. metadata +361 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 55deed92d3c485a1be152d296ee2811252f48947
4
+ data.tar.gz: 1203252d41c3fb84053d04f0d01a3668fa8ed70f
5
+ SHA512:
6
+ metadata.gz: 47599a271bec411480ccd2be7d7ec53e4e55e9baa04d82ccd6e40cfcdc40224910ac2a62ab26a690d03d4ac0b6dcc5243c547b70e6f4f583922a1c639d5ba680
7
+ data.tar.gz: da2432e8ba13859e503a8404e578c01e6995cd9ee878de3d00859140bf63f0c09ebc3ba7d5cba7d837d117634549d4db08fc14fda6d5bbcaa1c2d4bfe22dc2ff
data/.document ADDED
@@ -0,0 +1,3 @@
1
+ -
2
+ ChangeLog.md
3
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ .idea
2
+ .yardoc
3
+ Gemfile.lock
4
+ doc/
5
+ pkg/
6
+ tmp/
7
+ vendor/cache/*.gem
8
+ tmp/rspec_guard_result
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format progress
data/.rubocop.yml ADDED
@@ -0,0 +1,31 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`.
2
+ # The point is for the user to remove these configuration records
3
+ # one by one as the offences are removed from the code base.
4
+
5
+ AllCops:
6
+ Excludes:
7
+ - vendor/**
8
+
9
+ Documentation:
10
+ Enabled: false
11
+
12
+ LineLength:
13
+ Enabled: false
14
+
15
+ Encoding:
16
+ Enabled: false
17
+
18
+ StringLiterals:
19
+ Enabled: false
20
+
21
+ SpaceInsideHashLiteralBraces:
22
+ EnforcedStyle: no_space
23
+
24
+ MethodLength:
25
+ Max: 20
26
+
27
+ FinalNewline:
28
+ Enabled: False
29
+
30
+ SignalException:
31
+ Enabled: False
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --markup markdown --title "healthy Documentation" --protected
data/ChangeLog.md ADDED
@@ -0,0 +1,10 @@
1
+ ### 1.0.0 / 2014-01-22
2
+
3
+ * Released under the name 'roqua-healthy' to work around name collision on Rubygems.org.
4
+ This new name also makes it clearer that this gem is probably not very useful to others.
5
+ Note that everything is now nested under the Roqua::Healthy module instead of Healthy.
6
+
7
+ ### 0.1.0 / 2013-09-24
8
+
9
+ * Initial release:
10
+
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ # Only add dependencies here if they're only used by CI or other services.
6
+ # Normal development dependencies should go in the gemspec. People shouldn't
7
+ # need to use bundler to develop on our gem.
8
+ gem "codeclimate-test-reporter", group: :test, require: nil
data/Guardfile ADDED
@@ -0,0 +1,11 @@
1
+ guard 'rspec', cmd: 'bundle exec rspec -f Fuubar' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/healthy/(.+)\.rb$}) { |m| ["spec/unit/#{m[1]}_spec.rb", "spec/integration"] }
4
+ watch('spec/spec_helper.rb') { "spec" }
5
+ watch(%r{^spec/fixtures/([^_]+)_.*.xml}) { |m| "spec/integration/#{m[1]}_spec.rb" }
6
+ end
7
+
8
+ guard :rubocop do
9
+ watch(%r{.+\.rb$})
10
+ watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
11
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 Marten Veldthuis
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Healthy [![Code Climate](https://codeclimate.com/repos/524944dd56b10217490074e8/badges/5dd696b69c4614c83c2d/gpa.png)](https://codeclimate.com/repos/524944dd56b10217490074e8/feed) [![CircleCi](https://circleci.com/gh/roqua/healthy.png?circle-token=ece8f36798b00bc8659d5c76f720b22693d6600a)](https://circleci.com/gh/roqua/healthy)
2
+
3
+ ## Patient details aka QRY\^A19
4
+
5
+ ### Usage
6
+
7
+ ```ruby
8
+ Healthy::A19.fetch(patient_identifier)
9
+ ```
10
+
11
+ ### Adding integration tests
12
+
13
+ If you find any A19 response that Healthy currently does not handle correctly, please add a fixture and integration test for it.
14
+
15
+ * `curl --data "method=A19&application=healthy&patient_id=7767853" "http://10.20.11.100:60401"`
16
+ * Paste the resulting XML into a new file in `spec/fixtures`. Name this after the specific thing that is different, prefixed with the originating EPD. Don't name this after a specific organization, this repository is open-sourced and our customers might not want to be named publicly here.
17
+ * Please run it through an XML pretty printer like `xmllint --format` to get indented output.
18
+ * **<blink>Remove/sanitize/anonymize the XML file where needed.</blink>** We can't do this automatically with a script, because having a script normalize e.g. all names to "Voornaam Achternaam" would defeat the entire point of having multiple fixtures to show the different styles of names we can encounter.
19
+ * Add an integration spec example that uses it and checks all currently returned values.
20
+
21
+ ### Manually trying out parsing of a given record
22
+
23
+ There are two helpers in `bin`: `get_xml_for_patient` and `parse_local_xml`. The first one takes a patient number and ip+port on the mirth machine, and gets the XML from there. The second parses a chunk of XML from either standard input or a given file.
24
+
25
+ These two commands are then chained together by `bin/get`:
26
+
27
+ `bin/get 7767853 10.20.11.100:60201`
28
+
29
+ ## Copyright
30
+
31
+ Copyright (c) 2013 Marten Veldthuis. Publicly available under an MIT license. See [LICENSE.txt](https://github.com/roqua/healthy/blob/master/LICENSE.txt) for details.
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+
5
+ begin
6
+ require 'bundler'
7
+ rescue LoadError => e
8
+ warn e.message
9
+ warn "Run `gem install bundler` to install Bundler."
10
+ exit -1
11
+ end
12
+
13
+ begin
14
+ Bundler.setup(:development)
15
+ rescue Bundler::BundlerError => e
16
+ warn e.message
17
+ warn "Run `bundle install` to install missing gems."
18
+ exit e.status_code
19
+ end
20
+
21
+ require 'rake'
22
+
23
+ require 'rspec/core/rake_task'
24
+ RSpec::Core::RakeTask.new
25
+
26
+ task :test => :spec
27
+ task :default => :spec
28
+
29
+ require "bundler/gem_tasks"
30
+
31
+ require 'yard'
32
+ YARD::Rake::YardocTask.new
33
+ task :doc => :yard
data/bin/get ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ unless ARGV[0] && ARGV[1]
4
+ puts "Usage: get PATIENT_ID IP:PORT"
5
+ exit 1
6
+ end
7
+
8
+ exec "bin/get_xml_for_patient #{ARGV[0]} '#{ARGV[1]}' | ruby -Ilib bin/parse_local_xml"
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+
3
+ COMMAND="curl --data \"method=A19&patient_id=$1\" \"http://$2\""
4
+ XML=$(ssh x3mirth "$COMMAND")
5
+
6
+ echo $XML | xmllint --format -
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+
3
+ COMMAND="curl --data \"method=A19&application=healthy&patient_id=$1\" \"http://$2\""
4
+ XML=$(ssh x3mirth "$COMMAND")
5
+
6
+ echo $XML | xmllint --format -
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'healthy'
4
+ require 'ap'
5
+
6
+ body = ARGF.read
7
+ message = Hash.from_xml(body).fetch("HL7Message") { Hash.new }
8
+
9
+ ap Healthy::A19::Transformer.new(message).to_patient
data/healthy.gemspec ADDED
@@ -0,0 +1,42 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path('../lib/roqua/healthy/version', __FILE__)
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.name = "roqua-healthy"
7
+ gem.version = Roqua::Healthy::VERSION
8
+ gem.summary = %q{Arranges communication between Mirth and RoQua}
9
+ gem.description = %q{Receives queries from RoQua, sends them to Mirth, and translates Mirth's responses back into Rubyland.}
10
+ gem.license = "MIT"
11
+ gem.authors = ["Marten Veldthuis"]
12
+ gem.email = "marten@roqua.nl"
13
+ gem.homepage = "https://github.com/roqua/healthy"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ['lib']
19
+
20
+ gem.add_dependency 'activesupport', '~> 3.2'
21
+ gem.add_dependency 'addressable', '~> 2.3'
22
+ gem.add_dependency 'roqua-support', '~> 0.1.0'
23
+
24
+ gem.add_development_dependency 'bundler', '~> 1.0'
25
+ gem.add_development_dependency 'rake', '~> 10.0'
26
+ gem.add_development_dependency 'rspec', '~> 3.0.0.beta1'
27
+ gem.add_development_dependency 'yard', '~> 0.8'
28
+
29
+ # Required for the tests
30
+ gem.add_development_dependency 'webmock', '~> 1.13'
31
+
32
+ # Workflow and tools
33
+ gem.add_development_dependency 'guard', '~> 2.1'
34
+ gem.add_development_dependency 'guard-rspec', '~> 4.2.4'
35
+ gem.add_development_dependency 'listen', '~> 2.1'
36
+ gem.add_development_dependency 'guard-rubocop', '~> 1.0.1'
37
+ gem.add_development_dependency 'rubocop', '~> 0.15'
38
+ gem.add_development_dependency 'fuubar'
39
+
40
+ # Documentation generation
41
+ gem.add_development_dependency 'kramdown', '1.2'
42
+ end
@@ -0,0 +1,46 @@
1
+ module Roqua
2
+ module Healthy
3
+ module A19
4
+ class AddressParser
5
+ attr_reader :message
6
+
7
+ def initialize(message)
8
+ @message = message
9
+ end
10
+
11
+ def address_type
12
+ return nil unless record
13
+ record.fetch('PID.11.7')
14
+ end
15
+
16
+ def street
17
+ return nil unless record
18
+ record.fetch('PID.11.1').fetch('PID.11.1.1')
19
+ end
20
+
21
+ def city
22
+ return nil unless record
23
+ record.fetch('PID.11.3')
24
+ end
25
+
26
+ def zipcode
27
+ return nil unless record
28
+ record.fetch('PID.11.5')
29
+ end
30
+
31
+ def country
32
+ return nil unless record
33
+ record.fetch('PID.11.6')
34
+ end
35
+
36
+ def record
37
+ @record = nil
38
+ @record ||= message.fetch('PID').fetch('PID.11').find { |record| record.fetch('PID.11.7', :unknown_type_of_address_record) == 'M' }
39
+ @record ||= message.fetch('PID').fetch('PID.11').find { |record| record.fetch('PID.11.7', :unknown_type_of_address_record) == 'H' }
40
+ @record ||= message.fetch('PID').fetch('PID.11').find { |record| record.fetch('PID.11.7', :unknown_type_of_address_record) == 'L' }
41
+ @record
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,23 @@
1
+ require 'roqua/healthy/a19/name_parser'
2
+
3
+ module Roqua
4
+ module Healthy
5
+ module A19
6
+ # The CDIS EPD returns names in a format different from most other EPD vendors.
7
+ # This parser overrides some methods that are affected by the differences.
8
+ class CdisNameParser < NameParser
9
+ def firstname
10
+ names[:legal].fetch('PID.5.2')
11
+ end
12
+
13
+ def initials
14
+ names[:legal].fetch('PID.5.3')
15
+ end
16
+
17
+ def lastname
18
+ names[:legal].fetch('PID.5.1').fetch('PID.5.1.3')
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ module Roqua
2
+ module Healthy
3
+ module A19
4
+ class CorrectPatientCheck
5
+ attr_reader :patient_id, :record
6
+
7
+ def initialize(patient_id, record)
8
+ @patient_id = patient_id
9
+ @record = record
10
+ end
11
+
12
+ def check
13
+ record[:identities].any? { |i| i[:ident] == patient_id }
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,61 @@
1
+ require 'net/http'
2
+ require 'addressable/uri'
3
+
4
+ require 'roqua/healthy/a19/response_validator'
5
+ require 'roqua/healthy/a19/response_parser'
6
+
7
+ module Roqua
8
+ module Healthy
9
+ module A19
10
+ class Fetcher
11
+ attr_reader :patient_id
12
+
13
+ def initialize(patient_id)
14
+ @patient_id = patient_id
15
+ end
16
+
17
+ def fetch
18
+ response = mirth_response
19
+ parser = ResponseParser.new(response)
20
+
21
+ if ResponseValidator.new(response.code, parser, patient_id).validate
22
+ parser.fetch("HL7Message")
23
+ end
24
+ end
25
+
26
+ def mirth_response
27
+ Net::HTTP.start(remote_url.host, remote_url.port, use_ssl: use_ssl?) do |http|
28
+ request = Net::HTTP::Post.new(remote_url.path)
29
+ request.set_form_data(mirth_params)
30
+ http.request request
31
+ end
32
+ rescue ::Timeout::Error, Errno::ETIMEDOUT => error
33
+ raise ::Roqua::Healthy::Timeout, error.message
34
+ rescue Errno::EHOSTUNREACH => error
35
+ raise ::Roqua::Healthy::HostUnreachable, error.message
36
+ rescue Errno::ECONNREFUSED => error
37
+ raise ::Roqua::Healthy::ConnectionRefused, error.message
38
+ end
39
+
40
+ private
41
+
42
+ def mirth_params
43
+ {'method' => 'A19', 'patient_id' => patient_id.to_s, 'application' => "healthy"}
44
+ end
45
+
46
+ def use_ssl?
47
+ remote_url.port == 443 || remote_url.scheme == 'https'
48
+ end
49
+
50
+ def remote_url
51
+ return @remote_url if @remote_url
52
+
53
+ url = Addressable::URI.parse(Healthy.a19_endpoint)
54
+ url.path = "/"
55
+
56
+ @remote_url = URI.parse(url.to_s)
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,52 @@
1
+ module Roqua
2
+ module Healthy
3
+ module A19
4
+ class NameParser
5
+ attr_reader :message
6
+
7
+ def initialize(message)
8
+ @message = message
9
+ end
10
+
11
+ def firstname
12
+ return unless names[:nick]
13
+ names[:nick].fetch('PID.5.2')
14
+ end
15
+
16
+ def initials
17
+ "#{names[:legal].fetch('PID.5.2')} #{names[:legal].fetch('PID.5.3')}".strip
18
+ end
19
+
20
+ def lastname
21
+ prefix = names[:legal].fetch('PID.5.1').fetch('PID.5.1.2')
22
+ lastname = names[:legal].fetch('PID.5.1').fetch('PID.5.1.3')
23
+ "#{prefix} #{lastname}".strip
24
+ end
25
+
26
+ def display_name
27
+ return unless names[:display]
28
+ names[:display].fetch('PID.5.1')
29
+ end
30
+
31
+ private
32
+
33
+ def names
34
+ names = {}
35
+ message.fetch('PID').fetch('PID.5').each do |record|
36
+ case record.fetch('PID.5.7', :unknown_type_of_name_record)
37
+ when 'L'
38
+ names[:legal] = record
39
+ when 'D'
40
+ names[:display] = record
41
+ when 'N'
42
+ names[:nick] = record
43
+ else
44
+ # ignore record
45
+ end
46
+ end
47
+ names
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,27 @@
1
+ require 'active_support/core_ext/hash/conversions'
2
+
3
+ module Roqua
4
+ module Healthy
5
+ module A19
6
+ class ResponseParser
7
+ attr_reader :response
8
+
9
+ def initialize(response)
10
+ @response = response
11
+ end
12
+
13
+ def fetch(root)
14
+ parsed_body[root] || {}
15
+ end
16
+
17
+ private
18
+
19
+ def parsed_body
20
+ @parsed_body ||= Hash.from_xml(response.body)
21
+ rescue REXML::ParseException => e
22
+ raise IllegalMirthResponse, e.message
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,45 @@
1
+ require 'roqua/healthy/a19/response_parser'
2
+
3
+ module Roqua
4
+ module Healthy
5
+ module A19
6
+ class ResponseValidator
7
+ attr_reader :response_code
8
+ attr_reader :parser
9
+ attr_reader :patient_id
10
+
11
+ def initialize(response_code, parser, patient_id)
12
+ @response_code = response_code
13
+ @parser = parser
14
+ @patient_id = patient_id
15
+ end
16
+
17
+ def validate
18
+ case response_code
19
+ when '200'
20
+ validate_200
21
+ when '500'
22
+ validate_500
23
+ else
24
+ raise ::Roqua::Healthy::UnknownFailure, "Unexpected HTTP response code #{response_code}."
25
+ end
26
+ end
27
+
28
+ def validate_200
29
+ failure = parser.fetch("HL7Message")
30
+ raise ::Roqua::Healthy::PatientNotFound if failure.key?("ERR") && failure.fetch("ERR").fetch("ERR.1").fetch("ERR.1.4").fetch("ERR.1.4.2") =~ /Patient \(@\) niet gevonden\(.*\)/
31
+ raise ::Roqua::Healthy::MirthErrors::WrongPatient if failure.key?('QRD') && failure.fetch("QRD").fetch("QRD.8").fetch("QRD.8.1") != patient_id
32
+ true
33
+ end
34
+
35
+ def validate_500
36
+ failure = parser.fetch("failure")
37
+ raise ::Roqua::Healthy::Timeout, failure["error"] if failure["error"] == "Timeout waiting for ACK"
38
+ raise ::Roqua::Healthy::Timeout, failure["error"] if failure["error"] == "Unable to connect to destination\tSocketTimeoutException\tconnect timed out"
39
+ raise ::Roqua::Healthy::ConnectionRefused, failure["error"] if failure["error"] == "Unable to connect to destination\tConnectException\tConnection refused"
40
+ raise ::Roqua::Healthy::UnknownFailure, failure["error"]
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,102 @@
1
+ require 'roqua/healthy/a19/name_parser'
2
+ require 'roqua/healthy/a19/cdis_name_parser'
3
+ require 'roqua/healthy/a19/address_parser'
4
+
5
+ module Roqua
6
+ module Healthy
7
+ module A19
8
+ class Transformer
9
+ attr_reader :message
10
+
11
+ def initialize(message)
12
+ @message = message
13
+ @message['PID']['PID.3'] = [@message.fetch('PID').fetch('PID.3')].flatten.compact
14
+ @message['PID']['PID.5'] = [@message.fetch('PID').fetch('PID.5')].flatten.compact
15
+ @message['PID']['PID.11'] = [@message.fetch('PID').fetch('PID.11')].flatten.compact
16
+ @message['PID']['PID.13'] = [@message.fetch('PID').fetch('PID.13')].flatten.compact
17
+ @message = MessageCleaner.new(@message).message
18
+ end
19
+
20
+ def to_patient
21
+ {
22
+ status: status,
23
+ source: source,
24
+ identities: identities,
25
+ firstname: name.firstname,
26
+ initials: name.initials,
27
+ lastname: name.lastname,
28
+ display_name: name.display_name,
29
+ email: email,
30
+ address_type: address.address_type,
31
+ street: address.street,
32
+ city: address.city,
33
+ zipcode: address.zipcode,
34
+ country: address.country,
35
+ birthdate: birthdate,
36
+ gender: gender,
37
+ phone_cell: phone_cell
38
+ }
39
+ end
40
+
41
+ def status
42
+ 'SUCCESS'
43
+ end
44
+
45
+ def source
46
+ message.fetch('MSH').fetch('MSH.4').fetch('MSH.4.1')
47
+ end
48
+
49
+ def identities
50
+ message.fetch('PID').fetch('PID.3').map do |identity|
51
+ next if identity.fetch('PID.3.1').blank?
52
+ {ident: identity.fetch('PID.3.1'), authority: identity.fetch('PID.3.5')}
53
+ end.compact
54
+ end
55
+
56
+ def birthdate
57
+ birthdate_details = message.fetch('PID').fetch('PID.7')
58
+ birthdate_details.fetch('PID.7.1') if birthdate_details
59
+ end
60
+
61
+ def email
62
+ email_record = message.fetch('PID').fetch('PID.13').find do |record|
63
+ record.fetch('PID.13.2', :unknown_type_of_phone_record) == 'NET'
64
+ end
65
+ return nil unless email_record
66
+
67
+ email_address = email_record.fetch('PID.13.1', "")
68
+ email_address = email_record.fetch('PID.13.4', "") if email_address.blank?
69
+ email_address
70
+ end
71
+
72
+ def phone_cell
73
+ phone_cell_record = message.fetch('PID').fetch('PID.13').find do |record|
74
+ record.fetch('PID.13.2', :unknown_type_of_phone_record) == 'ORN'
75
+ end
76
+ return nil unless phone_cell_record
77
+
78
+ phone_cell_record.fetch('PID.13.1', "")
79
+ end
80
+
81
+ def gender
82
+ message.fetch('PID').fetch('PID.8').fetch('PID.8.1')
83
+ end
84
+
85
+ private
86
+
87
+ def name
88
+ case source
89
+ when "UMCG", "IMPULSE"
90
+ CdisNameParser.new(message)
91
+ else
92
+ NameParser.new(message)
93
+ end
94
+ end
95
+
96
+ def address
97
+ AddressParser.new(message)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,25 @@
1
+ module Roqua
2
+ module Healthy
3
+ module A19
4
+ extend ::Roqua::Logging
5
+
6
+ # Fetches a patient record given a `patient_id` and returns a hash containing
7
+ # the interesting information that was returned from an upstream `ADR^A19`
8
+ # response.
9
+ #
10
+ # @param patient_id [String] the patient identifier
11
+ # @return [Hash] the patient details.
12
+ def self.fetch(patient_id)
13
+ eventlog.lifecycle('roqua.hl7.a19', patient_id: patient_id) do
14
+ message = Fetcher.new(patient_id).fetch
15
+ patient = Transformer.new(message).to_patient
16
+ patient
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ require_relative 'a19/fetcher'
24
+ require_relative 'a19/transformer'
25
+ require_relative 'a19/correct_patient_check'