mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
111 lines
3.3 KiB
Ruby
111 lines
3.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Spree
|
|
class OrderInventory
|
|
attr_accessor :order
|
|
|
|
def initialize(order)
|
|
@order = order
|
|
end
|
|
|
|
# Only verify inventory for completed orders (as orders in frontend checkout
|
|
# have inventory assigned via +order.create_proposed_shipment+) or when
|
|
# shipment is explicitly passed
|
|
#
|
|
# In case shipment is passed stock should only be adjusted
|
|
# if the order is completed. That is so because stock items
|
|
# are always unstocked when the order is completed through +shipment.finalize+
|
|
def verify(line_item, shipment = nil)
|
|
if order.completed? || shipment.present?
|
|
|
|
variant_units = inventory_units_for(line_item.variant)
|
|
|
|
if variant_units.size < line_item.quantity
|
|
quantity = line_item.quantity - variant_units.size
|
|
|
|
shipment ||= determine_target_shipment(line_item.variant)
|
|
add_to_shipment(shipment, line_item.variant, quantity)
|
|
elsif variant_units.size > line_item.quantity
|
|
remove(line_item, variant_units, shipment)
|
|
end
|
|
else
|
|
true
|
|
end
|
|
end
|
|
|
|
def inventory_units_for(variant)
|
|
units = order.shipments.collect{ |s| s.inventory_units.to_a }.flatten
|
|
units.group_by(&:variant_id)[variant.id] || []
|
|
end
|
|
|
|
private
|
|
|
|
def remove(line_item, variant_units, shipment = nil)
|
|
quantity = variant_units.size - line_item.quantity
|
|
|
|
if shipment.present?
|
|
remove_from_shipment(shipment, line_item.variant, quantity, line_item.restock_item)
|
|
else
|
|
order.shipments.each do |each_shipment|
|
|
break if quantity == 0
|
|
|
|
quantity -= remove_from_shipment(each_shipment,
|
|
line_item.variant,
|
|
quantity,
|
|
line_item.restock_item)
|
|
end
|
|
end
|
|
end
|
|
|
|
# Returns either one of the shipment:
|
|
#
|
|
# first unshipped that already includes this variant
|
|
def determine_target_shipment(variant)
|
|
target_shipment = order.shipments.detect do |shipment|
|
|
(shipment.ready? || shipment.pending?) && shipment.contains?(variant)
|
|
end
|
|
|
|
target_shipment || order.shipments.detect do |shipment|
|
|
shipment.ready? || shipment.pending?
|
|
end
|
|
end
|
|
|
|
def add_to_shipment(shipment, variant, quantity)
|
|
on_hand, back_order = variant.fill_status(quantity)
|
|
|
|
on_hand.times { shipment.set_up_inventory('on_hand', variant, order) }
|
|
back_order.times { shipment.set_up_inventory('backordered', variant, order) }
|
|
|
|
if order.completed?
|
|
variant.move(-quantity)
|
|
end
|
|
|
|
quantity
|
|
end
|
|
|
|
def remove_from_shipment(shipment, variant, quantity, restock_item)
|
|
return 0 if quantity == 0 || shipment.shipped?
|
|
|
|
shipment_units = shipment.inventory_units_for(variant).reject do |variant_unit|
|
|
variant_unit.state == 'shipped'
|
|
end.sort_by(&:state)
|
|
|
|
removed_quantity = 0
|
|
|
|
shipment_units.each do |inventory_unit|
|
|
break if removed_quantity == quantity
|
|
|
|
inventory_unit.destroy
|
|
removed_quantity += 1
|
|
end
|
|
shipment.destroy if shipment.inventory_units.reload.count == 0
|
|
|
|
if order.completed? && restock_item
|
|
variant.move(removed_quantity)
|
|
end
|
|
|
|
removed_quantity
|
|
end
|
|
end
|
|
end
|