friendly_shipping 0.7.3 → 0.8.1

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.env.template +4 -0
  3. data/.env.test +4 -0
  4. data/CHANGELOG.md +23 -0
  5. data/friendly_shipping.gemspec +1 -1
  6. data/lib/friendly_shipping/package_options.rb +4 -0
  7. data/lib/friendly_shipping/rate.rb +1 -1
  8. data/lib/friendly_shipping/services/ship_engine/label_customs_options.rb +25 -0
  9. data/lib/friendly_shipping/services/ship_engine/label_item_options.rb +27 -0
  10. data/lib/friendly_shipping/services/ship_engine/label_options.rb +5 -1
  11. data/lib/friendly_shipping/services/ship_engine/label_package_options.rb +2 -1
  12. data/lib/friendly_shipping/services/ship_engine/serialize_label_shipment.rb +37 -0
  13. data/lib/friendly_shipping/services/ship_engine_ltl/bad_request.rb +9 -0
  14. data/lib/friendly_shipping/services/ship_engine_ltl/bad_request_handler.rb +33 -0
  15. data/lib/friendly_shipping/services/ship_engine_ltl/item_options.rb +31 -0
  16. data/lib/friendly_shipping/services/ship_engine_ltl/package_options.rb +15 -0
  17. data/lib/friendly_shipping/services/ship_engine_ltl/parse_carrier_response.rb +49 -0
  18. data/lib/friendly_shipping/services/ship_engine_ltl/parse_quote_response.rb +72 -0
  19. data/lib/friendly_shipping/services/ship_engine_ltl/quote_options.rb +34 -0
  20. data/lib/friendly_shipping/services/ship_engine_ltl/serialize_packages.rb +41 -0
  21. data/lib/friendly_shipping/services/ship_engine_ltl/serialize_quote_request.rb +109 -0
  22. data/lib/friendly_shipping/services/ship_engine_ltl.rb +133 -0
  23. data/lib/friendly_shipping/services/ups/label_item_options.rb +4 -1
  24. data/lib/friendly_shipping/services/ups/label_package_options.rb +7 -3
  25. data/lib/friendly_shipping/services/ups/parse_rate_response.rb +3 -3
  26. data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +1 -1
  27. data/lib/friendly_shipping/services/ups/serialize_address_snippet.rb +5 -2
  28. data/lib/friendly_shipping/services/ups/serialize_package_node.rb +11 -1
  29. data/lib/friendly_shipping/services/ups/serialize_shipment_confirm_request.rb +11 -7
  30. data/lib/friendly_shipping/services/ups_freight/api_error.rb +2 -0
  31. data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +10 -6
  32. data/lib/friendly_shipping/services/usps/parse_package_rate.rb +2 -1
  33. data/lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb +6 -2
  34. data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +4 -8
  35. data/lib/friendly_shipping/services/usps/shipping_methods.rb +4 -2
  36. data/lib/friendly_shipping/services/usps_international/parse_package_rate.rb +81 -0
  37. data/lib/friendly_shipping/services/usps_international/parse_rate_response.rb +86 -0
  38. data/lib/friendly_shipping/services/usps_international/rate_estimate_options.rb +28 -0
  39. data/lib/friendly_shipping/services/usps_international/rate_estimate_package_options.rb +45 -0
  40. data/lib/friendly_shipping/services/usps_international/serialize_rate_request.rb +75 -0
  41. data/lib/friendly_shipping/services/usps_international/shipping_methods.rb +38 -0
  42. data/lib/friendly_shipping/services/usps_international.rb +80 -0
  43. data/lib/friendly_shipping/version.rb +1 -1
  44. data/lib/friendly_shipping.rb +2 -0
  45. 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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FriendlyShipping
4
- VERSION = "0.7.3"
4
+ VERSION = "0.8.1"
5
5
  end
@@ -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.7.3
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-01-30 00:00:00.000000000 Z
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.3.26
420
+ rubygems_version: 3.4.10
400
421
  signing_key:
401
422
  specification_version: 4
402
423
  summary: An integration layer for shipping services