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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +18 -5
- data/.env.template +1 -1
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +14 -3
- data/README.md +1 -1
- data/friendly_shipping.gemspec +6 -7
- data/lib/friendly_shipping/api_error.rb +14 -0
- data/lib/friendly_shipping/api_error_handler.rb +30 -0
- data/lib/friendly_shipping/http_client.rb +9 -27
- data/lib/friendly_shipping/request.rb +5 -3
- data/lib/friendly_shipping/response.rb +27 -1
- data/lib/friendly_shipping/services/ship_engine/parse_label_response.rb +8 -2
- data/lib/friendly_shipping/services/ship_engine/parse_rate_estimate_response.rb +28 -6
- data/lib/friendly_shipping/services/ship_engine.rb +9 -5
- data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +1 -1
- data/lib/friendly_shipping/services/ups/parse_shipment_confirm_response.rb +1 -1
- data/lib/friendly_shipping/services/ups/parse_void_shipment_response.rb +1 -1
- data/lib/friendly_shipping/services/ups/rate_estimate_options.rb +1 -1
- data/lib/friendly_shipping/services/ups/rate_estimate_package_options.rb +1 -1
- data/lib/friendly_shipping/services/ups/shipping_methods.rb +4 -0
- data/lib/friendly_shipping/services/ups.rb +10 -2
- data/lib/friendly_shipping/services/ups_freight/api_error.rb +36 -0
- data/lib/friendly_shipping/services/ups_freight/generate_delivery_options_hash.rb +6 -4
- data/lib/friendly_shipping/services/ups_freight/generate_freight_ship_request_hash.rb +5 -2
- data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +6 -9
- data/lib/friendly_shipping/services/ups_freight/generate_pickup_options_hash.rb +4 -3
- data/lib/friendly_shipping/services/ups_freight/generate_reference_hash.rb +27 -0
- data/lib/friendly_shipping/services/ups_freight/label_delivery_options.rb +7 -1
- data/lib/friendly_shipping/services/ups_freight/label_options.rb +28 -2
- data/lib/friendly_shipping/services/ups_freight/label_pickup_options.rb +3 -0
- data/lib/friendly_shipping/services/ups_freight/parse_freight_label_response.rb +27 -8
- data/lib/friendly_shipping/services/ups_freight/parse_shipment_document.rb +1 -1
- data/lib/friendly_shipping/services/ups_freight/shipment_information.rb +5 -2
- data/lib/friendly_shipping/services/ups_freight.rb +8 -5
- data/lib/friendly_shipping/services/usps/parse_package_rate.rb +16 -1
- data/lib/friendly_shipping/services/usps/rate_estimate_options.rb +1 -1
- data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +23 -19
- data/lib/friendly_shipping/services/usps/serialize_rate_request.rb +2 -0
- data/lib/friendly_shipping/services/usps.rb +2 -1
- data/lib/friendly_shipping/version.rb +1 -1
- data/lib/friendly_shipping.rb +1 -0
- metadata +18 -35
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4e5444887ead0f957efaa619fc49bf737c34513f8a2480504beaabdbdab0eb2d
|
4
|
+
data.tar.gz: c52c103c53e9be10cef0d6288c1713de54441e536f8691cf0685c2bb0a4859ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
7
|
+
test:
|
8
|
+
parameters:
|
9
|
+
ruby-version:
|
10
|
+
type: string
|
8
11
|
docker:
|
9
12
|
# specify the version you desire here
|
10
|
-
- image:
|
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=
|
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
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.
|
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 `
|
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
|
|
data/friendly_shipping.gemspec
CHANGED
@@ -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.
|
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.
|
30
|
+
spec.required_ruby_version = '>= 2.7'
|
32
31
|
|
33
|
-
spec.add_development_dependency "bundler", ">= 1.
|
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", "~>
|
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"
|
39
|
+
spec.add_development_dependency "rubocop"
|
41
40
|
spec.add_development_dependency "simplecov", "~> 0.17"
|
42
|
-
spec.add_development_dependency "vcr", "~>
|
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
|
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
|
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:
|
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(
|
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(
|
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(
|
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
|
-
#
|
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
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
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
|
31
|
+
# Get configured carriers from ShipEngine
|
32
32
|
#
|
33
|
-
# @return [Result<ApiResult<Array<Carrier>>>] Carriers configured in your
|
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
|
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
|
@@ -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
|
87
|
+
super(**kwargs.merge(package_options_class: package_options_class))
|
88
88
|
end
|
89
89
|
|
90
90
|
def pickup_type_code
|
@@ -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
|
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
|
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
|