friendly_shipping 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +18 -5
  3. data/.env.template +1 -1
  4. data/.rubocop.yml +4 -1
  5. data/CHANGELOG.md +14 -3
  6. data/README.md +1 -1
  7. data/friendly_shipping.gemspec +6 -7
  8. data/lib/friendly_shipping/api_error.rb +14 -0
  9. data/lib/friendly_shipping/api_error_handler.rb +30 -0
  10. data/lib/friendly_shipping/http_client.rb +9 -27
  11. data/lib/friendly_shipping/request.rb +5 -3
  12. data/lib/friendly_shipping/response.rb +27 -1
  13. data/lib/friendly_shipping/services/ship_engine/parse_label_response.rb +8 -2
  14. data/lib/friendly_shipping/services/ship_engine/parse_rate_estimate_response.rb +28 -6
  15. data/lib/friendly_shipping/services/ship_engine.rb +9 -5
  16. data/lib/friendly_shipping/services/ups/parse_shipment_accept_response.rb +1 -1
  17. data/lib/friendly_shipping/services/ups/parse_shipment_confirm_response.rb +1 -1
  18. data/lib/friendly_shipping/services/ups/parse_void_shipment_response.rb +1 -1
  19. data/lib/friendly_shipping/services/ups/rate_estimate_options.rb +1 -1
  20. data/lib/friendly_shipping/services/ups/rate_estimate_package_options.rb +1 -1
  21. data/lib/friendly_shipping/services/ups/shipping_methods.rb +4 -0
  22. data/lib/friendly_shipping/services/ups.rb +10 -2
  23. data/lib/friendly_shipping/services/ups_freight/api_error.rb +36 -0
  24. data/lib/friendly_shipping/services/ups_freight/generate_delivery_options_hash.rb +6 -4
  25. data/lib/friendly_shipping/services/ups_freight/generate_freight_ship_request_hash.rb +5 -2
  26. data/lib/friendly_shipping/services/ups_freight/generate_location_hash.rb +6 -9
  27. data/lib/friendly_shipping/services/ups_freight/generate_pickup_options_hash.rb +4 -3
  28. data/lib/friendly_shipping/services/ups_freight/generate_reference_hash.rb +27 -0
  29. data/lib/friendly_shipping/services/ups_freight/label_delivery_options.rb +7 -1
  30. data/lib/friendly_shipping/services/ups_freight/label_options.rb +28 -2
  31. data/lib/friendly_shipping/services/ups_freight/label_pickup_options.rb +3 -0
  32. data/lib/friendly_shipping/services/ups_freight/parse_freight_label_response.rb +27 -8
  33. data/lib/friendly_shipping/services/ups_freight/parse_shipment_document.rb +1 -1
  34. data/lib/friendly_shipping/services/ups_freight/shipment_information.rb +5 -2
  35. data/lib/friendly_shipping/services/ups_freight.rb +8 -5
  36. data/lib/friendly_shipping/services/usps/parse_package_rate.rb +16 -1
  37. data/lib/friendly_shipping/services/usps/rate_estimate_options.rb +1 -1
  38. data/lib/friendly_shipping/services/usps/rate_estimate_package_options.rb +23 -19
  39. data/lib/friendly_shipping/services/usps/serialize_rate_request.rb +2 -0
  40. data/lib/friendly_shipping/services/usps.rb +2 -1
  41. data/lib/friendly_shipping/version.rb +1 -1
  42. data/lib/friendly_shipping.rb +1 -0
  43. metadata +18 -35
  44. data/lib/friendly_shipping/services/ups_freight/restful_api_error_handler.rb +0 -30
@@ -7,11 +7,13 @@ module FriendlyShipping
7
7
  def self.call(delivery_options:)
8
8
  {
9
9
  DeliveryOptions: {
10
+ CallBeforeDeliveryIndicator: delivery_options.call_before_delivery ? "" : nil,
11
+ HolidayDeliveryIndicator: delivery_options.holiday_delivery ? "" : nil,
12
+ InsideDeliveryIndicator: delivery_options.inside_delivery ? "" : nil,
13
+ ResidentialDeliveryIndicator: delivery_options.residential_delivery ? "" : nil,
14
+ WeekendDeliveryIndicator: delivery_options.weekend_delivery ? "" : nil,
10
15
  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
16
+ LimitedAccessDeliveryIndicator: delivery_options.limited_access_delivery ? "" : nil
15
17
  }.compact.presence
16
18
  }.compact.presence
17
19
  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_reference_hash'
4
5
  require 'friendly_shipping/services/ups_freight/generate_document_options_hash'
5
6
  require 'friendly_shipping/services/ups_freight/generate_email_options_hash'
6
7
  require 'friendly_shipping/services/ups_freight/generate_pickup_options_hash'
@@ -30,8 +31,10 @@ module FriendlyShipping
30
31
  HandlingInstructions: options.handling_instructions,
31
32
  PickupInstructions: options.pickup_instructions,
32
33
  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)
34
+ PickupRequest: GeneratePickupRequestHash.call(pickup_request_options: options.pickup_request_options),
35
+ }.compact.
36
+ merge(handling_units(shipment, options).reduce(&:merge).to_h).
37
+ merge(GenerateReferenceHash.call(reference_numbers: options.reference_numbers))
35
38
  }
36
39
  }
37
40
  end
@@ -6,16 +6,14 @@ module FriendlyShipping
6
6
  class GenerateLocationHash
7
7
  class << self
8
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
9
  {
12
- Name: location.company_name,
10
+ Name: location.company_name.presence || location.name,
13
11
  Address: {
14
12
  AddressLine: address_line(location),
15
13
  City: location.city,
16
- StateProvinceCode: location.region.code,
14
+ StateProvinceCode: location.region&.code,
17
15
  PostalCode: location.zip,
18
- CountryCode: location.country.code
16
+ CountryCode: location.country&.code
19
17
  },
20
18
  AttentionName: location.name,
21
19
  Phone: {
@@ -27,13 +25,12 @@ module FriendlyShipping
27
25
  private
28
26
 
29
27
  def address_line(location)
30
- [
28
+ address_lines = [
31
29
  location.address1,
32
30
  location.address2,
33
31
  location.address3
34
- ].compact.
35
- reject(&:empty?).
36
- join(", ")
32
+ ].compact.reject(&:empty?)
33
+ address_lines.size > 1 ? address_lines : address_lines.first
37
34
  end
38
35
  end
39
36
  end
@@ -7,10 +7,11 @@ module FriendlyShipping
7
7
  def self.call(pickup_options:)
8
8
  {
9
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
10
  HolidayPickupIndicator: pickup_options.holiday_pickup ? "" : nil,
11
+ InsidePickupIndicator: pickup_options.inside_pickup ? "" : nil,
12
+ ResidentialPickupIndicator: pickup_options.residential_pickup ? "" : nil,
13
+ WeekendPickupIndicator: pickup_options.weekend_pickup ? "" : nil,
14
+ LiftGateRequiredIndicator: pickup_options.lift_gate_required ? "" : nil,
14
15
  LimitedAccessPickupIndicator: pickup_options.limited_access_pickup ? "" : nil
15
16
  }.compact.presence
16
17
  }.compact.presence
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FriendlyShipping
4
+ module Services
5
+ class UpsFreight
6
+ class GenerateReferenceHash
7
+ class << self
8
+ # @param [Array] reference_numbers Reference numbers for the Bill of Lading
9
+ # @return [Hash] Reference hash suitable for JSON request
10
+ def call(reference_numbers:)
11
+ return {} unless reference_numbers
12
+
13
+ references = reference_numbers.map do |reference_number|
14
+ {
15
+ Number: {
16
+ Code: reference_number[:code],
17
+ Value: reference_number[:value]
18
+ }
19
+ }
20
+ end
21
+ references.any? ? { Reference: references } : {}
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -4,21 +4,27 @@ module FriendlyShipping
4
4
  module Services
5
5
  class UpsFreight
6
6
  class LabelDeliveryOptions
7
- attr_reader :holiday_delivery,
7
+ attr_reader :call_before_delivery,
8
+ :holiday_delivery,
8
9
  :inside_delivery,
10
+ :residential_delivery,
9
11
  :weekend_delivery,
10
12
  :lift_gate_required,
11
13
  :limited_access_delivery
12
14
 
13
15
  def initialize(
16
+ call_before_delivery: nil,
14
17
  holiday_delivery: nil,
15
18
  inside_delivery: nil,
19
+ residential_delivery: nil,
16
20
  weekend_delivery: nil,
17
21
  lift_gate_required: nil,
18
22
  limited_access_delivery: nil
19
23
  )
24
+ @call_before_delivery = call_before_delivery
20
25
  @holiday_delivery = holiday_delivery
21
26
  @inside_delivery = inside_delivery
27
+ @residential_delivery = residential_delivery
22
28
  @weekend_delivery = weekend_delivery
23
29
  @lift_gate_required = lift_gate_required
24
30
  @limited_access_delivery = limited_access_delivery
@@ -4,14 +4,30 @@ module FriendlyShipping
4
4
  module Services
5
5
  class UpsFreight
6
6
  class LabelOptions < RatesOptions
7
+ REFERENCE_NUMBER_CODES = {
8
+ bill_of_lading_number: "57",
9
+ purchase_order_number: "28",
10
+ shipper_reference: "SH",
11
+ consignee_reference: "CO",
12
+ pm: "PM",
13
+ proj: "PROJ",
14
+ quote: "QUOTE",
15
+ sid: "SID",
16
+ task: "TASK",
17
+ vprc: "VPRC",
18
+ other: "OTHER"
19
+ }.freeze
20
+
7
21
  attr_reader :document_options,
8
22
  :email_options,
9
23
  :pickup_options,
10
24
  :delivery_options,
11
25
  :pickup_instructions,
12
26
  :delivery_instructions,
13
- :handling_instructions
27
+ :handling_instructions,
28
+ :reference_numbers
14
29
 
30
+ # @param [Array] reference_numbers Reference numbers for the Bill of Lading
15
31
  def initialize(
16
32
  document_options: [],
17
33
  email_options: [],
@@ -20,6 +36,7 @@ module FriendlyShipping
20
36
  pickup_instructions: nil,
21
37
  delivery_instructions: nil,
22
38
  handling_instructions: nil,
39
+ reference_numbers: [],
23
40
  **kwargs
24
41
  )
25
42
  @pickup_options = pickup_options
@@ -29,7 +46,16 @@ module FriendlyShipping
29
46
  @pickup_instructions = pickup_instructions
30
47
  @delivery_instructions = delivery_instructions
31
48
  @handling_instructions = handling_instructions
32
- super kwargs
49
+ @reference_numbers = fill_codes(reference_numbers)
50
+ super(**kwargs)
51
+ end
52
+
53
+ private
54
+
55
+ def fill_codes(reference_numbers)
56
+ reference_numbers.each do |reference_number|
57
+ reference_number[:code] = REFERENCE_NUMBER_CODES.fetch(reference_number[:code])
58
+ end
33
59
  end
34
60
  end
35
61
  end
@@ -6,6 +6,7 @@ module FriendlyShipping
6
6
  class LabelPickupOptions
7
7
  attr_reader :holiday_pickup,
8
8
  :inside_pickup,
9
+ :residential_pickup,
9
10
  :weekend_pickup,
10
11
  :lift_gate_required,
11
12
  :limited_access_pickup
@@ -13,12 +14,14 @@ module FriendlyShipping
13
14
  def initialize(
14
15
  holiday_pickup: nil,
15
16
  inside_pickup: nil,
17
+ residential_pickup: nil,
16
18
  weekend_pickup: nil,
17
19
  lift_gate_required: nil,
18
20
  limited_access_pickup: nil
19
21
  )
20
22
  @holiday_pickup = holiday_pickup
21
23
  @inside_pickup = inside_pickup
24
+ @residential_pickup = residential_pickup
22
25
  @weekend_pickup = weekend_pickup
23
26
  @lift_gate_required = lift_gate_required
24
27
  @limited_access_pickup = limited_access_pickup
@@ -23,19 +23,23 @@ module FriendlyShipping
23
23
  service_code = shipment_results.dig("Service", "Code")
24
24
  shipping_method = SHIPPING_METHODS.detect { |sm| sm.service_code == service_code }
25
25
 
26
- total_shipment_charge = shipment_results.dig("TotalShipmentCharge")
27
- currency = Money::Currency.new(total_shipment_charge['CurrencyCode'])
28
- amount = total_shipment_charge['MonetaryValue'].to_f
29
- total_money = Money.new(amount * currency.subunit_to_unit, currency)
26
+ total_shipment_charge = shipment_results["TotalShipmentCharge"]
27
+ if total_shipment_charge
28
+ currency = Money::Currency.new(total_shipment_charge['CurrencyCode'])
29
+ amount = total_shipment_charge['MonetaryValue'].to_f
30
+ total_money = Money.new(amount * currency.subunit_to_unit, currency)
31
+ end
30
32
 
31
33
  images_data = Array.wrap(shipment_results.dig("Documents", "Image"))
32
34
 
33
- bol_id = shipment_results.dig("BOLID")
34
- shipment_number = shipment_results.dig("ShipmentNumber")
35
- pickup_request_number = shipment_results.dig("PickupRequestConfirmationNumber")
35
+ bol_id = shipment_results["BOLID"]
36
+ shipment_number = shipment_results["ShipmentNumber"]
37
+ pickup_request_number = shipment_results["PickupRequestConfirmationNumber"]
36
38
 
37
39
  documents = images_data.map { |image_data| ParseShipmentDocument.call(image_data: image_data) }
38
40
 
41
+ cost_breakdown = build_cost_breakdown(shipment_results)
42
+
39
43
  FriendlyShipping::ApiResult.new(
40
44
  ShipmentInformation.new(
41
45
  total: total_money,
@@ -44,12 +48,27 @@ module FriendlyShipping
44
48
  pickup_request_number: pickup_request_number,
45
49
  shipping_method: shipping_method,
46
50
  warnings: warnings,
47
- documents: documents
51
+ documents: documents,
52
+ data: {
53
+ cost_breakdown: cost_breakdown
54
+ }
48
55
  ),
49
56
  original_request: request,
50
57
  original_response: response
51
58
  )
52
59
  end
60
+
61
+ private
62
+
63
+ def build_cost_breakdown(shipment_results)
64
+ {
65
+ "Rates" => shipment_results.fetch("Rate", []).each_with_object({}) do |rate, hash|
66
+ hash[rate.dig("Type", "Code")] = rate.dig("Factor", "Value")
67
+ end,
68
+ "TotalShipmentCharge" => shipment_results.dig("TotalShipmentCharge", "MonetaryValue"),
69
+ "BillableShipmentWeight" => shipment_results.dig("BillableShipmentWeight", "Value")
70
+ }.compact
71
+ end
53
72
  end
54
73
  end
55
74
  end
@@ -10,7 +10,7 @@ module FriendlyShipping
10
10
 
11
11
  def self.call(image_data:)
12
12
  format_code = image_data.dig("Type", "Code")
13
- graphic_image_b64 = image_data.dig("GraphicImage")
13
+ graphic_image_b64 = image_data["GraphicImage"]
14
14
 
15
15
  ShipmentDocument.new(
16
16
  format: image_data.dig("Format", "Code").downcase.to_sym,
@@ -10,7 +10,8 @@ module FriendlyShipping
10
10
  :total,
11
11
  :bol_id,
12
12
  :shipping_method,
13
- :warnings
13
+ :warnings,
14
+ :data
14
15
 
15
16
  def initialize(
16
17
  total:,
@@ -19,7 +20,8 @@ module FriendlyShipping
19
20
  pickup_request_number: nil,
20
21
  documents: [],
21
22
  shipping_method: nil,
22
- warnings: nil
23
+ warnings: nil,
24
+ data: {}
23
25
  )
24
26
  @total = total
25
27
  @bol_id = bol_id
@@ -28,6 +30,7 @@ module FriendlyShipping
28
30
  @documents = documents
29
31
  @shipping_method = shipping_method
30
32
  @warnings = warnings
33
+ @data = data
31
34
  end
32
35
  end
33
36
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/result'
3
+ require 'dry/monads'
4
4
  require 'friendly_shipping/http_client'
5
5
  require 'friendly_shipping/services/ups_freight/shipping_methods'
6
6
  require 'friendly_shipping/services/ups_freight/rates_options'
@@ -18,12 +18,12 @@ require 'friendly_shipping/services/ups_freight/parse_freight_label_response'
18
18
  require 'friendly_shipping/services/ups_freight/parse_freight_rate_response'
19
19
  require 'friendly_shipping/services/ups_freight/generate_freight_rate_request_hash'
20
20
  require 'friendly_shipping/services/ups_freight/generate_freight_ship_request_hash'
21
- require 'friendly_shipping/services/ups_freight/restful_api_error_handler'
21
+ require 'friendly_shipping/services/ups_freight/api_error'
22
22
 
23
23
  module FriendlyShipping
24
24
  module Services
25
25
  class UpsFreight
26
- include Dry::Monads::Result::Mixin
26
+ include Dry::Monads[:result]
27
27
 
28
28
  attr_reader :test, :key, :login, :password, :client
29
29
 
@@ -42,12 +42,14 @@ module FriendlyShipping
42
42
  labels: '/ship/v1607/freight/shipments/Ground'
43
43
  }.freeze
44
44
 
45
- def initialize(key:, login:, password:, test: true, client: HttpClient.new(error_handler: RestfulApiErrorHandler))
45
+ def initialize(key:, login:, password:, test: true, client: nil)
46
46
  @key = key
47
47
  @login = login
48
48
  @password = password
49
49
  @test = test
50
- @client = client
50
+
51
+ error_handler = ApiErrorHandler.new(api_error_class: UpsFreight::ApiError)
52
+ @client = client || HttpClient.new(error_handler: error_handler)
51
53
  end
52
54
 
53
55
  def carriers
@@ -87,6 +89,7 @@ module FriendlyShipping
87
89
  url = base_url + RESOURCES[action]
88
90
  FriendlyShipping::Request.new(
89
91
  url: url,
92
+ http_method: "POST",
90
93
  body: payload.to_json,
91
94
  headers: {
92
95
  Content_Type: 'application/json',
@@ -55,6 +55,8 @@ module FriendlyShipping
55
55
  RATE_TAG = 'Rate'
56
56
  COMMERCIAL_RATE_TAG = 'CommercialRate'
57
57
  COMMERCIAL_PLUS_RATE_TAG = 'CommercialPlusRate'
58
+ DIMENSIONAL_WEIGHT_RATE = 'DimensionalWeightRate'
59
+ FEES = './/Fees/Fee'
58
60
  CURRENCY = Money::Currency.new('USD').freeze
59
61
 
60
62
  class << self
@@ -119,6 +121,17 @@ module FriendlyShipping
119
121
  box_name_match = service_name.match(/#{BOX_REGEX}/)
120
122
  box_name = box_name_match ? box_name_match.named_captures.compact.keys.last.to_sym : :variable
121
123
 
124
+ dimensional_weight_rate = rate_node.at(DIMENSIONAL_WEIGHT_RATE)&.text&.to_i
125
+
126
+ fees = rate_node.xpath(FEES).map do |fee_node|
127
+ type = fee_node.at('FeeType').text
128
+ price = fee_node.at('FeePrice').text.to_d
129
+ {
130
+ type: type,
131
+ price: Money.new(price * CURRENCY.subunit_to_unit, CURRENCY)
132
+ }
133
+ end
134
+
122
135
  # Combine all the gathered information in a FriendlyShipping::Rate object.
123
136
  # Careful: This rate is only for one package within the shipment, and we get multiple
124
137
  # rates per package for the different shipping method/box/hold for pickup combinations.
@@ -132,7 +145,9 @@ module FriendlyShipping
132
145
  days_to_delivery: days_to_delivery,
133
146
  military: military,
134
147
  full_mail_service: service_name,
135
- service_code: service_code
148
+ service_code: service_code,
149
+ dimensional_weight_rate: dimensional_weight_rate,
150
+ fees: fees
136
151
  }
137
152
  )
138
153
  end
@@ -20,7 +20,7 @@ module FriendlyShipping
20
20
  package_options_class: FriendlyShipping::Services::Usps::RateEstimatePackageOptions,
21
21
  **kwargs
22
22
  )
23
- super kwargs.merge(package_options_class: package_options_class)
23
+ super(**kwargs.merge(package_options_class: package_options_class))
24
24
  end
25
25
  end
26
26
  end
@@ -8,6 +8,8 @@ module FriendlyShipping
8
8
  #
9
9
  # @param [Symbol] box_name The type of box we want to get rates for. Has to be one of the keys
10
10
  # of FriendlyShipping::Services::Usps::CONTAINERS.
11
+ # @param [Symbol] return_dimensional_weight Boolean indicating whether the response should include dimensional weight.
12
+ # @param [Symbol] return_fees Boolean indicating whether the response should include fees.
11
13
  class Usps
12
14
  class RateEstimatePackageOptions < FriendlyShipping::PackageOptions
13
15
  attr_reader :box_name,
@@ -16,26 +18,22 @@ module FriendlyShipping
16
18
  :hold_for_pickup,
17
19
  :shipping_method,
18
20
  :transmit_dimensions,
19
- :rectangular
20
-
21
- def initialize(
22
- box_name: :variable,
23
- commercial_pricing: false,
24
- first_class_mail_type: nil,
25
- hold_for_pickup: false,
26
- shipping_method: nil,
27
- transmit_dimensions: true,
28
- rectangular: true,
29
- **kwargs
30
- )
21
+ :rectangular,
22
+ :return_dimensional_weight,
23
+ :return_fees
24
+
25
+ def initialize(**kwargs)
26
+ box_name = value_or_default(:box_name, :variable, kwargs)
31
27
  @box_name = CONTAINERS.key?(box_name) ? box_name : :variable
32
- @commercial_pricing = commercial_pricing
33
- @first_class_mail_type = first_class_mail_type
34
- @hold_for_pickup = hold_for_pickup
35
- @shipping_method = shipping_method
36
- @transmit_dimensions = transmit_dimensions
37
- @rectangular = rectangular
38
- super kwargs
28
+ @commercial_pricing = value_or_default(:commercial_pricing, false, kwargs)
29
+ @first_class_mail_type = kwargs.delete(:first_class_mail_type)
30
+ @hold_for_pickup = value_or_default(:hold_for_pickup, false, kwargs)
31
+ @shipping_method = kwargs.delete(:shipping_method)
32
+ @transmit_dimensions = value_or_default(:transmit_dimensions, true, kwargs)
33
+ @rectangular = value_or_default(:rectangular, true, kwargs)
34
+ @return_dimensional_weight = value_or_default(:return_dimensional_weight, true, kwargs)
35
+ @return_fees = value_or_default(:return_fees, false, kwargs)
36
+ super(**kwargs)
39
37
  end
40
38
 
41
39
  def container_code
@@ -57,6 +55,12 @@ module FriendlyShipping
57
55
  service_code << 'COMMERCIAL' if commercial_pricing
58
56
  service_code.join(' ')
59
57
  end
58
+
59
+ private
60
+
61
+ def value_or_default(key, default, kwargs)
62
+ kwargs.key?(key) ? kwargs.delete(key) : default
63
+ end
60
64
  end
61
65
  end
62
66
  end
@@ -46,6 +46,8 @@ module FriendlyShipping
46
46
  end
47
47
  end
48
48
  xml.Machinable(machinable(package))
49
+ xml.ReturnDimensionalWeight(true) if package_options.return_dimensional_weight
50
+ xml.ReturnFees(true) if package_options.return_fees
49
51
  end
50
52
  end
51
53
  end
@@ -16,7 +16,7 @@ require 'friendly_shipping/services/usps/rate_estimate_options'
16
16
  module FriendlyShipping
17
17
  module Services
18
18
  class Usps
19
- include Dry::Monads::Result::Mixin
19
+ include Dry::Monads[:result]
20
20
 
21
21
  attr_reader :test, :login, :client
22
22
 
@@ -111,6 +111,7 @@ module FriendlyShipping
111
111
  def build_request(api:, xml:, debug:)
112
112
  FriendlyShipping::Request.new(
113
113
  url: base_url,
114
+ http_method: "POST",
114
115
  body: "API=#{RESOURCES[api]}&XML=#{CGI.escape xml}",
115
116
  readable_body: xml,
116
117
  debug: debug
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FriendlyShipping
4
- VERSION = "0.6.4"
4
+ VERSION = "0.7.0"
5
5
  end
@@ -18,6 +18,7 @@ require "friendly_shipping/api_failure"
18
18
 
19
19
  require "friendly_shipping/services/ship_engine"
20
20
  require "friendly_shipping/services/ups"
21
+ require "friendly_shipping/services/ups_freight"
21
22
  require "friendly_shipping/services/usps"
22
23
 
23
24
  module FriendlyShipping