solidus_easypost 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +6 -0
  3. data/.github/stale.yml +4 -4
  4. data/.github_changelog_generator +2 -0
  5. data/.gitignore +1 -0
  6. data/.rubocop.yml +3 -0
  7. data/.rubocop_todo.yml +12 -47
  8. data/CHANGELOG.md +113 -0
  9. data/LICENSE +1 -1
  10. data/README.md +111 -21
  11. data/app/controllers/spree/admin/postage_labels_controller.rb +20 -0
  12. data/app/decorators/models/solidus_easypost/spree/carton_decorator.rb +38 -0
  13. data/app/decorators/models/solidus_easypost/spree/shipment_decorator.rb +18 -23
  14. data/app/models/solidus_easypost/parcel_dimension.rb +34 -0
  15. data/app/models/solidus_easypost/return_authorization.rb +2 -13
  16. data/app/overrides/spree/admin/orders/_shipment/add_postage_label.html.erb.deface +10 -0
  17. data/bin/rails +0 -1
  18. data/bin/rails-engine +0 -2
  19. data/bin/rails-sandbox +1 -2
  20. data/bin/sandbox +2 -0
  21. data/config/initializers/webhooks.rb +7 -0
  22. data/config/locales/en.yml +7 -4
  23. data/config/routes.rb +5 -1
  24. data/db/migrate/20201025110912_add_tracker_id_to_cartons.rb +6 -0
  25. data/lib/generators/solidus_easypost/install/install_generator.rb +7 -1
  26. data/lib/generators/solidus_easypost/install/templates/initializer.rb +26 -0
  27. data/lib/solidus_easypost/address_builder.rb +45 -0
  28. data/lib/solidus_easypost/calculator/base_dimension_calculator.rb +28 -0
  29. data/lib/solidus_easypost/calculator/weight_dimension_calculator.rb +22 -0
  30. data/lib/solidus_easypost/configuration.rb +25 -2
  31. data/lib/solidus_easypost/errors/unknown_partial_resource_error.rb +11 -0
  32. data/lib/solidus_easypost/estimator.rb +37 -0
  33. data/lib/solidus_easypost/parcel_builder.rb +27 -0
  34. data/lib/solidus_easypost/shipment_builder.rb +32 -0
  35. data/lib/solidus_easypost/shipping_method_selector.rb +17 -0
  36. data/lib/solidus_easypost/shipping_rate_calculator.rb +9 -0
  37. data/lib/solidus_easypost/testing_support/factories/address_factory.rb +10 -0
  38. data/lib/solidus_easypost/testing_support/factories/product_factory.rb +7 -0
  39. data/lib/solidus_easypost/testing_support/factories/shipment_factory.rb +30 -0
  40. data/lib/solidus_easypost/testing_support/factories/shipping_method_factory.rb +8 -0
  41. data/lib/solidus_easypost/testing_support/factories/stock_location_factory.rb +10 -0
  42. data/lib/solidus_easypost/testing_support/factories/variant_factory.rb +7 -0
  43. data/lib/solidus_easypost/testing_support/factories.rb +3 -0
  44. data/lib/solidus_easypost/tracker_webhook_handler.rb +14 -0
  45. data/lib/solidus_easypost/version.rb +1 -1
  46. data/lib/solidus_easypost.rb +11 -0
  47. data/solidus_easypost.gemspec +8 -5
  48. data/spec/cassettes/{Spree_Address/_easypost_address/is_an_EasyPost_Address_object.yml → address_builder/from_address.yml} +19 -23
  49. data/spec/cassettes/{Spree_StockLocation/_easypost_address/is_an_EasyPost_Address_object.yml → address_builder/from_stock_location.yml} +19 -23
  50. data/spec/cassettes/{Spree_Stock_Estimator/_shipping_rates/when_rates_are_found/when_shipping_methods_exist/when_shipping_methods_are_front_end_visible/has_the_correct_costs.yml → estimator.yml} +0 -0
  51. data/spec/cassettes/integration/checkout.yml +377 -0
  52. data/spec/cassettes/integration/order_shipping/with_purchase_labels.yml +373 -0
  53. data/spec/cassettes/integration/order_shipping/without_purchase_labels.yml +251 -0
  54. data/spec/cassettes/{Spree_Stock_Package/_easypost_parcel/is_an_EasyPost_Parcel_object.yml → parcel_builder/from_package.yml} +17 -22
  55. data/spec/cassettes/{Spree_Stock_Package/_easypost_parcel/has_the_correct_attributes.yml → parcel_builder/from_return_authorization.yml} +17 -22
  56. data/spec/cassettes/postage_labels/show.yml +72 -0
  57. data/spec/cassettes/return_authorization.yml +310 -0
  58. data/spec/cassettes/{Spree_Stock_Package/_easypost_shipment/is_an_EasyPost_Shipment_object.yml → shipment_builder/from_package.yml} +74 -92
  59. data/spec/cassettes/{Spree_Stock_Estimator/_shipping_rates/when_rates_are_found/when_shipping_methods_exist/create_no_new_shipping_methods.yml → shipment_builder/from_return_authorization.yml} +77 -95
  60. data/spec/cassettes/shipment_builder/from_shipment.yml +250 -0
  61. data/spec/controllers/spree/admin/postage_labels_controller_spec.rb +18 -0
  62. data/spec/features/admin/postage_labels_spec.rb +18 -0
  63. data/spec/integration/checkout_spec.rb +45 -0
  64. data/spec/integration/order_shipping_spec.rb +33 -0
  65. data/spec/models/solidus_easypost/parcel_dimension_spec.rb +80 -0
  66. data/spec/models/solidus_easypost/return_authorization_spec.rb +7 -40
  67. data/spec/models/spree/carton_spec.rb +57 -0
  68. data/spec/models/spree/shipment_spec.rb +48 -59
  69. data/spec/models/spree/shipping_rate_spec.rb +14 -7
  70. data/spec/solidus_easypost/address_builder_spec.rb +17 -0
  71. data/spec/solidus_easypost/calculator/weight_dimension_calculator_spec.rb +39 -0
  72. data/spec/solidus_easypost/estimator_spec.rb +52 -0
  73. data/spec/solidus_easypost/parcel_builder_spec.rb +113 -0
  74. data/spec/solidus_easypost/shipment_builder_spec.rb +28 -0
  75. data/spec/solidus_easypost/shipping_method_selector_spec.rb +33 -0
  76. data/spec/solidus_easypost/shipping_rate_calculator_spec.rb +12 -0
  77. data/spec/solidus_easypost/tracker_webhook_handler_spec.rb +58 -0
  78. data/spec/spec_helper.rb +11 -7
  79. data/spec/support/easypost.rb +3 -1
  80. data/spec/support/helpers/api_stubs.rb +40 -0
  81. data/spec/support/helpers/configuration.rb +28 -0
  82. data/spec/support/helpers/shipping_methods.rb +26 -0
  83. data/spec/support/solidus.rb +1 -0
  84. data/spec/support/vcr.rb +1 -0
  85. metadata +118 -85
  86. data/app/decorators/models/solidus_easypost/spree/address_decorator.rb +0 -30
  87. data/app/decorators/models/solidus_easypost/spree/stock/estimator_decorator.rb +0 -15
  88. data/app/decorators/models/solidus_easypost/spree/stock/package_decorator.rb +0 -27
  89. data/app/decorators/models/solidus_easypost/spree/stock_location_decorator.rb +0 -26
  90. data/app/models/solidus_easypost/estimator.rb +0 -51
  91. data/lib/solidus_easypost/factories.rb +0 -24
  92. data/spec/cassettes/SolidusEasypost_ReturnAuthorization/_easypost_shipment/is_an_EasyPost_Shipment_object.yml +0 -271
  93. data/spec/cassettes/SolidusEasypost_ReturnAuthorization/_return_label/has_the_correct_fields.yml +0 -336
  94. data/spec/cassettes/SolidusEasypost_ReturnAuthorization/_return_label/is_an_EasyPost_PackageLabel_object.yml +0 -336
  95. data/spec/cassettes/Spree_Address/_easypost_address/has_the_correct_attributes.yml +0 -69
  96. data/spec/cassettes/Spree_Order/_refresh_shipment_rates/can_get_rates_from_easy_post.yml +0 -271
  97. data/spec/cassettes/Spree_Order/_refresh_shipment_rates/create_shipping_methods_for_the_rates.yml +0 -269
  98. data/spec/cassettes/Spree_Shipment/_buys_a_shipping_rate_after_transitioning_to_ship.yml +0 -403
  99. data/spec/cassettes/Spree_Shipment/_easypost_shipment/when_it_is_a_new_shipment/behaves_like_an_easypost_shipment/is_an_EasyPost_Shipment_object.yml +0 -271
  100. data/spec/cassettes/Spree_Shipment/_easypost_shipment/when_it_is_a_new_shipment/calls_the_api.yml +0 -200
  101. data/spec/cassettes/Spree_Shipment/_easypost_shipment/when_it_is_an_existing_shipment/behaves_like_an_easypost_shipment/is_an_EasyPost_Shipment_object.yml +0 -334
  102. data/spec/cassettes/Spree_Shipment/_easypost_shipment/when_it_is_an_existing_shipment/loads_the_existing_shipment.yml +0 -271
  103. data/spec/cassettes/Spree_StockLocation/_easypost_address/has_the_correct_attributes.yml +0 -69
  104. data/spec/cassettes/Spree_Stock_Estimator/_shipping_rates/when_rates_are_found/when_shipping_methods_dont_exist/creates_new_shipping_methods.yml +0 -269
  105. data/spec/cassettes/Spree_Stock_Estimator/_shipping_rates/when_rates_are_found/when_shipping_methods_dont_exist/is_empty.yml +0 -269
  106. data/spec/cassettes/Spree_Stock_Estimator/_shipping_rates/when_rates_are_found/when_shipping_methods_exist/when_shipping_methods_are_front_end_visible/has_the_correct_names.yml +0 -269
  107. data/spec/cassettes/Spree_Stock_Estimator/_shipping_rates/when_rates_are_found/when_shipping_methods_exist/when_shipping_methods_are_not_front_end_visible/is_empty.yml +0 -269
  108. data/spec/cassettes/Spree_Stock_Package/_easypost_shipment/calls_the_api.yml +0 -200
  109. data/spec/factories/spree_modification.rb +0 -25
  110. data/spec/models/spree/address_spec.rb +0 -31
  111. data/spec/models/spree/order_spec.rb +0 -31
  112. data/spec/models/spree/stock/estimator_spec.rb +0 -80
  113. data/spec/models/spree/stock/package_spec.rb +0 -35
  114. data/spec/models/spree/stock_location_spec.rb +0 -31
  115. data/spec/support/shipping_method_helpers.rb +0 -43
@@ -0,0 +1,10 @@
1
+ <!-- insert_bottom '[data-hook="stock-contents"] tbody' -->
2
+
3
+ <% if shipment.selected_easy_post_rate_id && shipment.shipped? %>
4
+ <tr class="postage-label">
5
+ <td colspan="5">
6
+ <strong><%= t('spree.postage_label') %>:</strong>
7
+ <%= link_to_with_icon('external-link', t('spree.open_postage_label'), admin_shipment_postage_label_path(shipment)) %>
8
+ </td>
9
+ </tr>
10
+ <% end %>
data/bin/rails CHANGED
@@ -1,5 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
2
 
4
3
  if %w[g generate].include? ARGV.first
5
4
  exec "#{__dir__}/rails-engine", *ARGV
data/bin/rails-engine CHANGED
@@ -1,6 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
2
  # This command will automatically be run when you run "rails" with Rails gems
5
3
  # installed from the root of your application.
6
4
 
data/bin/rails-sandbox CHANGED
@@ -1,12 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
2
 
4
3
  app_root = 'sandbox'
5
4
 
6
5
  unless File.exist? "#{app_root}/bin/rails"
7
6
  warn 'Creating the sandbox app...'
8
7
  Dir.chdir "#{__dir__}/.." do
9
- system "#{__dir__}/sandbox" or begin # rubocop:disable Style/AndOr
8
+ system "#{__dir__}/sandbox" or begin
10
9
  warn 'Automatic creation of the sandbox app failed'
11
10
  exit 1
12
11
  end
data/bin/sandbox CHANGED
@@ -72,9 +72,11 @@ unbundled bundle exec rails generate spree:install \
72
72
  --user_class=Spree::User \
73
73
  --enforce_available_locales=true \
74
74
  --with-authentication=false \
75
+ --payment-method=none \
75
76
  $@
76
77
 
77
78
  unbundled bundle exec rails generate solidus:auth:install
79
+ unbundled bundle exec rails generate ${extension_name}:install
78
80
 
79
81
  echo
80
82
  echo "🚀 Sandbox app successfully created for $extension_name!"
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(SolidusWebhooks)
4
+ SolidusWebhooks.config.register_webhook_handler :easypost_trackers, ->(payload) do
5
+ SolidusEasypost.configuration.webhook_handler_class.call(payload)
6
+ end
7
+ end
@@ -1,5 +1,8 @@
1
- # Sample localization file for English. Add more files in this directory for other locales.
2
- # See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3
-
4
1
  en:
5
- hello: Hello world
2
+ spree:
3
+ postage_label: 'Postage Label'
4
+ open_postage_label: 'Open'
5
+ admin:
6
+ postage_labels:
7
+ show:
8
+ no_postage_label: 'No postage label available for shipment %{shipment_number}.'
data/config/routes.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Spree::Core::Engine.routes.draw do
4
- # Add your extension routes here
4
+ namespace :admin do
5
+ resources :shipments, only: [] do
6
+ resource :postage_label, only: :show
7
+ end
8
+ end
5
9
  end
@@ -0,0 +1,6 @@
1
+ class AddTrackerIdToCartons < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :spree_cartons, :easy_post_tracker_id, :string
4
+ add_index :spree_cartons, :easy_post_tracker_id
5
+ end
6
+ end
@@ -3,14 +3,20 @@
3
3
  module SolidusEasypost
4
4
  module Generators
5
5
  class InstallGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('templates', __dir__)
7
+
6
8
  class_option :auto_run_migrations, type: :boolean, default: false
7
9
 
10
+ def copy_initializer
11
+ template 'initializer.rb', 'config/initializers/solidus_easypost.rb'
12
+ end
13
+
8
14
  def add_migrations
9
15
  run 'bin/rails railties:install:migrations FROM=solidus_easypost'
10
16
  end
11
17
 
12
18
  def run_migrations
13
- run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]')) # rubocop:disable Metrics/LineLength
19
+ run_migrations = options[:auto_run_migrations] || ['', 'y', 'Y'].include?(ask('Would you like to run the migrations now? [Y/n]'))
14
20
  if run_migrations
15
21
  run 'bin/rails db:migrate'
16
22
  else
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ EasyPost.api_key = 'YOUR_API_KEY_HERE'
4
+
5
+ SolidusEasypost.configure do |config|
6
+ # Purchase labels from EasyPost when shipping shipments in Solidus?
7
+ # config.purchase_labels = true
8
+
9
+ # Create a tracker in EasyPost and receive webhooks for all cartons?
10
+ # config.track_all_cartons = false
11
+
12
+ # A class that responds to `#compute`, accepting an `EasyPost::Rate`
13
+ # instance and returning the cost for that rate.
14
+ # config.shipping_rate_calculator_class = 'SolidusEasypost::ShippingRateCalculator'
15
+
16
+ # A class that responds to `#shipping_method_for`, accepting an
17
+ # `EasyPost::Rate` instance and returning the shipping method for
18
+ # that rate.
19
+ # config.shipping_method_selector_class = 'SolidusEasypost::ShippingMethodSelector'
20
+
21
+ # A class that responds to '#compute', accepting a `SolidusEasypost::ReturnAuthorization`
22
+ # instance or a `Spree::Stock::Package` instance and returing the `SolidusEasypost::ParcelDimension` object.
23
+ # The `SolidusEasypost::Calculator::BaseDimensionCalculator` class can be extended to have a common
24
+ # functionality.
25
+ # config.parcel_dimension_calculator_class = 'SolidusEasypost::Calculator::WeightDimensionCalculator'
26
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusEasypost
4
+ class AddressBuilder
5
+ class << self
6
+ def from_address(address)
7
+ attributes = {
8
+ street1: address.address1,
9
+ street2: address.address2,
10
+ city: address.city,
11
+ zip: address.zipcode,
12
+ phone: address.phone
13
+ }
14
+
15
+ attributes[:company] = address.company if address.respond_to?(:company)
16
+ attributes[:name] = if address.respond_to?(:name)
17
+ address.name
18
+ elsif respond_to?(:full_name)
19
+ address.full_name
20
+ end
21
+ attributes[:state] = address.state ? address.state.abbr : address.state_name
22
+ attributes[:country] = address.country&.iso
23
+
24
+ ::EasyPost::Address.create attributes
25
+ end
26
+
27
+ def from_stock_location(stock_location)
28
+ attributes = {
29
+ street1: stock_location.address1,
30
+ street2: stock_location.address2,
31
+ city: stock_location.city,
32
+ zip: stock_location.zipcode,
33
+ phone: stock_location.phone,
34
+ name: stock_location.name,
35
+ company: stock_location.name
36
+ }
37
+
38
+ attributes[:state] = stock_location.state ? stock_location.state.abbr : stock_location.state_name
39
+ attributes[:country] = stock_location.country&.iso
40
+
41
+ ::EasyPost::Address.create attributes
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusEasypost
4
+ module Calculator
5
+ class BaseDimensionCalculator
6
+ def compute(resource)
7
+ case resource
8
+ when ::SolidusEasypost::ReturnAuthorization
9
+ compute_for_return_authorization(resource)
10
+ when ::Spree::Stock::Package
11
+ compute_for_package(resource)
12
+ else
13
+ raise SolidusEasypost::Errors::UnknownPartialResourceError
14
+ end
15
+ end
16
+
17
+ protected
18
+
19
+ def compute_for_return_authorization(return_authorization)
20
+ raise NotImplementedError
21
+ end
22
+
23
+ def compute_for_package(package)
24
+ raise NotImplementedError
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusEasypost
4
+ module Calculator
5
+ class WeightDimensionCalculator < BaseDimensionCalculator
6
+ protected
7
+
8
+ def compute_for_return_authorization(return_authorization)
9
+ total_weight = return_authorization.inventory_units.joins(:variant).sum(:weight)
10
+ SolidusEasypost::ParcelDimension.new(weight: total_weight)
11
+ end
12
+
13
+ def compute_for_package(package)
14
+ total_weight = package.contents.sum do |item|
15
+ item.quantity * item.variant.weight
16
+ end
17
+
18
+ SolidusEasypost::ParcelDimension.new(weight: total_weight)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -2,10 +2,33 @@
2
2
 
3
3
  module SolidusEasypost
4
4
  class Configuration
5
- attr_reader :purchase_labels
5
+ attr_accessor :purchase_labels, :track_all_cartons
6
+ attr_writer :shipping_rate_calculator_class, :shipping_method_selector_class, :parcel_dimension_calculator_class,
7
+ :webhook_handler_class
6
8
 
7
9
  def initialize
8
- @purchase_labels = true
10
+ self.purchase_labels = true
11
+ self.track_all_cartons = false
12
+ end
13
+
14
+ def shipping_rate_calculator_class
15
+ @shipping_rate_calculator_class ||= 'SolidusEasypost::ShippingRateCalculator'
16
+ @shipping_rate_calculator_class.constantize
17
+ end
18
+
19
+ def shipping_method_selector_class
20
+ @shipping_method_selector_class ||= 'SolidusEasypost::ShippingMethodSelector'
21
+ @shipping_method_selector_class.constantize
22
+ end
23
+
24
+ def parcel_dimension_calculator_class
25
+ @parcel_dimension_calculator_class ||= 'SolidusEasypost::Calculator::WeightDimensionCalculator'
26
+ @parcel_dimension_calculator_class.constantize
27
+ end
28
+
29
+ def webhook_handler_class
30
+ @webhook_handler_class ||= 'SolidusEasypost::TrackerWebhookHandler'
31
+ @webhook_handler_class.constantize
9
32
  end
10
33
  end
11
34
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusEasypost
4
+ module Errors
5
+ class UnknownPartialResourceError < StandardError
6
+ def message
7
+ 'The passed resource must be a Spree::ReturnAuthorization or a Spree::Stock::Package!'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusEasypost
4
+ class Estimator
5
+ def shipping_rates(package, _frontend_only = true)
6
+ easypost_rates = ShipmentBuilder.from_package(package).rates.sort_by(&:rate)
7
+
8
+ shipping_rates = easypost_rates.map { |rate| build_shipping_rate(rate) }.compact
9
+ shipping_rates.min_by(&:cost)&.selected = true
10
+
11
+ shipping_rates
12
+ end
13
+
14
+ private
15
+
16
+ def build_shipping_rate(rate)
17
+ shipping_method = shipping_method_selector.shipping_method_for(rate)
18
+ return unless shipping_method.available_to_users?
19
+
20
+ ::Spree::ShippingRate.new(
21
+ name: "#{rate.carrier} #{rate.service}",
22
+ cost: shipping_rate_calculator.compute(rate),
23
+ easy_post_shipment_id: rate.shipment_id,
24
+ easy_post_rate_id: rate.id,
25
+ shipping_method: shipping_method,
26
+ )
27
+ end
28
+
29
+ def shipping_rate_calculator
30
+ @shipping_rate_calculator ||= SolidusEasypost.configuration.shipping_rate_calculator_class.new
31
+ end
32
+
33
+ def shipping_method_selector
34
+ @shipping_method_selector ||= SolidusEasypost.configuration.shipping_method_selector_class.new
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusEasypost
4
+ class ParcelBuilder
5
+ class << self
6
+ def from_package(package)
7
+ parcel_dimension = SolidusEasypost
8
+ .configuration
9
+ .parcel_dimension_calculator_class
10
+ .new
11
+ .compute(package)
12
+
13
+ ::EasyPost::Parcel.create(parcel_dimension.to_h)
14
+ end
15
+
16
+ def from_return_authorization(return_authorization)
17
+ parcel_dimension = SolidusEasypost
18
+ .configuration
19
+ .parcel_dimension_calculator_class
20
+ .new
21
+ .compute(return_authorization)
22
+
23
+ ::EasyPost::Parcel.create(parcel_dimension.to_h)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusEasypost
4
+ class ShipmentBuilder
5
+ class << self
6
+ def from_package(package)
7
+ ::EasyPost::Shipment.create(
8
+ to_address: AddressBuilder.from_address(package.order.ship_address),
9
+ from_address: AddressBuilder.from_stock_location(package.stock_location),
10
+ parcel: ParcelBuilder.from_package(package),
11
+ )
12
+ end
13
+
14
+ def from_shipment(shipment)
15
+ ::EasyPost::Shipment.create(
16
+ to_address: AddressBuilder.from_address(shipment.order.ship_address),
17
+ from_address: AddressBuilder.from_stock_location(shipment.stock_location),
18
+ parcel: ParcelBuilder.from_package(shipment.to_package),
19
+ )
20
+ end
21
+
22
+ def from_return_authorization(return_authorization)
23
+ ::EasyPost::Shipment.create(
24
+ from_address: AddressBuilder.from_stock_location(return_authorization.stock_location),
25
+ to_address: AddressBuilder.from_address(return_authorization.order.ship_address),
26
+ parcel: ParcelBuilder.from_return_authorization(return_authorization),
27
+ is_return: true
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusEasypost
4
+ class ShippingMethodSelector
5
+ def shipping_method_for(rate)
6
+ ::Spree::ShippingMethod.find_or_create_by(
7
+ carrier: rate.carrier,
8
+ service_level: rate.service,
9
+ ) do |shipping_method|
10
+ shipping_method.name = "#{rate.carrier} #{rate.service}"
11
+ shipping_method.calculator = ::Spree::Calculator::Shipping::FlatRate.create
12
+ shipping_method.shipping_categories = [::Spree::ShippingCategory.first]
13
+ shipping_method.available_to_users = false
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusEasypost
4
+ class ShippingRateCalculator
5
+ def compute(rate)
6
+ rate.rate
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.modify do
4
+ factory :address do
5
+ address1 { '215 N 7th Ave' }
6
+ city { 'Manville' }
7
+ association(:state, name: 'New Jersey', abbr: 'NJ')
8
+ zipcode { '08835' }
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.modify do
4
+ factory :base_product do
5
+ weight { 10.0 }
6
+ end
7
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.modify do
4
+ factory :shipment do
5
+ transient do
6
+ inventory_units { 1 }
7
+ end
8
+
9
+ after(:create) do |shipment, e|
10
+ create_list(:inventory_unit, e.inventory_units, shipment: shipment)
11
+ end
12
+
13
+ trait :with_easypost do
14
+ transient do
15
+ easypost_shipment_id { 'sh_test' }
16
+ easypost_rate_id { 'rt_test' }
17
+ end
18
+
19
+ after(:create) do |shipment, evaluator|
20
+ create(
21
+ :shipping_rate,
22
+ shipment: shipment,
23
+ selected: true,
24
+ easy_post_shipment_id: evaluator.easypost_shipment_id,
25
+ easy_post_rate_id: evaluator.easypost_rate_id,
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.modify do
4
+ factory :shipping_method do
5
+ admin_name { 'Stuff' }
6
+ available_to_users { true }
7
+ end
8
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.modify do
4
+ factory :stock_location do
5
+ address1 { '131 S 8th Ave' }
6
+ city { 'Manville' }
7
+ association(:state, name: 'New Jersey', abbr: 'NJ')
8
+ zipcode { '08835' }
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ FactoryBot.modify do
4
+ factory :variant do
5
+ weight { 10.0 }
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir["#{__dir__}/factories/**/*.rb"].sort.each { |f| require f }
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusEasypost
4
+ class TrackerWebhookHandler
5
+ def self.call(payload)
6
+ return unless payload['description'] == 'tracker.updated'
7
+
8
+ carton = ::Spree::Carton.find_by(easy_post_tracker_id: payload['result']['id'])
9
+ return unless carton
10
+
11
+ ::Spree::Event.fire 'solidus_easypost.tracker.updated', carton: carton, payload: payload
12
+ end
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusEasypost
4
- VERSION = '2.0.0'
4
+ VERSION = '3.0.0'
5
5
  end
@@ -2,11 +2,22 @@
2
2
 
3
3
  require 'solidus_core'
4
4
  require 'solidus_support'
5
+ require 'deface'
5
6
  require 'easypost'
6
7
 
7
8
  require 'solidus_easypost/version'
8
9
  require 'solidus_easypost/engine'
9
10
  require 'solidus_easypost/configuration'
11
+ require 'solidus_easypost/address_builder'
12
+ require 'solidus_easypost/parcel_builder'
13
+ require 'solidus_easypost/shipment_builder'
14
+ require 'solidus_easypost/estimator'
15
+ require 'solidus_easypost/shipping_rate_calculator'
16
+ require 'solidus_easypost/shipping_method_selector'
17
+ require 'solidus_easypost/calculator/base_dimension_calculator'
18
+ require 'solidus_easypost/calculator/weight_dimension_calculator'
19
+ require 'solidus_easypost/tracker_webhook_handler'
20
+ require 'solidus_easypost/errors/unknown_partial_resource_error'
10
21
 
11
22
  module SolidusEasypost
12
23
  class << self
@@ -8,15 +8,14 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ['Brendan Deere']
9
9
  spec.email = 'brendan@stembolt.com'
10
10
 
11
- spec.summary = 'Easy post integration for Solidus'
12
- spec.description = 'Easy post integration for Solidus'
11
+ spec.summary = 'EasyPost integration for Solidus stores.'
13
12
  spec.homepage = 'https://github.com/solidusio-contrib/solidus_easypost'
14
13
  spec.license = 'BSD-3-Clause'
15
14
 
16
15
  spec.metadata['homepage_uri'] = spec.homepage
17
16
  spec.metadata['source_code_uri'] = 'https://github.com/solidusio-contrib/solidus_easypost'
18
17
 
19
- spec.required_ruby_version = Gem::Requirement.new('~> 2.5')
18
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5')
20
19
 
21
20
  # Specify which files should be added to the gem when it is released.
22
21
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -28,11 +27,15 @@ Gem::Specification.new do |spec|
28
27
  spec.executables = files.grep(%r{^exe/}) { |f| File.basename(f) }
29
28
  spec.require_paths = ["lib"]
30
29
 
30
+ spec.add_dependency 'deface'
31
31
  spec.add_dependency 'easypost'
32
- spec.add_dependency 'solidus_core', ['>= 2.0.0', '< 3']
32
+ spec.add_dependency 'solidus_core', ['>= 2.0.0', '< 4']
33
33
  spec.add_dependency 'solidus_support', '~> 0.5'
34
34
 
35
- spec.add_development_dependency 'solidus_dev_support'
35
+ spec.add_development_dependency 'solidus_dev_support', '~> 2.1'
36
36
  spec.add_development_dependency 'vcr'
37
37
  spec.add_development_dependency 'webmock'
38
+ spec.metadata = {
39
+ 'rubygems_mfa_required' => 'true'
40
+ }
38
41
  end