lib/ups.rb in trackerific-0.2.1 vs lib/ups.rb in trackerific-0.3.0

- old
+ new

@@ -1,58 +1,84 @@ +require 'date' + module Trackerific require 'httparty' + # Provides package tracking support for UPS. class UPS < Base include ::HTTParty format :xml base_uri defined?(Rails) ? case Rails.env when 'test','development' then 'https://wwwcie.ups.com/ups.app/xml' when 'production' then 'https://www.ups.com/ups.app/xml' end : 'https://www.ups.com/ups.app/xml' + # The required options for tracking a UPS package are :key, :user_id, and + # :password. + # + # @return [Array] the required options for tracking a UPS package. def required_options [:key, :user_id, :password] end + # Tracks a UPS package. + # A Trackerific::Error is raised when a package cannot be tracked. + # @return [Trackerific::Details] the tracking details def track_package(package_id) super + # connect to UPS via HTTParty http_response = self.class.post('/Track', :body => build_xml_request) + # throw any HTTP errors http_response.error! unless http_response.code == 200 + # Check the response for errors, return a Trackerific::Error, or parse + # the response from UPS and return a Trackerific::Details case http_response['TrackResponse']['Response']['ResponseStatusCode'] when "0" then raise Trackerific::Error, parse_error_response(http_response) when "1" then return parse_success_response(http_response) else raise Trackerific::Error, "Invalid response code returned from server." end end protected + # Parses the response from UPS + # @return [Trackerific::Details] def parse_success_response(http_response) + # get the activity from the UPS response activity = http_response['TrackResponse']['Shipment']['Package']['Activity'] + # if there's only one activity in the list, we need to put it in an array activity = [activity] if activity.is_a? Hash + # UPS does not provide a summary, so we'll just use the last tracking status + summary = activity.first['Status']['StatusType']['Description'].titleize details = [] activity.each do |a| - status = a['Status']['StatusType']['Description'] - if status != "UPS INTERNAL ACTIVITY CODE" - address = a['ActivityLocation']['Address'].map {|k,v| v}.join(" ") - date = "#{a['Date'].to_date} #{a['Time'][0..1]}:#{a['Time'][2..3]}:#{a['Time'][4..5]}".to_datetime - details << "#{date.strftime('%b %d %I:%M %P')} #{status}" - end + # the time format from UPS is HHMMSS, which cannot be directly converted + # to a Ruby time. + hours = a['Time'][0..1] + minutes = a['Time'][2..3] + seconds = a['Time'][4..5] + date = Date.parse(a['Date']) + date = DateTime.parse("#{date} #{hours}:#{minutes}:#{seconds}") + desc = a['Status']['StatusType']['Description'].titleize + loc = a['ActivityLocation']['Address'].map {|k,v| v}.join(" ") + details << Trackerific::Event.new(date, desc, loc) end - # UPS does not provide a summary, so just use the last tracking details - summary = details.last - details.delete(summary) - return { - :package_id => @package_id, - :summary => summary, - :details => details.reverse - } + + Trackerific::Details.new( + @package_id, + summary, + details + ) end + # Parses a UPS tracking response, and returns any errors. + # @return [String] the UPS tracking error def parse_error_response(http_response) http_response['TrackResponse']['Response']['Error']['ErrorDescription'] end + # Builds the XML request to send to UPS for tracking a package. + # @return [String] the XML request def build_xml_request xml = "" builder = ::Builder::XmlMarkup.new(:target => xml) builder.AccessRequest do |ar| ar.AccessLicenseNumber @options[:key]