friendly_shipping 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) 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 +14 -3
  6. data/README.md +1 -1
  7. data/friendly_shipping.gemspec +6 -7
  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/parse_rate_estimate_response.rb +28 -6
  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/parse_package_rate.rb +16 -1
  37. data/lib/friendly_shipping/services/usps/rate_estimate_options.rb +1 -1
  38. data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +23 -19
  39. data/lib/friendly_shipping/services/usps/serialize_rate_request.rb +2 -0
  40. data/lib/friendly_shipping/services/usps.rb +2 -1
  41. data/lib/friendly_shipping/version.rb +1 -1
  42. data/lib/friendly_shipping.rb +1 -0
  43. metadata +18 -35
  44. 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: 107fa27ec95b49342549dbf24c53cc483cd05bdfbb64871940036aaac6567eb6
4
- data.tar.gz: 7dd9c281178e513482ae0cb93787eb551b09e5f697f10d4db50dc2aef21dd4a8
3
+ metadata.gz: 4e5444887ead0f957efaa619fc49bf737c34513f8a2480504beaabdbdab0eb2d
4
+ data.tar.gz: c52c103c53e9be10cef0d6288c1713de54441e536f8691cf0685c2bb0a4859ff
5
5
  SHA512:
6
- metadata.gz: 30c37297f77dc6be490cf9719211780b81b0d91cdc49311b349fc3844a6cbcb5755265e663b80e24a67cda9847e19d328808cec786cf7172d6986ccb75bbf6eb
7
- data.tar.gz: 022c69680c07d9fed0b2b9afa8093e40b20bb7b441b332acd743078f74db70f3de03227953952de8b08048aa40eb902895529c781b6332036cf4e38ba653804e
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,22 +4,33 @@ 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.6.4] - 2021-01-27
7
+ ## [0.7.0] - 2022-12-14
8
+ - Removes dependency on unmaintained data_uri gem
9
+ - Bumps required Ruby to 2.7
10
+
11
+ ## [0.6.5] - 2022-04-25
8
12
 
9
13
  ### Added
14
+ - USPS Service: Add support for returned dimensional weight (#128)
15
+ - USPS Service: Add support for returned fees (#127)
10
16
 
17
+ ### Changed
18
+ - ShipEngine Service: Prevent exceptions when no rates are returned (#125)
19
+ - Misc dependency updates (#116, #120, #121, #124)
20
+
21
+ ## [0.6.4] - 2021-01-27
22
+
23
+ ### Added
11
24
  - UPS Service: Include negotiated charges for UPS (#119)
12
25
  - UPS Service: Include shipment-level itemized charges (#117)
13
26
 
14
27
  ## [0.6.3] - 2020-10-30
15
28
 
16
29
  ### Added
17
-
18
30
  - USPS Service: Append HFP (Hold For Pickup) to service code when necessary (#110)
19
31
  - USPS Service: Add Priority Cubic shipping method (#113)
20
32
 
21
33
  ### Changed
22
-
23
34
  - USPS Service: Refactor to use explicit service codes (#111)
24
35
  - USPS Service: Match Priority Express by CLASSID instead of service name (#112)
25
36
  - UPS Service: Rename peak surcharge keys to match UPS docs (#114)
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,23 +22,22 @@ 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"
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
- spec.add_development_dependency "bundler", ">= 1.17", "< 3"
32
+ spec.add_development_dependency "bundler", ">= 2.1.4", "< 3"
34
33
  spec.add_development_dependency "dotenv", "~> 2.7"
35
- spec.add_development_dependency "factory_bot", "~> 5.0"
34
+ spec.add_development_dependency "factory_bot", "~> 6.2"
36
35
  spec.add_development_dependency "pry", "~> 0.12"
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
- spec.add_development_dependency "vcr", "~> 5.0"
41
+ spec.add_development_dependency "vcr", "~> 6.0"
43
42
  spec.add_development_dependency "webmock", "~> 3.6"
44
43
  end
@@ -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
@@ -10,8 +10,14 @@ module FriendlyShipping
10
10
 
11
11
  class << self
12
12
  def call(response:, request:, options:)
13
+ error_messages = []
13
14
  parsed_json = JSON.parse(response.body)
14
15
  rates = parsed_json.map do |rate|
16
+ if rate['validation_status'] == 'invalid'
17
+ error_messages.concat rate['error_messages']
18
+ next
19
+ end
20
+
15
21
  carrier = options.carriers.detect { |c| c.id == rate['carrier_id'] }
16
22
  next unless carrier
17
23
 
@@ -31,17 +37,33 @@ module FriendlyShipping
31
37
  )
32
38
  end.compact
33
39
 
34
- Success(
35
- ApiResult.new(
36
- rates,
37
- original_request: request,
38
- original_response: response
40
+ if valid_rates(parsed_json)
41
+ Success(
42
+ ApiResult.new(
43
+ rates,
44
+ original_request: request,
45
+ original_response: response
46
+ )
47
+ )
48
+ else
49
+ Failure(
50
+ ApiFailure.new(
51
+ error_messages,
52
+ original_request: request,
53
+ original_response: response
54
+ )
39
55
  )
40
- )
56
+ end
41
57
  end
42
58
 
43
59
  private
44
60
 
61
+ def valid_rates(parsed_json)
62
+ parsed_json.map do |rate|
63
+ ["valid", "has_warnings", "unknown"].include? rate['validation_status']
64
+ end.any?
65
+ end
66
+
45
67
  def get_amounts(rate_hash)
46
68
  [:shipping, :other, :insurance, :confirmation].map do |name|
47
69
  currency = Money::Currency.new(rate_hash["#{name}_amount"]["currency"])
@@ -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