diff --git a/app/models/spree/stock/availability_validator_decorator.rb b/app/models/spree/stock/availability_validator_decorator.rb new file mode 100644 index 0000000000..f0411881e7 --- /dev/null +++ b/app/models/spree/stock/availability_validator_decorator.rb @@ -0,0 +1,37 @@ +Spree::Stock::AvailabilityValidator.class_eval do + def validate(line_item) + quantity = adapt_line_item_quantity_to_inventory_units(line_item) + + validate_quantity(line_item, quantity) + end + + private + + # This is an adapted version of a fix to the inventory_units not being considered here. + # See #3090 for details. + # This can be removed after upgrading to Spree 2.4. + def adapt_line_item_quantity_to_inventory_units(line_item) + shipment = line_item_shipment(line_item) + return line_item.quantity unless shipment + + units = shipment.inventory_units_for(line_item.variant) + line_item.quantity - units.count + end + + def line_item_shipment(line_item) + return line_item.target_shipment if line_item.target_shipment + return line_item.order.shipments.first if line_item.order.present? && line_item.order.shipments.any? + end + + # This is the spree v2.0.4 implementation of validate + # But using the calculated quantity instead of the line_item.quantity. + def validate_quantity(line_item, quantity) + quantifier = Spree::Stock::Quantifier.new(line_item.variant_id) + return if quantifier.can_supply? quantity + + variant = line_item.variant + display_name = %Q{#{variant.name}} + display_name += %Q{ (#{variant.options_text})} unless variant.options_text.blank? + line_item.errors[:quantity] << Spree.t(:out_of_stock, :scope => :order_populator, :item => display_name.inspect) + end +end diff --git a/spec/features/admin/bulk_order_management_spec.rb b/spec/features/admin/bulk_order_management_spec.rb index e6a3423868..6cbdd615b2 100644 --- a/spec/features/admin/bulk_order_management_spec.rb +++ b/spec/features/admin/bulk_order_management_spec.rb @@ -139,11 +139,10 @@ feature %q{ end context "submitting data to the server" do - let!(:o1) { create(:order_with_distributor, state: 'complete', completed_at: Time.zone.now ) } - let!(:li1) { create(:line_item_with_shipment, order: o1, :quantity => 5 ) } + let!(:order) { create(:completed_order_with_fees) } before :each do - li1.variant.update_attributes(on_hand: 1, on_demand: false) + order.line_items.second.destroy # we keep only one line item for this test visit '/admin/orders/bulk_management' end @@ -162,13 +161,14 @@ feature %q{ context "when unacceptable data is sent to the server" do it "displays an update button which submits pending changes" do expect(page).to have_no_selector "#save-bar" - fill_in "quantity", :with => li1.variant.on_hand + li1.quantity + 10 + line_item = order.line_items.first + fill_in "quantity", :with => line_item.variant.on_hand + line_item.quantity + 10 expect(page).to have_selector "input[name='quantity'].ng-dirty" expect(page).to have_selector "#save-bar", text: "You have unsaved changes" click_button "Save Changes" expect(page).to have_selector "#save-bar", text: "Fields with red borders contain errors." expect(page).to have_selector "input[name='quantity'].ng-dirty.update-error" - expect(page).to have_content "exceeds available stock. Please ensure line items have a valid quantity." + expect(page).to have_content "is out of stock" end end end