Class: SpreeCmCommissioner::Seats::ApplyLocks

Inherits:
Object
  • Object
show all
Extended by:
SpreeCmCommissioner::ServiceModuleThrowable
Includes:
Spree::ServiceModule::Base
Defined in:
app/services/spree_cm_commissioner/seats/apply_locks.rb

Overview

Applies one operator submission of the "Lock Seats" drawer.

The submission is the DESIRED end state (which seats should be locked across the selected dates). This service diffs it against what is currently locked and calls LockBlocks / UnlockBlocks for the difference only. Diffing here rather than at submit time means it works from fresh data, not from a snapshot taken when the drawer was rendered.

Runs from AsyncOperationJob via AsyncOperations::SeatLock#process!, so progress is written to the operation as it goes and the admin panel can poll it. This service owns the operation's terminal state in BOTH directions -- it marks it done or failed and returns success either way, because a refused precondition is a deterministic answer, not a transient error worth a Sidekiq retry.

Instance Method Summary collapse

Methods included from SpreeCmCommissioner::ServiceModuleThrowable

call!

Instance Method Details

#call(operation:) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'app/services/spree_cm_commissioner/seats/apply_locks.rb', line 18

def call(operation:)
  operation.start!

  state = LockState.new(selections: parse_selections(operation.selections))
  desired = operation.block_ids.map(&:to_i)

  # UNLOCK BEFORE LOCK. InventoryItem validates quantity_available >= 0 and LockBlocks turns that
  # failure into a :no_sellable_quantity skip, so on a sold-out date an operator swapping seat 1A
  # for 1B would otherwise lose 1A and not gain 1B. Releasing first frees the quantity the lock
  # then consumes.
  error = apply(operation, state, :unlock, state.locked_block_ids - desired)
  error ||= apply(operation, state, :lock, desired - state.fully_locked_block_ids)

  error ? operation.fail!(error) : operation.finish!

  success(operation)
end