Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Detailed shipment status information for UPS and FedEx #43

Merged
merged 20 commits into from

3 participants

@jbrowning

This is a cleaned-up version of pull request #29. Among other improvements, this adds more robust status information to UPS and FedEx tracking requests and makes shipment tracking response parsing more tolerant when incomplete data is received in tracking responses.

jbrowning and others added some commits
@jbrowning jbrowning Added carrier, delivered, exception, and exception_event properties t…
…o TrackingResponse. Modified the UPS tracking result parse to detect exceptions and the delivery status of the package.
e20e6f3
@jbrowning jbrowning Added carrier_name attribute to tracking result, expanded tests for u…
…ps tracking
9314963
@jbrowning jbrowning Added status to tracking information 28f9ec1
@jbrowning jbrowning Merge remote-tracking branch 'upstream/master' dfba8f4
@jbrowning jbrowning Fixed adding destination info to last shipment event if UPS shipment …
…is delivered
76caf15
Jeff Browning Added schedule_delivery_date to UPS 8384c5b
@jbrowning jbrowning Merge branch 'master' of https://github.com/Shopify/active_shipping
* 'master' of https://github.com/Shopify/active_shipping:
  Update ShipmentPacker to cast item values
  Add ShipmentPacker class to handle packaging items
  Stricter parsing of delivery dates
  Add Location#to_xml
  update README again
  update README
  Fix Rails 3.1 deprecation warnings
  Add address_type= so address type can be changed
  FedEx: Pass Residential true unless localtion is commerial
  Remove lib/certs/cacerts.pem
  Fix Package#cents_from incorrectly converting from an inprecise Float to Integer
  Add Gemfile, use Bundler::GemHelper
  Remove active_merchant/common, and use active_utils

Conflicts:
	test/remote/fedex_test.rb
d66f2d0
@jbrowning jbrowning added zip_plus_4 zip code formatting to Location 63a4670
@jbrowning jbrowning Added origin address to fedex tracking result 167a13b
@jbrowning jbrowning Added origin and destination tests to UPS a916e58
@jbrowning jbrowning Added destination robustness for abbreviated UPS Tracking responses. 0b0b560
@jbrowning jbrowning Disabled adding additional event location information for abbreviated…
… and delivered tracking results
1785056
@jbrowning jbrowning Surrounded origin_node with begin block 2dcebef
@jbrowning jbrowning Fixed case where the FedEx tracking response does not contain a Desti…
…nationAddressNode
213d28b
@jbrowning jbrowning removed zip_plus_4 e42308a
@jbrowning jbrowning Added UPS support for out_for_delivery status 4d9f4a5
@jbrowning jbrowning Merge branch 'master' of https://github.com/Shopify/active_shipping
* 'master' of https://github.com/Shopify/active_shipping:
  We don't want to have ruby version specific dependencies
  Release v0.9.14
  No need to have a begin / end block anymore.
  We do not need to downcase, split and capitalize each word as titleize does this for us.
  Interpolation implicitly calls .to_s
  Add spacing in CanadaPost's service_name
  NZ Post: Add International API and switch to JSON
  Remove invalid CanadaPost test expectation
  Calculates UPS delivery date for rate estimates Closes #38
22faec5
@jbrowning jbrowning Cleanup for upstream pull request. 6f64283
@Capncavedan

Looks nice, @jbrowning !

lib/active_shipping/shipping/carriers/fedex.rb
((6 lines not shown))
shipment_events = []
-
+ status, status_code, status_description = nil
@csaunders Collaborator

Oops!

Perhaps move status up into the assignment with the rest of them

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@csaunders
Collaborator

Don't mind the comments. I can go through and clean this stuff up when I merge everything in. Just taking notes ;)

@jbrowning

Oops indeed. :)

I'll have that fixed up later tonight if you haven't merged by then.

@csaunders csaunders merged commit affddc8 into from
@csaunders
Collaborator

Awesome stuff! Thanks :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 6, 2011
  1. @jbrowning

    Added carrier, delivered, exception, and exception_event properties t…

    jbrowning authored
    …o TrackingResponse. Modified the UPS tracking result parse to detect exceptions and the delivery status of the package.
Commits on Jul 7, 2011
  1. @jbrowning
Commits on Aug 15, 2011
  1. @jbrowning
Commits on Aug 16, 2011
  1. @jbrowning
  2. @jbrowning
Commits on Sep 26, 2011
  1. Added schedule_delivery_date to UPS

    Jeff Browning authored
Commits on Dec 12, 2011
  1. @jbrowning

    Merge branch 'master' of https://github.com/Shopify/active_shipping

    jbrowning authored
    * 'master' of https://github.com/Shopify/active_shipping:
      Update ShipmentPacker to cast item values
      Add ShipmentPacker class to handle packaging items
      Stricter parsing of delivery dates
      Add Location#to_xml
      update README again
      update README
      Fix Rails 3.1 deprecation warnings
      Add address_type= so address type can be changed
      FedEx: Pass Residential true unless localtion is commerial
      Remove lib/certs/cacerts.pem
      Fix Package#cents_from incorrectly converting from an inprecise Float to Integer
      Add Gemfile, use Bundler::GemHelper
      Remove active_merchant/common, and use active_utils
    
    Conflicts:
    	test/remote/fedex_test.rb
  2. @jbrowning
Commits on Dec 26, 2011
  1. @jbrowning
  2. @jbrowning
Commits on Dec 29, 2011
  1. @jbrowning
  2. @jbrowning

    Disabled adding additional event location information for abbreviated…

    jbrowning authored
    … and delivered tracking results
  3. @jbrowning
Commits on Jan 5, 2012
  1. @jbrowning
Commits on May 6, 2012
  1. @jbrowning

    removed zip_plus_4

    jbrowning authored
Commits on May 10, 2012
  1. @jbrowning
Commits on May 17, 2012
  1. @jbrowning

    Merge branch 'master' of https://github.com/Shopify/active_shipping

    jbrowning authored
    * 'master' of https://github.com/Shopify/active_shipping:
      We don't want to have ruby version specific dependencies
      Release v0.9.14
      No need to have a begin / end block anymore.
      We do not need to downcase, split and capitalize each word as titleize does this for us.
      Interpolation implicitly calls .to_s
      Add spacing in CanadaPost's service_name
      NZ Post: Add International API and switch to JSON
      Remove invalid CanadaPost test expectation
      Calculates UPS delivery date for rate estimates Closes #38
  2. @jbrowning
  3. @jbrowning
  4. @jbrowning

    Merge branches 'master' and 'better-status' into better-status

    jbrowning authored
    * master:
      cleanup and removal of debug code
    
    * better-status:
This page is out of date. Refresh to see the latest.
View
65 lib/active_shipping/shipping/carriers/fedex.rb
@@ -85,6 +85,42 @@ class FedEx < Carrier
'express_mps_master' => 'EXPRESS_MPS_MASTER'
}
+ # FedEx tracking codes as described in the FedEx Tracking Service WSDL Guide
+ # All delays also have been marked as exceptions
+ TRACKING_STATUS_CODES = HashWithIndifferentAccess.new({
+ 'AA' => :at_airport,
+ 'AD' => :at_delivery,
+ 'AF' => :at_fedex_facility,
+ 'AR' => :at_fedex_facility,
+ 'AP' => :at_pickup,
+ 'CA' => :canceled,
+ 'CH' => :location_changed,
+ 'DE' => :exception,
+ 'DL' => :delivered,
+ 'DP' => :departed_fedex_location,
+ 'DR' => :vehicle_furnished_not_used,
+ 'DS' => :vehicle_dispatched,
+ 'DY' => :exception,
+ 'EA' => :exception,
+ 'ED' => :enroute_to_delivery,
+ 'EO' => :enroute_to_origin_airport,
+ 'EP' => :enroute_to_pickup,
+ 'FD' => :at_fedex_destination,
+ 'HL' => :held_at_location,
+ 'IT' => :in_transit,
+ 'LO' => :left_origin,
+ 'OC' => :order_created,
+ 'OD' => :out_for_delivery,
+ 'PF' => :plane_in_flight,
+ 'PL' => :plane_landed,
+ 'PU' => :picked_up,
+ 'RS' => :return_to_shipper,
+ 'SE' => :exception,
+ 'SF' => :at_sort_facility,
+ 'SP' => :split_status,
+ 'TR' => :transfer
+ })
+
def self.service_name_for_code(service_code)
ServiceTypes[service_code] || "FedEx #{service_code.titleize.sub(/Fedex /, '')}"
end
@@ -262,13 +298,32 @@ def parse_tracking_response(response, options)
message = response_message(xml)
if success
- tracking_number, origin, destination = nil
+ tracking_number, origin, destination, status, status_code, status_description = nil
shipment_events = []
-
+
tracking_details = root_node.elements['TrackDetails']
tracking_number = tracking_details.get_text('TrackingNumber').to_s
+ status_code = tracking_details.get_text('StatusCode').to_s
+ status_description = tracking_details.get_text('StatusDescription').to_s
+ status = TRACKING_STATUS_CODES[status_code]
+
+ origin_node = tracking_details.elements['OriginLocationAddress']
+
+ if origin_node
+ origin = Location.new(
+ :country => origin_node.get_text('CountryCode').to_s,
+ :province => origin_node.get_text('StateOrProvinceCode').to_s,
+ :city => origin_node.get_text('City').to_s
+ )
+ end
+
destination_node = tracking_details.elements['DestinationAddress']
+
+ if destination_node.nil?
+ destination_node = tracking_details.elements['ActualDeliveryAddress']
+ end
+
destination = Location.new(
:country => destination_node.get_text('CountryCode').to_s,
:province => destination_node.get_text('StateOrProvinceCode').to_s,
@@ -294,12 +349,18 @@ def parse_tracking_response(response, options)
shipment_events << ShipmentEvent.new(description, zoneless_time, location)
end
shipment_events = shipment_events.sort_by(&:time)
+
end
TrackingResponse.new(success, message, Hash.from_xml(response),
+ :carrier => @@name,
:xml => response,
:request => last_request,
+ :status => status,
+ :status_code => status_code,
+ :status_description => status_description,
:shipment_events => shipment_events,
+ :origin => origin,
:destination => destination,
:tracking_number => tracking_number
)
View
74 lib/active_shipping/shipping/carriers/ups.rb
@@ -26,13 +26,13 @@ class UPS < Carrier
:letter_center => "19",
:air_service_center => "20"
})
-
+
CUSTOMER_CLASSIFICATIONS = HashWithIndifferentAccess.new({
:wholesale => "01",
:occasional => "03",
:retail => "04"
})
-
+
# these are the defaults described in the UPS API docs,
# but they don't seem to apply them under all circumstances,
# so we need to take matters into our own hands
@@ -85,7 +85,15 @@ class UPS < Carrier
OTHER_NON_US_ORIGIN_SERVICES = {
"07" => "UPS Express"
}
-
+
+ TRACKING_STATUS_CODES = HashWithIndifferentAccess.new({
+ 'I' => :in_transit,
+ 'D' => :delivered,
+ 'X' => :exception,
+ 'P' => :pickup,
+ 'M' => :manifest_pickup
+ })
+
# From http://en.wikipedia.org/w/index.php?title=European_Union&oldid=174718707 (Current as of November 30, 2007)
EU_COUNTRY_CODES = ["GB", "AT", "BE", "BG", "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", "HU", "IE", "IT", "LV", "LT", "LU", "MT", "NL", "PL", "PT", "RO", "SK", "SI", "ES", "SE"]
@@ -296,17 +304,39 @@ def parse_tracking_response(response, options={})
message = response_message(xml)
if success
- tracking_number, origin, destination = nil
+ tracking_number, origin, destination, status_code, status_description = nil
+ delivered, exception = false
+ exception_event = nil
shipment_events = []
-
+ status = {}
+ scheduled_delivery_date = nil
+
first_shipment = xml.elements['/*/Shipment']
first_package = first_shipment.elements['Package']
tracking_number = first_shipment.get_text('ShipmentIdentificationNumber | Package/TrackingNumber').to_s
+ # Build status hash
+ status_node = first_package.elements['Activity/Status/StatusType']
+ status_code = status_node.get_text('Code').to_s
+ status_description = status_node.get_text('Description').to_s
+ status = TRACKING_STATUS_CODES[status_code]
+
+ if status_description =~ /out.*delivery/i
+ status = :out_for_delivery
+ end
+
origin, destination = %w{Shipper ShipTo}.map do |location|
location_from_address_node(first_shipment.elements["#{location}/Address"])
end
-
+
+ # Get scheduled delivery date
+ unless status == :delivered
+ scheduled_delivery_date = parse_ups_datetime({
+ :date => first_shipment.get_text('ScheduledDeliveryDate'),
+ :time => nil
+ })
+ end
+
activities = first_package.get_elements('Activity')
unless activities.empty?
shipment_events = activities.map do |activity|
@@ -324,7 +354,10 @@ def parse_tracking_response(response, options={})
shipment_events = shipment_events.sort_by(&:time)
- if origin
+ # UPS will sometimes archive a shipment, stripping all shipment activity except for the delivery
+ # event (see test/fixtures/xml/delivered_shipment_without_events_tracking_response.xml for an example).
+ # This adds an origin event to the shipment activity in such cases.
+ if origin && !(shipment_events.count == 1 && status == :delivered)
first_event = shipment_events[0]
same_country = origin.country_code(:alpha2) == first_event.location.country_code(:alpha2)
same_or_blank_city = first_event.location.city.blank? or first_event.location.city == origin.city
@@ -335,16 +368,29 @@ def parse_tracking_response(response, options={})
shipment_events.unshift(origin_event)
end
end
- if shipment_events.last.name.downcase == 'delivered'
+
+ # Has the shipment been delivered?
+ if status == :delivered
+ if !destination
+ destination = shipment_events[-1].location
+ end
shipment_events[-1] = ShipmentEvent.new(shipment_events.last.name, shipment_events.last.time, destination)
end
end
end
TrackingResponse.new(success, message, Hash.from_xml(response).values.first,
+ :carrier => @@name,
:xml => response,
:request => last_request,
+ :status => status,
+ :status_code => status_code,
+ :status_description => status_description,
+ :scheduled_delivery_date => scheduled_delivery_date,
:shipment_events => shipment_events,
+ :delivered => delivered,
+ :exception => exception,
+ :exception_event => exception_event,
:origin => origin,
:destination => destination,
:tracking_number => tracking_number)
@@ -363,6 +409,18 @@ def location_from_address_node(address)
)
end
+ def parse_ups_datetime(options = {})
+ time, date = options[:time].to_s, options[:date].to_s
+ if time.nil?
+ hour, minute, second = 0
+ else
+ hour, minute, second = time.scan(/\d{2}/)
+ end
+ year, month, day = date[0..3], date[4..5], date[6..7]
+
+ Time.utc(year, month, day, hour, minute, second)
+ end
+
def response_success?(xml)
xml.get_text('/*/Response/ResponseStatusCode').to_s == '1'
end
View
12 lib/active_shipping/shipping/location.rb
@@ -131,6 +131,18 @@ def inspect
string << "\nFax: #{@fax}" unless @fax.blank?
string
end
+
+ # Returns the postal code as a properly formatted Zip+4 code, e.g. "77095-2233"
+ def zip_plus_4
+ if /(?<zip>\d{5})(?<plus_4>\d{4})/ =~ @postal_code
+ return "#{zip}-#{plus_4}"
+ elsif /\d{5}-\d{4}/ =~ @postal_code
+ return @postal_code
+ else
+ nil
+ end
+ end
+
end
end
View
27 lib/active_shipping/shipping/tracking_response.rb
@@ -2,20 +2,45 @@ module ActiveMerchant #:nodoc:
module Shipping
class TrackingResponse < Response
+ attr_reader :carrier # symbol
+ attr_reader :carrier_name # string
+ attr_reader :status # symbol
+ attr_reader :status_code # string
+ attr_reader :status_description #string
+ attr_reader :scheduled_delivery_date # time
attr_reader :tracking_number # string
attr_reader :shipment_events # array of ShipmentEvents in chronological order
attr_reader :origin, :destination
def initialize(success, message, params = {}, options = {})
+ @carrier = options[:carrier].parameterize.to_sym
+ @carrier_name = options[:carrier]
+ @status = options[:status]
+ @status_code = options[:status_code]
+ @status_description = options[:status_description]
+ @scheduled_delivery_date = options[:scheduled_delivery_date]
@tracking_number = options[:tracking_number]
@shipment_events = Array(options[:shipment_events])
@origin, @destination = options[:origin], options[:destination]
super
end
-
+
def latest_event
@shipment_events.last
end
+
+ def is_delivered?
+ @status == :delivered
+ end
+
+ def has_exception?
+ @status == :exception
+ end
+
+ alias_method(:exception_event, :latest_event)
+ alias_method(:delivered?, :is_delivered?)
+ alias_method(:exception?, :has_exception?)
+
end
end
View
62 test/fixtures/xml/ups/delivered_shipment_without_events_tracking_response.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<TrackResponse>
+ <Response>
+ <ResponseStatusCode>1</ResponseStatusCode>
+ <ResponseStatusDescription>Success</ResponseStatusDescription>
+ </Response>
+ <Shipment>
+ <Shipper>
+ <ShipperNumber>A7226W</ShipperNumber>
+ <Address>
+ <AddressLine1>1 AMAZON WAY</AddressLine1>
+ <City>COFFEYVILLE</City>
+ <StateProvinceCode>KS</StateProvinceCode>
+ <PostalCode>67337</PostalCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </Shipper>
+ <ShipmentWeight>
+ <UnitOfMeasurement>
+ <Code>LBS</Code>
+ </UnitOfMeasurement>
+ <Weight>0.00</Weight>
+ </ShipmentWeight>
+ <Service>
+ <Code>13</Code>
+ <Description>UPS NEXT DAY AIR SAVER</Description>
+ </Service>
+ <ShipmentIdentificationNumber>1ZA7226W1388491331</ShipmentIdentificationNumber>
+ <Package>
+ <TrackingNumber>1ZA7226W1388491331</TrackingNumber>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <City>CYPRESS</City>
+ <StateProvinceCode>TX</StateProvinceCode>
+ <PostalCode>77433</PostalCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ <Code>MQ</Code>
+ <Description>PORCH</Description>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>D</Code>
+ <Description>DELIVERED</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>FS</Code>
+ </StatusCode>
+ </Status>
+ <Date>20110617</Date>
+ <Time>134500</Time>
+ </Activity>
+ <PackageWeight>
+ <UnitOfMeasurement>
+ <Code>LBS</Code>
+ </UnitOfMeasurement>
+ <Weight>0.00</Weight>
+ </PackageWeight>
+ </Package>
+ </Shipment>
+</TrackResponse>
View
183 test/fixtures/xml/ups/in_transit_shipment.xml
@@ -0,0 +1,183 @@
+<?xml version="1.0"?>
+<TrackResponse>
+ <Response>
+ <ResponseStatusCode>1</ResponseStatusCode>
+ <ResponseStatusDescription>Success</ResponseStatusDescription>
+ </Response>
+ <Shipment>
+ <Shipper>
+ <ShipperNumber>4F940A</ShipperNumber>
+ <Address>
+ <AddressLine1>1600 WORLDWIDE BLVD</AddressLine1>
+ <City>HEBRON</City>
+ <StateProvinceCode>KY</StateProvinceCode>
+ <PostalCode>41048 8640</PostalCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </Shipper>
+ <ShipTo>
+ <Address>
+ <City>CYPRESS</City>
+ <StateProvinceCode>TX</StateProvinceCode>
+ <PostalCode>774332681</PostalCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ShipTo>
+ <ShipmentWeight>
+ <UnitOfMeasurement>
+ <Code>LBS</Code>
+ </UnitOfMeasurement>
+ <Weight>5.40</Weight>
+ </ShipmentWeight>
+ <Service>
+ <Code>002</Code>
+ <Description>2ND DAY AIR</Description>
+ </Service>
+ <ReferenceNumber>
+ <Code>01</Code>
+ <Value>62093047</Value>
+ </ReferenceNumber>
+ <ShipmentIdentificationNumber>1Z4F940A0266088694</ShipmentIdentificationNumber>
+ <PickupDate>20110822</PickupDate>
+ <ScheduledDeliveryDate>20110824</ScheduledDeliveryDate>
+ <Package>
+ <TrackingNumber>1Z4F940A0266088694</TrackingNumber>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <City>LOUISVILLE</City>
+ <StateProvinceCode>KY</StateProvinceCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>I</Code>
+ <Description>ARRIVAL SCAN</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>AR</Code>
+ </StatusCode>
+ </Status>
+ <Date>20110823</Date>
+ <Time>063800</Time>
+ </Activity>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <City>SHARONVILLE</City>
+ <StateProvinceCode>OH</StateProvinceCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>I</Code>
+ <Description>DEPARTURE SCAN</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>DP</Code>
+ </StatusCode>
+ </Status>
+ <Date>20110823</Date>
+ <Time>041500</Time>
+ </Activity>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <City>SHARONVILLE</City>
+ <StateProvinceCode>OH</StateProvinceCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>I</Code>
+ <Description>ARRIVAL SCAN</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>AR</Code>
+ </StatusCode>
+ </Status>
+ <Date>20110823</Date>
+ <Time>005700</Time>
+ </Activity>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <City>CINCINNATI</City>
+ <StateProvinceCode>OH</StateProvinceCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>I</Code>
+ <Description>DEPARTURE SCAN</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>DP</Code>
+ </StatusCode>
+ </Status>
+ <Date>20110823</Date>
+ <Time>003200</Time>
+ </Activity>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <City>CINCINNATI</City>
+ <StateProvinceCode>OH</StateProvinceCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>I</Code>
+ <Description>ORIGIN SCAN</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>OR</Code>
+ </StatusCode>
+ </Status>
+ <Date>20110822</Date>
+ <Time>190100</Time>
+ </Activity>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>M</Code>
+ <Description>BILLING INFORMATION RECEIVED</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>MP</Code>
+ </StatusCode>
+ </Status>
+ <Date>20110822</Date>
+ <Time>172303</Time>
+ </Activity>
+ <Message>
+ <Code>01</Code>
+ <Description>On Time</Description>
+ </Message>
+ <PackageWeight>
+ <UnitOfMeasurement>
+ <Code>LBS</Code>
+ </UnitOfMeasurement>
+ <Weight>5.40</Weight>
+ </PackageWeight>
+ <ReferenceNumber>
+ <Code>01</Code>
+ <Value>FN3-6732456-0526660</Value>
+ </ReferenceNumber>
+ <ReferenceNumber>
+ <Code>01</Code>
+ <Value>DZWHLCGPR</Value>
+ </ReferenceNumber>
+ </Package>
+ </Shipment>
+</TrackResponse>
View
165 test/fixtures/xml/ups/out_for_delivery_shipment.xml
@@ -0,0 +1,165 @@
+<?xml version="1.0"?>
+<TrackResponse>
+ <Response>
+ <ResponseStatusCode>1</ResponseStatusCode>
+ <ResponseStatusDescription>Success</ResponseStatusDescription>
+ </Response>
+ <Shipment>
+ <Shipper>
+ <ShipperNumber>W22A28</ShipperNumber>
+ <Address>
+ <AddressLine1>1050 S COLUMBIA AVE</AddressLine1>
+ <City>CAMPBELLSVILLE</City>
+ <StateProvinceCode>KY</StateProvinceCode>
+ <PostalCode>42718 2454</PostalCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </Shipper>
+ <ShipTo>
+ <Address>
+ <City>CYPRESS</City>
+ <StateProvinceCode>TX</StateProvinceCode>
+ <PostalCode>774332681</PostalCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ShipTo>
+ <ShipmentWeight>
+ <UnitOfMeasurement>
+ <Code>LBS</Code>
+ </UnitOfMeasurement>
+ <Weight>1.20</Weight>
+ </ShipmentWeight>
+ <Service>
+ <Code>003</Code>
+ <Description>GROUND</Description>
+ </Service>
+ <ReferenceNumber>
+ <Code>01</Code>
+ <Value>643293013</Value>
+ </ReferenceNumber>
+ <ShipmentIdentificationNumber>
+ 1ZW22A280305086608</ShipmentIdentificationNumber>
+ <PickupDate>20120508</PickupDate>
+ <ScheduledDeliveryDate>20120511</ScheduledDeliveryDate>
+ <Package>
+ <TrackingNumber>1ZW22A280305086608</TrackingNumber>
+ <RescheduledDeliveryDate>20120510</RescheduledDeliveryDate>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <City>STAFFORD</City>
+ <StateProvinceCode>TX</StateProvinceCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>I</Code>
+ <Description>OUT FOR DELIVERY</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>DS</Code>
+ </StatusCode>
+ </Status>
+ <Date>20120510</Date>
+ <Time>043400</Time>
+ </Activity>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <City>STAFFORD</City>
+ <StateProvinceCode>TX</StateProvinceCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>I</Code>
+ <Description>ARRIVAL SCAN</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>AR</Code>
+ </StatusCode>
+ </Status>
+ <Date>20120510</Date>
+ <Time>000200</Time>
+ </Activity>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <City>MESQUITE</City>
+ <StateProvinceCode>TX</StateProvinceCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>I</Code>
+ <Description>DEPARTURE SCAN</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>DP</Code>
+ </StatusCode>
+ </Status>
+ <Date>20120509</Date>
+ <Time>200300</Time>
+ </Activity>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <City>MESQUITE</City>
+ <StateProvinceCode>TX</StateProvinceCode>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>I</Code>
+ <Description>ORIGIN SCAN</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>OR</Code>
+ </StatusCode>
+ </Status>
+ <Date>20120509</Date>
+ <Time>141800</Time>
+ </Activity>
+ <Activity>
+ <ActivityLocation>
+ <Address>
+ <CountryCode>US</CountryCode>
+ </Address>
+ </ActivityLocation>
+ <Status>
+ <StatusType>
+ <Code>M</Code>
+ <Description>BILLING INFORMATION RECEIVED</Description>
+ </StatusType>
+ <StatusCode>
+ <Code>MP</Code>
+ </StatusCode>
+ </Status>
+ <Date>20120508</Date>
+ <Time>230354</Time>
+ </Activity>
+ <Message>
+ <Code>02</Code>
+ <Description>Rescheduled</Description>
+ </Message>
+ <PackageWeight>
+ <UnitOfMeasurement>
+ <Code>LBS</Code>
+ </UnitOfMeasurement>
+ <Weight>1.20</Weight>
+ </PackageWeight>
+ <ReferenceNumber>
+ <Code>01</Code>
+ <Value>FN3-4603152-0261546</Value>
+ </ReferenceNumber>
+ <ReferenceNumber>
+ <Code>01</Code>
+ <Value>DTG4MDX2R</Value>
+ </ReferenceNumber>
+ </Package>
+ </Shipment>
+</TrackResponse>
View
6 test/remote/fedex_test.rb
@@ -132,6 +132,12 @@ def test_tracking
end
end
+ def test_tracking_with_bad_number
+ assert_raises ResponseError do
+ response = @carrier.find_tracking_info('12345')
+ end
+ end
+
def test_different_rates_for_commercial
residential_response = @carrier.find_rates(
@locations[:beverly_hills],
View
55 test/unit/carriers/fedex_test.rb
@@ -5,6 +5,7 @@ def setup
@packages = TestFixtures.packages
@locations = TestFixtures.locations
@carrier = FedEx.new(:key => '1111', :password => '2222', :account => '3333', :login => '4444')
+ @tracking_response = xml_fixture('fedex/tracking_response')
end
def test_initialize_options_requirements
@@ -26,24 +27,68 @@ def test_initialize_options_requirements
# end
def test_find_tracking_info_should_return_a_tracking_response
- @carrier.expects(:commit).returns(xml_fixture('fedex/tracking_response'))
+ @carrier.expects(:commit).returns(@tracking_response)
assert_instance_of ActiveMerchant::Shipping::TrackingResponse, @carrier.find_tracking_info('077973360403984', :test => true)
end
+ def test_find_tracking_info_should_mark_shipment_as_delivered
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal true, @carrier.find_tracking_info('077973360403984').delivered?
+ end
+
+ def test_find_tracking_info_should_return_correct_carrier
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal :fedex, @carrier.find_tracking_info('077973360403984').carrier
+ end
+
+ def test_find_tracking_info_should_return_correct_carrier_name
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal 'FedEx', @carrier.find_tracking_info('077973360403984').carrier_name
+ end
+
+ def test_find_tracking_info_should_return_correct_status
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal :delivered, @carrier.find_tracking_info('077973360403984').status
+ end
+
+ def test_find_tracking_info_should_return_correct_status_code
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal 'dl', @carrier.find_tracking_info('077973360403984').status_code.downcase
+ end
+
+ def test_find_tracking_info_should_return_correct_status_description
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal 'delivered', @carrier.find_tracking_info('1Z5FX0076803466397').status_description.downcase
+ end
+
+ def test_find_tracking_info_should_return_destination_address
+ @carrier.expects(:commit).returns(@tracking_response)
+ result = @carrier.find_tracking_info('077973360403984')
+ assert_equal 'sacramento', result.destination.city.downcase
+ assert_equal 'CA', result.destination.state
+ end
+
+ def test_find_tracking_info_should_return_origin_address
+ @carrier.expects(:commit).returns(@tracking_response)
+ result = @carrier.find_tracking_info('077973360403984')
+ assert_equal 'nashville', result.origin.city.downcase
+ assert_equal 'TN', result.origin.state
+ end
+
def test_find_tracking_info_should_parse_response_into_correct_number_of_shipment_events
- @carrier.expects(:commit).returns(xml_fixture('fedex/tracking_response'))
+ @carrier.expects(:commit).returns(@tracking_response)
response = @carrier.find_tracking_info('077973360403984', :test => true)
assert_equal 6, response.shipment_events.size
end
def test_find_tracking_info_should_return_shipment_events_in_ascending_chronological_order
- @carrier.expects(:commit).returns(xml_fixture('fedex/tracking_response'))
+ @carrier.expects(:commit).returns(@tracking_response)
response = @carrier.find_tracking_info('077973360403984', :test => true)
assert_equal response.shipment_events.map(&:time).sort, response.shipment_events.map(&:time)
end
-
+
def test_find_tracking_info_should_not_include_events_without_an_address
- @carrier.expects(:commit).returns(xml_fixture('fedex/tracking_response'))
+ @carrier.expects(:commit).returns(@tracking_response)
assert_nothing_raised do
response = @carrier.find_tracking_info('077973360403984', :test => true)
assert_nil response.shipment_events.find{|event| event.name == 'Shipment information sent to FedEx' }
View
62 test/unit/carriers/ups_test.rb
@@ -11,6 +11,7 @@ def setup
:password => 'password'
)
@tracking_response = xml_fixture('ups/shipment_from_tiger_direct')
+
end
def test_initialize_options_requirements
@@ -26,6 +27,64 @@ def test_find_tracking_info_should_return_a_tracking_response
assert_equal 'ActiveMerchant::Shipping::TrackingResponse', @carrier.find_tracking_info('1Z5FX0076803466397').class.name
end
+ def test_find_tracking_info_should_mark_shipment_as_delivered
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal true, @carrier.find_tracking_info('1Z5FX0076803466397').delivered?
+ end
+
+ def test_find_tracking_info_should_return_correct_carrier
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal :ups, @carrier.find_tracking_info('1Z5FX0076803466397').carrier
+ end
+
+ def test_find_tracking_info_should_return_correct_carrier_name
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal 'UPS', @carrier.find_tracking_info('1Z5FX0076803466397').carrier_name
+ end
+
+ def test_find_tracking_info_should_return_correct_status
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal :delivered, @carrier.find_tracking_info('1Z5FX0076803466397').status
+ end
+
+ def test_find_tracking_info_should_return_correct_status_code
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal 'd', @carrier.find_tracking_info('1Z5FX0076803466397').status_code.downcase
+ end
+
+ def test_find_tracking_info_should_return_correct_status_description
+ @carrier.expects(:commit).returns(@tracking_response)
+ assert_equal 'delivered', @carrier.find_tracking_info('1Z5FX0076803466397').status_description.downcase
+ end
+
+ def test_find_tracking_info_should_have_an_out_for_delivery_status
+ out_for_delivery_tracking_response = xml_fixture('ups/out_for_delivery_shipment')
+ @carrier.expects(:commit).returns(out_for_delivery_tracking_response)
+ assert_equal :out_for_delivery, @carrier.find_tracking_info('1Z5FX0076803466397').status
+ end
+
+ def test_find_tracking_info_should_return_destination_address
+ @carrier.expects(:commit).returns(@tracking_response)
+ result = @carrier.find_tracking_info('1Z5FX0076803466397')
+ assert_equal 'ottawa', result.destination.city.downcase
+ assert_equal 'ON', result.destination.state
+ end
+
+ def test_find_tracking_info_should_return_destination_address_for_abbreviated_response
+ tracking_response = xml_fixture('ups/delivered_shipment_without_events_tracking_response')
+ @carrier.expects(:commit).returns(tracking_response)
+ result = @carrier.find_tracking_info('1Z5FX0076803466397')
+ assert_equal 'cypress', result.destination.city.downcase
+ assert_equal 'TX', result.destination.state
+ end
+
+ def test_find_tracking_info_should_return_origin_address
+ @carrier.expects(:commit).returns(@tracking_response)
+ result = @carrier.find_tracking_info('1Z5FX0076803466397')
+ assert_equal 'naperville', result.origin.city.downcase
+ assert_equal 'IL', result.origin.state
+ end
+
def test_find_tracking_info_should_parse_response_into_correct_number_of_shipment_events
@carrier.expects(:commit).returns(@tracking_response)
response = @carrier.find_tracking_info('1Z5FX0076803466397')
@@ -50,7 +109,8 @@ def test_find_tracking_info_should_have_correct_names_for_shipment_events
"OUT FOR DELIVERY",
"DELIVERED" ], response.shipment_events.map(&:name)
end
-
+
+
def test_add_origin_and_destination_data_to_shipment_events_where_appropriate
@carrier.expects(:commit).returns(@tracking_response)
response = @carrier.find_tracking_info('1Z5FX0076803466397')
View
16 test/unit/location_test.rb
@@ -98,4 +98,20 @@ def test_custom_root_to_xml
location_xml = @locations[:ottawa].to_xml(:root => "destination")
assert_equal @locations[:ottawa].to_hash, Hash.from_xml(location_xml)["destination"].symbolize_keys
end
+
+ def test_zip_plus_4_with_no_dash
+ zip = "33333"
+ plus_4 = "1234"
+ zip_plus_4 = "#{zip}-#{plus_4}"
+ location = Location.from(:zip => "#{zip}#{plus_4}")
+ assert_equal zip_plus_4, location.zip_plus_4
+ end
+
+ def test_zip_plus_4_with_dash
+ zip = "33333"
+ plus_4 = "1234"
+ zip_plus_4 = "#{zip}-#{plus_4}"
+ location = Location.from(:zip => zip_plus_4)
+ assert_equal zip_plus_4, location.zip_plus_4
+ end
end
Something went wrong with that request. Please try again.