freight_kit 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +201 -0
- data/MIT-LICENSE +31 -0
- data/README.md +153 -0
- data/VERSION +1 -0
- data/accessorial_symbols.txt +95 -0
- data/freight_kit.gemspec +58 -0
- data/lib/freight_kit/carrier.rb +473 -0
- data/lib/freight_kit/carriers.rb +24 -0
- data/lib/freight_kit/contact.rb +17 -0
- data/lib/freight_kit/error.rb +5 -0
- data/lib/freight_kit/errors/document_not_found_error.rb +5 -0
- data/lib/freight_kit/errors/expired_credentials_error.rb +5 -0
- data/lib/freight_kit/errors/http_error.rb +25 -0
- data/lib/freight_kit/errors/invalid_credentials_error.rb +5 -0
- data/lib/freight_kit/errors/response_error.rb +16 -0
- data/lib/freight_kit/errors/shipment_not_found_error.rb +5 -0
- data/lib/freight_kit/errors/unserviceable_accessorials_error.rb +17 -0
- data/lib/freight_kit/errors/unserviceable_error.rb +5 -0
- data/lib/freight_kit/errors.rb +10 -0
- data/lib/freight_kit/model.rb +17 -0
- data/lib/freight_kit/models/credential.rb +117 -0
- data/lib/freight_kit/models/date_time.rb +37 -0
- data/lib/freight_kit/models/document_response.rb +17 -0
- data/lib/freight_kit/models/label.rb +13 -0
- data/lib/freight_kit/models/location.rb +108 -0
- data/lib/freight_kit/models/pickup_response.rb +19 -0
- data/lib/freight_kit/models/price.rb +38 -0
- data/lib/freight_kit/models/rate.rb +81 -0
- data/lib/freight_kit/models/rate_response.rb +15 -0
- data/lib/freight_kit/models/response.rb +21 -0
- data/lib/freight_kit/models/shipment.rb +66 -0
- data/lib/freight_kit/models/shipment_event.rb +38 -0
- data/lib/freight_kit/models/tracking_response.rb +75 -0
- data/lib/freight_kit/models.rb +17 -0
- data/lib/freight_kit/package.rb +313 -0
- data/lib/freight_kit/package_item.rb +65 -0
- data/lib/freight_kit/packaging.rb +52 -0
- data/lib/freight_kit/platform.rb +36 -0
- data/lib/freight_kit/shipment_packer.rb +116 -0
- data/lib/freight_kit/tariff.rb +29 -0
- data/lib/freight_kit/version.rb +5 -0
- data/lib/freight_kit.rb +34 -0
- data/service_type_symbols.txt +4 -0
- data/shipment_event_symbols.txt +17 -0
- 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,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'
|