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.
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