friendly_shipping 0.6.5 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) 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 +7 -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/serialize_label_shipment.rb +7 -10
  15. data/lib/friendly_shipping/services/ship_engine.rb +9 -5
  16. data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +1 -1
  17. data/lib/friendly_shipping/services/ups/parse_shipment_confirm_response.rb +1 -1
  18. data/lib/friendly_shipping/services/ups/parse_void_shipment_response.rb +1 -1
  19. data/lib/friendly_shipping/services/ups/rate_estimate_options.rb +1 -1
  20. data/lib/friendly_shipping/services/ups/rate_estimate_package_options.rb +1 -1
  21. data/lib/friendly_shipping/services/ups/shipping_methods.rb +4 -0
  22. data/lib/friendly_shipping/services/ups.rb +10 -2
  23. data/lib/friendly_shipping/services/ups_freight/api_error.rb +36 -0
  24. data/lib/friendly_shipping/services/ups_freight/generate_delivery_options_hash.rb +6 -4
  25. data/lib/friendly_shipping/services/ups_freight/generate_freight_ship_request_hash.rb +5 -2
  26. data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +6 -9
  27. data/lib/friendly_shipping/services/ups_freight/generate_pickup_options_hash.rb +4 -3
  28. data/lib/friendly_shipping/services/ups_freight/generate_reference_hash.rb +27 -0
  29. data/lib/friendly_shipping/services/ups_freight/label_delivery_options.rb +7 -1
  30. data/lib/friendly_shipping/services/ups_freight/label_options.rb +28 -2
  31. data/lib/friendly_shipping/services/ups_freight/label_pickup_options.rb +3 -0
  32. data/lib/friendly_shipping/services/ups_freight/parse_freight_label_response.rb +27 -8
  33. data/lib/friendly_shipping/services/ups_freight/parse_shipment_document.rb +1 -1
  34. data/lib/friendly_shipping/services/ups_freight/shipment_information.rb +5 -2
  35. data/lib/friendly_shipping/services/ups_freight.rb +8 -5
  36. data/lib/friendly_shipping/services/usps/rate_estimate_options.rb +1 -1
  37. data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +17 -21
  38. data/lib/friendly_shipping/services/usps.rb +2 -1
  39. data/lib/friendly_shipping/version.rb +1 -1
  40. data/lib/friendly_shipping.rb +1 -0
  41. metadata +12 -35
  42. 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: 748717bbd3258962363ac3c25a9159cbcf384c91d8f5a356a1c405441bec7bac
4
+ data.tar.gz: cf66d120169edd0bdc1608a27c0a015da599ca7800e813245cb1af9b2ce7992d
5
5
  SHA512:
6
- metadata.gz: 9080b93ddde6399677499cb65e6b1a184985af772067548b45c977fd6d8744c9c6a08899c2b27426e3fcd795b13950141d017183c40aa25026d7cb3bf2eeb120
7
- data.tar.gz: 413036408bfc7852a141c1b19e557b7533ca3288b371e6f5e09d78da279ef470bd764c9c46de145fbc6a079de9b18b858cb5bff75b972d3bed76ce4a946a2626
6
+ metadata.gz: f5b2fe10990482d30af429f31bbb48acfafa3dec81adf728a18a29d3de20bafaf329d00c73bb8899ab21469b7068a67bdb848067980d4deee559cdd1cbe511bb
7
+ data.tar.gz: 483efd68ebd20f3554baa8a239d1372a3fea8805cbcd203e84f7ec2401fd135627c452c2002147b474635806748dffd926ead4f40030ce583fb8a01c6d60ef3a
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,13 @@ 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.1] - 2023-01-20
8
+ - ShipEngine Service: Include package dimensions even if package code given
9
+
10
+ ## [0.7.0] - 2022-12-14
11
+ - Removes dependency on unmaintained data_uri gem
12
+ - Bumps required Ruby to 2.7
13
+
7
14
  ## [0.6.5] - 2022-04-25
8
15
 
9
16
  ### 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
@@ -53,16 +53,13 @@ module FriendlyShipping
53
53
  ["reference#{index + 1}".to_sym, message]
54
54
  end.to_h
55
55
 
56
- if package_options.package_code
57
- package_hash[:package_code] = package_options.package_code
58
- else
59
- package_hash[:dimensions] = {
60
- unit: 'inch',
61
- width: package.container.width.convert_to(:inches).value.to_f.round(2),
62
- length: package.container.length.convert_to(:inches).value.to_f.round(2),
63
- height: package.container.height.convert_to(:inches).value.to_f.round(2)
64
- }
65
- end
56
+ package_hash[:package_code] = package_options.package_code
57
+ package_hash[:dimensions] = {
58
+ unit: 'inch',
59
+ width: package.container.width.convert_to(:inches).value.to_f.round(2),
60
+ length: package.container.length.convert_to(:inches).value.to_f.round(2),
61
+ height: package.container.height.convert_to(:inches).value.to_f.round(2)
62
+ }
66
63
  package_hash
67
64
  end
68
65
  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.1"
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.1
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: 2023-01-20 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