friendly_shipping 0.5.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop-relaxed.yml +3 -4
  4. data/.rubocop.yml +9 -0
  5. data/CHANGELOG.md +32 -1
  6. data/friendly_shipping.gemspec +12 -12
  7. data/lib/friendly_shipping/api_failure.rb +2 -15
  8. data/lib/friendly_shipping/http_client.rb +16 -9
  9. data/lib/friendly_shipping/services/ship_engine/bad_request_handler.rb +15 -3
  10. data/lib/friendly_shipping/services/ups/parse_address_classification_response.rb +5 -2
  11. data/lib/friendly_shipping/services/ups/parse_address_validation_response.rb +5 -2
  12. data/lib/friendly_shipping/services/ups/parse_city_state_lookup_response.rb +5 -2
  13. data/lib/friendly_shipping/services/ups/parse_money_element.rb +2 -2
  14. data/lib/friendly_shipping/services/ups/parse_rate_response.rb +5 -1
  15. data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +5 -1
  16. data/lib/friendly_shipping/services/ups/parse_shipment_confirm_response.rb +5 -1
  17. data/lib/friendly_shipping/services/ups/parse_time_in_transit_response.rb +6 -2
  18. data/lib/friendly_shipping/services/ups/parse_void_shipment_response.rb +5 -1
  19. data/lib/friendly_shipping/services/ups/parse_xml_response.rb +16 -7
  20. data/lib/friendly_shipping/services/ups_freight.rb +44 -13
  21. data/lib/friendly_shipping/services/ups_freight/generate_delivery_options_hash.rb +21 -0
  22. data/lib/friendly_shipping/services/ups_freight/generate_document_options_hash.rb +28 -0
  23. data/lib/friendly_shipping/services/ups_freight/generate_email_options_hash.rb +25 -0
  24. data/lib/friendly_shipping/services/ups_freight/generate_freight_rate_request_hash.rb +2 -10
  25. data/lib/friendly_shipping/services/ups_freight/generate_freight_ship_request_hash.rb +81 -0
  26. data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +5 -2
  27. data/lib/friendly_shipping/services/ups_freight/generate_pickup_options_hash.rb +21 -0
  28. data/lib/friendly_shipping/services/ups_freight/generate_pickup_request_hash.rb +31 -0
  29. data/lib/friendly_shipping/services/ups_freight/label_delivery_options.rb +29 -0
  30. data/lib/friendly_shipping/services/ups_freight/label_document_options.rb +56 -0
  31. data/lib/friendly_shipping/services/ups_freight/label_email_options.rb +40 -0
  32. data/lib/friendly_shipping/services/ups_freight/label_item_options.rb +10 -0
  33. data/lib/friendly_shipping/services/ups_freight/label_options.rb +37 -0
  34. data/lib/friendly_shipping/services/ups_freight/label_package_options.rb +10 -0
  35. data/lib/friendly_shipping/services/ups_freight/label_pickup_options.rb +29 -0
  36. data/lib/friendly_shipping/services/ups_freight/parse_freight_label_response.rb +57 -0
  37. data/lib/friendly_shipping/services/ups_freight/parse_freight_rate_response.rb +29 -32
  38. data/lib/friendly_shipping/services/ups_freight/parse_shipment_document.rb +24 -0
  39. data/lib/friendly_shipping/services/ups_freight/pickup_request_options.rb +29 -0
  40. data/lib/friendly_shipping/services/ups_freight/rates_options.rb +3 -6
  41. data/lib/friendly_shipping/services/ups_freight/restful_api_error_handler.rb +30 -0
  42. data/lib/friendly_shipping/services/ups_freight/shipment_document.rb +21 -0
  43. data/lib/friendly_shipping/services/ups_freight/shipment_information.rb +35 -0
  44. data/lib/friendly_shipping/services/usps/parse_address_validation_response.rb +5 -1
  45. data/lib/friendly_shipping/services/usps/parse_city_state_lookup_response.rb +5 -1
  46. data/lib/friendly_shipping/services/usps/parse_package_rate.rb +25 -15
  47. data/lib/friendly_shipping/services/usps/parse_rate_response.rb +5 -2
  48. data/lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb +6 -2
  49. data/lib/friendly_shipping/services/usps/parse_xml_response.rb +15 -5
  50. data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +7 -5
  51. data/lib/friendly_shipping/services/usps/shipping_methods.rb +23 -12
  52. data/lib/friendly_shipping/shipping_method.rb +5 -2
  53. data/lib/friendly_shipping/version.rb +1 -1
  54. metadata +75 -40
  55. data/lib/friendly_shipping/services/ups_freight/generate_ups_security_hash.rb +0 -23
  56. data/lib/friendly_shipping/services/ups_freight/parse_json_response.rb +0 -38
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class GenerateDeliveryOptionsHash
7
+ def self.call(delivery_options:)
8
+ {
9
+ DeliveryOptions: {
10
+ LiftGateRequiredIndicator: delivery_options.lift_gate_required ? "" : nil,
11
+ WeekendPickupIndicator: delivery_options.weekend_delivery ? "" : nil,
12
+ InsidePickupIndicator: delivery_options.inside_delivery ? "" : nil,
13
+ HolidayPickupIndicator: delivery_options.holiday_delivery ? "" : nil,
14
+ LimitedAccessPickupIndicator: delivery_options.limited_access_delivery ? "" : nil
15
+ }.compact.presence
16
+ }.compact.presence
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class GenerateDocumentOptionsHash
7
+ def self.call(document_options:)
8
+ {
9
+ Type: {
10
+ Code: document_options.document_type_code
11
+ },
12
+ LabelsPerPage: document_options.labels_per_page,
13
+ Format: {
14
+ Code: document_options.format_code
15
+ },
16
+ PrintFormat: {
17
+ Code: document_options.thermal_code,
18
+ },
19
+ PrintSize: {
20
+ Length: document_options.length,
21
+ Width: document_options.width,
22
+ }
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class GenerateEmailOptionsHash
7
+ def self.call(email_options:)
8
+ {
9
+ EMailInformation: {
10
+ EMailType: {
11
+ Code: email_options.email_type_code,
12
+ },
13
+ EMail: {
14
+ EMailAddress: email_options.email,
15
+ UndeliverableEMailAddress: email_options.undeliverable_email,
16
+ EMailText: email_options.body,
17
+ Subject: email_options.subject
18
+ }.compact
19
+ }
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ 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_pickup_request_hash'
4
5
 
5
6
  module FriendlyShipping
6
7
  module Services
@@ -20,22 +21,13 @@ module FriendlyShipping
20
21
  },
21
22
  Commodity: options.commodity_information_generator.call(shipment: shipment, options: options),
22
23
  TimeInTransitIndicator: 'true',
23
- PickupRequest: pickup_request(options)
24
+ PickupRequest: GeneratePickupRequestHash.call(pickup_request_options: options.pickup_request_options),
24
25
  }.compact.merge(handling_units(shipment, options).reduce(&:merge).to_h)
25
26
  }
26
27
  end
27
28
 
28
29
  private
29
30
 
30
- def pickup_request(options)
31
- return unless options.pickup_date
32
-
33
- {
34
- PickupDate: options.pickup_date.strftime('%Y%m%d'),
35
- AdditionalComments: options.pickup_comments
36
- }
37
- end
38
-
39
31
  def handling_units(shipment, options)
40
32
  all_package_options = shipment.packages.map { |package| options.options_for_package(package) }
41
33
  all_package_options.group_by(&:handling_unit_code).map do |_handling_unit_code, options_group|
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'friendly_shipping/services/ups_freight/generate_location_hash'
4
+ require 'friendly_shipping/services/ups_freight/generate_document_options_hash'
5
+ require 'friendly_shipping/services/ups_freight/generate_email_options_hash'
6
+ require 'friendly_shipping/services/ups_freight/generate_pickup_options_hash'
7
+ require 'friendly_shipping/services/ups_freight/generate_delivery_options_hash'
8
+
9
+ module FriendlyShipping
10
+ module Services
11
+ class UpsFreight
12
+ class GenerateFreightShipRequestHash
13
+ class << self
14
+ def call(shipment:, options:)
15
+ {
16
+ FreightShipRequest: {
17
+ Shipment: {
18
+ ShipperNumber: options.shipper_number,
19
+ ShipFrom: GenerateLocationHash.call(location: shipment.origin),
20
+ ShipTo: GenerateLocationHash.call(location: shipment.destination),
21
+ PaymentInformation: payment_information(options),
22
+ Service: {
23
+ Code: options.shipping_method.service_code
24
+ },
25
+ Commodity: options.commodity_information_generator.call(shipment: shipment, options: options),
26
+ Documents: {
27
+ Image: options.document_options.map { |doc_opts| GenerateDocumentOptionsHash.call(document_options: doc_opts) }
28
+ },
29
+ ShipmentServiceOptions: shipment_service_options(options),
30
+ HandlingInstructions: options.handling_instructions,
31
+ PickupInstructions: options.pickup_instructions,
32
+ DeliveryInstructions: options.delivery_instructions,
33
+ PickupRequest: GeneratePickupRequestHash.call(pickup_request_options: options.pickup_request_options)
34
+ }.compact.merge(handling_units(shipment, options).reduce(&:merge).to_h)
35
+ }
36
+ }
37
+ end
38
+
39
+ private
40
+
41
+ def shipment_service_options(options)
42
+ email_options = options.email_options.map { |email_opts| GenerateEmailOptionsHash.call(email_options: email_opts) }.presence
43
+ pickup_options = options.pickup_options ? GeneratePickupOptionsHash.call(pickup_options: options.pickup_options) : nil
44
+ delivery_options = options.delivery_options ? GenerateDeliveryOptionsHash.call(delivery_options: options.delivery_options) : nil
45
+ [email_options, pickup_options, delivery_options].compact.presence
46
+ end
47
+
48
+ def handling_units(shipment, options)
49
+ all_package_options = shipment.packages.map { |package| options.options_for_package(package) }
50
+ all_package_options.group_by(&:handling_unit_code).map do |_handling_unit_code, options_group|
51
+ [options_group.first, options_group.length]
52
+ end.map { |package_options, quantity| handling_unit_hash(package_options, quantity) }
53
+ end
54
+
55
+ def handling_unit_hash(package_options, quantity)
56
+ {
57
+ package_options.handling_unit_tag => {
58
+ Quantity: quantity.to_s,
59
+ Type: {
60
+ Code: package_options.handling_unit_code,
61
+ Description: package_options.handling_unit_description
62
+ }
63
+ }
64
+ }
65
+ end
66
+
67
+ def payment_information(options)
68
+ payer_address = GenerateLocationHash.call(location: options.billing_address).
69
+ merge(ShipperNumber: options.shipper_number)
70
+ {
71
+ Payer: payer_address,
72
+ ShipmentBillingOption: {
73
+ Code: options.billing_code
74
+ }
75
+ }
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -17,8 +17,11 @@ module FriendlyShipping
17
17
  PostalCode: location.zip,
18
18
  CountryCode: location.country.code
19
19
  },
20
- AttentionName: location.name
21
- }
20
+ AttentionName: location.name,
21
+ Phone: {
22
+ Number: location.phone
23
+ }.compact.presence
24
+ }.compact
22
25
  end
23
26
 
24
27
  private
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class GeneratePickupOptionsHash
7
+ def self.call(pickup_options:)
8
+ {
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
+ HolidayPickupIndicator: pickup_options.holiday_pickup ? "" : nil,
14
+ LimitedAccessPickupIndicator: pickup_options.limited_access_pickup ? "" : nil
15
+ }.compact.presence
16
+ }.compact.presence
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class GeneratePickupRequestHash
7
+ class << self
8
+ def call(pickup_request_options:)
9
+ return unless pickup_request_options
10
+
11
+ {
12
+ AdditionalComments: pickup_request_options.comments,
13
+ Requester: {
14
+ ThirdPartyRequester: pickup_request_options.third_party_requester ? '' : nil,
15
+ AttentionName: pickup_request_options.requester.name,
16
+ EMailAddress: pickup_request_options.requester_email,
17
+ Name: pickup_request_options.requester.company_name,
18
+ Phone: {
19
+ Number: pickup_request_options.requester.phone
20
+ }.compact
21
+ }.compact,
22
+ PickupDate: pickup_request_options.pickup_time_window.begin.strftime('%Y%m%d'),
23
+ EarliestTimeReady: pickup_request_options.pickup_time_window.begin.strftime('%H%M'),
24
+ LatestTimeReady: pickup_request_options.pickup_time_window.end.strftime('%H%M'),
25
+ }.compact
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class LabelDeliveryOptions
7
+ attr_reader :holiday_delivery,
8
+ :inside_delivery,
9
+ :weekend_delivery,
10
+ :lift_gate_required,
11
+ :limited_access_delivery
12
+
13
+ def initialize(
14
+ holiday_delivery: nil,
15
+ inside_delivery: nil,
16
+ weekend_delivery: nil,
17
+ lift_gate_required: nil,
18
+ limited_access_delivery: nil
19
+ )
20
+ @holiday_delivery = holiday_delivery
21
+ @inside_delivery = inside_delivery
22
+ @weekend_delivery = weekend_delivery
23
+ @lift_gate_required = lift_gate_required
24
+ @limited_access_delivery = limited_access_delivery
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class LabelDocumentOptions
7
+ attr_reader :format, :type, :length, :width, :thermal
8
+
9
+ DOCUMENT_TYPES = {
10
+ label: "30",
11
+ ups_bol: "20",
12
+ vics_bol: "21"
13
+ }.freeze
14
+
15
+ DOCUMENT_FORMATS = {
16
+ pdf: "01"
17
+ }.freeze
18
+
19
+ THERMAL_CODE = {
20
+ false => "01",
21
+ true => "02"
22
+ }.freeze
23
+
24
+ def initialize(
25
+ format: :pdf,
26
+ type: :label,
27
+ size: "4x6",
28
+ thermal: false,
29
+ labels_per_page: 1
30
+ )
31
+ @format = format
32
+ @type = type
33
+ @length, @width = size.split('x').sort
34
+ @thermal = thermal
35
+ @labels_per_page = labels_per_page
36
+ end
37
+
38
+ def format_code
39
+ DOCUMENT_FORMATS.fetch(format)
40
+ end
41
+
42
+ def document_type_code
43
+ DOCUMENT_TYPES.fetch(type)
44
+ end
45
+
46
+ def thermal_code
47
+ THERMAL_CODE.fetch(thermal)
48
+ end
49
+
50
+ def labels_per_page
51
+ @labels_per_page.to_s
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class LabelEmailOptions
7
+ EMAIL_TYPES = {
8
+ ship_notification: '001',
9
+ delivery_notification: '002',
10
+ exception_notification: '003',
11
+ bol_labels: '004'
12
+ }.freeze
13
+
14
+ attr_reader :email_type,
15
+ :email,
16
+ :undeliverable_email,
17
+ :subject,
18
+ :body
19
+
20
+ def initialize(
21
+ email:,
22
+ email_type:,
23
+ undeliverable_email:,
24
+ subject: nil,
25
+ body: nil
26
+ )
27
+ @email = email
28
+ @email_type = email_type
29
+ @undeliverable_email = undeliverable_email
30
+ @subject = subject
31
+ @body = body
32
+ end
33
+
34
+ def email_type_code
35
+ EMAIL_TYPES.fetch(email_type)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class LabelItemOptions < RatesItemOptions
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class LabelOptions < RatesOptions
7
+ attr_reader :document_options,
8
+ :email_options,
9
+ :pickup_options,
10
+ :delivery_options,
11
+ :pickup_instructions,
12
+ :delivery_instructions,
13
+ :handling_instructions
14
+
15
+ def initialize(
16
+ document_options: [],
17
+ email_options: [],
18
+ pickup_options: nil,
19
+ delivery_options: nil,
20
+ pickup_instructions: nil,
21
+ delivery_instructions: nil,
22
+ handling_instructions: nil,
23
+ **kwargs
24
+ )
25
+ @pickup_options = pickup_options
26
+ @delivery_options = delivery_options
27
+ @document_options = document_options
28
+ @email_options = email_options
29
+ @pickup_instructions = pickup_instructions
30
+ @delivery_instructions = delivery_instructions
31
+ @handling_instructions = handling_instructions
32
+ super kwargs
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class LabelPackageOptions < RatesPackageOptions
7
+ end
8
+ end
9
+ end
10
+ end