friendly_shipping 0.7.3 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.template +4 -0
- data/.env.test +4 -0
- data/CHANGELOG.md +23 -0
- data/friendly_shipping.gemspec +1 -1
- data/lib/friendly_shipping/package_options.rb +4 -0
- data/lib/friendly_shipping/rate.rb +1 -1
- data/lib/friendly_shipping/services/ship_engine/label_customs_options.rb +25 -0
- data/lib/friendly_shipping/services/ship_engine/label_item_options.rb +27 -0
- data/lib/friendly_shipping/services/ship_engine/label_options.rb +5 -1
- data/lib/friendly_shipping/services/ship_engine/label_package_options.rb +2 -1
- data/lib/friendly_shipping/services/ship_engine/serialize_label_shipment.rb +37 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/bad_request.rb +9 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/bad_request_handler.rb +33 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/item_options.rb +31 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/package_options.rb +15 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/parse_carrier_response.rb +49 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/parse_quote_response.rb +72 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/quote_options.rb +34 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/serialize_packages.rb +41 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/serialize_quote_request.rb +109 -0
- data/lib/friendly_shipping/services/ship_engine_ltl.rb +133 -0
- data/lib/friendly_shipping/services/ups/label_item_options.rb +4 -1
- data/lib/friendly_shipping/services/ups/label_package_options.rb +7 -3
- data/lib/friendly_shipping/services/ups/parse_rate_response.rb +3 -3
- data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +1 -1
- data/lib/friendly_shipping/services/ups/serialize_address_snippet.rb +5 -2
- data/lib/friendly_shipping/services/ups/serialize_package_node.rb +11 -1
- data/lib/friendly_shipping/services/ups/serialize_shipment_confirm_request.rb +11 -7
- data/lib/friendly_shipping/services/ups_freight/api_error.rb +2 -0
- data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +10 -6
- data/lib/friendly_shipping/services/usps/parse_package_rate.rb +2 -1
- data/lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb +6 -2
- data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +4 -8
- data/lib/friendly_shipping/services/usps/shipping_methods.rb +4 -2
- data/lib/friendly_shipping/services/usps_international/parse_package_rate.rb +81 -0
- data/lib/friendly_shipping/services/usps_international/parse_rate_response.rb +86 -0
- data/lib/friendly_shipping/services/usps_international/rate_estimate_options.rb +28 -0
- data/lib/friendly_shipping/services/usps_international/rate_estimate_package_options.rb +45 -0
- data/lib/friendly_shipping/services/usps_international/serialize_rate_request.rb +75 -0
- data/lib/friendly_shipping/services/usps_international/shipping_methods.rb +38 -0
- data/lib/friendly_shipping/services/usps_international.rb +80 -0
- data/lib/friendly_shipping/version.rb +1 -1
- data/lib/friendly_shipping.rb +2 -0
- metadata +24 -3
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'friendly_shipping/services/ups/rate_estimate_package_options'
|
4
|
+
|
5
|
+
module FriendlyShipping
|
6
|
+
module Services
|
7
|
+
# Options for one package when rating
|
8
|
+
#
|
9
|
+
# @param [Symbol] box_name The type of box we want to get rates for.
|
10
|
+
# @param [Boolean] commercial_pricing Indicate whether the response should include commercial pricing rates.
|
11
|
+
# @param [Boolean] commercial_plus_pricing Indicate whether the response should include commercial pluse pricing rates.
|
12
|
+
# @param [Symbol] container_code Indicate the type of container of the package.
|
13
|
+
# @param [Symbol] mail_type Indicate the type of mail to estimate rates.
|
14
|
+
# @param [Boolean] rectangular Indicate whether the package is rectangular.
|
15
|
+
# @param [FriendlyShipping::ShippingMethod] shipping_method Describe the requested shipping method.
|
16
|
+
# @param [Symbol] transmit_dimensions Indicate whether the request should include the package dimensionals.
|
17
|
+
class UspsInternational
|
18
|
+
class RateEstimatePackageOptions < FriendlyShipping::PackageOptions
|
19
|
+
attr_reader :box_name,
|
20
|
+
:commercial_pricing,
|
21
|
+
:commercial_plus_pricing,
|
22
|
+
:container,
|
23
|
+
:mail_type,
|
24
|
+
:rectangular,
|
25
|
+
:shipping_method,
|
26
|
+
:transmit_dimensions
|
27
|
+
|
28
|
+
def initialize(**kwargs)
|
29
|
+
container_code = value_or_default(:container, :variable, kwargs) || :variable
|
30
|
+
mail_type_code = value_or_default(:mail_type, :all, kwargs) || :all
|
31
|
+
|
32
|
+
@box_name = value_or_default(:box_name, :variable, kwargs)
|
33
|
+
@commercial_pricing = value_or_default(:commercial_pricing, false, kwargs) ? 'Y' : 'N'
|
34
|
+
@commercial_plus_pricing = value_or_default(:commercial_plus_pricing, false, kwargs) ? 'Y' : 'N'
|
35
|
+
@container = CONTAINERS.fetch(container_code)
|
36
|
+
@mail_type = MAIL_TYPES.fetch(mail_type_code)
|
37
|
+
@rectangular = @container.eql?("ROLL") ? false : value_or_default(:rectangular, true, kwargs)
|
38
|
+
@shipping_method = kwargs.delete(:shipping_method)
|
39
|
+
@transmit_dimensions = value_or_default(:transmit_dimensions, true, kwargs)
|
40
|
+
super(**kwargs)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'friendly_shipping/services/usps/machinable_package'
|
4
|
+
|
5
|
+
module FriendlyShipping
|
6
|
+
module Services
|
7
|
+
class UspsInternational
|
8
|
+
class SerializeRateRequest
|
9
|
+
class << self
|
10
|
+
# @param [Physical::Shipment] shipment The shipment we want to get rates for
|
11
|
+
# shipment.packages[0].properties[:box_name] Can be :variable or a
|
12
|
+
# flat rate container defined in CONTAINERS.
|
13
|
+
# @param [String] login The USPS login code
|
14
|
+
# @param [FriendlyShipping::Services::UspsInternational::RateEstimateOptions] options The options
|
15
|
+
# object to use with this request.
|
16
|
+
# @return Array<[FriendlyShipping::Rate]> A set of Rates that this package may be sent with
|
17
|
+
def call(shipment:, login:, options:)
|
18
|
+
xml_builder = Nokogiri::XML::Builder.new do |xml|
|
19
|
+
xml.IntlRateV2Request('USERID' => login) do
|
20
|
+
xml.Revision("2")
|
21
|
+
shipment.packages.each_with_index do |package, index|
|
22
|
+
xml.Package('ID' => index) do
|
23
|
+
xml.Pounds(pounds_for(package))
|
24
|
+
xml.Ounces(ounces_for(package))
|
25
|
+
xml.Machinable(machinable(package))
|
26
|
+
package_options = options.options_for_package(package)
|
27
|
+
xml.MailType(package_options.mail_type)
|
28
|
+
xml.ValueOfContents(package.items_value)
|
29
|
+
xml.Country(shipment.destination.country)
|
30
|
+
xml.Container(package_options.container)
|
31
|
+
if package_options.transmit_dimensions && package_options.container == 'VARIABLE'
|
32
|
+
xml.Width("%<width>0.2f" % { width: package.width.convert_to(:inches).value.to_f })
|
33
|
+
xml.Length("%<length>0.2f" % { length: package.length.convert_to(:inches).value.to_f })
|
34
|
+
xml.Height("%<height>0.2f" % { height: package.height.convert_to(:inches).value.to_f })
|
35
|
+
|
36
|
+
# When girth is present, the package is treated as non-rectangular
|
37
|
+
# when calculating dimensional weight. This results in a smaller
|
38
|
+
# dimensional weight than a rectangular package would have.
|
39
|
+
unless package_options.rectangular
|
40
|
+
xml.Girth("%<girth>0.2f" % { girth: girth(package) })
|
41
|
+
end
|
42
|
+
xml.CommercialFlag(package_options.commercial_pricing)
|
43
|
+
xml.CommercialPlusFlag(package_options.commercial_plus_pricing)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
xml_builder.to_xml
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def machinable(package)
|
55
|
+
FriendlyShipping::Services::Usps::MachinablePackage.new(package).machinable? ? 'true' : 'false'
|
56
|
+
end
|
57
|
+
|
58
|
+
def ounces_for(package)
|
59
|
+
ounces = (package.weight.convert_to(:ounces).value.to_f % 16).round(2).ceil
|
60
|
+
ounces == 16 ? 15.999 : [ounces, 1].max
|
61
|
+
end
|
62
|
+
|
63
|
+
def pounds_for(package)
|
64
|
+
package.weight.convert_to(:pounds).value.to_f.floor
|
65
|
+
end
|
66
|
+
|
67
|
+
def girth(package)
|
68
|
+
width, length = package.dimensions.sort.first(2)
|
69
|
+
(width.scale(2) + length.scale(2)).convert_to(:inches).value.to_f
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UspsInternational
|
6
|
+
SHIPPING_METHODS = [
|
7
|
+
["1", "Priority Mail Express International"],
|
8
|
+
["2", "Priority Mail International"],
|
9
|
+
["4", "Global Express Guaranteed; (GXG)"],
|
10
|
+
["5", "Global Express Guaranteed; Document"],
|
11
|
+
["6", "Global Express Guarantee; Non-Document Rectangular"],
|
12
|
+
["7", "Global Express Guaranteed; Non-Document Non-Rectangular"],
|
13
|
+
["8", "Priority Mail International; Flat Rate Envelope"],
|
14
|
+
["9", "Priority Mail International; Medium Flat Rate Box"],
|
15
|
+
["10", "Priority Mail Express International; Flat Rate Envelope"],
|
16
|
+
["11", "Priority Mail International; Large Flat Rate Box"],
|
17
|
+
["12", "USPS GXG; Envelopes"],
|
18
|
+
["13", "First-Class Mail; International Letter"],
|
19
|
+
["14", "First-Class Mail; International Large Envelope"],
|
20
|
+
["15", "First-Class Package International Service"],
|
21
|
+
["16", "Priority Mail International; Small Flat Rate Box"],
|
22
|
+
["17", "Priority Mail Express International; Legal Flat Rate Envelope"],
|
23
|
+
["18", "Priority Mail International; Gift Card Flat Rate Envelope"],
|
24
|
+
["19", "Priority Mail International; Window Flat Rate Envelope"],
|
25
|
+
["20", "Priority Mail International; Small Flat Rate Envelope"],
|
26
|
+
["28", "Airmail M-Bag"]
|
27
|
+
].map do |code, name|
|
28
|
+
FriendlyShipping::ShippingMethod.new(
|
29
|
+
origin_countries: [Carmen::Country.coded('US')],
|
30
|
+
name: name,
|
31
|
+
service_code: code,
|
32
|
+
domestic: false,
|
33
|
+
international: true,
|
34
|
+
)
|
35
|
+
end.freeze
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'friendly_shipping/http_client'
|
4
|
+
require 'friendly_shipping/services/usps_international/shipping_methods'
|
5
|
+
require 'friendly_shipping/services/usps_international/serialize_rate_request'
|
6
|
+
require 'friendly_shipping/services/usps_international/parse_rate_response'
|
7
|
+
require 'friendly_shipping/services/usps_international/rate_estimate_options'
|
8
|
+
|
9
|
+
module FriendlyShipping
|
10
|
+
module Services
|
11
|
+
class UspsInternational
|
12
|
+
include Dry::Monads[:result]
|
13
|
+
|
14
|
+
attr_reader :test, :login, :client
|
15
|
+
|
16
|
+
CONTAINERS = {
|
17
|
+
rectanglular: 'RECTANGULAR',
|
18
|
+
roll: 'ROLL',
|
19
|
+
variable: 'VARIABLE'
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
MAIL_TYPES = {
|
23
|
+
all: 'ALL',
|
24
|
+
airmail: 'AIRMAIL MBAG',
|
25
|
+
envelope: 'ENVELOPE',
|
26
|
+
flat_rate: 'FLATRATE',
|
27
|
+
letter: 'LETTER',
|
28
|
+
large_envelope: 'LARGEENVELOPE',
|
29
|
+
package: 'PACKAGE',
|
30
|
+
post_cards: 'POSTCARDS'
|
31
|
+
}.freeze
|
32
|
+
|
33
|
+
TEST_URL = 'https://stg-secure.shippingapis.com/ShippingAPI.dll'
|
34
|
+
LIVE_URL = 'https://secure.shippingapis.com/ShippingAPI.dll'
|
35
|
+
|
36
|
+
RESOURCES = {
|
37
|
+
rates: 'IntlRateV2',
|
38
|
+
}.freeze
|
39
|
+
|
40
|
+
def initialize(login:, test: true, client: HttpClient.new)
|
41
|
+
@login = login
|
42
|
+
@test = test
|
43
|
+
@client = client
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get rate estimates from USPS International
|
47
|
+
#
|
48
|
+
# @param [Physical::Shipment] shipment
|
49
|
+
# @param [FriendlyShipping::Services::UspsInternational::RateEstimateOptions] options What options
|
50
|
+
# to use for this rate estimate call
|
51
|
+
#
|
52
|
+
# @return [Result<Array<FriendlyShipping::Rate>>] When successfully parsing, an array of rates in a Success Monad.
|
53
|
+
# When the parsing is not successful or USPS can't give us rates, a Failure monad containing something that
|
54
|
+
# can be serialized into an error message using `to_s`.
|
55
|
+
def rate_estimates(shipment, options: RateEstimateOptions.new, debug: false)
|
56
|
+
rate_request_xml = SerializeRateRequest.call(shipment: shipment, login: login, options: options)
|
57
|
+
request = build_request(api: :rates, xml: rate_request_xml, debug: debug)
|
58
|
+
client.post(request).bind do |response|
|
59
|
+
ParseRateResponse.call(response: response, request: request, shipment: shipment, options: options)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def build_request(api:, xml:, debug:)
|
66
|
+
FriendlyShipping::Request.new(
|
67
|
+
url: base_url,
|
68
|
+
http_method: "POST",
|
69
|
+
body: "API=#{RESOURCES[api]}&XML=#{CGI.escape xml}",
|
70
|
+
readable_body: xml,
|
71
|
+
debug: debug
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
def base_url
|
76
|
+
test ? TEST_URL : LIVE_URL
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/friendly_shipping.rb
CHANGED
@@ -17,9 +17,11 @@ require "friendly_shipping/api_result"
|
|
17
17
|
require "friendly_shipping/api_failure"
|
18
18
|
|
19
19
|
require "friendly_shipping/services/ship_engine"
|
20
|
+
require 'friendly_shipping/services/ship_engine_ltl'
|
20
21
|
require "friendly_shipping/services/ups"
|
21
22
|
require "friendly_shipping/services/ups_freight"
|
22
23
|
require "friendly_shipping/services/usps"
|
24
|
+
require "friendly_shipping/services/usps_international"
|
23
25
|
|
24
26
|
module FriendlyShipping
|
25
27
|
end
|
metadata
CHANGED
@@ -1,14 +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.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Meyerhoff
|
8
|
+
- Matthew Bass
|
8
9
|
autorequire:
|
9
10
|
bindir: exe
|
10
11
|
cert_chain: []
|
11
|
-
date: 2023-
|
12
|
+
date: 2023-08-03 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: dry-monads
|
@@ -255,6 +256,7 @@ extra_rdoc_files: []
|
|
255
256
|
files:
|
256
257
|
- ".circleci/config.yml"
|
257
258
|
- ".env.template"
|
259
|
+
- ".env.test"
|
258
260
|
- ".github/dependabot.yml"
|
259
261
|
- ".gitignore"
|
260
262
|
- ".rspec"
|
@@ -286,6 +288,8 @@ files:
|
|
286
288
|
- lib/friendly_shipping/services/ship_engine.rb
|
287
289
|
- lib/friendly_shipping/services/ship_engine/bad_request.rb
|
288
290
|
- lib/friendly_shipping/services/ship_engine/bad_request_handler.rb
|
291
|
+
- lib/friendly_shipping/services/ship_engine/label_customs_options.rb
|
292
|
+
- lib/friendly_shipping/services/ship_engine/label_item_options.rb
|
289
293
|
- lib/friendly_shipping/services/ship_engine/label_options.rb
|
290
294
|
- lib/friendly_shipping/services/ship_engine/label_package_options.rb
|
291
295
|
- lib/friendly_shipping/services/ship_engine/parse_carrier_response.rb
|
@@ -295,6 +299,16 @@ files:
|
|
295
299
|
- lib/friendly_shipping/services/ship_engine/rate_estimates_options.rb
|
296
300
|
- lib/friendly_shipping/services/ship_engine/serialize_label_shipment.rb
|
297
301
|
- lib/friendly_shipping/services/ship_engine/serialize_rate_estimate_request.rb
|
302
|
+
- lib/friendly_shipping/services/ship_engine_ltl.rb
|
303
|
+
- lib/friendly_shipping/services/ship_engine_ltl/bad_request.rb
|
304
|
+
- lib/friendly_shipping/services/ship_engine_ltl/bad_request_handler.rb
|
305
|
+
- lib/friendly_shipping/services/ship_engine_ltl/item_options.rb
|
306
|
+
- lib/friendly_shipping/services/ship_engine_ltl/package_options.rb
|
307
|
+
- lib/friendly_shipping/services/ship_engine_ltl/parse_carrier_response.rb
|
308
|
+
- lib/friendly_shipping/services/ship_engine_ltl/parse_quote_response.rb
|
309
|
+
- lib/friendly_shipping/services/ship_engine_ltl/quote_options.rb
|
310
|
+
- lib/friendly_shipping/services/ship_engine_ltl/serialize_packages.rb
|
311
|
+
- lib/friendly_shipping/services/ship_engine_ltl/serialize_quote_request.rb
|
298
312
|
- lib/friendly_shipping/services/ups.rb
|
299
313
|
- lib/friendly_shipping/services/ups/label.rb
|
300
314
|
- lib/friendly_shipping/services/ups/label_billing_options.rb
|
@@ -372,6 +386,13 @@ files:
|
|
372
386
|
- lib/friendly_shipping/services/usps/serialize_time_in_transit_request.rb
|
373
387
|
- lib/friendly_shipping/services/usps/shipping_methods.rb
|
374
388
|
- lib/friendly_shipping/services/usps/timing_options.rb
|
389
|
+
- lib/friendly_shipping/services/usps_international.rb
|
390
|
+
- lib/friendly_shipping/services/usps_international/parse_package_rate.rb
|
391
|
+
- lib/friendly_shipping/services/usps_international/parse_rate_response.rb
|
392
|
+
- lib/friendly_shipping/services/usps_international/rate_estimate_options.rb
|
393
|
+
- lib/friendly_shipping/services/usps_international/rate_estimate_package_options.rb
|
394
|
+
- lib/friendly_shipping/services/usps_international/serialize_rate_request.rb
|
395
|
+
- lib/friendly_shipping/services/usps_international/shipping_methods.rb
|
375
396
|
- lib/friendly_shipping/shipment_options.rb
|
376
397
|
- lib/friendly_shipping/shipping_method.rb
|
377
398
|
- lib/friendly_shipping/timing.rb
|
@@ -396,7 +417,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
396
417
|
- !ruby/object:Gem::Version
|
397
418
|
version: '0'
|
398
419
|
requirements: []
|
399
|
-
rubygems_version: 3.
|
420
|
+
rubygems_version: 3.4.10
|
400
421
|
signing_key:
|
401
422
|
specification_version: 4
|
402
423
|
summary: An integration layer for shipping services
|