Class: Spree::Stock::Quantifier
- Inherits:
-
Object
- Object
- Spree::Stock::Quantifier
- Defined in:
- app/models/spree/stock/quantifier.rb
Instance Attribute Summary collapse
-
#excluded_order ⇒ Object
readonly
Returns the value of attribute excluded_order.
-
#stock_location ⇒ Object
readonly
Returns the value of attribute stock_location.
-
#variant ⇒ Object
readonly
Returns the value of attribute variant.
Class Method Summary collapse
-
.allocated_count_column? ⇒ Boolean
Memoized schema check so #available_stock doesn’t introspect the column list on every call.
Instance Method Summary collapse
-
#available_stock ⇒ Integer
Physical pool minus already-allocated units, summed across the variant’s active stock items.
-
#backorderable? ⇒ Boolean
Check if any of variant stock items is backorderable.
- #can_supply?(required = 1) ⇒ Boolean
-
#initialize(variant, stock_location = nil, excluded_order: nil) ⇒ Quantifier
constructor
A new instance of Quantifier.
-
#reserved_quantity ⇒ Integer
Units currently held by active checkout reservations on the location-filtered stock items.
- #stock_items ⇒ Object
-
#total_on_hand ⇒ Integer, BigDecimal
Units a customer can purchase right now: physical pool minus already-allocated units minus active checkout reservations.
Constructor Details
#initialize(variant, stock_location = nil, excluded_order: nil) ⇒ Quantifier
Returns a new instance of Quantifier.
10 11 12 13 14 |
# File 'app/models/spree/stock/quantifier.rb', line 10 def initialize(variant, stock_location = nil, excluded_order: nil) @variant = variant @stock_location = stock_location @excluded_order = excluded_order end |
Instance Attribute Details
#excluded_order ⇒ Object (readonly)
Returns the value of attribute excluded_order.
4 5 6 |
# File 'app/models/spree/stock/quantifier.rb', line 4 def excluded_order @excluded_order end |
#stock_location ⇒ Object (readonly)
Returns the value of attribute stock_location.
4 5 6 |
# File 'app/models/spree/stock/quantifier.rb', line 4 def stock_location @stock_location end |
#variant ⇒ Object (readonly)
Returns the value of attribute variant.
4 5 6 |
# File 'app/models/spree/stock/quantifier.rb', line 4 def variant @variant end |
Class Method Details
.allocated_count_column? ⇒ Boolean
Memoized schema check so #available_stock doesn’t introspect the column list on every call. Flips from false → true when 6.0 Typed Stock Movements adds the ‘allocated_count` column.
104 105 106 107 108 |
# File 'app/models/spree/stock/quantifier.rb', line 104 def self.allocated_count_column? return @allocated_count_column if defined?(@allocated_count_column) @allocated_count_column = Spree::StockItem.connection.column_exists?(:spree_stock_items, :allocated_count) end |
Instance Method Details
#available_stock ⇒ Integer
Physical pool minus already-allocated units, summed across the variant’s active stock items.
In Spree 5.5 Spree::StockItem#allocated_count is a Ruby shim that always returns 0, so this equals SUM(count_on_hand). In 6.0 (Typed Stock Movements) allocated_count becomes a real column and the SQL path subtracts it natively.
41 42 43 44 45 46 47 48 49 |
# File 'app/models/spree/stock/quantifier.rb', line 41 def available_stock if association_loaded? stock_items.sum(&:available_count) elsif self.class.allocated_count_column? stock_items.sum('count_on_hand - allocated_count') else stock_items.sum(:count_on_hand) end end |
#backorderable? ⇒ Boolean
Check if any of variant stock items is backorderable
87 88 89 |
# File 'app/models/spree/stock/quantifier.rb', line 87 def backorderable? @backorderable ||= stock_items.any?(&:backorderable) end |
#can_supply?(required = 1) ⇒ Boolean
91 92 93 |
# File 'app/models/spree/stock/quantifier.rb', line 91 def can_supply?(required = 1) variant.available? && (backorderable? || total_on_hand >= required) end |
#reserved_quantity ⇒ Integer
Units currently held by active checkout reservations on the location-filtered stock items. Returns 0 when stock reservations are globally disabled.
Reads through the same #stock_items collection as #available_stock so a per-location query (filtered by ‘stock_location`) only counts reservations that belong to those same stock items — otherwise a multi-location variant would subtract reservations from other warehouses.
When excluded_order is set, that order’s own reservations are left out of the count so an order’s own checkout hold doesn’t count against the availability of its own line items.
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'app/models/spree/stock/quantifier.rb', line 66 def reserved_quantity return @reserved_quantity if defined?(@reserved_quantity) return @reserved_quantity = 0 unless Spree::Config[:stock_reservations_enabled] return @reserved_quantity = 0 if stock_items.blank? excluded_order_id = excluded_order&.id @reserved_quantity = if reservations_preloaded? stock_items.sum do |si| reservations = si.active_stock_reservations reservations = reservations.reject { |r| r.order_id == excluded_order_id } if excluded_order_id reservations.sum(&:quantity) end else reservations = Spree::StockReservation.active.where(stock_item_id: stock_items.map(&:id)) reservations = reservations.where.not(order_id: excluded_order_id) if excluded_order_id reservations.sum(:quantity) end end |
#stock_items ⇒ Object
95 96 97 |
# File 'app/models/spree/stock/quantifier.rb', line 95 def stock_items @stock_items ||= scope_to_location(variant.stock_items) end |
#total_on_hand ⇒ Integer, BigDecimal
Units a customer can purchase right now: physical pool minus already-allocated units minus active checkout reservations. Clamped at zero so callers never see a negative count.
Returns BigDecimal::INFINITY when the variant does not track inventory (effectively unlimited supply).
24 25 26 27 28 29 30 |
# File 'app/models/spree/stock/quantifier.rb', line 24 def total_on_hand @total_on_hand ||= if variant.should_track_inventory? [available_stock - reserved_quantity, 0].max else BigDecimal::INFINITY end end |