Class: SpreeSquare::OrderStatusMapper

Inherits:
Object
  • Object
show all
Defined in:
app/services/spree_square/order_status_mapper.rb

Overview

Applies a Square order/fulfillment status change to the mapped Spree order.

Deliberately does NOT gate on version being newer than what's recorded, despite that being the pattern used elsewhere in this extension (catalog/inventory sync). Verified directly: Square emits order.updated and order.fulfillment.updated for the same underlying mutation carrying the same version number — they're two views of one change, not a sequence. Gating on version meant whichever webhook's job happened to run first "claimed" that version, and the other was dropped as "stale" even though it carried different, necessary information (e.g. the fulfillment transition itself). That bug was caught by testing a real cancellation end-to-end, not by inspecting the code.

Safety against duplicate/out-of-order delivery instead comes from two places that don't have this problem: WebhookEvent's uniqueness on Square's own event_id (exact redelivery is a no-op before this class ever runs), and the state-guarded idempotent operations below (unless canceled?, if ready?) — applying the same transition twice, or an old one after a newer one already landed, does nothing either way.

Constant Summary collapse

FULFILLMENT_SHIP_STATES =
%w[COMPLETED].freeze
FULFILLMENT_LABEL_STATES =

PROPOSED/RESERVED/PREPARED: kitchen-visible progress with no Spree shipment-state equivalent ("food is cooking") — recorded as a friendly label on the mapping, not forced into shipment_state.

%w[PROPOSED RESERVED PREPARED].freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.callObject



30
# File 'app/services/spree_square/order_status_mapper.rb', line 30

def self.call(...) = new.call(...)

Instance Method Details

#call(square_order_id:, version:, order_state: nil, fulfillment_state: nil) ⇒ Object



32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'app/services/spree_square/order_status_mapper.rb', line 32

def call(square_order_id:, version:, order_state: nil, fulfillment_state: nil)
  mapping = SpreeSquare::OrderMapping.find_by(square_order_id: square_order_id)
  return unless mapping

  order = mapping.order

  apply_fulfillment_state(order, fulfillment_state) if fulfillment_state
  apply_order_state(order, order_state) if order_state

  # Recorded for visibility/debugging (admin page, M8) — informational
  # only, never gates whether this call's transitions above applied.
  mapping.update!(square_version: version, last_status: fulfillment_state || order_state || mapping.last_status)
end