freight_kit 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +5 -0
  3. data/Gemfile.lock +201 -0
  4. data/MIT-LICENSE +31 -0
  5. data/README.md +153 -0
  6. data/VERSION +1 -0
  7. data/accessorial_symbols.txt +95 -0
  8. data/freight_kit.gemspec +58 -0
  9. data/lib/freight_kit/carrier.rb +473 -0
  10. data/lib/freight_kit/carriers.rb +24 -0
  11. data/lib/freight_kit/contact.rb +17 -0
  12. data/lib/freight_kit/error.rb +5 -0
  13. data/lib/freight_kit/errors/document_not_found_error.rb +5 -0
  14. data/lib/freight_kit/errors/expired_credentials_error.rb +5 -0
  15. data/lib/freight_kit/errors/http_error.rb +25 -0
  16. data/lib/freight_kit/errors/invalid_credentials_error.rb +5 -0
  17. data/lib/freight_kit/errors/response_error.rb +16 -0
  18. data/lib/freight_kit/errors/shipment_not_found_error.rb +5 -0
  19. data/lib/freight_kit/errors/unserviceable_accessorials_error.rb +17 -0
  20. data/lib/freight_kit/errors/unserviceable_error.rb +5 -0
  21. data/lib/freight_kit/errors.rb +10 -0
  22. data/lib/freight_kit/model.rb +17 -0
  23. data/lib/freight_kit/models/credential.rb +117 -0
  24. data/lib/freight_kit/models/date_time.rb +37 -0
  25. data/lib/freight_kit/models/document_response.rb +17 -0
  26. data/lib/freight_kit/models/label.rb +13 -0
  27. data/lib/freight_kit/models/location.rb +108 -0
  28. data/lib/freight_kit/models/pickup_response.rb +19 -0
  29. data/lib/freight_kit/models/price.rb +38 -0
  30. data/lib/freight_kit/models/rate.rb +81 -0
  31. data/lib/freight_kit/models/rate_response.rb +15 -0
  32. data/lib/freight_kit/models/response.rb +21 -0
  33. data/lib/freight_kit/models/shipment.rb +66 -0
  34. data/lib/freight_kit/models/shipment_event.rb +38 -0
  35. data/lib/freight_kit/models/tracking_response.rb +75 -0
  36. data/lib/freight_kit/models.rb +17 -0
  37. data/lib/freight_kit/package.rb +313 -0
  38. data/lib/freight_kit/package_item.rb +65 -0
  39. data/lib/freight_kit/packaging.rb +52 -0
  40. data/lib/freight_kit/platform.rb +36 -0
  41. data/lib/freight_kit/shipment_packer.rb +116 -0
  42. data/lib/freight_kit/tariff.rb +29 -0
  43. data/lib/freight_kit/version.rb +5 -0
  44. data/lib/freight_kit.rb +34 -0
  45. data/service_type_symbols.txt +4 -0
  46. data/shipment_event_symbols.txt +17 -0
  47. metadata +453 -0
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # Class representing credentials.
5
+ #
6
+ # @!attribute kind
7
+ # What kind?
8
+ # @return [Symbol] One of `:api`, `:api_key`, `:oauth2`, `:website`
9
+ #
10
+ # @!attribute access_token
11
+ # Access token when type is `:oauth2`
12
+ # @return [String] Access token
13
+ #
14
+ # @!attribute expires_at
15
+ # Token expiration date/time when type is `:oauth2`
16
+ # @return [DateTime] Token expiration date/time
17
+ #
18
+ # @!attribute scope
19
+ # Scope when type is `:oauth2`
20
+ # @return [String] Scope
21
+ #
22
+ # @!attribute username
23
+ # Username when type is one of `:api`, `:website`
24
+ # @return [String] Username
25
+ #
26
+ # @!attribute password
27
+ # Password when type is one of `:api`, `:website`
28
+ # @return [String] Username
29
+ #
30
+ class Credential < Model
31
+ attr_accessor :type
32
+
33
+ # Returns a new instance of Credential.
34
+ #
35
+ # Other than the following, instance `:attr_reader`s are generated dynamically based on keys.
36
+ #
37
+ # @param [Symbol] type One of `:api`, `:website`
38
+ # @param [String] base_url Required when type is `:selenoid`
39
+ # @param [String] username Required when type is one of `:api`, `:website`
40
+ # @param [String] password Required when type is one of `:api`, `:website`
41
+ # @param [String] access_token Required when type is `:oauth2`
42
+ # @param [DateTime] expires_at Required when type is `:oauth2`
43
+ # @param [String] scope Required when type is `:oauth2`
44
+ # @param [String] proxy_url Required when type is `:api_proxy`
45
+ def initialize(hash)
46
+ raise ArgumentError, 'Credential#new: `type` cannot be blank' if hash[:type].blank?
47
+
48
+ type = hash[:type]
49
+
50
+ requirements = case type
51
+ when :api_key
52
+ { api_key: String }
53
+ when :api, :website
54
+ { password: String }
55
+ when :api_proxy
56
+ { api_key: String, proxy_url: String }
57
+ when :oauth2
58
+ { access_token: String, expires_at: ::DateTime, scope: String }
59
+ when :selenoid
60
+ { base_url: URI, browser: Symbol }
61
+ else
62
+ {}
63
+ end
64
+
65
+ requirements.each_key do |k|
66
+ raise ArgumentError, "Credential#new: `#{k}` cannot be blank" if hash[k].blank?
67
+
68
+ unless hash[k].is_a?(requirements[k])
69
+ raise ArgumentError, "Credential#new: `#{k}` must be a #{requirements[k]}, got #{hash[k].class}"
70
+ end
71
+ end
72
+
73
+ hash.each do |k, _v|
74
+ next if k == :type
75
+
76
+ singleton_class.class_eval { attr_accessor(k.to_s) } unless singleton_class.respond_to?(k)
77
+ end
78
+
79
+ super
80
+ end
81
+
82
+ def selenoid_options
83
+ return unless type == :selenoid
84
+ return @selenoid_options if @selenoid_options.present?
85
+
86
+ download_url = base_url.dup
87
+ download_url.path = '/download'
88
+ download_url = download_url.to_s
89
+
90
+ @selenoid_options = { download_url: }
91
+ end
92
+
93
+ def watir_args
94
+ return unless type == :selenoid
95
+ return @watir_args if @watir_args.present?
96
+
97
+ url = base_url.dup
98
+ url.path = '/wd/hub/'
99
+ url = url.to_s
100
+
101
+ @watir_args = [
102
+ browser,
103
+ {
104
+ options: {
105
+ prefs: {
106
+ download: {
107
+ directory_upgrade: true,
108
+ prompt_for_download: false
109
+ }
110
+ }
111
+ },
112
+ url:
113
+ },
114
+ ]
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # Represent dates and times in varous formats.
5
+ #
6
+ # @attribute date_time_with_zone
7
+ # Date and time with time zone.
8
+ # @return [ActiveSupport::TimeWithZone]
9
+ #
10
+ # @attribute local_date
11
+ # Local date.
12
+ # @return [Date]
13
+ #
14
+ # @attribute local_date_time
15
+ # Local date and time in the format `"YYYY-MM-DD HH:MM:SS"`
16
+ # (zero-padded 24 hour clock) aka `DateTime#to_fs(:db)` format.
17
+ # @return [String]
18
+ #
19
+ class DateTime < Model
20
+ attr_accessor :local_date, :local_date_time, :location, :date_time_with_zone
21
+
22
+ def initialize(*)
23
+ super
24
+
25
+ attempt_upgrade_using_location(location) if location.present?
26
+ end
27
+
28
+ private
29
+
30
+ def attempt_upgrade_using_location(location)
31
+ return if @date_time_with_zone.present? || @local_date_time.blank? || location.time_zone.blank?
32
+
33
+ @date_time_with_zone = location.time_zone.parse(@local_date_time)
34
+ @local_date_time = nil
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # Represents the response to calls:
5
+ # - {FreightKit::Carrier#bol}
6
+ # - {FreightKit::Carrier#pod}
7
+ # - {FreightKit::Carrier#scanned_bol}
8
+ #
9
+ # @attribute content_type
10
+ # @return [String] The HTTP `Content-Type`
11
+ #
12
+ # @attribute data
13
+ # @return [String] Raw document data.
14
+ class DocumentResponse < Response
15
+ attr_accessor :content_type, :data
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # Class representing a shipping option with estimated price.
5
+ #
6
+ # @!attribute data
7
+ # The label image data.
8
+ # @return [String]
9
+ #
10
+ class Label < Model
11
+ attr_accessor :data
12
+ end
13
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # Class representing a location.
5
+ #
6
+ # @attribute address1
7
+ # The first street line
8
+ # @return [String, nil]
9
+ #
10
+ # @attribute address2
11
+ # The second street line
12
+ # @return [String, nil]
13
+ #
14
+ # @attribute address3
15
+ # The third street line
16
+ # @return [String, nil]
17
+ #
18
+ # @attribute city
19
+ # The city name.
20
+ # @return [String, nil]
21
+ #
22
+ # @attribute contact
23
+ # The contact at the location.
24
+ # @return [String, nil]
25
+ #
26
+ # @attribute country
27
+ # The country of the location.
28
+ # @return [ActiveUtils::Country, nil]
29
+ #
30
+ # @attribute lat
31
+ # The latitude of the location.
32
+ # @return [BigNum, nil]
33
+ #
34
+ # @attribute lng
35
+ # The longitude of the location.
36
+ # @return [BigNum, nil]
37
+ #
38
+ # @attribute postal_code
39
+ # The postal code (or ZIP® code) of the location.
40
+ # @return [String, nil]
41
+ #
42
+ # @attribute province
43
+ # The province (or state/territory) abbreviation of the location.
44
+ # @return [String, nil]
45
+ #
46
+ # @attribute type
47
+ # The type of the location.
48
+ #
49
+ # It should be one of: :commercial, :po_box, :residential
50
+ #
51
+ # @return [Symbol, nil]
52
+ #
53
+ class Location < Model
54
+ TYPES = %i[commercial po_box residential].freeze
55
+
56
+ attr_accessor :address1, :address2, :address3, :city, :postal_code, :province
57
+ attr_reader :contact, :country, :lat, :lng, :type
58
+
59
+ def contact=(contact)
60
+ return @contact = nil if contact.blank?
61
+
62
+ raise ArgumentError, 'contact must be a Contact' unless contact.is_a?(FreightKit::Contact)
63
+
64
+ @contact = contact
65
+ end
66
+
67
+ def country=(country)
68
+ return country = nil if country.blank?
69
+
70
+ if country.is_a?(ActiveUtils::Country)
71
+ @country = country
72
+ return country
73
+ end
74
+
75
+ raise ArgumentError, 'country must be an ActiveUtils::Country'
76
+ end
77
+
78
+ def lat=(num)
79
+ return @lat = nil if num.blank?
80
+
81
+ return @lat = num if num.is_a?(BigNum)
82
+
83
+ raise ArgumentError, 'lat must be a BigNum'
84
+ end
85
+
86
+ def lng=(num)
87
+ return @lng = nil if num.blank?
88
+
89
+ return @lng = num if num.is_a?(BigNum)
90
+
91
+ raise ArgumentError, 'lng must be a BigNum'
92
+ end
93
+
94
+ def time_zone
95
+ return if country&.code(:alpha2)&.blank? || province.blank? || city.blank?
96
+
97
+ PlaceKit.lookup(country.code(:alpha2).to_s, province, city)
98
+ end
99
+
100
+ def type=(value)
101
+ return @type = nil if value.blank?
102
+
103
+ raise ArgumentError, "type must be one of :#{TYPES.join(", :")}" unless TYPES.include?(value)
104
+
105
+ @type = value
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # The `PickupResponse` object is returned by the {FreightKit::Carrier#create_pickup}
5
+ # call. The most important method is {#pickup_number}, which will return the pickup reference
6
+ # number.
7
+ #
8
+ # @!attribute labels
9
+ # Shipping labels.
10
+ # @return [Array<FreightKit::Label>]
11
+ #
12
+ # @!attribute pickup_number
13
+ # Pickup reference number.
14
+ # @return [String]
15
+ #
16
+ class PickupResponse < Response
17
+ attr_accessor :labels, :pickup_number
18
+ end
19
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # Class representing a price.
5
+ #
6
+ # @!attribute blame
7
+ # Where did the cost come from?
8
+ # @return [Symbol] One of :api, :library, :tariff
9
+ #
10
+ # @!attribute description
11
+ # Description.
12
+ # @return [String]
13
+ #
14
+ # @!attribute objects
15
+ # Array of objects that the price applies to.
16
+ # @return [Array]
17
+ #
18
+ # @!attribute cents
19
+ # The price in cents.
20
+ # @return [Integer]
21
+ #
22
+ class Price < Model
23
+ attr_accessor :description, :objects
24
+ attr_writer :blame, :cents
25
+
26
+ def blame
27
+ return @blame if %i[api library tariff].include?(@blame)
28
+
29
+ raise 'blame must be one of :api, :library, :tariff'
30
+ end
31
+
32
+ def cents
33
+ return @cents if @cents.is_a?(Integer)
34
+
35
+ raise 'cents must be an `Integer`'
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # Class representing a shipping option with estimated price.
5
+ #
6
+ # @!attribute carrier
7
+ # The carrier.
8
+ # @return [FreightKit::Carrier]
9
+ # @see FreightKit::Carrier
10
+ #
11
+ # @!attribute carrier_name
12
+ # Name of the carrier. It may differ from the `Carrier` providing the rate quote
13
+ # when the `Carrier` is acting as a broker.
14
+ # @return [String]
15
+ #
16
+ # @!attribute currency
17
+ # ISO4217 currency code of the quoted rate estimates (e.g. `CAD`, `EUR`, or `USD`)
18
+ # @return [String]
19
+ # @see http://en.wikipedia.org/wiki/ISO_4217
20
+ #
21
+ # @!attribute estimate_reference
22
+ # Quote number.
23
+ # @return [String]
24
+ #
25
+ # @!attribute expires_at
26
+ # When the rate estimate will expire.
27
+ # @return [DateTime]
28
+ #
29
+ # @!attribute prices
30
+ # Breakdown of a rate estimate's prices with amounts in cents.
31
+ # @return [Array<Prices>]
32
+ # @see FreightKit::Price
33
+ #
34
+ # @!attribute scac
35
+ # SCAC code of the carrier. It may differ from the `Carrier` providing the rate
36
+ # estimate when the `Carrier` is acting as a broker.
37
+ # @return [String]
38
+ #
39
+ # @!attribute service_name
40
+ # The name of the shipping service (e.g. 'First Class Ground')
41
+ # @return [String]
42
+ #
43
+ # @!attribute shipment
44
+ # The shipment.
45
+ # @return [FreightKit::Shipment]
46
+ #
47
+ # @!attribute transit_days
48
+ # Estimated transit days after date of pickup.
49
+ # @return [Integer]
50
+ #
51
+ # @!attribute with_excessive_length_fees
52
+ # When the rate estimate `Price`s include applicable excessive length fees.
53
+ # @return [Integer]
54
+ #
55
+ class Rate < Model
56
+ attr_accessor :carrier,
57
+ :carrier_name,
58
+ :estimate_reference,
59
+ :expires_at,
60
+ :prices,
61
+ :scac,
62
+ :service_name,
63
+ :shipment,
64
+ :transit_days,
65
+ :with_excessive_length_fees
66
+
67
+ attr_writer :currency
68
+
69
+ def currency
70
+ ActiveUtils::CurrencyCode.standardize(@currency)
71
+ end
72
+
73
+ # The total price of the shipment in cents.
74
+ # @return [Integer]
75
+ def total_cents
76
+ return 0 if @prices.blank?
77
+
78
+ @prices.sum(&:cents)
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # The `RateResponse` object is returned by the {FreightKit::Carrier#find_rates}
5
+ # call. The most important method is {#rates}, which will return a list of possible
6
+ # shipping options with an estimated price.
7
+ #
8
+ # @!attribute rates
9
+ # The available rate options for the shipment, with an estimated price.
10
+ # @return [Array<FreightKit::Rate>]
11
+ #
12
+ class RateResponse < Response
13
+ attr_accessor :rates
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # Basic Response class for requests against a carrier's API.
5
+ #
6
+ # @!attribute error
7
+ # The error object.
8
+ # @return [FreightKit::Error, NilClass]
9
+ #
10
+ # @!attribute request
11
+ # The raw request.
12
+ # @return [String]
13
+ #
14
+ # @!attribute response
15
+ # The raw response.
16
+ # @return [String]
17
+ #
18
+ class Response < Model
19
+ attr_accessor :error, :request, :response
20
+ end
21
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # Shipment is the abstract base class for all rate requests.
5
+ #
6
+ # @!attribute accessorials [Hash<Symbol>] Acceessorials requested.
7
+ # @!attribute declared_value_cents [Integer] Declared value in cents.
8
+ # @!attribute destination [FreightKit::Location] Where the package will go.
9
+ # @!attribute origin [FreightKit::Location] Where the shipment will originate from.
10
+ # @!attribute order_number [String] Order number (also known as shipper number, SO #).
11
+ # @!attribute packages [Array<FreightKit::Package>] The list of packages that will
12
+ # be in the shipment.
13
+ # @!attribute po_number [String] Purchase order number (also known as PO #).
14
+ # @!attribute pickup_at [FreightKit::DateTime] Pickup date/time.
15
+ class Shipment < Model
16
+ attr_accessor :accessorials,
17
+ :declared_value_cents,
18
+ :destination,
19
+ :origin,
20
+ :order_number,
21
+ :packages,
22
+ :po_number,
23
+ :pro
24
+ attr_reader :pickup_at
25
+
26
+ def loose?
27
+ return false if @packages.blank?
28
+
29
+ packages.map(&:packaging).map(&:pallet?).none?(true)
30
+ end
31
+
32
+ def hazmat?
33
+ packages.map(&:hazmat?).any?(true)
34
+ end
35
+
36
+ def loose_and_palletized?
37
+ !loose? && !palletized?
38
+ end
39
+
40
+ def palletized?
41
+ return false if @packages.blank?
42
+
43
+ packages.map(&:packaging).map(&:pallet?).none?(false)
44
+ end
45
+
46
+ def pickup_at=(date_time)
47
+ if date_time.is_a?(ActiveSupport::TimeWithZone)
48
+ @pickup_at = FreightKit::DateTime.new(date_time_with_zone: date_time)
49
+ return
50
+ end
51
+
52
+ raise ArgumentError, 'date_time must be an FreightKit::DateTime' unless date_time.is_a?(DateTime)
53
+
54
+ @pickup_at = date_time
55
+ end
56
+
57
+ def valid?
58
+ return false if @accessorials.nil?
59
+ return false unless @destination.is_a?(Location)
60
+ return false unless @packages.is_a?(Array)
61
+ return false if @packages.any? { |p| p.class != Package }
62
+
63
+ true
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # `ShipmentEvent` is the abstract base class for all shipment events (usually
5
+ # attached to `TrackingEresponse`).
6
+ #
7
+ # @attribute date_time
8
+ # @return [DateTime] Date and time the event occurred.
9
+ #
10
+ # @attribute location
11
+ # @return [Location] Location the event occurred.
12
+ #
13
+ # @attribute type_code
14
+ # @return [Symbol] One of:
15
+ # ```
16
+ # :arrived_at_terminal
17
+ # :delayed_due_to_weather
18
+ # :delivered
19
+ # :delivery_appointment_scheduled
20
+ # :departed
21
+ # :found
22
+ # :located
23
+ # :lost
24
+ # :out_for_delivery
25
+ # :pending_delivery_appointment
26
+ # :picked_up
27
+ # :pickup_driver_assigned
28
+ # :pickup_information_received_by_carrier
29
+ # :pickup_information_sent_to_carrier
30
+ # :sailed
31
+ # :trailer_closed
32
+ # :trailer_unloaded
33
+ # ```
34
+ #
35
+ class ShipmentEvent < Model
36
+ attr_accessor :date_time, :location, :type_code
37
+ end
38
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FreightKit
4
+ # Represents the response to a {FreightKit::Carrier#find_tracking_info} call.
5
+ #
6
+ # @note Some carriers provide more information than others, so not all attributes
7
+ # will be set, depending on what carrier you are using.
8
+ #
9
+ # @!attribute actual_delivery_date
10
+ # @return [DateTime]
11
+ #
12
+ # @!attribute attempted_delivery_date
13
+ # @return [DateTime]
14
+ #
15
+ # @!attribute carrier
16
+ # @return [Symbol]
17
+ #
18
+ # @!attribute carrier_name
19
+ # @return [String]
20
+ #
21
+ # @!attribute delivery_signature
22
+ # @return [String]
23
+ #
24
+ # @!attribute destination
25
+ # @return [FreightKit::Location]
26
+ #
27
+ # @!attribute estimated_delivery_date
28
+ # @return [FreightKit::DateTime]
29
+ #
30
+ # @!attribute origin
31
+ # @return [FreightKit::Location]
32
+ #
33
+ # @!attribute scheduled_delivery_date
34
+ # @return [DateTime]
35
+ #
36
+ # @!attribute ship_time
37
+ # @return [Date, Time]
38
+ #
39
+ # @!attribute shipment_events
40
+ # @return [Array<FreightKit::ShipmentEvent>]
41
+ #
42
+ # @!attribute shipper_address
43
+ # @return [FreightKit::Location]
44
+ #
45
+ # @!attribute status
46
+ # @return [Symbol]
47
+ #
48
+ # @!attribute status_code
49
+ # @return [string]
50
+ #
51
+ # @!attribute status_description
52
+ # @return [String]
53
+ #
54
+ # @!attribute tracking_number
55
+ # @return [String]
56
+ #
57
+ class TrackingResponse < Response
58
+ attr_accessor :actual_delivery_date,
59
+ :attempted_delivery_date,
60
+ :carrier,
61
+ :carrier_name,
62
+ :delivery_signature,
63
+ :destination,
64
+ :estimated_delivery_date,
65
+ :origin,
66
+ :scheduled_delivery_date,
67
+ :ship_time,
68
+ :shipment_events,
69
+ :shipper_address,
70
+ :status,
71
+ :status_code,
72
+ :status_description,
73
+ :tracking_number
74
+ end
75
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'freight_kit/models/credential'
4
+ require 'freight_kit/models/label'
5
+ require 'freight_kit/models/price'
6
+ require 'freight_kit/models/rate'
7
+ require 'freight_kit/models/shipment'
8
+
9
+ require 'freight_kit/models/date_time'
10
+ require 'freight_kit/models/location'
11
+
12
+ require 'freight_kit/models/response'
13
+ require 'freight_kit/models/document_response'
14
+ require 'freight_kit/models/pickup_response'
15
+ require 'freight_kit/models/rate_response'
16
+ require 'freight_kit/models/shipment_event'
17
+ require 'freight_kit/models/tracking_response'