From 08ec5720cdb71c39b18c7caf227fffd58d6cb66b Mon Sep 17 00:00:00 2001 From: Mayur Shah Date: Thu, 27 Mar 2025 15:08:04 +0530 Subject: [PATCH 1/4] Add states and columns to shipment for tracking Add new state inbound_ready, inbound_shipped and complete, which can be used to set based on webhooks of easypost. Add new columns to store tracker IDs of easypost shipments, which can be used to update state based on the webhooks. --- .../spree/shipment_decorator.rb | 31 +++++++++++++++++++ ...93651_add_easypost_tracker_to_shipments.rb | 6 ++++ 2 files changed, 37 insertions(+) create mode 100644 db/migrate/20250326093651_add_easypost_tracker_to_shipments.rb 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/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 From 37304accafc06e8fb8de9000768930730d47a70e Mon Sep 17 00:00:00 2001 From: Mayur Shah Date: Thu, 27 Mar 2025 15:11:16 +0530 Subject: [PATCH 2/4] Add webhooks for shipment states Add class for publish, recieve and susbcribe events for the tracking information from easypost webhooks, add a new handler which can be used to update shipment states based on the easypost tracking_info --- .../solidus_easypost/status_tracker.rb | 45 +++++++++++++++++++ config/initializers/webhooks.rb | 4 ++ lib/solidus_easypost.rb | 2 + lib/solidus_easypost/engine.rb | 2 + .../shipment_state_handler.rb | 19 ++++++++ 5 files changed, 72 insertions(+) create mode 100644 app/subscribers/solidus_easypost/status_tracker.rb create mode 100644 lib/solidus_easypost/shipment_state_handler.rb 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/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/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 From 5b72dceb5d73c8ad0cf0ab74cb137ae2bdafa411 Mon Sep 17 00:00:00 2001 From: Mayur Shah Date: Thu, 27 Mar 2025 15:13:53 +0530 Subject: [PATCH 3/4] Add translation for shipment_states Add missing translation for the new states introduced to shipment --- config/locales/en.yml | 4 ++++ 1 file changed, 4 insertions(+) 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' From 0ba68cec112619e7cfc644381af48a7e29133550 Mon Sep 17 00:00:00 2001 From: Mayur Shah Date: Thu, 27 Mar 2025 19:18:47 +0530 Subject: [PATCH 4/4] Add solidus webhook to sandbox --- bin/sandbox | 2 ++ 1 file changed, 2 insertions(+) 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