module Shippinglogic class FedEx # An interface to the track services provided by FedEx. Allows you to get an array of events for a specific # tracking number. # # == Accessor methods / options # # * tracking_number - the tracking number # # === Simple Example # # Here is a very simple example: # # fedex = Shippinglogic::FedEx.new(key, password, account, meter) # tracking_details = fedex.track(:tracking_number => "my number") # # tracking_details.status # # => "Delivered" # # tracking_details.signature_name # # => "KKING" # # tracking_details.events.first # # => # # # tracking_details.events.first.name # # => "Delivered" # # === Note # # FedEx does support locating packages through means other than a tracking number. # These are not supported and probably won't be until someone needs them. It should # be fairly simple to add, but I could not think of a reason why anyone would want to track # a package with anything other than a tracking number. class Track < Service class Details # Each tracking result is an object of this class class Event; attr_accessor :name, :type, :occured_at, :city, :state, :postal_code, :country, :residential; end attr_accessor :origin_city, :origin_state, :origin_country, :origin_residential, :destination_city, :destination_state, :destination_country, :destination_residential, :signature_name, :service_type, :status, :delivery_at, :events def origin_residential? origin_residential == true end def destination_residential? destination_residential == true end def initialize(response) details = response[:track_details] self.origin_city = details[:origin_location_address][:city] self.origin_state = details[:origin_location_address][:state_or_province_code] self.origin_country = details[:origin_location_address][:country_code] self.origin_residential = details[:origin_location_address][:residential] == "true" self.destination_city = details[:destination_address][:city] self.destination_state = details[:destination_address][:state_or_province_code] self.destination_country = details[:destination_address][:country_code] self.destination_residential = details[:destination_address][:residential] == "true" self.signature_name = details[:delivery_signature_name] self.service_type = details[:service_type] self.status = details[:status_description] self.delivery_at = Time.parse(details[:actual_delivery_timestamp]) self.events = response[:track_details][:events].collect do |details| event = Event.new event.name = details[:event_description] event.type = details[:event_type] event.occured_at = Time.parse(details[:timestamp]) event.city = details[:address][:city] event.state = details[:address][:state_or_province_code] event.postal_code = details[:address][:postal_code] event.country = details[:address][:country_code] event.residential = details[:address][:residential] == "true" event end end end VERSION = {:major => 3, :intermediate => 0, :minor => 0} attribute :tracking_number, :string private # The parent class Service requires that we define this method. This is our kicker. This method is only # called when we need to deal with information from FedEx. Notice the caching into the @target variable. def target @target ||= Details.new(request(build_request)) end # Just building some XML to send off to FedEx. FedEx require this particualr format. def build_request b = builder xml = b.TrackRequest(:xmlns => "http://fedex.com/ws/track/v#{VERSION[:major]}") do build_authentication(b) build_version(b, "trck", VERSION[:major], VERSION[:intermediate], VERSION[:minor]) b.PackageIdentifier do b.Value tracking_number b.Type "TRACKING_NUMBER_OR_DOORTAG" end b.IncludeDetailedScans true end end end end end