friendly_shipping 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.template +1 -0
- data/.gitignore +1 -0
- data/CHANGELOG.md +13 -4
- data/Gemfile +1 -0
- data/README.md +21 -2
- data/friendly_shipping.gemspec +1 -1
- data/lib/friendly_shipping/api_failure.rb +3 -0
- data/lib/friendly_shipping/api_result.rb +3 -0
- data/lib/friendly_shipping/carrier.rb +6 -0
- data/lib/friendly_shipping/http_client.rb +1 -0
- data/lib/friendly_shipping/item_options.rb +11 -0
- data/lib/friendly_shipping/label.rb +17 -9
- data/lib/friendly_shipping/package_options.rb +28 -0
- data/lib/friendly_shipping/rate.rb +9 -8
- data/lib/friendly_shipping/request.rb +4 -0
- data/lib/friendly_shipping/response.rb +3 -0
- data/lib/friendly_shipping/services/ship_engine.rb +10 -11
- data/lib/friendly_shipping/services/ship_engine/label_options.rb +34 -0
- data/lib/friendly_shipping/services/ship_engine/label_package_options.rb +28 -0
- data/lib/friendly_shipping/services/ship_engine/parse_label_response.rb +6 -1
- data/lib/friendly_shipping/services/ship_engine/parse_rate_estimate_response.rb +7 -7
- data/lib/friendly_shipping/services/ship_engine/rate_estimates_options.rb +25 -0
- data/lib/friendly_shipping/services/ship_engine/serialize_label_shipment.rb +15 -14
- data/lib/friendly_shipping/services/ship_engine/serialize_rate_estimate_request.rb +2 -2
- data/lib/friendly_shipping/services/ups.rb +47 -2
- data/lib/friendly_shipping/services/ups/label_billing_options.rb +41 -0
- data/lib/friendly_shipping/services/ups/label_item_options.rb +74 -0
- data/lib/friendly_shipping/services/ups/label_options.rb +165 -0
- data/lib/friendly_shipping/services/ups/label_package_options.rb +43 -0
- data/lib/friendly_shipping/services/ups/parse_money_element.rb +128 -0
- data/lib/friendly_shipping/services/ups/parse_rate_response.rb +8 -7
- data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +75 -0
- data/lib/friendly_shipping/services/ups/parse_shipment_confirm_response.rb +22 -0
- data/lib/friendly_shipping/services/ups/parse_xml_response.rb +2 -1
- data/lib/friendly_shipping/services/ups/serialize_address_snippet.rb +11 -6
- data/lib/friendly_shipping/services/ups/serialize_package_node.rb +21 -6
- data/lib/friendly_shipping/services/ups/serialize_shipment_accept_request.rb +27 -0
- data/lib/friendly_shipping/services/ups/serialize_shipment_address_snippet.rb +21 -0
- data/lib/friendly_shipping/services/ups/serialize_shipment_confirm_request.rb +282 -0
- data/lib/friendly_shipping/services/ups_freight.rb +76 -0
- data/lib/friendly_shipping/services/ups_freight/generate_commodity_information.rb +33 -0
- data/lib/friendly_shipping/services/ups_freight/generate_freight_rate_request_hash.rb +72 -0
- data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +39 -0
- data/lib/friendly_shipping/services/ups_freight/generate_ups_security_hash.rb +23 -0
- data/lib/friendly_shipping/services/ups_freight/parse_freight_rate_response.rb +53 -0
- data/lib/friendly_shipping/services/ups_freight/parse_json_response.rb +38 -0
- data/lib/friendly_shipping/services/ups_freight/rates_item_options.rb +72 -0
- data/lib/friendly_shipping/services/ups_freight/rates_options.rb +54 -0
- data/lib/friendly_shipping/services/ups_freight/rates_package_options.rb +38 -0
- data/lib/friendly_shipping/services/ups_freight/shipping_methods.rb +25 -0
- data/lib/friendly_shipping/services/usps.rb +1 -1
- data/lib/friendly_shipping/services/usps/parse_xml_response.rb +1 -1
- data/lib/friendly_shipping/services/usps/serialize_rate_request.rb +0 -4
- data/lib/friendly_shipping/shipment_options.rb +23 -0
- data/lib/friendly_shipping/shipping_method.rb +7 -0
- data/lib/friendly_shipping/version.rb +1 -1
- metadata +33 -6
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/monads/result'
|
4
|
+
require 'friendly_shipping/http_client'
|
5
|
+
require 'friendly_shipping/services/ups_freight/shipping_methods'
|
6
|
+
require 'friendly_shipping/services/ups_freight/rates_options'
|
7
|
+
require 'friendly_shipping/services/ups_freight/rates_package_options'
|
8
|
+
require 'friendly_shipping/services/ups_freight/rates_item_options'
|
9
|
+
require 'friendly_shipping/services/ups_freight/parse_freight_rate_response'
|
10
|
+
require 'friendly_shipping/services/ups_freight/generate_freight_rate_request_hash'
|
11
|
+
require 'friendly_shipping/services/ups_freight/generate_ups_security_hash'
|
12
|
+
|
13
|
+
module FriendlyShipping
|
14
|
+
module Services
|
15
|
+
class UpsFreight
|
16
|
+
include Dry::Monads::Result::Mixin
|
17
|
+
|
18
|
+
attr_reader :test, :key, :login, :password, :client
|
19
|
+
|
20
|
+
CARRIER = FriendlyShipping::Carrier.new(
|
21
|
+
id: 'ups_freight',
|
22
|
+
name: 'United Parcel Service LTL',
|
23
|
+
code: 'ups-freight',
|
24
|
+
shipping_methods: SHIPPING_METHODS
|
25
|
+
)
|
26
|
+
|
27
|
+
TEST_URL = 'https://wwwcie.ups.com'
|
28
|
+
LIVE_URL = 'https://onlinetools.ups.com'
|
29
|
+
|
30
|
+
RESOURCES = {
|
31
|
+
rates: '/rest/FreightRate'
|
32
|
+
}.freeze
|
33
|
+
|
34
|
+
def initialize(key:, login:, password:, test: true, client: HttpClient.new)
|
35
|
+
@key = key
|
36
|
+
@login = login
|
37
|
+
@password = password
|
38
|
+
@test = test
|
39
|
+
@client = client
|
40
|
+
end
|
41
|
+
|
42
|
+
def carriers
|
43
|
+
Success([CARRIER])
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get rates for a shipment
|
47
|
+
# @param [Physical::Shipment] location The shipment we want to get rates for
|
48
|
+
# @param [FriendlyShipping::Services::UpsFreight::RatesOptions] options Options for obtaining rates for this shipment.
|
49
|
+
# @return [Result<ApiResult<Array<Rate>>>] The rates returned from UPS encoded in a
|
50
|
+
# `FriendlyShipping::ApiResult` object.
|
51
|
+
def rate_estimates(shipment, options:, debug: false)
|
52
|
+
freight_rate_request_hash = GenerateFreightRateRequestHash.call(shipment: shipment, options: options)
|
53
|
+
url = base_url + RESOURCES[:rates]
|
54
|
+
request = FriendlyShipping::Request.new(
|
55
|
+
url: url,
|
56
|
+
body: authentication_hash.merge(freight_rate_request_hash).to_json,
|
57
|
+
debug: debug
|
58
|
+
)
|
59
|
+
|
60
|
+
client.post(request).bind do |response|
|
61
|
+
ParseFreightRateResponse.call(response: response, request: request)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def authentication_hash
|
68
|
+
GenerateUpsSecurityHash.call(key: key, login: login, password: password)
|
69
|
+
end
|
70
|
+
|
71
|
+
def base_url
|
72
|
+
test ? TEST_URL : LIVE_URL
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class GenerateCommodityInformation
|
7
|
+
def self.call(shipment:, options:)
|
8
|
+
shipment.packages.flat_map do |package|
|
9
|
+
package_options = options.options_for_package(package)
|
10
|
+
package.items.map do |item|
|
11
|
+
item_options = package_options.options_for_item(item)
|
12
|
+
{
|
13
|
+
# This is a required field
|
14
|
+
Description: item.description || 'Commodities',
|
15
|
+
Weight: {
|
16
|
+
UnitOfMeasurement: {
|
17
|
+
Code: 'LBS' # Only Pounds are supported
|
18
|
+
},
|
19
|
+
Value: item.weight.convert_to(:pounds).value.to_f.round(2).to_s
|
20
|
+
},
|
21
|
+
NumberOfPieces: '1', # We won't support this yet.
|
22
|
+
PackagingType: {
|
23
|
+
Code: item_options.packaging_code
|
24
|
+
},
|
25
|
+
FreightClass: item_options.freight_class
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'friendly_shipping/services/ups_freight/generate_location_hash'
|
4
|
+
|
5
|
+
module FriendlyShipping
|
6
|
+
module Services
|
7
|
+
class UpsFreight
|
8
|
+
class GenerateFreightRateRequestHash
|
9
|
+
class << self
|
10
|
+
def call(shipment:, options:)
|
11
|
+
{
|
12
|
+
FreightRateRequest: {
|
13
|
+
Request: request_options(options.customer_context),
|
14
|
+
ShipperNumber: options.shipper_number,
|
15
|
+
ShipFrom: GenerateLocationHash.call(location: shipment.origin),
|
16
|
+
ShipTo: GenerateLocationHash.call(location: shipment.destination),
|
17
|
+
PaymentInformation: payment_information(options),
|
18
|
+
Service: {
|
19
|
+
Code: options.shipping_method.service_code
|
20
|
+
},
|
21
|
+
Commodity: options.commodity_information_generator.call(shipment: shipment, options: options),
|
22
|
+
TimeInTransitIndicator: true
|
23
|
+
}.compact.merge(handling_units(shipment, options).reduce(&:merge).to_h)
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def handling_units(shipment, options)
|
30
|
+
all_package_options = shipment.packages.map { |package| options.options_for_package(package) }
|
31
|
+
all_package_options.group_by(&:handling_unit_code).map do |_handling_unit_code, options_group|
|
32
|
+
[options_group.first, options_group.length]
|
33
|
+
end.map { |package_options, quantity| handling_unit_hash(package_options, quantity) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def handling_unit_hash(package_options, quantity)
|
37
|
+
{
|
38
|
+
package_options.handling_unit_tag => {
|
39
|
+
Quantity: quantity.to_s,
|
40
|
+
Type: {
|
41
|
+
Code: package_options.handling_unit_code,
|
42
|
+
Description: package_options.handling_unit_description
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
def request_options(customer_context)
|
49
|
+
return {} unless customer_context
|
50
|
+
|
51
|
+
{
|
52
|
+
TransactionReference: {
|
53
|
+
CustomerContext: customer_context
|
54
|
+
}
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def payment_information(options)
|
59
|
+
payer_address = GenerateLocationHash.call(location: options.billing_address).
|
60
|
+
merge(ShipperNumber: options.shipper_number)
|
61
|
+
{
|
62
|
+
Payer: payer_address,
|
63
|
+
ShipmentBillingOption: {
|
64
|
+
Code: options.billing_code
|
65
|
+
}
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class GenerateLocationHash
|
7
|
+
class << self
|
8
|
+
def call(location:)
|
9
|
+
# We ship freight here, which will mostly be used for businesses.
|
10
|
+
# If a personal name is given, treat is as the contact person ("AttentionName")
|
11
|
+
{
|
12
|
+
Name: location.company_name,
|
13
|
+
Address: {
|
14
|
+
AddressLine: address_line(location),
|
15
|
+
City: location.city,
|
16
|
+
StateProvinceCode: location.region.code,
|
17
|
+
PostalCode: location.zip,
|
18
|
+
CountryCode: location.country.code
|
19
|
+
},
|
20
|
+
AttentionName: location.name
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def address_line(location)
|
27
|
+
[
|
28
|
+
location.address1,
|
29
|
+
location.address2,
|
30
|
+
location.address3
|
31
|
+
].compact.
|
32
|
+
reject(&:empty?).
|
33
|
+
join(", ")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class GenerateUpsSecurityHash
|
7
|
+
def self.call(login:, password:, key:)
|
8
|
+
{
|
9
|
+
UPSSecurity: {
|
10
|
+
UsernameToken: {
|
11
|
+
Username: login,
|
12
|
+
Password: password
|
13
|
+
},
|
14
|
+
ServiceAccessToken: {
|
15
|
+
AccessLicenseNumber: key
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'friendly_shipping/rate'
|
4
|
+
require 'friendly_shipping/api_result'
|
5
|
+
require 'friendly_shipping/services/ups_freight/parse_json_response'
|
6
|
+
require 'friendly_shipping/services/ups_freight/shipping_methods'
|
7
|
+
|
8
|
+
module FriendlyShipping
|
9
|
+
module Services
|
10
|
+
class UpsFreight
|
11
|
+
class ParseFreightRateResponse
|
12
|
+
class << self
|
13
|
+
def call(request:, response:)
|
14
|
+
parsed_json = ParseJSONResponse.call(response.body, 'FreightRateResponse')
|
15
|
+
|
16
|
+
parsed_json.fmap do |json|
|
17
|
+
service_code = json.dig("FreightRateResponse", "Service", "Code")
|
18
|
+
shipping_method = SHIPPING_METHODS.detect { |sm| sm.service_code == service_code }
|
19
|
+
total_shipment_charge = json.dig("FreightRateResponse", "TotalShipmentCharge")
|
20
|
+
currency = Money::Currency.new(total_shipment_charge['CurrencyCode'])
|
21
|
+
amount = total_shipment_charge['MonetaryValue'].to_f
|
22
|
+
total_money = Money.new(amount * currency.subunit_to_unit, currency)
|
23
|
+
data = {
|
24
|
+
customer_context: json.dig("FreightRateResponse", "TransactionReference", "TransactionIdentifier"),
|
25
|
+
commodities: Array.wrap(json.dig("FreightRateResponse", "Commodity")),
|
26
|
+
response_body: json
|
27
|
+
}
|
28
|
+
|
29
|
+
days_in_transit = json.dig("FreightRateResponse", "TimeInTransit", "DaysInTransit")
|
30
|
+
if days_in_transit
|
31
|
+
data[:days_in_transit] = days_in_transit.to_i
|
32
|
+
end
|
33
|
+
|
34
|
+
FriendlyShipping::ApiResult.new(
|
35
|
+
[
|
36
|
+
FriendlyShipping::Rate.new(
|
37
|
+
amounts: {
|
38
|
+
total: total_money
|
39
|
+
},
|
40
|
+
shipping_method: shipping_method,
|
41
|
+
data: data
|
42
|
+
)
|
43
|
+
],
|
44
|
+
original_request: request,
|
45
|
+
original_response: response
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
class ParseJSONResponse
|
7
|
+
extend Dry::Monads::Result::Mixin
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def call(response_body, expected_root_tag)
|
11
|
+
json = JSON.parse(response_body)
|
12
|
+
|
13
|
+
if request_successful?(json, expected_root_tag)
|
14
|
+
Success(json)
|
15
|
+
else
|
16
|
+
Failure(error_message(json))
|
17
|
+
end
|
18
|
+
rescue JSON::ParserError => e
|
19
|
+
Failure(e)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def request_successful?(json, expected_root_tag)
|
25
|
+
json[expected_root_tag].present?
|
26
|
+
end
|
27
|
+
|
28
|
+
def error_message(json)
|
29
|
+
detailed_error = json.dig('Fault', 'detail', 'Errors', 'ErrorDetail', 'PrimaryErrorCode')
|
30
|
+
status = detailed_error['Code']
|
31
|
+
desc = detailed_error['Description']
|
32
|
+
[status, desc].compact.join(": ").presence || 'UPS could not process the request.'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FriendlyShipping
|
4
|
+
module Services
|
5
|
+
class UpsFreight
|
6
|
+
# Options for Items in a UPS Freight shipment
|
7
|
+
#
|
8
|
+
# @attribute [Symbol] packaging How the item is packaged, one of the keys of `PACKAGING_TYPES`
|
9
|
+
# @attribute [String] freight_class The freight class of this item, for example '55' or '92.5'
|
10
|
+
# @attribute [String] nmfc_code The national motor freight corporation code for this item. Something like '13050 sub 4'
|
11
|
+
class RatesItemOptions < FriendlyShipping::ItemOptions
|
12
|
+
PACKAGING_TYPES = {
|
13
|
+
bag: { code: "BAG", description: "Bag" },
|
14
|
+
bale: { code: "BAL", description: "Bale" },
|
15
|
+
barrel: { code: "BAR", description: "Barrel" },
|
16
|
+
bundle: { code: "BDL", description: "Bundle" },
|
17
|
+
bin: { code: "BIN", description: "Bin" },
|
18
|
+
box: { code: "BOX", description: "Box" },
|
19
|
+
basket: { code: "BSK", description: "Basket" },
|
20
|
+
bunch: { code: "BUN", description: "Bunch" },
|
21
|
+
cabinet: { code: "CAB", description: "Cabinet" },
|
22
|
+
can: { code: "CAN", description: "Can" },
|
23
|
+
carrier: { code: "CAR", description: "Carrier" },
|
24
|
+
case: { code: "CAS", description: "Case" },
|
25
|
+
carboy: { code: "CBY", description: "Carboy" },
|
26
|
+
container: { code: "CON", description: "Container" },
|
27
|
+
crate: { code: "CRT", description: "Crate" },
|
28
|
+
cask: { code: "CSK", description: "Cask" },
|
29
|
+
carton: { code: "CTN", description: "Carton" },
|
30
|
+
cylinder: { code: "CYL", description: "Cylinder" },
|
31
|
+
drum: { code: "DRM", description: "Drum" },
|
32
|
+
loose: { code: "LOO", description: "Loose" },
|
33
|
+
other: { code: "OTH", description: "Other" },
|
34
|
+
pail: { code: "PAL", description: "Pail" },
|
35
|
+
pieces: { code: "PCS", description: "Pieces" },
|
36
|
+
package: { code: "PKG", description: "Package" },
|
37
|
+
pipe_line: { code: "PLN", description: "Pipe Line" },
|
38
|
+
pallet: { code: "PLT", description: "Pallet" },
|
39
|
+
rack: { code: "RCK", description: "Rack" },
|
40
|
+
reel: { code: "REL", description: "Reel" },
|
41
|
+
roll: { code: "ROL", description: "Roll" },
|
42
|
+
skid: { code: "SKD", description: "Skid" },
|
43
|
+
spool: { code: "SPL", description: "Spool" },
|
44
|
+
tube: { code: "TBE", description: "Tube" },
|
45
|
+
tank: { code: "TNK", description: "Tank" },
|
46
|
+
totes: { code: "TOT", description: "Totes" },
|
47
|
+
unit: { code: "UNT", description: "Unit" },
|
48
|
+
van_pack: { code: "VPK", description: "Van Pack" },
|
49
|
+
wrapped: { code: "WRP", description: "Wrapped" }
|
50
|
+
}.freeze
|
51
|
+
|
52
|
+
attr_reader :packaging_code,
|
53
|
+
:packaging_description,
|
54
|
+
:freight_class,
|
55
|
+
:nmfc_code
|
56
|
+
|
57
|
+
def initialize(
|
58
|
+
packaging: :carton,
|
59
|
+
freight_class: nil,
|
60
|
+
nmfc_code: nil,
|
61
|
+
**kwargs
|
62
|
+
)
|
63
|
+
@packaging_code = PACKAGING_TYPES.fetch(packaging).fetch(:code)
|
64
|
+
@packaging_description = PACKAGING_TYPES.fetch(packaging).fetch(:description)
|
65
|
+
@freight_class = freight_class
|
66
|
+
@nmfc_code = nmfc_code
|
67
|
+
super kwargs
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'friendly_shipping/services/ups_freight/rates_package_options'
|
4
|
+
require 'friendly_shipping/services/ups_freight/generate_commodity_information'
|
5
|
+
|
6
|
+
module FriendlyShipping
|
7
|
+
module Services
|
8
|
+
class UpsFreight
|
9
|
+
# Options for generating UPS Freight rates for a shipment
|
10
|
+
#
|
11
|
+
# @attribute [Physical::Location] billing_address The billing address
|
12
|
+
# @attribute [String] shipper_number The shipper number associated with the shipper
|
13
|
+
# @attribute [String] customer_context A reference to match this request with an order or shipment
|
14
|
+
# @attribute [FriendlyShipping::ShippingMethod] shipping_method The shipping method to use
|
15
|
+
# @attribute [Callable] commodity_information_generator A callable that takes a shipment
|
16
|
+
# and an options object to create an Array of commodity fields as per the UPS docs.
|
17
|
+
# @attribute [Symbol] billing One of the keys in the `BILLING_CODES` constant. How the shipment
|
18
|
+
# would be billed.
|
19
|
+
# @attribute [RatesPackageOptions] package_options Options for each of the packages/pallets in this shipment
|
20
|
+
class RatesOptions < FriendlyShipping::ShipmentOptions
|
21
|
+
BILLING_CODES = {
|
22
|
+
prepaid: '10',
|
23
|
+
third_party: '30',
|
24
|
+
freight_collect: '40'
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
attr_reader :shipper_number,
|
28
|
+
:billing_address,
|
29
|
+
:billing_code,
|
30
|
+
:customer_context,
|
31
|
+
:shipping_method,
|
32
|
+
:commodity_information_generator
|
33
|
+
|
34
|
+
def initialize(
|
35
|
+
shipper_number:,
|
36
|
+
billing_address:,
|
37
|
+
shipping_method:,
|
38
|
+
billing: :prepaid,
|
39
|
+
customer_context: nil,
|
40
|
+
commodity_information_generator: GenerateCommodityInformation,
|
41
|
+
**kwargs
|
42
|
+
)
|
43
|
+
@shipper_number = shipper_number
|
44
|
+
@billing_address = billing_address
|
45
|
+
@shipping_method = shipping_method
|
46
|
+
@billing_code = BILLING_CODES.fetch(billing)
|
47
|
+
@customer_context = customer_context
|
48
|
+
@commodity_information_generator = commodity_information_generator
|
49
|
+
super kwargs.merge(package_options_class: RatesPackageOptions)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|