redox 0.1.6 → 1.1.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4cf3d701269f03a48d3cd1fe870e2f124aeb705c643c4cd3826ad5b352317276
4
- data.tar.gz: 562cc78ba951b7a58a3365612e09e38f114d7a7ab8ceb80b6e0e1c73b5592c7a
3
+ metadata.gz: af07742de7bb1cc39182903d8246bb8a59dfdb1b660fd629568ee799eef03f90
4
+ data.tar.gz: e088a4fbc1bd383ee5ea0570d6b3933a4d4eccafe1d7a70aa37de49925fe1beb
5
5
  SHA512:
6
- metadata.gz: fdd640751e3226609ac29cf6be385b7ae52487df1e46fa925e8e984cdf1e0458066f14e16a464dfa43d1201f9b0efcd988442c4eea26fd770a9b57d10e5cfd48
7
- data.tar.gz: a339571774b1058f4b646d0d2667bee605def7683c2aa47e152f41bfb3cb51872915a91d120a8b7da5e75c89da0ff0b46ef7292931c3da9cd5941b74fd31b73e
6
+ metadata.gz: efc0fe9382fecb0a4a738796e7dfb89f2b17438e5dbe4730a5de6357dea040f043e8f41130e331780a58263e61416581c024ff4ddcb90c28230f2d2a99bfa9e9
7
+ data.tar.gz: b6ec18283534dde1ca34cf053dad85df88fa9335e08ce4e631e81b0723f00f81a7ff9e72f6e417b3acb5cfa59410238912557cd5ea22890d1120018e5a478b0d
@@ -4,7 +4,47 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [0.1.6] - Unreleased
7
+ ## [1.1.1] - 2020-06-15
8
+ ### Changed
9
+ - Bugfix with patient param in update
10
+
11
+ ## [1.1.0] - 2020-06-15
12
+ ### Changed
13
+ - Moving to Requst classes instead of mixing in logic to models (kept backwards compatibility)
14
+ - Added potential matches to responses and implemented for patient search
15
+
16
+ =======
17
+ ### Added
18
+ - PotentialMatches class
19
+
20
+ ## [1.0.2] - 2019-06-04
21
+ ### Changed
22
+ - Added Extensions to all Redox models
23
+ - Fixed warnings in gemspec
24
+ - Fixed author emails in gemspec
25
+ - Removed packaging of bin and files starting with '.'
26
+ - Added helper file to translate Redox JSON to Hashie model.
27
+
28
+ ### Removed
29
+ - Unused response model.
30
+
31
+ ## [1.0.1] - 2019-05-02
32
+ ### Changed
33
+ - Check for high-level key as symbol
34
+
35
+ ## [1.0.0] - 2019-05-01
36
+ ### Changed
37
+ - How it works
38
+
39
+ ### Added
40
+ - Connection, RedoxClient, Authorization
41
+ - Global configuration block
42
+ - Gems httparty, hashie
43
+
44
+ ### Removed
45
+ - Identifiers, Demographics
46
+
47
+ ## [0.1.6] - 2019-04-22
8
48
  ### Added
9
49
  - Meta model
10
50
  - Response and Authentication classes
@@ -58,7 +98,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
58
98
  ### Added
59
99
  - Initial Release
60
100
 
61
- [Unreleased]: https://github.com/WeInfuse/redox/compare/v0.1.5...HEAD
101
+ [1.1.1]: https://github.com/WeInfuse/redox/compare/v1.1.0...v1.1.1
102
+ [1.1.0]: https://github.com/WeInfuse/redox/compare/v1.0.2...v1.1.0
103
+ [1.0.2]: https://github.com/WeInfuse/redox/compare/v1.0.1...v1.0.2
104
+ [1.0.1]: https://github.com/WeInfuse/redox/compare/v1.0.0...v1.0.1
105
+ [1.0.0]: https://github.com/WeInfuse/redox/compare/v0.1.6...v1.0.0
106
+ [0.1.6]: https://github.com/WeInfuse/redox/compare/v0.1.5...v0.1.6
62
107
  [0.1.5]: https://github.com/WeInfuse/redox/compare/v0.1.4...v0.1.5
63
108
  [0.1.4]: https://github.com/WeInfuse/redox/compare/0.1.3...v0.1.4
64
109
  [0.1.3]: https://github.com/WeInfuse/redox/compare/0.1.2...0.1.3
data/README.md CHANGED
@@ -21,34 +21,90 @@ Or install it yourself as:
21
21
 
22
22
  ## Usage
23
23
 
24
+ ### Setup
25
+
26
+ Make sure you're [configured](#configuration)!
27
+
24
28
  ```ruby
25
- source = {
26
- Name: 'Redox Dev Tools',
27
- ID: ENV['REDOX_SRC_ID']
28
- }
29
+ patient = Redox::Models::Patient.new
30
+ patient.demographics.first_name = 'Joe'
31
+ patient.demographics['LastName'] = 'Joerson'
32
+ patient.add_identifier(type: 'TheType', value: 'x13005')
33
+
34
+ meta = Redox::Models::Meta.new
35
+ meta.set_source(name: 'MySource', id: '123-584')
36
+ meta.add_destination(name: 'TheDest', id: '973-238')
37
+ ```
38
+
39
+ ### Create
40
+
41
+ ```ruby
42
+ response = patient.create(meta: meta)
43
+ ```
44
+
45
+ ### Update
46
+
47
+ ```ruby
48
+ response = patient.update(meta: meta)
49
+ ```
50
+
51
+ ### Search
52
+
53
+ ```ruby
54
+ response = Redox::Models::Patient.query(patient, meta: meta)
55
+ ```
56
+
57
+ ### Response
58
+
59
+ The response object is a base `Redox::Models::Model` class.
60
+
61
+ With the HTTParty response object
62
+ ```ruby
63
+ response.response
64
+ #<HTTParty::Response:0x7fa354c1fbe8>
65
+
66
+ response.response.ok?
67
+ true
68
+ ```
29
69
 
30
- destinations = [
31
- {
32
- Name: 'Redox EMR',
33
- ID: ENV['REDOX_DEST_ID']
70
+ And any `Model` objects that were returned
71
+ ```ruby
72
+ response.patient
73
+ {
74
+ "Identifiers"=> [
75
+ {"IDType"=>"MR", "ID"=>"0000000003"},
76
+ {"ID"=>"e3fedf48-c8bf-4728-845f-cb810001b571", "IDType"=>"EHRID"}
77
+ ],
78
+ "Demographics"=> {
79
+ "Race"=>"Black",
80
+ "SSN"=>"303-03-0003",
81
+ "Nickname"=>"Walt"
82
+ ...
34
83
  }
35
- ]
36
-
37
- redox = Redox::Redox.new(
38
- api_key: ENV['REDOX_KEY'],
39
- secret: ENV['REDOX_SECRET'],
40
- source: source,
41
- destinations: destinations,
42
- test: true
43
- )
44
-
45
- redox.add_patient(
46
- Identifiers: [...],
47
- Demographics: {
48
- FirstName: 'Joe'
49
- ...
84
+ "PCP"=> {
85
+ "NPI"=>nil,
50
86
  }
51
- )
87
+ }
88
+
89
+ response.meta
90
+ {
91
+ "EventDateTime"=>"2019-04-26T20:03:00.304866Z",
92
+ "DataModel"=>"PatientAdmin",
93
+ ...
94
+ "Transmission"=>{"ID"=>797225234},
95
+ "Message"=>{"ID"=>1095117817}
96
+ }
97
+ ```
98
+
99
+ ### Configuration
100
+
101
+ ```ruby
102
+ Redox.configure do |c|
103
+ c.api_key = ENV['REDOX_API_KEY']
104
+ c.secret = ENV['REDOX_SECRET']
105
+ c.api_endpoint = 'http://hello.com' # Defaults to Redox endpoint
106
+ c.token_expiry_padding = 120 # Defaults to 60 seconds
107
+ end
52
108
  ```
53
109
 
54
110
  ## Development
@@ -1,160 +1,85 @@
1
- require 'json'
2
- require 'net/http'
3
- require 'uri'
4
- require 'openssl'
1
+ require 'httparty'
2
+ require 'hashie'
5
3
  require 'redox/version'
6
4
  require 'redox/redox_exception'
5
+ require 'redox/connection'
7
6
  require 'redox/authentication'
8
- require 'redox/response'
9
7
  require 'redox/models/model'
10
8
  require 'redox/models/meta'
11
9
  require 'redox/models/patient'
12
- require 'redox/models/demographics'
13
- require 'redox/models/identifiers'
10
+ require 'redox/models/patient/demographics'
11
+ require 'redox/models/patient/identifier'
12
+ require 'redox/models/patient/insurance'
13
+ require 'redox/models/patient/p_c_p'
14
+ require 'redox/models/potential_matches'
15
+ require 'redox/request/patient_admin'
16
+ require 'redox/request/patient_search'
14
17
 
15
18
  module Redox
16
- # Redox API client
17
- class Redox
18
- DEFAULT_URI = 'https://api.redoxengine.com/'.freeze
19
+ class Configuration
20
+ attr_accessor :api_key, :secret
19
21
 
20
- # Instantiates a new Redox connection object
21
- #
22
- # @param [String] api_key API key for the connection
23
- # @param [String] secret API secret for the connection
24
- # @param [Hash] source source information
25
- # @param [Array<Hash>] destinations list of destinations
26
- # @param [Boolean] test whether to use test mode
27
- # @example
28
- # redox = Redox::Redox.new(
29
- # api_key: ENV['REDOX_KEY'],
30
- # secret: ENV['REDOX_SECRET'],
31
- # source: source,
32
- # destinations: destinations,
33
- # test: true
34
- # )
35
- def initialize(api_key:, secret:, source: nil, destinations: nil, facility_code: nil, test: true, uri: DEFAULT_URI)
36
- @api_key = api_key
37
- @secret = secret
38
- @meta = Models::Meta.new
39
- destinations.each {|dest| @meta.add_destination(dest['Name'], dest['ID']) } if destinations
40
- @meta.source = source if source
41
- @meta.facility_code = facility_code if facility_code
42
- @meta.test = test
43
- @connection = nil
44
- @authentication = nil
45
- @uri = uri
22
+ def initialize
23
+ @api_key = nil
24
+ @secret = nil
46
25
  end
47
26
 
48
- # Send NewPatient message
49
- #
50
- # @param [Hash] patient_params data to send in the Patient JSON object
51
- # @return [Hash] parsed response object
52
- # @example
53
- # Redox::Redox.new(*connection_params).add_patient(
54
- # Identifiers: [],
55
- # Demographics: {
56
- # FirstName: 'Joe'
57
- # }
58
- # )
59
- def add_patient(patient_params, meta = nil)
60
- meta = @meta.merge(Models::Meta.from_h(Models::Patient::ADD[:meta]).merge(meta))
61
- body = meta.to_h.merge(Patient: patient_params)
62
-
63
- return request(
64
- endpoint: Models::Patient::ADD[:endpoint],
65
- body: body.to_json,
66
- model: Models::Patient
67
- )
27
+ def api_endpoint=(endpoint)
28
+ Connection.base_uri(endpoint.freeze)
68
29
  end
69
30
 
70
- # Send PatientUpdate message
71
- #
72
- # @param [Hash] patient_params data to send in the Patient JSON object
73
- # @return [Hash] parsed response object
74
- # @example
75
- # Redox::Redox.new(*connection_params).update_patient(
76
- # Identifiers: [],
77
- # Demographics: {
78
- # FirstName: 'Joe'
79
- # }
80
- # )
81
- def update_patient(patient_params, meta = nil)
82
- meta = @meta.merge(Models::Meta.from_h(Models::Patient::UPDATE[:meta]).merge(meta))
83
- body = meta.to_h.merge(Patient: patient_params)
84
-
85
- return request(
86
- endpoint: Models::Patient::UPDATE[:endpoint],
87
- body: body.to_json,
88
- model: Models::Patient
89
- )
31
+ def api_endpoint
32
+ return Connection.base_uri
90
33
  end
91
34
 
92
- # Send PatientSearch query
93
- #
94
- # @param [Hash] patient_params data to send in the Patient JSON object
95
- # @return [Hash] Redox Patient object
96
- # @example
97
- # Redox::Redox.new(*connection_params).search_patients(
98
- # Identifiers: [],
99
- # Demographics: {
100
- # FirstName: 'Joe'
101
- # }
102
- # )
103
- def search_patients(patient_params, meta = nil)
104
- meta = @meta.merge(Models::Meta.from_h(Models::Patient::SEARCH[:meta]).merge(meta))
105
- body = meta.to_h.merge(Patient: patient_params)
106
-
107
- return request(
108
- endpoint: Models::Patient::SEARCH[:endpoint],
109
- body: body.to_json,
110
- model: Models::Patient
111
- )
35
+ def token_expiry_padding=(time_in_seconds)
36
+ Authentication.token_expiry_padding = time_in_seconds
112
37
  end
113
38
 
114
- private
115
-
116
- attr_reader :api_key, :secret, :meta
117
-
118
- def request(endpoint: , body: , header: {}, model: nil, authorize: true)
119
- header = {
120
- 'Content-Type' => 'application/json'
121
- }.merge(header)
122
-
123
- header = header.merge(authenticate.access_header) if authorize
124
-
125
- request = Net::HTTP::Post.new(endpoint, header)
126
- request.body = body
127
-
128
- return Response.new(connection.request(request), model)
39
+ def token_expiry_padding
40
+ return Authentication.token_expiry_padding
129
41
  end
130
42
 
131
- def authenticate
132
- return @authentication if @authentication
43
+ def to_h
44
+ return {
45
+ api_key: @api_key,
46
+ secret: @secret,
47
+ api_endpoint: api_endpoint,
48
+ token_expiry_padding: token_expiry_padding
49
+ }
50
+ end
133
51
 
134
- redox_response = request(
135
- endpoint: Authentication::ENDPOINT,
136
- body: { apiKey: api_key, secret: secret }.to_json,
137
- model: Authentication,
138
- authorize: false
139
- )
52
+ def from_h(h)
53
+ self.api_key = h[:api_key]
54
+ self.secret = h[:secret]
55
+ self.api_endpoint = h[:api_endpoint]
56
+ self.token_expiry_padding = h[:token_expiry_padding]
140
57
 
141
- if (false == redox_response.success?)
142
- raise RedoxException.from_response(redox_response.http_response, msg: 'Authentication')
143
- end
58
+ return self
59
+ end
60
+ end
144
61
 
145
- @authentication = redox_response.model
62
+ class << self
63
+ def configuration
64
+ @configuration ||= Configuration.new
146
65
  end
147
66
 
148
- def connection
149
- return @connection if @connection
67
+ def configure
68
+ yield(configuration)
69
+ end
70
+ end
150
71
 
151
- uri = URI.parse(@uri)
152
- http = Net::HTTP.new(uri.host, uri.port)
153
- http.use_ssl = true
154
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
155
- http.verify_depth = 5
72
+ # Redox API client
73
+ class RedoxClient
74
+ class << self
75
+ def connection
76
+ Redox.configuration.token_expiry_padding = 60 if Redox.configuration.token_expiry_padding.nil?
77
+ @connection ||= Connection.new
78
+ end
156
79
 
157
- @connection = http
80
+ def release
81
+ @connection = nil
82
+ end
158
83
  end
159
84
  end
160
85
  end
@@ -1,19 +1,77 @@
1
1
  module Redox
2
- class Authentication
3
- ENDPOINT = '/auth/authenticate'.freeze
2
+ class Authentication < Connection
3
+ attr_accessor :response
4
4
 
5
- def initialize(response_body)
6
- @body = response_body
5
+ BASE_ENDPOINT = '/auth'.freeze
6
+
7
+ AUTH_ENDPOINT = "#{BASE_ENDPOINT}/authenticate".freeze
8
+ REFRESH_ENDPOINT = "#{BASE_ENDPOINT}/refreshToken".freeze
9
+
10
+ class << self
11
+ attr_accessor :token_expiry_padding
12
+
13
+ @@token_expiry_padding = 0
14
+ end
15
+
16
+ def initialize
17
+ @response = nil
18
+ end
19
+
20
+ def authenticate
21
+ if (self.expires?)
22
+ if (self.refresh_token)
23
+ request = {
24
+ body: { apiKey: Redox.configuration.api_key, refreshToken: self.refresh_token },
25
+ endpoint: REFRESH_ENDPOINT
26
+ }
27
+ else
28
+ request = {
29
+ body: { apiKey: Redox.configuration.api_key, secret: Redox.configuration.secret },
30
+ endpoint: AUTH_ENDPOINT
31
+ }
32
+ end
33
+
34
+ response = self.request(**request, auth: false)
35
+
36
+ if (false == response.ok?)
37
+ @response = nil
38
+ raise RedoxException.from_response(response, msg: 'Authentication')
39
+ else
40
+ @response = response
41
+ end
42
+ end
43
+
44
+ return self
7
45
  end
8
46
 
9
47
  def access_token
10
- return @body['accessToken']
48
+ return @response['accessToken'] if @response
49
+ end
50
+
51
+ def expiry
52
+ return @response['expires'] if @response
53
+ end
54
+
55
+ def refresh_token
56
+ return @response['refreshToken'] if @response
57
+ end
58
+
59
+ def expires?(seconds_from_now = Authentication.token_expiry_padding)
60
+ if (self.expiry)
61
+ return DateTime.strptime(self.expiry, Models::Meta::FROM_DATETIME_FORMAT).to_time.utc <= (Time.now + seconds_from_now).utc
62
+ else
63
+ return true
64
+ end
11
65
  end
12
66
 
13
67
  def access_header
14
68
  return {
15
- 'Authorization' => "Bearer #{access_token}",
69
+ 'Authorization' => "Bearer #{self.access_token}",
16
70
  }
17
71
  end
72
+
73
+ def expire!
74
+ @response = nil
75
+ end
18
76
  end
19
77
  end
@@ -0,0 +1,28 @@
1
+ module Redox
2
+ class Connection
3
+ DEFAULT_ENDPOINT = '/endpoint'.freeze
4
+
5
+ include HTTParty
6
+
7
+ base_uri 'https://api.redoxengine.com/'.freeze
8
+
9
+ headers 'Content-Type' => 'application/json'
10
+
11
+ format :json
12
+
13
+ def request(endpoint: DEFAULT_ENDPOINT, body: nil, headers: {}, auth: true)
14
+ body = body.to_json if body.is_a?(Hash)
15
+ headers = auth_header.merge(headers) if auth
16
+
17
+ self.class.post(endpoint, body: body, headers: headers)
18
+ end
19
+
20
+ private
21
+
22
+ def auth_header
23
+ @auth ||= Authentication.new
24
+
25
+ return @auth.authenticate.access_header
26
+ end
27
+ end
28
+ end
@@ -1,79 +1,45 @@
1
1
  module Redox
2
2
  module Models
3
3
  class Meta < Model
4
- KEY = 'Meta'.freeze
5
-
6
- DEFAULT = -> () {
7
- return {
8
- KEY => {
9
- 'DataModel' => nil,
10
- 'EventType' => nil,
11
- 'EventDateTime' => Time.now.strftime("%Y-%m-%dT%H:%M:%S.%6NZ"),
12
- 'Test' => true,
13
- 'Source' => {},
14
- 'Destinations' => [],
15
- 'FacilityCode' => nil
16
- }
17
- }
18
- }
19
-
20
- def initialize(data = DEFAULT.call)
21
- super(data)
22
- end
23
-
24
- def add_destination(name, id)
25
- self.inner['Destinations'] << Meta.build_subscription(name, id)
4
+ TO_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%6NZ'.freeze
5
+ FROM_DATETIME_FORMAT = '%Y-%m-%dT%H:%M:%S.%N%Z'.freeze
6
+
7
+ property :DataModel, from: :data_model, required: false
8
+ property :EventType, from: :event_type, required: false
9
+ property :EventDateTime, from: :event_date_time, default: ->() { Time.now.utc.strftime(TO_DATETIME_FORMAT) }
10
+ property :Test, from: :test, default: true
11
+ property :Source, from: :source, required: false
12
+ property :Destinations, from: :destinations, required: false
13
+ property :FacilityCode, from: :facility_code, required: false
14
+
15
+ alias_method :data_model, :DataModel
16
+ alias_method :event_type, :EventType
17
+ alias_method :event_date_time, :EventDateTime
18
+ alias_method :test, :Test
19
+ alias_method :source, :Source
20
+ alias_method :destinations, :Destinations
21
+ alias_method :facility_code, :FacilityCode
22
+
23
+ def add_destination(name: , id: )
24
+ self[:Destinations] ||= []
25
+ self[:Destinations] << Meta.build_subscription(name: name, id: id)
26
26
 
27
27
  return self
28
28
  end
29
29
 
30
- def set_source(name, id)
31
- self.source = Meta.build_subscription(name, id)
32
-
33
- return self
34
- end
35
-
36
- def source=(source)
37
- self.inner['Source'] = source
38
- end
39
-
40
- def facility_code=(facility_code)
41
- self.inner['FacilityCode'] = facility_code.to_s
42
- end
43
-
44
- def test=(test)
45
- self.inner['Test'] = (true == test)
46
- end
47
-
48
- def merge(other)
49
- if (other.is_a?(Hash))
50
- if (other.include?(KEY))
51
- self.inner.merge!(other[KEY])
52
- else
53
- self.inner.merge!(other)
54
- end
55
- elsif (other.is_a?(self.class))
56
- self.inner.merge!(other.inner.select {|k,v| !v.nil?})
57
- end
30
+ def set_source(name: , id: )
31
+ self[:Source] = Meta.build_subscription(name: name, id: id)
58
32
 
59
33
  return self
60
34
  end
61
35
 
62
- def to_h
63
- return JSON.parse(@data.to_json)
64
- end
65
-
66
36
  class << self
67
- def build_subscription(name, id)
37
+ def build_subscription(name: , id:)
68
38
  return {
69
39
  'ID' => id,
70
40
  'Name' => name
71
41
  }
72
42
  end
73
-
74
- def from_h(hash)
75
- return Meta.new.merge(hash)
76
- end
77
43
  end
78
44
  end
79
45
  end
@@ -1,27 +1,60 @@
1
1
  module Redox
2
2
  module Models
3
- class Model
4
- KEY = nil
3
+ class Model < Hashie::Trash
4
+ include Hashie::Extensions::IgnoreUndeclared
5
+ include Hashie::Extensions::IndifferentAccess
5
6
 
6
- def initialize(data)
7
- @data = data.freeze
7
+ property :Meta, from: :meta, required: false
8
+ property :Patient, from: :patient, required: false
9
+ property :PotentialMatches, from: :potential_matches, required: false
10
+ property :Extensions, from: :extensions, required: false
11
+ property :response, required: false
12
+
13
+ alias_method :potential_matches, :PotentialMatches
14
+ alias_method :patient, :Patient
15
+ alias_method :meta, :Meta
16
+
17
+ def initialize(data = {})
18
+ if data.is_a?(Hash)
19
+ if data.include?(key)
20
+ data = data[key]
21
+ elsif data.include?(key.to_sym)
22
+ data = data[key.to_sym]
23
+ end
24
+ end
25
+
26
+ super(data)
8
27
  end
9
28
 
10
- def valid?
11
- return @data.is_a?(Hash) && @data.include?(self.class::KEY)
29
+ def to_h
30
+ return { key => super.to_h }
12
31
  end
13
32
 
14
- def raw
15
- return self.inner(key: nil)
33
+ def to_json
34
+ return self.to_h.to_json
16
35
  end
17
36
 
18
- def inner(key: self.class::KEY)
19
- if key.nil?
20
- return @data
21
- else
22
- return @data[key]
37
+ class << self
38
+ def from_response(response)
39
+ model = Model.new
40
+ model.response = response
41
+
42
+ %w[Meta Patient PotentialMatches].each do |k|
43
+ begin
44
+ model.send("#{k}=", Module.const_get("Redox::Models::#{k}").new(response[k])) if response[k]
45
+ rescue
46
+ end
47
+ end
48
+
49
+ return model
23
50
  end
24
51
  end
52
+
53
+ private
54
+
55
+ def key
56
+ return self.class.to_s.split('::').last.to_s
57
+ end
25
58
  end
26
59
  end
27
60
  end
@@ -1,40 +1,50 @@
1
1
  module Redox
2
2
  module Models
3
3
  class Patient < Model
4
- attr_reader :demographics, :identifiers
5
-
6
- KEY = 'Patient'.freeze
7
-
8
- SEARCH = {
9
- meta: {
10
- 'DataModel' => 'PatientSearch',
11
- 'EventType' => 'Query'
12
- },
13
- endpoint: '/query'
14
- }
15
-
16
- ADD = {
17
- meta: {
18
- 'DataModel' => 'PatientAdmin',
19
- 'EventType' => 'NewPatient'
20
- },
21
- endpoint: '/endpoint'
22
- }
23
-
24
- UPDATE = {
25
- meta: {
26
- 'DataModel' => 'PatientAdmin',
27
- 'EventType' => 'PatientUpdate'
28
- },
29
- endpoint: '/endpoint'
30
- }
31
-
32
- def initialize(data)
33
- super(data)
34
-
35
- if (self.valid?)
36
- @demographics = Demographics.new(self.inner)
37
- @identifiers = Identifiers.new(self.inner)
4
+ property :Identifiers, from: :identifiers, required: false, default: []
5
+ property :Insurances, from: :insurances, required: false, default: []
6
+ property :Demographics, from: :demographics, required: false
7
+ property :PCP, from: :primary_care_provider, required: false
8
+
9
+ alias_method :identifiers, :Identifiers
10
+ alias_method :insurances, :Insurances
11
+
12
+ def demographics
13
+ self[:Demographics] = Demographics.new(self[:Demographics]) unless self[:Demographics].is_a?(Redox::Models::Demographics)
14
+ self[:Demographics] ||= Demographics.new
15
+ end
16
+
17
+ def insurances
18
+ self[:Insurances] = self[:Insurances].map {|ins| ins.is_a?(Redox::Models::Insurance) ? ins : Insurance.new(ins) }
19
+ end
20
+
21
+ def primary_care_provider
22
+ self[:PCP] ||= PCP.new
23
+ end
24
+
25
+ def add_identifier(type: , value: )
26
+ self[:Identifiers] << Identifier.new({'ID' => value, 'IDType' => type})
27
+
28
+ return self
29
+ end
30
+
31
+ def add_insurance(data = {})
32
+ self[:Insurances] << Insurance.new(data)
33
+
34
+ return self
35
+ end
36
+
37
+ def update(meta: Meta.new)
38
+ Redox::Request::PatientAdmin.update(patient: self, meta: meta)
39
+ end
40
+
41
+ def create(meta: Meta.new)
42
+ Redox::Request::PatientAdmin.create(patient: self, meta: meta)
43
+ end
44
+
45
+ class << self
46
+ def query(params, meta: Meta.new)
47
+ return Redox::Request::PatientSearch.query(params, meta: meta)
38
48
  end
39
49
  end
40
50
  end
@@ -0,0 +1,34 @@
1
+ module Redox
2
+ module Models
3
+ class Demographics < Model
4
+ property :FirstName, required: false, from: :first_name
5
+ property :MiddleName, required: false, from: :middle_name
6
+ property :LastName, required: false, from: :last_name
7
+ property :DOB, required: false, from: :dob
8
+ property :SSN, required: false, from: :ssn
9
+ property :Sex, required: false, from: :sex
10
+ property :Race, required: false, from: :race
11
+ property :IsHispanic, required: false
12
+ property :MaritalStatus, required: false, from: :martial_status
13
+ property :IsDeceased, required: false
14
+ property :DeathDateTime, required: false
15
+ property :Language, required: false, from: :language
16
+ property :EmailAddresses, required: false, default: []
17
+ property :Citizenship, required: false, default: []
18
+ property :Address, required: false, default: {}
19
+ property :PhoneNumber, required: false, default: {}
20
+
21
+ alias_method :first_name, :FirstName
22
+ alias_method :middle_name, :MiddleName
23
+ alias_method :last_name, :LastName
24
+ alias_method :dob, :DOB
25
+ alias_method :ssn, :SSN
26
+ alias_method :sex, :Sex
27
+ alias_method :race, :Race
28
+ alias_method :martial_status, :MaritalStatus
29
+ alias_method :language, :Language
30
+ alias_method :address, :Address
31
+ alias_method :phone_number, :PhoneNumber
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,11 @@
1
+ module Redox
2
+ module Models
3
+ class Identifier < Model
4
+ property :ID, from: :id
5
+ property :IDType, from: :id_type
6
+
7
+ alias_method :id, :ID
8
+ alias_method :id_type, :IDType
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ module Redox
2
+ module Models
3
+ class Insurance < Model
4
+ property :Plan, required: false, from: :plan, default: {}
5
+ property :MemberNumber, required: false, from: :member_number
6
+ property :Company, required: false, from: :company, default: {}
7
+ property :GroupNumber, required: false, from: :group_number
8
+ property :GroupName, required: false, from: :group_name
9
+ property :EffectiveDate, required: false, from: :effective_date
10
+ property :ExpirationDate, required: false, from: :expiration_date
11
+ property :PolicyNumber, required: false, from: :policy_number
12
+ property :AgreementType, required: false, from: :agreement_type
13
+ property :CoverageType, required: false, from: :coverage_type
14
+ property :Insured, required: false, from: :insured, default: {}
15
+
16
+ alias_method :plan, :Plan
17
+ alias_method :member_number, :MemberNumber
18
+ alias_method :company, :Company
19
+ alias_method :group_number, :GroupNumber
20
+ alias_method :group_name, :GroupName
21
+ alias_method :effective_date, :EffectiveDate
22
+ alias_method :expiration_date, :ExpirationDate
23
+ alias_method :policy_number, :PolicyNumber
24
+ alias_method :agreement_type, :AgreementType
25
+ alias_method :coverage_type, :CoverageType
26
+ alias_method :insured, :Insured
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ module Redox
2
+ module Models
3
+ class PCP < Model
4
+ property :NPI, from: :npi
5
+ property :FirstName, required: false, from: :first_name
6
+ property :LastName, required: false, from: :last_name
7
+
8
+ alias_method :npi, :NPI
9
+ alias_method :first_name, :FirstName
10
+ alias_method :last_name, :LastName
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module Redox
2
+ module Models
3
+ class PotentialMatches < Array
4
+ def initialize(data = [])
5
+ if false == data.nil?
6
+ super(data.map {|patient| Redox::Models::Patient.new(patient) })
7
+ else
8
+ super([])
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ module Redox
2
+ module Request
3
+ class PatientAdmin
4
+ CREATE_META = Redox::Models::Meta.new(EventType: 'NewPatient', DataModel: 'PatientAdmin')
5
+ UPDATE_META = Redox::Models::Meta.new(EventType: 'PatientUpdate', DataModel: 'PatientAdmin')
6
+
7
+ def self.create(patient: , meta: Redox::Models::Meta.new)
8
+ meta = CREATE_META.merge(meta)
9
+ return Redox::Models::Model.from_response((RedoxClient.connection.request(body: Redox::Request::PatientAdmin.build_body(patient, meta))))
10
+ end
11
+
12
+ def self.update(patient: , meta: Redox::Models::Meta.new)
13
+ meta = UPDATE_META.merge(meta)
14
+ return Redox::Models::Model.from_response((RedoxClient.connection.request(body: Redox::Request::PatientAdmin.build_body(patient, meta))))
15
+ end
16
+
17
+ def self.build_body(params, meta)
18
+ meta = Redox::Models::Meta.new.merge(meta)
19
+
20
+ return meta.to_h.merge(params.to_h)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ module Redox
2
+ module Request
3
+ class PatientSearch
4
+ QUERY_ENDPOINT = '/query'.freeze
5
+ QUERY_META = Redox::Models::Meta.new(EventType: 'Query', DataModel: 'PatientSearch')
6
+
7
+ def self.query(params, meta: Redox::Models::Meta.new)
8
+ meta = QUERY_META.merge(meta)
9
+ return Redox::Models::Model.from_response((RedoxClient.connection.request(endpoint: QUERY_ENDPOINT, body: Redox::Request::PatientAdmin.build_body(params, meta))))
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,3 +1,3 @@
1
1
  module Redox
2
- VERSION = '0.1.6'.freeze
2
+ VERSION = '1.1.1'.freeze
3
3
  end
@@ -5,8 +5,8 @@ require 'redox/version'
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = 'redox'
7
7
  spec.version = Redox::VERSION
8
- spec.authors = ['Alexander Clark']
9
- spec.email = ['sasha.jackal@gmail.com']
8
+ spec.authors = ['Alexander Clark', 'Mike Crockett']
9
+ spec.email = ['alexander.clark@weinfuse.com', 'mike.crockett@weinfuse.com']
10
10
 
11
11
  spec.summary = 'Ruby wrapper for the Redox Engine API'
12
12
  spec.homepage = 'https://github.com/WeInfuse/redox'
@@ -20,14 +20,18 @@ Gem::Specification.new do |spec|
20
20
  end
21
21
 
22
22
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
23
- f.match(%r{^(test|spec|features)/})
23
+ f.match?(%r{^(test|spec|features|bin|helpers|)/}) || f.match?(%r{^(\.[[:alnum:]]+)})
24
24
  end
25
+
25
26
  spec.bindir = 'exe'
26
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
28
  spec.require_paths = ['lib']
29
+ spec.licenses = ['MIT']
28
30
 
29
- spec.add_development_dependency 'bundler'
30
- spec.add_development_dependency 'byebug'
31
+ spec.add_dependency 'httparty', '~> 0.17'
32
+ spec.add_dependency 'hashie', '~> 3.5'
33
+ spec.add_development_dependency 'bundler', '>=1', '<3'
34
+ spec.add_development_dependency 'byebug', '~> 11'
31
35
  spec.add_development_dependency 'minitest', '~> 5.0'
32
36
  spec.add_development_dependency 'rake', '~> 10.0'
33
37
  spec.add_development_dependency 'webmock', '~> 3.1'
metadata CHANGED
@@ -1,43 +1,78 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Clark
8
+ - Mike Crockett
8
9
  autorequire:
9
10
  bindir: exe
10
11
  cert_chain: []
11
- date: 2019-04-22 00:00:00.000000000 Z
12
+ date: 2020-06-16 00:00:00.000000000 Z
12
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: httparty
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '0.17'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '0.17'
28
+ - !ruby/object:Gem::Dependency
29
+ name: hashie
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '3.5'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '3.5'
13
42
  - !ruby/object:Gem::Dependency
14
43
  name: bundler
15
44
  requirement: !ruby/object:Gem::Requirement
16
45
  requirements:
17
46
  - - ">="
18
47
  - !ruby/object:Gem::Version
19
- version: '0'
48
+ version: '1'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '3'
20
52
  type: :development
21
53
  prerelease: false
22
54
  version_requirements: !ruby/object:Gem::Requirement
23
55
  requirements:
24
56
  - - ">="
25
57
  - !ruby/object:Gem::Version
26
- version: '0'
58
+ version: '1'
59
+ - - "<"
60
+ - !ruby/object:Gem::Version
61
+ version: '3'
27
62
  - !ruby/object:Gem::Dependency
28
63
  name: byebug
29
64
  requirement: !ruby/object:Gem::Requirement
30
65
  requirements:
31
- - - ">="
66
+ - - "~>"
32
67
  - !ruby/object:Gem::Version
33
- version: '0'
68
+ version: '11'
34
69
  type: :development
35
70
  prerelease: false
36
71
  version_requirements: !ruby/object:Gem::Requirement
37
72
  requirements:
38
- - - ">="
73
+ - - "~>"
39
74
  - !ruby/object:Gem::Version
40
- version: '0'
75
+ version: '11'
41
76
  - !ruby/object:Gem::Dependency
42
77
  name: minitest
43
78
  requirement: !ruby/object:Gem::Requirement
@@ -96,34 +131,36 @@ dependencies:
96
131
  version: '0.9'
97
132
  description:
98
133
  email:
99
- - sasha.jackal@gmail.com
134
+ - alexander.clark@weinfuse.com
135
+ - mike.crockett@weinfuse.com
100
136
  executables: []
101
137
  extensions: []
102
138
  extra_rdoc_files: []
103
139
  files:
104
- - ".circleci/config.yml"
105
- - ".editorconfig"
106
- - ".gitignore"
107
140
  - CHANGELOG.md
108
141
  - CODE_OF_CONDUCT.md
109
142
  - Gemfile
110
143
  - README.md
111
144
  - Rakefile
112
- - bin/console
113
- - bin/setup
114
145
  - lib/redox.rb
115
146
  - lib/redox/authentication.rb
116
- - lib/redox/models/demographics.rb
117
- - lib/redox/models/identifiers.rb
147
+ - lib/redox/connection.rb
118
148
  - lib/redox/models/meta.rb
119
149
  - lib/redox/models/model.rb
120
150
  - lib/redox/models/patient.rb
151
+ - lib/redox/models/patient/demographics.rb
152
+ - lib/redox/models/patient/identifier.rb
153
+ - lib/redox/models/patient/insurance.rb
154
+ - lib/redox/models/patient/p_c_p.rb
155
+ - lib/redox/models/potential_matches.rb
121
156
  - lib/redox/redox_exception.rb
122
- - lib/redox/response.rb
157
+ - lib/redox/request/patient_admin.rb
158
+ - lib/redox/request/patient_search.rb
123
159
  - lib/redox/version.rb
124
160
  - redox.gemspec
125
161
  homepage: https://github.com/WeInfuse/redox
126
- licenses: []
162
+ licenses:
163
+ - MIT
127
164
  metadata:
128
165
  allowed_push_host: https://rubygems.org
129
166
  post_install_message:
@@ -1,23 +0,0 @@
1
- version: 2
2
- jobs:
3
- build:
4
- working_directory: ~/weinfuse_api
5
- docker:
6
- - image: circleci/ruby:2.4
7
- steps:
8
- - checkout
9
- - type: restore-cache
10
- key: redox_{{ checksum "Gemfile.lock" }}
11
- key: redox
12
- - run: bundle install --path vendor/bundle --jobs 20 --retry 5
13
- - type: cache-save
14
- key: redox_{{ checksum "Gemfile.lock" }}
15
- key: redox
16
- paths:
17
- - vendor/bundle
18
- - type: shell
19
- command: |
20
- bundle exec rake test
21
- - type: store_test_results
22
- path: /tmp/test-results
23
-
@@ -1,10 +0,0 @@
1
- root=true
2
-
3
- [*]
4
- indent_style = space
5
- indent_size = 2
6
- end_of_line = lf
7
- charset = utf-8
8
- trim_trailing_whitespace = true
9
- insert_final_newline = true
10
-
data/.gitignore DELETED
@@ -1,10 +0,0 @@
1
- /.bundle/
2
- /.yardoc
3
- /Gemfile.lock
4
- /_yardoc/
5
- /coverage/
6
- /doc/
7
- /pkg/
8
- /spec/reports/
9
- /tmp/
10
- /redox*.gem
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'bundler/setup'
4
- require 'json'
5
- require 'redox'
6
-
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
13
-
14
- require 'irb'
15
- IRB.start
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
@@ -1,7 +0,0 @@
1
- module Redox
2
- module Models
3
- class Demographics < Model
4
- KEY = 'Demographics'.freeze
5
- end
6
- end
7
- end
@@ -1,7 +0,0 @@
1
- module Redox
2
- module Models
3
- class Identifiers < Model
4
- KEY = 'Identifiers'.freeze
5
- end
6
- end
7
- end
@@ -1,14 +0,0 @@
1
- module Redox
2
- class Response
3
- attr_reader :model, :http_response
4
-
5
- def initialize(response, model_class = nil)
6
- @http_response = response
7
- @model = model_class.new(JSON.parse(response.body)) if !model_class.nil? && self.success?
8
- end
9
-
10
- def success?
11
- return @http_response.is_a?(Net::HTTPOK)
12
- end
13
- end
14
- end