From 9539dd4dc7124d435b408fa078e88a45c2739970 Mon Sep 17 00:00:00 2001 From: andrea longhi Date: Mon, 26 Feb 2024 16:19:43 +0100 Subject: [PATCH] Properly calculate inventory item quantities to be moved 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. --- core/app/models/spree/fulfilment_changer.rb | 41 ++++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/core/app/models/spree/fulfilment_changer.rb b/core/app/models/spree/fulfilment_changer.rb index 61a4234716f..1178c08f8e6 100644 --- a/core/app/models/spree/fulfilment_changer.rb +++ b/core/app/models/spree/fulfilment_changer.rb @@ -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 @@ -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 @@ -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 @@ -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)