Class: Spree::OrderRouting::Strategy::Reducer

Inherits:
Object
  • Object
show all
Defined in:
app/models/spree/order_routing/strategy/reducer.rb

Overview

Walks rules in priority order and applies a “first non-tie wins” reducer.

For each rule:

1. Drop rankings where rank is nil (rule abstains for that location).
2. Find the location(s) with the lowest rank (best).
3. Unique winner -> return it.
4. Tie -> carry the tied set forward to the next rule.

Out of rules with ties: prefer the StockLocation marked default, then by id. Guarantees a winner whenever locations is non-empty.

Instance Method Summary collapse

Constructor Details

#initialize(rules, order:) ⇒ Reducer

Returns a new instance of Reducer.



17
18
19
20
# File 'app/models/spree/order_routing/strategy/reducer.rb', line 17

def initialize(rules, order:)
  @rules = rules
  @order = order
end

Instance Method Details

#pick(locations) ⇒ Spree::StockLocation?

Parameters:

Returns:



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'app/models/spree/order_routing/strategy/reducer.rb', line 24

def pick(locations)
  return nil if locations.empty?

  remaining = locations
  remaining_ids = remaining.map(&:id).to_set

  @rules.each do |rule|
    rankings = rule.rank(@order, remaining).select do |r|
      r.rank && remaining_ids.include?(r.location.id)
    end
    next if rankings.empty?

    min_rank = rankings.map(&:rank).min
    top = rankings.select { |r| r.rank == min_rank }.map(&:location)

    return top.first if top.size == 1

    remaining = top
    remaining_ids = top.map(&:id).to_set
  end

  remaining.min_by { |l| [l.default? ? 0 : 1, l.id] }
end

#rank_all(locations) ⇒ Array<Spree::StockLocation>

Returns every input location, ordered best-first by the same rule chain that drives #pick. Each successive location is the best of what remains — used by Strategy::Rules to fan out an allocation across multiple locations when no single location covers the cart.

Parameters:

Returns:



55
56
57
58
59
60
61
62
63
64
# File 'app/models/spree/order_routing/strategy/reducer.rb', line 55

def rank_all(locations)
  remaining = locations.dup
  ordered = []
  until remaining.empty?
    chosen = pick(remaining) or break
    ordered << chosen
    remaining = remaining.reject { |l| l.id == chosen.id }
  end
  ordered
end