updox 0.12.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd8b2034246435b98b4d29ec70697b0d89d8d2ff6ec802cea01eb8ae70084eed
4
- data.tar.gz: 07ce5cb4a144d0c244b975105795e561e0006e2ec9e355b563cd680355302a4f
3
+ metadata.gz: 1f62aa99da193e378457e56e3a055b4d52973c4cae2bb4944f2e300e51287064
4
+ data.tar.gz: e399c7debeefac7f7608579f056db93cdf3ea24ace47e4173c96adb0d176f87f
5
5
  SHA512:
6
- metadata.gz: da03e1b1cf8aa70cb65e1e91b0147b2680f7e5307695c9ad071dd0f08d546ba122b43c3c5576b40d7699196d2121d0cffa9365822bca4c0b5a77b2def5f4c567
7
- data.tar.gz: 9afd1c083421450366536f88212a27ae2142dafff9c9f5928b9976a2faa3c2896ac7ede4cf18bdc16bc49001804f0ba415f23191d8960f427b3697553a7e805d
6
+ metadata.gz: 3654a26917f7d18de3661921fe72253fbdbc9b7d518f6a9465cde9ee84d5ef65b0ad62e480213618ad676cdf6b74ff6b510bad05e917603c5c2956b69d9c8318
7
+ data.tar.gz: 82f90067272574222de2a8009b49c0109696a626aea6800c0b415e842a17026b1efa75c8f65cddc5e7493d4616163cee0e4df9e12f44a60514488c7eadc4a611
data/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@ 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
+ ## [1.0.0] - [UNRELEASED]
8
+ ### Added
9
+ - Aliases canceled to cancelled
10
+ - Patient#exists?
11
+
12
+ ### Fixed
13
+ - `failure_action = :raise` works better
14
+ - README fix for `failure_action` method
15
+
7
16
  ## [0.12.0] - [2020-02-21]
8
17
  ### Added
9
18
  - Configuration to `raise` on non-success response
@@ -89,7 +98,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
89
98
  ### Added
90
99
  - Initial Release with ability to ping Updox api
91
100
 
92
- [0.12.0]: https://github.com/WeInfuse/updox/compare/v0.11.0...HEAD
101
+ [1.0.0]: https://github.com/WeInfuse/updox/compare/v0.12.0...HEAD
102
+ [0.12.0]: https://github.com/WeInfuse/updox/compare/v0.11.0...v0.12.0
93
103
  [0.11.0]: https://github.com/WeInfuse/updox/compare/v0.10.0...v0.11.0
94
104
  [0.10.0]: https://github.com/WeInfuse/updox/compare/v0.9.0...v0.10.0
95
105
  [0.9.0]: https://github.com/WeInfuse/updox/compare/v0.8.0...v0.9.0
data/README.md CHANGED
@@ -146,9 +146,9 @@ response.practices # Has the practices as Updox::Models::Practice model
146
146
  response.items # Same as practices, always exists on any model if alias is broken
147
147
  response.item # If there is no array, we populate this object
148
148
 
149
- resposne.successful? # Indicates Updox successful indication
150
- resposne.response_code? # Indicates Updox response code
151
- resposne.response_message? # Indicates Updox response message
149
+ response.successful? # Indicates Updox successful indication
150
+ response.response_code? # Indicates Updox response code
151
+ response.response_message? # Indicates Updox response message
152
152
 
153
153
  response.response # Raw HTTParty response is here
154
154
  ```
@@ -159,9 +159,9 @@ response.response # Raw HTTParty response is here
159
159
  Updox.configure do |c|
160
160
  c.application_id = ENV['UPDOX_APP_ID']
161
161
  c.application_password = ENV['UPDOX_APP_PASS']
162
- c.api_endpoint = 'http://hello.com' # Defaults to Updox endpoint
162
+ c.api_endpoint = Updox::Connection::PROD_ENDPOINT # Defaults to Updox QA endpoint
163
163
  c.parse_responses = false # Defaults to true
164
- c.failure_response = :raise # Defaults to do nothing and allows lambdas
164
+ c.failure_action = :raise # Defaults to do nothing and allows lambdas
165
165
  end
166
166
  ```
167
167
 
data/lib/updox.rb CHANGED
@@ -4,6 +4,8 @@ require 'updox/version'
4
4
  require 'updox/updox_exception'
5
5
  require 'updox/connection'
6
6
  require 'updox/models/model'
7
+ require 'updox/models/extensions/exists'
8
+ require 'updox/models/extensions/sync'
7
9
  require 'updox/models/auth'
8
10
  require 'updox/models/application'
9
11
  require 'updox/models/appointment'
@@ -11,6 +13,7 @@ require 'updox/models/appointment_status'
11
13
  require 'updox/models/calendar'
12
14
  require 'updox/models/location'
13
15
  require 'updox/models/patient'
16
+ require 'updox/models/patient_message'
14
17
  require 'updox/models/practice'
15
18
  require 'updox/models/reminder'
16
19
  require 'updox/models/status'
@@ -1,11 +1,13 @@
1
1
  module Updox
2
2
  class Connection
3
- TEST_HOST = 'updoxqa.com'
4
- PROD_HOST = 'xxxxxxx.com'
3
+ URI_BUILDER = ->(host) { "https://#{host}/api/io/".freeze }
4
+
5
+ QA_ENDPOINT = URI_BUILDER.call('updoxqa.com')
6
+ PROD_ENDPOINT = URI_BUILDER.call('myupdox.com')
5
7
 
6
8
  include HTTParty
7
9
 
8
- base_uri "https://#{TEST_HOST}/api/io/".freeze
10
+ base_uri QA_ENDPOINT
9
11
 
10
12
  headers 'Content-Type' => 'application/json'
11
13
 
@@ -0,0 +1,60 @@
1
+ module Updox
2
+ ERROR_CODES = {
3
+ "2000"=>"OK",
4
+ "4000"=>"Bad Request",
5
+ "4010"=>"Unauthorized",
6
+ "4011"=>"Unauthorized [Practice does not exist or is inactive]",
7
+ "4012"=>"Unauthorized [User does not exist or is inactive]",
8
+ "4060"=>"A validation error in the request. For example not including a required field, an invalid e-mail address, too long of a value, etc. A list of the errors is included in the message.",
9
+ "5000"=>"an unknown error has occurred",
10
+ "5100"=>"an unknown server error has occurred",
11
+ "5110"=>"an unknown server error has occurred",
12
+ "4130"=>"account already exists",
13
+ "4110"=>"no practice ID",
14
+ "4160"=>"direct domain is invalid",
15
+ "4621"=>"direct address error: domain does not match the direct domain for this vendor",
16
+ "4150"=>"direct domain is already taken",
17
+ "4163"=>"direct domain is unavailable",
18
+ "4610"=>"direct address error: direct address is taken",
19
+ "4161"=>"web address is invalid",
20
+ "4131"=>"account does not exist",
21
+ "4140"=>"web address is already taken",
22
+ "4230"=>"user already exists",
23
+ "4210"=>"no user ID",
24
+ "4241"=>"invalid user ID, user IDs starting with '@' are reserved for practice users",
25
+ "4251"=>"invalid NPI",
26
+ "4252"=>"invalid taxonomy code",
27
+ "4630"=>"direct address error: account does not have a direct domain configured",
28
+ "4232"=>"user password is required",
29
+ "4240"=>"user does not exist, use practice methods instead",
30
+ "4231"=>"user does not exist",
31
+ "4641"=>"direct address error: sending user does not have a direct address configured",
32
+ "4642"=>"direct address error: identity verification required to send to this address",
33
+ "4640"=>"direct address error: invalid direct address",
34
+ "4650"=>"direct error: send failed",
35
+ "4651"=>"direct error: send failed and/or invalid direct address",
36
+ "4430"=>"message type does not have any MDNs",
37
+ "4410"=>"message not found",
38
+ "4652"=>"direct error: either from or patientDemographics is required",
39
+ "4071"=>"Recipient not found",
40
+ "4070"=>"Invalid recipient",
41
+ "4831"=>"portal account does not exist",
42
+ "4830"=>"portal account already exists",
43
+ "4832"=>"patient has opted out of portal communications",
44
+ "4731"=>"patient account does not exist",
45
+ "4960"=>"image not found",
46
+ "4331"=>"contact does not exist",
47
+ "4931"=>"you sent zero bulk faxes with this bulkFaxId",
48
+ "4021"=>"Invalid date format",
49
+ "4930"=>"no fax found for this ID",
50
+ "4932"=>"fax number does not appear to be available",
51
+ "4933"=>"invalid fax number",
52
+ "4330"=>"contact already exists",
53
+ "6212"=>"at least one id must be specified for the request",
54
+ "4162"=>"ip is invalid",
55
+ "4165"=>"port is invalid",
56
+ "6210"=>"at least one value must be provided",
57
+ "6213"=>"record does not exist for ID",
58
+ "9010"=>"the date format must be in the format is yyyy-MM-dd"
59
+ }
60
+ end
@@ -1,6 +1,8 @@
1
1
  module Updox
2
2
  module Models
3
3
  class Appointment < Model
4
+ extend Updox::Models::Extensions::Sync
5
+
4
6
  SYNC_ENDPOINT = '/AppointmentsSync'.freeze
5
7
 
6
8
  SYNC_LIST_TYPE = 'appointments'.freeze
@@ -14,8 +16,8 @@ module Updox
14
16
  property :typeId, from: :type_id
15
17
  property :summary
16
18
  property :details
17
- property :blocked, required: true, transform_with: ->(v) { true == v }, default: false
18
- property :cancelled, required: true, transform_with: ->(v) { true == v }, default: false
19
+ property :blocked, required: true, default: false
20
+ property :cancelled, required: true, from: :canceled, default: false
19
21
  property :locationId, from: :location_id
20
22
  property :reminderTokens, from: :reminder_tokens
21
23
 
@@ -25,6 +27,7 @@ module Updox
25
27
  alias_method :type_id, :typeId
26
28
  alias_method :location_id, :locationId
27
29
  alias_method :reminder_tokens, :reminderTokens
30
+ alias_method :canceled, :cancelled
28
31
 
29
32
  def to_h
30
33
  result = super.to_h
@@ -1,6 +1,8 @@
1
1
  module Updox
2
2
  module Models
3
3
  class AppointmentStatus < Model
4
+ extend Updox::Models::Extensions::Exists
5
+
4
6
  LIST_ENDPOINT = '/AppointmentStatusesGetByIds'.freeze
5
7
 
6
8
  LIST_TYPE = 'appointmentStatuses'
@@ -1,6 +1,8 @@
1
1
  module Updox
2
2
  module Models
3
3
  class Calendar < Model
4
+ extend Updox::Models::Extensions::Exists
5
+
4
6
  SYNC_ENDPOINT = '/CalendarsSync'.freeze
5
7
  LIST_ENDPOINT = '/PracticeCalendarsRetrieve'.freeze
6
8
 
@@ -0,0 +1,17 @@
1
+ module Updox
2
+ module Models
3
+ module Extensions
4
+ module Exists
5
+ def exists?(item_id, account_id: , cached_query: nil)
6
+ raise UpdoxException.new('Not implemented on this model.') unless self.respond_to?(:find)
7
+ opts = { account_id: account_id }
8
+ opts[:cached_query] = cached_query unless cached_query.nil?
9
+
10
+ response = self.find(item_id, **opts)
11
+
12
+ false == response.nil?
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ module Updox
2
+ module Models
3
+ module Extensions
4
+ module Sync
5
+ RECOMMENDED_BATCH_SIZE = 200
6
+
7
+ def sync(items, account_id: , batch_size: RECOMMENDED_BATCH_SIZE, endpoint: self.const_get(:SYNC_ENDPOINT))
8
+ response = nil
9
+ list_type = self.const_get(:SYNC_LIST_TYPE)
10
+
11
+ if 0 >= batch_size
12
+ response = request(endpoint: endpoint, body: { list_type => items }, auth: {accountId: account_id}, required_auths: Updox::Models::Auth::AUTH_ACCT)
13
+ else
14
+ items.each_slice(batch_size) do |batch|
15
+ r = request(endpoint: endpoint, body: { list_type => batch }, auth: {accountId: account_id}, required_auths: Updox::Models::Auth::AUTH_ACCT)
16
+
17
+ return r unless r.successful?
18
+
19
+ if response
20
+ response.items += r.items
21
+ else
22
+ response = r
23
+ end
24
+ end
25
+ end
26
+
27
+ return response
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -1,6 +1,9 @@
1
1
  module Updox
2
2
  module Models
3
3
  class Location < Model
4
+ extend Updox::Models::Extensions::Exists
5
+ extend Updox::Models::Extensions::Sync
6
+
4
7
  SYNC_ENDPOINT = '/LocationsSync'.freeze
5
8
  LIST_ENDPOINT = '/PracticeLocationsRetrieve'.freeze
6
9
 
@@ -1,9 +1,7 @@
1
1
  module Updox
2
2
  module Models
3
3
  DATETIME_FORMAT = '%Y-%m-%d %H:%M'.freeze
4
- DATETIME_OTHER_FORMAT = '%m/%d/%Y %H:%M:%s %z'.freeze
5
-
6
- RECOMMENDED_BATCH_SIZE = 200
4
+ DATETIME_TZ_FORMAT = '%m/%d/%Y %H:%M:%s %z'.freeze
7
5
 
8
6
  class Model < Hashie::Trash
9
7
  include Hashie::Extensions::IgnoreUndeclared
@@ -33,39 +31,6 @@ module Updox
33
31
  "#{response_code}: #{response_message}"
34
32
  end
35
33
 
36
- def self.exists?(item_id, account_id: , cached_query: nil)
37
- raise UpdoxException.new('Not implemented on this model.') unless self.respond_to?(:find)
38
- opts = { account_id: account_id }
39
- opts[:cached_query] = cached_query unless cached_query.nil?
40
-
41
- response = self.find(item_id, **opts)
42
-
43
- false == response.nil? && (false == self.const_defined?(:FIND_ENDPOINT) || response.successful?)
44
- end
45
-
46
- def self.sync(items, account_id: , batch_size: RECOMMENDED_BATCH_SIZE, endpoint: self.const_get(:SYNC_ENDPOINT))
47
- response = nil
48
- list_type = self.const_get(:SYNC_LIST_TYPE)
49
-
50
- if 0 >= batch_size
51
- response = request(endpoint: endpoint, body: { list_type => items }, auth: {accountId: account_id}, required_auths: Updox::Models::Auth::AUTH_ACCT)
52
- else
53
- items.each_slice(batch_size) do |batch|
54
- r = request(endpoint: endpoint, body: { list_type => batch }, auth: {accountId: account_id}, required_auths: Updox::Models::Auth::AUTH_ACCT)
55
-
56
- return r unless r.successful?
57
-
58
- if response
59
- response.items += r.items
60
- else
61
- response = r
62
- end
63
- end
64
- end
65
-
66
- return response
67
- end
68
-
69
34
  def self.request(**kwargs)
70
35
  from_response(UpdoxClient.connection.request(kwargs))
71
36
  end
@@ -88,15 +53,15 @@ module Updox
88
53
  model.item = klazz.new(data.dig(klazz.const_get(:ITEM_TYPE)))
89
54
  model.define_singleton_method(klazz.const_get(:ITEM_TYPE)) { self.item }
90
55
  else
91
- k = data&.keys&.find {|k| k.to_s.downcase.end_with?('statuses') }
92
- c = 'Updox::Models::' + k[0..-3].capitalize if k
56
+ status_key = data&.keys&.find {|k| k.to_s.downcase.end_with?('statuses') }
57
+ status_class = 'Updox::Models::' + status_key[0..-3].capitalize if status_key
93
58
 
94
- if k.nil? || false == Module.const_defined?(c)
59
+ if status_key.nil? || false == Module.const_defined?(status_class)
95
60
  model.items = [data]
96
61
  else
97
- statuses = data.delete(k)
62
+ statuses = data.delete(status_key)
98
63
 
99
- model.items = statuses.map {|status| Object.const_get(c).new(status) }
64
+ model.items = statuses.map {|status| Object.const_get(status_class).new(status) }
100
65
  model.define_singleton_method(:statuses) { self.items }
101
66
  end
102
67
 
@@ -1,6 +1,8 @@
1
1
  module Updox
2
2
  module Models
3
3
  class Patient < Model
4
+ extend Updox::Models::Extensions::Sync
5
+
4
6
  SYNC_ENDPOINT = '/PatientsSync'.freeze
5
7
  SYNC_LIST_TYPE = 'patients'.freeze
6
8
 
@@ -33,7 +35,7 @@ module Updox
33
35
  end
34
36
 
35
37
  def self.exists?(patient_id, account_id: )
36
- request(endpoint: MESSAGE_COUNT_ENDPOINT, body: { patientId: patient_id }, auth: {accountId: account_id}, required_auths: Updox::Models::Auth::AUTH_ACCT).successful?
38
+ Updox::Models::PatientMessage.exists?(patient_id, account_id: account_id)
37
39
  end
38
40
  end
39
41
  end
@@ -0,0 +1,15 @@
1
+ module Updox
2
+ module Models
3
+ class PatientMessage < Model
4
+ LIST_ENDPOINT = '/PatientMessageCountSince'.freeze
5
+
6
+ def self.query(patient_id, account_id: )
7
+ request(endpoint: LIST_ENDPOINT, body: { patientId: patient_id }, auth: {accountId: account_id}, required_auths: Updox::Models::Auth::AUTH_ACCT)
8
+ end
9
+
10
+ def self.exists?(patient_id, account_id: )
11
+ request(endpoint: LIST_ENDPOINT, body: { patientId: patient_id }, auth: {accountId: account_id}, required_auths: Updox::Models::Auth::AUTH_ACCT).successful?
12
+ end
13
+ end
14
+ end
15
+ end
@@ -40,11 +40,17 @@ module Updox
40
40
  end
41
41
 
42
42
  def self.exists?(account_id)
43
- self.find(account_id).successful?
43
+ false == self.find(account_id).nil?
44
44
  end
45
45
 
46
46
  def self.find(account_id)
47
- request(endpoint: FIND_ENDPOINT, body: {accountId: account_id}, required_auths: Updox::Models::Auth::AUTH_APP)
47
+ response = request(endpoint: FIND_ENDPOINT, body: {accountId: account_id}, required_auths: Updox::Models::Auth::AUTH_APP)
48
+
49
+ if response.successful?
50
+ response
51
+ else
52
+ nil
53
+ end
48
54
  end
49
55
 
50
56
  def self.query
@@ -3,7 +3,7 @@ module Updox
3
3
  class Reminder < Model
4
4
  property :reminderId
5
5
  property :reminderStatus
6
- property :reminderStatusDate, transform_with: ->(v) { DateTime.strptime(v, DATETIME_OTHER_FORMAT) unless v.nil? || v.empty? }
6
+ property :reminderStatusDate, transform_with: ->(v) { DateTime.strptime(v, DATETIME_TZ_FORMAT) unless v.nil? || v.empty? }
7
7
  property :reminderType
8
8
 
9
9
  alias_method :reminder_id, :reminderId
@@ -1,6 +1,8 @@
1
1
  module Updox
2
2
  module Models
3
3
  class User < Model
4
+ extend Updox::Models::Extensions::Exists
5
+
4
6
  SAVE_ENDPOINT = '/UserSave'.freeze
5
7
  QUERY_ENDPOINT = '/UserList'.freeze
6
8
  FIND_ENDPOINT = '/UserGet'.freeze
@@ -45,7 +47,13 @@ module Updox
45
47
  end
46
48
 
47
49
  def self.find(user_id, account_id: )
48
- request(endpoint: FIND_ENDPOINT, account_id: account_id, body: { userId: user_id}, required_auths: Updox::Models::Auth::AUTH_ACCT)
50
+ response = request(endpoint: FIND_ENDPOINT, account_id: account_id, body: { userId: user_id}, required_auths: Updox::Models::Auth::AUTH_ACCT)
51
+
52
+ if response.successful?
53
+ response
54
+ else
55
+ nil
56
+ end
49
57
  end
50
58
 
51
59
  def self.query
data/lib/updox/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Updox
2
- VERSION = '0.12.0'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: updox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Crockett
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-02-21 00:00:00.000000000 Z
11
+ date: 2020-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -142,14 +142,18 @@ files:
142
142
  - Rakefile
143
143
  - lib/updox.rb
144
144
  - lib/updox/connection.rb
145
+ - lib/updox/error_message.rb
145
146
  - lib/updox/models/application.rb
146
147
  - lib/updox/models/appointment.rb
147
148
  - lib/updox/models/appointment_status.rb
148
149
  - lib/updox/models/auth.rb
149
150
  - lib/updox/models/calendar.rb
151
+ - lib/updox/models/extensions/exists.rb
152
+ - lib/updox/models/extensions/sync.rb
150
153
  - lib/updox/models/location.rb
151
154
  - lib/updox/models/model.rb
152
155
  - lib/updox/models/patient.rb
156
+ - lib/updox/models/patient_message.rb
153
157
  - lib/updox/models/practice.rb
154
158
  - lib/updox/models/reminder.rb
155
159
  - lib/updox/models/status.rb