lib/active_shipping/carriers/usps.rb in active_shipping-1.0.1 vs lib/active_shipping/carriers/usps.rb in active_shipping-1.1.0

- old
+ new

@@ -8,15 +8,12 @@ # usps.valid_credentials? # # This will send a test request to the USPS test servers, which they ask you # to do before they put your API key in production mode. class USPS < Carrier - EventDetails = Struct.new(:description, :time, :zoneless_time, :location) - EVENT_MESSAGE_PATTERNS = [ - /^(.*), (\w+ \d{1,2}, \d{4}, \d{1,2}:\d\d [ap]m), (.*), (\w\w) (\d{5})$/i, - /^Your item \w{2,3} (out for delivery|delivered).* at (\d{1,2}:\d\d [ap]m on \w+ \d{1,2}, \d{4}) in (.*), (\w\w) (\d{5})\.$/i - ] + EventDetails = Struct.new(:description, :time, :zoneless_time, :location, :event_code) + ONLY_PREFIX_EVENTS = ['DELIVERED','OUT FOR DELIVERY'] self.retry_safe = true cattr_reader :name @@name = "USPS" @@ -230,30 +227,48 @@ def maximum_weight Mass.new(70, :pounds) end - def extract_event_details(message) - return EventDetails.new unless EVENT_MESSAGE_PATTERNS.any? { |pattern| message =~ pattern } - description = $1.upcase - timestamp = $2 - city = $3 - state = $4 - zip_code = $5 + def extract_event_details(node) + description = node.at('Event').text.upcase + if prefix = ONLY_PREFIX_EVENTS.find { |p| description.starts_with?(p) } + description = prefix + end + + timestamp = "#{node.at('EventDate').text}, #{node.at('EventTime').text}" + event_code = node.at('EventCode').text + city = node.at('EventCity').text + state = node.at('EventState').text + zip_code = node.at('EventZIPCode').text + + country_node = node.at('EventCountry') + country = country_node ? country_node.text : '' + country = 'USA' if country.empty? + time = Time.parse(timestamp) zoneless_time = Time.utc(time.year, time.month, time.mday, time.hour, time.min, time.sec) - location = Location.new(city: city, state: state, postal_code: zip_code, country: 'USA') - EventDetails.new(description, time, zoneless_time, location) + location = Location.new(city: city, state: state, postal_code: zip_code, country: country) + EventDetails.new(description, time, zoneless_time, location, event_code) end protected def build_tracking_request(tracking_number, options = {}) xml_builder = Nokogiri::XML::Builder.new do |xml| - xml.TrackRequest('USERID' => @options[:login]) do - xml.TrackID('ID' => tracking_number) + xml.TrackFieldRequest('USERID' => @options[:login]) do + xml.Revision { xml.text('1') } + xml.ClientIp { xml.text(@options[:client_ip] || '127.0.0.1') } + xml.SourceId { xml.text(@options[:source_id] || 'active_shipping') } + xml.TrackID('ID' => tracking_number) do + xml.DestinationZipCode { xml.text(@options[:destination_zip])} if @options[:destination_zip] + if @options[:mailing_date] + formatted_date = @options[:mailing_date].strftime('%Y-%m-%d') + xml.MailingDate { xml.text(formatted_date)} + end + end end end xml_builder.to_xml end @@ -527,33 +542,29 @@ end def parse_tracking_response(response, options) actual_delivery_date, status = nil xml = Nokogiri.XML(response) - root_node = xml.root success = response_success?(xml) message = response_message(xml) if success destination = nil shipment_events = [] tracking_details = xml.root.xpath('TrackInfo/TrackDetail') + tracking_details << xml.root.at('TrackInfo/TrackSummary') - tracking_summary = xml.root.at('TrackInfo/TrackSummary') - if tracking_details.length > 0 - tracking_details << tracking_summary - else - success = false - message = tracking_summary.text - end - tracking_number = xml.root.at('TrackInfo').attributes['ID'].value + scheduled_delivery = Time.parse(xml.root.at('PredictedDeliveryDate').text) tracking_details.each do |event| - details = extract_event_details(event.text) - shipment_events << ShipmentEvent.new(details.description, details.zoneless_time, details.location) if details.location + details = extract_event_details(event) + if details.location + shipment_events << ShipmentEvent.new(details.description, details.zoneless_time, + details.location, details.description, details.event_code) + end end shipment_events = shipment_events.sort_by(&:time) if last_shipment = shipment_events.last @@ -568,15 +579,16 @@ :request => last_request, :shipment_events => shipment_events, :destination => destination, :tracking_number => tracking_number, :status => status, - :actual_delivery_date => actual_delivery_date + :actual_delivery_date => actual_delivery_date, + :scheduled_delivery_date => scheduled_delivery ) end def track_summary_node(document) - document.root.xpath('TrackInfo/TrackSummary') + document.root.xpath('TrackInfo/StatusSummary') end def error_description_node(document) STATUS_NODE_PATTERNS.each do |pattern| if node = document.elements[pattern]