redox 0.1.6 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +15 -2
- data/README.md +80 -24
- data/lib/redox.rb +53 -131
- data/lib/redox/authentication.rb +64 -6
- data/lib/redox/connection.rb +28 -0
- data/lib/redox/models/meta.rb +25 -59
- data/lib/redox/models/model.rb +39 -13
- data/lib/redox/models/patient.rb +54 -34
- 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/version.rb +1 -1
- data/redox.gemspec +2 -0
- metadata +35 -4
- 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: 63503f81ebcb62da585b095cbe53721f14fd4924b6b7f292db34dc28a1fb58a0
|
4
|
+
data.tar.gz: d79801d7d642ada1dd96952fb00882c858a06b6b3a165e9aa634624cd8580872
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc2504239a0515d8d951a7d0d181a260ca7719130fd0fffc40d309cf8938c46ebce2d1c402a1864e019d689836f5988857608d6e19c18326f7d00dcc180985a5
|
7
|
+
data.tar.gz: cf26db2a8ee7d9379c01f2af44aa9b25c2b67a6d6b5fc8d09faa5d449dcfb89b6d8ef32e22cebb2f0dda1b68238f0982103a08e4d5d8accbb5635682f73532bd
|
data/CHANGELOG.md
CHANGED
@@ -4,7 +4,19 @@ 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.
|
7
|
+
## [1.0.0] - Unreleased
|
8
|
+
### Changed
|
9
|
+
- How it works
|
10
|
+
|
11
|
+
### Added
|
12
|
+
- Connection, RedoxClient, Authorization
|
13
|
+
- Global configuration block
|
14
|
+
- Gems httparty, hashie
|
15
|
+
|
16
|
+
### Removed
|
17
|
+
- Identifiers, Demographics
|
18
|
+
|
19
|
+
## [0.1.6] - 2019-04-22
|
8
20
|
### Added
|
9
21
|
- Meta model
|
10
22
|
- Response and Authentication classes
|
@@ -58,7 +70,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
58
70
|
### Added
|
59
71
|
- Initial Release
|
60
72
|
|
61
|
-
[Unreleased]: https://github.com/WeInfuse/redox/compare/v0.1.
|
73
|
+
[Unreleased]: https://github.com/WeInfuse/redox/compare/v0.1.6...HEAD
|
74
|
+
[0.1.6]: https://github.com/WeInfuse/redox/compare/v0.1.5...v0.1.6
|
62
75
|
[0.1.5]: https://github.com/WeInfuse/redox/compare/v0.1.4...v0.1.5
|
63
76
|
[0.1.4]: https://github.com/WeInfuse/redox/compare/0.1.3...v0.1.4
|
64
77
|
[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,160 +1,82 @@
|
|
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'
|
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/
|
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
14
|
|
15
15
|
module Redox
|
16
|
-
|
17
|
-
|
18
|
-
DEFAULT_URI = 'https://api.redoxengine.com/'.freeze
|
16
|
+
class Configuration
|
17
|
+
attr_accessor :api_key, :secret
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
19
|
+
def initialize
|
20
|
+
@api_key = nil
|
21
|
+
@secret = nil
|
46
22
|
end
|
47
23
|
|
48
|
-
|
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
|
-
)
|
24
|
+
def api_endpoint=(endpoint)
|
25
|
+
Connection.base_uri(endpoint.freeze)
|
68
26
|
end
|
69
27
|
|
70
|
-
|
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
|
-
)
|
28
|
+
def api_endpoint
|
29
|
+
return Connection.base_uri
|
90
30
|
end
|
91
31
|
|
92
|
-
|
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
|
-
)
|
32
|
+
def token_expiry_padding=(time_in_seconds)
|
33
|
+
Authentication.token_expiry_padding = time_in_seconds
|
112
34
|
end
|
113
35
|
|
114
|
-
|
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)
|
36
|
+
def token_expiry_padding
|
37
|
+
return Authentication.token_expiry_padding
|
129
38
|
end
|
130
39
|
|
131
|
-
def
|
132
|
-
return
|
40
|
+
def to_h
|
41
|
+
return {
|
42
|
+
api_key: @api_key,
|
43
|
+
secret: @secret,
|
44
|
+
api_endpoint: api_endpoint,
|
45
|
+
token_expiry_padding: token_expiry_padding
|
46
|
+
}
|
47
|
+
end
|
133
48
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
)
|
49
|
+
def from_h(h)
|
50
|
+
self.api_key = h[:api_key]
|
51
|
+
self.secret = h[:secret]
|
52
|
+
self.api_endpoint = h[:api_endpoint]
|
53
|
+
self.token_expiry_padding = h[:token_expiry_padding]
|
140
54
|
|
141
|
-
|
142
|
-
|
143
|
-
|
55
|
+
return self
|
56
|
+
end
|
57
|
+
end
|
144
58
|
|
145
|
-
|
59
|
+
class << self
|
60
|
+
def configuration
|
61
|
+
@configuration ||= Configuration.new
|
146
62
|
end
|
147
63
|
|
148
|
-
def
|
149
|
-
|
64
|
+
def configure
|
65
|
+
yield(configuration)
|
66
|
+
end
|
67
|
+
end
|
150
68
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
69
|
+
# Redox API client
|
70
|
+
class RedoxClient
|
71
|
+
class << self
|
72
|
+
def connection
|
73
|
+
Redox.configuration.token_expiry_padding = 60 if Redox.configuration.token_expiry_padding.nil?
|
74
|
+
@connection ||= Connection.new
|
75
|
+
end
|
156
76
|
|
157
|
-
|
77
|
+
def release
|
78
|
+
@connection = nil
|
79
|
+
end
|
158
80
|
end
|
159
81
|
end
|
160
82
|
end
|
data/lib/redox/authentication.rb
CHANGED
@@ -1,19 +1,77 @@
|
|
1
1
|
module Redox
|
2
|
-
class Authentication
|
3
|
-
|
2
|
+
class Authentication < Connection
|
3
|
+
attr_accessor :response
|
4
4
|
|
5
|
-
|
6
|
-
|
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 @
|
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
|
data/lib/redox/models/meta.rb
CHANGED
@@ -1,79 +1,45 @@
|
|
1
1
|
module Redox
|
2
2
|
module Models
|
3
3
|
class Meta < Model
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
self
|
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
|
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
|
data/lib/redox/models/model.rb
CHANGED
@@ -1,27 +1,53 @@
|
|
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 :response, required: false
|
10
|
+
|
11
|
+
alias_method :patient, :Patient
|
12
|
+
alias_method :meta, :Meta
|
13
|
+
|
14
|
+
def initialize(data = {})
|
15
|
+
if (data.is_a?(Hash) && data.include?(key))
|
16
|
+
data = data[key]
|
17
|
+
end
|
18
|
+
|
19
|
+
super(data)
|
8
20
|
end
|
9
21
|
|
10
|
-
def
|
11
|
-
return
|
22
|
+
def to_h
|
23
|
+
return {"#{key}" => super.to_h}
|
12
24
|
end
|
13
25
|
|
14
|
-
def
|
15
|
-
return self.
|
26
|
+
def to_json
|
27
|
+
return self.to_h.to_json
|
16
28
|
end
|
17
29
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
30
|
+
class << self
|
31
|
+
def from_response(response)
|
32
|
+
model = Model.new
|
33
|
+
model.response = response
|
34
|
+
|
35
|
+
%w[Meta Patient].each do |k|
|
36
|
+
begin
|
37
|
+
model.send("#{k}=", Module.const_get("Redox::Models::#{k}").new(response[k])) if response[k]
|
38
|
+
rescue
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
return model
|
23
43
|
end
|
24
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def key
|
49
|
+
return self.class.to_s.split('::').last
|
50
|
+
end
|
25
51
|
end
|
26
52
|
end
|
27
53
|
end
|
data/lib/redox/models/patient.rb
CHANGED
@@ -1,40 +1,60 @@
|
|
1
1
|
module Redox
|
2
2
|
module Models
|
3
3
|
class Patient < Model
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
4
|
+
QUERY_ENDPOINT = '/query'.freeze
|
5
|
+
QUERY_META = Meta.new(EventType: 'Query', DataModel: 'PatientSearch')
|
6
|
+
CREATE_META = Meta.new(EventType: 'NewPatient', DataModel: 'PatientAdmin')
|
7
|
+
UPDATE_META = Meta.new(EventType: 'PatientUpdate', DataModel: 'PatientAdmin')
|
8
|
+
|
9
|
+
property :Identifiers, from: :identifiers, required: false, default: []
|
10
|
+
property :Insurances, from: :insurances, required: false, default: []
|
11
|
+
property :Demographics, from: :demographics, required: false
|
12
|
+
property :PCP, from: :primary_care_provider, required: false
|
13
|
+
|
14
|
+
alias_method :identifiers, :Identifiers
|
15
|
+
alias_method :insurances, :Insurances
|
16
|
+
|
17
|
+
def demographics
|
18
|
+
self[:Demographics] = Demographics.new(self[:Demographics]) unless self[:Demographics].is_a?(Redox::Models::Demographics)
|
19
|
+
self[:Demographics] ||= Demographics.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def primary_care_provider
|
23
|
+
self[:PCP] ||= PCP.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_identifier(type: , value: )
|
27
|
+
self[:Identifiers] << Identifier.new({'ID' => value, 'IDType' => type})
|
28
|
+
|
29
|
+
return self
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_insurance(data = {})
|
33
|
+
self[:Insurances] << Insurance.new(data)
|
34
|
+
|
35
|
+
return self
|
36
|
+
end
|
37
|
+
|
38
|
+
def update(meta: Meta.new)
|
39
|
+
meta = UPDATE_META.merge(meta)
|
40
|
+
return Model.from_response((RedoxClient.connection.request(body: Patient.body(self, meta))))
|
41
|
+
end
|
42
|
+
|
43
|
+
def create(meta: Meta.new)
|
44
|
+
meta = CREATE_META.merge(meta)
|
45
|
+
return Model.from_response((RedoxClient.connection.request(body: Patient.body(self, meta))))
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
def query(params, meta: Meta.new)
|
50
|
+
meta = QUERY_META.merge(meta)
|
51
|
+
return Model.from_response((RedoxClient.connection.request(endpoint: QUERY_ENDPOINT, body: Patient.body(params, meta))))
|
52
|
+
end
|
53
|
+
|
54
|
+
def body(params, meta)
|
55
|
+
meta = Meta.new.merge(meta)
|
56
|
+
|
57
|
+
return meta.to_h.merge(params.to_h)
|
38
58
|
end
|
39
59
|
end
|
40
60
|
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
|
data/lib/redox/version.rb
CHANGED
data/redox.gemspec
CHANGED
@@ -26,6 +26,8 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
27
|
spec.require_paths = ['lib']
|
28
28
|
|
29
|
+
spec.add_dependency 'httparty'
|
30
|
+
spec.add_dependency 'hashie'
|
29
31
|
spec.add_development_dependency 'bundler'
|
30
32
|
spec.add_development_dependency 'byebug'
|
31
33
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Clark
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hashie
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
13
41
|
- !ruby/object:Gem::Dependency
|
14
42
|
name: bundler
|
15
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -113,11 +141,14 @@ files:
|
|
113
141
|
- bin/setup
|
114
142
|
- lib/redox.rb
|
115
143
|
- lib/redox/authentication.rb
|
116
|
-
- lib/redox/
|
117
|
-
- lib/redox/models/identifiers.rb
|
144
|
+
- lib/redox/connection.rb
|
118
145
|
- lib/redox/models/meta.rb
|
119
146
|
- lib/redox/models/model.rb
|
120
147
|
- lib/redox/models/patient.rb
|
148
|
+
- lib/redox/models/patient/demographics.rb
|
149
|
+
- lib/redox/models/patient/identifier.rb
|
150
|
+
- lib/redox/models/patient/insurance.rb
|
151
|
+
- lib/redox/models/patient/p_c_p.rb
|
121
152
|
- lib/redox/redox_exception.rb
|
122
153
|
- lib/redox/response.rb
|
123
154
|
- lib/redox/version.rb
|