redox 0.1.5 → 1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +49 -3
- data/README.md +80 -24
- data/lib/redox.rb +58 -140
- data/lib/redox/authentication.rb +77 -0
- data/lib/redox/connection.rb +28 -0
- data/lib/redox/models/meta.rb +46 -0
- data/lib/redox/models/model.rb +43 -32
- data/lib/redox/models/patient.rb +40 -14
- data/lib/redox/models/patient/demographics.rb +34 -0
- data/lib/redox/models/patient/identifier.rb +11 -0
- data/lib/redox/models/patient/insurance.rb +29 -0
- data/lib/redox/models/patient/p_c_p.rb +13 -0
- data/lib/redox/models/potential_matches.rb +13 -0
- data/lib/redox/request/patient_admin.rb +24 -0
- data/lib/redox/request/patient_search.rb +13 -0
- data/lib/redox/version.rb +1 -1
- data/redox.gemspec +9 -4
- metadata +67 -13
- data/.circleci/config.yml +0 -23
- data/.editorconfig +0 -10
- data/.gitignore +0 -10
- data/bin/console +0 -15
- data/bin/setup +0 -8
- data/lib/redox/models/demographics.rb +0 -7
- data/lib/redox/models/identifiers.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 451221082b696c7421fa2feacde94c0235bbd78348c416d904cba8df3d1ff67b
|
4
|
+
data.tar.gz: 9934ade2a99d85628444a8845b15bf14c79cb595f1307da196d57d1faa2a2668
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 192db714b76ee2a5d197577e21c2907f50d211667b1d16f7ee468af71196655da67fc593771e1f713419bc5a382e8b196b315660dba62c4563ee553bc9581e8d
|
7
|
+
data.tar.gz: 2f72e880e360b4d74e6b8b27b25baf0f9a4bb867615723afa9c40089d1a4debaf42c96aa6ee5997f2bc432d315bcbd6c02d9612c9f73aa096dffed1e6cb18cb9
|
data/CHANGELOG.md
CHANGED
@@ -4,9 +4,51 @@ 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
|
-
## [
|
7
|
+
## [1.1.0] - 2020-06-15
|
8
|
+
### Changed
|
9
|
+
- Moving to Requst classes instead of mixing in logic to models (kept backwards compatibility)
|
10
|
+
- Added potential matches to responses and implemented for patient search
|
11
|
+
|
12
|
+
=======
|
13
|
+
### Added
|
14
|
+
- PotentialMatches class
|
15
|
+
|
16
|
+
## [1.0.2] - 2019-06-04
|
17
|
+
### Changed
|
18
|
+
- Added Extensions to all Redox models
|
19
|
+
- Fixed warnings in gemspec
|
20
|
+
- Fixed author emails in gemspec
|
21
|
+
- Removed packaging of bin and files starting with '.'
|
22
|
+
- Added helper file to translate Redox JSON to Hashie model.
|
23
|
+
|
24
|
+
### Removed
|
25
|
+
- Unused response model.
|
26
|
+
|
27
|
+
## [1.0.1] - 2019-05-02
|
28
|
+
### Changed
|
29
|
+
- Check for high-level key as symbol
|
30
|
+
|
31
|
+
## [1.0.0] - 2019-05-01
|
32
|
+
### Changed
|
33
|
+
- How it works
|
34
|
+
|
8
35
|
### Added
|
9
|
-
-
|
36
|
+
- Connection, RedoxClient, Authorization
|
37
|
+
- Global configuration block
|
38
|
+
- Gems httparty, hashie
|
39
|
+
|
40
|
+
### Removed
|
41
|
+
- Identifiers, Demographics
|
42
|
+
|
43
|
+
## [0.1.6] - 2019-04-22
|
44
|
+
### Added
|
45
|
+
- Meta model
|
46
|
+
- Response and Authentication classes
|
47
|
+
|
48
|
+
### Changed
|
49
|
+
- Created a single request method
|
50
|
+
- Allow caller to override all Meta
|
51
|
+
- Made calls consistent in return and call signature
|
10
52
|
|
11
53
|
## [0.1.5] - 2019-04-09
|
12
54
|
### Added
|
@@ -52,7 +94,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
52
94
|
### Added
|
53
95
|
- Initial Release
|
54
96
|
|
55
|
-
[
|
97
|
+
[1.1.0]: https://github.com/WeInfuse/redox/compare/v1.0.2...v1.1.0
|
98
|
+
[1.0.2]: https://github.com/WeInfuse/redox/compare/v1.0.1...v1.0.2
|
99
|
+
[1.0.1]: https://github.com/WeInfuse/redox/compare/v1.0.0...v1.0.1
|
100
|
+
[1.0.0]: https://github.com/WeInfuse/redox/compare/v0.1.6...v1.0.0
|
101
|
+
[0.1.6]: https://github.com/WeInfuse/redox/compare/v0.1.5...v0.1.6
|
56
102
|
[0.1.5]: https://github.com/WeInfuse/redox/compare/v0.1.4...v0.1.5
|
57
103
|
[0.1.4]: https://github.com/WeInfuse/redox/compare/0.1.3...v0.1.4
|
58
104
|
[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
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
data/lib/redox.rb
CHANGED
@@ -1,167 +1,85 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
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'
|
6
|
+
require 'redox/authentication'
|
7
7
|
require 'redox/models/model'
|
8
|
+
require 'redox/models/meta'
|
8
9
|
require 'redox/models/patient'
|
9
|
-
require 'redox/models/demographics'
|
10
|
-
require 'redox/models/
|
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'
|
11
17
|
|
12
18
|
module Redox
|
13
|
-
|
14
|
-
|
15
|
-
# Instantiates a new Redox connection object
|
16
|
-
#
|
17
|
-
# @param [String] api_key API key for the connection
|
18
|
-
# @param [String] secret API secret for the connection
|
19
|
-
# @param [Hash] source source information
|
20
|
-
# @param [Array<Hash>] destinations list of destinations
|
21
|
-
# @param [Boolean] test whether to use test mode
|
22
|
-
# @example
|
23
|
-
# redox = Redox::Redox.new(
|
24
|
-
# api_key: ENV['REDOX_KEY'],
|
25
|
-
# secret: ENV['REDOX_SECRET'],
|
26
|
-
# source: source,
|
27
|
-
# destinations: destinations,
|
28
|
-
# test: true
|
29
|
-
# )
|
30
|
-
def initialize(api_key:, secret:, source:, destinations:, facility_code: nil, test: true)
|
31
|
-
@api_key = api_key
|
32
|
-
@secret = secret
|
33
|
-
@source = source
|
34
|
-
@destinations = destinations
|
35
|
-
@facility_code = facility_code
|
36
|
-
@test = test
|
37
|
-
@connection = nil
|
38
|
-
@access_token = nil
|
39
|
-
end
|
40
|
-
|
41
|
-
# Send NewPatient message
|
42
|
-
#
|
43
|
-
# @param [Hash] patient_params data to send in the Patient JSON object
|
44
|
-
# @return [Hash] parsed response object
|
45
|
-
# @example
|
46
|
-
# Redox::Redox.new(*connection_params).add_patient(
|
47
|
-
# Identifiers: [],
|
48
|
-
# Demographics: {
|
49
|
-
# FirstName: 'Joe'
|
50
|
-
# }
|
51
|
-
# )
|
52
|
-
def add_patient(patient_params)
|
53
|
-
patient_request = Net::HTTP::Post.new('/endpoint', auth_header)
|
54
|
-
request_body = request_meta(
|
55
|
-
data_model: 'PatientAdmin', event_type: 'NewPatient'
|
56
|
-
).merge(Patient: patient_params)
|
57
|
-
patient_request.body = request_body.to_json
|
58
|
-
|
59
|
-
response = connection.request(patient_request)
|
19
|
+
class Configuration
|
20
|
+
attr_accessor :api_key, :secret
|
60
21
|
|
61
|
-
|
22
|
+
def initialize
|
23
|
+
@api_key = nil
|
24
|
+
@secret = nil
|
62
25
|
end
|
63
26
|
|
64
|
-
|
65
|
-
|
66
|
-
# @param [Hash] patient_params data to send in the Patient JSON object
|
67
|
-
# @return [Hash] parsed response object
|
68
|
-
# @example
|
69
|
-
# Redox::Redox.new(*connection_params).update_patient(
|
70
|
-
# Identifiers: [],
|
71
|
-
# Demographics: {
|
72
|
-
# FirstName: 'Joe'
|
73
|
-
# }
|
74
|
-
# )
|
75
|
-
def update_patient(patient_params)
|
76
|
-
patient_request = Net::HTTP::Post.new('/endpoint', auth_header)
|
77
|
-
request_body = request_meta(
|
78
|
-
data_model: 'PatientAdmin', event_type: 'PatientUpdate'
|
79
|
-
).merge(Patient: patient_params)
|
80
|
-
patient_request.body = request_body.to_json
|
81
|
-
|
82
|
-
response = connection.request(patient_request)
|
83
|
-
|
84
|
-
JSON.parse(response.body)
|
27
|
+
def api_endpoint=(endpoint)
|
28
|
+
Connection.base_uri(endpoint.freeze)
|
85
29
|
end
|
86
30
|
|
87
|
-
|
88
|
-
|
89
|
-
# @param [Hash] patient_params data to send in the Patient JSON object
|
90
|
-
# @return [Hash] Redox Patient object
|
91
|
-
# @example
|
92
|
-
# Redox::Redox.new(*connection_params).search_patients(
|
93
|
-
# Identifiers: [],
|
94
|
-
# Demographics: {
|
95
|
-
# FirstName: 'Joe'
|
96
|
-
# }
|
97
|
-
# )
|
98
|
-
def search_patients(patient_params)
|
99
|
-
patient_request = Net::HTTP::Post.new(Models::Patient::SEARCH[:endpoint], auth_header)
|
100
|
-
request_body = request_meta(Models::Patient::SEARCH[:meta])
|
101
|
-
.merge(Patient: patient_params)
|
102
|
-
patient_request.body = request_body.to_json
|
103
|
-
|
104
|
-
response = connection.request(patient_request)
|
105
|
-
|
106
|
-
return Models::Patient.new(JSON.parse(response.body))
|
31
|
+
def api_endpoint
|
32
|
+
return Connection.base_uri
|
107
33
|
end
|
108
34
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
def access_token
|
114
|
-
return @access_token if @access_token
|
115
|
-
|
116
|
-
login_request = Net::HTTP::Post.new(
|
117
|
-
'/auth/authenticate', 'Content-Type' => 'application/json'
|
118
|
-
)
|
119
|
-
login_request.body = { apiKey: api_key, secret: secret }.to_json
|
120
|
-
response = connection.request(login_request)
|
121
|
-
|
122
|
-
if (false == response.is_a?(Net::HTTPOK))
|
123
|
-
raise RedoxException.from_response(response, msg: 'Authentication')
|
124
|
-
end
|
125
|
-
|
126
|
-
body = JSON.parse(response.body)
|
35
|
+
def token_expiry_padding=(time_in_seconds)
|
36
|
+
Authentication.token_expiry_padding = time_in_seconds
|
37
|
+
end
|
127
38
|
|
128
|
-
|
39
|
+
def token_expiry_padding
|
40
|
+
return Authentication.token_expiry_padding
|
129
41
|
end
|
130
42
|
|
131
|
-
def
|
132
|
-
return
|
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
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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]
|
139
57
|
|
140
|
-
|
58
|
+
return self
|
141
59
|
end
|
60
|
+
end
|
142
61
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
'Content-Type' => 'application/json'
|
147
|
-
}
|
62
|
+
class << self
|
63
|
+
def configuration
|
64
|
+
@configuration ||= Configuration.new
|
148
65
|
end
|
149
66
|
|
150
|
-
def
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
EventType: event_type,
|
155
|
-
EventDateTime: nil,
|
156
|
-
Test: test,
|
157
|
-
}
|
158
|
-
}
|
67
|
+
def configure
|
68
|
+
yield(configuration)
|
69
|
+
end
|
70
|
+
end
|
159
71
|
|
160
|
-
|
161
|
-
|
162
|
-
|
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
|
163
79
|
|
164
|
-
|
80
|
+
def release
|
81
|
+
@connection = nil
|
82
|
+
end
|
165
83
|
end
|
166
84
|
end
|
167
85
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Redox
|
2
|
+
class Authentication < Connection
|
3
|
+
attr_accessor :response
|
4
|
+
|
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
|
45
|
+
end
|
46
|
+
|
47
|
+
def access_token
|
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
|
65
|
+
end
|
66
|
+
|
67
|
+
def access_header
|
68
|
+
return {
|
69
|
+
'Authorization' => "Bearer #{self.access_token}",
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def expire!
|
74
|
+
@response = nil
|
75
|
+
end
|
76
|
+
end
|
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
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Redox
|
2
|
+
module Models
|
3
|
+
class Meta < Model
|
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
|
+
|
27
|
+
return self
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_source(name: , id: )
|
31
|
+
self[:Source] = Meta.build_subscription(name: name, id: id)
|
32
|
+
|
33
|
+
return self
|
34
|
+
end
|
35
|
+
|
36
|
+
class << self
|
37
|
+
def build_subscription(name: , id:)
|
38
|
+
return {
|
39
|
+
'ID' => id,
|
40
|
+
'Name' => name
|
41
|
+
}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/redox/models/model.rb
CHANGED
@@ -1,48 +1,59 @@
|
|
1
1
|
module Redox
|
2
2
|
module Models
|
3
|
-
class Model
|
4
|
-
|
3
|
+
class Model < Hashie::Trash
|
4
|
+
include Hashie::Extensions::IgnoreUndeclared
|
5
|
+
include Hashie::Extensions::IndifferentAccess
|
5
6
|
|
6
|
-
|
7
|
-
|
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
|
11
|
-
return
|
29
|
+
def to_h
|
30
|
+
return { key => super.to_h }
|
12
31
|
end
|
13
32
|
|
14
|
-
def
|
15
|
-
|
16
|
-
return @data
|
17
|
-
else
|
18
|
-
return @data[key]
|
19
|
-
end
|
33
|
+
def to_json
|
34
|
+
return self.to_h.to_json
|
20
35
|
end
|
21
36
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
if (true == lambda_result.is_a?(Hash))
|
33
|
-
result = result.merge(lambda_result)
|
34
|
-
else
|
35
|
-
raise "lambda must return hash"
|
36
|
-
end
|
37
|
-
else
|
38
|
-
result[value] = 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
|
39
46
|
end
|
40
47
|
end
|
41
|
-
|
42
|
-
|
48
|
+
|
49
|
+
return model
|
43
50
|
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
44
54
|
|
45
|
-
|
55
|
+
def key
|
56
|
+
return self.class.to_s.split('::').last.to_s
|
46
57
|
end
|
47
58
|
end
|
48
59
|
end
|
data/lib/redox/models/patient.rb
CHANGED
@@ -1,24 +1,50 @@
|
|
1
1
|
module Redox
|
2
2
|
module Models
|
3
3
|
class Patient < Model
|
4
|
-
|
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
|
5
8
|
|
6
|
-
|
9
|
+
alias_method :identifiers, :Identifiers
|
10
|
+
alias_method :insurances, :Insurances
|
7
11
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
15
36
|
|
16
|
-
def
|
17
|
-
|
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
|
18
44
|
|
19
|
-
|
20
|
-
|
21
|
-
|
45
|
+
class << self
|
46
|
+
def query(params, meta: Meta.new)
|
47
|
+
return Redox::Request::PatientSearch.query(params, meta: meta)
|
22
48
|
end
|
23
49
|
end
|
24
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,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,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: p, 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(p, meta))))
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.update(patient: p, 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(p, 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
|
data/lib/redox/version.rb
CHANGED
data/redox.gemspec
CHANGED
@@ -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 = ['
|
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,13 +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.
|
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'
|
30
35
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
31
36
|
spec.add_development_dependency 'rake', '~> 10.0'
|
32
37
|
spec.add_development_dependency 'webmock', '~> 3.1'
|
metadata
CHANGED
@@ -1,29 +1,78 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.0
|
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:
|
12
|
+
date: 2020-06-15 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: '
|
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: '
|
58
|
+
version: '1'
|
59
|
+
- - "<"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: byebug
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '11'
|
69
|
+
type: :development
|
70
|
+
prerelease: false
|
71
|
+
version_requirements: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '11'
|
27
76
|
- !ruby/object:Gem::Dependency
|
28
77
|
name: minitest
|
29
78
|
requirement: !ruby/object:Gem::Requirement
|
@@ -82,31 +131,36 @@ dependencies:
|
|
82
131
|
version: '0.9'
|
83
132
|
description:
|
84
133
|
email:
|
85
|
-
-
|
134
|
+
- alexander.clark@weinfuse.com
|
135
|
+
- mike.crockett@weinfuse.com
|
86
136
|
executables: []
|
87
137
|
extensions: []
|
88
138
|
extra_rdoc_files: []
|
89
139
|
files:
|
90
|
-
- ".circleci/config.yml"
|
91
|
-
- ".editorconfig"
|
92
|
-
- ".gitignore"
|
93
140
|
- CHANGELOG.md
|
94
141
|
- CODE_OF_CONDUCT.md
|
95
142
|
- Gemfile
|
96
143
|
- README.md
|
97
144
|
- Rakefile
|
98
|
-
- bin/console
|
99
|
-
- bin/setup
|
100
145
|
- lib/redox.rb
|
101
|
-
- lib/redox/
|
102
|
-
- lib/redox/
|
146
|
+
- lib/redox/authentication.rb
|
147
|
+
- lib/redox/connection.rb
|
148
|
+
- lib/redox/models/meta.rb
|
103
149
|
- lib/redox/models/model.rb
|
104
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
|
105
156
|
- lib/redox/redox_exception.rb
|
157
|
+
- lib/redox/request/patient_admin.rb
|
158
|
+
- lib/redox/request/patient_search.rb
|
106
159
|
- lib/redox/version.rb
|
107
160
|
- redox.gemspec
|
108
161
|
homepage: https://github.com/WeInfuse/redox
|
109
|
-
licenses:
|
162
|
+
licenses:
|
163
|
+
- MIT
|
110
164
|
metadata:
|
111
165
|
allowed_push_host: https://rubygems.org
|
112
166
|
post_install_message:
|
data/.circleci/config.yml
DELETED
@@ -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
|
-
|
data/.editorconfig
DELETED
data/.gitignore
DELETED
data/bin/console
DELETED
@@ -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