friendly_shipping 0.6.5 → 0.7.0

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +18 -5
  3. data/.env.template +1 -1
  4. data/.rubocop.yml +4 -1
  5. data/CHANGELOG.md +4 -0
  6. data/README.md +1 -1
  7. data/friendly_shipping.gemspec +3 -4
  8. data/lib/friendly_shipping/api_error.rb +14 -0
  9. data/lib/friendly_shipping/api_error_handler.rb +30 -0
  10. data/lib/friendly_shipping/http_client.rb +9 -27
  11. data/lib/friendly_shipping/request.rb +5 -3
  12. data/lib/friendly_shipping/response.rb +27 -1
  13. data/lib/friendly_shipping/services/ship_engine/parse_label_response.rb +8 -2
  14. data/lib/friendly_shipping/services/ship_engine.rb +9 -5
  15. data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +1 -1
  16. data/lib/friendly_shipping/services/ups/parse_shipment_confirm_response.rb +1 -1
  17. data/lib/friendly_shipping/services/ups/parse_void_shipment_response.rb +1 -1
  18. data/lib/friendly_shipping/services/ups/rate_estimate_options.rb +1 -1
  19. data/lib/friendly_shipping/services/ups/rate_estimate_package_options.rb +1 -1
  20. data/lib/friendly_shipping/services/ups/shipping_methods.rb +4 -0
  21. data/lib/friendly_shipping/services/ups.rb +10 -2
  22. data/lib/friendly_shipping/services/ups_freight/api_error.rb +36 -0
  23. data/lib/friendly_shipping/services/ups_freight/generate_delivery_options_hash.rb +6 -4
  24. data/lib/friendly_shipping/services/ups_freight/generate_freight_ship_request_hash.rb +5 -2
  25. data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +6 -9
  26. data/lib/friendly_shipping/services/ups_freight/generate_pickup_options_hash.rb +4 -3
  27. data/lib/friendly_shipping/services/ups_freight/generate_reference_hash.rb +27 -0
  28. data/lib/friendly_shipping/services/ups_freight/label_delivery_options.rb +7 -1
  29. data/lib/friendly_shipping/services/ups_freight/label_options.rb +28 -2
  30. data/lib/friendly_shipping/services/ups_freight/label_pickup_options.rb +3 -0
  31. data/lib/friendly_shipping/services/ups_freight/parse_freight_label_response.rb +27 -8
  32. data/lib/friendly_shipping/services/ups_freight/parse_shipment_document.rb +1 -1
  33. data/lib/friendly_shipping/services/ups_freight/shipment_information.rb +5 -2
  34. data/lib/friendly_shipping/services/ups_freight.rb +8 -5
  35. data/lib/friendly_shipping/services/usps/rate_estimate_options.rb +1 -1
  36. data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +17 -21
  37. data/lib/friendly_shipping/services/usps.rb +2 -1
  38. data/lib/friendly_shipping/version.rb +1 -1
  39. data/lib/friendly_shipping.rb +1 -0
  40. metadata +12 -35
  41. data/lib/friendly_shipping/services/ups_freight/restful_api_error_handler.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 921ae3f517c9fcf14e7932e110b6468d7bf2b78e46864bb50a3272b6257e2bea
4
- data.tar.gz: d7cf64cc30bedd17adca882b9365f647498f8c4430f59e0a4fe1a00efe1ac017
3
+ metadata.gz: 4e5444887ead0f957efaa619fc49bf737c34513f8a2480504beaabdbdab0eb2d
4
+ data.tar.gz: c52c103c53e9be10cef0d6288c1713de54441e536f8691cf0685c2bb0a4859ff
5
5
  SHA512:
6
- metadata.gz: 9080b93ddde6399677499cb65e6b1a184985af772067548b45c977fd6d8744c9c6a08899c2b27426e3fcd795b13950141d017183c40aa25026d7cb3bf2eeb120
7
- data.tar.gz: 413036408bfc7852a141c1b19e557b7533ca3288b371e6f5e09d78da279ef470bd764c9c46de145fbc6a079de9b18b858cb5bff75b972d3bed76ce4a946a2626
6
+ metadata.gz: eff139906b09356f48bbb34e39587f41f3802cba25abb87921b7e2883865d399d4b043b793c5e0ca40fddf9fe9ca00b326be39722466a9c59c83020a67d6674e
7
+ data.tar.gz: 396fe842544a93357d601d383a27d116b5b6f4e2947fec39703e7bd70a57b8fe30a63f68eb7312761db56e3533d59fbf70a3c87bb673ac3d497912c84b5a703b
data/.circleci/config.yml CHANGED
@@ -2,12 +2,15 @@
2
2
  #
3
3
  # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
4
  #
5
- version: 2
5
+ version: 2.1
6
6
  jobs:
7
- build:
7
+ test:
8
+ parameters:
9
+ ruby-version:
10
+ type: string
8
11
  docker:
9
12
  # specify the version you desire here
10
- - image: circleci/ruby:2.5
13
+ - image: cimg/ruby:<< parameters.ruby-version >>
11
14
 
12
15
  # Specify service dependencies here if necessary
13
16
  # CircleCI maintains a library of pre-built images
@@ -22,7 +25,7 @@ jobs:
22
25
  # Download and cache dependencies
23
26
  - restore_cache:
24
27
  keys:
25
- - v1-dependencies-{{ checksum "friendly_shipping.gemspec" }}
28
+ - v1-dependencies-{{ checksum "friendly_shipping.gemspec" }}-<< parameters.ruby-version >>
26
29
  # fallback to using the latest cache if no exact match is found
27
30
  - v1-dependencies-
28
31
 
@@ -35,7 +38,7 @@ jobs:
35
38
  - save_cache:
36
39
  paths:
37
40
  - ./vendor/bundle
38
- key: v1-dependencies-{{ checksum "Gemfile.lock" }}
41
+ key: v1-dependencies-{{ checksum "Gemfile.lock" }}-<< parameters.ruby-version >>
39
42
 
40
43
  - run:
41
44
  name: run Rubocop
@@ -60,3 +63,13 @@ jobs:
60
63
  - store_artifacts:
61
64
  path: /tmp/test-results
62
65
  destination: test-results
66
+
67
+ workflows:
68
+ build_and_test:
69
+ jobs:
70
+ - test:
71
+ matrix:
72
+ parameters:
73
+ # https://github.com/CircleCI-Public/cimg-ruby
74
+ # only supports the last three ruby versions
75
+ ruby-version: ["3.1", "3.0", "2.7"]
data/.env.template CHANGED
@@ -2,7 +2,7 @@
2
2
  # NO PASSWORDS OR SENSITIVE INFORMATION SHOULD BE STORED HERE
3
3
  # Only pass along how those passwords/info are reference via ENV VARS
4
4
 
5
- SHIPENGINE_API_KEY=Ship Engine API key
5
+ SHIPENGINE_API_KEY=ShipEngine API key
6
6
  SHIPENGINE_CARRIER_ID=Carrier ID from your ShipEngine account to run test labels with
7
7
 
8
8
  UPS_KEY=UPS API access key
data/.rubocop.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.5
2
+ TargetRubyVersion: 2.7
3
3
 
4
4
  inherit_from:
5
5
  - .rubocop-relaxed.yml
@@ -15,3 +15,6 @@ Style/HashTransformKeys:
15
15
 
16
16
  Style/HashTransformValues:
17
17
  Enabled: true
18
+
19
+ Naming/VariableNumber:
20
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.7.0] - 2022-12-14
8
+ - Removes dependency on unmaintained data_uri gem
9
+ - Bumps required Ruby to 2.7
10
+
7
11
  ## [0.6.5] - 2022-04-25
8
12
 
9
13
  ### Added
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # FriendlyShipping - the friendly shipping provider API wrapper
2
2
 
3
- This gem provides wrappers for popular shipping provider APIs. Currently, there are implementations for rate quoting and address validation, as well as shipping label generation via the `ShipStation` API.
3
+ This gem provides wrappers for popular shipping provider APIs. Currently, there are implementations for rate quoting and address validation, as well as shipping label generation via the `ShipEngine` API.
4
4
 
5
5
  ## Installation
6
6
 
@@ -22,13 +22,12 @@ Gem::Specification.new do |spec|
22
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
23
23
  spec.require_paths = ["lib"]
24
24
 
25
- spec.add_runtime_dependency "data_uri", ">= 0.0.3", "< 0.2.0"
26
25
  spec.add_runtime_dependency "dry-monads", "~> 1.0"
27
26
  spec.add_runtime_dependency "money", "~> 6.0"
28
27
  spec.add_runtime_dependency "nokogiri", "~> 1.6"
29
- spec.add_runtime_dependency "physical", "~> 0.4", ">= 0.4.4"
28
+ spec.add_runtime_dependency "physical", "~> 0.4", ">= 0.4.5"
30
29
  spec.add_runtime_dependency "rest-client", "~> 2.0"
31
- spec.required_ruby_version = '>= 2.5'
30
+ spec.required_ruby_version = '>= 2.7'
32
31
 
33
32
  spec.add_development_dependency "bundler", ">= 2.1.4", "< 3"
34
33
  spec.add_development_dependency "dotenv", "~> 2.7"
@@ -37,7 +36,7 @@ Gem::Specification.new do |spec|
37
36
  spec.add_development_dependency "rake", ">= 12.3.3"
38
37
  spec.add_development_dependency "rspec", "~> 3.0"
39
38
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.4"
40
- spec.add_development_dependency "rubocop", ">= 0.80", "< 1"
39
+ spec.add_development_dependency "rubocop"
41
40
  spec.add_development_dependency "simplecov", "~> 0.17"
42
41
  spec.add_development_dependency "vcr", "~> 6.0"
43
42
  spec.add_development_dependency "webmock", "~> 3.6"
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ class ApiError < StandardError
5
+ attr_reader :cause
6
+
7
+ # @param [RestClient::Exception] cause
8
+ # @param [String] msg
9
+ def initialize(cause, msg = nil)
10
+ @cause = cause
11
+ super msg || cause.message
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'friendly_shipping/api_error'
4
+
5
+ module FriendlyShipping
6
+ class ApiErrorHandler
7
+ include Dry::Monads[:result]
8
+
9
+ attr_reader :api_error_class
10
+
11
+ # @param [Class] api_error_class
12
+ def initialize(api_error_class: FriendlyShipping::ApiError)
13
+ @api_error_class = api_error_class
14
+ end
15
+
16
+ # @param [StandardError] error
17
+ # @param [FriendlyShipping::Request] original_request
18
+ # @param [RestClient::Response] original_response
19
+ # @return [Dry::Monads::Failure<FriendlyShipping::ApiFailure>]
20
+ def call(error, original_request: nil, original_response: nil)
21
+ Failure(
22
+ ApiFailure.new(
23
+ api_error_class.new(error),
24
+ original_request: original_request,
25
+ original_response: Response.new_from_rest_client_response(original_response)
26
+ )
27
+ )
28
+ end
29
+ end
30
+ end
@@ -1,17 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/result'
4
- require 'friendly_shipping/api_failure'
3
+ require 'dry/monads'
5
4
  require 'rest-client'
6
5
 
6
+ require 'friendly_shipping/api_failure'
7
+ require 'friendly_shipping/api_error_handler'
8
+
7
9
  module FriendlyShipping
8
10
  class HttpClient
9
- include Dry::Monads::Result::Mixin
11
+ include Dry::Monads[:result]
10
12
 
11
13
  attr_reader :error_handler
12
14
 
13
15
  # @param [Proc] error_handler Called to handle an error if one occurs
14
- def initialize(error_handler: method(:wrap_in_failure))
16
+ def initialize(error_handler: FriendlyShipping::ApiErrorHandler.new)
15
17
  @error_handler = error_handler
16
18
  end
17
19
 
@@ -20,7 +22,7 @@ module FriendlyShipping
20
22
  request.url, request.headers
21
23
  )
22
24
 
23
- Success(convert_to_friendly_response(http_response))
25
+ Success(Response.new_from_rest_client_response(http_response))
24
26
  rescue ::RestClient::Exception => e
25
27
  error_handler.call(e, original_request: request, original_response: e.response)
26
28
  end
@@ -32,7 +34,7 @@ module FriendlyShipping
32
34
  request.headers
33
35
  )
34
36
 
35
- Success(convert_to_friendly_response(http_response))
37
+ Success(Response.new_from_rest_client_response(http_response))
36
38
  rescue ::RestClient::Exception => e
37
39
  error_handler.call(e, original_request: request, original_response: e.response)
38
40
  end
@@ -44,29 +46,9 @@ module FriendlyShipping
44
46
  request.headers
45
47
  )
46
48
 
47
- Success(convert_to_friendly_response(http_response))
49
+ Success(Response.new_from_rest_client_response(http_response))
48
50
  rescue ::RestClient::Exception => e
49
51
  error_handler.call(e, original_request: request, original_response: e.response)
50
52
  end
51
-
52
- private
53
-
54
- def wrap_in_failure(error, original_request: nil, original_response: nil)
55
- Failure(
56
- ApiFailure.new(
57
- error,
58
- original_request: original_request,
59
- original_response: original_response
60
- )
61
- )
62
- end
63
-
64
- def convert_to_friendly_response(http_response)
65
- FriendlyShipping::Response.new(
66
- status: http_response.code,
67
- body: http_response.body,
68
- headers: http_response.headers
69
- )
70
- end
71
53
  end
72
54
  end
@@ -2,15 +2,17 @@
2
2
 
3
3
  module FriendlyShipping
4
4
  class Request
5
- attr_reader :url, :body, :headers, :debug
5
+ attr_reader :url, :http_method, :body, :headers, :debug
6
6
 
7
7
  # @param [String] url The HTTP request URL
8
+ # @param [String] http_method The HTTP request method
8
9
  # @param [String] body The HTTP request body
9
- # # @param [String] readable_body Human-readable HTTP request body
10
+ # @param [String] readable_body Human-readable HTTP request body
10
11
  # @param [Hash] headers The HTTP request headers
11
12
  # @param [Boolean] debug Whether to debug the request
12
- def initialize(url:, body: nil, readable_body: nil, headers: {}, debug: false)
13
+ def initialize(url:, http_method: nil, body: nil, readable_body: nil, headers: {}, debug: false)
13
14
  @url = url
15
+ @http_method = http_method
14
16
  @body = body
15
17
  @readable_body = readable_body
16
18
  @headers = headers
@@ -10,7 +10,33 @@ module FriendlyShipping
10
10
  def initialize(status:, body:, headers:)
11
11
  @status = status
12
12
  @body = body
13
- @headers = headers
13
+ @headers = headers || {}
14
+ end
15
+
16
+ alias_method :code, :status
17
+
18
+ # @param [RestClient::Response] response
19
+ # @return [FriendlyShipping::Response]
20
+ def self.new_from_rest_client_response(response)
21
+ new(status: response&.code, body: response&.body, headers: response&.headers)
22
+ end
23
+
24
+ # @param [Object] other
25
+ def ==(other)
26
+ other.class == self.class &&
27
+ other.attributes == attributes
28
+ end
29
+
30
+ alias_method :eql?, :==
31
+
32
+ def hash
33
+ attributes.hash
34
+ end
35
+
36
+ protected
37
+
38
+ def attributes
39
+ [status, body, headers]
14
40
  end
15
41
  end
16
42
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'json'
4
- require 'data_uri'
5
4
 
6
5
  module FriendlyShipping
7
6
  module Services
@@ -14,7 +13,14 @@ module FriendlyShipping
14
13
  label_data = nil
15
14
  label_url = nil
16
15
  if label_uri_string.starts_with?('data')
17
- label_data = URI::Data.new(label_uri_string).data
16
+ # This URI has the following form:
17
+ # data:application/zpl;base64,XlhBDQpeTEwxMjE4....
18
+ # We don't know the content type here, but we can assume Base64
19
+ # encoding.
20
+ # This next line splits the URI at the first occurrence of ";base64,",
21
+ # giving us the desired base64 encoded string.
22
+ _, base64_encoded = label_uri_string.split(";base64,", 2)
23
+ label_data = Base64.decode64(base64_encoded)
18
24
  else
19
25
  label_url = label_uri_string
20
26
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/result'
3
+ require 'dry/monads'
4
4
  require 'friendly_shipping/http_client'
5
5
  require 'friendly_shipping/services/ship_engine/bad_request_handler'
6
6
  require 'friendly_shipping/services/ship_engine/parse_carrier_response'
@@ -28,12 +28,13 @@ module FriendlyShipping
28
28
  @client = client
29
29
  end
30
30
 
31
- # Get configured carriers from USPS
31
+ # Get configured carriers from ShipEngine
32
32
  #
33
- # @return [Result<ApiResult<Array<Carrier>>>] Carriers configured in your shipstation account
33
+ # @return [Result<ApiResult<Array<Carrier>>>] Carriers configured in your account
34
34
  def carriers(debug: false)
35
35
  request = FriendlyShipping::Request.new(
36
36
  url: API_BASE + API_PATHS[:carriers],
37
+ http_method: "GET",
37
38
  headers: request_headers,
38
39
  debug: debug
39
40
  )
@@ -53,7 +54,8 @@ module FriendlyShipping
53
54
  # can be serialized into an error message using `to_s`.
54
55
  def rate_estimates(shipment, options: FriendlyShipping::Services::ShipEngine::RateEstimatesOptions.new, debug: false)
55
56
  request = FriendlyShipping::Request.new(
56
- url: API_BASE + 'rates/estimate',
57
+ url: "#{API_BASE}rates/estimate",
58
+ http_method: "POST",
57
59
  body: SerializeRateEstimateRequest.call(shipment: shipment, options: options).to_json,
58
60
  headers: request_headers,
59
61
  debug: debug
@@ -68,13 +70,14 @@ module FriendlyShipping
68
70
  # @param [Physical::Shipment] shipment The shipment object we're trying to get labels for
69
71
  # Note: Some ShipEngine carriers, notably USPS, only support one package per shipment, and that's
70
72
  # all that the integration supports at this point.
71
- # @param [FriendlyShipping::Services::ShipEngine::LabelOptions] The options relevant to estimating rates. See object description.
73
+ # @param [FriendlyShipping::Services::ShipEngine::LabelOptions] options The options relevant to estimating rates. See object description.
72
74
  #
73
75
  # @return [Result<ApiResult<Array<FriendlyShipping::Label>>>] The label returned.
74
76
  #
75
77
  def labels(shipment, options:)
76
78
  request = FriendlyShipping::Request.new(
77
79
  url: API_BASE + API_PATHS[:labels],
80
+ http_method: "POST",
78
81
  body: SerializeLabelShipment.call(shipment: shipment, options: options, test: test).to_json,
79
82
  headers: request_headers
80
83
  )
@@ -86,6 +89,7 @@ module FriendlyShipping
86
89
  def void(label, debug: false)
87
90
  request = FriendlyShipping::Request.new(
88
91
  url: "#{API_BASE}labels/#{label.id}/void",
92
+ http_method: "PUT",
89
93
  body: '',
90
94
  headers: request_headers,
91
95
  debug: debug
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/result'
3
+ require 'dry/monads'
4
4
  require 'friendly_shipping/services/ups/parse_money_element'
5
5
 
6
6
  module FriendlyShipping
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/result'
3
+ require 'dry/monads'
4
4
 
5
5
  module FriendlyShipping
6
6
  module Services
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/result'
3
+ require 'dry/monads'
4
4
 
5
5
  module FriendlyShipping
6
6
  module Services
@@ -84,7 +84,7 @@ module FriendlyShipping
84
84
  @shipper = shipper
85
85
  @shipping_method = shipping_method
86
86
  @with_time_in_transit = with_time_in_transit
87
- super kwargs.merge(package_options_class: package_options_class)
87
+ super(**kwargs.merge(package_options_class: package_options_class))
88
88
  end
89
89
 
90
90
  def pickup_type_code
@@ -16,7 +16,7 @@ module FriendlyShipping
16
16
  **kwargs
17
17
  )
18
18
  @transmit_dimensions = transmit_dimensions
19
- super kwargs
19
+ super(**kwargs)
20
20
  end
21
21
  end
22
22
  end
@@ -39,6 +39,10 @@ module FriendlyShipping
39
39
  ['US', 'domestic', 'UPS Next Day Air', '01'],
40
40
  ['US', 'domestic', 'UPS Next Day Air Early', '14'],
41
41
  ['US', 'domestic', 'UPS Next Day Air Saver', '13'],
42
+ ['US', 'domestic', 'UPS SurePost Less than 1LB', '92'],
43
+ ['US', 'domestic', 'UPS SurePost 1LB or greater', '93'],
44
+ ['US', 'domestic', 'UPS SurePost BPM', '94'],
45
+ ['US', 'domestic', 'UPS SurePost Media Mail', '95'],
42
46
  ['CA', 'domestic', 'UPS Expedited Canadian domestic shipments', '02'],
43
47
  ['CA', 'domestic', 'UPS Express Saver Canadian domestic shipments', '13'],
44
48
  ['CA', 'domestic', 'UPS 3 Day Select Shipments originating in Canada to CA and US 48', '12'],
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/result'
3
+ require 'dry/monads'
4
4
  require 'friendly_shipping/http_client'
5
5
  require 'friendly_shipping/services/ups/serialize_access_request'
6
6
  require 'friendly_shipping/services/ups/serialize_city_state_lookup_request'
@@ -26,7 +26,7 @@ require 'friendly_shipping/services/ups/timing_options'
26
26
  module FriendlyShipping
27
27
  module Services
28
28
  class Ups
29
- include Dry::Monads::Result::Mixin
29
+ include Dry::Monads[:result]
30
30
 
31
31
  attr_reader :test, :key, :login, :password, :client
32
32
 
@@ -73,6 +73,7 @@ module FriendlyShipping
73
73
  url = base_url + RESOURCES[:rates]
74
74
  request = FriendlyShipping::Request.new(
75
75
  url: url,
76
+ http_method: "POST",
76
77
  body: access_request_xml + rate_request_xml,
77
78
  readable_body: rate_request_xml,
78
79
  debug: debug
@@ -95,6 +96,7 @@ module FriendlyShipping
95
96
 
96
97
  request = FriendlyShipping::Request.new(
97
98
  url: time_in_transit_url,
99
+ http_method: "POST",
98
100
  body: access_request_xml + time_in_transit_request_xml,
99
101
  readable_body: time_in_transit_request_xml,
100
102
  debug: debug
@@ -115,6 +117,7 @@ module FriendlyShipping
115
117
 
116
118
  ship_confirm_request = FriendlyShipping::Request.new(
117
119
  url: ship_confirm_url,
120
+ http_method: "POST",
118
121
  body: access_request_xml + ship_confirm_request_xml,
119
122
  readable_body: ship_confirm_request_xml,
120
123
  debug: debug
@@ -134,6 +137,7 @@ module FriendlyShipping
134
137
 
135
138
  ship_accept_request = FriendlyShipping::Request.new(
136
139
  url: ship_accept_url,
140
+ http_method: "POST",
137
141
  body: access_request_xml + ship_accept_request_xml,
138
142
  readable_body: ship_accept_request_xml,
139
143
  debug: debug
@@ -156,6 +160,7 @@ module FriendlyShipping
156
160
  url = base_url + RESOURCES[:address_validation]
157
161
  request = FriendlyShipping::Request.new(
158
162
  url: url,
163
+ http_method: "POST",
159
164
  body: access_request_xml + address_validation_request_xml,
160
165
  readable_body: address_validation_request_xml,
161
166
  debug: debug
@@ -174,6 +179,7 @@ module FriendlyShipping
174
179
  url = base_url + RESOURCES[:address_validation]
175
180
  request = FriendlyShipping::Request.new(
176
181
  url: url,
182
+ http_method: "POST",
177
183
  body: access_request_xml + address_validation_request_xml,
178
184
  readable_body: address_validation_request_xml,
179
185
  debug: debug
@@ -193,6 +199,7 @@ module FriendlyShipping
193
199
  url = base_url + RESOURCES[:city_state_lookup]
194
200
  request = FriendlyShipping::Request.new(
195
201
  url: url,
202
+ http_method: "POST",
196
203
  body: access_request_xml + city_state_lookup_request_xml,
197
204
  readable_body: city_state_lookup_request_xml,
198
205
  debug: debug
@@ -208,6 +215,7 @@ module FriendlyShipping
208
215
  void_request_xml = SerializeVoidShipmentRequest.call(label: label)
209
216
  request = FriendlyShipping::Request.new(
210
217
  url: url,
218
+ http_method: "POST",
211
219
  body: access_request_xml + void_request_xml,
212
220
  readable_body: void_request_xml,
213
221
  debug: debug
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'friendly_shipping/api_error'
4
+
5
+ module FriendlyShipping
6
+ module Services
7
+ class UpsFreight
8
+ class ApiError < FriendlyShipping::ApiError
9
+ # @param [RestClient::Exception] cause
10
+ def initialize(cause)
11
+ super cause, parse_message(cause)
12
+ end
13
+
14
+ private
15
+
16
+ # @param [RestClient::Exception] cause
17
+ def parse_message(cause)
18
+ parsed_json = JSON.parse(cause.response.body)
19
+
20
+ if parsed_json['httpCode'].present?
21
+ status = [parsed_json['httpCode'], parsed_json['httpMessage']].compact.join(" ")
22
+ desc = parsed_json['moreInformation']
23
+ [status, desc].compact.join(": ")
24
+ else
25
+ errors = parsed_json.dig('response', 'errors') || []
26
+ errors.map do |err|
27
+ status = err['code']
28
+ desc = err['message']
29
+ [status, desc].compact.join(": ").presence || "UPS Freight could not process the request."
30
+ end.join("\n")
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -7,11 +7,13 @@ module FriendlyShipping
7
7
  def self.call(delivery_options:)
8
8
  {
9
9
  DeliveryOptions: {
10
+ CallBeforeDeliveryIndicator: delivery_options.call_before_delivery ? "" : nil,
11
+ HolidayDeliveryIndicator: delivery_options.holiday_delivery ? "" : nil,
12
+ InsideDeliveryIndicator: delivery_options.inside_delivery ? "" : nil,
13
+ ResidentialDeliveryIndicator: delivery_options.residential_delivery ? "" : nil,
14
+ WeekendDeliveryIndicator: delivery_options.weekend_delivery ? "" : nil,
10
15
  LiftGateRequiredIndicator: delivery_options.lift_gate_required ? "" : nil,
11
- WeekendPickupIndicator: delivery_options.weekend_delivery ? "" : nil,
12
- InsidePickupIndicator: delivery_options.inside_delivery ? "" : nil,
13
- HolidayPickupIndicator: delivery_options.holiday_delivery ? "" : nil,
14
- LimitedAccessPickupIndicator: delivery_options.limited_access_delivery ? "" : nil
16
+ LimitedAccessDeliveryIndicator: delivery_options.limited_access_delivery ? "" : nil
15
17
  }.compact.presence
16
18
  }.compact.presence
17
19
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'friendly_shipping/services/ups_freight/generate_location_hash'
4
+ require 'friendly_shipping/services/ups_freight/generate_reference_hash'
4
5
  require 'friendly_shipping/services/ups_freight/generate_document_options_hash'
5
6
  require 'friendly_shipping/services/ups_freight/generate_email_options_hash'
6
7
  require 'friendly_shipping/services/ups_freight/generate_pickup_options_hash'
@@ -30,8 +31,10 @@ module FriendlyShipping
30
31
  HandlingInstructions: options.handling_instructions,
31
32
  PickupInstructions: options.pickup_instructions,
32
33
  DeliveryInstructions: options.delivery_instructions,
33
- PickupRequest: GeneratePickupRequestHash.call(pickup_request_options: options.pickup_request_options)
34
- }.compact.merge(handling_units(shipment, options).reduce(&:merge).to_h)
34
+ PickupRequest: GeneratePickupRequestHash.call(pickup_request_options: options.pickup_request_options),
35
+ }.compact.
36
+ merge(handling_units(shipment, options).reduce(&:merge).to_h).
37
+ merge(GenerateReferenceHash.call(reference_numbers: options.reference_numbers))
35
38
  }
36
39
  }
37
40
  end
@@ -6,16 +6,14 @@ module FriendlyShipping
6
6
  class GenerateLocationHash
7
7
  class << self
8
8
  def call(location:)
9
- # We ship freight here, which will mostly be used for businesses.
10
- # If a personal name is given, treat is as the contact person ("AttentionName")
11
9
  {
12
- Name: location.company_name,
10
+ Name: location.company_name.presence || location.name,
13
11
  Address: {
14
12
  AddressLine: address_line(location),
15
13
  City: location.city,
16
- StateProvinceCode: location.region.code,
14
+ StateProvinceCode: location.region&.code,
17
15
  PostalCode: location.zip,
18
- CountryCode: location.country.code
16
+ CountryCode: location.country&.code
19
17
  },
20
18
  AttentionName: location.name,
21
19
  Phone: {
@@ -27,13 +25,12 @@ module FriendlyShipping
27
25
  private
28
26
 
29
27
  def address_line(location)
30
- [
28
+ address_lines = [
31
29
  location.address1,
32
30
  location.address2,
33
31
  location.address3
34
- ].compact.
35
- reject(&:empty?).
36
- join(", ")
32
+ ].compact.reject(&:empty?)
33
+ address_lines.size > 1 ? address_lines : address_lines.first
37
34
  end
38
35
  end
39
36
  end
@@ -7,10 +7,11 @@ module FriendlyShipping
7
7
  def self.call(pickup_options:)
8
8
  {
9
9
  PickupOptions: {
10
- LiftGateRequiredIndicator: pickup_options.lift_gate_required ? "" : nil,
11
- WeekendPickupIndicator: pickup_options.weekend_pickup ? "" : nil,
12
- InsidePickupIndicator: pickup_options.inside_pickup ? "" : nil,
13
10
  HolidayPickupIndicator: pickup_options.holiday_pickup ? "" : nil,
11
+ InsidePickupIndicator: pickup_options.inside_pickup ? "" : nil,
12
+ ResidentialPickupIndicator: pickup_options.residential_pickup ? "" : nil,
13
+ WeekendPickupIndicator: pickup_options.weekend_pickup ? "" : nil,
14
+ LiftGateRequiredIndicator: pickup_options.lift_gate_required ? "" : nil,
14
15
  LimitedAccessPickupIndicator: pickup_options.limited_access_pickup ? "" : nil
15
16
  }.compact.presence
16
17
  }.compact.presence
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class GenerateReferenceHash
7
+ class << self
8
+ # @param [Array] reference_numbers Reference numbers for the Bill of Lading
9
+ # @return [Hash] Reference hash suitable for JSON request
10
+ def call(reference_numbers:)
11
+ return {} unless reference_numbers
12
+
13
+ references = reference_numbers.map do |reference_number|
14
+ {
15
+ Number: {
16
+ Code: reference_number[:code],
17
+ Value: reference_number[:value]
18
+ }
19
+ }
20
+ end
21
+ references.any? ? { Reference: references } : {}
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -4,21 +4,27 @@ module FriendlyShipping
4
4
  module Services
5
5
  class UpsFreight
6
6
  class LabelDeliveryOptions
7
- attr_reader :holiday_delivery,
7
+ attr_reader :call_before_delivery,
8
+ :holiday_delivery,
8
9
  :inside_delivery,
10
+ :residential_delivery,
9
11
  :weekend_delivery,
10
12
  :lift_gate_required,
11
13
  :limited_access_delivery
12
14
 
13
15
  def initialize(
16
+ call_before_delivery: nil,
14
17
  holiday_delivery: nil,
15
18
  inside_delivery: nil,
19
+ residential_delivery: nil,
16
20
  weekend_delivery: nil,
17
21
  lift_gate_required: nil,
18
22
  limited_access_delivery: nil
19
23
  )
24
+ @call_before_delivery = call_before_delivery
20
25
  @holiday_delivery = holiday_delivery
21
26
  @inside_delivery = inside_delivery
27
+ @residential_delivery = residential_delivery
22
28
  @weekend_delivery = weekend_delivery
23
29
  @lift_gate_required = lift_gate_required
24
30
  @limited_access_delivery = limited_access_delivery
@@ -4,14 +4,30 @@ module FriendlyShipping
4
4
  module Services
5
5
  class UpsFreight
6
6
  class LabelOptions < RatesOptions
7
+ REFERENCE_NUMBER_CODES = {
8
+ bill_of_lading_number: "57",
9
+ purchase_order_number: "28",
10
+ shipper_reference: "SH",
11
+ consignee_reference: "CO",
12
+ pm: "PM",
13
+ proj: "PROJ",
14
+ quote: "QUOTE",
15
+ sid: "SID",
16
+ task: "TASK",
17
+ vprc: "VPRC",
18
+ other: "OTHER"
19
+ }.freeze
20
+
7
21
  attr_reader :document_options,
8
22
  :email_options,
9
23
  :pickup_options,
10
24
  :delivery_options,
11
25
  :pickup_instructions,
12
26
  :delivery_instructions,
13
- :handling_instructions
27
+ :handling_instructions,
28
+ :reference_numbers
14
29
 
30
+ # @param [Array] reference_numbers Reference numbers for the Bill of Lading
15
31
  def initialize(
16
32
  document_options: [],
17
33
  email_options: [],
@@ -20,6 +36,7 @@ module FriendlyShipping
20
36
  pickup_instructions: nil,
21
37
  delivery_instructions: nil,
22
38
  handling_instructions: nil,
39
+ reference_numbers: [],
23
40
  **kwargs
24
41
  )
25
42
  @pickup_options = pickup_options
@@ -29,7 +46,16 @@ module FriendlyShipping
29
46
  @pickup_instructions = pickup_instructions
30
47
  @delivery_instructions = delivery_instructions
31
48
  @handling_instructions = handling_instructions
32
- super kwargs
49
+ @reference_numbers = fill_codes(reference_numbers)
50
+ super(**kwargs)
51
+ end
52
+
53
+ private
54
+
55
+ def fill_codes(reference_numbers)
56
+ reference_numbers.each do |reference_number|
57
+ reference_number[:code] = REFERENCE_NUMBER_CODES.fetch(reference_number[:code])
58
+ end
33
59
  end
34
60
  end
35
61
  end
@@ -6,6 +6,7 @@ module FriendlyShipping
6
6
  class LabelPickupOptions
7
7
  attr_reader :holiday_pickup,
8
8
  :inside_pickup,
9
+ :residential_pickup,
9
10
  :weekend_pickup,
10
11
  :lift_gate_required,
11
12
  :limited_access_pickup
@@ -13,12 +14,14 @@ module FriendlyShipping
13
14
  def initialize(
14
15
  holiday_pickup: nil,
15
16
  inside_pickup: nil,
17
+ residential_pickup: nil,
16
18
  weekend_pickup: nil,
17
19
  lift_gate_required: nil,
18
20
  limited_access_pickup: nil
19
21
  )
20
22
  @holiday_pickup = holiday_pickup
21
23
  @inside_pickup = inside_pickup
24
+ @residential_pickup = residential_pickup
22
25
  @weekend_pickup = weekend_pickup
23
26
  @lift_gate_required = lift_gate_required
24
27
  @limited_access_pickup = limited_access_pickup
@@ -23,19 +23,23 @@ module FriendlyShipping
23
23
  service_code = shipment_results.dig("Service", "Code")
24
24
  shipping_method = SHIPPING_METHODS.detect { |sm| sm.service_code == service_code }
25
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)
26
+ total_shipment_charge = shipment_results["TotalShipmentCharge"]
27
+ if total_shipment_charge
28
+ currency = Money::Currency.new(total_shipment_charge['CurrencyCode'])
29
+ amount = total_shipment_charge['MonetaryValue'].to_f
30
+ total_money = Money.new(amount * currency.subunit_to_unit, currency)
31
+ end
30
32
 
31
33
  images_data = Array.wrap(shipment_results.dig("Documents", "Image"))
32
34
 
33
- bol_id = shipment_results.dig("BOLID")
34
- shipment_number = shipment_results.dig("ShipmentNumber")
35
- pickup_request_number = shipment_results.dig("PickupRequestConfirmationNumber")
35
+ bol_id = shipment_results["BOLID"]
36
+ shipment_number = shipment_results["ShipmentNumber"]
37
+ pickup_request_number = shipment_results["PickupRequestConfirmationNumber"]
36
38
 
37
39
  documents = images_data.map { |image_data| ParseShipmentDocument.call(image_data: image_data) }
38
40
 
41
+ cost_breakdown = build_cost_breakdown(shipment_results)
42
+
39
43
  FriendlyShipping::ApiResult.new(
40
44
  ShipmentInformation.new(
41
45
  total: total_money,
@@ -44,12 +48,27 @@ module FriendlyShipping
44
48
  pickup_request_number: pickup_request_number,
45
49
  shipping_method: shipping_method,
46
50
  warnings: warnings,
47
- documents: documents
51
+ documents: documents,
52
+ data: {
53
+ cost_breakdown: cost_breakdown
54
+ }
48
55
  ),
49
56
  original_request: request,
50
57
  original_response: response
51
58
  )
52
59
  end
60
+
61
+ private
62
+
63
+ def build_cost_breakdown(shipment_results)
64
+ {
65
+ "Rates" => shipment_results.fetch("Rate", []).each_with_object({}) do |rate, hash|
66
+ hash[rate.dig("Type", "Code")] = rate.dig("Factor", "Value")
67
+ end,
68
+ "TotalShipmentCharge" => shipment_results.dig("TotalShipmentCharge", "MonetaryValue"),
69
+ "BillableShipmentWeight" => shipment_results.dig("BillableShipmentWeight", "Value")
70
+ }.compact
71
+ end
53
72
  end
54
73
  end
55
74
  end
@@ -10,7 +10,7 @@ module FriendlyShipping
10
10
 
11
11
  def self.call(image_data:)
12
12
  format_code = image_data.dig("Type", "Code")
13
- graphic_image_b64 = image_data.dig("GraphicImage")
13
+ graphic_image_b64 = image_data["GraphicImage"]
14
14
 
15
15
  ShipmentDocument.new(
16
16
  format: image_data.dig("Format", "Code").downcase.to_sym,
@@ -10,7 +10,8 @@ module FriendlyShipping
10
10
  :total,
11
11
  :bol_id,
12
12
  :shipping_method,
13
- :warnings
13
+ :warnings,
14
+ :data
14
15
 
15
16
  def initialize(
16
17
  total:,
@@ -19,7 +20,8 @@ module FriendlyShipping
19
20
  pickup_request_number: nil,
20
21
  documents: [],
21
22
  shipping_method: nil,
22
- warnings: nil
23
+ warnings: nil,
24
+ data: {}
23
25
  )
24
26
  @total = total
25
27
  @bol_id = bol_id
@@ -28,6 +30,7 @@ module FriendlyShipping
28
30
  @documents = documents
29
31
  @shipping_method = shipping_method
30
32
  @warnings = warnings
33
+ @data = data
31
34
  end
32
35
  end
33
36
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/result'
3
+ require 'dry/monads'
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'
@@ -18,12 +18,12 @@ require 'friendly_shipping/services/ups_freight/parse_freight_label_response'
18
18
  require 'friendly_shipping/services/ups_freight/parse_freight_rate_response'
19
19
  require 'friendly_shipping/services/ups_freight/generate_freight_rate_request_hash'
20
20
  require 'friendly_shipping/services/ups_freight/generate_freight_ship_request_hash'
21
- require 'friendly_shipping/services/ups_freight/restful_api_error_handler'
21
+ require 'friendly_shipping/services/ups_freight/api_error'
22
22
 
23
23
  module FriendlyShipping
24
24
  module Services
25
25
  class UpsFreight
26
- include Dry::Monads::Result::Mixin
26
+ include Dry::Monads[:result]
27
27
 
28
28
  attr_reader :test, :key, :login, :password, :client
29
29
 
@@ -42,12 +42,14 @@ module FriendlyShipping
42
42
  labels: '/ship/v1607/freight/shipments/Ground'
43
43
  }.freeze
44
44
 
45
- def initialize(key:, login:, password:, test: true, client: HttpClient.new(error_handler: RestfulApiErrorHandler))
45
+ def initialize(key:, login:, password:, test: true, client: nil)
46
46
  @key = key
47
47
  @login = login
48
48
  @password = password
49
49
  @test = test
50
- @client = client
50
+
51
+ error_handler = ApiErrorHandler.new(api_error_class: UpsFreight::ApiError)
52
+ @client = client || HttpClient.new(error_handler: error_handler)
51
53
  end
52
54
 
53
55
  def carriers
@@ -87,6 +89,7 @@ module FriendlyShipping
87
89
  url = base_url + RESOURCES[action]
88
90
  FriendlyShipping::Request.new(
89
91
  url: url,
92
+ http_method: "POST",
90
93
  body: payload.to_json,
91
94
  headers: {
92
95
  Content_Type: 'application/json',
@@ -20,7 +20,7 @@ module FriendlyShipping
20
20
  package_options_class: FriendlyShipping::Services::Usps::RateEstimatePackageOptions,
21
21
  **kwargs
22
22
  )
23
- super kwargs.merge(package_options_class: package_options_class)
23
+ super(**kwargs.merge(package_options_class: package_options_class))
24
24
  end
25
25
  end
26
26
  end
@@ -22,28 +22,18 @@ module FriendlyShipping
22
22
  :return_dimensional_weight,
23
23
  :return_fees
24
24
 
25
- def initialize(
26
- box_name: :variable,
27
- commercial_pricing: false,
28
- first_class_mail_type: nil,
29
- hold_for_pickup: false,
30
- shipping_method: nil,
31
- transmit_dimensions: true,
32
- rectangular: true,
33
- return_dimensional_weight: true,
34
- return_fees: false,
35
- **kwargs
36
- )
25
+ def initialize(**kwargs)
26
+ box_name = value_or_default(:box_name, :variable, kwargs)
37
27
  @box_name = CONTAINERS.key?(box_name) ? box_name : :variable
38
- @commercial_pricing = commercial_pricing
39
- @first_class_mail_type = first_class_mail_type
40
- @hold_for_pickup = hold_for_pickup
41
- @shipping_method = shipping_method
42
- @transmit_dimensions = transmit_dimensions
43
- @rectangular = rectangular
44
- @return_dimensional_weight = return_dimensional_weight
45
- @return_fees = return_fees
46
- super kwargs
28
+ @commercial_pricing = value_or_default(:commercial_pricing, false, kwargs)
29
+ @first_class_mail_type = kwargs.delete(:first_class_mail_type)
30
+ @hold_for_pickup = value_or_default(:hold_for_pickup, false, kwargs)
31
+ @shipping_method = kwargs.delete(:shipping_method)
32
+ @transmit_dimensions = value_or_default(:transmit_dimensions, true, kwargs)
33
+ @rectangular = value_or_default(:rectangular, true, kwargs)
34
+ @return_dimensional_weight = value_or_default(:return_dimensional_weight, true, kwargs)
35
+ @return_fees = value_or_default(:return_fees, false, kwargs)
36
+ super(**kwargs)
47
37
  end
48
38
 
49
39
  def container_code
@@ -65,6 +55,12 @@ module FriendlyShipping
65
55
  service_code << 'COMMERCIAL' if commercial_pricing
66
56
  service_code.join(' ')
67
57
  end
58
+
59
+ private
60
+
61
+ def value_or_default(key, default, kwargs)
62
+ kwargs.key?(key) ? kwargs.delete(key) : default
63
+ end
68
64
  end
69
65
  end
70
66
  end
@@ -16,7 +16,7 @@ require 'friendly_shipping/services/usps/rate_estimate_options'
16
16
  module FriendlyShipping
17
17
  module Services
18
18
  class Usps
19
- include Dry::Monads::Result::Mixin
19
+ include Dry::Monads[:result]
20
20
 
21
21
  attr_reader :test, :login, :client
22
22
 
@@ -111,6 +111,7 @@ module FriendlyShipping
111
111
  def build_request(api:, xml:, debug:)
112
112
  FriendlyShipping::Request.new(
113
113
  url: base_url,
114
+ http_method: "POST",
114
115
  body: "API=#{RESOURCES[api]}&XML=#{CGI.escape xml}",
115
116
  readable_body: xml,
116
117
  debug: debug
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FriendlyShipping
4
- VERSION = "0.6.5"
4
+ VERSION = "0.7.0"
5
5
  end
@@ -18,6 +18,7 @@ require "friendly_shipping/api_failure"
18
18
 
19
19
  require "friendly_shipping/services/ship_engine"
20
20
  require "friendly_shipping/services/ups"
21
+ require "friendly_shipping/services/ups_freight"
21
22
  require "friendly_shipping/services/usps"
22
23
 
23
24
  module FriendlyShipping
metadata CHANGED
@@ -1,35 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: friendly_shipping
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Meyerhoff
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-10 00:00:00.000000000 Z
11
+ date: 2022-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: data_uri
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 0.0.3
20
- - - "<"
21
- - !ruby/object:Gem::Version
22
- version: 0.2.0
23
- type: :runtime
24
- prerelease: false
25
- version_requirements: !ruby/object:Gem::Requirement
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- version: 0.0.3
30
- - - "<"
31
- - !ruby/object:Gem::Version
32
- version: 0.2.0
33
13
  - !ruby/object:Gem::Dependency
34
14
  name: dry-monads
35
15
  requirement: !ruby/object:Gem::Requirement
@@ -81,7 +61,7 @@ dependencies:
81
61
  version: '0.4'
82
62
  - - ">="
83
63
  - !ruby/object:Gem::Version
84
- version: 0.4.4
64
+ version: 0.4.5
85
65
  type: :runtime
86
66
  prerelease: false
87
67
  version_requirements: !ruby/object:Gem::Requirement
@@ -91,7 +71,7 @@ dependencies:
91
71
  version: '0.4'
92
72
  - - ">="
93
73
  - !ruby/object:Gem::Version
94
- version: 0.4.4
74
+ version: 0.4.5
95
75
  - !ruby/object:Gem::Dependency
96
76
  name: rest-client
97
77
  requirement: !ruby/object:Gem::Requirement
@@ -216,20 +196,14 @@ dependencies:
216
196
  requirements:
217
197
  - - ">="
218
198
  - !ruby/object:Gem::Version
219
- version: '0.80'
220
- - - "<"
221
- - !ruby/object:Gem::Version
222
- version: '1'
199
+ version: '0'
223
200
  type: :development
224
201
  prerelease: false
225
202
  version_requirements: !ruby/object:Gem::Requirement
226
203
  requirements:
227
204
  - - ">="
228
205
  - !ruby/object:Gem::Version
229
- version: '0.80'
230
- - - "<"
231
- - !ruby/object:Gem::Version
232
- version: '1'
206
+ version: '0'
233
207
  - !ruby/object:Gem::Dependency
234
208
  name: simplecov
235
209
  requirement: !ruby/object:Gem::Requirement
@@ -297,6 +271,8 @@ files:
297
271
  - bin/setup
298
272
  - friendly_shipping.gemspec
299
273
  - lib/friendly_shipping.rb
274
+ - lib/friendly_shipping/api_error.rb
275
+ - lib/friendly_shipping/api_error_handler.rb
300
276
  - lib/friendly_shipping/api_failure.rb
301
277
  - lib/friendly_shipping/api_result.rb
302
278
  - lib/friendly_shipping/carrier.rb
@@ -350,6 +326,7 @@ files:
350
326
  - lib/friendly_shipping/services/ups/shipping_methods.rb
351
327
  - lib/friendly_shipping/services/ups/timing_options.rb
352
328
  - lib/friendly_shipping/services/ups_freight.rb
329
+ - lib/friendly_shipping/services/ups_freight/api_error.rb
353
330
  - lib/friendly_shipping/services/ups_freight/generate_commodity_information.rb
354
331
  - lib/friendly_shipping/services/ups_freight/generate_delivery_options_hash.rb
355
332
  - lib/friendly_shipping/services/ups_freight/generate_document_options_hash.rb
@@ -359,6 +336,7 @@ files:
359
336
  - lib/friendly_shipping/services/ups_freight/generate_location_hash.rb
360
337
  - lib/friendly_shipping/services/ups_freight/generate_pickup_options_hash.rb
361
338
  - lib/friendly_shipping/services/ups_freight/generate_pickup_request_hash.rb
339
+ - lib/friendly_shipping/services/ups_freight/generate_reference_hash.rb
362
340
  - lib/friendly_shipping/services/ups_freight/label_delivery_options.rb
363
341
  - lib/friendly_shipping/services/ups_freight/label_document_options.rb
364
342
  - lib/friendly_shipping/services/ups_freight/label_email_options.rb
@@ -373,7 +351,6 @@ files:
373
351
  - lib/friendly_shipping/services/ups_freight/rates_item_options.rb
374
352
  - lib/friendly_shipping/services/ups_freight/rates_options.rb
375
353
  - lib/friendly_shipping/services/ups_freight/rates_package_options.rb
376
- - lib/friendly_shipping/services/ups_freight/restful_api_error_handler.rb
377
354
  - lib/friendly_shipping/services/ups_freight/shipment_document.rb
378
355
  - lib/friendly_shipping/services/ups_freight/shipment_information.rb
379
356
  - lib/friendly_shipping/services/ups_freight/shipping_methods.rb
@@ -411,14 +388,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
411
388
  requirements:
412
389
  - - ">="
413
390
  - !ruby/object:Gem::Version
414
- version: '2.5'
391
+ version: '2.7'
415
392
  required_rubygems_version: !ruby/object:Gem::Requirement
416
393
  requirements:
417
394
  - - ">="
418
395
  - !ruby/object:Gem::Version
419
396
  version: '0'
420
397
  requirements: []
421
- rubygems_version: 3.1.6
398
+ rubygems_version: 3.3.26
422
399
  signing_key:
423
400
  specification_version: 4
424
401
  summary: An integration layer for shipping services
@@ -1,30 +0,0 @@
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