vng 1.1.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1356553075599aa2888d10740b02d282d6f6407c69bf49f67e0dbdc46475cebc
4
- data.tar.gz: a8d09b9454c4fe51de636f61a880614eca6d12e9fc8455e5fc3888f324eaab9c
3
+ metadata.gz: d55841e2ab8e3e620c5bd29d8c994cbbb441a327ab3006ee262c3c44f207fda1
4
+ data.tar.gz: d4fb1cd2865d72faa464711cd03d61974a991d53e766310523ee5adc0353ba1e
5
5
  SHA512:
6
- metadata.gz: 273b479db2901d89fbdd880383cdcf212aaffcfd1637ca973464567b33b98eafeb2036a6e7e46357d6e7aadc87d70876733bc7094c7c727a0e04118f0b8772fe
7
- data.tar.gz: '088ea1b5e63a121b23f956b533d34b3adcf5a570851d999e583197134ae5af69b8345e9ff4946d15183723e031c87015dae8b112e1bf30edc2a2d683b3ca8ee1'
6
+ metadata.gz: f118bbfc089a69e924fdcc0948de07dbb20217d4b5556a0e80abea896734f545199f27afdf1edf7c6d1c3ffec2ee9a6a04497a7629527e1623c44ba5ea75e894
7
+ data.tar.gz: fce28eb9405e05bc3620e67a53942ae901ec0f655dca7e640755ac231c975b262329596ec5dbd6a5e0dfa6180ebd5b2edc9d95503b3e8f09db0f670c97618920
data/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
- ## [Unreleased]
1
+ ## [Unreleased] -
2
+
3
+ ## [1.3] - 2024-11-21
4
+
5
+ - Adds MockRequest which can be set with VNG_MOCK=1
6
+
7
+ ## [1.2] - 2024-11-20
8
+
9
+ - Adds WorkOrder#url and Case#url
2
10
 
3
11
  ## [1.1] - 2024-11-20
4
12
 
data/README.md CHANGED
@@ -84,7 +84,14 @@ To run tests:
84
84
  rspec
85
85
  ```
86
86
 
87
- Set `VNG_MOCK=1` to test against HTTP mocks.
87
+ By default, tests are run with real HTTP calls to Vonigo that must be
88
+ set with the environment variables specified above.
89
+
90
+ If you do not have access to Vonigo, you can still run the tests mocked:
91
+
92
+ ```bash
93
+ VNG_MOCK=1 rspec
94
+ ```
88
95
 
89
96
  How to release new versions
90
97
  ===========================
@@ -1,3 +1,4 @@
1
+ require 'date'
1
2
  require 'vng/resource'
2
3
 
3
4
  module Vng
data/lib/vng/case.rb CHANGED
@@ -32,6 +32,11 @@ module Vng
32
32
  new id: data['Case']['objectID']
33
33
  end
34
34
 
35
+ # Returns the URL to manage the case in the Vonigo UI.
36
+ def url
37
+ "https://#{self.class.host}/Client/Case/Case_Main.aspx?caseID=#{id}"
38
+ end
39
+
35
40
  def destroy
36
41
  body = {
37
42
  method: '4',
data/lib/vng/franchise.rb CHANGED
@@ -21,7 +21,7 @@ module Vng
21
21
  zip: zip,
22
22
  }
23
23
 
24
- data = request path: Vng::Availability::PATH, body: body
24
+ data = request path: Availability::PATH, body: body
25
25
 
26
26
  franchise_id = data['Ids']['franchiseID']
27
27
  new(id: franchise_id) unless franchise_id == '0'
@@ -0,0 +1,95 @@
1
+ require 'json'
2
+ require 'net/http'
3
+
4
+ require 'vng/connection_error'
5
+ require 'vng/error'
6
+
7
+ module Vng
8
+ # A wrapper around +Net::HTTP+ to send HTTP requests to the Vonigo API and
9
+ # return their result or raise an error if the result is unexpected.
10
+ # The basic way to use HTTPRequest is by calling +run+ on an instance.
11
+ # @example List the species of all breeds.
12
+ # host = ''subdomain.vonigo.com'
13
+ # path = '/api/v1/resources/breeds/'
14
+ # body = {securityToken: security_token}
15
+ # response = Vng::HTTPRequest.new(path: path, body: body).run
16
+ # response['Breeds'].map{|breed| breed['species']}
17
+ # @api private
18
+ class Request
19
+ # Initializes an HTTPRequest object.
20
+ # @param [Hash] options the options for the request.
21
+ # @option options [String] :host The host of the request URI.
22
+ # @option options [String] :path The path of the request URI.
23
+ # @option options [Hash] :query ({}) The params to use as the query
24
+ # component of the request URI, for instance the Hash +{a: 1, b: 2}+
25
+ # corresponds to the query parameters +"a=1&b=2"+.
26
+ # @option options [Hash] :body The body of the request.
27
+ def initialize(options = {})
28
+ @host = options[:host]
29
+ @path = options[:path]
30
+ @body = options[:body]
31
+ @query = options.fetch :query, {}
32
+ end
33
+
34
+ # Sends the request and returns the body parsed from the JSON response.
35
+ # @return [Hash] the body parsed from the JSON response.
36
+ # @raise [Vng::ConnectionError] if the request fails.
37
+ # @raise [Vng::Error] if parsed body includes errors.
38
+ def run
39
+ return {} if response.body.empty?
40
+ JSON(response.body).tap do |data|
41
+ raise Error, "#{data['errMsg']} #{data['Errors']}" unless data['errNo'].zero?
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ # Run the request and memoize the response or the server error received.
48
+ def response
49
+ @response ||= Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
50
+ http.request http_request
51
+ end
52
+ rescue *server_errors => e
53
+ raise ConnectionError, e.message
54
+ end
55
+
56
+ # @return [URI::HTTPS] the (memoized) URI of the request.
57
+ def uri
58
+ attributes = { host: @host, path: @path, query: URI.encode_www_form(@query) }
59
+ @uri ||= URI::HTTPS.build attributes
60
+ end
61
+
62
+ # @return [Net::HTTPRequest] the full HTTP request object,
63
+ # inclusive of headers of request body.
64
+ def http_request
65
+ http_class = @query.any? ? Net::HTTP::Get : Net::HTTP::Post
66
+
67
+ @http_request ||= http_class.new(uri.request_uri).tap do |request|
68
+ set_request_body! request
69
+ set_request_headers! request
70
+ end
71
+ end
72
+
73
+ # Adds the request headers to the request in the appropriate format.
74
+ # The User-Agent header is also set to recognize the request.
75
+ def set_request_headers!(request)
76
+ request.initialize_http_header 'Content-Type' => 'application/json'
77
+ request.add_field 'User-Agent', 'Vng::HTTPRequest'
78
+ end
79
+
80
+ # Adds the request body to the request in the appropriate format.
81
+ def set_request_body!(request)
82
+ request.body = @body.to_json if @body
83
+ end
84
+
85
+ # Returns the list of server errors worth retrying the request once.
86
+ def server_errors
87
+ [
88
+ Errno::ECONNRESET, Errno::EHOSTUNREACH, Errno::ENETUNREACH,
89
+ Errno::ETIMEDOUT, Errno::ECONNREFUSED, Net::HTTPServerError,
90
+ OpenSSL::SSL::SSLError, OpenSSL::SSL::SSLErrorWaitReadable,
91
+ Net::OpenTimeout, SocketError,
92
+ ]
93
+ end
94
+ end
95
+ end
data/lib/vng/lock.rb CHANGED
@@ -22,7 +22,7 @@ module Vng
22
22
  startTime: minutes,
23
23
  }
24
24
 
25
- data = request path: Vng::Availability::PATH, body: body
25
+ data = request path: Availability::PATH, body: body
26
26
 
27
27
  new id: data['Ids']['lockID']
28
28
  end
@@ -0,0 +1,130 @@
1
+ module Vng
2
+ # A mock version of HTTPRequest which returns pre-built responses.
3
+ # @example List the species of all breeds.
4
+ # host = ''subdomain.vonigo.com'
5
+ # path = '/api/v1/resources/breeds/'
6
+ # body = {securityToken: security_token}
7
+ # response = Vng::Request.new(path: path, body: body).run
8
+ # response['Breeds'].map{|breed| breed['species']}
9
+ # @api private
10
+ class Request
11
+ # Initializes an MockRequest object.
12
+ # @param [Hash] options the options for the request.
13
+ # @option options [String] :host The host of the request URI.
14
+ # @option options [String] :path The path of the request URI.
15
+ # @option options [Hash] :query ({}) The params to use as the query
16
+ # component of the request URI, for instance the Hash +{a: 1, b: 2}+
17
+ # corresponds to the query parameters +"a=1&b=2"+.
18
+ # @option options [Hash] :body The body of the request.
19
+ def initialize(options = {})
20
+ @host = options[:host]
21
+ @path = options[:path]
22
+ @body = options[:body]
23
+ @query = options.fetch :query, {}
24
+ end
25
+
26
+ ROUTE_ID = 1630
27
+ @@logged_out = false
28
+
29
+ # Sends the request and returns the body parsed from the JSON response.
30
+ # @return [Hash] the body parsed from the JSON response.
31
+ # @raise [Vng::ConnectionError] if the request fails.
32
+ # @raise [Vng::Error] if parsed body includes errors.
33
+ def run
34
+ case @path
35
+ when '/api/v1/security/session/'
36
+ raise Error.new 'Same franchise ID supplied.'
37
+ when '/api/v1/security/login/'
38
+ if @host == 'invalid-host'
39
+ raise ConnectionError.new 'Failed to open connection'
40
+ else
41
+ { "securityToken"=>"1234567" }
42
+ end
43
+ when '/api/v1/security/logout/'
44
+ if @@logged_out
45
+ raise Error.new 'Session expired. '
46
+ else
47
+ @@logged_out = true
48
+ {}
49
+ end
50
+ when '/api/v1/resources/zips/'
51
+ { "Zips"=>[{ "zip"=>"21765", "zoneName"=>"Brentwood", "state"=>"MD" }] }
52
+ when '/api/v1/resources/franchises/'
53
+ if @body.key?(:objectID)
54
+ { "Franchise"=>{ "objectID"=>"2201007" }, "Fields"=>[
55
+ { "fieldID"=>9, "fieldValue"=>"vng@example.com" },
56
+ ] }
57
+ else
58
+ { "Franchises"=>[
59
+ { "franchiseID"=>106, "franchiseName"=>"Mississauga", "gmtOffsetFranchise"=>-300, "isActive"=>false },
60
+ { "franchiseID"=>107, "franchiseName"=>"Boise", "gmtOffsetFranchise"=>-420, "isActive"=>true },
61
+ ] }
62
+ end
63
+ when '/api/v1/resources/availability/'
64
+ if @body.key?(:zip)
65
+ { "Ids"=>{ "franchiseID"=>"172" } }
66
+ elsif @body[:method] == '2'
67
+ { "Ids"=>{ "lockID"=>"1406328" } }
68
+ else
69
+ { "Availability"=> [
70
+ { "dayID"=>"20281119", "routeID"=>"#{ROUTE_ID}", "startTime"=>"1080" },
71
+ { "dayID"=>"20281119", "routeID"=>"#{ROUTE_ID}", "startTime"=>"1110" },
72
+ ] }
73
+ end
74
+ when '/api/v1/resources/breeds/'
75
+ { "Breeds"=>[{ "breedID"=>2, "breed"=>"Bulldog", "species"=>"Dog", "optionID"=>303, "breedLowWeight"=>30, "breedHighWeight"=>50 }] }
76
+ when '/api/v1/data/Leads/'
77
+ { "Client"=>{ "objectID"=>"916347" }, "Fields"=> [
78
+ { "fieldID"=>126, "fieldValue"=>"Vng Example" },
79
+ { "fieldID"=>238, "fieldValue"=>"vng@example.com" },
80
+ { "fieldID"=>1024, "fieldValue"=>"8648648640" },
81
+ ] }
82
+ when '/api/v1/data/Contacts/'
83
+ { "Contact"=>{ "objectID"=>"2201007" }, "Fields"=>[
84
+ { "fieldID"=>127, "fieldValue"=>"Vng" },
85
+ { "fieldID"=>128, "fieldValue"=>"Example" },
86
+ { "fieldID"=>97, "fieldValue"=>"vng@example.com" },
87
+ { "fieldID"=>96, "fieldValue"=>"8648648640" },
88
+ ] }
89
+ when '/api/v1/data/Locations/'
90
+ { "Location"=>{ "objectID"=>"995681" } }
91
+ when '/api/v1/data/Assets/'
92
+ if @body[:method].eql? '3'
93
+ { "Asset"=>{ "objectID"=>"2201008" } }
94
+ elsif @body[:method].eql? '4'
95
+ {}
96
+ end
97
+ when '/api/v1/data/priceLists/'
98
+ { "PriceItems"=>[
99
+ { "priceItemID"=>275111, "priceItem"=>"15 Step SPA Grooming", "value"=>85.0, "taxID"=>256, "durationPerUnit"=>45.0, "serviceBadge"=>"Required", "serviceCategory"=>"15 Step Spa", "isOnline"=>true, "isActive"=>true },
100
+ { "priceItemID"=>275300, "priceItem"=>"De-Matting - Light", "value"=>10.0, "taxID"=>256, "durationPerUnit"=>15.0, "serviceBadge"=>nil, "serviceCategory"=>"De-Shed", "isOnline"=>true, "isActive"=>true },
101
+ { "priceItemID"=>275301, "priceItem"=>"De-Shedding Treatment", "value"=>20.0, "taxID"=>256, "durationPerUnit"=>15.0, "serviceBadge"=>nil, "serviceCategory"=>"De-Shed", "isOnline"=>true, "isActive"=>false },
102
+ ] }
103
+ when '/api/v1/resources/serviceTypes/'
104
+ if @body.key?(:zip)
105
+ {"ServiceTypes" => [
106
+ {"serviceTypeID" => 14, "serviceType" => "Pet Grooming (name)", "duration" => 45,"isActive" => true},
107
+ {"serviceTypeID" => 16, "serviceType" => "Pet Grooming (name)", "duration" => 45,"isActive" => false},
108
+ ]}
109
+ else
110
+ { "ServiceTypes"=>[
111
+ { "serviceTypeID"=>14, "serviceType"=>"Pet Grooming", "duration"=>90, "isActive"=>true },
112
+ ] }
113
+ end
114
+ when '/api/v1/resources/Routes/'
115
+ {"Routes" => [
116
+ {"routeID" => ROUTE_ID, "routeName" => "Route 1", "isActive" => true},
117
+ {"routeID" => 2, "routeName" => "Inactive", "isActive" => false},
118
+ ]}
119
+ when '/api/v1/data/WorkOrders/'
120
+ { "WorkOrder"=>{ "objectID"=>"4138030" } }
121
+ when '/api/v1/data/Cases/'
122
+ if @body[:method].eql? '3'
123
+ {"Case" => {"objectID" => "28503"}}
124
+ elsif @body[:method].eql? '4'
125
+ {}
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
data/lib/vng/resource.rb CHANGED
@@ -1,42 +1,18 @@
1
- require 'vng/connection_error'
2
- require 'vng/error'
1
+ require ENV['VNG_MOCK'] ? 'vng/mock_request' : 'vng/http_request'
3
2
 
4
3
  module Vng
5
4
  # Provides an abstract class for every Vonigo resource.
6
5
  class Resource
7
6
  private
8
- def self.request(path:, body: {}, query: {}, include_security_token: true)
9
- uri = URI::HTTPS.build host: host, path: path
10
- uri.query = URI.encode_www_form(query) if query.any?
11
-
12
- method = query.any? ? Net::HTTP::Get : Net::HTTP::Post
13
- request = method.new uri.request_uri
14
- request.initialize_http_header 'Content-Type' => 'application/json'
15
-
16
- if query.none?
17
- body = body.merge(securityToken: security_token) if include_security_token
18
- request.body = body.to_json
19
- end
20
7
 
21
- response = instrument do |data|
22
- data[:response] = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
23
- http.request request
24
- end
8
+ def self.request(path:, body: {}, query: {}, include_security_token: true)
9
+ if query.none? && include_security_token
10
+ body = body.merge securityToken: Vng.configuration.security_token
25
11
  end
26
12
 
27
- JSON(response.body).tap do |data|
28
- raise Vng::Error, "#{data['errMsg']} #{data['Errors']}" unless data['errNo'].zero?
13
+ instrument do |data|
14
+ Request.new(host: host, path: path, query: query, body: body).run
29
15
  end
30
- rescue Errno::ECONNREFUSED, SocketError => e
31
- raise Vng::ConnectionError, e.message
32
- end
33
-
34
- def self.host
35
- Vng.configuration.host
36
- end
37
-
38
- def self.security_token
39
- Vng.configuration.security_token
40
16
  end
41
17
 
42
18
  def self.value_for_field(data, field_id)
@@ -44,12 +20,18 @@ module Vng
44
20
  field['fieldValue'] if field
45
21
  end
46
22
 
23
+ # @return [String] the Vonigo API host.
24
+ def self.host
25
+ Vng.configuration.host
26
+ end
27
+
28
+ # Provides instrumentation to ActiveSupport listeners
47
29
  def self.instrument(&block)
48
- data = {class_name: name} # TODO: Add path, query, ...
30
+ data = { class_name: name }
49
31
  if defined?(ActiveSupport::Notifications)
50
32
  ActiveSupport::Notifications.instrument 'Vng.request', data, &block
51
33
  else
52
- block.call(data)
34
+ block.call data
53
35
  end
54
36
  end
55
37
  end
@@ -1,3 +1,4 @@
1
+ require 'digest/md5'
1
2
  require 'vng/resource'
2
3
 
3
4
  module Vng
@@ -32,14 +33,14 @@ module Vng
32
33
  }
33
34
 
34
35
  self.class.request path: '/api/v1/security/session/', body: body, include_security_token: false
35
- rescue Vng::Error => e
36
+ rescue Error => e
36
37
  raise unless e.message.include? 'Same franchise ID supplied'
37
38
  end
38
39
 
39
40
  def destroy
40
41
  query = { securityToken: @token }
41
42
  self.class.request path: '/api/v1/security/logout/', query: query
42
- rescue Vng::Error => e
43
+ rescue Error => e
43
44
  raise unless e.message.include?('Session expired') || e.message.include?('Session does not exist')
44
45
  end
45
46
  end
data/lib/vng/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Vng
2
- VERSION = '1.1.0'
2
+ VERSION = '1.3.0'
3
3
  end
@@ -32,6 +32,11 @@ module Vng
32
32
  new id: data['WorkOrder']['objectID']
33
33
  end
34
34
 
35
+ # Returns the URL to manage the work order in the Vonigo UI.
36
+ def url
37
+ "https://#{self.class.host}/Schedule/Job/Job_Main.aspx?woID=#{id}"
38
+ end
39
+
35
40
  private
36
41
 
37
42
  def self.charges_for(line_items)
data/lib/vng.rb CHANGED
@@ -1,14 +1,13 @@
1
- require 'date'
2
- require 'digest/md5'
3
- require 'json'
4
- require 'net/http'
1
+ # Used by multiple resources
5
2
  require 'uri'
3
+ require_relative 'vng/error'
4
+ require_relative 'vng/config'
6
5
 
6
+ # Individual resources
7
7
  require_relative 'vng/asset'
8
8
  require_relative 'vng/availability'
9
9
  require_relative 'vng/breed'
10
10
  require_relative 'vng/case'
11
- require_relative 'vng/config'
12
11
  require_relative 'vng/connection_error'
13
12
  require_relative 'vng/contact'
14
13
  require_relative 'vng/franchise'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vng
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - claudiob
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-21 00:00:00.000000000 Z
11
+ date: 2024-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simplecov
@@ -76,10 +76,11 @@ files:
76
76
  - lib/vng/contact.rb
77
77
  - lib/vng/error.rb
78
78
  - lib/vng/franchise.rb
79
+ - lib/vng/http_request.rb
79
80
  - lib/vng/lead.rb
80
81
  - lib/vng/location.rb
81
82
  - lib/vng/lock.rb
82
- - lib/vng/mock_resource.rb
83
+ - lib/vng/mock_request.rb
83
84
  - lib/vng/price_item.rb
84
85
  - lib/vng/resource.rb
85
86
  - lib/vng/route.rb
@@ -1,107 +0,0 @@
1
- require 'vng/connection_error'
2
- require 'vng/error'
3
-
4
- module Vng
5
- # Provides an abstract class for every Vonigo resource.
6
- class Resource
7
- private
8
- def self.request(path:, body: {}, query: {}, include_security_token: true)
9
- if Vng.configuration.mock
10
- mock_request(path:, body:, query:)
11
- else
12
- http_request(path:, body:, query:, include_security_token:)
13
- end
14
- end
15
-
16
- def self.mock_request(path:, body:, query:)
17
- case path
18
- when '/api/v1/security/login/'
19
- { "securityToken"=>"1234567" }
20
- when '/api/v1/resources/zips/'
21
- { "Zips"=>[{ "zip"=>"21765", "zoneName"=>"Brentwood", "state"=>"MD" }] }
22
- when '/api/v1/resources/franchises/'
23
- { "Franchises"=>[
24
- { "franchiseID"=>106, "franchiseName"=>"Mississauga", "gmtOffsetFranchise"=>-300, "isActive"=>false },
25
- { "franchiseID"=>107, "franchiseName"=>"Boise", "gmtOffsetFranchise"=>-420, "isActive"=>true },
26
- ] }
27
- when '/api/v1/resources/availability/'
28
- if body.key?(:zip)
29
- { "Ids"=>{ "franchiseID"=>"172" } }
30
- elsif body[:method] == '2'
31
- { "Ids"=>{ "lockID"=>"1406328" } }
32
- else
33
- { "Availability"=> [
34
- { "dayID"=>"20241119", "routeID"=>"8949", "startTime"=>"1080" },
35
- { "dayID"=>"20241119", "routeID"=>"8949", "startTime"=>"1110" },
36
- ] }
37
- end
38
- when '/api/v1/resources/breeds/'
39
- { "Breeds"=>[{ "breedID"=>2, "breed"=>"Bulldog", "species"=>"Dog", "optionID"=>303, "breedLowWeight"=>30, "breedHighWeight"=>50 }] }
40
- when '/api/v1/data/Leads/'
41
- { "Client"=>{ "objectID"=>"916347" }, "Fields"=> [
42
- { "fieldID"=>126, "fieldValue"=>"Vng Example" },
43
- { "fieldID"=>238, "fieldValue"=>"vng@example.com" },
44
- { "fieldID"=>1024, "fieldValue"=>"8648648640" },
45
- ] }
46
- when '/api/v1/data/Contacts/'
47
- { "Contact"=>{ "objectID"=>"2201007" }, "Fields"=>[
48
- { "fieldID"=>127, "fieldValue"=>"Vng" },
49
- { "fieldID"=>128, "fieldValue"=>"Example" },
50
- { "fieldID"=>97, "fieldValue"=>"vng@example.com" },
51
- { "fieldID"=>96, "fieldValue"=>"8648648640" },
52
- ] }
53
- when '/api/v1/data/Locations/'
54
- { "Location"=>{ "objectID"=>"995681" } }
55
- when '/api/v1/data/Assets/'
56
- { "Asset"=>{ "objectID"=>"2201008" } }
57
- when '/api/v1/data/priceLists/'
58
- { "PriceItems"=>[
59
- { "priceItemID"=>275111, "priceItem"=>"15 Step SPA Grooming", "value"=>85.0, "taxID"=>256, "durationPerUnit"=>45.0, "serviceBadge"=>"Required", "serviceCategory"=>"15 Step Spa", "isOnline"=>true, "isActive"=>true },
60
- { "priceItemID"=>275300, "priceItem"=>"De-Shedding Treatment", "value"=>20.0, "taxID"=>256, "durationPerUnit"=>15.0, "serviceBadge"=>nil, "serviceCategory"=>"De-Shed", "isOnline"=>true, "isActive"=>false },
61
- ] }
62
- when '/api/v1/resources/serviceTypes/'
63
- { "ServiceTypes"=>[
64
- { "serviceTypeID"=>14, "serviceType"=>"Pet Grooming", "duration"=>90, "isActive"=>true },
65
- ] }
66
- when '/api/v1/data/WorkOrders/'
67
- { "WorkOrder"=>{ "objectID"=>"4138030" } }
68
- when '/api/v1/data/Cases/'
69
- { "Case"=>{ "objectID"=>"28460" } }
70
- else
71
- {}
72
- end
73
- end
74
-
75
- def self.http_request(path:, body:, query:, include_security_token: true)
76
- uri = URI::HTTPS.build host: host, path: path
77
- uri.query = URI.encode_www_form(query) if query.any?
78
-
79
- method = query.any? ? Net::HTTP::Get : Net::HTTP::Post
80
- request = method.new uri.request_uri
81
- request.initialize_http_header 'Content-Type' => 'application/json'
82
-
83
- if query.none?
84
- body = body.merge(securityToken: security_token) if include_security_token
85
- request.body = body.to_json
86
- end
87
-
88
- response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
89
- http.request request
90
- end
91
-
92
- JSON(response.body).tap do |data|
93
- raise Vng::Error, "#{data['errMsg']} #{data['Errors']}" unless data['errNo'].zero?
94
- end
95
- rescue Errno::ECONNREFUSED, SocketError => e
96
- raise Vng::ConnectionError, e.message
97
- end
98
-
99
- def self.host
100
- Vng.configuration.host
101
- end
102
-
103
- def self.security_token
104
- Vng.configuration.security_token
105
- end
106
- end
107
- end