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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6ab25d3f19478659e8b289237cfc384ac214d2ac2fe880a4e5ea324b16488e0
4
- data.tar.gz: 035f903ba8152429b06c1ab2e1a6a17bc7639974bd483440448a391bab7c7763
3
+ metadata.gz: 451221082b696c7421fa2feacde94c0235bbd78348c416d904cba8df3d1ff67b
4
+ data.tar.gz: 9934ade2a99d85628444a8845b15bf14c79cb595f1307da196d57d1faa2a2668
5
5
  SHA512:
6
- metadata.gz: de4c1669a46c1cc4257d84ae12a8a3243679bf6d264e58383519a57cc405ab71fa870d098903b92edd322a672f6901481e9e824d259c6f1d86e8223d642f25e7
7
- data.tar.gz: e98d7dfdfd023b845dcffadfcf46e17f8e21d2f1357f88cc0e0454cb377d2f7e6dad179a9c206f75be9432630cc6ccfcb6ec6ab6d73da8e06f73f43657e88de4
6
+ metadata.gz: 192db714b76ee2a5d197577e21c2907f50d211667b1d16f7ee468af71196655da67fc593771e1f713419bc5a382e8b196b315660dba62c4563ee553bc9581e8d
7
+ data.tar.gz: 2f72e880e360b4d74e6b8b27b25baf0f9a4bb867615723afa9c40089d1a4debaf42c96aa6ee5997f2bc432d315bcbd6c02d9612c9f73aa096dffed1e6cb18cb9
@@ -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
- ## [Unreleased]
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
- - <TBD>
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
- [Unreleased]: https://github.com/WeInfuse/redox/compare/v0.1.5...HEAD
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
- 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,167 +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'
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/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'
11
17
 
12
18
  module Redox
13
- # Redox API client
14
- class Redox
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
- JSON.parse(response.body)
22
+ def initialize
23
+ @api_key = nil
24
+ @secret = nil
62
25
  end
63
26
 
64
- # Send PatientUpdate message
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
- # Send PatientSearch query
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
- private
110
-
111
- attr_reader :api_key, :secret, :source, :destinations, :facility_code, :test
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
- @access_token = body['accessToken']
39
+ def token_expiry_padding
40
+ return Authentication.token_expiry_padding
129
41
  end
130
42
 
131
- def connection
132
- return @connection if @connection
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
- uri = URI.parse('https://api.redoxengine.com/')
135
- http = Net::HTTP.new(uri.host, uri.port)
136
- http.use_ssl = true
137
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
138
- http.verify_depth = 5
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
- @connection = http
58
+ return self
141
59
  end
60
+ end
142
61
 
143
- def auth_header
144
- {
145
- 'Authorization' => "Bearer #{access_token}",
146
- 'Content-Type' => 'application/json'
147
- }
62
+ class << self
63
+ def configuration
64
+ @configuration ||= Configuration.new
148
65
  end
149
66
 
150
- def request_meta(data_model:, event_type:)
151
- meta_object = {
152
- Meta: {
153
- DataModel: data_model,
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
- meta_object[:Meta][:FacilityCode] = facility_code if facility_code
161
- meta_object[:Meta][:Source] = source if source
162
- meta_object[:Meta][:Destinations] = destinations if destinations && !destinations.empty?
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
- meta_object
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
@@ -1,48 +1,59 @@
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(key: self.class::KEY)
15
- if key.nil?
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
- def map(mapper: {}, data: self.raw)
23
- result = {}
24
-
25
- if (true == mapper.is_a?(Hash))
26
- mapper.each do |key, value|
27
- if (true == value.is_a?(Hash))
28
- result = result.merge(self.map(data: data[key], mapper: value))
29
- elsif (true == value.respond_to?(:call))
30
- lambda_result = value.call(data[key])
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
- else
42
- raise "mapper must be a hash, got '#{mapper}'"
48
+
49
+ return model
43
50
  end
51
+ end
52
+
53
+ private
44
54
 
45
- return result
55
+ def key
56
+ return self.class.to_s.split('::').last.to_s
46
57
  end
47
58
  end
48
59
  end
@@ -1,24 +1,50 @@
1
1
  module Redox
2
2
  module Models
3
3
  class Patient < Model
4
- attr_reader :demographics, :identifiers
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
- KEY = 'Patient'
9
+ alias_method :identifiers, :Identifiers
10
+ alias_method :insurances, :Insurances
7
11
 
8
- SEARCH = {
9
- meta: {
10
- data_model: 'PatientSearch',
11
- event_type: 'Query'
12
- },
13
- endpoint: '/query'
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 initialize(data)
17
- super(data)
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
- if (self.valid?)
20
- @demographics = Demographics.new(self.raw)
21
- @identifiers = Identifiers.new(self.raw)
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,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: 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
@@ -1,3 +1,3 @@
1
1
  module Redox
2
- VERSION = '0.1.5'.freeze
2
+ VERSION = '1.1.0'.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,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.add_development_dependency 'bundler'
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: 0.1.5
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: 2019-04-09 00:00:00.000000000 Z
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: '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'
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
- - sasha.jackal@gmail.com
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/models/demographics.rb
102
- - lib/redox/models/identifiers.rb
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:
@@ -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'
5
- end
6
- end
7
- end
@@ -1,7 +0,0 @@
1
- module Redox
2
- module Models
3
- class Identifiers < Model
4
- KEY = 'Identifiers'
5
- end
6
- end
7
- end