friendly_shipping 0.5.3 → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b2b1c8a12304b7f798f0df9210f6e52027bd588b9d612f5f05bf5d102e8db0e8
4
- data.tar.gz: 7813b10233d7364d836d5cd50bb281b9ef43c37d936009f8f400a164d4a30fb1
3
+ metadata.gz: 107fa27ec95b49342549dbf24c53cc483cd05bdfbb64871940036aaac6567eb6
4
+ data.tar.gz: 7dd9c281178e513482ae0cb93787eb551b09e5f697f10d4db50dc2aef21dd4a8
5
5
  SHA512:
6
- metadata.gz: dc7eb250872e158e3ba105168bda09f47328bd2077f758a5e7e746416aa5af071686b992609c1b62d50d399085164999970119ba2d801cbe7d5f99803d675132
7
- data.tar.gz: 4ccb36047bfc9f612af55014b35fb3d72e629277776a65d4c7b4363c056d28d7de16d77564bf371a17ef01002cf04322047b93526f7aa35cc648b6acbfc33567
6
+ metadata.gz: 30c37297f77dc6be490cf9719211780b81b0d91cdc49311b349fc3844a6cbcb5755265e663b80e24a67cda9847e19d328808cec786cf7172d6986ccb75bbf6eb
7
+ data.tar.gz: 022c69680c07d9fed0b2b9afa8093e40b20bb7b441b332acd743078f74db70f3de03227953952de8b08048aa40eb902895529c781b6332036cf4e38ba653804e
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "bundler"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "daily"
data/.gitignore CHANGED
@@ -4,6 +4,7 @@
4
4
  /coverage/
5
5
  /doc/
6
6
  /.idea/
7
+ /.vscode/
7
8
  /pkg/
8
9
  /spec/reports/
9
10
  /tmp/
@@ -4,9 +4,43 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.6.4] - 2021-01-27
8
+
9
+ ### Added
10
+
11
+ - UPS Service: Include negotiated charges for UPS (#119)
12
+ - UPS Service: Include shipment-level itemized charges (#117)
13
+
14
+ ## [0.6.3] - 2020-10-30
15
+
16
+ ### Added
17
+
18
+ - USPS Service: Append HFP (Hold For Pickup) to service code when necessary (#110)
19
+ - USPS Service: Add Priority Cubic shipping method (#113)
20
+
21
+ ### Changed
22
+
23
+ - USPS Service: Refactor to use explicit service codes (#111)
24
+ - USPS Service: Match Priority Express by CLASSID instead of service name (#112)
25
+ - UPS Service: Rename peak surcharge keys to match UPS docs (#114)
26
+
27
+ ## [0.6.2] - 2020-08-12
28
+
29
+ - UPS Service: Be more resilient when UPS does not send a PickupTime element
30
+
31
+ ## [0.6.1] - 2020-03-11
32
+
33
+ - Add Content-Type header to UPS Freight API requests, fixing "Name too long" 500 error responses
34
+
35
+ ## [0.6.0] - 2020-03-11
36
+
37
+ - Changelog additions missed in previous release
38
+
7
39
  ## [0.5.3] - 2020-03-11
8
40
 
9
- - UPS Service: Add support for shipping labels / bills of lading
41
+ - UPS Service: Add support for shipping labels / bills of lading (#92)
42
+ - UPS/USPS Services: Return ApiFailure instead of a string for failed API responses (#95)
43
+ - UPS/USPS Services: Refactor ApiFailure to subclass ApiResponse (#96)
10
44
 
11
45
  ## [0.5.2] - 2020-01-31
12
46
 
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
12
12
 
13
13
  spec.summary = "An integration layer for shipping services"
14
14
  spec.description = "Allows you to quote or ship a Physical::Shipment object"
15
- spec.homepage = "https://github.com/friendly_cart/friendly_shipping"
15
+ spec.homepage = "https://github.com/friendlycart/friendly_shipping"
16
16
  spec.license = "MIT"
17
17
 
18
18
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency "dotenv", "~> 2.7"
35
35
  spec.add_development_dependency "factory_bot", "~> 5.0"
36
36
  spec.add_development_dependency "pry", "~> 0.12"
37
- spec.add_development_dependency "rake", "~> 10.0"
37
+ spec.add_development_dependency "rake", ">= 12.3.3"
38
38
  spec.add_development_dependency "rspec", "~> 3.0"
39
39
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.4"
40
40
  spec.add_development_dependency "rubocop", ">= 0.80", "< 1"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'dry/monads/result'
4
+ require 'friendly_shipping/api_failure'
4
5
  require 'rest-client'
5
6
 
6
7
  module FriendlyShipping
@@ -21,19 +22,19 @@ module FriendlyShipping
21
22
 
22
23
  Success(convert_to_friendly_response(http_response))
23
24
  rescue ::RestClient::Exception => e
24
- error_handler.call(e)
25
+ error_handler.call(e, original_request: request, original_response: e.response)
25
26
  end
26
27
 
27
- def post(friendly_shipping_request)
28
+ def post(request)
28
29
  http_response = ::RestClient.post(
29
- friendly_shipping_request.url,
30
- friendly_shipping_request.body,
31
- friendly_shipping_request.headers
30
+ request.url,
31
+ request.body,
32
+ request.headers
32
33
  )
33
34
 
34
35
  Success(convert_to_friendly_response(http_response))
35
36
  rescue ::RestClient::Exception => e
36
- error_handler.call(e)
37
+ error_handler.call(e, original_request: request, original_response: e.response)
37
38
  end
38
39
 
39
40
  def put(request)
@@ -45,13 +46,19 @@ module FriendlyShipping
45
46
 
46
47
  Success(convert_to_friendly_response(http_response))
47
48
  rescue ::RestClient::Exception => e
48
- error_handler.call(e)
49
+ error_handler.call(e, original_request: request, original_response: e.response)
49
50
  end
50
51
 
51
52
  private
52
53
 
53
- def wrap_in_failure(error)
54
- Failure(error)
54
+ def wrap_in_failure(error, original_request: nil, original_response: nil)
55
+ Failure(
56
+ ApiFailure.new(
57
+ error,
58
+ original_request: original_request,
59
+ original_response: original_response
60
+ )
61
+ )
55
62
  end
56
63
 
57
64
  def convert_to_friendly_response(http_response)
@@ -8,11 +8,23 @@ module FriendlyShipping
8
8
  class BadRequestHandler
9
9
  extend Dry::Monads::Result::Mixin
10
10
 
11
- def self.call(error)
11
+ def self.call(error, original_request: nil, original_response: nil)
12
12
  if error.http_code == 400
13
- Failure(BadRequest.new(error))
13
+ Failure(
14
+ ApiFailure.new(
15
+ BadRequest.new(error),
16
+ original_request: original_request,
17
+ original_response: original_response
18
+ )
19
+ )
14
20
  else
15
- Failure(error)
21
+ Failure(
22
+ ApiFailure.new(
23
+ error,
24
+ original_request: original_request,
25
+ original_response: original_response
26
+ )
27
+ )
16
28
  end
17
29
  end
18
30
  end
@@ -75,8 +75,8 @@ module FriendlyShipping
75
75
  "407" => "EXTENDED AREA PICKUP",
76
76
  "410" => "RETURN OF DOCUMENT",
77
77
  "430" => "PEAK SEASON",
78
- "431" => "PEAK SEASON SURCHARGE - LARGE PACK",
79
- "432" => "PEAK SEASON SURCHARGE - ADDITIONAL HANDLING",
78
+ "431" => "LARGE PACKAGE SEASONAL SURCHARGE",
79
+ "432" => "ADDITIONAL HANDLING SEASONAL SURCHARGE",
80
80
  "440" => "SHIP LARGE PACKAGE",
81
81
  "441" => "CARBON NEUTRAL",
82
82
  "442" => "PKG QV IN TRANSIT NOTIFICATION",
@@ -36,6 +36,8 @@ module FriendlyShipping
36
36
  negotiated_rate = ParseMoneyElement.call(
37
37
  rated_shipment.at('NegotiatedRates/NetSummaryCharges/GrandTotal')
38
38
  )&.last
39
+ negotiated_charges = extract_charges(rated_shipment.xpath('NegotiatedRates/ItemizedCharges'))
40
+ itemized_charges = extract_charges(rated_shipment.xpath('ItemizedCharges'))
39
41
 
40
42
  rated_shipment_warnings = rated_shipment.css('RatedShipmentWarning').map { |e| e.text.strip }
41
43
  if rated_shipment_warnings.any? { |e| e.match?(/to Residential/) }
@@ -52,8 +54,10 @@ module FriendlyShipping
52
54
  data: {
53
55
  insurance_price: insurance_price,
54
56
  negotiated_rate: negotiated_rate,
57
+ negotiated_charges: negotiated_charges,
55
58
  days_to_delivery: days_to_delivery,
56
59
  new_address_type: new_address_type,
60
+ itemized_charges: itemized_charges,
57
61
  packages: build_packages(rated_shipment)
58
62
  }.compact
59
63
  )
@@ -64,20 +68,24 @@ module FriendlyShipping
64
68
 
65
69
  def build_packages(rated_shipment)
66
70
  rated_shipment.css('RatedPackage').map do |rated_package|
67
- itemized_charges = rated_package.xpath('ItemizedCharges').map do |element|
68
- ParseMoneyElement.call(element)
69
- end.compact.to_h
70
71
  {
71
72
  transportation_charges: ParseMoneyElement.call(rated_package.at('TransportationCharges')).last,
72
73
  base_service_charge: ParseMoneyElement.call(rated_package.at('BaseServiceCharge')).last,
73
74
  service_options_charges: ParseMoneyElement.call(rated_package.at('ServiceOptionsCharges'))&.last,
74
- itemized_charges: itemized_charges,
75
+ itemized_charges: extract_charges(rated_package.xpath('ItemizedCharges')),
75
76
  total_charges: ParseMoneyElement.call(rated_package.at('TotalCharges')).last,
77
+ negotiated_charges: extract_charges(rated_package.xpath('NegotiatedCharges/ItemizedCharges')),
76
78
  weight: BigDecimal(rated_package.at('Weight').text),
77
79
  billing_weight: BigDecimal(rated_package.at('BillingWeight/Weight').text)
78
80
  }.compact
79
81
  end
80
82
  end
83
+
84
+ def extract_charges(node)
85
+ node.map do |element|
86
+ ParseMoneyElement.call(element)
87
+ end.compact.to_h
88
+ end
81
89
  end
82
90
  end
83
91
  end
@@ -25,7 +25,7 @@ module FriendlyShipping
25
25
  delivery_time = service_summary.at('EstimatedArrival/Time').text
26
26
  delivery = Time.parse("#{delivery_date} #{delivery_time}")
27
27
  pickup_date = service_summary.at('EstimatedArrival/PickupDate').text
28
- pickup_time = service_summary.at('EstimatedArrival/PickupTime').text
28
+ pickup_time = service_summary.at('EstimatedArrival/PickupTime')&.text
29
29
  pickup = Time.parse("#{pickup_date} #{pickup_time}")
30
30
 
31
31
  # Some additional data
@@ -55,7 +55,7 @@ module FriendlyShipping
55
55
  end
56
56
 
57
57
  # Get rates for a shipment
58
- # @param [Physical::Shipment] location The shipment we want to get rates for
58
+ # @param [Physical::Shipment] shipment The shipment we want to get rates for
59
59
  # @param [FriendlyShipping::Services::UpsFreight::RatesOptions] options Options for obtaining rates for this shipment.
60
60
  # @return [Result<ApiResult<Array<Rate>>>] The rates returned from UPS encoded in a
61
61
  # `FriendlyShipping::ApiResult` object.
@@ -69,7 +69,7 @@ module FriendlyShipping
69
69
  end
70
70
 
71
71
  # Get labels for a shipment
72
- # @param [Physical::Shipment] location The shipment we want to get rates for
72
+ # @param [Physical::Shipment] shipment The shipment we want to get rates for
73
73
  # @param [FriendlyShipping::Services::UpsFreight::LabelOptions] options Options for shipping this shipment.
74
74
  # @return [Result<ApiResult<ShipmentInformation>] The information that you need for shipping this shipment.
75
75
  def labels(shipment, options:, debug: false)
@@ -89,6 +89,7 @@ module FriendlyShipping
89
89
  url: url,
90
90
  body: payload.to_json,
91
91
  headers: {
92
+ Content_Type: 'application/json',
92
93
  Accept: 'application/json',
93
94
  Username: login,
94
95
  Password: password,
@@ -6,7 +6,7 @@ module FriendlyShipping
6
6
  class RestfulApiErrorHandler
7
7
  extend Dry::Monads::Result::Mixin
8
8
 
9
- def self.call(error)
9
+ def self.call(error, original_request: nil, original_response: nil)
10
10
  parsed_json = JSON.parse(error.response.body)
11
11
  errors = parsed_json.dig('response', 'errors')
12
12
 
@@ -16,7 +16,13 @@ module FriendlyShipping
16
16
  [status, desc].compact.join(": ").presence || 'UPS could not process the request.'
17
17
  end.join("\n")
18
18
 
19
- Failure(failure_string)
19
+ Failure(
20
+ ApiFailure.new(
21
+ failure_string,
22
+ original_request: original_request,
23
+ original_response: original_response
24
+ )
25
+ )
20
26
  end
21
27
  end
22
28
  end
@@ -54,6 +54,7 @@ module FriendlyShipping
54
54
  SERVICE_NAME_TAG = 'MailService'
55
55
  RATE_TAG = 'Rate'
56
56
  COMMERCIAL_RATE_TAG = 'CommercialRate'
57
+ COMMERCIAL_PLUS_RATE_TAG = 'CommercialPlusRate'
57
58
  CURRENCY = Money::Currency.new('USD').freeze
58
59
 
59
60
  class << self
@@ -82,27 +83,36 @@ module FriendlyShipping
82
83
 
83
84
  # Some USPS services only offer commercial pricing. Unfortunately, USPS then returns a retail rate of 0.
84
85
  # In these cases, return the commercial rate instead of the normal rate.
86
+ #
85
87
  # Some rates are available in both commercial and retail pricing - if we want the commercial pricing here,
86
88
  # we need to specify the commercial_pricing property on the `Physical::Package`.
87
- rate_value = if (package_options.commercial_pricing || rate_node.at(RATE_TAG).text.to_d.zero?) && rate_node.at(COMMERCIAL_RATE_TAG)
88
- rate_node.at(COMMERCIAL_RATE_TAG).text.to_d
89
- else
90
- rate_node.at(RATE_TAG).text.to_d
91
- end
89
+ #
90
+ commercial_rate_requested_or_rate_is_zero = package_options.commercial_pricing || rate_node.at(RATE_TAG).text.to_d.zero?
91
+ commercial_rate_available = rate_node.at(COMMERCIAL_RATE_TAG) || rate_node.at(COMMERCIAL_PLUS_RATE_TAG)
92
+
93
+ rate_value =
94
+ if commercial_rate_requested_or_rate_is_zero && commercial_rate_available
95
+ rate_node.at(COMMERCIAL_RATE_TAG)&.text&.to_d || rate_node.at(COMMERCIAL_PLUS_RATE_TAG).text.to_d
96
+ else
97
+ rate_node.at(RATE_TAG).text.to_d
98
+ end
92
99
 
93
100
  # The rate expressed as a RubyMoney objext
94
101
  rate = Money.new(rate_value * CURRENCY.subunit_to_unit, CURRENCY)
95
102
 
96
- # Which shipping method does this rate belong to? This is trickier than it sounds, because we match
97
- # strings here, and we have a `Priority Mail` and `Priority Mail Express` shipping method.
98
- # If we have multiple matches, we take the longest matching shipping method name so `Express` rates
99
- # do not accidentally get marked as `Priority` only.
100
- possible_shipping_methods = SHIPPING_METHODS.select do |sm|
101
- service_name.tr('-', ' ').upcase.starts_with?(sm.service_code)
102
- end.sort_by do |shipping_method|
103
- shipping_method.name.length
104
- end
105
- shipping_method = possible_shipping_methods.last
103
+ # Which shipping method does this rate belong to? We first try to match a rate to a shipping method
104
+ # by class ID (the CLASSID attribute in the USPS API rate response). Not every shipping method
105
+ # has a class ID defined, and a shipping method can have multiple class IDs (for example, Priority
106
+ # Express has different class IDs for standard, hold for pickup, and Sunday/Holiday delivery).
107
+ #
108
+ # If we don't find a match for class ID, we next try to match a rate to a shipping method using the
109
+ # shipping method's service code. The USPS API rate response includes a name for each rate in the
110
+ # MailService element. We match to see if the name starts with the given value. For example:
111
+ # `Priority Mail Express 2-day™`
112
+ #
113
+ shipping_method =
114
+ SHIPPING_METHODS.detect { |sm| sm.data[:class_ids]&.include?(service_code) } ||
115
+ SHIPPING_METHODS.detect { |sm| service_name.tr('-', ' ').upcase.starts_with?(sm.service_code) }
106
116
 
107
117
  # We find out the box name using a bit of Regex magic using named captures. See the `BOX_REGEX`
108
118
  # constant above.
@@ -115,7 +115,7 @@ module FriendlyShipping
115
115
  # This will likely be somewhat more work in the future.
116
116
  MAIL_CLASSES = {
117
117
  '1' => 'Priority Mail Express',
118
- '2' => 'Priority',
118
+ '2' => 'Priority Mail',
119
119
  '3' => 'First-Class',
120
120
  '6' => 'Package Services'
121
121
  }.freeze
@@ -49,11 +49,13 @@ module FriendlyShipping
49
49
  def service_code
50
50
  return 'ALL' unless shipping_method
51
51
 
52
- if commercial_pricing
53
- "#{shipping_method.service_code} COMMERCIAL"
54
- else
55
- shipping_method.service_code
56
- end
52
+ # Cubic shipping methods don't have HFP or COMMERCIAL modifiers
53
+ return shipping_method.service_code if shipping_method.service_code =~ /CUBIC/
54
+
55
+ service_code = [shipping_method.service_code]
56
+ service_code << 'HFP' if hold_for_pickup
57
+ service_code << 'COMMERCIAL' if commercial_pricing
58
+ service_code.join(' ')
57
59
  end
58
60
  end
59
61
  end
@@ -29,22 +29,33 @@ module FriendlyShipping
29
29
  package_service_retail: 'PACKAGE SERVICE RETAIL'
30
30
  }.freeze
31
31
 
32
+ CLASS_IDS = {
33
+ priority_mail_express: {
34
+ standard: '3',
35
+ hold_for_pickup: '2',
36
+ sunday_holiday_delivery: '23'
37
+ },
38
+ priority_mail_cubic: '999'
39
+ }.freeze
40
+
32
41
  SHIPPING_METHODS = [
33
- 'First-Class',
34
- 'Package Services',
35
- 'Priority',
36
- 'Priority Mail Express',
37
- 'Standard Post',
38
- 'Retail Ground',
39
- 'Media Mail',
40
- 'Library Mail',
41
- ].map do |shipping_method_name|
42
+ ['FIRST CLASS', 'First-Class'],
43
+ ['PACKAGE SERVICES', 'Package Services'],
44
+ ['PRIORITY', 'Priority Mail'],
45
+ ['PRIORITY MAIL EXPRESS', 'Priority Mail Express', CLASS_IDS[:priority_mail_express].values],
46
+ ['PRIORITY MAIL CUBIC', 'Priority Mail Cubic', CLASS_IDS[:priority_mail_cubic]],
47
+ ['STANDARD POST', 'Standard Post'],
48
+ ['RETAIL GROUND', 'Retail Ground'],
49
+ ['MEDIA MAIL', 'Media Mail'],
50
+ ['LIBRARY MAIL', 'Library Mail'],
51
+ ].map do |code, name, class_ids|
42
52
  FriendlyShipping::ShippingMethod.new(
43
53
  origin_countries: [Carmen::Country.coded('US')],
44
- name: shipping_method_name,
45
- service_code: shipping_method_name.tr('-', ' ').upcase,
54
+ name: name,
55
+ service_code: code,
46
56
  domestic: true,
47
- international: false
57
+ international: false,
58
+ data: { class_ids: class_ids }
48
59
  )
49
60
  end.freeze
50
61
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module FriendlyShipping
4
4
  class ShippingMethod
5
- attr_reader :name, :service_code, :carrier, :origin_countries
5
+ attr_reader :name, :service_code, :carrier, :origin_countries, :data
6
6
 
7
7
  # @param [String] name The shipping method's name
8
8
  # @param [String] service_code The shipping method's service code
@@ -11,6 +11,7 @@ module FriendlyShipping
11
11
  # @param [Boolean] multi_package Whether this is a multi-package shipping method
12
12
  # @param [FriendlyShipping::Carrier] carrier This shipping method's carrier
13
13
  # @param [Array] origin_countries Countries this shipping method ships from
14
+ # @param [Hash] data Additional carrier-specific data for this shipping method
14
15
  def initialize(
15
16
  name: nil,
16
17
  service_code: nil,
@@ -18,7 +19,8 @@ module FriendlyShipping
18
19
  international: nil,
19
20
  multi_package: nil,
20
21
  carrier: nil,
21
- origin_countries: []
22
+ origin_countries: [],
23
+ data: {}
22
24
  )
23
25
  @name = name
24
26
  @service_code = service_code
@@ -27,6 +29,7 @@ module FriendlyShipping
27
29
  @multi_package = multi_package
28
30
  @carrier = carrier
29
31
  @origin_countries = origin_countries
32
+ @data = data
30
33
  end
31
34
 
32
35
  def domestic?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FriendlyShipping
4
- VERSION = "0.5.3"
4
+ VERSION = "0.6.4"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: friendly_shipping
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.6.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Meyerhoff
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-11 00:00:00.000000000 Z
11
+ date: 2021-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: data_uri
@@ -166,16 +166,16 @@ dependencies:
166
166
  name: rake
167
167
  requirement: !ruby/object:Gem::Requirement
168
168
  requirements:
169
- - - "~>"
169
+ - - ">="
170
170
  - !ruby/object:Gem::Version
171
- version: '10.0'
171
+ version: 12.3.3
172
172
  type: :development
173
173
  prerelease: false
174
174
  version_requirements: !ruby/object:Gem::Requirement
175
175
  requirements:
176
- - - "~>"
176
+ - - ">="
177
177
  - !ruby/object:Gem::Version
178
- version: '10.0'
178
+ version: 12.3.3
179
179
  - !ruby/object:Gem::Dependency
180
180
  name: rspec
181
181
  requirement: !ruby/object:Gem::Requirement
@@ -275,6 +275,7 @@ extra_rdoc_files: []
275
275
  files:
276
276
  - ".circleci/config.yml"
277
277
  - ".env.template"
278
+ - ".github/dependabot.yml"
278
279
  - ".gitignore"
279
280
  - ".rspec"
280
281
  - ".rubocop-relaxed.yml"
@@ -392,11 +393,11 @@ files:
392
393
  - lib/friendly_shipping/timing.rb
393
394
  - lib/friendly_shipping/types.rb
394
395
  - lib/friendly_shipping/version.rb
395
- homepage: https://github.com/friendly_cart/friendly_shipping
396
+ homepage: https://github.com/friendlycart/friendly_shipping
396
397
  licenses:
397
398
  - MIT
398
399
  metadata: {}
399
- post_install_message:
400
+ post_install_message:
400
401
  rdoc_options: []
401
402
  require_paths:
402
403
  - lib
@@ -412,7 +413,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
412
413
  version: '0'
413
414
  requirements: []
414
415
  rubygems_version: 3.0.3
415
- signing_key:
416
+ signing_key:
416
417
  specification_version: 4
417
418
  summary: An integration layer for shipping services
418
419
  test_files: []