Skip to content

Commit

Permalink
Properly calculate inventory item quantities to be moved
Browse files Browse the repository at this point in the history
The backordered quantity count should differ depending on whether
moving to the same or a different stock location. For this reason,
the way we calculate `available_quantity` changes as follows:

* when the stock location differs:
  the stock on hand at the new shipment stock location;
* when the stock location is the same:
  the sum of the stock on hand at the shipment stock location
  plus the number of on_hand inventory items from the shipment

The explicit `backordered_quantity` variable is introduced to track
the number of backordered items for the target shipment. The value
is calculated as follows:

* when the stock location differs:
  the quantity to be moved minus the positive available quantity at
  the stock location;
* when the stock location is the same:
  the shipment total quantity for the variant minus the positive
  available quantity at the stock location.

Also, we start the process by moving backordered items first to
to make sure no pending backordered item remains. If the backordered
count decreased, we're going to leave a few to be later moved and
transformed to on hand, while if the backordered count increased, we
are going to move also some previously on hand items.
  • Loading branch information
spaghetticode committed Mar 7, 2024
1 parent f135a4b commit 9539dd4
Showing 1 changed file with 31 additions and 10 deletions.
41 changes: 31 additions & 10 deletions core/app/models/spree/fulfilment_changer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ def run!
# we can take from the desired location, we could end up with some items being backordered.
def run_tracking_inventory
# Retrieve how many on hand items we can take from desired stock location
available_quantity = [desired_shipment.stock_location.count_on_hand(variant), default_on_hand_quantity].max

available_quantity = get_available_quantity
new_on_hand_quantity = [available_quantity, quantity].min
backordered_quantity = get_backordered_quantity(available_quantity, new_on_hand_quantity)
unstock_quantity = desired_shipment.stock_location.backorderable?(variant) ? quantity : new_on_hand_quantity

ActiveRecord::Base.transaction do
Expand All @@ -105,19 +105,21 @@ def run_tracking_inventory
# 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'`.
# We start to move the new actual backordered quantity, so the remaining
# quantity can be set to on_hand state.
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)
limit(backordered_quantity).
update_all(shipment_id: desired_shipment.id, state: :backordered)

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)
limit(quantity - backordered_quantity).
update_all(shipment_id: desired_shipment.id, state: :on_hand)
end
end

Expand All @@ -141,11 +143,22 @@ def handle_stock_counts?
current_shipment.order.completed? && current_stock_location != desired_stock_location
end

def default_on_hand_quantity
def get_available_quantity
if current_stock_location != desired_stock_location
desired_location_quantifier.positive_stock
else
sl_availability = current_location_quantifier.positive_stock
shipment_availability = current_shipment.inventory_units.where(variant: variant).on_hand.count
sl_availability + shipment_availability
end
end

def get_backordered_quantity(available_quantity, new_on_hand_quantity)
if current_stock_location != desired_stock_location
0
quantity - new_on_hand_quantity
else
current_shipment.inventory_units.where(variant: variant).on_hand.count
shipment_quantity = current_shipment.inventory_units.where(variant: variant).size
shipment_quantity - available_quantity
end
end

Expand All @@ -156,11 +169,19 @@ def current_shipment_not_already_shipped
end

def enough_stock_at_desired_location
unless Spree::Stock::Quantifier.new(variant, desired_stock_location).can_supply?(quantity)
unless desired_location_quantifier.can_supply?(quantity)
errors.add(:desired_shipment, :not_enough_stock_at_desired_location)
end
end

def desired_location_quantifier
@desired_location_quantifier ||= Spree::Stock::Quantifier.new(variant, desired_stock_location)
end

def current_location_quantifier
@current_location_quantifier ||= Spree::Stock::Quantifier.new(variant, current_stock_location)
end

def desired_shipment_different_from_current
if desired_shipment.id == current_shipment.id
errors.add(:desired_shipment, :can_not_transfer_within_same_shipment)
Expand Down

0 comments on commit 9539dd4

Please sign in to comment.