vng 1.2.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/README.md +12 -3
- data/lib/vng/availability.rb +2 -1
- data/lib/vng/franchise.rb +1 -1
- data/lib/vng/http_request.rb +95 -0
- data/lib/vng/lock.rb +1 -1
- data/lib/vng/mock_request.rb +130 -0
- data/lib/vng/resource.rb +14 -32
- data/lib/vng/security_token.rb +3 -2
- data/lib/vng/version.rb +1 -1
- data/lib/vng.rb +4 -5
- metadata +4 -3
- data/lib/vng/mock_resource.rb +0 -107
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d0e9b73d6daf01fecd5b989986337da1a29c1d95980d6f13fcb67f1a63b0511
|
4
|
+
data.tar.gz: f08205f3dbb85321b59811724f7795e85896e89b5f6709c1570b5ec80aeec591
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d60605d76c893a885144b8f17fbd69078f88134ec3603dca89aedeca9821a09a9defaebf7698835676e641054e9f694d0801d4042178c26b1dbb7d2bf2f48882
|
7
|
+
data.tar.gz: b3d5d51fe500345f85d449c6794d3e59ea8cbf4a8d5d54d77a1ff612ae76772acf96ab042d4837a2c586c3244103b244243c43740634eecbc4baa56e78f051f1
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -6,6 +6,8 @@ Vng helps you write apps that need to interact with Vonigo.
|
|
6
6
|
The **source code** is available on [GitHub](https://github.com/HouseAccountEng/vng) and the **documentation** on [RubyDoc](http://www.rubydoc.info/gems/vng/frames).
|
7
7
|
|
8
8
|
[![Code Climate](https://codeclimate.com/github/HouseAccountEng/vng.png)](https://codeclimate.com/github/HouseAccountEng/vng)
|
9
|
+
[![Code coverage](https://img.shields.io/badge/code_coverage-100%25-44d298)](https://github.com/HouseAccountEng/bookmaker/actions)
|
10
|
+
[![Rubygems](https://img.shields.io/gem/v/vng)](https://rubygems.org/gems/vng)
|
9
11
|
|
10
12
|
After [registering your app](#configuring-your-app), you can run commands like:
|
11
13
|
|
@@ -84,7 +86,14 @@ To run tests:
|
|
84
86
|
rspec
|
85
87
|
```
|
86
88
|
|
87
|
-
|
89
|
+
By default, tests are run with real HTTP calls to Vonigo that must be
|
90
|
+
set with the environment variables specified above.
|
91
|
+
|
92
|
+
If you do not have access to Vonigo, you can still run the tests mocked:
|
93
|
+
|
94
|
+
```bash
|
95
|
+
VNG_MOCK=1 rspec
|
96
|
+
```
|
88
97
|
|
89
98
|
How to release new versions
|
90
99
|
===========================
|
@@ -97,8 +106,8 @@ Document the changes in CHANGELOG.md and README.md, bump the version, then run:
|
|
97
106
|
rake release
|
98
107
|
|
99
108
|
Remember that the vng gem follows [Semantic Versioning](http://semver.org).
|
100
|
-
Any new release that is fully backward-compatible should bump the *
|
101
|
-
Any new version that breaks compatibility should bump the *
|
109
|
+
Any new release that is fully backward-compatible should bump the *minor* version (1.x).
|
110
|
+
Any new version that breaks compatibility should bump the *major* version (x.0)
|
102
111
|
|
103
112
|
How to contribute
|
104
113
|
=================
|
data/lib/vng/availability.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'date'
|
1
2
|
require 'vng/resource'
|
2
3
|
|
3
4
|
module Vng
|
@@ -26,7 +27,7 @@ module Vng
|
|
26
27
|
data = request path: PATH, body: body
|
27
28
|
|
28
29
|
data['Availability'].map do |availability|
|
29
|
-
route_id = availability['routeID']
|
30
|
+
route_id = availability['routeID'].to_i
|
30
31
|
date = Date.strptime availability['dayID'], '%Y%m%d'
|
31
32
|
minutes = availability['startTime'].to_i
|
32
33
|
|
data/lib/vng/franchise.rb
CHANGED
@@ -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
@@ -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/
|
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
|
-
|
22
|
-
|
23
|
-
|
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
|
-
|
28
|
-
|
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}
|
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
|
34
|
+
block.call data
|
53
35
|
end
|
54
36
|
end
|
55
37
|
end
|
data/lib/vng/security_token.rb
CHANGED
@@ -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
|
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
|
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
data/lib/vng.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
|
-
|
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.
|
4
|
+
version: 1.4.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-
|
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/
|
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
|
data/lib/vng/mock_resource.rb
DELETED
@@ -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
|