Class: Deliveries::Couriers::Ups::CollectionPoints::Search

Inherits:
Object
  • Object
show all
Defined in:
lib/deliveries/couriers/ups/collection_points/search.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(country:, postcode: nil, point_id: nil) ⇒ Search

Returns a new instance of Search.

Raises:



8
9
10
11
12
13
14
# File 'lib/deliveries/couriers/ups/collection_points/search.rb', line 8

def initialize(country:, postcode: nil, point_id: nil)
  raise Error, 'Both postcode and point_id cannot be nil' if postcode.nil? && point_id.nil?

  self.country = country.to_s.downcase
  self.postcode = postcode
  self.point_id = point_id
end

Instance Attribute Details

#countryObject

Returns the value of attribute country.



6
7
8
# File 'lib/deliveries/couriers/ups/collection_points/search.rb', line 6

def country
  @country
end

#point_idObject

Returns the value of attribute point_id.



6
7
8
# File 'lib/deliveries/couriers/ups/collection_points/search.rb', line 6

def point_id
  @point_id
end

#postcodeObject

Returns the value of attribute postcode.



6
7
8
# File 'lib/deliveries/couriers/ups/collection_points/search.rb', line 6

def postcode
  @postcode
end

Instance Method Details

#executeObject

Raises:



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/deliveries/couriers/ups/collection_points/search.rb', line 16

def execute
  request_id = SecureRandom.uuid

  access = Nokogiri::XML::Builder.new do |xml|
    xml.AccessRequest('xml:lang': 'en-US') do
      xml.AccessLicenseNumber Ups.config(:license_number)
      xml.UserId Ups.config(:username)
      xml.Password Ups.config(:password)
    end
  end

  locator = Nokogiri::XML::Builder.new do |xml|
    xml.LocatorRequest do
      xml.Request do
        xml.RequestAction 'Locator'
        xml.RequestOption '64'
        xml.TransactionReference do
          xml.CustomerContext request_id
          xml.XpciVersion '1.0014'
        end
      end
      xml.OriginAddress do
        xml.AddressKeyFormat do
          xml.SingleLineAddress postcode if postcode
          xml.CountryCode country.upcase
        end
      end

      xml.LocationSearchCriteria do
        xml.AccessPointSearch do
          xml.AccessPointStatus '01'
          if point_id
            xml.PublicAccessPointID point_id
          else
            xml.IncludeCriteria do
              xml.SearchFilter do
                xml.ShippingAvailabilityIndicator ''
              end
            end
          end
        end

        xml.MaximumListSize '20'
      end

      xml.Translate do
        xml.Locale locale
      end
    end
  end

  request_body = access.to_xml + locator.to_xml

  response = HTTParty.post(
    api_endpoint,
    body: request_body,
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    debug_output: Deliveries.debug ? Deliveries.logger : nil
  )

  response_doc = Nokogiri.XML(response.body)
  response_id = response_doc.at_xpath('//LocatorResponse/Response/TransactionReference/CustomerContext')&.content
  raise Error, 'Request and response ID mismatch' if request_id != response_id

  unless response_doc.at_xpath('//LocatorResponse/Response/ResponseStatusCode')&.content == '1'
    error_code = response_doc.at_xpath('//LocatorResponse/Response/Error/ErrorCode')&.content
    error_description = response_doc.at_xpath('//LocatorResponse/Response/Error/ErrorDescription')&.content

    raise APIError.new(error_description, error_code)
  end

  response_doc.xpath('//LocatorResponse/SearchResults/DropLocation').map do |location_doc|
    timetable = location_doc.xpath('OperatingHours/StandardHours/DayOfWeek').map do |day_doc|
      wday = day_doc.at_xpath('Day')&.content.to_i % 7
      open_hours = day_doc.xpath('OpenHours')&.map(&:content)&.map do |h|
        h == '0' ? '00:00' : h.insert(-3, ':')
      end || []
      close_hours = day_doc.xpath('CloseHours')&.map(&:content)&.map do |h|
        h == '0' ? '00:00' : h.insert(-3, ':')
      end || []
      hours = open_hours.zip(close_hours).map { |open, close| OpenStruct.new(open: open, close: close) }

      [wday, hours]
    end.to_h

    {
      courier_id: Ups::COURIER_ID,
      point_id: location_doc.at_xpath('AccessPointInformation/PublicAccessPointID')&.content,
      latitude: location_doc.at_xpath('Geocode/Latitude')&.content,
      longitude: location_doc.at_xpath('Geocode/Longitude')&.content,
      timetable: timetable,
      url_photo: location_doc.at_xpath('AccessPointInformation/ImageURL')&.content,
      name: location_doc.at_xpath('AddressKeyFormat/ConsigneeName')&.content,
      email: location_doc.at_xpath('EMailAddress')&.content,
      phone: location_doc.at_xpath('PhoneNumber')&.content,
      country: location_doc.at_xpath('AddressKeyFormat/CountryCode')&.content&.downcase,
      state: location_doc.at_xpath('AddressKeyFormat/PoliticalDivision1')&.content,
      city: location_doc.at_xpath('AddressKeyFormat/PoliticalDivision2')&.content,
      street: location_doc.at_xpath('AddressKeyFormat/AddressLine')&.content,
      postcode: location_doc.at_xpath('AddressKeyFormat/PostcodePrimaryLow')&.content
    }
  end
end