parking_ticket 1.0.46 → 1.0.49
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 +4 -4
- data/.rubocop.yml +4 -0
- data/.vscode/settings.json +3 -0
- data/Gemfile +0 -15
- data/Gemfile.lock +72 -4
- data/Rakefile +2 -2
- data/bin/console +3 -3
- data/bin/tapioca +29 -0
- data/lib/clients/models/payment_method.rb +15 -0
- data/lib/clients/models/quote.rb +16 -0
- data/lib/clients/models/rate_option.rb +19 -0
- data/lib/clients/models/structuraly_comparable.rb +14 -0
- data/lib/clients/models/ticket.rb +19 -0
- data/lib/clients/models/vehicle.rb +17 -0
- data/lib/clients/pay_by_phone/adapter.rb +107 -53
- data/lib/clients/pay_by_phone/client.rb +101 -38
- data/lib/parking_ticket/configuration.rb +3 -0
- data/lib/parking_ticket/version.rb +2 -1
- data/lib/parking_ticket.rb +79 -54
- data/sorbet/config +4 -0
- data/sorbet/rbi/annotations/faraday.rbi +17 -0
- data/sorbet/rbi/annotations/rainbow.rbi +269 -0
- data/sorbet/rbi/annotations/webmock.rbi +9 -0
- data/sorbet/rbi/gems/addressable@2.8.1.rbi +2000 -0
- data/sorbet/rbi/gems/amazing_print@1.4.0.rbi +872 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +584 -0
- data/sorbet/rbi/gems/crack@0.4.5.rbi +144 -0
- data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1079 -0
- data/sorbet/rbi/gems/faraday-net_http@3.0.2.rbi +146 -0
- data/sorbet/rbi/gems/faraday@2.7.2.rbi +2518 -0
- data/sorbet/rbi/gems/hashdiff@1.0.1.rbi +350 -0
- data/sorbet/rbi/gems/json@2.6.3.rbi +1541 -0
- data/sorbet/rbi/gems/json_matchers@0.11.1.rbi +133 -0
- data/sorbet/rbi/gems/json_schema@0.21.0.rbi +1165 -0
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +161 -0
- data/sorbet/rbi/gems/parallel@1.22.1.rbi +277 -0
- data/sorbet/rbi/gems/parser@3.2.2.0.rbi +7207 -0
- data/sorbet/rbi/gems/public_suffix@5.0.1.rbi +940 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +402 -0
- data/sorbet/rbi/gems/rake@13.0.6.rbi +2881 -0
- data/sorbet/rbi/gems/rbi@0.0.16.rbi +3008 -0
- data/sorbet/rbi/gems/regexp_parser@2.7.0.rbi +3600 -0
- data/sorbet/rbi/gems/rexml@3.2.5.rbi +4823 -0
- data/sorbet/rbi/gems/rspec-core@3.12.0.rbi +10826 -0
- data/sorbet/rbi/gems/rspec-expectations@3.12.1.rbi +8118 -0
- data/sorbet/rbi/gems/rspec-mocks@3.12.1.rbi +5300 -0
- data/sorbet/rbi/gems/rspec-support@3.12.0.rbi +1615 -0
- data/sorbet/rbi/gems/rspec@3.12.0.rbi +82 -0
- data/sorbet/rbi/gems/rubocop-ast@1.28.0.rbi +6985 -0
- data/sorbet/rbi/gems/rubocop-sorbet@0.7.0.rbi +1043 -0
- data/sorbet/rbi/gems/rubocop@1.48.1.rbi +54934 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1317 -0
- data/sorbet/rbi/gems/ruby2_keywords@0.0.5.rbi +8 -0
- data/sorbet/rbi/gems/spoom@1.2.1.rbi +2503 -0
- data/sorbet/rbi/gems/tapioca@0.11.4.rbi +3212 -0
- data/sorbet/rbi/gems/thor@1.2.1.rbi +3956 -0
- data/sorbet/rbi/gems/unicode-display_width@2.4.2.rbi +65 -0
- data/sorbet/rbi/gems/unparser@0.6.7.rbi +4515 -0
- data/sorbet/rbi/gems/vcr@6.1.0.rbi +3023 -0
- data/sorbet/rbi/gems/webmock@3.18.1.rbi +1728 -0
- data/sorbet/rbi/gems/webrick@1.7.0.rbi +2584 -0
- data/sorbet/rbi/gems/yard-sorbet@0.8.0.rbi +441 -0
- data/sorbet/rbi/gems/yard@0.9.28.rbi +17802 -0
- data/sorbet/tapioca/config.yml +13 -0
- data/sorbet/tapioca/require.rb +4 -0
- metadata +241 -4
- data/lib/clients/adapter.rb +0 -75
@@ -1,21 +1,16 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
1
4
|
require 'faraday'
|
5
|
+
|
2
6
|
module ParkingTicket
|
3
7
|
module Clients
|
4
8
|
module PayByPhone
|
5
9
|
class Client
|
10
|
+
extend T::Sig
|
6
11
|
class << self
|
7
|
-
|
8
|
-
|
9
|
-
{
|
10
|
-
parkingAccountId: account_id,
|
11
|
-
licensePlate: license_plate
|
12
|
-
}).body
|
13
|
-
end
|
14
|
-
|
15
|
-
def vehicles(token)
|
16
|
-
connection(token).get('/identity/profileservice/v1/members/vehicles/paybyphone').body
|
17
|
-
end
|
18
|
-
|
12
|
+
extend T::Sig
|
13
|
+
sig { params(username: String, password: String).returns(Faraday::Response) }
|
19
14
|
def auth(username, password)
|
20
15
|
conn = Faraday.new('https://auth.paybyphoneapis.com') do |f|
|
21
16
|
f.response :json
|
@@ -35,14 +30,41 @@ module ParkingTicket
|
|
35
30
|
)
|
36
31
|
end
|
37
32
|
|
33
|
+
sig { params(token: String, account_id: String, zipcode: String, license_plate: String).returns(Array) }
|
34
|
+
def rate_options(token, account_id, zipcode, license_plate)
|
35
|
+
connection(token).get("/parking/locations/#{zipcode}/rateOptions",
|
36
|
+
{
|
37
|
+
parkingAccountId: account_id,
|
38
|
+
licensePlate: license_plate
|
39
|
+
}).body
|
40
|
+
end
|
41
|
+
|
42
|
+
sig { params(token: String).returns(T::Array[T::Hash[String, T.untyped]]) }
|
43
|
+
def vehicles(token)
|
44
|
+
connection(token).get('/identity/profileservice/v1/members/vehicles/paybyphone').body
|
45
|
+
end
|
46
|
+
|
47
|
+
sig { params(token: String).returns(String) }
|
38
48
|
def account_id(token)
|
39
49
|
connection(token).get('/parking/accounts').body.dig(0, 'id')
|
40
50
|
end
|
41
51
|
|
52
|
+
sig { params(token: String, account_id: String).returns(T::Array[T::Hash[String, T.untyped]]) }
|
42
53
|
def running_tickets(token, account_id)
|
43
54
|
connection(token).get("/parking/accounts/#{account_id}/sessions?periodType=Current").body
|
44
55
|
end
|
45
56
|
|
57
|
+
sig do
|
58
|
+
params(
|
59
|
+
token: String,
|
60
|
+
account_id: String,
|
61
|
+
rate_option_id: String,
|
62
|
+
zipcode: String,
|
63
|
+
license_plate: String,
|
64
|
+
quantity: Integer,
|
65
|
+
time_unit: String
|
66
|
+
).returns(T::Hash[String, T.untyped])
|
67
|
+
end
|
46
68
|
def quote(token, account_id, rate_option_id, zipcode, license_plate, quantity, time_unit)
|
47
69
|
connection(token).get(
|
48
70
|
"/parking/accounts/#{account_id}/quote",
|
@@ -58,35 +80,50 @@ module ParkingTicket
|
|
58
80
|
).body
|
59
81
|
end
|
60
82
|
|
61
|
-
|
83
|
+
sig do
|
84
|
+
params(
|
85
|
+
token: String,
|
86
|
+
account_id: String,
|
87
|
+
license_plate: String,
|
88
|
+
zipcode: String,
|
89
|
+
rate_option_client_internal_id: String,
|
90
|
+
quantity: Integer,
|
91
|
+
time_unit: String,
|
92
|
+
quote_client_internal_id: String,
|
93
|
+
starts_on: DateTime,
|
94
|
+
payment_method_id: T.nilable(String)
|
95
|
+
).void
|
96
|
+
end
|
97
|
+
def new_ticket(token, account_id, license_plate:, zipcode:, rate_option_client_internal_id:, quantity:,
|
98
|
+
time_unit:, quote_client_internal_id:, starts_on:, payment_method_id:)
|
62
99
|
base_data = {
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
100
|
+
expireTime: nil,
|
101
|
+
duration: {
|
102
|
+
quantity: quantity.to_s,
|
103
|
+
timeUnit: time_unit
|
67
104
|
},
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
105
|
+
licensePlate: license_plate,
|
106
|
+
locationId: zipcode,
|
107
|
+
rateOptionId: rate_option_client_internal_id,
|
108
|
+
startTime: starts_on,
|
109
|
+
quoteId: quote_client_internal_id,
|
110
|
+
parkingAccountId: account_id
|
74
111
|
}
|
75
112
|
|
76
113
|
payment_data = {
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
114
|
+
paymentMethod: {
|
115
|
+
paymentMethodType: 'PaymentAccount',
|
116
|
+
payload: {
|
117
|
+
paymentAccountId: payment_method_id,
|
118
|
+
clientBrowserDetails: {
|
119
|
+
browserAcceptHeader: 'text/html',
|
120
|
+
browserColorDepth: '30',
|
121
|
+
browserJavaEnabled: 'false',
|
122
|
+
browserLanguage: 'fr-FR',
|
123
|
+
browserScreenHeight: '900',
|
124
|
+
browserScreenWidth: '1440',
|
125
|
+
browserTimeZone: '-60',
|
126
|
+
browserUserAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36'
|
90
127
|
}
|
91
128
|
}
|
92
129
|
}
|
@@ -96,16 +133,18 @@ module ParkingTicket
|
|
96
133
|
|
97
134
|
connection(token).post(
|
98
135
|
"/parking/accounts/#{account_id}/sessions/",
|
99
|
-
final_data
|
136
|
+
JSON.generate(final_data)
|
100
137
|
).body
|
101
138
|
end
|
102
139
|
|
140
|
+
sig { params(token: String).returns(T::Hash[String, T::Array[T::Hash[String, T.untyped]]]) }
|
103
141
|
def payment_methods(token)
|
104
142
|
connection(token).get('/payment/v3/accounts').body
|
105
143
|
end
|
106
144
|
|
107
145
|
private
|
108
146
|
|
147
|
+
sig { params(token: String).returns(Faraday::Connection) }
|
109
148
|
def connection(token)
|
110
149
|
Faraday.new(
|
111
150
|
url: 'https://consumer.paybyphoneapis.com',
|
@@ -124,27 +163,49 @@ module ParkingTicket
|
|
124
163
|
@password = password
|
125
164
|
end
|
126
165
|
|
166
|
+
sig { returns(T::Array[T::Hash[String, T.untyped]]) }
|
127
167
|
def vehicles
|
128
168
|
self.class.vehicles(token)
|
129
169
|
end
|
130
170
|
|
171
|
+
sig { params(zipcode: String, license_plate: String).returns(T::Array[T::Hash[String, T.untyped]]) }
|
131
172
|
def rate_options(zipcode, license_plate)
|
132
173
|
self.class.rate_options(token, account_id, zipcode, license_plate)
|
133
174
|
end
|
134
175
|
|
176
|
+
sig { returns(T::Array[T::Hash[String, T.untyped]]) }
|
135
177
|
def running_tickets
|
136
178
|
self.class.running_tickets(token, account_id)
|
137
179
|
end
|
138
180
|
|
181
|
+
sig { returns(T::Hash[String, T::Array[T::Hash[String, T.untyped]]]) }
|
139
182
|
def payment_methods
|
140
183
|
self.class.payment_methods(token)
|
141
184
|
end
|
142
185
|
|
186
|
+
sig do
|
187
|
+
params(rate_option_id: String, zipcode: String, license_plate: String, quantity: Integer,
|
188
|
+
time_unit: String).returns(T::Hash[String, T.untyped])
|
189
|
+
end
|
143
190
|
def quote(rate_option_id, zipcode, license_plate, quantity, time_unit)
|
144
191
|
self.class.quote(token, account_id, rate_option_id, zipcode, license_plate, quantity, time_unit)
|
145
192
|
end
|
146
193
|
|
147
|
-
|
194
|
+
sig do
|
195
|
+
params(
|
196
|
+
license_plate: String,
|
197
|
+
zipcode: String,
|
198
|
+
rate_option_client_internal_id: String,
|
199
|
+
quantity: Integer,
|
200
|
+
time_unit: String,
|
201
|
+
quote_client_internal_id: String,
|
202
|
+
starts_on: DateTime,
|
203
|
+
payment_method_id: T.nilable(String)
|
204
|
+
)
|
205
|
+
.void
|
206
|
+
end
|
207
|
+
def new_ticket(license_plate:, zipcode:, rate_option_client_internal_id:, quantity:, time_unit:,
|
208
|
+
quote_client_internal_id:, starts_on:, payment_method_id:)
|
148
209
|
self.class.new_ticket(token, account_id,
|
149
210
|
license_plate: license_plate,
|
150
211
|
zipcode: zipcode,
|
@@ -158,10 +219,12 @@ module ParkingTicket
|
|
158
219
|
|
159
220
|
private
|
160
221
|
|
222
|
+
sig { returns(String) }
|
161
223
|
def token
|
162
224
|
@token ||= self.class.auth(@username, @password).body['access_token']
|
163
225
|
end
|
164
226
|
|
227
|
+
sig { returns(String) }
|
165
228
|
def account_id
|
166
229
|
@account_id ||= self.class.account_id(token)
|
167
230
|
end
|
data/lib/parking_ticket.rb
CHANGED
@@ -1,73 +1,113 @@
|
|
1
|
+
# typed: strict
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
|
-
|
4
|
+
# requires
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
# sorbet
|
8
|
+
require 'sorbet-runtime'
|
9
|
+
|
10
|
+
# gem version
|
4
11
|
require 'parking_ticket/version'
|
5
12
|
|
6
|
-
#
|
7
|
-
require 'clients/
|
8
|
-
require 'clients/
|
13
|
+
# models
|
14
|
+
require 'clients/models/structuraly_comparable'
|
15
|
+
require 'clients/models/vehicle'
|
16
|
+
require 'clients/models/rate_option'
|
17
|
+
require 'clients/models/ticket'
|
18
|
+
require 'clients/models/payment_method'
|
19
|
+
require 'clients/models/quote'
|
20
|
+
|
21
|
+
# pay_by_phone_subclasses
|
9
22
|
require 'clients/pay_by_phone/client'
|
23
|
+
require 'clients/pay_by_phone/adapter'
|
10
24
|
|
11
25
|
module ParkingTicket
|
12
26
|
class Base
|
27
|
+
extend T::Sig
|
13
28
|
class << self
|
29
|
+
extend T::Sig
|
30
|
+
|
31
|
+
sig do
|
32
|
+
params(
|
33
|
+
adapter_name: String,
|
34
|
+
username: String,
|
35
|
+
password: String
|
36
|
+
)
|
37
|
+
.returns(T::Boolean)
|
38
|
+
end
|
14
39
|
def valid_credentials?(adapter_name, username, password)
|
15
|
-
|
40
|
+
adapter_class = Clients::PayByPhone::Adapter if adapter_name == 'pay_by_phone'
|
16
41
|
raise Error, 'EasyPark will be handled in the next major release' if adapter_name == 'easy_park'
|
17
|
-
raise Error, "Unhandled adapter : #{adapter_name}" unless
|
18
|
-
|
19
|
-
adapter.valid_credentials?(username, password)
|
20
|
-
end
|
42
|
+
raise Error, "Unhandled adapter : #{adapter_name}" unless adapter_class
|
21
43
|
|
22
|
-
|
23
|
-
yield(self)
|
24
|
-
end
|
25
|
-
|
26
|
-
attr_accessor :ticket_format
|
27
|
-
|
28
|
-
def format_ticket(ticket)
|
29
|
-
return unless ticket_format
|
30
|
-
|
31
|
-
ticket_format.each_with_object({}) do |element, acumulator|
|
32
|
-
if element.is_a?(Hash)
|
33
|
-
original_key = element.keys.first
|
34
|
-
target_key = element.values.first
|
35
|
-
acumulator[target_key] = ticket[original_key]
|
36
|
-
else
|
37
|
-
acumulator[element] = ticket[element]
|
38
|
-
end
|
39
|
-
end
|
44
|
+
adapter_class.valid_credentials?(username, password)
|
40
45
|
end
|
41
46
|
end
|
42
|
-
attr_reader :configuration
|
43
47
|
|
44
48
|
class Error < StandardError
|
45
49
|
end
|
46
50
|
|
51
|
+
sig do
|
52
|
+
params(
|
53
|
+
adapter_name: String,
|
54
|
+
username: String,
|
55
|
+
password: String
|
56
|
+
)
|
57
|
+
.void
|
58
|
+
end
|
47
59
|
def initialize(adapter_name, username, password)
|
48
|
-
@adapter_name = adapter_name
|
49
60
|
@username = username
|
50
61
|
@password = password
|
62
|
+
@adapter = T.let(load_adapter!(adapter_name), ParkingTicket::Clients::PayByPhone::Adapter)
|
51
63
|
end
|
52
64
|
|
65
|
+
sig { returns(T::Array[ParkingTicket::Clients::Models::Vehicle]) }
|
53
66
|
def vehicles
|
54
|
-
adapter.vehicles
|
67
|
+
@adapter.vehicles
|
55
68
|
end
|
56
69
|
|
70
|
+
sig { params(zipcode: String, license_plate: String).returns(T::Array[ParkingTicket::Clients::Models::RateOption]) }
|
57
71
|
def rate_options(zipcode, license_plate)
|
58
|
-
adapter.rate_options(zipcode, license_plate)
|
72
|
+
@adapter.rate_options(zipcode, license_plate)
|
59
73
|
end
|
60
74
|
|
75
|
+
sig { params(license_plate: String, zipcode: String).returns(T.nilable(ParkingTicket::Clients::Models::Ticket)) }
|
61
76
|
def running_ticket(license_plate, zipcode)
|
62
|
-
adapter.running_ticket(license_plate, zipcode)
|
77
|
+
@adapter.running_ticket(license_plate, zipcode)
|
63
78
|
end
|
64
79
|
|
80
|
+
sig { returns(T::Array[ParkingTicket::Clients::Models::PaymentMethod]) }
|
65
81
|
def payment_methods
|
66
|
-
adapter.payment_methods
|
82
|
+
@adapter.payment_methods
|
67
83
|
end
|
68
84
|
|
85
|
+
sig do
|
86
|
+
params(
|
87
|
+
rate_option_id: String,
|
88
|
+
zipcode: String,
|
89
|
+
license_plate: String,
|
90
|
+
quantity: Integer,
|
91
|
+
time_unit: String
|
92
|
+
)
|
93
|
+
.returns(ParkingTicket::Clients::Models::Quote)
|
94
|
+
end
|
95
|
+
def quote(rate_option_id, zipcode, license_plate, quantity, time_unit)
|
96
|
+
@adapter.quote(rate_option_id, zipcode, license_plate, quantity, time_unit)
|
97
|
+
end
|
98
|
+
|
99
|
+
sig do
|
100
|
+
params(
|
101
|
+
license_plate: String,
|
102
|
+
zipcode: String,
|
103
|
+
rate_option_client_internal_id: String,
|
104
|
+
quantity: Integer,
|
105
|
+
time_unit: String,
|
106
|
+
payment_method_id: T.nilable(String)
|
107
|
+
).void
|
108
|
+
end
|
69
109
|
def new_ticket(license_plate:, zipcode:, rate_option_client_internal_id:, quantity:, time_unit:, payment_method_id:)
|
70
|
-
adapter.new_ticket(
|
110
|
+
@adapter.new_ticket(
|
71
111
|
license_plate: license_plate,
|
72
112
|
zipcode: zipcode,
|
73
113
|
rate_option_client_internal_id: rate_option_client_internal_id,
|
@@ -77,29 +117,14 @@ module ParkingTicket
|
|
77
117
|
)
|
78
118
|
end
|
79
119
|
|
80
|
-
def quote(rate_option_id, zipcode, license_plate, quantity, time_unit)
|
81
|
-
adapter.quote(rate_option_id, zipcode, license_plate, quantity, time_unit)
|
82
|
-
end
|
83
|
-
|
84
120
|
private
|
85
121
|
|
86
|
-
|
87
|
-
|
88
|
-
return
|
89
|
-
|
90
|
-
raise Error, "Unhandled adapter : #{@adapter_name}"
|
91
|
-
end
|
92
|
-
|
93
|
-
def prepare_pay_by_phone_adapter!
|
94
|
-
Clients::PayByPhone::Adapter.new(@username, @password)
|
95
|
-
end
|
96
|
-
|
97
|
-
def prepare_easy_park_adapter!
|
98
|
-
raise Error, 'EasyPark will be handled in the next major release'
|
99
|
-
end
|
122
|
+
sig { params(adapter_name: String).returns(ParkingTicket::Clients::PayByPhone::Adapter) }
|
123
|
+
def load_adapter!(adapter_name)
|
124
|
+
return Clients::PayByPhone::Adapter.new(@username, @password) if adapter_name == 'pay_by_phone'
|
125
|
+
raise Error, 'EasyPark will be handled in the next major release' if adapter_name == 'easy_park'
|
100
126
|
|
101
|
-
|
102
|
-
@adapter ||= load_adapter!
|
127
|
+
raise Error, "Unhandled adapter : #{adapter_name}"
|
103
128
|
end
|
104
129
|
end
|
105
130
|
end
|
data/sorbet/config
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
# DO NOT EDIT MANUALLY
|
4
|
+
# This file was pulled from a central RBI files repository.
|
5
|
+
# Please run `bin/tapioca annotations` to update it.
|
6
|
+
|
7
|
+
module Faraday
|
8
|
+
class << self
|
9
|
+
sig { params(url: T.untyped, options: T::Hash[Symbol, T.untyped], block: T.nilable(T.proc.params(connection: Faraday::Connection).void)).returns(Faraday::Connection) }
|
10
|
+
def new(url = nil, options = {}, &block); end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Faraday::Response
|
15
|
+
sig { returns(T::Boolean) }
|
16
|
+
def success?; end
|
17
|
+
end
|