Class: FreightKit::FWDA

Inherits:
Carrier show all
Includes:
Pickupable, Rateable, Trackable
Defined in:
lib/freight_kit/carriers/fwda.rb

Constant Summary collapse

REACTIVE_FREIGHT_CARRIER =
true
JSON_HEADERS =
{
  Accept: 'application/json',
  charset: 'utf-8',
  'Content-Type' => 'application/json'
}.freeze

Constants inherited from Carrier

Carrier::BOL_NUMBER_TRACKING_URL_TEMPLATE, Carrier::NUMBERS, Carrier::ORDER_NUMBER_TRACKING_URL_TEMPLATE, Carrier::PICKUP_NUMBER_TRACKING_URL_TEMPLATE, Carrier::PO_NUMBER_TRACKING_URL_TEMPLATE, Carrier::TRACKING_NUMBER_TRACKING_URL_TEMPLATE, Carrier::VALID_BOL_NUMBER_REGEX, Carrier::VALID_ORDER_NUMBER_REGEX, Carrier::VALID_PICKUP_NUMBER_REGEX, Carrier::VALID_PO_NUMBER_REGEX, Carrier::VALID_TRACKING_NUMBER_REGEX

Class Attribute Summary collapse

Attributes inherited from Carrier

#conf, #credentials, #customer_location, #last_request, #rates_with_excessive_length_fees, #tariff, #tmpdir

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Pickupable

#create_pickup

Methods included from Trackable

#find_tracking_info

Methods inherited from Carrier

#available_services, #bol, bol_requires_tracking_number?, #cancel_shipment, #create_pickup, default_location, #fetch_credential, #find_estimate, #find_tracking_info, #find_tracking_number_from_pickup_number, implemented?, #initialize, maximum_address_field_length, #overlength_fee, tracking_url_template, #valid_credentials?, valid_number_regex, #valid_tracking_number?, #validate_packages

Constructor Details

This class inherits a constructor from FreightKit::Carrier

Class Attribute Details

.nameObject (readonly)

Returns the value of attribute name.



46
47
48
# File 'lib/freight_kit/carriers/fwda.rb', line 46

def name
  @name
end

.scacObject (readonly)

Returns the value of attribute scac.



46
47
48
# File 'lib/freight_kit/carriers/fwda.rb', line 46

def scac
  @scac
end

Class Method Details

.find_rates_with_declared_value?Boolean

Returns:

  • (Boolean)


6
7
8
# File 'lib/freight_kit/carriers/fwda.rb', line 6

def find_rates_with_declared_value?
  true
end

.maximum_heightObject



10
11
12
# File 'lib/freight_kit/carriers/fwda.rb', line 10

def maximum_height
  Measured::Length.new(105, :inches)
end

.maximum_weightObject



14
15
16
# File 'lib/freight_kit/carriers/fwda.rb', line 14

def maximum_weight
  Measured::Weight.new(10_000, :pounds)
end

.minimum_length_for_overlength_feesObject



18
19
20
# File 'lib/freight_kit/carriers/fwda.rb', line 18

def minimum_length_for_overlength_fees
  Measured::Length.new(6, :feet)
end

.overlength_fees_require_tariff?Boolean

Returns:

  • (Boolean)


22
23
24
# File 'lib/freight_kit/carriers/fwda.rb', line 22

def overlength_fees_require_tariff?
  false
end

.pickup_number_is_tracking_number?Boolean

Returns:

  • (Boolean)


26
27
28
# File 'lib/freight_kit/carriers/fwda.rb', line 26

def pickup_number_is_tracking_number?
  true
end

.required_credential_typesObject



30
31
32
# File 'lib/freight_kit/carriers/fwda.rb', line 30

def required_credential_types
  %i[api]
end

.requirementsObject



34
35
36
# File 'lib/freight_kit/carriers/fwda.rb', line 34

def requirements
  %i[credentials]
end

Instance Method Details

#find_locations(country) ⇒ Object

Locations

Raises:

  • (ArgumentError)


133
134
135
136
137
138
# File 'lib/freight_kit/carriers/fwda.rb', line 133

def find_locations(country)
  raise ArgumentError, 'country must be a ActiveUtils::Country' unless country.is_a?(ActiveUtils::Country)

  request = build_locations_request
  parse_locations_response(country:, response: commit(request))
end

#find_rates(shipment:) ⇒ Object

Rates



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/freight_kit/carriers/fwda.rb', line 142

def find_rates(shipment:)
  if shipment.packages.map { |package| package.height(:in) }.any?(&:blank?) ||
     shipment.packages.map { |package| package.length(:in) }.any?(&:blank?) ||
     shipment.packages.map { |package| package.width(:in) }.any?(&:blank?)

    raise UnserviceableError, 'Dimensions required for quoting'
  end

  packages = shipment.packages.select { |package| package.height(:in) > 89 }
  if packages.any?
    message = <<~MESSAGE.squish
      #{"Height".pluralize(packages)}
      #{packages.map { |package| "#{package.height(:in)} inches" }.join(", ")}
      greater than maximum allowed of 89 inches.
    MESSAGE
    raise UnserviceableError, message
  end

  packages = shipment.packages.select { |package| package.length(:in) > 240 }
  if packages.any?
    message = <<~MESSAGE.squish
      #{"Length".pluralize(packages)}
      #{packages.map { |package| "#{package.length(:in)} inches" }.join(", ")}
      greater than maximum allowed of 240 inches.
    MESSAGE
    raise UnserviceableError, message
  end

  packages = shipment.packages.select { |package| package.width(:in) > 82 }
  if packages.any?
    message = <<~MESSAGE.squish
      #{"Width".pluralize(packages)}
      #{packages.map { |package| "#{package.width(:in)} inches" }.join(", ")}
      greater than maximum allowed of 82 inches.
    MESSAGE
    raise UnserviceableError, message
  end

  super
end

#pod(tracking_number) ⇒ Object

Documents



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/freight_kit/carriers/fwda.rb', line 83

def pod(tracking_number)
  # Retrieve list of available documents first
  begin
    documents = commit(build_documents_request(tracking_number))
  rescue FreightKit::ResponseError => e
    if e.message.downcase.include?('no airbills found')
      return DocumentResponse.new(error: FreightKit::DocumentNotFoundError)
    end

    return DocumentResponse.new(error: e)
  end

  begin
    doc_id = get_doc_id(documents:, tracking_number:, type: :pod)
  rescue StandardError => e
    return DocumentResponse.new(error: e)
  end

  request = build_document_request(doc_id:, tracking_number:)
  response = commit(request)

  parse_document_response(:pod, tracking_number, response)
end

#scanned_bol(tracking_number, _options = {}) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/freight_kit/carriers/fwda.rb', line 107

def scanned_bol(tracking_number, _options = {})
  # Retrieve list of available documents first
  begin
    documents = commit(build_documents_request(tracking_number))
  rescue FreightKit::ResponseError => e
    if e.message.downcase.include?('no airbills found')
      return DocumentResponse.new(error: FreightKit::DocumentNotFoundError)
    end

    return DocumentResponse.new(error: e)
  end

  begin
    doc_id = get_doc_id(documents:, tracking_number:, type: :bol)
  rescue StandardError => e
    return DocumentResponse.new(e:)
  end

  request = build_document_request(doc_id:, tracking_number:)
  response = commit(request)

  parse_document_response(:bol, tracking_number, response)
end

#serviceable_accessorials?(accessorials) ⇒ Boolean

Override Carrier#serviceable_accessorials? since we have separate delivery/pickup accessorials

Returns:

  • (Boolean)


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/freight_kit/carriers/fwda.rb', line 58

def serviceable_accessorials?(accessorials)
  return true if accessorials.blank?

  if !self.class::REACTIVE_FREIGHT_CARRIER ||
     !@conf.dig(:accessorials, :mappable) ||
     !@conf.dig(:accessorials, :unquotable) ||
     !@conf.dig(:accessorials, :unserviceable)
    raise NotImplementedError, "#{self.class.name}: #serviceable_accessorials? not supported"
  end

  serviceable_accessorials = @conf.dig(:accessorials, :mappable, :delivery).keys +
                             @conf.dig(:accessorials, :mappable, :pickup).keys +
                             @conf.dig(:accessorials, :unquotable)

  unsupported_accessorials = accessorials - serviceable_accessorials

  if unsupported_accessorials.any?
    raise FreightKit::UnserviceableError, "#{self.class.name}: #{unsupported_accessorials.join(", ")} not supported"
  end

  true
end