Class: SpreeCmCommissioner::InventoryItems::MoveToLocked

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

Overview

Moves units between an inventory item's two pools. Positive locks (public -> locked), negative releases (locked -> public). One service for both directions because they are the same transfer, and splitting them would duplicate the guards.

success(inventory_item)
| failure(nil, :invalid_quantity | :inactive_inventory_item
           | :quantity_exceeds_lock | :no_sellable_quantity
           | :locked_units_on_hold)

This is the ONLY moment locking changes public availability. Once units sit in the locked pool, buying from it never touches quantity_available again.

Instance Method Summary collapse

Methods included from ServiceModuleThrowable

call!

Instance Method Details

#call(inventory_item:, quantity:, caller_source: nil) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'app/services/spree_cm_commissioner/inventory_items/move_to_locked.rb', line 19

def call(inventory_item:, quantity:, caller_source: nil)
  quantity = quantity.to_i
  return failure(nil, :invalid_quantity) if quantity.zero?

  # A past-dated item cannot be sold, so withholding from it protects nothing — and
  # CachedInventoryItemsBuilder deliberately skips its SET NX for inactive items, so the Redis
  # key could not be warmed and the adjustment would clamp the date to 0 for a year.
  return failure(nil, :inactive_inventory_item) unless inventory_item.active?

  outcome = nil

  # requires_new, not a bare with_lock: an ActiveRecord::Rollback raised in a nested transaction
  # is swallowed without rolling anything back, so a refused transfer would leave the row already
  # moved. The savepoint makes the rollback real wherever this is called from.
  inventory_item.transaction(requires_new: true) do
    inventory_item.lock!
    outcome = transfer!(inventory_item, quantity, caller_source)
    raise ActiveRecord::Rollback unless outcome == :moved
  end

  return failure(nil, outcome) unless outcome == :moved

  log(inventory_item, quantity, outcome)
  success(inventory_item)
end