Class: Fedex::Base

Inherits:
Object
  • Object
show all
Defined in:
lib/fedex.rb

Overview

Provides access to Fedex Web Services

Constant Summary collapse

REQUIRED_OPTIONS =

Defines the required parameters for various methods

{
  :base        => [ :auth_key, :security_code, :account_number, :meter_number ],
  :price       => [ :shipper, :recipient, :weight ],
  :label       => [ :shipper, :recipient, :weight, :service_type ],
  :contact     => [ :name, :phone_number ],
  :address     => [ :country, :street, :city, :state, :zip ],
  :ship_cancel => [ :tracking_number ]
}
WSDL_PATHS =

Defines the relative path to the WSDL files. Defaults assume lib/wsdl under plugin directory.

{
  :rate => 'wsdl/RateService_v8.wsdl',
  :ship => 'wsdl/ShipService_v8.wsdl',
}
WS_VERSION =

Defines the Web Services version implemented.

{ :Major => 8, :Intermediate => 0, :Minor => 0 }
SUCCESSFUL_RESPONSES =

:nodoc:

['SUCCESS', 'WARNING', 'NOTE']
DIR =
File.dirname(__FILE__)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Base

Initializes the Fedex::Base class, setting defaults where necessary.

fedex = Fedex::Base.new(options = {})

Example:

fedex = Fedex::Base.new(:auth_key       => AUTH_KEY,
                        :security_code  => SECURITY_CODE
                        :account_number => ACCOUNT_NUMBER,
                        :meter_number   => METER_NUMBER)

Required options for new

:auth_key       - Your Fedex Authorization Key
:security_code  - Your Fedex Security Code
:account_number - Your Fedex Account Number
:meter_number   - Your Fedex Meter Number

Additional options

:dropoff_type       - One of Fedex::DropoffTypes.  Defaults to DropoffTypes::REGULAR_PICKUP
:packaging_type     - One of Fedex::PackagingTypes.  Defaults to PackagingTypes::YOUR_PACKAGING
:label_type         - One of Fedex::LabelFormatTypes.  Defaults to LabelFormatTypes::COMMON2D.  You'll only need to change this
                      if you're generating completely custom labels with a format of your own design.  If printing to Fedex stock
                      leave this alone.
:label_image_type   - One of Fedex::LabelSpecificationImageTypes.  Defaults to LabelSpecificationImageTypes::PDF.
:rate_request_type  - One of Fedex::RateRequestTypes.  Defaults to RateRequestTypes::ACCOUNT
:payment            - One of Fedex::PaymentTypes.  Defaults to PaymentTypes::SENDER
:units              - One of Fedex::WeightUnits.  Defaults to WeightUnits::LB
:currency           - One of Fedex::CurrencyTypes.  Defaults to CurrencyTypes::USD
:debug              - Enable or disable debug (wiredump) output.  Defaults to false.


94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/fedex.rb', line 94

def initialize(options = {})
  check_required_options(:base, options)
  
  @auth_key           = options[:auth_key]
  @security_code      = options[:security_code]
  @account_number     = options[:account_number]
  @meter_number       = options[:meter_number]
                    
  @dropoff_type       = options[:dropoff_type]      || DropoffTypes::REGULAR_PICKUP
  @packaging_type     = options[:packaging_type]    || PackagingTypes::YOUR_PACKAGING
  @label_type         = options[:label_type]        || LabelFormatTypes::COMMON2D
  @label_image_type   = options[:label_image_type]  || LabelSpecificationImageTypes::PDF
  @rate_request_type  = options[:rate_request_type] || RateRequestTypes::LIST
  @payment_type       = options[:payment]           || PaymentTypes::SENDER
  @units              = options[:units]             || WeightUnits::LB
  @currency           = options[:currency]          || CurrencyTypes::USD
  @debug              = options[:debug]             || false
end

Instance Attribute Details

#account_numberObject

Returns the value of attribute account_number.



55
56
57
# File 'lib/fedex.rb', line 55

def 
  @account_number
end

#auth_keyObject

Returns the value of attribute auth_key.



55
56
57
# File 'lib/fedex.rb', line 55

def auth_key
  @auth_key
end

#debugObject

Returns the value of attribute debug.



55
56
57
# File 'lib/fedex.rb', line 55

def debug
  @debug
end

#dropoff_typeObject

Returns the value of attribute dropoff_type.



55
56
57
# File 'lib/fedex.rb', line 55

def dropoff_type
  @dropoff_type
end

#meter_numberObject

Returns the value of attribute meter_number.



55
56
57
# File 'lib/fedex.rb', line 55

def meter_number
  @meter_number
end

#packaging_typeObject

Returns the value of attribute packaging_type.



55
56
57
# File 'lib/fedex.rb', line 55

def packaging_type
  @packaging_type
end

#security_codeObject

Returns the value of attribute security_code.



55
56
57
# File 'lib/fedex.rb', line 55

def security_code
  @security_code
end

#senderObject

Returns the value of attribute sender.



55
56
57
# File 'lib/fedex.rb', line 55

def sender
  @sender
end

#service_typeObject

Returns the value of attribute service_type.



55
56
57
# File 'lib/fedex.rb', line 55

def service_type
  @service_type
end

#unitsObject

Returns the value of attribute units.



55
56
57
# File 'lib/fedex.rb', line 55

def units
  @units
end

Instance Method Details

#cancel(options = {}) ⇒ Object

Cancel a shipment

fedex = Fedex::Base.new(options)
result = fedex.cancel(options)

Returns a boolean indicating whether or not the operation was successful

Required options for cancel

:tracking_number - The Fedex-provided tracking number you wish to cancel


268
269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/fedex.rb', line 268

def cancel(options = {})
  check_required_options(:ship_cancel, options)

  tracking_number = options[:tracking_number]
  #carrier_code    = options[:carrier_code] || carrier_code_for_tracking_number(tracking_number)

  driver = create_driver(:ship)

  result = driver.deleteShipment(common_options(:ship).merge(
    :TrackingNumber => tracking_number
  ))

  return successful?(result)
end

#label(options = {}) ⇒ Object

Generate a new shipment and return associated data, including price, tracking number, and the label itself.

fedex = Fedex::Base.new(options)
price, label, tracking_number = fedex.label(fields)

Returns the actual price for the label, the Base64-decoded label in the format specified in Fedex::Base, and the tracking_number for the shipment.

Required options for label

:shipper      - A hash containing contact information and an address for the shipper.  (See below.)
:recipient    - A hash containing contact information and an address for the recipient.  (See below.)
:weight       - The total weight of the shipped package.
:service_type - One of Fedex::ServiceTypes

Address format

The ‘shipper’ and ‘recipient’ address values should be hashes. Like this:

shipper = {:contact => {:name => 'John Doe',
                        :phone_number => '4805551212'},
           :address => address} # See "Address" for under price.


225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/fedex.rb', line 225

def label(options = {})
  puts options.inspect if $DEBUG

  # Check overall options
  check_required_options(:label, options)

  # Check Address Options
  check_required_options(:contact, options[:shipper][:contact])
  check_required_options(:address, options[:shipper][:address])

  # Check Contact Options
  check_required_options(:contact, options[:recipient][:contact])
  check_required_options(:address, options[:recipient][:address])

  # Build shipment options
  options = build_shipment_options(:ship, options)

 # Process the shipment request
  driver = create_driver(:ship)
  result = driver.processShipment(options)
  successful = successful?(result)

  msg = error_msg(result, false)
  if successful && msg !~ /There are no valid services available/
    pre = result.completedShipmentDetail.shipmentRating.shipmentRateDetails
    charge = ((pre.class == Array ? pre[0].totalNetCharge.amount.to_f : pre.totalNetCharge.amount.to_f) * 100).to_i
    label = Base64.decode64(result.completedShipmentDetail.completedPackageDetails.label.parts.image)
    tracking_number = result.completedShipmentDetail.completedPackageDetails.trackingIds.trackingNumber
    [charge, label, tracking_number]
  else
    raise FedexError.new("Unable to get label from Fedex: #{msg}")
  end
end

#price(options = {}) ⇒ Object

Gets a rate quote from Fedex.

fedex = Fedex::Base.new(options)

single_price = fedex.price(
  :shipper => { ... },
  :recipient => { ... },
  :weight => 1,
  :service_type => 'STANDARD_OVERNIGHT'
}
single_price #=> 1315

multiple_prices = fedex.price(
  :shipper => { ... },
  :recipient => { ... },
  :weight => 1
)
multiple_prices #=> { 'STANDARD_OVERNIGHT' => 1315, 'PRIORITY_OVERNIGHT' => 2342, ... }

Required options for price

:shipper              - A hash containing contact information and an address for the shipper.  (See below.)
:recipient            - A hash containing contact information and an address for the recipient.  (See below.)
:weight               - The total weight of the shipped package.

Optional options

:count                - How many packages are in the shipment. Defaults to 1.
:service_type         - One of Fedex::ServiceTypes. If not specified, Fedex gives you rates for all
                        of the available service types (and you will receive a hash of prices instead of a
                        single price).

Address format

The ‘shipper’ and ‘recipient’ address values should be hashes. Like this:

address = {
  :country => 'US',
  :street => '1600 Pennsylvania Avenue NW'
  :city => 'Washington',
  :state => 'DC',
  :zip => '20500'
}


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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/fedex.rb', line 153

def price(options = {})
  puts options.inspect if $DEBUG

  # Check overall options
  check_required_options(:price, options)

  # Check Address Options
  check_required_options(:contact, options[:shipper][:contact])
  check_required_options(:address, options[:shipper][:address])

  # Check Contact Options
  check_required_options(:contact, options[:recipient][:contact])
  check_required_options(:address, options[:recipient][:address])

  # Build shipment options
  options = build_shipment_options(:crs, options) 

  # Process the rate request 
  driver = create_driver(:rate)
  result = driver.getRates(options)

  extract_price = proc do |reply_detail|
    shipment_details = reply_detail.ratedShipmentDetails
    price = nil
    for shipment_detail in shipment_details
      rate_detail = shipment_detail.shipmentRateDetail
      if rate_detail.rateType == "PAYOR_#{@rate_request_type}"
        price = (rate_detail.totalNetCharge.amount.to_f * 100).to_i
        break
      end
    end
    if price
      return price
    else
      raise "Couldn't find Fedex price in response!"
    end
  end

  msg = error_msg(result, false)
  if successful?(result) && msg !~ /There are no valid services available/
    reply_details = result.rateReplyDetails
    if reply_details.respond_to?(:ratedShipmentDetails)
      price = extract_price.call(reply_details)
      service_type ? price : { reply_details.serviceType => price }
    else
      reply_details.inject({}) {|h,r| h[r.serviceType] = extract_price.call(r); h }
    end
  else
    raise FedexError.new("Unable to retrieve price from Fedex: #{msg}")
  end
end