diff --git a/app/decorators/models/solidus_easypost/spree/shipment_decorator.rb b/app/decorators/models/solidus_easypost/spree/shipment_decorator.rb index f2d92a7..8f0ad15 100644 --- a/app/decorators/models/solidus_easypost/spree/shipment_decorator.rb +++ b/app/decorators/models/solidus_easypost/spree/shipment_decorator.rb @@ -26,6 +26,32 @@ def self.prepended(base) prefix: :selected, allow_nil: true, ) + + base.state_machine do + state :inbound_ready + state :inbound_shipped + state :complete + + event :ship do + transition from: [:ready, :canceled, :pending, :inbound_ready, :inbound_shipped], to: :shipped + end + + event :inbound_ready do + transition from: :pending, to: :inbound_ready + end + + event :inbound_ship do + transition from: :inbound_ready, to: :inbound_shipped + end + + event :pending do + transition from: :inbound_shipped, to: :pending + end + + event :complete do + transition from: [:shipped, :inbound_shipped], to: :complete + end + end end def easypost_shipment @@ -100,6 +126,9 @@ def generate_inbound_label end end ) + + update!(easy_post_inbound_tracker_id: purchased_shipment.tracker.id) + inbound_ready! if easy_post_inbound_tracker_id.present? rescue StandardError => e Rails.logger.error "Failed to generate inbound label or create pickup: #{e.message}" raise e @@ -123,6 +152,8 @@ def generate_return_label order.update!(admin_metadata: order.admin_metadata.merge( return_label_url: return_label.postage_label.label_url )) + + update!(easy_post_tracker_id: return_label.tracker.id) rescue StandardError => e Rails.logger.error "Failed to generate return label: #{e.message}" end diff --git a/app/subscribers/solidus_easypost/status_tracker.rb b/app/subscribers/solidus_easypost/status_tracker.rb new file mode 100644 index 0000000..9c526cd --- /dev/null +++ b/app/subscribers/solidus_easypost/status_tracker.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module SolidusEasypost + class StatusTracker + include Omnes::Subscriber + + handle :'solidus_easypost.shipment_tracker.updated', + with: :handle_shipment_tracker_updated + + def handle_shipment_tracker_updated(event) + shipment = event.payload[:shipment] + payload = event.payload[:payload] + tracker_id = payload[:result][:id] + status = payload[:result][:status] + + if shipment.easy_post_tracker_id == tracker_id + update_outbound_shipment_status(shipment, status) + elsif shipment.easy_post_inbound_tracker_id == tracker_id + update_inbound_shipment_status(shipment, status) + end + rescue StandardError => e + Rails.logger.error("Failed to update shipment status: #{e.message}") + end + + private + + def update_outbound_shipment_status(shipment, status) + case status + when 'in_transit' + shipment.ship! + end + end + + def update_inbound_shipment_status(shipment, status) + case status + when 'pre_transit', 'unknown' + shipment.inbound_ready! unless shipment.inbound_ready? + when 'in_transit', 'out_for_delivery' + shipment.inbound_ship! unless shipment.inbound_shipped? + when 'delivered' + shipment.pending! unless shipment.pending? + end + end + end +end diff --git a/bin/sandbox b/bin/sandbox index f60e8db..8976af2 100755 --- a/bin/sandbox +++ b/bin/sandbox @@ -66,6 +66,8 @@ unbundled bundle add solidus --github solidusio/solidus --branch "${BRANCH:-main unbundled bundle exec rake db:drop db:create unbundled bundle exec rails generate solidus:install --payment-method=none --auto-accept "$@" unbundled bundle add ${extension_name} --path '../' + +unbundled bundle add 'solidus_webhooks' unbundled bundle exec rails generate $extension_name:install --auto-run-migrations echo diff --git a/config/initializers/webhooks.rb b/config/initializers/webhooks.rb index 5373725..a48a728 100644 --- a/config/initializers/webhooks.rb +++ b/config/initializers/webhooks.rb @@ -4,4 +4,8 @@ SolidusWebhooks.config.register_webhook_handler :easypost_trackers, ->(payload) do SolidusEasypost.configuration.webhook_handler_class.call(payload) end + + SolidusWebhooks.config.register_webhook_handler :shipment_status_trackers, ->(payload) do + SolidusEasypost::ShipmentStateHandler.call(payload) + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 811b429..d6b76c8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,5 +1,9 @@ en: spree: + shipment_states: + inbound_shipped: 'Inbound Shipped' + inbound_ready: 'Inbound Ready' + complete: 'Complete' postage_label: 'Postage Label' download_shipping_label: 'Download your Shipping Label' open_postage_label: 'Open' diff --git a/db/migrate/20250326093651_add_easypost_tracker_to_shipments.rb b/db/migrate/20250326093651_add_easypost_tracker_to_shipments.rb new file mode 100644 index 0000000..f9c687b --- /dev/null +++ b/db/migrate/20250326093651_add_easypost_tracker_to_shipments.rb @@ -0,0 +1,6 @@ +class AddEasypostTrackerToShipments < ActiveRecord::Migration[7.2] + def change + add_column :spree_shipments, :easy_post_inbound_tracker_id, :string + add_column :spree_shipments, :easy_post_tracker_id, :string + end +end diff --git a/lib/solidus_easypost.rb b/lib/solidus_easypost.rb index 295e363..62fb2bc 100644 --- a/lib/solidus_easypost.rb +++ b/lib/solidus_easypost.rb @@ -17,6 +17,8 @@ require 'solidus_easypost/calculator/base_dimension_calculator' require 'solidus_easypost/calculator/weight_dimension_calculator' require 'solidus_easypost/tracker_webhook_handler' +require 'solidus_easypost/shipment_state_handler' + require 'solidus_easypost/errors/unknown_partial_resource_error' module SolidusEasypost diff --git a/lib/solidus_easypost/engine.rb b/lib/solidus_easypost/engine.rb index f7e41e4..8863bf8 100644 --- a/lib/solidus_easypost/engine.rb +++ b/lib/solidus_easypost/engine.rb @@ -20,6 +20,8 @@ class Engine < Rails::Engine unless SolidusSupport::LegacyEventCompat.using_legacy? app.reloader.to_prepare do ::Spree::Bus.register(:'solidus_easypost.tracker.updated') + ::Spree::Bus.register(:'solidus_easypost.shipment_tracker.updated') + SolidusEasypost::StatusTracker.new.subscribe_to(::Spree::Bus) end end end diff --git a/lib/solidus_easypost/shipment_state_handler.rb b/lib/solidus_easypost/shipment_state_handler.rb new file mode 100644 index 0000000..da4b95c --- /dev/null +++ b/lib/solidus_easypost/shipment_state_handler.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module SolidusEasypost + class ShipmentStateHandler + def self.call(payload) + return unless payload['description'] == 'tracker.updated' + + shipment = find_shipment_by_tracker_id(payload['result']['id']) + return unless shipment + + ::Spree::Bus.publish :'solidus_easypost.shipment_tracker.updated', shipment: shipment, payload: payload + end + + def self.find_shipment_by_tracker_id(tracker_id) + ::Spree::Shipment.find_by(easy_post_tracker_id: tracker_id) || + ::Spree::Shipment.find_by(easy_post_inbound_tracker_id: tracker_id) + end + end +end