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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/.vscode/settings.json +3 -0
  4. data/Gemfile +0 -15
  5. data/Gemfile.lock +72 -4
  6. data/Rakefile +2 -2
  7. data/bin/console +3 -3
  8. data/bin/tapioca +29 -0
  9. data/lib/clients/models/payment_method.rb +15 -0
  10. data/lib/clients/models/quote.rb +16 -0
  11. data/lib/clients/models/rate_option.rb +19 -0
  12. data/lib/clients/models/structuraly_comparable.rb +14 -0
  13. data/lib/clients/models/ticket.rb +19 -0
  14. data/lib/clients/models/vehicle.rb +17 -0
  15. data/lib/clients/pay_by_phone/adapter.rb +107 -53
  16. data/lib/clients/pay_by_phone/client.rb +101 -38
  17. data/lib/parking_ticket/configuration.rb +3 -0
  18. data/lib/parking_ticket/version.rb +2 -1
  19. data/lib/parking_ticket.rb +79 -54
  20. data/sorbet/config +4 -0
  21. data/sorbet/rbi/annotations/faraday.rbi +17 -0
  22. data/sorbet/rbi/annotations/rainbow.rbi +269 -0
  23. data/sorbet/rbi/annotations/webmock.rbi +9 -0
  24. data/sorbet/rbi/gems/addressable@2.8.1.rbi +2000 -0
  25. data/sorbet/rbi/gems/amazing_print@1.4.0.rbi +872 -0
  26. data/sorbet/rbi/gems/ast@2.4.2.rbi +584 -0
  27. data/sorbet/rbi/gems/crack@0.4.5.rbi +144 -0
  28. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1079 -0
  29. data/sorbet/rbi/gems/faraday-net_http@3.0.2.rbi +146 -0
  30. data/sorbet/rbi/gems/faraday@2.7.2.rbi +2518 -0
  31. data/sorbet/rbi/gems/hashdiff@1.0.1.rbi +350 -0
  32. data/sorbet/rbi/gems/json@2.6.3.rbi +1541 -0
  33. data/sorbet/rbi/gems/json_matchers@0.11.1.rbi +133 -0
  34. data/sorbet/rbi/gems/json_schema@0.21.0.rbi +1165 -0
  35. data/sorbet/rbi/gems/netrc@0.11.0.rbi +161 -0
  36. data/sorbet/rbi/gems/parallel@1.22.1.rbi +277 -0
  37. data/sorbet/rbi/gems/parser@3.2.2.0.rbi +7207 -0
  38. data/sorbet/rbi/gems/public_suffix@5.0.1.rbi +940 -0
  39. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +402 -0
  40. data/sorbet/rbi/gems/rake@13.0.6.rbi +2881 -0
  41. data/sorbet/rbi/gems/rbi@0.0.16.rbi +3008 -0
  42. data/sorbet/rbi/gems/regexp_parser@2.7.0.rbi +3600 -0
  43. data/sorbet/rbi/gems/rexml@3.2.5.rbi +4823 -0
  44. data/sorbet/rbi/gems/rspec-core@3.12.0.rbi +10826 -0
  45. data/sorbet/rbi/gems/rspec-expectations@3.12.1.rbi +8118 -0
  46. data/sorbet/rbi/gems/rspec-mocks@3.12.1.rbi +5300 -0
  47. data/sorbet/rbi/gems/rspec-support@3.12.0.rbi +1615 -0
  48. data/sorbet/rbi/gems/rspec@3.12.0.rbi +82 -0
  49. data/sorbet/rbi/gems/rubocop-ast@1.28.0.rbi +6985 -0
  50. data/sorbet/rbi/gems/rubocop-sorbet@0.7.0.rbi +1043 -0
  51. data/sorbet/rbi/gems/rubocop@1.48.1.rbi +54934 -0
  52. data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +1317 -0
  53. data/sorbet/rbi/gems/ruby2_keywords@0.0.5.rbi +8 -0
  54. data/sorbet/rbi/gems/spoom@1.2.1.rbi +2503 -0
  55. data/sorbet/rbi/gems/tapioca@0.11.4.rbi +3212 -0
  56. data/sorbet/rbi/gems/thor@1.2.1.rbi +3956 -0
  57. data/sorbet/rbi/gems/unicode-display_width@2.4.2.rbi +65 -0
  58. data/sorbet/rbi/gems/unparser@0.6.7.rbi +4515 -0
  59. data/sorbet/rbi/gems/vcr@6.1.0.rbi +3023 -0
  60. data/sorbet/rbi/gems/webmock@3.18.1.rbi +1728 -0
  61. data/sorbet/rbi/gems/webrick@1.7.0.rbi +2584 -0
  62. data/sorbet/rbi/gems/yard-sorbet@0.8.0.rbi +441 -0
  63. data/sorbet/rbi/gems/yard@0.9.28.rbi +17802 -0
  64. data/sorbet/tapioca/config.yml +13 -0
  65. data/sorbet/tapioca/require.rb +4 -0
  66. metadata +241 -4
  67. data/lib/clients/adapter.rb +0 -75
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de1dded37503f11b5a809b56ca98dec69781e02cf6cd73d1641e9965de3ae257
4
- data.tar.gz: 1f6387e3eb9da51dedeb572dfa2671ecf7fc1406fc9d5df1b030c514ee9480a2
3
+ metadata.gz: 3b46304973466b46ffd135627aa9ed02e08d0165275e3d309d07fa7cdd4f043a
4
+ data.tar.gz: b1b7d77658c9ffb2ca0886b0ec4e056e843d5ff662223b64f7cd2a37d9b3b31d
5
5
  SHA512:
6
- metadata.gz: e198ce49533ab058756a127c17cd3a55e51e9a752689b035453025f214fa774171994db7447979652c244da2722bf9200a5b7fd365936048cd0b446e154c6cf1
7
- data.tar.gz: 4e4284028b493807cefcb0c6efbd6d12ec34eb901d5ad085660178899e6b13cae736351cb37bcf022659d9b19bdc0d4a5447f950fff35406e27004ab60d4389f
6
+ metadata.gz: 86469cd585d95b63a7366a61081159a6e800aa3c4bb046adad5ad51cf0d5d3a9e7c9964c2f58d4c3e8af296a57cf61c986b26d378df215255a25f29b96aa9506
7
+ data.tar.gz: 45f94644040eb191fb0d44ec90e565de09fa8f00daa4387eea31dbfbcc5d55100db0cd480bde2ae67cadce4b4d7f7dc9b8b3a0a2c34f57e6ce1ddf0ef052b995
data/.rubocop.yml ADDED
@@ -0,0 +1,4 @@
1
+ require:
2
+ - rubocop-sorbet
3
+ AllCops:
4
+ NewCops: enable
@@ -0,0 +1,3 @@
1
+ {
2
+ "ruby.rubocop.onSave": false
3
+ }
data/Gemfile CHANGED
@@ -1,19 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  source 'https://rubygems.org'
4
-
5
- # Specify your gem's dependencies in parking_ticket.gemspec
6
4
  gemspec
7
-
8
- gem 'rake', '~> 13.0'
9
-
10
- gem 'rspec', '~> 3.0'
11
-
12
- # VCR, save test suite's http requests and replay them
13
- gem 'vcr', '~> 6.0'
14
- # Mock web requests in tests
15
- gem 'webmock', '~> 3.12'
16
-
17
- gem 'faraday', '~> 2.7', '>= 2.7.2'
18
-
19
- gem 'json_matchers'
data/Gemfile.lock CHANGED
@@ -1,27 +1,42 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- parking_ticket (1.0.46)
5
- faraday
4
+ parking_ticket (1.0.48)
5
+ faraday (>= 2.7.2)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
10
  addressable (2.8.1)
11
11
  public_suffix (>= 2.0.2, < 6.0)
12
+ amazing_print (1.4.0)
13
+ ast (2.4.2)
14
+ byebug (11.1.3)
12
15
  crack (0.4.5)
13
16
  rexml
14
17
  diff-lcs (1.5.0)
15
- faraday (2.7.2)
18
+ faraday (2.7.4)
16
19
  faraday-net_http (>= 2.0, < 3.1)
17
20
  ruby2_keywords (>= 0.0.4)
18
21
  faraday-net_http (3.0.2)
19
22
  hashdiff (1.0.1)
23
+ json (2.6.3)
20
24
  json_matchers (0.11.1)
21
25
  json_schema
22
26
  json_schema (0.21.0)
27
+ netrc (0.11.0)
28
+ parallel (1.22.1)
29
+ parser (3.2.2.0)
30
+ ast (~> 2.4.1)
23
31
  public_suffix (5.0.1)
32
+ rainbow (3.1.1)
24
33
  rake (13.0.6)
34
+ rbi (0.0.16)
35
+ ast
36
+ parser (>= 2.6.4.0)
37
+ sorbet-runtime (>= 0.5.9204)
38
+ unparser
39
+ regexp_parser (2.7.0)
25
40
  rexml (3.2.5)
26
41
  rspec (3.12.0)
27
42
  rspec-core (~> 3.12.0)
@@ -36,23 +51,76 @@ GEM
36
51
  diff-lcs (>= 1.2.0, < 2.0)
37
52
  rspec-support (~> 3.12.0)
38
53
  rspec-support (3.12.0)
54
+ rubocop (1.48.1)
55
+ json (~> 2.3)
56
+ parallel (~> 1.10)
57
+ parser (>= 3.2.0.0)
58
+ rainbow (>= 2.2.2, < 4.0)
59
+ regexp_parser (>= 1.8, < 3.0)
60
+ rexml (>= 3.2.5, < 4.0)
61
+ rubocop-ast (>= 1.26.0, < 2.0)
62
+ ruby-progressbar (~> 1.7)
63
+ unicode-display_width (>= 2.4.0, < 3.0)
64
+ rubocop-ast (1.28.0)
65
+ parser (>= 3.2.1.0)
66
+ rubocop-sorbet (0.7.0)
67
+ rubocop (>= 0.90.0)
68
+ ruby-progressbar (1.13.0)
39
69
  ruby2_keywords (0.0.5)
70
+ sorbet (0.5.10746)
71
+ sorbet-static (= 0.5.10746)
72
+ sorbet-runtime (0.5.10746)
73
+ sorbet-static (0.5.10746-universal-darwin-20)
74
+ sorbet-static-and-runtime (0.5.10746)
75
+ sorbet (= 0.5.10746)
76
+ sorbet-runtime (= 0.5.10746)
77
+ spoom (1.2.1)
78
+ sorbet (>= 0.5.10187)
79
+ sorbet-runtime (>= 0.5.9204)
80
+ thor (>= 0.19.2)
81
+ tapioca (0.11.4)
82
+ bundler (>= 2.2.25)
83
+ netrc (>= 0.11.0)
84
+ parallel (>= 1.21.0)
85
+ rbi (~> 0.0.0, >= 0.0.16)
86
+ sorbet-static-and-runtime (>= 0.5.10187)
87
+ spoom (~> 1.2.0, >= 1.2.0)
88
+ thor (>= 1.2.0)
89
+ yard-sorbet
90
+ thor (1.2.1)
91
+ unicode-display_width (2.4.2)
92
+ unparser (0.6.7)
93
+ diff-lcs (~> 1.3)
94
+ parser (>= 3.2.0)
40
95
  vcr (6.1.0)
41
96
  webmock (3.18.1)
42
97
  addressable (>= 2.8.0)
43
98
  crack (>= 0.3.2)
44
99
  hashdiff (>= 0.4.0, < 2.0.0)
100
+ webrick (1.7.0)
101
+ yard (0.9.28)
102
+ webrick (~> 1.7.0)
103
+ yard-sorbet (0.8.0)
104
+ sorbet-runtime (>= 0.5)
105
+ yard (>= 0.9)
45
106
 
46
107
  PLATFORMS
47
108
  arm64-darwin-20
48
109
  x86_64-linux
49
110
 
50
111
  DEPENDENCIES
51
- faraday (~> 2.7, >= 2.7.2)
112
+ amazing_print
113
+ byebug
52
114
  json_matchers
53
115
  parking_ticket!
54
116
  rake (~> 13.0)
55
117
  rspec (~> 3.0)
118
+ rubocop
119
+ rubocop-sorbet
120
+ sorbet
121
+ sorbet-runtime
122
+ tapioca
123
+ unparser
56
124
  vcr (~> 6.0)
57
125
  webmock (~> 3.12)
58
126
 
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  RSpec::Core::RakeTask.new(:spec)
7
7
 
data/bin/console CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- require "bundler/setup"
5
- require "parking_ticket"
4
+ require 'bundler/setup'
5
+ require 'parking_ticket'
6
6
 
7
7
  # You can add fixtures and/or initialization code here to make experimenting
8
8
  # with your gem easier. You can also use a different console, if you like.
@@ -11,5 +11,5 @@ require "parking_ticket"
11
11
  # require "pry"
12
12
  # Pry.start
13
13
 
14
- require "irb"
14
+ require 'irb'
15
15
  IRB.start(__FILE__)
data/bin/tapioca ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ #
5
+ # This file was generated by Bundler.
6
+ #
7
+ # The application 'tapioca' is installed as part of a gem, and
8
+ # this file is here to facilitate running it.
9
+ #
10
+
11
+ require 'pathname'
12
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile',
13
+ Pathname.new(__FILE__).realpath)
14
+
15
+ bundle_binstub = File.expand_path('bundle', __dir__)
16
+
17
+ if File.file?(bundle_binstub)
18
+ if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/
19
+ load(bundle_binstub)
20
+ else
21
+ abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
22
+ Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
23
+ end
24
+ end
25
+
26
+ require 'rubygems'
27
+ require 'bundler/setup'
28
+
29
+ load Gem.bin_path('tapioca', 'tapioca')
@@ -0,0 +1,15 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module ParkingTicket
5
+ module Clients
6
+ module Models
7
+ class PaymentMethod < T::Struct
8
+ include ParkingTicket::Clients::Models::StructuralyComparable
9
+ const :client_internal_id, String
10
+ const :anonymised_card_number, String
11
+ const :payment_card_type, String
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module ParkingTicket
5
+ module Clients
6
+ module Models
7
+ class Quote < T::Struct
8
+ include ParkingTicket::Clients::Models::StructuralyComparable
9
+ const :client_internal_id, String
10
+ const :starts_on, DateTime
11
+ const :ends_on, DateTime
12
+ const :cost, Float
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,19 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module ParkingTicket
5
+ module Clients
6
+ module Models
7
+ class RateOption < T::Struct
8
+ include ParkingTicket::Clients::Models::StructuralyComparable
9
+
10
+ const :client_internal_id, String
11
+ const :name, String
12
+ const :type, String
13
+ const :accepted_time_units, T::Array[String]
14
+
15
+ prop :free, T.nilable(T::Boolean)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ # typed: false
2
+ # frozen_string_literal: true
3
+
4
+ module ParkingTicket
5
+ module Clients
6
+ module Models
7
+ module StructuralyComparable
8
+ def ==(other)
9
+ serialize == other.serialize
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module ParkingTicket
5
+ module Clients
6
+ module Models
7
+ class Ticket < T::Struct
8
+ include ParkingTicket::Clients::Models::StructuralyComparable
9
+
10
+ const :client_internal_id, String
11
+ const :starts_on, DateTime
12
+ const :ends_on, DateTime
13
+ const :license_plate, String
14
+ const :cost, Float
15
+ const :client, String
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module ParkingTicket
5
+ module Clients
6
+ module Models
7
+ class Vehicle < T::Struct
8
+ include ParkingTicket::Clients::Models::StructuralyComparable
9
+
10
+ const :client_internal_id, String
11
+ const :license_plate, String
12
+ const :vehicle_type, String
13
+ const :vehicle_description, T.nilable(String)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,108 +1,162 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
1
4
  module ParkingTicket
2
5
  module Clients
3
6
  module PayByPhone
4
- class Adapter < Clients::Adapter
5
- ACCEPTED_TIME_UNIT_MAPPER = {
7
+ class Adapter
8
+ extend T::Sig
9
+
10
+ class << self
11
+ extend T::Sig
12
+ sig { returns(T.class_of(ParkingTicket::Clients::PayByPhone::Client)) }
13
+ def client_class
14
+ ParkingTicket::Clients::PayByPhone::Client
15
+ end
16
+
17
+ sig { params(username: String, password: String).returns(T::Boolean) }
18
+ def valid_credentials?(username, password)
19
+ client_class.auth(username, password).status == 200
20
+ end
21
+ end
22
+
23
+ ACCEPTED_TIME_UNIT_MAPPER = T.let({
6
24
  'Days' => 'days',
7
25
  'Minutes' => 'minutes',
8
26
  'Hours' => 'hours'
9
- }.freeze
27
+ }.freeze, T::Hash[String, String])
10
28
 
11
- PAYMENT_CARD_TYPE_MAPPER = {
29
+ PAYMENT_CARD_TYPE_MAPPER = T.let({
12
30
  'MasterCard' => 'master_card',
13
31
  'Visa' => 'visa'
14
- }.freeze
32
+ }.freeze, T::Hash[String, String])
15
33
 
16
- VEHICLE_TYPE_MAPPER = {
34
+ VEHICLE_TYPE_MAPPER = T.let({
17
35
  'Car' => 'combustion_car',
18
36
  'ElectricMotorcycle' => 'electric_motorcycle'
19
- }.freeze
37
+ }.freeze, T::Hash[String, String])
20
38
 
21
- private
39
+ class Error < StandardError; end
40
+
41
+ sig { params(username: String, password: String).void }
42
+ def initialize(username, password)
43
+ @username = username
44
+ @password = password
45
+ @valid_credentials = T.let(self.class.valid_credentials?(username, password), T::Boolean)
46
+ @client = T.let(self.class.client_class.new(@username, @password), ParkingTicket::Clients::PayByPhone::Client)
47
+ end
22
48
 
23
- def fetch_and_map_vehicles
24
- client.vehicles.map do |vehicle|
25
- {
49
+ sig { returns(T::Array[ParkingTicket::Clients::Models::Vehicle]) }
50
+ def vehicles
51
+ raise_invalid_credentials! unless @valid_credentials
52
+ @client.vehicles.map do |vehicle|
53
+ ParkingTicket::Clients::Models::Vehicle.new(
26
54
  client_internal_id: vehicle['vehicleId'],
27
55
  license_plate: vehicle['licensePlate'],
28
- vehicle_type: VEHICLE_TYPE_MAPPER[vehicle['type']],
29
- vehicle_description: vehicle.dig("profile", "description"),
30
- }
56
+ vehicle_type: T.must(VEHICLE_TYPE_MAPPER[vehicle['type']]),
57
+ vehicle_description: vehicle.dig('profile', 'description')
58
+ )
31
59
  end
32
60
  end
33
61
 
34
- def fetch_and_map_rate_options(zipcode, license_plate)
35
- client.rate_options(zipcode, license_plate).map do |rate_option|
62
+ sig do
63
+ params(zipcode: String, license_plate: String).returns(T::Array[ParkingTicket::Clients::Models::RateOption])
64
+ end
65
+ def rate_options(zipcode, license_plate)
66
+ raise_invalid_credentials! unless @valid_credentials
67
+ @client.rate_options(zipcode, license_plate).map do |rate_option|
36
68
  mapped_time_units = rate_option['acceptedTimeUnits'].map do |accepted_time_unit|
37
69
  ACCEPTED_TIME_UNIT_MAPPER[accepted_time_unit]
38
70
  end
39
- time_unit = mapped_time_units.include?('days') ? 'days' : 'hours'
40
- {
71
+ ParkingTicket::Clients::Models::RateOption.new(
41
72
  client_internal_id: rate_option['rateOptionId'],
42
73
  name: rate_option['name'],
43
74
  type: rate_option['type'],
44
- accepted_time_units: mapped_time_units,
45
- free: fetch_and_map_quote(rate_option['rateOptionId'], zipcode, license_plate, 1, time_unit)[:cost].zero?
46
- }
75
+ accepted_time_units: mapped_time_units
76
+ )
47
77
  end
48
78
  end
49
79
 
50
- def fetch_and_map_running_ticket(license_plate, zipcode)
51
- client.running_tickets.filter do |ticket|
80
+ sig do
81
+ params(license_plate: String, zipcode: String).returns(T.nilable(ParkingTicket::Clients::Models::Ticket))
82
+ end
83
+ def running_ticket(license_plate, zipcode)
84
+ raise_invalid_credentials! unless @valid_credentials
85
+ @client.running_tickets.filter do |ticket|
52
86
  ticket.dig('vehicle', 'licensePlate') == license_plate && ticket['locationId'] == zipcode
53
87
  end.map do |ticket|
54
- {
88
+ ParkingTicket::Clients::Models::Ticket.new(
55
89
  client_internal_id: ticket['parkingSessionId'],
56
90
  starts_on: DateTime.parse(ticket['startTime']),
57
91
  ends_on: DateTime.parse(ticket['expireTime']),
58
92
  license_plate: ticket.dig('vehicle', 'licensePlate'),
59
93
  cost: ticket.dig('segments', 0, 'cost'),
60
94
  client: 'PayByPhone'
61
- }
95
+ )
62
96
  end.first
63
97
  end
64
98
 
65
- def request_new_ticket(license_plate:, zipcode:, rate_option_client_internal_id:, quantity:, time_unit:, payment_method_id:)
66
- mapped_time_unit = ACCEPTED_TIME_UNIT_MAPPER.key(time_unit)
99
+ sig do
100
+ returns(T::Array[ParkingTicket::Clients::Models::PaymentMethod])
101
+ end
102
+ def payment_methods
103
+ raise_invalid_credentials! unless @valid_credentials
104
+ @client.payment_methods.fetch('items').map do |payment_method|
105
+ ParkingTicket::Clients::Models::PaymentMethod.new(
106
+ client_internal_id: payment_method['id'],
107
+ anonymised_card_number: payment_method['maskedCardNumber'][-4..],
108
+ payment_card_type: PAYMENT_CARD_TYPE_MAPPER.fetch(payment_method['paymentCardType'])
109
+ )
110
+ end
111
+ end
67
112
 
68
- quote = fetch_and_map_quote(rate_option_client_internal_id, zipcode, license_plate, quantity,
69
- time_unit)
113
+ sig do
114
+ params(rate_option_id: String, zipcode: String, license_plate: String, quantity: Integer,
115
+ time_unit: String).returns(ParkingTicket::Clients::Models::Quote)
116
+ end
117
+ def quote(rate_option_id, zipcode, license_plate, quantity, time_unit)
118
+ raise_invalid_credentials! unless @valid_credentials
119
+ mapped_time_unit = T.must(ACCEPTED_TIME_UNIT_MAPPER.key(time_unit))
120
+ fetched_quote = @client.quote(rate_option_id, zipcode, license_plate, quantity, mapped_time_unit)
70
121
 
71
- client.new_ticket(
122
+ ParkingTicket::Clients::Models::Quote.new(
123
+ client_internal_id: fetched_quote['quoteId'],
124
+ starts_on: DateTime.parse(fetched_quote['parkingStartTime']),
125
+ ends_on: DateTime.parse(fetched_quote['parkingExpiryTime']),
126
+ cost: fetched_quote.dig('totalCost', 'amount').to_f
127
+ )
128
+ end
129
+
130
+ sig do
131
+ params(license_plate: String, zipcode: String, rate_option_client_internal_id: String, quantity: Integer,
132
+ time_unit: String, payment_method_id: T.nilable(String)).void
133
+ end
134
+ def new_ticket(license_plate:, zipcode:, rate_option_client_internal_id:, quantity:, time_unit:,
135
+ payment_method_id:)
136
+ raise_invalid_credentials! unless @valid_credentials
137
+
138
+ mapped_time_unit = ACCEPTED_TIME_UNIT_MAPPER.invert.fetch(time_unit)
139
+
140
+ quote = quote(rate_option_client_internal_id, zipcode, license_plate, quantity,
141
+ time_unit)
142
+
143
+ @client.new_ticket(
72
144
  license_plate: license_plate,
73
145
  zipcode: zipcode,
74
146
  rate_option_client_internal_id: rate_option_client_internal_id,
75
147
  quantity: quantity,
76
148
  time_unit: mapped_time_unit,
77
- quote_client_internal_id: quote[:client_internal_id],
78
- starts_on: quote[:starts_on],
149
+ quote_client_internal_id: quote.client_internal_id,
150
+ starts_on: quote.starts_on.to_s,
79
151
  payment_method_id: payment_method_id
80
152
  )
81
153
  end
82
154
 
83
- def fetch_and_map_payment_methods
84
- client.payment_methods['items'].map do |payment_method|
85
- {
86
- client_internal_id: payment_method['id'],
87
- anonymised_card_number: payment_method['maskedCardNumber'][-4..],
88
- payment_card_type: PAYMENT_CARD_TYPE_MAPPER[payment_method['paymentCardType']]
89
- }
90
- end
91
- end
92
-
93
- def fetch_and_map_quote(rate_option_id, zipcode, license_plate, quantity, time_unit)
94
- mapped_time_unit = ACCEPTED_TIME_UNIT_MAPPER.key(time_unit)
95
- fetched_quote = client.quote(rate_option_id, zipcode, license_plate, quantity, mapped_time_unit)
96
-
97
- {
98
- client_internal_id: fetched_quote['quoteId'],
99
- starts_on: fetched_quote['parkingStartTime'],
100
- ends_on: fetched_quote['parkingExpiryTime'],
101
- cost: fetched_quote.dig('totalCost', 'amount')
102
- }
155
+ sig { void }
156
+ def raise_invalid_credentials!
157
+ raise Error, 'Adapter credentials are not valid'
103
158
  end
104
159
  end
105
160
  end
106
161
  end
107
162
  end
108
-