friendly_shipping 0.6.5 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +18 -5
- data/.env.template +1 -1
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +4 -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.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: 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,6 +4,10 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [0.7.0] - 2022-12-14
|
8
|
+
- Removes dependency on unmaintained data_uri gem
|
9
|
+
- Bumps required Ruby to 2.7
|
10
|
+
|
7
11
|
## [0.6.5] - 2022-04-25
|
8
12
|
|
9
13
|
### Added
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# FriendlyShipping - the friendly shipping provider API wrapper
|
2
2
|
|
3
|
-
This gem provides wrappers for popular shipping provider APIs. Currently, there are implementations for rate quoting and address validation, as well as shipping label generation via the `
|
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
|
@@ -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.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Meyerhoff
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: data_uri
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: 0.0.3
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 0.2.0
|
23
|
-
type: :runtime
|
24
|
-
prerelease: false
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
requirements:
|
27
|
-
- - ">="
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 0.0.3
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 0.2.0
|
33
13
|
- !ruby/object:Gem::Dependency
|
34
14
|
name: dry-monads
|
35
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,7 +61,7 @@ dependencies:
|
|
81
61
|
version: '0.4'
|
82
62
|
- - ">="
|
83
63
|
- !ruby/object:Gem::Version
|
84
|
-
version: 0.4.
|
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
|