friendly_shipping 0.5.1 → 0.6.2

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop-relaxed.yml +3 -4
  3. data/.rubocop.yml +9 -0
  4. data/CHANGELOG.md +28 -1
  5. data/friendly_shipping.gemspec +12 -12
  6. data/lib/friendly_shipping/api_failure.rb +2 -15
  7. data/lib/friendly_shipping/http_client.rb +16 -9
  8. data/lib/friendly_shipping/request.rb +7 -1
  9. data/lib/friendly_shipping/services/ship_engine/bad_request_handler.rb +15 -3
  10. data/lib/friendly_shipping/services/ups.rb +8 -0
  11. data/lib/friendly_shipping/services/ups/parse_address_classification_response.rb +5 -2
  12. data/lib/friendly_shipping/services/ups/parse_address_validation_response.rb +5 -2
  13. data/lib/friendly_shipping/services/ups/parse_city_state_lookup_response.rb +5 -2
  14. data/lib/friendly_shipping/services/ups/parse_rate_response.rb +5 -1
  15. data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +5 -1
  16. data/lib/friendly_shipping/services/ups/parse_shipment_confirm_response.rb +5 -1
  17. data/lib/friendly_shipping/services/ups/parse_time_in_transit_response.rb +6 -2
  18. data/lib/friendly_shipping/services/ups/parse_void_shipment_response.rb +5 -1
  19. data/lib/friendly_shipping/services/ups/parse_xml_response.rb +16 -7
  20. data/lib/friendly_shipping/services/ups_freight.rb +44 -13
  21. data/lib/friendly_shipping/services/ups_freight/generate_delivery_options_hash.rb +21 -0
  22. data/lib/friendly_shipping/services/ups_freight/generate_document_options_hash.rb +28 -0
  23. data/lib/friendly_shipping/services/ups_freight/generate_email_options_hash.rb +25 -0
  24. data/lib/friendly_shipping/services/ups_freight/generate_freight_rate_request_hash.rb +2 -10
  25. data/lib/friendly_shipping/services/ups_freight/generate_freight_ship_request_hash.rb +81 -0
  26. data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +5 -2
  27. data/lib/friendly_shipping/services/ups_freight/generate_pickup_options_hash.rb +21 -0
  28. data/lib/friendly_shipping/services/ups_freight/generate_pickup_request_hash.rb +31 -0
  29. data/lib/friendly_shipping/services/ups_freight/label_delivery_options.rb +29 -0
  30. data/lib/friendly_shipping/services/ups_freight/label_document_options.rb +56 -0
  31. data/lib/friendly_shipping/services/ups_freight/label_email_options.rb +40 -0
  32. data/lib/friendly_shipping/services/ups_freight/label_item_options.rb +10 -0
  33. data/lib/friendly_shipping/services/ups_freight/label_options.rb +37 -0
  34. data/lib/friendly_shipping/services/ups_freight/label_package_options.rb +10 -0
  35. data/lib/friendly_shipping/services/ups_freight/label_pickup_options.rb +29 -0
  36. data/lib/friendly_shipping/services/ups_freight/parse_freight_label_response.rb +57 -0
  37. data/lib/friendly_shipping/services/ups_freight/parse_freight_rate_response.rb +29 -32
  38. data/lib/friendly_shipping/services/ups_freight/parse_shipment_document.rb +24 -0
  39. data/lib/friendly_shipping/services/ups_freight/pickup_request_options.rb +29 -0
  40. data/lib/friendly_shipping/services/ups_freight/rates_options.rb +3 -6
  41. data/lib/friendly_shipping/services/ups_freight/restful_api_error_handler.rb +30 -0
  42. data/lib/friendly_shipping/services/ups_freight/shipment_document.rb +21 -0
  43. data/lib/friendly_shipping/services/ups_freight/shipment_information.rb +35 -0
  44. data/lib/friendly_shipping/services/usps.rb +1 -0
  45. data/lib/friendly_shipping/services/usps/parse_address_validation_response.rb +5 -1
  46. data/lib/friendly_shipping/services/usps/parse_city_state_lookup_response.rb +5 -1
  47. data/lib/friendly_shipping/services/usps/parse_rate_response.rb +5 -2
  48. data/lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb +5 -1
  49. data/lib/friendly_shipping/services/usps/parse_xml_response.rb +15 -5
  50. data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +4 -1
  51. data/lib/friendly_shipping/services/usps/serialize_rate_request.rb +9 -3
  52. data/lib/friendly_shipping/services/usps/shipping_methods.rb +1 -2
  53. data/lib/friendly_shipping/version.rb +1 -1
  54. metadata +75 -40
  55. data/lib/friendly_shipping/services/ups_freight/generate_ups_security_hash.rb +0 -23
  56. 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,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class LabelItemOptions < RatesItemOptions
7
+ end
8
+ end
9
+ end
10
+ 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,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class LabelPackageOptions < RatesPackageOptions
7
+ end
8
+ end
9
+ end
10
+ 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
- parsed_json = ParseJSONResponse.call(response.body, 'FreightRateResponse')
13
+ json = JSON.parse(response.body)
15
14
 
16
- parsed_json.fmap do |json|
17
- service_code = json.dig("FreightRateResponse", "Service", "Code")
18
- shipping_method = SHIPPING_METHODS.detect { |sm| sm.service_code == service_code }
19
- total_shipment_charge = json.dig("FreightRateResponse", "TotalShipmentCharge")
20
- currency = Money::Currency.new(total_shipment_charge['CurrencyCode'])
21
- amount = total_shipment_charge['MonetaryValue'].to_f
22
- total_money = Money.new(amount * currency.subunit_to_unit, currency)
23
- data = {
24
- customer_context: json.dig("FreightRateResponse", "TransactionReference", "TransactionIdentifier"),
25
- commodities: Array.wrap(json.dig("FreightRateResponse", "Commodity")),
26
- response_body: json
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
- days_in_transit = json.dig("FreightRateResponse", "TimeInTransit", "DaysInTransit")
30
- if days_in_transit
31
- data[:days_in_transit] = days_in_transit.to_i
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
- :pickup_date,
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
- pickup_date: nil,
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
- @pickup_date = pickup_date
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,30 @@
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, original_request: nil, original_response: nil)
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(
20
+ ApiFailure.new(
21
+ failure_string,
22
+ original_request: original_request,
23
+ original_response: original_response
24
+ )
25
+ )
26
+ end
27
+ end
28
+ end
29
+ end
30
+ 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
@@ -112,6 +112,7 @@ module FriendlyShipping
112
112
  FriendlyShipping::Request.new(
113
113
  url: base_url,
114
114
  body: "API=#{RESOURCES[api]}&XML=#{CGI.escape xml}",
115
+ readable_body: xml,
115
116
  debug: debug
116
117
  )
117
118
  end