Class: Delivery::Transitions::ToShippedHandler

Inherits:
BaseService
  • Object
show all
Includes:
AfterCommitEverywhere
Defined in:
app/services/delivery/transitions/to_shipped_handler.rb

Overview

Handles all business logic after a delivery transitions to the 'shipped' state.

This is an AFTER_TRANSITION handler - the delivery state has already been
saved as 'shipped'. These are post-processing tasks that should not prevent
the shipment from being recorded.

== Execution Order (sync steps run in-process, then event triggers async work)

  1. handle_serial_numbers - Link serials to line items and update counts [sync]
  2. set_shipped_date - Record when the shipment left the warehouse [sync]
  3. update_order_status - Notify order that a delivery shipped [sync]
  4. update_line_item_quantities - Update qty_shipped on line items [sync]
  5. reset_order_discount - Recalculate order totals after shipment [sync]
    ↳ MUST complete before invoicing; keeping sync preserves ordering guarantee.
  6. publish Events::DeliveryShipped (after_commit)
    → NotificationShippingTrackingHandler - Email customer with tracking info [async]
    → Delivery::InvoicingHandler - Enqueue invoice creation [async]

== Why After Transition?

These are all post-shipment housekeeping tasks. The shipment has physically
left the building - we're just updating records and notifying stakeholders.
If any of these fail, we don't want to "unship" the delivery.

== Why reset_order_discount stays synchronous

Invoicing must see correct discount totals. If reset ran as an async subscriber
alongside invoicing, a race condition would allow invoicing to snapshot stale
discount data. Keeping it synchronous in this handler guarantees ordering.

Examples:

Delivery::Transitions::ToShippedHandler.new(delivery).process

Instance Method Summary collapse

Constructor Details

#initialize(delivery) ⇒ ToShippedHandler

Returns a new instance of ToShippedHandler.



39
40
41
42
43
# File 'app/services/delivery/transitions/to_shipped_handler.rb', line 39

def initialize(delivery)
  super()
  @delivery = delivery
  @order = delivery.order
end

Instance Method Details

#processObject



45
46
47
48
49
50
51
52
53
54
# File 'app/services/delivery/transitions/to_shipped_handler.rb', line 45

def process
  logger.tagged("Delivery #{@delivery.id} ToShippedHandler") do
    handle_serial_numbers
    set_shipped_date
    update_order_status
    update_line_item_quantities
    reset_order_discount
    publish_delivery_shipped_event
  end
end