freight_kit 0.1.15 → 0.1.16
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/Gemfile.lock +96 -43
- data/README.md +28 -6
- data/VERSION +1 -1
- data/configuration/carriers/abfs.yml +124 -0
- data/configuration/carriers/btvp.yml +84 -0
- data/configuration/carriers/ccyq.yml +121 -0
- data/configuration/carriers/clni.yml +113 -0
- data/configuration/carriers/cnwy.yml +113 -0
- data/configuration/carriers/ctbv.yml +117 -0
- data/configuration/carriers/dcha.yml +105 -0
- data/configuration/carriers/dlds.yml +111 -0
- data/configuration/carriers/dphe.yml +130 -0
- data/configuration/carriers/drrq.yml +131 -0
- data/configuration/carriers/fcsy.yml +102 -0
- data/configuration/carriers/fwda.yml +137 -0
- data/configuration/carriers/jfj_transportation.yml +2 -0
- data/configuration/carriers/mtvl.yml +12 -0
- data/configuration/carriers/numk.yml +14 -0
- data/configuration/carriers/otcl.yml +124 -0
- data/configuration/carriers/pens.yml +22 -0
- data/configuration/carriers/rdfs.yml +142 -0
- data/configuration/carriers/saia.yml +129 -0
- data/configuration/carriers/sefl.yml +115 -0
- data/configuration/carriers/totl.yml +111 -0
- data/configuration/carriers/tqyl.yml +28 -0
- data/configuration/carriers/wrds.yml +20 -0
- data/configuration/platforms/carrier_logistics.yml +25 -0
- data/configuration/platforms/next.yml +12 -0
- data/configuration/platforms/the_great_information_factory.yml +122 -0
- data/freight_kit.gemspec +9 -7
- data/lib/freight_kit/api_clients/soap_client.rb +70 -0
- data/lib/freight_kit/api_clients.rb +3 -0
- data/lib/freight_kit/carriers/abfs.rb +421 -0
- data/lib/freight_kit/carriers/btvp.rb +29 -0
- data/lib/freight_kit/carriers/ccyq.rb +317 -0
- data/lib/freight_kit/carriers/clni.rb +396 -0
- data/lib/freight_kit/carriers/cnwy.rb +327 -0
- data/lib/freight_kit/carriers/ctbv.rb +53 -0
- data/lib/freight_kit/carriers/dcha.rb +76 -0
- data/lib/freight_kit/carriers/dlds.rb +49 -0
- data/lib/freight_kit/carriers/dphe.rb +474 -0
- data/lib/freight_kit/carriers/drrq.rb +580 -0
- data/lib/freight_kit/carriers/fcsy.rb +57 -0
- data/lib/freight_kit/carriers/fwda.rb +744 -0
- data/lib/freight_kit/carriers/jfj_transportation.rb +13 -0
- data/lib/freight_kit/carriers/mtvl.rb +34 -0
- data/lib/freight_kit/carriers/numk.rb +58 -0
- data/lib/freight_kit/carriers/otcl.rb +528 -0
- data/lib/freight_kit/carriers/pens.rb +204 -0
- data/lib/freight_kit/carriers/rdfs.rb +521 -0
- data/lib/freight_kit/carriers/saia.rb +438 -0
- data/lib/freight_kit/carriers/sefl.rb +342 -0
- data/lib/freight_kit/carriers/totl.rb +172 -0
- data/lib/freight_kit/carriers/tqyl.rb +339 -0
- data/lib/freight_kit/carriers/wrds.rb +246 -0
- data/lib/freight_kit/carriers.rb +26 -0
- data/lib/freight_kit/helpers/documentable.rb +13 -0
- data/lib/freight_kit/helpers/pickupable.rb +39 -0
- data/lib/freight_kit/helpers/rateable.rb +28 -0
- data/lib/freight_kit/helpers/trackable.rb +25 -0
- data/lib/freight_kit/helpers.rb +6 -0
- data/lib/freight_kit/platforms/carrier_logistics.rb +450 -0
- data/lib/freight_kit/platforms/next.rb +101 -0
- data/lib/freight_kit/platforms/the_great_information_factory.rb +528 -0
- data/lib/freight_kit/platforms.rb +5 -0
- data/lib/freight_kit.rb +20 -1
- metadata +94 -14
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FreightKit
|
|
4
|
+
class CNWY < Carrier
|
|
5
|
+
class << self
|
|
6
|
+
def maximum_height
|
|
7
|
+
Measured::Length.new(105, :inches)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def maximum_weight
|
|
11
|
+
Measured::Weight.new(10_000, :pounds)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def minimum_length_for_overlength_fees
|
|
15
|
+
Measured::Length.new(8, :feet)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def overlength_fees_require_tariff?
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def required_credential_types
|
|
23
|
+
%i[api api_key]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def requirements
|
|
27
|
+
%i[credentials]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
REACTIVE_FREIGHT_CARRIER = true
|
|
32
|
+
|
|
33
|
+
class << self
|
|
34
|
+
attr_reader :name, :scac
|
|
35
|
+
end
|
|
36
|
+
@name = 'XPO Logistics'
|
|
37
|
+
@scac = 'CNWY'
|
|
38
|
+
|
|
39
|
+
# Documents
|
|
40
|
+
|
|
41
|
+
# Pickups
|
|
42
|
+
|
|
43
|
+
# Rates
|
|
44
|
+
|
|
45
|
+
def find_rates(shipment:)
|
|
46
|
+
begin
|
|
47
|
+
validate_packages(shipment.packages)
|
|
48
|
+
rescue UnserviceableError => e
|
|
49
|
+
return RateResponse.new(error: e)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
request = build_rate_request(shipment:)
|
|
53
|
+
parse_rate_response(shipment:, response: commit(request))
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Tracking
|
|
57
|
+
|
|
58
|
+
protected
|
|
59
|
+
|
|
60
|
+
def build_headers
|
|
61
|
+
{
|
|
62
|
+
accept: 'application/json',
|
|
63
|
+
authorization: "Bearer #{bearer_token}",
|
|
64
|
+
'Content-Type': 'application/json'
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def bearer_token
|
|
69
|
+
@bearer_token ||= commit(build_bearer_token_request)[:access_token]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def build_bearer_token_request
|
|
73
|
+
api_credentials = fetch_credential(:api)
|
|
74
|
+
|
|
75
|
+
body = URI.encode_www_form(
|
|
76
|
+
grant_type: 'password',
|
|
77
|
+
password: api_credentials.password,
|
|
78
|
+
username: api_credentials.username,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
{
|
|
82
|
+
body:,
|
|
83
|
+
headers: {
|
|
84
|
+
authorization: "Basic #{api_credentials.api_key}",
|
|
85
|
+
content_type: 'application/x-www-form-urlencoded'
|
|
86
|
+
},
|
|
87
|
+
method: :post,
|
|
88
|
+
url: build_url(:token)
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def build_url(action)
|
|
93
|
+
scheme = @conf.dig(:api, :use_ssl) ? 'https://' : 'http://'
|
|
94
|
+
"#{scheme}#{@conf.dig(:api, :domain)}#{@conf.dig(:api, :endpoints, action)}"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def commit(request)
|
|
98
|
+
url = request[:url]
|
|
99
|
+
headers = request[:headers] || build_headers
|
|
100
|
+
method = request[:method]
|
|
101
|
+
body = request[:body]
|
|
102
|
+
|
|
103
|
+
response = case method
|
|
104
|
+
when :post
|
|
105
|
+
HTTParty.post(url, headers:, body:, debug_output: $stdout)
|
|
106
|
+
else
|
|
107
|
+
HTTParty.get(url, headers:, debug_output: $stdout)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
begin
|
|
111
|
+
json = JSON.parse(response.body).deep_symbolize_keys
|
|
112
|
+
rescue JSON::ParserError => e
|
|
113
|
+
# CNWY returns a string during runtime/server error
|
|
114
|
+
raise FreightKit::ResponseError, 'Runtime Error' if response.body.include?('Runtime Error')
|
|
115
|
+
|
|
116
|
+
raise e
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
error = if json.is_a?(Hash)
|
|
120
|
+
json[:error_description] || json.dig(:fault, :description) || json.dig(:error, :message)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
if error.blank?
|
|
124
|
+
return json if (200..299).include?(response.code)
|
|
125
|
+
else
|
|
126
|
+
case response.code
|
|
127
|
+
when 401
|
|
128
|
+
raise FreightKit::InvalidCredentialsError
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
raise FreightKit::ResponseError, error
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def request_url(action)
|
|
136
|
+
scheme = @conf.dig(:api, :use_ssl, action) ? 'https://' : 'http://'
|
|
137
|
+
"#{scheme}#{@conf.dig(:api, :domains, action)}#{@conf.dig(:api, :endpoints, action)}"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# Documents
|
|
141
|
+
|
|
142
|
+
# Rates
|
|
143
|
+
|
|
144
|
+
def build_accessorials(shipment:)
|
|
145
|
+
serviceable_accessorials?(shipment.accessorials)
|
|
146
|
+
|
|
147
|
+
accessorial_codes = []
|
|
148
|
+
accessorial_codes << 'SSC'
|
|
149
|
+
accessorial_codes << 'ZHM' if shipment.hazmat?
|
|
150
|
+
|
|
151
|
+
if shipment.destination.province.upcase == 'HI'
|
|
152
|
+
accessorial_codes = accessorial_codes.map { |code| ['DID', 'OIP'].include?(code) ? 'WHN' : code }.uniq
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
longest_dimension_in = shipment.packages.map { |p| [p.width(:inch), p.length(:inch)].max }.max.ceil
|
|
156
|
+
|
|
157
|
+
# Switch to accessorials rather than accessorial_codes since now we need more complex structures
|
|
158
|
+
|
|
159
|
+
accessorials = accessorial_codes.map { |accessorial_code| { accessorial_cd: accessorial_code, quantity: 0 } }
|
|
160
|
+
|
|
161
|
+
return accessorials if longest_dimension_in < 96 && shipment.accessorials.blank?
|
|
162
|
+
|
|
163
|
+
if longest_dimension_in >= 96
|
|
164
|
+
accessorials << {
|
|
165
|
+
accessorial_cd: 'ELS',
|
|
166
|
+
quantity_uom: 'INCH',
|
|
167
|
+
quantity: longest_dimension_in
|
|
168
|
+
}
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
return accessorials if shipment.accessorials.blank?
|
|
172
|
+
|
|
173
|
+
shipment.accessorials.map do |accessorial|
|
|
174
|
+
next if @conf.dig(:accessorials, :unquotable)&.include?(accessorial)
|
|
175
|
+
|
|
176
|
+
accessorials << { accessorial_cd: @conf.dig(:accessorials, :mappable, accessorial), quantity: 0 }
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
accessorials
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def parse_amount(amount)
|
|
183
|
+
(amount.to_f * 100).to_i
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def build_commodity(shipment:)
|
|
187
|
+
shipment.packages.map do |package|
|
|
188
|
+
{
|
|
189
|
+
dimensions: {
|
|
190
|
+
dimensions_uom: 'INCH',
|
|
191
|
+
height: package.inches(:height).ceil,
|
|
192
|
+
length: package.inches(:length).ceil,
|
|
193
|
+
width: package.inches(:width).ceil
|
|
194
|
+
},
|
|
195
|
+
gross_weight: {
|
|
196
|
+
weight: package.pounds(:total).ceil,
|
|
197
|
+
weight_uom: 'LBS'
|
|
198
|
+
},
|
|
199
|
+
hazmat_ind: package.hazmat?,
|
|
200
|
+
nmfc_class: package.freight_class.to_s,
|
|
201
|
+
nmfc_item_cd: package.nmfc,
|
|
202
|
+
piece_cnt: package.quantity
|
|
203
|
+
}
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def build_rate_request(shipment:)
|
|
208
|
+
api_credentials = fetch_credential(:api)
|
|
209
|
+
shipment_date = shipment.pickup_at.date_time_with_zone.iso8601
|
|
210
|
+
|
|
211
|
+
accessorials = build_accessorials(shipment:)
|
|
212
|
+
commodity = build_commodity(shipment:)
|
|
213
|
+
|
|
214
|
+
body = {
|
|
215
|
+
shipmentInfo: {
|
|
216
|
+
accessorials:,
|
|
217
|
+
bill_2_party: { acct_inst_id: api_credentials.account },
|
|
218
|
+
commodity:,
|
|
219
|
+
consignee: { address: { postal_cd: shipment.destination.postal_code.to_s } },
|
|
220
|
+
pallet_cnt: shipment.packages.map(&:packaging).map(&:pallet?).count(true),
|
|
221
|
+
payment_term_cd: 'P', # prepaid,
|
|
222
|
+
shipment_date:,
|
|
223
|
+
shipper: { address: { postal_cd: shipment.origin.postal_code.to_s } }
|
|
224
|
+
}
|
|
225
|
+
}.deep_transform_keys! { |key| key.to_s.camelize(:lower) }.to_json
|
|
226
|
+
|
|
227
|
+
request = {
|
|
228
|
+
body:,
|
|
229
|
+
headers: build_headers,
|
|
230
|
+
method: :post,
|
|
231
|
+
url: build_url(:rates)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
save_request(request)
|
|
235
|
+
request
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def parse_rate_response(shipment:, response:)
|
|
239
|
+
rate_response = RateResponse.new(request: last_request, response:)
|
|
240
|
+
|
|
241
|
+
if response.blank?
|
|
242
|
+
rate_response.error = ResponseError.new('Unknown response')
|
|
243
|
+
return rate_response
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
if response.dig(:data, :rateQuote, :totCharge, 0, :amt).blank?
|
|
247
|
+
rate_response.error = ResponseError.new('Cost is empty')
|
|
248
|
+
return rate_response
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
accessorials = response.dig(:data, :rateQuote, :shipmentInfo, :accessorials)
|
|
252
|
+
commodities = response.dig(:data, :rateQuote, :shipmentInfo, :commodity)
|
|
253
|
+
deficit_weight = response.dig(:data, :rateQuote, :deficitRatingInfo)
|
|
254
|
+
|
|
255
|
+
prices = []
|
|
256
|
+
|
|
257
|
+
prices << FreightKit::Price.new(
|
|
258
|
+
blame: :api,
|
|
259
|
+
cents: parse_amount(
|
|
260
|
+
commodities.sum { |c| c.dig(:charge, :chargeAmt, :amt) },
|
|
261
|
+
),
|
|
262
|
+
description: 'Freight',
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
if deficit_weight.present?
|
|
266
|
+
prices << FreightKit::Price.new(
|
|
267
|
+
blame: :api,
|
|
268
|
+
cents: parse_amount(deficit_weight.dig(:deficitAmt, :amt)),
|
|
269
|
+
description: <<~DESC.squish,
|
|
270
|
+
Deficit weight
|
|
271
|
+
#{deficit_weight.dig(:deficitWght, :weight).ceil}
|
|
272
|
+
#{deficit_weight.dig(:deficitWght, :weightUom).downcase}
|
|
273
|
+
DESC
|
|
274
|
+
)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
prices << FreightKit::Price.new(
|
|
278
|
+
blame: :api,
|
|
279
|
+
cents: parse_amount(response.dig(:data, :rateQuote, :totDiscountAmt, :amt)) * -1,
|
|
280
|
+
description: "Discount #{response.dig(:data, :rateQuote, :actlDiscountPct)}%",
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
prices += accessorials.map do |accessorial|
|
|
284
|
+
FreightKit::Price.new(
|
|
285
|
+
blame: :api,
|
|
286
|
+
cents: parse_amount(accessorial.dig(:chargeAmt, :amt)),
|
|
287
|
+
description: accessorial[:accessorialDesc].squish.capitalize.gsub('Xpo', 'XPO'),
|
|
288
|
+
)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
comment = response.dig(:data, :rateQuote, :shipmentInfo, :comment)
|
|
292
|
+
days = if comment.blank?
|
|
293
|
+
nil
|
|
294
|
+
else
|
|
295
|
+
comment.match(/\d+ days/)&.to_s&.split(' days')&.first&.to_i
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
expires_at = if days.is_a?(Integer) && days.positive?
|
|
299
|
+
days.days.from_now
|
|
300
|
+
else
|
|
301
|
+
2.days.from_now
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
estimate_reference = response.dig(:data, :rateQuote, :confirmationNbr)
|
|
305
|
+
transit_days = response.dig(:data, :transitTime, :transitDays)
|
|
306
|
+
|
|
307
|
+
rate = Rate.new(
|
|
308
|
+
carrier: self,
|
|
309
|
+
carrier_name: self.class.name,
|
|
310
|
+
currency: 'USD',
|
|
311
|
+
estimate_reference:,
|
|
312
|
+
expires_at:,
|
|
313
|
+
scac: self.class.scac.upcase,
|
|
314
|
+
service_name: :standard,
|
|
315
|
+
shipment:,
|
|
316
|
+
prices:,
|
|
317
|
+
transit_days:,
|
|
318
|
+
with_excessive_length_fees: @conf.dig(:attributes, :rates, :with_excessive_length_fees),
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
rate_response.rates = [rate]
|
|
322
|
+
rate_response
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# Tracking
|
|
326
|
+
end
|
|
327
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FreightKit
|
|
4
|
+
class CTBV < CarrierLogistics
|
|
5
|
+
class << self
|
|
6
|
+
def maximum_height
|
|
7
|
+
Measured::Length.new(105, :inches)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def maximum_weight
|
|
11
|
+
Measured::Weight.new(6999, :pounds)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def minimum_length_for_overlength_fees
|
|
15
|
+
Measured::Length.new(8, :feet)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def overlength_fees_require_tariff?
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
REACTIVE_FREIGHT_CARRIER = true
|
|
24
|
+
|
|
25
|
+
class << self
|
|
26
|
+
attr_reader :name, :scac
|
|
27
|
+
end
|
|
28
|
+
@name = 'The Custom Companies'
|
|
29
|
+
@scac = 'CTBV'
|
|
30
|
+
|
|
31
|
+
# Documents
|
|
32
|
+
|
|
33
|
+
# Rates
|
|
34
|
+
def build_calculated_accessorials(shipment)
|
|
35
|
+
[].tap do |builder|
|
|
36
|
+
longest_dimension = shipment.packages.map { |package| [package.length(:in), package.width(:in)].max }.max.ceil
|
|
37
|
+
|
|
38
|
+
case longest_dimension
|
|
39
|
+
when (96..143) then builder << 'OL1'
|
|
40
|
+
when (144..) then builder << 'OL'
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Tracking
|
|
46
|
+
|
|
47
|
+
# protected
|
|
48
|
+
|
|
49
|
+
# Documents
|
|
50
|
+
|
|
51
|
+
# Rates
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FreightKit
|
|
4
|
+
class DCHA < CarrierLogistics
|
|
5
|
+
class << self
|
|
6
|
+
def maximum_height
|
|
7
|
+
Measured::Length.new(105, :inches)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def maximum_weight
|
|
11
|
+
Measured::Weight.new(10_000, :pounds)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def minimum_length_for_overlength_fees
|
|
15
|
+
Measured::Length.new(12, :feet)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def overlength_fees_require_tariff?
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
REACTIVE_FREIGHT_CARRIER = true
|
|
24
|
+
|
|
25
|
+
class << self
|
|
26
|
+
attr_reader :name, :scac
|
|
27
|
+
end
|
|
28
|
+
@name = 'Mountain Valley Express'
|
|
29
|
+
@scac = 'DCHA'
|
|
30
|
+
|
|
31
|
+
# Documents
|
|
32
|
+
|
|
33
|
+
# Rates
|
|
34
|
+
def build_calculated_accessorials(shipment)
|
|
35
|
+
[].tap do |builder|
|
|
36
|
+
builder << 'HAZM' if shipment.packages.any?(&:hazmat?)
|
|
37
|
+
|
|
38
|
+
if shipment.accessorials.present? && %i[
|
|
39
|
+
residential_delivery
|
|
40
|
+
residential_pickup
|
|
41
|
+
].intersect?(shipment.accessorials)
|
|
42
|
+
builder << 'RES'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
longest_dimension = shipment.packages.map { |package| [package.length(:in), package.width(:in)].max }.max.ceil
|
|
46
|
+
|
|
47
|
+
case longest_dimension
|
|
48
|
+
when (144..155) then builder << 'XL12'
|
|
49
|
+
when (156..167) then builder << 'XL13'
|
|
50
|
+
when (168..179) then builder << 'XL14'
|
|
51
|
+
when (180..191) then builder << 'XL15'
|
|
52
|
+
when (192..203) then builder << 'XL16'
|
|
53
|
+
when (204..215) then builder << 'XL17'
|
|
54
|
+
when (216..227) then builder << 'XL18'
|
|
55
|
+
when (228..239) then builder << 'XL19'
|
|
56
|
+
when (240..251) then builder << 'XL20'
|
|
57
|
+
when (252..483) then builder << 'XL21'
|
|
58
|
+
when (484..275) then builder << 'XL22'
|
|
59
|
+
when (276..287) then builder << 'XL23'
|
|
60
|
+
when (288..299) then builder << 'XL24'
|
|
61
|
+
when (300..311) then builder << 'XL25'
|
|
62
|
+
when (312..323) then builder << 'XL26'
|
|
63
|
+
when (324..) then builder << 'XL27'
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Tracking
|
|
69
|
+
|
|
70
|
+
# protected
|
|
71
|
+
|
|
72
|
+
# Documents
|
|
73
|
+
|
|
74
|
+
# Rates
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FreightKit
|
|
4
|
+
class DLDS < CarrierLogistics
|
|
5
|
+
class << self
|
|
6
|
+
def maximum_height
|
|
7
|
+
Measured::Length.new(105, :inches)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def maximum_weight
|
|
11
|
+
Measured::Weight.new(10_000, :pounds)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def minimum_length_for_overlength_fees
|
|
15
|
+
Measured::Length.new(8, :feet)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def overlength_fees_require_tariff?
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
REACTIVE_FREIGHT_CARRIER = true
|
|
24
|
+
|
|
25
|
+
class << self
|
|
26
|
+
attr_reader :name, :scac
|
|
27
|
+
end
|
|
28
|
+
@name = 'Diamond Line Delivery'
|
|
29
|
+
@scac = 'DLDS'
|
|
30
|
+
|
|
31
|
+
# Documents
|
|
32
|
+
|
|
33
|
+
# Rates
|
|
34
|
+
def build_calculated_accessorials(shipment)
|
|
35
|
+
[].tap do |builder|
|
|
36
|
+
builder << 'SS'
|
|
37
|
+
builder << 'HAZ' if shipment.packages.any?(&:hazmat?)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Tracking
|
|
42
|
+
|
|
43
|
+
# protected
|
|
44
|
+
|
|
45
|
+
# Documents
|
|
46
|
+
|
|
47
|
+
# Rates
|
|
48
|
+
end
|
|
49
|
+
end
|