Module: SpreeCmCommissioner::OrderHoldable

Extended by:
ActiveSupport::Concern
Defined in:
app/models/concerns/spree_cm_commissioner/order_holdable.rb

Instance Method Summary collapse

Instance Method Details

#hold_order_holdsObject

Called before transitioning to :address state. Acquires seat holds (if applicable) + inventory holds for the order.



37
38
39
40
41
42
43
# File 'app/models/concerns/spree_cm_commissioner/order_holdable.rb', line 37

def hold_order_holds
  result = SpreeCmCommissioner::OrderHolds::Hold.call(order: self)
  return true if result.success?

  errors.add(:holds, result.error.value[:message])
  false
end

#lock_order_holds_for_paymentObject

Called via PaymentDecorator#after_commit when a payment is created. Idempotent: skips if holds are already locked (payment_locked_at is set). On first call, ensures all active holds have at least 5 minutes remaining, transitions the inventory hold to :payment_locked, stamps payment_locked_at on both inventory hold and seat blocks, and resyncs order.hold_expires_at.



50
51
52
53
54
55
56
57
# File 'app/models/concerns/spree_cm_commissioner/order_holdable.rb', line 50

def lock_order_holds_for_payment
  return true unless should_manage_blocks? || should_hold_inventory?

  result = SpreeCmCommissioner::OrderHolds::LockForPayment.call(order: self)
  return true if result.success?

  false
end

#release_order_holds(reason: :user_canceled) ⇒ Object

Non-raising variant. OrderHolds::Release rescues internally and returns a failure result, so callers can guard on .success? instead of handling exceptions.



67
68
69
# File 'app/models/concerns/spree_cm_commissioner/order_holdable.rb', line 67

def release_order_holds(reason: :user_canceled)
  SpreeCmCommissioner::OrderHolds::Release.call(order: self, reason: reason)
end

#release_order_holds!(reason: :user_canceled) ⇒ Object

Releases all holds (seats + inventory) for the order. Raises on failure so the surrounding transaction rolls back.



61
62
63
# File 'app/models/concerns/spree_cm_commissioner/order_holdable.rb', line 61

def release_order_holds!(reason: :user_canceled)
  SpreeCmCommissioner::OrderHolds::Release.call!(order: self, reason: reason)
end

#reserve_order_holds!Object

Converts all holds to reserved/complete state on order completion. Raises on failure so the surrounding transaction rolls back.



73
74
75
# File 'app/models/concerns/spree_cm_commissioner/order_holdable.rb', line 73

def reserve_order_holds!
  SpreeCmCommissioner::OrderHolds::Reserve.call!(order: self)
end

#should_hold_inventory?Boolean

Returns:



29
30
31
32
33
# File 'app/models/concerns/spree_cm_commissioner/order_holdable.rb', line 29

def should_hold_inventory?
  return true if line_items.any?(&:should_hold_inventory?)

  false
end

#should_manage_blocks?Boolean

Returns:



25
26
27
# File 'app/models/concerns/spree_cm_commissioner/order_holdable.rb', line 25

def should_manage_blocks?
  preload_block_ids.any?
end

#validate_inventory_hold_before_completeObject

Called before transitioning to :complete. Blocks on ANY finalized hold, not just released — a converted? hold reaching this point (while the order itself is still short of :complete) can only mean an earlier completion attempt already decremented real stock and then failed for some unrelated reason before the order's own state committed to match. InventoryHolds::Convert treats re-hitting a converted hold as a safe no-op for its own callers, but that's a different contract than this guard's: silently letting the state machine "reprocess" here would still re-run the rest of unstock_inventory! (external-system calls, notifications, ...) for what is actually an inconsistent state, not a normal retry. Failing loudly forces that inconsistency to be looked at rather than auto-healed blind.

Halting here (returning false), the same way hold_order_holds halts :address, keeps this a normal order.errors response instead of an exception, and skips straight past the external-system/Redis work in unstock_inventory! that would otherwise run first only to be rolled back once InventoryHolds::Convert makes this same finalized? check again.



91
92
93
94
95
96
97
# File 'app/models/concerns/spree_cm_commissioner/order_holdable.rb', line 91

def validate_inventory_hold_before_complete
  return true if inventory_hold.nil?
  return true unless inventory_hold.finalized?

  errors.add(:holds, I18n.t('inventory_hold.convert.hold_expired'))
  false
end