vng 0.1.18 → 0.1.20

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: a5a0ac30382d544a23cf237ceaed3b8d1ca72a91c1886126d007475bf8b5ee2b
4
- data.tar.gz: 62843a64cc58e6b21788d5fc87969fad1335e89740cd564247920df83620058c
3
+ metadata.gz: 0b49dda09b2542875760b7b2cdd3c4ab50d548458400e7dda9586edafd5c18b2
4
+ data.tar.gz: 0e86208199aebd2f79914bfd5e6c5ec330682bcebbe4d154bd808bb3bb4a64f7
5
5
  SHA512:
6
- metadata.gz: e516c0ab8fa41d444e923227ac3c2c4393a1451710e8ff10ac02dd2444c67c0423b3125471b290aa6b68b8a5e63c618c323df8ba41272e48361bf8e9c66151c2
7
- data.tar.gz: 8b236c7ad8f41302f1d5ff6de2ed222e1780217942c4bbdfdc441ecc3cbf2d43ed4ed8014946a7b200eef9e612affd77bfff4d3358211905eef3dd6caae8dd15
6
+ metadata.gz: 751d1a4eb1774f508106113b6cdc21988b6515ae8d965be322b205670b716214668ae72c67828e2a05fcb127a6c525fa741704c72244e8d9c52ad5e33fc55e43
7
+ data.tar.gz: 552dcc79f28b148d54559849f04052b5348e552c7fbecc2dbba81dc46a07744db9b83b90b4ff740e48893b1aedede0e3db31d05fcccb043bf6620a3c8af276ee
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.20] - 2024-11-20
4
+
5
+ - Adds Franchise.find
6
+
7
+ ## [0.1.19] - 2024-11-19
8
+
9
+ - Adds Route
10
+
3
11
  ## [0.1.18] - 2024-11-19
4
12
 
5
13
  - Ensure a plus sign in the email is not translated into a space
data/README.md CHANGED
@@ -84,6 +84,8 @@ To run tests:
84
84
  rspec
85
85
  ```
86
86
 
87
+ Set `VNG_MOCK=1` to test against HTTP mocks.
88
+
87
89
  How to release new versions
88
90
  ===========================
89
91
 
@@ -40,12 +40,16 @@ module Vng
40
40
  # @return [String] the password for the API calls.
41
41
  attr_accessor :password
42
42
 
43
+ # @return [Boolean] whether to mock the HTTP calls to Vonigo
44
+ attr_accessor :mock
45
+
43
46
  # Initialize the global configuration settings, using the values of
44
47
  # the specified following environment variables by default.
45
48
  def initialize
46
49
  @host = ENV['VNG_HOST']
47
50
  @username = ENV['VNG_USERNAME']
48
51
  @password = ENV['VNG_PASSWORD']
52
+ @mock = ENV['VNG_MOCK'] == '1'
49
53
  end
50
54
  end
51
55
  end
data/lib/vng/contact.rb CHANGED
@@ -37,16 +37,6 @@ module Vng
37
37
 
38
38
  new id: id, first_name: first_name, last_name: last_name, email: email, phone: phone
39
39
  end
40
-
41
- # Data validation failed. [{"fieldID"=>0, "fieldName"=>nil, "errNo"=>-1408, "errMsg"=>"Primary contact cannot be deleted."}]
42
- # def destroy
43
- # body = {
44
- # method: '4',
45
- # objectID: id,
46
- # }
47
- #
48
- # self.class.request path: PATH, body: body
49
- # end
50
40
  end
51
41
  end
52
42
 
data/lib/vng/franchise.rb CHANGED
@@ -5,12 +5,13 @@ module Vng
5
5
  class Franchise < Resource
6
6
  PATH = '/api/v1/resources/franchises/'
7
7
 
8
- attr_reader :id, :name, :gmt_offset
8
+ attr_reader :id, :name, :gmt_offset, :email
9
9
 
10
- def initialize(id:, name: nil, gmt_offset: nil)
10
+ def initialize(id:, name: nil, gmt_offset: nil, email: nil)
11
11
  @id = id
12
12
  @name = name
13
13
  @gmt_offset = gmt_offset
14
+ @email = email
14
15
  end
15
16
 
16
17
 
@@ -26,6 +27,19 @@ module Vng
26
27
  new(id: franchise_id) unless franchise_id == '0'
27
28
  end
28
29
 
30
+ def self.find(franchise_id)
31
+ body = {
32
+ method: '1',
33
+ objectID: franchise_id,
34
+ }
35
+
36
+ data = request path: PATH, body: body
37
+
38
+ email_field = data['Fields'].find{|field| field['fieldID'] == 9}
39
+ email = email_field['fieldValue'] if email_field
40
+ new id: franchise_id, email: email
41
+ end
42
+
29
43
  def self.all
30
44
  data = request path: PATH
31
45
 
data/lib/vng/lead.rb CHANGED
@@ -34,16 +34,5 @@ module Vng
34
34
 
35
35
  new id: id, name: name, email: email, phone: phone
36
36
  end
37
-
38
- # Data validation failed. [{"fieldID"=>0, "fieldName"=>nil, "errNo"=>-1201, "errMsg"=>"Lead ID does not exist."}]
39
- # TODO: has become an account meanwhile!! so this doesn't work
40
- # def destroy
41
- # body = {
42
- # method: '4',
43
- # objectID: id,
44
- # }
45
- #
46
- # self.class.request path: PATH, body: body
47
- # end
48
37
  end
49
38
  end
data/lib/vng/location.rb CHANGED
@@ -40,16 +40,6 @@ module Vng
40
40
 
41
41
  new id: data['Location']['objectID']
42
42
  end
43
-
44
- # Data validation failed. [{"fieldID"=>0, "fieldName"=>"", "errNo"=>-1809, "errMsg"=>"Primary location cannot be deleted."}]
45
- # def destroy
46
- # body = {
47
- # method: '4',
48
- # objectID: id,
49
- # }
50
- #
51
- # self.class.request path: PATH, body: body
52
- # end
53
43
  end
54
44
  end
55
45
 
@@ -0,0 +1,107 @@
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
data/lib/vng/route.rb ADDED
@@ -0,0 +1,29 @@
1
+ require 'vng/resource'
2
+
3
+ module Vng
4
+ # Provides methods to interact with Vonigo ZIP routes.
5
+ class Route < Resource
6
+ PATH = '/api/v1/resources/Routes/'
7
+
8
+ attr_reader :id, :name
9
+
10
+ def initialize(id:, name:)
11
+ @id = id
12
+ @name = name
13
+ end
14
+
15
+ # TODO: Needs pagination
16
+ def self.all
17
+ data = request path: PATH
18
+
19
+ data['Routes'].filter do |route|
20
+ route['isActive']
21
+ end.map do |body|
22
+ id = body['routeID']
23
+ name = body['routeName']
24
+
25
+ new id: id, name: name
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/vng/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Vng
2
- VERSION = '0.1.18'
2
+ VERSION = '0.1.20'
3
3
  end
@@ -32,16 +32,6 @@ module Vng
32
32
  new id: data['WorkOrder']['objectID']
33
33
  end
34
34
 
35
- # TODO: This moves to "archived". actual cancelation is different
36
- # def destroy
37
- # body = {
38
- # method: '8',
39
- # objectID: id,
40
- # }
41
- #
42
- # data = self.class.request path: PATH, body: body
43
- # end
44
-
45
35
  private
46
36
 
47
37
  def self.charges_for(line_items)
data/lib/vng.rb CHANGED
@@ -16,6 +16,7 @@ require_relative 'vng/lead'
16
16
  require_relative 'vng/location'
17
17
  require_relative 'vng/lock'
18
18
  require_relative 'vng/price_item'
19
+ require_relative 'vng/route'
19
20
  require_relative 'vng/security_token'
20
21
  require_relative 'vng/service_type'
21
22
  require_relative 'vng/version'
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: 0.1.18
4
+ version: 0.1.20
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-19 00:00:00.000000000 Z
11
+ date: 2024-11-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: simplecov
@@ -50,8 +50,10 @@ files:
50
50
  - lib/vng/lead.rb
51
51
  - lib/vng/location.rb
52
52
  - lib/vng/lock.rb
53
+ - lib/vng/mock_resource.rb
53
54
  - lib/vng/price_item.rb
54
55
  - lib/vng/resource.rb
56
+ - lib/vng/route.rb
55
57
  - lib/vng/security_token.rb
56
58
  - lib/vng/service_type.rb
57
59
  - lib/vng/version.rb