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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop-relaxed.yml +3 -4
- data/.rubocop.yml +9 -0
- data/CHANGELOG.md +32 -1
- data/friendly_shipping.gemspec +12 -12
- data/lib/friendly_shipping/api_failure.rb +2 -15
- data/lib/friendly_shipping/http_client.rb +16 -9
- data/lib/friendly_shipping/services/ship_engine/bad_request_handler.rb +15 -3
- data/lib/friendly_shipping/services/ups/parse_address_classification_response.rb +5 -2
- data/lib/friendly_shipping/services/ups/parse_address_validation_response.rb +5 -2
- data/lib/friendly_shipping/services/ups/parse_city_state_lookup_response.rb +5 -2
- data/lib/friendly_shipping/services/ups/parse_money_element.rb +2 -2
- data/lib/friendly_shipping/services/ups/parse_rate_response.rb +5 -1
- data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +5 -1
- data/lib/friendly_shipping/services/ups/parse_shipment_confirm_response.rb +5 -1
- data/lib/friendly_shipping/services/ups/parse_time_in_transit_response.rb +6 -2
- data/lib/friendly_shipping/services/ups/parse_void_shipment_response.rb +5 -1
- data/lib/friendly_shipping/services/ups/parse_xml_response.rb +16 -7
- data/lib/friendly_shipping/services/ups_freight.rb +44 -13
- data/lib/friendly_shipping/services/ups_freight/generate_delivery_options_hash.rb +21 -0
- data/lib/friendly_shipping/services/ups_freight/generate_document_options_hash.rb +28 -0
- data/lib/friendly_shipping/services/ups_freight/generate_email_options_hash.rb +25 -0
- data/lib/friendly_shipping/services/ups_freight/generate_freight_rate_request_hash.rb +2 -10
- data/lib/friendly_shipping/services/ups_freight/generate_freight_ship_request_hash.rb +81 -0
- data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +5 -2
- data/lib/friendly_shipping/services/ups_freight/generate_pickup_options_hash.rb +21 -0
- data/lib/friendly_shipping/services/ups_freight/generate_pickup_request_hash.rb +31 -0
- data/lib/friendly_shipping/services/ups_freight/label_delivery_options.rb +29 -0
- data/lib/friendly_shipping/services/ups_freight/label_document_options.rb +56 -0
- data/lib/friendly_shipping/services/ups_freight/label_email_options.rb +40 -0
- data/lib/friendly_shipping/services/ups_freight/label_item_options.rb +10 -0
- data/lib/friendly_shipping/services/ups_freight/label_options.rb +37 -0
- data/lib/friendly_shipping/services/ups_freight/label_package_options.rb +10 -0
- data/lib/friendly_shipping/services/ups_freight/label_pickup_options.rb +29 -0
- data/lib/friendly_shipping/services/ups_freight/parse_freight_label_response.rb +57 -0
- data/lib/friendly_shipping/services/ups_freight/parse_freight_rate_response.rb +29 -32
- data/lib/friendly_shipping/services/ups_freight/parse_shipment_document.rb +24 -0
- data/lib/friendly_shipping/services/ups_freight/pickup_request_options.rb +29 -0
- data/lib/friendly_shipping/services/ups_freight/rates_options.rb +3 -6
- data/lib/friendly_shipping/services/ups_freight/restful_api_error_handler.rb +30 -0
- data/lib/friendly_shipping/services/ups_freight/shipment_document.rb +21 -0
- data/lib/friendly_shipping/services/ups_freight/shipment_information.rb +35 -0
- data/lib/friendly_shipping/services/usps/parse_address_validation_response.rb +5 -1
- data/lib/friendly_shipping/services/usps/parse_city_state_lookup_response.rb +5 -1
- data/lib/friendly_shipping/services/usps/parse_package_rate.rb +25 -15
- data/lib/friendly_shipping/services/usps/parse_rate_response.rb +5 -2
- data/lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb +6 -2
- data/lib/friendly_shipping/services/usps/parse_xml_response.rb +15 -5
- data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +7 -5
- data/lib/friendly_shipping/services/usps/shipping_methods.rb +23 -12
- data/lib/friendly_shipping/shipping_method.rb +5 -2
- data/lib/friendly_shipping/version.rb +1 -1
- metadata +75 -40
- data/lib/friendly_shipping/services/ups_freight/generate_ups_security_hash.rb +0 -23
- 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:
|
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,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
|