friendly_shipping 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +1 -1
- data/.env.template +3 -0
- data/.env.test.local.template +6 -0
- data/.gitignore +1 -0
- data/.rubocop-relaxed.yml +7 -23
- data/.rubocop.yml +11 -2
- data/.rubocop_todo.yml +21 -0
- data/.yardopts +6 -0
- data/CHANGELOG.md +71 -0
- data/Gemfile +17 -0
- data/friendly_shipping.gemspec +4 -13
- data/lib/friendly_shipping/api_error.rb +6 -4
- data/lib/friendly_shipping/api_error_handler.rb +10 -6
- data/lib/friendly_shipping/api_failure.rb +4 -0
- data/lib/friendly_shipping/api_result.rb +16 -4
- data/lib/friendly_shipping/carrier.rb +28 -8
- data/lib/friendly_shipping/http_client.rb +25 -2
- data/lib/friendly_shipping/inflections.rb +10 -0
- data/lib/friendly_shipping/item_options.rb +3 -0
- data/lib/friendly_shipping/label.rb +41 -20
- data/lib/friendly_shipping/package_options.rb +21 -2
- data/lib/friendly_shipping/rate.rb +50 -15
- data/lib/friendly_shipping/request.rb +23 -7
- data/lib/friendly_shipping/response.rb +21 -6
- data/lib/friendly_shipping/services/rl/api_error.rb +33 -0
- data/lib/friendly_shipping/services/rl/bol_options.rb +107 -0
- data/lib/friendly_shipping/services/rl/bol_packages_serializer.rb +32 -0
- data/lib/friendly_shipping/services/rl/bol_structures_serializer.rb +31 -0
- data/lib/friendly_shipping/services/rl/item_options.rb +38 -0
- data/lib/friendly_shipping/services/rl/package_options.rb +40 -0
- data/lib/friendly_shipping/services/rl/parse_create_bol_response.rb +46 -0
- data/lib/friendly_shipping/services/rl/parse_invoice_response.rb +50 -0
- data/lib/friendly_shipping/services/rl/parse_print_bol_response.rb +47 -0
- data/lib/friendly_shipping/services/rl/parse_print_shipping_labels_response.rb +47 -0
- data/lib/friendly_shipping/services/rl/parse_rate_quote_response.rb +66 -0
- data/lib/friendly_shipping/services/rl/parse_transit_times_response.rb +76 -0
- data/lib/friendly_shipping/services/rl/rate_quote_options.rb +86 -0
- data/lib/friendly_shipping/services/rl/rate_quote_packages_serializer.rb +54 -0
- data/lib/friendly_shipping/services/rl/rate_quote_structures_serializer.rb +53 -0
- data/lib/friendly_shipping/services/rl/serialize_create_bol_request.rb +86 -0
- data/lib/friendly_shipping/services/rl/serialize_location.rb +46 -0
- data/lib/friendly_shipping/services/rl/serialize_rate_quote_request.rb +69 -0
- data/lib/friendly_shipping/services/rl/serialize_transit_times_request.rb +38 -0
- data/lib/friendly_shipping/services/rl/shipment_document.rb +40 -0
- data/lib/friendly_shipping/services/rl/shipment_information.rb +41 -0
- data/lib/friendly_shipping/services/rl/shipment_options.rb +50 -0
- data/lib/friendly_shipping/services/rl/shipping_methods.rb +28 -0
- data/lib/friendly_shipping/services/rl/structure_options.rb +13 -0
- data/lib/friendly_shipping/services/rl.rb +204 -0
- data/lib/friendly_shipping/services/ship_engine/api_error.rb +33 -0
- data/lib/friendly_shipping/services/ship_engine/customs_items_serializer.rb +36 -0
- data/lib/friendly_shipping/services/ship_engine/label_customs_options.rb +10 -7
- data/lib/friendly_shipping/services/ship_engine/label_item_options.rb +10 -5
- data/lib/friendly_shipping/services/ship_engine/label_options.rb +31 -14
- data/lib/friendly_shipping/services/ship_engine/label_package_options.rb +18 -11
- data/lib/friendly_shipping/services/ship_engine/parse_address_validation_response.rb +77 -0
- data/lib/friendly_shipping/services/ship_engine/parse_carrier_response.rb +9 -0
- data/lib/friendly_shipping/services/ship_engine/parse_label_response.rb +4 -0
- data/lib/friendly_shipping/services/ship_engine/{parse_rate_estimate_response.rb → parse_rate_estimates_response.rb} +26 -6
- data/lib/friendly_shipping/services/ship_engine/parse_rates_response.rb +101 -0
- data/lib/friendly_shipping/services/ship_engine/parse_void_response.rb +4 -0
- data/lib/friendly_shipping/services/ship_engine/rate_estimates_options.rb +17 -4
- data/lib/friendly_shipping/services/ship_engine/rates_item_options.rb +28 -0
- data/lib/friendly_shipping/services/ship_engine/rates_options.rb +61 -0
- data/lib/friendly_shipping/services/ship_engine/rates_package_options.rb +20 -0
- data/lib/friendly_shipping/services/ship_engine/serialize_address_residential_indicator.rb +27 -0
- data/lib/friendly_shipping/services/ship_engine/serialize_address_validation_request.rb +31 -0
- data/lib/friendly_shipping/services/ship_engine/serialize_label_shipment.rb +22 -27
- data/lib/friendly_shipping/services/ship_engine/serialize_rate_estimate_request.rb +41 -16
- data/lib/friendly_shipping/services/ship_engine/serialize_rates_request.rb +126 -0
- data/lib/friendly_shipping/services/ship_engine.rb +94 -21
- data/lib/friendly_shipping/services/ship_engine_ltl/api_error.rb +12 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/item_options.rb +24 -5
- data/lib/friendly_shipping/services/ship_engine_ltl/package_options.rb +39 -4
- data/lib/friendly_shipping/services/ship_engine_ltl/parse_carrier_response.rb +4 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/parse_quote_response.rb +10 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/quote_options.rb +29 -11
- data/lib/friendly_shipping/services/ship_engine_ltl/serialize_packages.rb +7 -2
- data/lib/friendly_shipping/services/ship_engine_ltl/serialize_quote_request.rb +50 -16
- data/lib/friendly_shipping/services/ship_engine_ltl/serialize_structures.rb +42 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/shipment_options.rb +47 -0
- data/lib/friendly_shipping/services/ship_engine_ltl/structure_options.rb +17 -0
- data/lib/friendly_shipping/services/ship_engine_ltl.rb +50 -30
- data/lib/friendly_shipping/services/tforce_freight/access_token.rb +43 -0
- data/lib/friendly_shipping/services/tforce_freight/api_error.rb +42 -0
- data/lib/friendly_shipping/services/tforce_freight/bol_options.rb +180 -0
- data/lib/friendly_shipping/services/tforce_freight/document_options.rb +100 -0
- data/lib/friendly_shipping/services/tforce_freight/generate_commodity_information.rb +92 -0
- data/lib/friendly_shipping/services/tforce_freight/generate_create_bol_request_hash.rb +165 -0
- data/lib/friendly_shipping/services/tforce_freight/generate_document_options_hash.rb +36 -0
- data/lib/friendly_shipping/services/tforce_freight/generate_handling_units_hash.rb +51 -0
- data/lib/friendly_shipping/services/tforce_freight/generate_location_hash.rb +25 -0
- data/lib/friendly_shipping/services/tforce_freight/generate_pickup_request_hash.rb +113 -0
- data/lib/friendly_shipping/services/tforce_freight/generate_rates_request_hash.rb +65 -0
- data/lib/friendly_shipping/services/tforce_freight/generate_reference_hash.rb +28 -0
- data/lib/friendly_shipping/services/tforce_freight/item_options.rb +93 -0
- data/lib/friendly_shipping/services/tforce_freight/package_options.rb +121 -0
- data/lib/friendly_shipping/services/tforce_freight/parse_create_bol_response.rb +94 -0
- data/lib/friendly_shipping/services/tforce_freight/parse_pickup_response.rb +45 -0
- data/lib/friendly_shipping/services/tforce_freight/parse_rates_response.rb +58 -0
- data/lib/friendly_shipping/services/tforce_freight/parse_shipment_document.rb +31 -0
- data/lib/friendly_shipping/services/tforce_freight/pickup_options.rb +82 -0
- data/lib/friendly_shipping/services/tforce_freight/rates_item_options.rb +12 -0
- data/lib/friendly_shipping/services/tforce_freight/rates_options.rb +162 -0
- data/lib/friendly_shipping/services/tforce_freight/rates_package_options.rb +12 -0
- data/lib/friendly_shipping/services/tforce_freight/shipment_document.rb +38 -0
- data/lib/friendly_shipping/services/tforce_freight/shipment_information.rb +104 -0
- data/lib/friendly_shipping/services/tforce_freight/shipment_options.rb +49 -0
- data/lib/friendly_shipping/services/tforce_freight/shipping_methods.rb +25 -0
- data/lib/friendly_shipping/services/tforce_freight/structure_options.rb +44 -0
- data/lib/friendly_shipping/services/tforce_freight.rb +202 -0
- data/lib/friendly_shipping/services/ups/label_options.rb +14 -2
- data/lib/friendly_shipping/services/ups/label_package_options.rb +1 -1
- data/lib/friendly_shipping/services/ups/parse_modifier_element.rb +29 -0
- data/lib/friendly_shipping/services/ups/parse_rate_response.rb +12 -0
- data/lib/friendly_shipping/services/ups/parse_time_in_transit_response.rb +1 -1
- data/lib/friendly_shipping/services/ups/rate_estimate_options.rb +14 -1
- data/lib/friendly_shipping/services/ups/serialize_rating_service_selection_request.rb +10 -1
- data/lib/friendly_shipping/services/ups/serialize_shipment_accept_request.rb +1 -1
- data/lib/friendly_shipping/services/ups/serialize_shipment_confirm_request.rb +2 -1
- data/lib/friendly_shipping/services/ups/shipping_methods.rb +1 -1
- data/lib/friendly_shipping/services/ups.rb +1 -1
- data/lib/friendly_shipping/services/ups_freight/api_error.rb +8 -5
- data/lib/friendly_shipping/services/ups_freight/generate_commodity_information.rb +65 -19
- data/lib/friendly_shipping/services/ups_freight/generate_freight_rate_request_hash.rb +3 -20
- data/lib/friendly_shipping/services/ups_freight/generate_freight_ship_request_hash.rb +2 -20
- data/lib/friendly_shipping/services/ups_freight/generate_handling_units_hash.rb +54 -0
- data/lib/friendly_shipping/services/ups_freight/label_options.rb +36 -10
- data/lib/friendly_shipping/services/ups_freight/label_structure_options.rb +13 -0
- data/lib/friendly_shipping/services/ups_freight/parse_freight_label_response.rb +2 -2
- data/lib/friendly_shipping/services/ups_freight/parse_shipment_document.rb +1 -1
- data/lib/friendly_shipping/services/ups_freight/rates_item_options.rb +18 -9
- data/lib/friendly_shipping/services/ups_freight/rates_options.rb +31 -21
- data/lib/friendly_shipping/services/ups_freight/rates_package_options.rb +79 -8
- data/lib/friendly_shipping/services/ups_freight/rates_structure_options.rb +46 -0
- data/lib/friendly_shipping/services/ups_freight/shipment_information.rb +7 -3
- data/lib/friendly_shipping/services/ups_freight/shipment_options.rb +49 -0
- data/lib/friendly_shipping/services/ups_freight.rb +3 -1
- data/lib/friendly_shipping/services/ups_json/access_token.rb +29 -0
- data/lib/friendly_shipping/services/ups_json/api_error.rb +29 -0
- data/lib/friendly_shipping/services/ups_json/generate_address_classification_payload.rb +29 -0
- data/lib/friendly_shipping/services/ups_json/generate_address_hash.rb +30 -0
- data/lib/friendly_shipping/services/ups_json/generate_labels_payload.rb +211 -0
- data/lib/friendly_shipping/services/ups_json/generate_package_hash.rb +76 -0
- data/lib/friendly_shipping/services/ups_json/generate_rates_payload.rb +86 -0
- data/lib/friendly_shipping/services/ups_json/generate_timings_payload.rb +44 -0
- data/lib/friendly_shipping/services/ups_json/label.rb +20 -0
- data/lib/friendly_shipping/services/ups_json/label_billing_options.rb +41 -0
- data/lib/friendly_shipping/services/ups_json/label_item_options.rb +77 -0
- data/lib/friendly_shipping/services/ups_json/label_options.rb +177 -0
- data/lib/friendly_shipping/services/ups_json/label_package_options.rb +51 -0
- data/lib/friendly_shipping/services/ups_json/parse_address_classification_response.rb +31 -0
- data/lib/friendly_shipping/services/ups_json/parse_json_response.rb +44 -0
- data/lib/friendly_shipping/services/ups_json/parse_labels_response.rb +71 -0
- data/lib/friendly_shipping/services/ups_json/parse_money_hash.rb +128 -0
- data/lib/friendly_shipping/services/ups_json/parse_rate_modifier_hash.rb +28 -0
- data/lib/friendly_shipping/services/ups_json/parse_rates_response.rb +105 -0
- data/lib/friendly_shipping/services/ups_json/parse_timings_response.rb +56 -0
- data/lib/friendly_shipping/services/ups_json/parse_void_response.rb +32 -0
- data/lib/friendly_shipping/services/ups_json/rates_item_options.rb +22 -0
- data/lib/friendly_shipping/services/ups_json/rates_options.rb +113 -0
- data/lib/friendly_shipping/services/ups_json/rates_package_options.rb +17 -0
- data/lib/friendly_shipping/services/ups_json/shipping_methods.rb +111 -0
- data/lib/friendly_shipping/services/ups_json/timings_options.rb +33 -0
- data/lib/friendly_shipping/services/ups_json.rb +216 -0
- data/lib/friendly_shipping/services/usps/choose_package_rate.rb +3 -3
- data/lib/friendly_shipping/services/usps/machinable_package.rb +1 -1
- data/lib/friendly_shipping/services/usps/parse_package_rate.rb +6 -6
- data/lib/friendly_shipping/services/usps/parse_time_in_transit_response.rb +6 -6
- data/lib/friendly_shipping/services/usps/rate_estimate_options.rb +1 -1
- data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +6 -1
- data/lib/friendly_shipping/services/usps/serialize_rate_request.rb +2 -2
- data/lib/friendly_shipping/services/usps/shipping_methods.rb +4 -3
- data/lib/friendly_shipping/services/usps.rb +1 -1
- data/lib/friendly_shipping/services/usps_international/parse_package_rate.rb +3 -3
- data/lib/friendly_shipping/services/usps_international/rate_estimate_options.rb +1 -1
- data/lib/friendly_shipping/services/usps_international/serialize_rate_request.rb +1 -1
- data/lib/friendly_shipping/services/usps_international.rb +1 -1
- data/lib/friendly_shipping/services/usps_ship/access_token.rb +37 -0
- data/lib/friendly_shipping/services/usps_ship/api_error.rb +29 -0
- data/lib/friendly_shipping/services/usps_ship/machinable_package.rb +53 -0
- data/lib/friendly_shipping/services/usps_ship/parse_rate_estimates_response.rb +80 -0
- data/lib/friendly_shipping/services/usps_ship/parse_timings_response.rb +80 -0
- data/lib/friendly_shipping/services/usps_ship/rate_estimate_options.rb +45 -0
- data/lib/friendly_shipping/services/usps_ship/rate_estimate_package_options.rb +124 -0
- data/lib/friendly_shipping/services/usps_ship/serialize_rate_estimates_request.rb +55 -0
- data/lib/friendly_shipping/services/usps_ship/shipping_methods.rb +38 -0
- data/lib/friendly_shipping/services/{ship_engine_ltl/bad_request.rb → usps_ship/timing_options.rb} +2 -2
- data/lib/friendly_shipping/services/usps_ship.rb +199 -0
- data/lib/friendly_shipping/shipment_options.rb +13 -1
- data/lib/friendly_shipping/shipping_method.rb +38 -11
- data/lib/friendly_shipping/structure_options.rb +38 -0
- data/lib/friendly_shipping/timing.rb +42 -7
- data/lib/friendly_shipping/version.rb +1 -1
- data/lib/friendly_shipping.rb +6 -0
- metadata +140 -174
- data/lib/friendly_shipping/services/ship_engine/bad_request.rb +0 -29
- data/lib/friendly_shipping/services/ship_engine/bad_request_handler.rb +0 -33
- data/lib/friendly_shipping/services/ship_engine_ltl/bad_request_handler.rb +0 -33
@@ -0,0 +1,177 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'friendly_shipping/services/ups_json/label_package_options'
|
4
|
+
require 'friendly_shipping/services/ups_json/label_billing_options'
|
5
|
+
|
6
|
+
module FriendlyShipping
|
7
|
+
module Services
|
8
|
+
# Option container for a generating UPS labels for a shipment
|
9
|
+
#
|
10
|
+
# Required:
|
11
|
+
#
|
12
|
+
# @param shipping_method [FriendlyShipping::ShippingMethod] The shipping method to use. We only need the
|
13
|
+
# service_code to be set.
|
14
|
+
# @param shipper_number [String] account number for the shipper
|
15
|
+
#
|
16
|
+
# Optional:
|
17
|
+
#
|
18
|
+
# @param shipper [Physical::Location] The company sending the shipment. Defaults to the shipment's origin.
|
19
|
+
# @param sub_version [String] The UPS API sub-version to use for requests. Default: 1707
|
20
|
+
# @param customer_context [String ] Optional element to identify transactions between client and server
|
21
|
+
# @param validate_address [Boolean] Validate the city field with ZIP code and state. If false, only ZIP code
|
22
|
+
# and state are validated. Default: true
|
23
|
+
# @param negotiated_rates [Boolean] if truthy negotiated rates will be requested from ups. Only valid if
|
24
|
+
# shipper account has negotiated rates. Default: false
|
25
|
+
# @option sold_to [Physical::Location] The person or company who imports and pays any duties due on the
|
26
|
+
# current shipment. Default: The shipment's destination
|
27
|
+
# @option saturday_delivery [Boolean] should we request Saturday delivery?. Default: false
|
28
|
+
# @option label_format [String] GIF, EPL, ZPL, STARPL and SPL
|
29
|
+
# @option label_size [Array<Integer>] Dimensions of the label. Default: [4, 6]
|
30
|
+
# @option delivery_confirmation [Symbol] Can be set to any key from SHIPMENT_DELIVERY_CONFIRMATION_CODES.
|
31
|
+
# Only possible for international shipments that are not between the US and Puerto Rico.
|
32
|
+
# @option carbon_neutral [Boolean] Ship with UPS' carbon neutral program
|
33
|
+
# @option return_service_code [Symbol] If present, marks this a return label. The kind
|
34
|
+
# of return label is specified by the symbol, one of the keys in RETURN_SERVICE_CODES. Default: nil
|
35
|
+
#
|
36
|
+
# Shipment options for international shipping:
|
37
|
+
#
|
38
|
+
# @option paperless_invoice [Boolean] set to truthy if using paperless invoice to ship internationally. Default false
|
39
|
+
# @option terms_of_shipment [Symbol] used with paperless invoice to specify who pays duties and taxes.
|
40
|
+
# See TERMS_OF_SHIPMENT constant for possible options.
|
41
|
+
# @option reason_for_export [String] A reason to export the current shipment. Possible values: 'SALE', 'GIFT', 'SAMPLE',
|
42
|
+
# 'RETURN', 'REPAIR', 'INTERCOMPANYDATA', Any other reason. Default: 'SALE'.
|
43
|
+
# @option invoice_date [Date] The invoice date for the shipment
|
44
|
+
# @param declaration_statement [String ] Optional element to add customs declaration text
|
45
|
+
#
|
46
|
+
class UpsJson
|
47
|
+
class LabelOptions < FriendlyShipping::ShipmentOptions
|
48
|
+
SHIPMENT_DELIVERY_CONFIRMATION_CODES = {
|
49
|
+
delivery_confirmation_signature_required: 1,
|
50
|
+
delivery_confirmation_adult_signature_required: 2
|
51
|
+
}.freeze
|
52
|
+
|
53
|
+
TERMS_OF_SHIPMENT_CODES = {
|
54
|
+
cost_and_freight: 'CFR',
|
55
|
+
cost_insurance_and_freight: 'CIF',
|
56
|
+
carriage_and_insurance_paid: 'CIP',
|
57
|
+
carriage_paid_to: 'CPT',
|
58
|
+
delivered_at_frontier: 'DAF',
|
59
|
+
delivery_duty_paid: 'DDP',
|
60
|
+
delivery_duty_unpaid: 'DDU',
|
61
|
+
delivered_ex_quay: 'DEQ',
|
62
|
+
delivered_ex_ship: 'DES',
|
63
|
+
ex_works: 'EXW',
|
64
|
+
free_alongside_ship: 'FAS',
|
65
|
+
free_carrier: 'FCA',
|
66
|
+
free_on_board: 'FOB'
|
67
|
+
}.freeze
|
68
|
+
|
69
|
+
RETURN_SERVICE_CODES = {
|
70
|
+
ups_print_and_mail: 2, # UPS Print and Mail (PNM)
|
71
|
+
ups_return_1_attempt: 3, # UPS Return Service 1-Attempt
|
72
|
+
ups_return_3_attempt: 5, # UPS Return Service 3-Attempt (RS3)
|
73
|
+
ups_electronic_return_label: 8, # UPS Electronic Return Label (ERL)
|
74
|
+
ups_print_return_label: 9, # UPS Print Return Label (PRL)
|
75
|
+
ups_exchange_print_return: 10, # UPS Exchange Print Return Label
|
76
|
+
ups_pack_collect_1_attemt_box_1: 11, # UPS Pack & Collect Service 1-Attempt Box 1
|
77
|
+
ups_pack_collect_1_attemt_box_2: 12, # UPS Pack & Collect Service 1-Attempt Box 2
|
78
|
+
ups_pack_collect_1_attemt_box_3: 13, # UPS Pack & Collect Service 1-Attempt Box 3
|
79
|
+
ups_pack_collect_1_attemt_box_4: 14, # UPS Pack & Collect Service 1-Attempt Box 4
|
80
|
+
ups_pack_collect_1_attemt_box_5: 15, # UPS Pack & Collect Service 1-Attempt Box 5
|
81
|
+
ups_pack_collect_3_attemt_box_1: 16, # UPS Pack & Collect Service 1-Attempt Box 1
|
82
|
+
ups_pack_collect_3_attemt_box_2: 17, # UPS Pack & Collect Service 1-Attempt Box 2
|
83
|
+
ups_pack_collect_3_attemt_box_3: 18, # UPS Pack & Collect Service 1-Attempt Box 3
|
84
|
+
ups_pack_collect_3_attemt_box_4: 19, # UPS Pack & Collect Service 1-Attempt Box 4
|
85
|
+
ups_pack_collect_3_attemt_box_5: 20 # UPS Pack & Collect Service 1-Attempt Box 5
|
86
|
+
}.freeze
|
87
|
+
|
88
|
+
SUB_VERSIONS = %w[1601 1607 1701 1707 1801 1807 2108 2205].freeze
|
89
|
+
|
90
|
+
attr_reader :shipping_method,
|
91
|
+
:shipper_number,
|
92
|
+
:shipper,
|
93
|
+
:sub_version,
|
94
|
+
:customer_context,
|
95
|
+
:validate_address,
|
96
|
+
:negotiated_rates,
|
97
|
+
:billing_options,
|
98
|
+
:sold_to,
|
99
|
+
:saturday_delivery,
|
100
|
+
:label_format,
|
101
|
+
:label_size,
|
102
|
+
:carbon_neutral,
|
103
|
+
:paperless_invoice,
|
104
|
+
:reason_for_export,
|
105
|
+
:invoice_date,
|
106
|
+
:declaration_statement
|
107
|
+
|
108
|
+
def initialize(
|
109
|
+
shipping_method:,
|
110
|
+
shipper_number:,
|
111
|
+
shipper: nil,
|
112
|
+
sub_version: '2205',
|
113
|
+
customer_context: nil,
|
114
|
+
validate_address: true,
|
115
|
+
negotiated_rates: false,
|
116
|
+
billing_options: LabelBillingOptions.new,
|
117
|
+
sold_to: nil,
|
118
|
+
saturday_delivery: false,
|
119
|
+
label_format: 'GIF',
|
120
|
+
label_size: [4, 6],
|
121
|
+
delivery_confirmation: nil,
|
122
|
+
carbon_neutral: true,
|
123
|
+
return_service: nil,
|
124
|
+
paperless_invoice: false,
|
125
|
+
terms_of_shipment: nil,
|
126
|
+
reason_for_export: 'SALE',
|
127
|
+
invoice_date: nil,
|
128
|
+
package_options_class: LabelPackageOptions,
|
129
|
+
declaration_statement: nil,
|
130
|
+
**kwargs
|
131
|
+
)
|
132
|
+
raise ArgumentError, "Invalid sub-version: #{sub_version}" unless sub_version.in?(SUB_VERSIONS)
|
133
|
+
|
134
|
+
@shipping_method = shipping_method
|
135
|
+
@shipper_number = shipper_number
|
136
|
+
@shipper = shipper
|
137
|
+
@sub_version = sub_version
|
138
|
+
@customer_context = customer_context
|
139
|
+
@validate_address = validate_address
|
140
|
+
@negotiated_rates = negotiated_rates
|
141
|
+
@billing_options = billing_options
|
142
|
+
@sold_to = sold_to
|
143
|
+
@saturday_delivery = saturday_delivery
|
144
|
+
@label_format = label_format
|
145
|
+
@label_size = label_size
|
146
|
+
@delivery_confirmation = delivery_confirmation
|
147
|
+
@carbon_neutral = carbon_neutral
|
148
|
+
@return_service = return_service
|
149
|
+
@paperless_invoice = paperless_invoice
|
150
|
+
@terms_of_shipment = terms_of_shipment
|
151
|
+
@reason_for_export = reason_for_export
|
152
|
+
@invoice_date = invoice_date
|
153
|
+
@declaration_statement = declaration_statement
|
154
|
+
super(**kwargs.reverse_merge(package_options_class: package_options_class))
|
155
|
+
end
|
156
|
+
|
157
|
+
def delivery_confirmation_code
|
158
|
+
SHIPMENT_DELIVERY_CONFIRMATION_CODES[delivery_confirmation]
|
159
|
+
end
|
160
|
+
|
161
|
+
def terms_of_shipment_code
|
162
|
+
TERMS_OF_SHIPMENT_CODES[terms_of_shipment]
|
163
|
+
end
|
164
|
+
|
165
|
+
def return_service_code
|
166
|
+
RETURN_SERVICE_CODES[return_service]
|
167
|
+
end
|
168
|
+
|
169
|
+
private
|
170
|
+
|
171
|
+
attr_reader :terms_of_shipment,
|
172
|
+
:return_service,
|
173
|
+
:delivery_confirmation
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'friendly_shipping/services/ups_json/label_item_options'
|
4
|
+
|
5
|
+
module FriendlyShipping
|
6
|
+
module Services
|
7
|
+
class UpsJson
|
8
|
+
# Package properties relevant for generating a UPS shipping label
|
9
|
+
#
|
10
|
+
# @option reference_numbers [Hash] a Hash where keys are _reference number codes_ and
|
11
|
+
# values are _reference number values_. Example: `{ reference_numbers: { xn: 'my_reference_1 }`
|
12
|
+
# @option delivery_confirmation [Symbol] Can be set to any key from PACKAGE_DELIVERY_CONFIRMATION_CODES.
|
13
|
+
# Only possible for domestic shipments or shipments between the US and Puerto Rico.
|
14
|
+
# @option shipper_release [Boolean] Indicates that the package may be released by driver without a signature from
|
15
|
+
# the consignee. Default: false
|
16
|
+
# @option declared_value [Boolean] When true, declared value (calculated as the sum of all items in the shipment)
|
17
|
+
# will be included in the request. Default: false
|
18
|
+
class LabelPackageOptions < FriendlyShipping::PackageOptions
|
19
|
+
PACKAGE_DELIVERY_CONFIRMATION_CODES = {
|
20
|
+
delivery_confirmation: 1,
|
21
|
+
delivery_confirmation_signature_required: 2,
|
22
|
+
delivery_confirmation_adult_signature_required: 3
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
attr_reader :reference_numbers, :shipper_release, :declared_value
|
26
|
+
|
27
|
+
def initialize(
|
28
|
+
reference_numbers: {},
|
29
|
+
delivery_confirmation: nil,
|
30
|
+
shipper_release: false,
|
31
|
+
declared_value: false,
|
32
|
+
**kwargs
|
33
|
+
)
|
34
|
+
@reference_numbers = reference_numbers
|
35
|
+
@delivery_confirmation = delivery_confirmation
|
36
|
+
@shipper_release = shipper_release
|
37
|
+
@declared_value = declared_value
|
38
|
+
super(**kwargs.reverse_merge(item_options_class: LabelItemOptions))
|
39
|
+
end
|
40
|
+
|
41
|
+
def delivery_confirmation_code
|
42
|
+
PACKAGE_DELIVERY_CONFIRMATION_CODES[delivery_confirmation]
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
attr_reader :delivery_confirmation
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsJson
|
6
|
+
class ParseAddressClassificationResponse
|
7
|
+
extend Dry::Monads::Result::Mixin
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def call(request:, response:)
|
11
|
+
parsed_response = ParseJsonResponse.call(
|
12
|
+
request: request,
|
13
|
+
response: response,
|
14
|
+
expected_root_key: 'XAVResponse'
|
15
|
+
)
|
16
|
+
parsed_response.bind do |classification_response|
|
17
|
+
address_type = classification_response.dig('XAVResponse', 'AddressClassification', 'Description')&.downcase
|
18
|
+
Success(
|
19
|
+
FriendlyShipping::ApiResult.new(
|
20
|
+
address_type,
|
21
|
+
original_request: request,
|
22
|
+
original_response: response
|
23
|
+
)
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsJson
|
6
|
+
class ParseJsonResponse
|
7
|
+
extend Dry::Monads::Result::Mixin
|
8
|
+
SUCCESSFUL_RESPONSE_STATUS_CODE = '1'
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def call(request:, response:, expected_root_key:)
|
12
|
+
api_error_message = response.headers.try(:[], :errordescription)
|
13
|
+
response_body = JSON.parse(response.body)
|
14
|
+
|
15
|
+
# UPS may return a 2xx status code on an unsuccessful request and include the error description in
|
16
|
+
# the response headers, which we will consider a failure
|
17
|
+
if api_error_message.present?
|
18
|
+
wrap_failure(api_error_message, request, response)
|
19
|
+
elsif response_body.nil? || response_body.keys.first != expected_root_key
|
20
|
+
wrap_failure('Empty or unexpected root key', request, response)
|
21
|
+
else
|
22
|
+
Success(response_body)
|
23
|
+
end
|
24
|
+
rescue JSON::ParserError => e
|
25
|
+
# when the response is not valid JSON(?!), the error description in the header is more descriptive
|
26
|
+
wrap_failure(api_error_message || e, request, response)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def wrap_failure(failure, request, response)
|
32
|
+
Failure(
|
33
|
+
FriendlyShipping::ApiFailure.new(
|
34
|
+
failure,
|
35
|
+
original_request: request,
|
36
|
+
original_response: response
|
37
|
+
)
|
38
|
+
)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsJson
|
6
|
+
class ParseLabelsResponse
|
7
|
+
class << self
|
8
|
+
def call(request:, response:)
|
9
|
+
parsed_response = ParseJsonResponse.call(
|
10
|
+
request: request,
|
11
|
+
response: response,
|
12
|
+
expected_root_key: 'ShipmentResponse'
|
13
|
+
)
|
14
|
+
parsed_response.fmap do |parsing_result|
|
15
|
+
FriendlyShipping::ApiResult.new(
|
16
|
+
build_labels(parsing_result),
|
17
|
+
original_request: request,
|
18
|
+
original_response: response
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_labels(labels_result)
|
24
|
+
shipment_result = labels_result["ShipmentResponse"]["ShipmentResults"]
|
25
|
+
|
26
|
+
Array.wrap(shipment_result["PackageResults"]).map do |package|
|
27
|
+
cost_breakdown = build_cost_breakdown(package)
|
28
|
+
package_cost = cost_breakdown.values.any? ? cost_breakdown.values.sum : nil
|
29
|
+
|
30
|
+
FriendlyShipping::Services::UpsJson::Label.new(
|
31
|
+
shipment_id: shipment_result["ShipmentIdentificationNumber"],
|
32
|
+
tracking_number: package["TrackingNumber"],
|
33
|
+
usps_tracking_number: package["USPSPICNumber"],
|
34
|
+
label_data: Base64.decode64(package["ShippingLabel"]["GraphicImage"]),
|
35
|
+
label_format: package["ShippingLabel"]["ImageFormat"]["Code"],
|
36
|
+
label_href: package["LabelURL"],
|
37
|
+
cost: package_cost,
|
38
|
+
shipment_cost: get_shipment_cost(shipment_result),
|
39
|
+
data: {
|
40
|
+
cost_breakdown: cost_breakdown,
|
41
|
+
negotiated_rate: get_negotiated_rate(shipment_result),
|
42
|
+
customer_context: labels_result["ShipmentResponse"]["Response"]["TransactionReference"]["CustomerContext"]
|
43
|
+
}.compact
|
44
|
+
)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_cost_breakdown(package)
|
49
|
+
costs = [
|
50
|
+
package["BaseServiceCharge"],
|
51
|
+
Array.wrap(package["ServiceOptionsCharges"]),
|
52
|
+
Array.wrap(package["ItemizedCharges"])
|
53
|
+
].flatten
|
54
|
+
|
55
|
+
costs.map { |cost| ParseMoneyHash.call(cost, "UnknownSurcharge") }.compact.to_h
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_shipment_cost(shipment_result)
|
59
|
+
total_charges_hash = shipment_result.dig("ShipmentCharges", "TotalCharges")
|
60
|
+
ParseMoneyHash.call(total_charges_hash, "TotalCharges")&.last
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_negotiated_rate(shipment_result)
|
64
|
+
negotiated_total_hash = shipment_result.dig("NegotiatedRateCharges", "TotalCharge")
|
65
|
+
ParseMoneyHash.call(negotiated_total_hash, "TotalCharge")&.last
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsJson
|
6
|
+
class ParseMoneyHash
|
7
|
+
def self.call(money_hash, key_name)
|
8
|
+
return unless money_hash
|
9
|
+
|
10
|
+
monetary_value = money_hash['MonetaryValue']&.to_d
|
11
|
+
return if monetary_value.zero?
|
12
|
+
|
13
|
+
currency_code = money_hash['CurrencyCode']
|
14
|
+
currency = Money::Currency.new(currency_code)
|
15
|
+
amount = Money.new(monetary_value * currency.subunit_to_unit, currency)
|
16
|
+
|
17
|
+
surcharge_code = money_hash['Code']
|
18
|
+
label = surcharge_code ? UPS_SURCHARGE_CODES[surcharge_code] : key_name
|
19
|
+
|
20
|
+
[label, amount]
|
21
|
+
end
|
22
|
+
|
23
|
+
UPS_SURCHARGE_CODES = {
|
24
|
+
"100" => "ADDITIONAL HANDLING",
|
25
|
+
"110" => "COD",
|
26
|
+
"120" => "DELIVERY CONFIRMATION",
|
27
|
+
"121" => "SHIP DELIVERY CONFIRMATION",
|
28
|
+
"153" => "PKG EMAIL SHIP NOTIFICATION",
|
29
|
+
"154" => "PKG EMAIL RETURN NOTIFICATION",
|
30
|
+
"155" => "PKG EMAIL INBOUND RETURN NOTIFICATION",
|
31
|
+
"156" => "PKG EMAIL QUANTUM VIEW SHIP NOTIFICATION",
|
32
|
+
"157" => "PKG EMAIL QUANTUM VIEW EXCEPTION NOTIFICATION",
|
33
|
+
"158" => "PKG EMAIL QUANTUM VIEW DELIVERY NOTIFICATION",
|
34
|
+
"165" => "PKG FAX INBOUND RETURN NOTIFICATION",
|
35
|
+
"166" => "PKG FAX QUANTUM VIEW SHIP NOTIFICATION",
|
36
|
+
"171" => "SHIP EMAIL ERL NOTIFICATION",
|
37
|
+
"173" => "SHIP EMAIL SHIP NOTIFICATION",
|
38
|
+
"174" => "SHIP EMAIL RETURN NOTIFICATION",
|
39
|
+
"175" => "SHIP EMAIL INBOUND RETURN NOTIFICATION",
|
40
|
+
"176" => "SHIP EMAIL QUANTUM VIEW SHIP NOTIFICATION",
|
41
|
+
"177" => "SHIP EMAIL QUANTUM VIEW EXCEPTION NOTIFICATION",
|
42
|
+
"178" => "SHIP EMAIL QUANTUM VIEW DELIVERY NOTIFICATION",
|
43
|
+
"179" => "SHIP EMAIL QUANTUM VIEW NOTIFY",
|
44
|
+
"187" => "SHIP UPS ACCESS POINT NOTIFICATION",
|
45
|
+
"188" => "SHIP EEI FILING NOTIFICATION",
|
46
|
+
"189" => "SHIP UAP SHIPPER NOTIFICATION",
|
47
|
+
"190" => "EXTENDED AREA",
|
48
|
+
"200" => "DRY ICE",
|
49
|
+
"220" => "HOLD FOR PICKUP",
|
50
|
+
"240" => "ORIGIN CERTIFICATE",
|
51
|
+
"250" => "PRINT RETURN LABEL",
|
52
|
+
"258" => "EXPORT LICENSE VERIFICATION",
|
53
|
+
"260" => "PRINT N MAIL",
|
54
|
+
"270" => "RESIDENTIAL ADDRESS",
|
55
|
+
"280" => "RETURN SERVICE 1ATTEMPT",
|
56
|
+
"290" => "RETURN SERVICE 3ATTEMPT",
|
57
|
+
"300" => "SATURDAY DELIVERY",
|
58
|
+
"310" => "SATURDAY PICKUP",
|
59
|
+
"330" => "PKG VERBAL CONFIRMATION",
|
60
|
+
"350" => "ELECTRONIC RETURN LABEL",
|
61
|
+
"372" => "QUANTUM VIEW NOTIFY DELIVERY",
|
62
|
+
"374" => "UPS PREPARED SED FORM",
|
63
|
+
"375" => "FUEL SURCHARGE",
|
64
|
+
"376" => "DELIVERY AREA",
|
65
|
+
"377" => "LARGE PACKAGE",
|
66
|
+
"378" => "SHIPPER PAYS DUTY TAX",
|
67
|
+
"379" => "SHIPPER PAYS DUTY TAX UNPAID",
|
68
|
+
"400" => "INSURANCE",
|
69
|
+
"401" => "SHIP ADDITIONAL HANDLING",
|
70
|
+
"402" => "SHIPPER RELEASE",
|
71
|
+
"403" => "CHECK TO SHIPPER",
|
72
|
+
"404" => "UPS PROACTIVE RESPONSE",
|
73
|
+
"405" => "GERMAN PICKUP",
|
74
|
+
"406" => "GERMAN ROAD TAX",
|
75
|
+
"407" => "EXTENDED AREA PICKUP",
|
76
|
+
"410" => "RETURN OF DOCUMENT",
|
77
|
+
"430" => "PEAK SEASON",
|
78
|
+
"431" => "LARGE PACKAGE SEASONAL SURCHARGE",
|
79
|
+
"432" => "ADDITIONAL HANDLING SEASONAL SURCHARGE",
|
80
|
+
"440" => "SHIP LARGE PACKAGE",
|
81
|
+
"441" => "CARBON NEUTRAL",
|
82
|
+
"442" => "PKG QV IN TRANSIT NOTIFICATION",
|
83
|
+
"443" => "SHIP QV IN TRANSIT NOTIFICATION",
|
84
|
+
"444" => "IMPORT CONTROL",
|
85
|
+
"445" => "COMMERCIAL INVOICE REMOVAL",
|
86
|
+
"446" => "IMPORT CONTROL ELECTRONIC LABEL",
|
87
|
+
"447" => "IMPORT CONTROL PRINT LABEL",
|
88
|
+
"448" => "IMPORT CONTROL PRINT AND MAIL LABEL",
|
89
|
+
"449" => "IMPORT CONTROL ONE PICK UP ATTEMPT LABEL",
|
90
|
+
"450" => "IMPORT CONTROL THREE PICK UP ATTEMPT LABEL",
|
91
|
+
"452" => "REFRIGERATION",
|
92
|
+
"454" => "PAC 1A BOX1",
|
93
|
+
"455" => "PAC 3A BOX1",
|
94
|
+
"456" => "PAC 1A BOX2",
|
95
|
+
"457" => "PAC 3A BOX2",
|
96
|
+
"458" => "PAC 1A BOX3",
|
97
|
+
"459" => "PAC 3A BOX3",
|
98
|
+
"460" => "PAC 1A BOX4",
|
99
|
+
"461" => "PAC 3A BOX4",
|
100
|
+
"462" => "PAC 1A BOX5",
|
101
|
+
"463" => "PAC 3A BOX5",
|
102
|
+
"464" => "EXCHANGE PRINT RETURN LABEL",
|
103
|
+
"465" => "EXCHANGE FORWARD",
|
104
|
+
"466" => "SHIP PREALERT NOTIFICATION",
|
105
|
+
"470" => "COMMITTED DELIVERY WINDOW",
|
106
|
+
"480" => "SECURITY SURCHARGE",
|
107
|
+
"492" => "CUSTOMER TRANSACTION FEE",
|
108
|
+
"500" => "SHIPMENT COD",
|
109
|
+
"510" => "LIFT GATE FOR PICKUP",
|
110
|
+
"511" => "LIFT GATE FOR DELIVERY",
|
111
|
+
"512" => "DROP OFF AT UPS FACILITY",
|
112
|
+
"515" => "UPS PREMIUM CARE",
|
113
|
+
"520" => "OVERSIZE PALLET",
|
114
|
+
"530" => "FREIGHT DELIVERY SURCHARGE",
|
115
|
+
"531" => "FREIGHT PICKUP SURCHARGE",
|
116
|
+
"540" => "DIRECT TO RETAIL",
|
117
|
+
"541" => "DIRECT DELIVERY ONLY",
|
118
|
+
"542" => "DELIVER TO ADDRESSEE ONLY",
|
119
|
+
"543" => "DIRECT TO RETAIL COD",
|
120
|
+
"544" => "RETAIL ACCESS POINT545 SHIPPING TICKET NOTIFICATION",
|
121
|
+
"546" => "ELECTRONIC PACKAGE RELEASE AUTHENTICATION",
|
122
|
+
"547" => "PAY AT STORE"
|
123
|
+
}.freeze
|
124
|
+
private_constant :UPS_SURCHARGE_CODES
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsJson
|
6
|
+
class ParseRateModifierHash
|
7
|
+
# @param [Hash] hash the RateModifier hash from the source JSON
|
8
|
+
# @param [String] currency_code The currency code for this modifier's amount (i.e. 'USD')
|
9
|
+
# @return [Hash]
|
10
|
+
def self.call(rate_modifier, currency_code:)
|
11
|
+
return unless rate_modifier
|
12
|
+
|
13
|
+
amount = rate_modifier['Amount'].to_d
|
14
|
+
return if amount.zero?
|
15
|
+
|
16
|
+
currency = Money::Currency.new(currency_code)
|
17
|
+
amount = Money.new(amount * currency.subunit_to_unit, currency)
|
18
|
+
|
19
|
+
modifier_type = rate_modifier['ModifierType']
|
20
|
+
modifier_description = rate_modifier['ModifierDesc']
|
21
|
+
label = "#{modifier_type} (#{modifier_description})"
|
22
|
+
|
23
|
+
{ label => amount }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsJson
|
6
|
+
class ParseRatesResponse
|
7
|
+
class << self
|
8
|
+
def call(request:, response:, shipment:)
|
9
|
+
parsed_response = ParseJsonResponse.call(
|
10
|
+
request: request,
|
11
|
+
response: response,
|
12
|
+
expected_root_key: 'RateResponse'
|
13
|
+
)
|
14
|
+
parsed_response.fmap do |parsing_result|
|
15
|
+
FriendlyShipping::ApiResult.new(
|
16
|
+
build_rates(parsing_result, shipment),
|
17
|
+
original_request: request,
|
18
|
+
original_response: response
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_rates(rates_result, shipment)
|
24
|
+
rates = []
|
25
|
+
|
26
|
+
rated_shipments = Array.wrap(rates_result.dig('RateResponse', 'RatedShipment'))
|
27
|
+
rated_shipments.each do |rated_shipment|
|
28
|
+
service_code = rated_shipment.dig('Service', 'Code')
|
29
|
+
shipping_method = CARRIER.shipping_methods.detect do |sm|
|
30
|
+
sm.service_code == service_code && shipment.origin.country.in?(sm.origin_countries)
|
31
|
+
end
|
32
|
+
days_to_delivery = rated_shipment.dig('GuaranteedDelivery', 'BusinessDaysInTransit').to_i
|
33
|
+
total_cost = ParseMoneyHash.call(rated_shipment['TotalCharges'], 'TotalCharges').last
|
34
|
+
insurance_price = ParseMoneyHash.call(rated_shipment['ServiceOptionsCharges'], 'ServiceOptionsCharges')&.last
|
35
|
+
negotiated_rate = ParseMoneyHash.call(rated_shipment.dig('NegotiatedRates', 'NetSummaryCharges', 'GrandTotal'), 'GrandTotal')&.last
|
36
|
+
negotiated_charges = ParseMoneyHash.call(rated_shipment.dig('NegotiatedRates', 'ItemizedCharges'), 'ItemizedCharges')&.last
|
37
|
+
|
38
|
+
itemized_charges = Array.wrap(rated_shipment['ItemizedCharges'])
|
39
|
+
itemized_charges = itemized_charges.map do |charge|
|
40
|
+
ParseMoneyHash.call(charge, 'MonetaryValue')
|
41
|
+
end
|
42
|
+
|
43
|
+
rated_shipment_warnings = Array.wrap(rated_shipment['RatedShipmentAlert'])
|
44
|
+
rated_shipment_warnings = rated_shipment_warnings.map { |alert| alert["Description"] }
|
45
|
+
if rated_shipment_warnings.any? { |e| e.match?(/to Residential/) }
|
46
|
+
new_address_type = 'residential'
|
47
|
+
elsif rated_shipment_warnings.any? { |e| e.match?(/to Commercial/) }
|
48
|
+
new_address_type = 'commercial'
|
49
|
+
end
|
50
|
+
|
51
|
+
rates << FriendlyShipping::Rate.new(
|
52
|
+
shipping_method: shipping_method,
|
53
|
+
amounts: { total: total_cost },
|
54
|
+
warnings: rated_shipment_warnings,
|
55
|
+
errors: [],
|
56
|
+
data: {
|
57
|
+
insurance_price: insurance_price,
|
58
|
+
negotiated_rate: negotiated_rate,
|
59
|
+
negotiated_charges: negotiated_charges,
|
60
|
+
days_to_delivery: days_to_delivery,
|
61
|
+
new_address_type: new_address_type,
|
62
|
+
itemized_charges: itemized_charges,
|
63
|
+
packages: build_packages(rated_shipment)
|
64
|
+
}.compact
|
65
|
+
)
|
66
|
+
end
|
67
|
+
rates
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def build_packages(rated_shipment)
|
73
|
+
package_array = Array.wrap(rated_shipment['RatedPackage'])
|
74
|
+
package_array.map do |rated_package|
|
75
|
+
currency_code = rated_package.dig('TotalCharges', 'CurrencyCode')
|
76
|
+
{
|
77
|
+
transportation_charges: ParseMoneyHash.call(rated_package['TransportationCharges'], 'TransportationCharges'),
|
78
|
+
base_service_charge: ParseMoneyHash.call(rated_package['BaseServiceCharge'], 'BaseServiceCharge'),
|
79
|
+
service_options_charges: ParseMoneyHash.call(rated_package['ServiceOptionsCharges'], 'ServiceOptionsCharges'),
|
80
|
+
itemized_charges: extract_charges(rated_package['ItemizedCharges'], 'ItemizedCharges'),
|
81
|
+
total_charges: ParseMoneyHash.call(rated_package['TotalCharges'], 'TotalCharges'),
|
82
|
+
negotiated_charges: extract_charges(rated_package.dig('NegotiatedRateCharges', 'ItemizedCharges'), 'ItemizedCharges'),
|
83
|
+
rate_modifiers: extract_modifiers(rated_package['RateModifier'], currency_code: currency_code).inject(:merge),
|
84
|
+
weight: BigDecimal(rated_package['Weight']),
|
85
|
+
billing_weight: BigDecimal(rated_package.dig('BillingWeight', 'Weight'))
|
86
|
+
}.compact
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def extract_charges(charges, key_name)
|
91
|
+
Array.wrap(charges).map do |charge|
|
92
|
+
ParseMoneyHash.call(charge, key_name)
|
93
|
+
end.compact
|
94
|
+
end
|
95
|
+
|
96
|
+
def extract_modifiers(modifiers, currency_code:)
|
97
|
+
Array.wrap(modifiers).map do |modifier|
|
98
|
+
ParseRateModifierHash.call(modifier, currency_code: currency_code)
|
99
|
+
end.compact
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|