class FriendlyShipping::Services::Usps::ParseTimeInTransitResponse
Constants
- COMMITMENT_SEQUENCES
This code carries a few details about the shipment:
-
What USPS commits to (1-Day, 2-Day or 3-Day delivery)
-
what time the package should arrive
-
Whether the package is sent from post office to post office ('Hold For Pickup')
A0110 1-Day at 10:30 AM B0110 1-Day at 10:30 AM HFPU A0112 1-Day at 12:00 PM A0115 1-Day at 3:00 PM B0115 1-Day at 3:00 PM HFPU A0210 2-Day at 10:30 AM A0212 2-Day at 12:00 PM A0215 2-Day at 3:00 PM B0210 2-Day at 10:30 AM HFPU B0215 2-Day at 3:00 PM HFPU C0100 1-Day Street C0200 2-Day Street C0300 3-Day Street D0100 1-Day PO Box D0200 2-Day PO Box D0300 3-Day PO Box E0100 1-Day HFPU E0200 2-Day HFPU E0300 3-Day HFPU
-
- MAIL_CLASSES
The USPS docs say the following:
Valid Values: “0” = All Mail Classes “1” = Priority Mail Express “2” = Priority Mail “3” = First Class Mail “4” = Marketing Mail “5” = Periodicals “6” = Package
Services
However, no shipping methods really map to “Marketing Mail” or “Periodicals”. This will likely be somewhat more work in the future.
- NON_EXPEDITED_DESTINATION_TYPES
Things are different for non-expedited shipping methods.
Public Class Methods
Parse a response from USPS' time in transit API
@param [FriendlyShipping::Request] request The request that was used to obtain this Response
@param [FriendlyShipping::Response] response The response that USPS returned @return [Result<ApiResult<Array<FriendlyShipping::Timing>>>] When successfully parsing, an array of timings in a Success Monad.
# File lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb, line 16 def call(request:, response:) # Filter out error responses and directly return a failure parsing_result = ParseXMLResponse.call( request: request, response: response, expected_root_tag: 'SDCGetLocationsResponse' ) parsing_result.fmap do |xml| expedited_commitments = xml.xpath('//Expedited') expedited_timings = parse_expedited_commitment_nodes(expedited_commitments) non_expedited_commitments = xml.xpath('//NonExpedited') non_expedited_timings = parse_non_expedited_commitment_nodes(non_expedited_commitments) ApiResult.new( expedited_timings + non_expedited_timings, original_request: request, original_response: response ) end end
Private Class Methods
# File lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb, line 40 def parse_expedited_commitment_nodes(expedited_commitment_nodes) return [] if expedited_commitment_nodes.empty? # All Expedited Commitments have the same acceptance date # However, sometimes that date is invalid. effective_acceptance_date = [ Time.parse(expedited_commitment_nodes.at('EAD').text), Time.parse(expedited_commitment_nodes.document.at('AcceptDate').text) ].max expedited_commitment_nodes.xpath('Commitment').map do |commitment_node| shipping_method = SHIPPING_METHODS.detect do |potential_shipping_method| potential_shipping_method.name == MAIL_CLASSES[commitment_node.at('MailClass').text] end commitment_sequence = commitment_node.at('CommitmentSeq').text properties = COMMITMENT_SEQUENCES[commitment_sequence] next unless properties # Sometimes USPS returns an invalid CommitmentSeq scheduled_delivery_time = properties.delete(:commitment_time) scheduled_delivery_date = commitment_node.at('SDD').text parsed_delivery_time = Time.parse("#{scheduled_delivery_date} #{scheduled_delivery_time}") guaranteed = commitment_node.at('IsGuaranteed').text == '1' FriendlyShipping::Timing.new( shipping_method: shipping_method, pickup: effective_acceptance_date, delivery: parsed_delivery_time, guaranteed: guaranteed, properties: properties ) end.compact end
# File lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb, line 72 def parse_non_expedited_commitment_nodes(non_expedited_commitment_nodes) non_expedited_commitment_nodes.map do |commitment_node| shipping_method = SHIPPING_METHODS.detect do |potential_shipping_method| potential_shipping_method.name == MAIL_CLASSES[commitment_node.at('MailClass').text] end # We cannot find a shipping method for Mail Classes 4 and 5 because USPS' docs are not clear next unless shipping_method warning_text = commitment_node.xpath('HFPU//NonExpeditedTransMsg/Msg')&.text warning = warning_text unless warning_text.empty? properties = { commitment: commitment_node.at('SvcStdMsg')&.text, destination_type: NON_EXPEDITED_DESTINATION_TYPES[commitment_node.at('NonExpeditedDestType').text], warning: warning }.compact scheduled_delivery_date = commitment_node.at('SchedDlvryDate')&.text parsed_delivery_time = Time.parse(scheduled_delivery_date) if scheduled_delivery_date effective_acceptance_date = Time.parse(commitment_node.at('EAD').text) FriendlyShipping::Timing.new( shipping_method: shipping_method, pickup: effective_acceptance_date, delivery: parsed_delivery_time, guaranteed: false, properties: properties ) end.compact end