Class: SpreeSquare::OrderStatusMapper
- Inherits:
-
Object
- Object
- SpreeSquare::OrderStatusMapper
- 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
.call ⇒ Object
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 |