friendly_shipping 0.5.2 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop-relaxed.yml +3 -4
- data/.rubocop.yml +9 -0
- data/CHANGELOG.md +5 -1
- data/friendly_shipping.gemspec +10 -10
- data/lib/friendly_shipping/api_failure.rb +2 -15
- data/lib/friendly_shipping/services/ups/parse_address_classification_response.rb +5 -2
- data/lib/friendly_shipping/services/ups/parse_address_validation_response.rb +5 -2
- data/lib/friendly_shipping/services/ups/parse_city_state_lookup_response.rb +5 -2
- data/lib/friendly_shipping/services/ups/parse_rate_response.rb +5 -1
- data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +5 -1
- data/lib/friendly_shipping/services/ups/parse_shipment_confirm_response.rb +5 -1
- data/lib/friendly_shipping/services/ups/parse_time_in_transit_response.rb +5 -1
- data/lib/friendly_shipping/services/ups/parse_void_shipment_response.rb +5 -1
- data/lib/friendly_shipping/services/ups/parse_xml_response.rb +16 -7
- data/lib/friendly_shipping/services/ups_freight/generate_delivery_options_hash.rb +21 -0
- data/lib/friendly_shipping/services/ups_freight/generate_document_options_hash.rb +28 -0
- data/lib/friendly_shipping/services/ups_freight/generate_email_options_hash.rb +25 -0
- data/lib/friendly_shipping/services/ups_freight/generate_freight_rate_request_hash.rb +2 -10
- data/lib/friendly_shipping/services/ups_freight/generate_freight_ship_request_hash.rb +81 -0
- data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +5 -2
- data/lib/friendly_shipping/services/ups_freight/generate_pickup_options_hash.rb +21 -0
- data/lib/friendly_shipping/services/ups_freight/generate_pickup_request_hash.rb +31 -0
- data/lib/friendly_shipping/services/ups_freight/label_delivery_options.rb +29 -0
- data/lib/friendly_shipping/services/ups_freight/label_document_options.rb +56 -0
- data/lib/friendly_shipping/services/ups_freight/label_email_options.rb +40 -0
- data/lib/friendly_shipping/services/ups_freight/label_item_options.rb +10 -0
- data/lib/friendly_shipping/services/ups_freight/label_options.rb +37 -0
- data/lib/friendly_shipping/services/ups_freight/label_package_options.rb +10 -0
- data/lib/friendly_shipping/services/ups_freight/label_pickup_options.rb +29 -0
- data/lib/friendly_shipping/services/ups_freight/parse_freight_label_response.rb +57 -0
- data/lib/friendly_shipping/services/ups_freight/parse_freight_rate_response.rb +29 -32
- data/lib/friendly_shipping/services/ups_freight/parse_shipment_document.rb +24 -0
- data/lib/friendly_shipping/services/ups_freight/pickup_request_options.rb +29 -0
- data/lib/friendly_shipping/services/ups_freight/rates_options.rb +3 -6
- data/lib/friendly_shipping/services/ups_freight/restful_api_error_handler.rb +24 -0
- data/lib/friendly_shipping/services/ups_freight/shipment_document.rb +21 -0
- data/lib/friendly_shipping/services/ups_freight/shipment_information.rb +35 -0
- data/lib/friendly_shipping/services/ups_freight.rb +42 -12
- data/lib/friendly_shipping/services/usps/parse_address_validation_response.rb +5 -1
- data/lib/friendly_shipping/services/usps/parse_city_state_lookup_response.rb +5 -1
- data/lib/friendly_shipping/services/usps/parse_rate_response.rb +5 -2
- data/lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb +5 -1
- data/lib/friendly_shipping/services/usps/parse_xml_response.rb +15 -5
- data/lib/friendly_shipping/version.rb +1 -1
- metadata +70 -35
- data/lib/friendly_shipping/services/ups_freight/generate_ups_security_hash.rb +0 -23
- data/lib/friendly_shipping/services/ups_freight/parse_json_response.rb +0 -38
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class LabelEmailOptions
|
7
|
+
EMAIL_TYPES = {
|
8
|
+
ship_notification: '001',
|
9
|
+
delivery_notification: '002',
|
10
|
+
exception_notification: '003',
|
11
|
+
bol_labels: '004'
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
attr_reader :email_type,
|
15
|
+
:email,
|
16
|
+
:undeliverable_email,
|
17
|
+
:subject,
|
18
|
+
:body
|
19
|
+
|
20
|
+
def initialize(
|
21
|
+
email:,
|
22
|
+
email_type:,
|
23
|
+
undeliverable_email:,
|
24
|
+
subject: nil,
|
25
|
+
body: nil
|
26
|
+
)
|
27
|
+
@email = email
|
28
|
+
@email_type = email_type
|
29
|
+
@undeliverable_email = undeliverable_email
|
30
|
+
@subject = subject
|
31
|
+
@body = body
|
32
|
+
end
|
33
|
+
|
34
|
+
def email_type_code
|
35
|
+
EMAIL_TYPES.fetch(email_type)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class LabelOptions < RatesOptions
|
7
|
+
attr_reader :document_options,
|
8
|
+
:email_options,
|
9
|
+
:pickup_options,
|
10
|
+
:delivery_options,
|
11
|
+
:pickup_instructions,
|
12
|
+
:delivery_instructions,
|
13
|
+
:handling_instructions
|
14
|
+
|
15
|
+
def initialize(
|
16
|
+
document_options: [],
|
17
|
+
email_options: [],
|
18
|
+
pickup_options: nil,
|
19
|
+
delivery_options: nil,
|
20
|
+
pickup_instructions: nil,
|
21
|
+
delivery_instructions: nil,
|
22
|
+
handling_instructions: nil,
|
23
|
+
**kwargs
|
24
|
+
)
|
25
|
+
@pickup_options = pickup_options
|
26
|
+
@delivery_options = delivery_options
|
27
|
+
@document_options = document_options
|
28
|
+
@email_options = email_options
|
29
|
+
@pickup_instructions = pickup_instructions
|
30
|
+
@delivery_instructions = delivery_instructions
|
31
|
+
@handling_instructions = handling_instructions
|
32
|
+
super kwargs
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class LabelPickupOptions
|
7
|
+
attr_reader :holiday_pickup,
|
8
|
+
:inside_pickup,
|
9
|
+
:weekend_pickup,
|
10
|
+
:lift_gate_required,
|
11
|
+
:limited_access_pickup
|
12
|
+
|
13
|
+
def initialize(
|
14
|
+
holiday_pickup: nil,
|
15
|
+
inside_pickup: nil,
|
16
|
+
weekend_pickup: nil,
|
17
|
+
lift_gate_required: nil,
|
18
|
+
limited_access_pickup: nil
|
19
|
+
)
|
20
|
+
@holiday_pickup = holiday_pickup
|
21
|
+
@inside_pickup = inside_pickup
|
22
|
+
@weekend_pickup = weekend_pickup
|
23
|
+
@lift_gate_required = lift_gate_required
|
24
|
+
@limited_access_pickup = limited_access_pickup
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'friendly_shipping/services/ups_freight/parse_shipment_document'
|
4
|
+
require 'friendly_shipping/services/ups_freight/shipment_information'
|
5
|
+
|
6
|
+
module FriendlyShipping
|
7
|
+
module Services
|
8
|
+
class UpsFreight
|
9
|
+
class ParseFreightLabelResponse
|
10
|
+
class << self
|
11
|
+
def call(request:, response:)
|
12
|
+
json = JSON.parse(response.body)
|
13
|
+
|
14
|
+
warnings_json = Array.wrap(json.dig("FreightShipResponse", "Response", "Alert"))
|
15
|
+
warnings = warnings_json.map do |detailed_warning|
|
16
|
+
status = detailed_warning['Code']
|
17
|
+
desc = detailed_warning['Description']
|
18
|
+
[status, desc].compact.join(": ")
|
19
|
+
end.join("\n")
|
20
|
+
|
21
|
+
shipment_results = json.dig("FreightShipResponse", "ShipmentResults")
|
22
|
+
|
23
|
+
service_code = shipment_results.dig("Service", "Code")
|
24
|
+
shipping_method = SHIPPING_METHODS.detect { |sm| sm.service_code == service_code }
|
25
|
+
|
26
|
+
total_shipment_charge = shipment_results.dig("TotalShipmentCharge")
|
27
|
+
currency = Money::Currency.new(total_shipment_charge['CurrencyCode'])
|
28
|
+
amount = total_shipment_charge['MonetaryValue'].to_f
|
29
|
+
total_money = Money.new(amount * currency.subunit_to_unit, currency)
|
30
|
+
|
31
|
+
images_data = Array.wrap(shipment_results.dig("Documents", "Image"))
|
32
|
+
|
33
|
+
bol_id = shipment_results.dig("BOLID")
|
34
|
+
shipment_number = shipment_results.dig("ShipmentNumber")
|
35
|
+
pickup_request_number = shipment_results.dig("PickupRequestConfirmationNumber")
|
36
|
+
|
37
|
+
documents = images_data.map { |image_data| ParseShipmentDocument.call(image_data: image_data) }
|
38
|
+
|
39
|
+
FriendlyShipping::ApiResult.new(
|
40
|
+
ShipmentInformation.new(
|
41
|
+
total: total_money,
|
42
|
+
bol_id: bol_id,
|
43
|
+
number: shipment_number,
|
44
|
+
pickup_request_number: pickup_request_number,
|
45
|
+
shipping_method: shipping_method,
|
46
|
+
warnings: warnings,
|
47
|
+
documents: documents
|
48
|
+
),
|
49
|
+
original_request: request,
|
50
|
+
original_response: response
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'friendly_shipping/rate'
|
4
4
|
require 'friendly_shipping/api_result'
|
5
|
-
require 'friendly_shipping/services/ups_freight/parse_json_response'
|
6
5
|
require 'friendly_shipping/services/ups_freight/shipping_methods'
|
7
6
|
|
8
7
|
module FriendlyShipping
|
@@ -11,40 +10,38 @@ module FriendlyShipping
|
|
11
10
|
class ParseFreightRateResponse
|
12
11
|
class << self
|
13
12
|
def call(request:, response:)
|
14
|
-
|
13
|
+
json = JSON.parse(response.body)
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
}
|
15
|
+
service_code = json.dig("FreightRateResponse", "Service", "Code")
|
16
|
+
shipping_method = SHIPPING_METHODS.detect { |sm| sm.service_code == service_code }
|
17
|
+
total_shipment_charge = json.dig("FreightRateResponse", "TotalShipmentCharge")
|
18
|
+
currency = Money::Currency.new(total_shipment_charge['CurrencyCode'])
|
19
|
+
amount = total_shipment_charge['MonetaryValue'].to_f
|
20
|
+
total_money = Money.new(amount * currency.subunit_to_unit, currency)
|
21
|
+
data = {
|
22
|
+
customer_context: json.dig("FreightRateResponse", "TransactionReference", "TransactionIdentifier"),
|
23
|
+
commodities: Array.wrap(json.dig("FreightRateResponse", "Commodity")),
|
24
|
+
response_body: json
|
25
|
+
}
|
28
26
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
end
|
33
|
-
|
34
|
-
FriendlyShipping::ApiResult.new(
|
35
|
-
[
|
36
|
-
FriendlyShipping::Rate.new(
|
37
|
-
amounts: {
|
38
|
-
total: total_money
|
39
|
-
},
|
40
|
-
shipping_method: shipping_method,
|
41
|
-
data: data
|
42
|
-
)
|
43
|
-
],
|
44
|
-
original_request: request,
|
45
|
-
original_response: response
|
46
|
-
)
|
27
|
+
days_in_transit = json.dig("FreightRateResponse", "TimeInTransit", "DaysInTransit")
|
28
|
+
if days_in_transit
|
29
|
+
data[:days_in_transit] = days_in_transit.to_i
|
47
30
|
end
|
31
|
+
|
32
|
+
FriendlyShipping::ApiResult.new(
|
33
|
+
[
|
34
|
+
FriendlyShipping::Rate.new(
|
35
|
+
amounts: {
|
36
|
+
total: total_money
|
37
|
+
},
|
38
|
+
shipping_method: shipping_method,
|
39
|
+
data: data
|
40
|
+
)
|
41
|
+
],
|
42
|
+
original_request: request,
|
43
|
+
original_response: response
|
44
|
+
)
|
48
45
|
end
|
49
46
|
end
|
50
47
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'friendly_shipping/services/ups_freight/shipment_document'
|
4
|
+
|
5
|
+
module FriendlyShipping
|
6
|
+
module Services
|
7
|
+
class UpsFreight
|
8
|
+
class ParseShipmentDocument
|
9
|
+
REVERSE_DOCUMENT_TYPES = LabelDocumentOptions::DOCUMENT_TYPES.map(&:reverse_each).map(&:to_a).to_h
|
10
|
+
|
11
|
+
def self.call(image_data:)
|
12
|
+
format_code = image_data.dig("Type", "Code")
|
13
|
+
graphic_image_b64 = image_data.dig("GraphicImage")
|
14
|
+
|
15
|
+
ShipmentDocument.new(
|
16
|
+
format: image_data.dig("Format", "Code").downcase.to_sym,
|
17
|
+
binary: Base64.decode64(graphic_image_b64),
|
18
|
+
document_type: REVERSE_DOCUMENT_TYPES.fetch(format_code)
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class PickupRequestOptions
|
7
|
+
attr_reader :pickup_time_window,
|
8
|
+
:requester,
|
9
|
+
:third_party_requester,
|
10
|
+
:requester_email,
|
11
|
+
:comments
|
12
|
+
|
13
|
+
def initialize(
|
14
|
+
pickup_time_window:,
|
15
|
+
requester:,
|
16
|
+
requester_email:,
|
17
|
+
comments: nil,
|
18
|
+
third_party_requester: false
|
19
|
+
)
|
20
|
+
@pickup_time_window = pickup_time_window
|
21
|
+
@requester = requester
|
22
|
+
@third_party_requester = third_party_requester
|
23
|
+
@requester_email = requester_email
|
24
|
+
@comments = comments
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -31,8 +31,7 @@ module FriendlyShipping
|
|
31
31
|
:billing_code,
|
32
32
|
:customer_context,
|
33
33
|
:shipping_method,
|
34
|
-
:
|
35
|
-
:pickup_comments,
|
34
|
+
:pickup_request_options,
|
36
35
|
:commodity_information_generator
|
37
36
|
|
38
37
|
def initialize(
|
@@ -41,8 +40,7 @@ module FriendlyShipping
|
|
41
40
|
shipping_method:,
|
42
41
|
billing: :prepaid,
|
43
42
|
customer_context: nil,
|
44
|
-
|
45
|
-
pickup_comments: nil,
|
43
|
+
pickup_request_options: nil,
|
46
44
|
commodity_information_generator: GenerateCommodityInformation,
|
47
45
|
**kwargs
|
48
46
|
)
|
@@ -51,8 +49,7 @@ module FriendlyShipping
|
|
51
49
|
@shipping_method = shipping_method
|
52
50
|
@billing_code = BILLING_CODES.fetch(billing)
|
53
51
|
@customer_context = customer_context
|
54
|
-
@
|
55
|
-
@pickup_comments = pickup_comments
|
52
|
+
@pickup_request_options = pickup_request_options
|
56
53
|
@commodity_information_generator = commodity_information_generator
|
57
54
|
super(**kwargs.merge(package_options_class: RatesPackageOptions))
|
58
55
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class RestfulApiErrorHandler
|
7
|
+
extend Dry::Monads::Result::Mixin
|
8
|
+
|
9
|
+
def self.call(error)
|
10
|
+
parsed_json = JSON.parse(error.response.body)
|
11
|
+
errors = parsed_json.dig('response', 'errors')
|
12
|
+
|
13
|
+
failure_string = errors.map do |err|
|
14
|
+
status = err['code']
|
15
|
+
desc = err['message']
|
16
|
+
[status, desc].compact.join(": ").presence || 'UPS could not process the request.'
|
17
|
+
end.join("\n")
|
18
|
+
|
19
|
+
Failure(failure_string)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class ShipmentDocument
|
7
|
+
attr_reader :format, :document_type, :binary
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
format:,
|
11
|
+
document_type:,
|
12
|
+
binary:
|
13
|
+
)
|
14
|
+
@format = format
|
15
|
+
@document_type = document_type
|
16
|
+
@binary = binary
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class ShipmentInformation
|
7
|
+
attr_reader :documents,
|
8
|
+
:number,
|
9
|
+
:pickup_request_number,
|
10
|
+
:total,
|
11
|
+
:bol_id,
|
12
|
+
:shipping_method,
|
13
|
+
:warnings
|
14
|
+
|
15
|
+
def initialize(
|
16
|
+
total:,
|
17
|
+
bol_id:,
|
18
|
+
number:,
|
19
|
+
pickup_request_number: nil,
|
20
|
+
documents: [],
|
21
|
+
shipping_method: nil,
|
22
|
+
warnings: nil
|
23
|
+
)
|
24
|
+
@total = total
|
25
|
+
@bol_id = bol_id
|
26
|
+
@number = number
|
27
|
+
@pickup_request_number = pickup_request_number
|
28
|
+
@documents = documents
|
29
|
+
@shipping_method = shipping_method
|
30
|
+
@warnings = warnings
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -4,11 +4,21 @@ require 'dry/monads/result'
|
|
4
4
|
require 'friendly_shipping/http_client'
|
5
5
|
require 'friendly_shipping/services/ups_freight/shipping_methods'
|
6
6
|
require 'friendly_shipping/services/ups_freight/rates_options'
|
7
|
+
require 'friendly_shipping/services/ups_freight/label_options'
|
7
8
|
require 'friendly_shipping/services/ups_freight/rates_package_options'
|
8
9
|
require 'friendly_shipping/services/ups_freight/rates_item_options'
|
10
|
+
require 'friendly_shipping/services/ups_freight/label_package_options'
|
11
|
+
require 'friendly_shipping/services/ups_freight/label_item_options'
|
12
|
+
require 'friendly_shipping/services/ups_freight/label_document_options'
|
13
|
+
require 'friendly_shipping/services/ups_freight/label_email_options'
|
14
|
+
require 'friendly_shipping/services/ups_freight/label_pickup_options'
|
15
|
+
require 'friendly_shipping/services/ups_freight/label_delivery_options'
|
16
|
+
require 'friendly_shipping/services/ups_freight/pickup_request_options'
|
17
|
+
require 'friendly_shipping/services/ups_freight/parse_freight_label_response'
|
9
18
|
require 'friendly_shipping/services/ups_freight/parse_freight_rate_response'
|
10
19
|
require 'friendly_shipping/services/ups_freight/generate_freight_rate_request_hash'
|
11
|
-
require 'friendly_shipping/services/ups_freight/
|
20
|
+
require 'friendly_shipping/services/ups_freight/generate_freight_ship_request_hash'
|
21
|
+
require 'friendly_shipping/services/ups_freight/restful_api_error_handler'
|
12
22
|
|
13
23
|
module FriendlyShipping
|
14
24
|
module Services
|
@@ -28,10 +38,11 @@ module FriendlyShipping
|
|
28
38
|
LIVE_URL = 'https://onlinetools.ups.com'
|
29
39
|
|
30
40
|
RESOURCES = {
|
31
|
-
rates: '/
|
41
|
+
rates: '/ship/v1801/freight/rating/ground',
|
42
|
+
labels: '/ship/v1607/freight/shipments/Ground'
|
32
43
|
}.freeze
|
33
44
|
|
34
|
-
def initialize(key:, login:, password:, test: true, client: HttpClient.new)
|
45
|
+
def initialize(key:, login:, password:, test: true, client: HttpClient.new(error_handler: RestfulApiErrorHandler))
|
35
46
|
@key = key
|
36
47
|
@login = login
|
37
48
|
@password = password
|
@@ -50,22 +61,41 @@ module FriendlyShipping
|
|
50
61
|
# `FriendlyShipping::ApiResult` object.
|
51
62
|
def rate_estimates(shipment, options:, debug: false)
|
52
63
|
freight_rate_request_hash = GenerateFreightRateRequestHash.call(shipment: shipment, options: options)
|
53
|
-
|
54
|
-
request = FriendlyShipping::Request.new(
|
55
|
-
url: url,
|
56
|
-
body: authentication_hash.merge(freight_rate_request_hash).to_json,
|
57
|
-
debug: debug
|
58
|
-
)
|
64
|
+
request = build_request(:rates, freight_rate_request_hash, debug)
|
59
65
|
|
60
|
-
client.post(request).
|
66
|
+
client.post(request).fmap do |response|
|
61
67
|
ParseFreightRateResponse.call(response: response, request: request)
|
62
68
|
end
|
63
69
|
end
|
64
70
|
|
71
|
+
# Get labels for a shipment
|
72
|
+
# @param [Physical::Shipment] location The shipment we want to get rates for
|
73
|
+
# @param [FriendlyShipping::Services::UpsFreight::LabelOptions] options Options for shipping this shipment.
|
74
|
+
# @return [Result<ApiResult<ShipmentInformation>] The information that you need for shipping this shipment.
|
75
|
+
def labels(shipment, options:, debug: false)
|
76
|
+
freight_ship_request_hash = GenerateFreightShipRequestHash.call(shipment: shipment, options: options)
|
77
|
+
request = build_request(:labels, freight_ship_request_hash, debug)
|
78
|
+
|
79
|
+
client.post(request).fmap do |response|
|
80
|
+
ParseFreightLabelResponse.call(response: response, request: request)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
65
84
|
private
|
66
85
|
|
67
|
-
def
|
68
|
-
|
86
|
+
def build_request(action, payload, debug)
|
87
|
+
url = base_url + RESOURCES[action]
|
88
|
+
FriendlyShipping::Request.new(
|
89
|
+
url: url,
|
90
|
+
body: payload.to_json,
|
91
|
+
headers: {
|
92
|
+
Accept: 'application/json',
|
93
|
+
Username: login,
|
94
|
+
Password: password,
|
95
|
+
AccessLicenseNumber: key
|
96
|
+
},
|
97
|
+
debug: debug
|
98
|
+
)
|
69
99
|
end
|
70
100
|
|
71
101
|
def base_url
|
@@ -12,7 +12,11 @@ module FriendlyShipping
|
|
12
12
|
# @return [Result<FriendlyShipping::AddressValidationResult>]
|
13
13
|
def call(request:, response:)
|
14
14
|
# Filter out error responses and directly return a failure
|
15
|
-
parsing_result = ParseXMLResponse.call(
|
15
|
+
parsing_result = ParseXMLResponse.call(
|
16
|
+
request: request,
|
17
|
+
response: response,
|
18
|
+
expected_root_tag: 'AddressValidateResponse'
|
19
|
+
)
|
16
20
|
parsing_result.fmap do |xml|
|
17
21
|
address = xml.root.at('Address')
|
18
22
|
suggestions = [
|
@@ -12,7 +12,11 @@ module FriendlyShipping
|
|
12
12
|
# @return [Result<FriendlyShipping::AddressValidationResult>]
|
13
13
|
def call(request:, response:)
|
14
14
|
# Filter out error responses and directly return a failure
|
15
|
-
parsing_result = ParseXMLResponse.call(
|
15
|
+
parsing_result = ParseXMLResponse.call(
|
16
|
+
request: request,
|
17
|
+
response: response,
|
18
|
+
expected_root_tag: 'CityStateLookupResponse'
|
19
|
+
)
|
16
20
|
parsing_result.fmap do |xml|
|
17
21
|
address = xml.root.at('ZipCode')
|
18
22
|
suggestions = [
|
@@ -20,8 +20,11 @@ module FriendlyShipping
|
|
20
20
|
# @return [Result<ApiResult<Array<FriendlyShipping::Rate>>>] When successfully parsing, an array of rates in a Success Monad.
|
21
21
|
def call(request:, response:, shipment:, options:)
|
22
22
|
# Filter out error responses and directly return a failure
|
23
|
-
parsing_result = ParseXMLResponse.call(
|
24
|
-
|
23
|
+
parsing_result = ParseXMLResponse.call(
|
24
|
+
request: request,
|
25
|
+
response: response,
|
26
|
+
expected_root_tag: 'RateV4Response'
|
27
|
+
)
|
25
28
|
parsing_result.fmap do |xml|
|
26
29
|
# Get all the possible rates for each package
|
27
30
|
rates_by_package = rates_from_response_node(xml, shipment, options)
|
@@ -15,7 +15,11 @@ module FriendlyShipping
|
|
15
15
|
# @return [Result<ApiResult<Array<FriendlyShipping::Timing>>>] When successfully parsing, an array of timings in a Success Monad.
|
16
16
|
def call(request:, response:)
|
17
17
|
# Filter out error responses and directly return a failure
|
18
|
-
parsing_result = ParseXMLResponse.call(
|
18
|
+
parsing_result = ParseXMLResponse.call(
|
19
|
+
request: request,
|
20
|
+
response: response,
|
21
|
+
expected_root_tag: 'SDCGetLocationsResponse'
|
22
|
+
)
|
19
23
|
parsing_result.fmap do |xml|
|
20
24
|
expedited_commitments = xml.xpath('//Expedited')
|
21
25
|
expedited_timings = parse_expedited_commitment_nodes(expedited_commitments)
|
@@ -8,18 +8,18 @@ module FriendlyShipping
|
|
8
8
|
ERROR_TAG = 'Error'
|
9
9
|
|
10
10
|
class << self
|
11
|
-
def call(
|
12
|
-
xml = Nokogiri.XML(
|
11
|
+
def call(request:, response:, expected_root_tag:)
|
12
|
+
xml = Nokogiri.XML(response.body, &:strict)
|
13
13
|
|
14
14
|
if xml.root.nil? || ![expected_root_tag, 'Error'].include?(xml.root.name)
|
15
|
-
|
15
|
+
wrap_failure('Invalid document', request, response)
|
16
16
|
elsif request_successful?(xml)
|
17
17
|
Success(xml)
|
18
18
|
else
|
19
|
-
|
19
|
+
wrap_failure(error_message(xml), request, response)
|
20
20
|
end
|
21
21
|
rescue Nokogiri::XML::SyntaxError => e
|
22
|
-
|
22
|
+
wrap_failure(e, request, response)
|
23
23
|
end
|
24
24
|
|
25
25
|
private
|
@@ -33,6 +33,16 @@ module FriendlyShipping
|
|
33
33
|
desc = xml.xpath('//Error/Description')&.text
|
34
34
|
[number, desc].select(&:present?).join(': ').presence&.strip || 'USPS could not process the request.'
|
35
35
|
end
|
36
|
+
|
37
|
+
def wrap_failure(failure, request, response)
|
38
|
+
Failure(
|
39
|
+
FriendlyShipping::ApiFailure.new(
|
40
|
+
failure,
|
41
|
+
original_request: request,
|
42
|
+
original_response: response
|
43
|
+
)
|
44
|
+
)
|
45
|
+
end
|
36
46
|
end
|
37
47
|
end
|
38
48
|
end
|