Skip to content

Commit 1f0a28f

Browse files
authored
Merge pull request #6319 from solidusio/spaghetticode/fix-issue-5669
Keep backorders when splitting part of variant to new shipment with same SL
2 parents 3610f90 + 5663477 commit 1f0a28f

File tree

4 files changed

+210
-142
lines changed

4 files changed

+210
-142
lines changed

core/app/models/spree/fulfilment_changer.rb

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,9 @@ def run!
8686
# we can take from the desired location, we could end up with some items being backordered.
8787
def run_tracking_inventory
8888
# Retrieve how many on hand items we can take from desired stock location
89-
available_quantity = [desired_shipment.stock_location.count_on_hand(variant), default_on_hand_quantity].max
90-
89+
available_quantity = get_available_quantity
9190
new_on_hand_quantity = [available_quantity, quantity].min
91+
backordered_quantity = get_backordered_quantity(available_quantity, new_on_hand_quantity)
9292
unstock_quantity = desired_shipment.stock_location.backorderable?(variant) ? quantity : new_on_hand_quantity
9393

9494
ActiveRecord::Base.transaction do
@@ -105,19 +105,21 @@ def run_tracking_inventory
105105
# These two statements are the heart of this class. We change the number
106106
# of inventory units requested from one shipment to the other.
107107
# We order by state, because `'backordered' < 'on_hand'`.
108+
# We start to move the new actual backordered quantity, so the remaining
109+
# quantity can be set to on_hand state.
108110
current_shipment.
109111
inventory_units.
110112
where(variant:).
111113
order(state: :asc).
112-
limit(new_on_hand_quantity).
113-
update_all(shipment_id: desired_shipment.id, state: :on_hand)
114+
limit(backordered_quantity).
115+
update_all(shipment_id: desired_shipment.id, state: :backordered)
114116

115117
current_shipment.
116118
inventory_units.
117119
where(variant:).
118120
order(state: :asc).
119-
limit(quantity - new_on_hand_quantity).
120-
update_all(shipment_id: desired_shipment.id, state: :backordered)
121+
limit(quantity - backordered_quantity).
122+
update_all(shipment_id: desired_shipment.id, state: :on_hand)
121123
end
122124
end
123125

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

144-
def default_on_hand_quantity
146+
def get_available_quantity
147+
if current_stock_location != desired_stock_location
148+
desired_location_quantifier.positive_stock
149+
else
150+
sl_availability = current_location_quantifier.positive_stock
151+
shipment_availability = current_shipment.inventory_units.where(variant: variant).on_hand.count
152+
sl_availability + shipment_availability
153+
end
154+
end
155+
156+
def get_backordered_quantity(available_quantity, new_on_hand_quantity)
145157
if current_stock_location != desired_stock_location
146-
0
158+
quantity - new_on_hand_quantity
147159
else
148-
current_shipment.inventory_units.where(variant:).on_hand.count
160+
shipment_quantity = current_shipment.inventory_units.where(variant: variant).size
161+
shipment_quantity - available_quantity
149162
end
150163
end
151164

@@ -156,11 +169,19 @@ def current_shipment_not_already_shipped
156169
end
157170

158171
def enough_stock_at_desired_location
159-
unless Spree::Stock::Quantifier.new(variant, desired_stock_location).can_supply?(quantity)
172+
unless desired_location_quantifier.can_supply?(quantity)
160173
errors.add(:desired_shipment, :not_enough_stock_at_desired_location)
161174
end
162175
end
163176

177+
def desired_location_quantifier
178+
@desired_location_quantifier ||= Spree::Stock::Quantifier.new(variant, desired_stock_location)
179+
end
180+
181+
def current_location_quantifier
182+
@current_location_quantifier ||= Spree::Stock::Quantifier.new(variant, current_stock_location)
183+
end
184+
164185
def desired_shipment_different_from_current
165186
if desired_shipment.id == current_shipment.id
166187
errors.add(:desired_shipment, :can_not_transfer_within_same_shipment)

core/app/models/spree/stock/quantifier.rb

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,16 @@ class Quantifier
1111
# If unspecified it will check inventory in all available StockLocations
1212
def initialize(variant, stock_location_or_id = nil)
1313
@variant = variant
14-
@stock_items = variant.stock_items.select do |stock_item|
15-
if stock_location_or_id
16-
stock_item.stock_location == stock_location_or_id ||
17-
stock_item.stock_location_id == stock_location_or_id
18-
else
19-
stock_item.stock_location.active?
20-
end
21-
end
14+
@stock_location_or_id = stock_location_or_id
15+
@stock_items = variant_stock_items
2216
end
2317

2418
# Returns the total number of inventory units on hand for the variant.
2519
#
2620
# @return [Fixnum] number of inventory units on hand, or infinity if
2721
# inventory is not tracked on the variant.
2822
def total_on_hand
29-
if @variant.should_track_inventory?
23+
if variant.should_track_inventory?
3024
stock_items.sum(&:count_on_hand)
3125
else
3226
Float::INFINITY
@@ -48,6 +42,36 @@ def backorderable?
4842
def can_supply?(required)
4943
total_on_hand >= required || backorderable?
5044
end
45+
46+
def positive_stock
47+
return unless stock_location
48+
49+
on_hand = stock_location.count_on_hand(variant)
50+
on_hand.positive? ? on_hand : 0
51+
end
52+
53+
private
54+
55+
attr_reader :variant, :stock_location_or_id
56+
57+
def stock_location
58+
@stock_location ||= if stock_location_or_id.is_a?(Spree::StockLocation)
59+
stock_location_or_id
60+
else
61+
Spree::StockLocation.find_by(id: stock_location_or_id)
62+
end
63+
end
64+
65+
def variant_stock_items
66+
variant.stock_items.select do |stock_item|
67+
if stock_location_or_id
68+
stock_item.stock_location == stock_location_or_id ||
69+
stock_item.stock_location_id == stock_location_or_id
70+
else
71+
stock_item.stock_location.active?
72+
end
73+
end
74+
end
5175
end
5276
end
5377
end

0 commit comments

Comments
 (0)