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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +18 -5
- data/.env.template +1 -1
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +7 -0
- data/README.md +1 -1
- data/friendly_shipping.gemspec +3 -4
- 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/serialize_label_shipment.rb +7 -10
- 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/rate_estimate_options.rb +1 -1
- data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +17 -21
- 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 +12 -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: 748717bbd3258962363ac3c25a9159cbcf384c91d8f5a356a1c405441bec7bac
|
4
|
+
data.tar.gz: cf66d120169edd0bdc1608a27c0a015da599ca7800e813245cb1af9b2ce7992d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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,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 `
|
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,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.
|
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
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"
|
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
|
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
|
@@ -53,16 +53,13 @@ module FriendlyShipping
|
|
53
53
|
["reference#{index + 1}".to_sym, message]
|
54
54
|
end.to_h
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
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
|
@@ -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
|
-
|
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.
|
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
|
14
|
+
StateProvinceCode: location.region&.code,
|
17
15
|
PostalCode: location.zip,
|
18
|
-
CountryCode: location.country
|
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
|
-
|
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 :
|
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
|
-
|
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
|
27
|
-
|
28
|
-
|
29
|
-
|
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
|
34
|
-
shipment_number = shipment_results
|
35
|
-
pickup_request_number = shipment_results
|
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
|
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
|
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/
|
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
|
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:
|
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
|
-
|
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
|
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
|
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
|
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
|
data/lib/friendly_shipping.rb
CHANGED
@@ -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.
|
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:
|
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.
|
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.
|
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
|
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
|
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.
|
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.
|
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
|