Class: Spree::FulfilmentChanger

Inherits:
Object
  • Object
show all
Includes:
ActiveModel::Validations
Defined in:
app/models/spree/fulfilment_changer.rb

Overview

Service class to change fulfilment of inventory units of a particular variant to another shipment. The other shipment would typically have a different shipping method, stock location or delivery date, such that we actually change the planned fulfilment for the items in question.

Can be used to merge shipments by moving all items to another shipment, because this class will delete any empty original shipment.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(current_shipment:, desired_shipment:, variant:, quantity:) ⇒ FulfilmentChanger

Returns a new instance of FulfilmentChanger



23
24
25
26
27
28
29
30
# File 'app/models/spree/fulfilment_changer.rb', line 23

def initialize(current_shipment:, desired_shipment:, variant:, quantity:)
  @current_shipment = current_shipment
  @desired_shipment = desired_shipment
  @current_stock_location = current_shipment.stock_location
  @desired_stock_location = desired_shipment.stock_location
  @variant = variant
  @quantity = quantity
end

Instance Attribute Details

#current_shipmentSpree::Shipment

The shipment we transfer units from

Returns:



17
18
19
# File 'app/models/spree/fulfilment_changer.rb', line 17

def current_shipment
  @current_shipment
end

#current_stock_locationSpree::StockLocation

The stock location of the current shipment

Returns:



17
18
19
# File 'app/models/spree/fulfilment_changer.rb', line 17

def current_stock_location
  @current_stock_location
end

#desired_shipmentSpree::Shipment

The shipment we want to move units onto

Returns:



17
18
19
# File 'app/models/spree/fulfilment_changer.rb', line 17

def desired_shipment
  @desired_shipment
end

#desired_stock_locationSpree::StockLocation

The stock location of the desired shipment

Returns:



17
18
19
# File 'app/models/spree/fulfilment_changer.rb', line 17

def desired_stock_location
  @desired_stock_location
end

#quantityInteger

How many units we want to move

Returns:

  • (Integer)

    the current value of quantity



17
18
19
# File 'app/models/spree/fulfilment_changer.rb', line 17

def quantity
  @quantity
end

#variantSpree::Variant

We only move units that represent this variant

Returns:



17
18
19
# File 'app/models/spree/fulfilment_changer.rb', line 17

def variant
  @variant
end

Instance Method Details

#run!true, false

Performs the change of fulfilment

Returns:

  • (true, false)

    Whether the requested fulfilment change was successful



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'app/models/spree/fulfilment_changer.rb', line 40

def run!
  # Validations here are intended to catch all necessary prerequisites.
  # We return early so all checks have happened already.
  return false if invalid?
  desired_shipment.save! if desired_shipment.new_record?

  new_on_hand_quantity = [desired_shipment.stock_location.count_on_hand(variant), quantity].min

  ActiveRecord::Base.transaction do
    if handle_stock_counts?
      # We only run this query if we need it.
      current_on_hand_quantity = [current_shipment.inventory_units.on_hand.size, quantity].min

      # Restock things we will not fulfil from the current shipment anymore
      current_stock_location.restock(variant, current_on_hand_quantity, current_shipment)
      # Unstock what we will fulfil with the new shipment
      desired_stock_location.unstock(variant, new_on_hand_quantity, desired_shipment)
    end

    # These two statements are the heart of this class. We change the number
    # of inventory units requested from one shipment to the other.
    # We order by state, because `'backordered' < 'on_hand'`.
    current_shipment.
      inventory_units.
      where(variant: variant).
      order(state: :asc).
      limit(new_on_hand_quantity).
      update_all(shipment_id: desired_shipment.id, state: :on_hand)

    current_shipment.
      inventory_units.
      where(variant: variant).
      order(state: :asc).
      limit(quantity - new_on_hand_quantity).
      update_all(shipment_id: desired_shipment.id, state: :backordered)
  end

  # We modified the inventory units at the database level for speed reasons.
  # The downside of that is that we need to reload the associations.
  current_shipment.inventory_units.reload
  desired_shipment.inventory_units.reload

  # If the current shipment now has no inventory units left, we won't need it any longer.
  if current_shipment.inventory_units.length.zero?
    current_shipment.destroy!
  else
    # The current shipment has changed, so we need to make sure that shipping rates
    # have the correct amount.
    current_shipment.refresh_rates
  end

  # The desired shipment has also change, so we need to make sure shipping rates
  # are up-to-date, too.
  desired_shipment.refresh_rates

  true
end