mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-21 05:09:15 +00:00
Bring models related to Order from spree_core
EPIC COMMIT ALERT :-)
This commit is contained in:
85
spec/models/spree/inventory_unit_spec.rb
Normal file
85
spec/models/spree/inventory_unit_spec.rb
Normal file
@@ -0,0 +1,85 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::InventoryUnit do
|
||||
let(:stock_location) { create(:stock_location_with_items) }
|
||||
let(:stock_item) { stock_location.stock_items.order(:id).first }
|
||||
|
||||
context "#backordered_for_stock_item" do
|
||||
let(:order) { create(:order) }
|
||||
|
||||
let(:shipment) do
|
||||
shipment = Spree::Shipment.new
|
||||
shipment.stock_location = stock_location
|
||||
shipment.shipping_methods << create(:shipping_method)
|
||||
shipment.order = order
|
||||
# We don't care about this in this test
|
||||
shipment.stub(:ensure_correct_adjustment)
|
||||
shipment.tap(&:save!)
|
||||
end
|
||||
|
||||
let!(:unit) do
|
||||
unit = shipment.inventory_units.build
|
||||
unit.state = 'backordered'
|
||||
unit.variant_id = stock_item.variant.id
|
||||
unit.tap(&:save!)
|
||||
end
|
||||
|
||||
# Regression for #3066
|
||||
it "returns modifiable objects" do
|
||||
units = Spree::InventoryUnit.backordered_for_stock_item(stock_item)
|
||||
expect { units.first.save! }.to_not raise_error
|
||||
end
|
||||
|
||||
it "finds inventory units from its stock location when the unit's variant matches the stock item's variant" do
|
||||
Spree::InventoryUnit.backordered_for_stock_item(stock_item).should =~ [unit]
|
||||
end
|
||||
|
||||
it "does not find inventory units that aren't backordered" do
|
||||
on_hand_unit = shipment.inventory_units.build
|
||||
on_hand_unit.state = 'on_hand'
|
||||
on_hand_unit.variant_id = 1
|
||||
on_hand_unit.save!
|
||||
|
||||
Spree::InventoryUnit.backordered_for_stock_item(stock_item).should_not include(on_hand_unit)
|
||||
end
|
||||
|
||||
it "does not find inventory units that don't match the stock item's variant" do
|
||||
other_variant_unit = shipment.inventory_units.build
|
||||
other_variant_unit.state = 'backordered'
|
||||
other_variant_unit.variant = create(:variant)
|
||||
other_variant_unit.save!
|
||||
|
||||
Spree::InventoryUnit.backordered_for_stock_item(stock_item).should_not include(other_variant_unit)
|
||||
end
|
||||
end
|
||||
|
||||
context "variants deleted" do
|
||||
let!(:unit) do
|
||||
Spree::InventoryUnit.create(variant: stock_item.variant)
|
||||
end
|
||||
|
||||
it "can still fetch variant" do
|
||||
unit.variant.destroy
|
||||
expect(unit.reload.variant).to be_a Spree::Variant
|
||||
end
|
||||
|
||||
it "can still fetch variants by eager loading (remove default_scope)" do
|
||||
unit.variant.destroy
|
||||
expect(Spree::InventoryUnit.joins(:variant).includes(:variant).first.variant).to be_a Spree::Variant
|
||||
end
|
||||
end
|
||||
|
||||
context "#finalize_units!" do
|
||||
let!(:stock_location) { create(:stock_location) }
|
||||
let(:variant) { create(:variant) }
|
||||
let(:inventory_units) { [
|
||||
create(:inventory_unit, variant: variant),
|
||||
create(:inventory_unit, variant: variant)
|
||||
] }
|
||||
|
||||
it "should create a stock movement" do
|
||||
Spree::InventoryUnit.finalize_units!(inventory_units)
|
||||
inventory_units.any?(&:pending).should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,6 +2,143 @@ require 'spec_helper'
|
||||
|
||||
module Spree
|
||||
describe LineItem do
|
||||
let(:order) { create :order_with_line_items, line_items_count: 1 }
|
||||
let(:line_item) { order.line_items.first }
|
||||
|
||||
context '#save' do
|
||||
it 'should update inventory, totals, and tax' do
|
||||
# Regression check for Spree #1481
|
||||
line_item.order.should_receive(:create_tax_charge!)
|
||||
line_item.order.should_receive(:update!)
|
||||
line_item.quantity = 2
|
||||
line_item.save
|
||||
end
|
||||
end
|
||||
|
||||
context '#destroy' do
|
||||
# Regression test for Spree #1481
|
||||
it "applies tax adjustments" do
|
||||
line_item.order.should_receive(:create_tax_charge!)
|
||||
line_item.destroy
|
||||
end
|
||||
|
||||
it "fetches deleted products" do
|
||||
line_item.product.destroy
|
||||
expect(line_item.reload.product).to be_a Spree::Product
|
||||
end
|
||||
|
||||
it "fetches deleted variants" do
|
||||
line_item.variant.destroy
|
||||
expect(line_item.reload.variant).to be_a Spree::Variant
|
||||
end
|
||||
end
|
||||
|
||||
# Test for Spree #3391
|
||||
context '#copy_price' do
|
||||
it "copies over a variant's prices" do
|
||||
line_item.price = nil
|
||||
line_item.cost_price = nil
|
||||
line_item.currency = nil
|
||||
line_item.copy_price
|
||||
variant = line_item.variant
|
||||
line_item.price.should == variant.price
|
||||
line_item.cost_price.should == variant.cost_price
|
||||
line_item.currency.should == variant.currency
|
||||
end
|
||||
end
|
||||
|
||||
# Test for Spree #3481
|
||||
context '#copy_tax_category' do
|
||||
it "copies over a variant's tax category" do
|
||||
line_item.tax_category = nil
|
||||
line_item.copy_tax_category
|
||||
line_item.tax_category.should == line_item.variant.product.tax_category
|
||||
end
|
||||
end
|
||||
|
||||
describe '.currency' do
|
||||
it 'returns the globally configured currency' do
|
||||
line_item.currency == 'USD'
|
||||
end
|
||||
end
|
||||
|
||||
describe ".money" do
|
||||
before do
|
||||
line_item.price = 3.50
|
||||
line_item.quantity = 2
|
||||
end
|
||||
|
||||
it "returns a Spree::Money representing the total for this line item" do
|
||||
line_item.money.to_s.should == "$7.00"
|
||||
end
|
||||
end
|
||||
|
||||
describe '.single_money' do
|
||||
before { line_item.price = 3.50 }
|
||||
it "returns a Spree::Money representing the price for one variant" do
|
||||
line_item.single_money.to_s.should == "$3.50"
|
||||
end
|
||||
end
|
||||
|
||||
context "has inventory (completed order so items were already unstocked)" do
|
||||
let(:order) { Spree::Order.create }
|
||||
let(:variant) { create(:variant) }
|
||||
|
||||
context "nothing left on stock" do
|
||||
before do
|
||||
variant.stock_items.update_all count_on_hand: 5, backorderable: false
|
||||
order.contents.add(variant, 5)
|
||||
order.create_proposed_shipments
|
||||
order.finalize!
|
||||
end
|
||||
|
||||
it "allows to decrease item quantity" do
|
||||
line_item = order.line_items.first
|
||||
line_item.quantity -= 1
|
||||
line_item.target_shipment = order.shipments.first
|
||||
|
||||
line_item.save
|
||||
expect(line_item).to have(0).errors_on(:quantity)
|
||||
end
|
||||
|
||||
it "doesnt allow to increase item quantity" do
|
||||
line_item = order.line_items.first
|
||||
line_item.quantity += 2
|
||||
line_item.target_shipment = order.shipments.first
|
||||
|
||||
line_item.save
|
||||
expect(line_item).to have(1).errors_on(:quantity)
|
||||
end
|
||||
end
|
||||
|
||||
context "2 items left on stock" do
|
||||
before do
|
||||
variant.stock_items.update_all count_on_hand: 7, backorderable: false
|
||||
order.contents.add(variant, 5)
|
||||
order.create_proposed_shipments
|
||||
order.finalize!
|
||||
end
|
||||
|
||||
it "allows to increase quantity up to stock availability" do
|
||||
line_item = order.line_items.first
|
||||
line_item.quantity += 2
|
||||
line_item.target_shipment = order.shipments.first
|
||||
|
||||
line_item.save
|
||||
expect(line_item).to have(0).errors_on(:quantity)
|
||||
end
|
||||
|
||||
it "doesnt allow to increase quantity over stock availability" do
|
||||
line_item = order.line_items.first
|
||||
line_item.quantity += 3
|
||||
line_item.target_shipment = order.shipments.first
|
||||
|
||||
line_item.save
|
||||
expect(line_item).to have(1).errors_on(:quantity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "scopes" do
|
||||
let(:o) { create(:order) }
|
||||
|
||||
|
||||
50
spec/models/spree/order/address_spec.rb
Normal file
50
spec/models/spree/order/address_spec.rb
Normal file
@@ -0,0 +1,50 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Order do
|
||||
let(:order) { Spree::Order.new }
|
||||
|
||||
context 'validation' do
|
||||
context "when @use_billing is populated" do
|
||||
before do
|
||||
order.bill_address = stub_model(Spree::Address)
|
||||
order.ship_address = nil
|
||||
end
|
||||
|
||||
context "with true" do
|
||||
before { order.use_billing = true }
|
||||
|
||||
it "clones the bill address to the ship address" do
|
||||
order.valid?
|
||||
order.ship_address.should == order.bill_address
|
||||
end
|
||||
end
|
||||
|
||||
context "with 'true'" do
|
||||
before { order.use_billing = 'true' }
|
||||
|
||||
it "clones the bill address to the shipping" do
|
||||
order.valid?
|
||||
order.ship_address.should == order.bill_address
|
||||
end
|
||||
end
|
||||
|
||||
context "with '1'" do
|
||||
before { order.use_billing = '1' }
|
||||
|
||||
it "clones the bill address to the shipping" do
|
||||
order.valid?
|
||||
order.ship_address.should == order.bill_address
|
||||
end
|
||||
end
|
||||
|
||||
context "with something other than a 'truthful' value" do
|
||||
before { order.use_billing = '0' }
|
||||
|
||||
it "does not clone the bill address to the shipping" do
|
||||
order.valid?
|
||||
order.ship_address.should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
148
spec/models/spree/order/adjustments_spec.rb
Normal file
148
spec/models/spree/order/adjustments_spec.rb
Normal file
@@ -0,0 +1,148 @@
|
||||
require 'spec_helper'
|
||||
describe Spree::Order do
|
||||
let(:order) { Spree::Order.new }
|
||||
|
||||
context "clear_adjustments" do
|
||||
|
||||
let(:adjustment) { double("Adjustment") }
|
||||
|
||||
it "destroys all order adjustments" do
|
||||
order.stub(:adjustments => adjustment)
|
||||
adjustment.should_receive(:destroy_all)
|
||||
order.clear_adjustments!
|
||||
end
|
||||
|
||||
it "destroy all line item adjustments" do
|
||||
order.stub(:line_item_adjustments => adjustment)
|
||||
adjustment.should_receive(:destroy_all)
|
||||
order.clear_adjustments!
|
||||
end
|
||||
end
|
||||
|
||||
context "totaling adjustments" do
|
||||
let(:adjustment1) { mock_model(Spree::Adjustment, :amount => 5) }
|
||||
let(:adjustment2) { mock_model(Spree::Adjustment, :amount => 10) }
|
||||
|
||||
context "#ship_total" do
|
||||
it "should return the correct amount" do
|
||||
order.stub_chain :adjustments, :shipping => [adjustment1, adjustment2]
|
||||
order.ship_total.should == 15
|
||||
end
|
||||
end
|
||||
|
||||
context "#tax_total" do
|
||||
it "should return the correct amount" do
|
||||
order.stub_chain :adjustments, :tax => [adjustment1, adjustment2]
|
||||
order.tax_total.should == 15
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
context "line item adjustment totals" do
|
||||
before { @order = Spree::Order.create! }
|
||||
|
||||
|
||||
context "when there are no line item adjustments" do
|
||||
before { @order.stub_chain(:line_item_adjustments, :eligible => []) }
|
||||
|
||||
it "should return an empty hash" do
|
||||
@order.line_item_adjustment_totals.should == {}
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are two adjustments with different labels" do
|
||||
let(:adj1) { mock_model Spree::Adjustment, :amount => 10, :label => "Foo" }
|
||||
let(:adj2) { mock_model Spree::Adjustment, :amount => 20, :label => "Bar" }
|
||||
|
||||
before do
|
||||
@order.stub_chain(:line_item_adjustments, :eligible => [adj1, adj2])
|
||||
end
|
||||
|
||||
it "should return exactly two totals" do
|
||||
@order.line_item_adjustment_totals.size.should == 2
|
||||
end
|
||||
|
||||
it "should return the correct totals" do
|
||||
@order.line_item_adjustment_totals["Foo"].should == Spree::Money.new(10)
|
||||
@order.line_item_adjustment_totals["Bar"].should == Spree::Money.new(20)
|
||||
end
|
||||
end
|
||||
|
||||
context "when there are two adjustments with one label and a single adjustment with another" do
|
||||
let(:adj1) { mock_model Spree::Adjustment, :amount => 10, :label => "Foo" }
|
||||
let(:adj2) { mock_model Spree::Adjustment, :amount => 20, :label => "Bar" }
|
||||
let(:adj3) { mock_model Spree::Adjustment, :amount => 40, :label => "Bar" }
|
||||
|
||||
before do
|
||||
@order.stub_chain(:line_item_adjustments, :eligible => [adj1, adj2, adj3])
|
||||
end
|
||||
|
||||
it "should return exactly two totals" do
|
||||
@order.line_item_adjustment_totals.size.should == 2
|
||||
end
|
||||
it "should return the correct totals" do
|
||||
@order.line_item_adjustment_totals["Foo"].should == Spree::Money.new(10)
|
||||
@order.line_item_adjustment_totals["Bar"].should == Spree::Money.new(60)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "line item adjustments" do
|
||||
before do
|
||||
@order = Spree::Order.create!
|
||||
@order.stub :line_items => [line_item1, line_item2]
|
||||
end
|
||||
|
||||
let(:line_item1) { create(:line_item, :order => @order) }
|
||||
let(:line_item2) { create(:line_item, :order => @order) }
|
||||
|
||||
context "when there are no line item adjustments" do
|
||||
it "should return nothing if line items have no adjustments" do
|
||||
@order.line_item_adjustments.should be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context "when only one line item has adjustments" do
|
||||
before do
|
||||
@adj1 = line_item1.adjustments.create(
|
||||
:amount => 2,
|
||||
:source => line_item1,
|
||||
:label => "VAT 5%"
|
||||
)
|
||||
|
||||
@adj2 = line_item1.adjustments.create(
|
||||
:amount => 5,
|
||||
:source => line_item1,
|
||||
:label => "VAT 10%"
|
||||
)
|
||||
end
|
||||
|
||||
it "should return the adjustments for that line item" do
|
||||
@order.line_item_adjustments.should =~ [@adj1, @adj2]
|
||||
end
|
||||
end
|
||||
|
||||
context "when more than one line item has adjustments" do
|
||||
before do
|
||||
@adj1 = line_item1.adjustments.create(
|
||||
:amount => 2,
|
||||
:source => line_item1,
|
||||
:label => "VAT 5%"
|
||||
)
|
||||
|
||||
@adj2 = line_item2.adjustments.create(
|
||||
:amount => 5,
|
||||
:source => line_item2,
|
||||
:label => "VAT 10%"
|
||||
)
|
||||
end
|
||||
|
||||
it "should return the adjustments for each line item" do
|
||||
expect(@order.line_item_adjustments).to include @adj1
|
||||
expect(@order.line_item_adjustments).to include @adj2
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
42
spec/models/spree/order/callbacks_spec.rb
Normal file
42
spec/models/spree/order/callbacks_spec.rb
Normal file
@@ -0,0 +1,42 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Order do
|
||||
let(:order) { stub_model(Spree::Order) }
|
||||
before do
|
||||
Spree::Order.define_state_machine!
|
||||
end
|
||||
|
||||
context "validations" do
|
||||
context "email validation" do
|
||||
# Regression test for Spree #1238
|
||||
it "o'brien@gmail.com is a valid email address" do
|
||||
order.state = 'address'
|
||||
order.email = "o'brien@gmail.com"
|
||||
order.should have(:no).error_on(:email)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "#save" do
|
||||
context "when associated with a registered user" do
|
||||
let(:user) { double(:user, :email => "test@example.com") }
|
||||
|
||||
before do
|
||||
order.stub :user => user
|
||||
end
|
||||
|
||||
it "should assign the email address of the user" do
|
||||
order.run_callbacks(:create)
|
||||
order.email.should == user.email
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "in the cart state" do
|
||||
it "should not validate email address" do
|
||||
order.state = "cart"
|
||||
order.email = nil
|
||||
order.should have(:no).error_on(:email)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -147,7 +147,7 @@ describe Spree::Order do
|
||||
end
|
||||
end
|
||||
|
||||
# Regression test for #2028
|
||||
# Regression test for Spree #2028
|
||||
context "when payment is not required" do
|
||||
before do
|
||||
allow(order).to receive_messages payment_required?: false
|
||||
@@ -211,7 +211,7 @@ describe Spree::Order do
|
||||
end
|
||||
end
|
||||
|
||||
# Regression test for #3665
|
||||
# Regression test for Spree #3665
|
||||
context "with only a complete step" do
|
||||
before do
|
||||
@old_checkout_flow = Spree::Order.checkout_flow
|
||||
|
||||
54
spec/models/spree/order/payment_spec.rb
Normal file
54
spec/models/spree/order/payment_spec.rb
Normal file
@@ -0,0 +1,54 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Spree
|
||||
describe Spree::Order do
|
||||
let(:order) { stub_model(Spree::Order) }
|
||||
let(:updater) { Spree::OrderUpdater.new(order) }
|
||||
|
||||
before do
|
||||
# So that Payment#purchase! is called during processing
|
||||
Spree::Config[:auto_capture] = true
|
||||
|
||||
order.stub_chain(:line_items, :empty?).and_return(false)
|
||||
order.stub :total => 100
|
||||
end
|
||||
|
||||
it 'processes all payments' do
|
||||
payment_1 = create(:payment, :amount => 50)
|
||||
payment_2 = create(:payment, :amount => 50)
|
||||
order.stub(:pending_payments).and_return([payment_1, payment_2])
|
||||
|
||||
order.process_payments!
|
||||
updater.update_payment_state
|
||||
order.payment_state.should == 'paid'
|
||||
|
||||
payment_1.should be_completed
|
||||
payment_2.should be_completed
|
||||
end
|
||||
|
||||
it 'does not go over total for order' do
|
||||
payment_1 = create(:payment, :amount => 50)
|
||||
payment_2 = create(:payment, :amount => 50)
|
||||
payment_3 = create(:payment, :amount => 50)
|
||||
order.stub(:pending_payments).and_return([payment_1, payment_2, payment_3])
|
||||
|
||||
order.process_payments!
|
||||
updater.update_payment_state
|
||||
order.payment_state.should == 'paid'
|
||||
|
||||
payment_1.should be_completed
|
||||
payment_2.should be_completed
|
||||
payment_3.should be_checkout
|
||||
end
|
||||
|
||||
it "does not use failed payments" do
|
||||
payment_1 = create(:payment, :amount => 50)
|
||||
payment_2 = create(:payment, :amount => 50, :state => 'failed')
|
||||
order.stub(:pending_payments).and_return([payment_1])
|
||||
|
||||
payment_2.should_not_receive(:process!)
|
||||
|
||||
order.process_payments!
|
||||
end
|
||||
end
|
||||
end
|
||||
183
spec/models/spree/order/state_machine_spec.rb
Normal file
183
spec/models/spree/order/state_machine_spec.rb
Normal file
@@ -0,0 +1,183 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Order do
|
||||
let(:order) { Spree::Order.new }
|
||||
before do
|
||||
# Ensure state machine has been re-defined correctly
|
||||
Spree::Order.define_state_machine!
|
||||
# We don't care about this validation here
|
||||
order.stub(:require_email)
|
||||
end
|
||||
|
||||
context "#next!" do
|
||||
context "when current state is confirm" do
|
||||
before do
|
||||
order.state = "confirm"
|
||||
order.run_callbacks(:create)
|
||||
order.stub :payment_required? => true
|
||||
order.stub :process_payments! => true
|
||||
order.stub :has_available_shipment
|
||||
end
|
||||
|
||||
context "when payment processing succeeds" do
|
||||
before { order.stub :process_payments! => true }
|
||||
|
||||
it "should finalize order when transitioning to complete state" do
|
||||
order.should_receive(:finalize!)
|
||||
order.next!
|
||||
end
|
||||
|
||||
context "when credit card processing fails" do
|
||||
before { order.stub :process_payments! => false }
|
||||
|
||||
it "should not complete the order" do
|
||||
order.next
|
||||
order.state.should == "confirm"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "when payment processing fails" do
|
||||
before { order.stub :process_payments! => false }
|
||||
|
||||
it "cannot transition to complete" do
|
||||
order.next
|
||||
order.state.should == "confirm"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "when current state is address" do
|
||||
before do
|
||||
order.stub(:has_available_payment)
|
||||
order.stub(:ensure_available_shipping_rates)
|
||||
order.state = "address"
|
||||
end
|
||||
|
||||
it "adjusts tax rates when transitioning to delivery" do
|
||||
# Once because the record is being saved
|
||||
# Twice because it is transitioning to the delivery state
|
||||
Spree::TaxRate.should_receive(:adjust).twice
|
||||
order.next!
|
||||
end
|
||||
end
|
||||
|
||||
context "when current state is delivery" do
|
||||
before do
|
||||
order.state = "delivery"
|
||||
order.stub :total => 10.0
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "#can_cancel?" do
|
||||
|
||||
%w(pending backorder ready).each do |shipment_state|
|
||||
it "should be true if shipment_state is #{shipment_state}" do
|
||||
order.stub :completed? => true
|
||||
order.shipment_state = shipment_state
|
||||
order.can_cancel?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
(Spree::Shipment.state_machine.states.keys - %w(pending backorder ready)).each do |shipment_state|
|
||||
it "should be false if shipment_state is #{shipment_state}" do
|
||||
order.stub :completed? => true
|
||||
order.shipment_state = shipment_state
|
||||
order.can_cancel?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "#cancel" do
|
||||
let!(:variant) { stub_model(Spree::Variant) }
|
||||
let!(:inventory_units) { [stub_model(Spree::InventoryUnit, :variant => variant),
|
||||
stub_model(Spree::InventoryUnit, :variant => variant) ]}
|
||||
let!(:shipment) do
|
||||
shipment = stub_model(Spree::Shipment)
|
||||
shipment.stub :inventory_units => inventory_units
|
||||
order.stub :shipments => [shipment]
|
||||
shipment
|
||||
end
|
||||
|
||||
before do
|
||||
order.stub :line_items => [stub_model(Spree::LineItem, :variant => variant, :quantity => 2)]
|
||||
order.line_items.stub :find_by_variant_id => order.line_items.first
|
||||
|
||||
order.stub :completed? => true
|
||||
order.stub :allow_cancel? => true
|
||||
end
|
||||
|
||||
it "should send a cancel email" do
|
||||
# Stub methods that cause side-effects in this test
|
||||
shipment.stub(:cancel!)
|
||||
order.stub :has_available_shipment
|
||||
order.stub :restock_items!
|
||||
mail_message = double "Mail::Message"
|
||||
order_id = nil
|
||||
Spree::OrderMailer.should_receive(:cancel_email) { |*args|
|
||||
order_id = args[0]
|
||||
mail_message
|
||||
}
|
||||
mail_message.should_receive :deliver
|
||||
order.cancel!
|
||||
order_id.should == order.id
|
||||
end
|
||||
|
||||
context "restocking inventory" do
|
||||
before do
|
||||
shipment.stub(:ensure_correct_adjustment)
|
||||
shipment.stub(:update_order)
|
||||
Spree::OrderMailer.stub(:cancel_email).and_return(mail_message = double)
|
||||
mail_message.stub :deliver
|
||||
|
||||
order.stub :has_available_shipment
|
||||
end
|
||||
end
|
||||
|
||||
context "resets payment state" do
|
||||
before do
|
||||
# Stubs methods that cause unwanted side effects in this test
|
||||
Spree::OrderMailer.stub(:cancel_email).and_return(mail_message = double)
|
||||
mail_message.stub :deliver
|
||||
order.stub :has_available_shipment
|
||||
order.stub :restock_items!
|
||||
shipment.stub(:cancel!)
|
||||
end
|
||||
|
||||
context "without shipped items" do
|
||||
it "should set payment state to 'credit owed'" do
|
||||
order.cancel!
|
||||
order.payment_state.should == 'credit_owed'
|
||||
end
|
||||
end
|
||||
|
||||
context "with shipped items" do
|
||||
before do
|
||||
order.stub :shipment_state => 'partial'
|
||||
end
|
||||
|
||||
it "should not alter the payment state" do
|
||||
order.cancel!
|
||||
order.payment_state.should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Another regression test for Spree #729
|
||||
context "#resume" do
|
||||
before do
|
||||
order.stub :email => "user@spreecommerce.com"
|
||||
order.stub :state => "canceled"
|
||||
order.stub :allow_resume? => true
|
||||
|
||||
# Stubs method that cause unwanted side effects in this test
|
||||
order.stub :has_available_shipment
|
||||
end
|
||||
end
|
||||
end
|
||||
115
spec/models/spree/order/tax_spec.rb
Normal file
115
spec/models/spree/order/tax_spec.rb
Normal file
@@ -0,0 +1,115 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Spree
|
||||
describe Spree::Order do
|
||||
let(:order) { stub_model(Spree::Order) }
|
||||
|
||||
context "#tax_zone" do
|
||||
let(:bill_address) { create :address }
|
||||
let(:ship_address) { create :address }
|
||||
let(:order) { Spree::Order.create(:ship_address => ship_address, :bill_address => bill_address) }
|
||||
let(:zone) { create :zone }
|
||||
|
||||
context "when no zones exist" do
|
||||
before { Spree::Zone.destroy_all }
|
||||
|
||||
it "should return nil" do
|
||||
order.tax_zone.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "when :tax_using_ship_address => true" do
|
||||
before { Spree::Config.set(:tax_using_ship_address => true) }
|
||||
|
||||
it "should calculate using ship_address" do
|
||||
Spree::Zone.should_receive(:match).at_least(:once).with(ship_address)
|
||||
Spree::Zone.should_not_receive(:match).with(bill_address)
|
||||
order.tax_zone
|
||||
end
|
||||
end
|
||||
|
||||
context "when :tax_using_ship_address => false" do
|
||||
before { Spree::Config.set(:tax_using_ship_address => false) }
|
||||
|
||||
it "should calculate using bill_address" do
|
||||
Spree::Zone.should_receive(:match).at_least(:once).with(bill_address)
|
||||
Spree::Zone.should_not_receive(:match).with(ship_address)
|
||||
order.tax_zone
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is a default tax zone" do
|
||||
before do
|
||||
@default_zone = create(:zone, :name => "foo_zone")
|
||||
Spree::Zone.stub :default_tax => @default_zone
|
||||
end
|
||||
|
||||
context "when there is a matching zone" do
|
||||
before { Spree::Zone.stub(:match => zone) }
|
||||
|
||||
it "should return the matching zone" do
|
||||
order.tax_zone.should == zone
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is no matching zone" do
|
||||
before { Spree::Zone.stub(:match => nil) }
|
||||
|
||||
it "should return the default tax zone" do
|
||||
order.tax_zone.should == @default_zone
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when no default tax zone" do
|
||||
before { Spree::Zone.stub :default_tax => nil }
|
||||
|
||||
context "when there is a matching zone" do
|
||||
before { Spree::Zone.stub(:match => zone) }
|
||||
|
||||
it "should return the matching zone" do
|
||||
order.tax_zone.should == zone
|
||||
end
|
||||
end
|
||||
|
||||
context "when there is no matching zone" do
|
||||
before { Spree::Zone.stub(:match => nil) }
|
||||
|
||||
it "should return nil" do
|
||||
order.tax_zone.should be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "#exclude_tax?" do
|
||||
before do
|
||||
@order = create(:order)
|
||||
@default_zone = create(:zone)
|
||||
Spree::Zone.stub :default_tax => @default_zone
|
||||
end
|
||||
|
||||
context "when prices include tax" do
|
||||
before { Spree::Config.set(:prices_inc_tax => true) }
|
||||
|
||||
it "should be true when tax_zone is not the same as the default" do
|
||||
@order.stub :tax_zone => create(:zone, :name => "other_zone")
|
||||
@order.exclude_tax?.should be_true
|
||||
end
|
||||
|
||||
it "should be false when tax_zone is the same as the default" do
|
||||
@order.stub :tax_zone => @default_zone
|
||||
@order.exclude_tax?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "when prices do not include tax" do
|
||||
before { Spree::Config.set(:prices_inc_tax => false) }
|
||||
|
||||
it "should be false" do
|
||||
@order.exclude_tax?.should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
18
spec/models/spree/order/updating_spec.rb
Normal file
18
spec/models/spree/order/updating_spec.rb
Normal file
@@ -0,0 +1,18 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::Order do
|
||||
let(:order) { stub_model(Spree::Order) }
|
||||
|
||||
context "#update!" do
|
||||
let(:line_items) { [mock_model(Spree::LineItem, :amount => 5) ]}
|
||||
|
||||
context "when there are update hooks" do
|
||||
before { Spree::Order.register_update_hook :foo }
|
||||
after { Spree::Order.update_hooks.clear }
|
||||
it "should call each of the update hooks" do
|
||||
order.should_receive :foo
|
||||
order.update!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
92
spec/models/spree/order_contents_spec.rb
Normal file
92
spec/models/spree/order_contents_spec.rb
Normal file
@@ -0,0 +1,92 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::OrderContents do
|
||||
let(:order) { Spree::Order.create }
|
||||
subject { described_class.new(order) }
|
||||
|
||||
context "#add" do
|
||||
let(:variant) { create(:variant) }
|
||||
|
||||
context 'given quantity is not explicitly provided' do
|
||||
it 'should add one line item' do
|
||||
line_item = subject.add(variant)
|
||||
line_item.quantity.should == 1
|
||||
order.line_items.size.should == 1
|
||||
end
|
||||
end
|
||||
|
||||
it 'should add line item if one does not exist' do
|
||||
line_item = subject.add(variant, 1)
|
||||
line_item.quantity.should == 1
|
||||
order.line_items.size.should == 1
|
||||
end
|
||||
|
||||
it 'should update line item if one exists' do
|
||||
subject.add(variant, 1)
|
||||
line_item = subject.add(variant, 1)
|
||||
line_item.quantity.should == 2
|
||||
order.line_items.size.should == 1
|
||||
end
|
||||
|
||||
it "should update order totals" do
|
||||
order.item_total.to_f.should == 0.00
|
||||
order.total.to_f.should == 0.00
|
||||
|
||||
subject.add(variant, 1)
|
||||
|
||||
order.item_total.to_f.should == 19.99
|
||||
order.total.to_f.should == 19.99
|
||||
end
|
||||
end
|
||||
|
||||
context "#remove" do
|
||||
let(:variant) { create(:variant) }
|
||||
|
||||
context "given an invalid variant" do
|
||||
it "raises an exception" do
|
||||
expect {
|
||||
subject.remove(variant, 1)
|
||||
}.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
context 'given quantity is not explicitly provided' do
|
||||
it 'should remove one line item' do
|
||||
line_item = subject.add(variant, 3)
|
||||
subject.remove(variant)
|
||||
|
||||
line_item.reload.quantity.should == 2
|
||||
end
|
||||
end
|
||||
|
||||
it 'should reduce line_item quantity if quantity is less the line_item quantity' do
|
||||
line_item = subject.add(variant, 3)
|
||||
subject.remove(variant, 1)
|
||||
|
||||
line_item.reload.quantity.should == 2
|
||||
end
|
||||
|
||||
it 'should remove line_item if quantity matches line_item quantity' do
|
||||
subject.add(variant, 1)
|
||||
subject.remove(variant, 1)
|
||||
|
||||
order.reload.find_line_item_by_variant(variant).should be_nil
|
||||
end
|
||||
|
||||
it "should update order totals" do
|
||||
order.item_total.to_f.should == 0.00
|
||||
order.total.to_f.should == 0.00
|
||||
|
||||
subject.add(variant,2)
|
||||
|
||||
order.item_total.to_f.should == 39.98
|
||||
order.total.to_f.should == 39.98
|
||||
|
||||
subject.remove(variant,1)
|
||||
order.item_total.to_f.should == 19.99
|
||||
order.total.to_f.should == 19.99
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
174
spec/models/spree/order_inventory_spec.rb
Normal file
174
spec/models/spree/order_inventory_spec.rb
Normal file
@@ -0,0 +1,174 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::OrderInventory do
|
||||
let(:order) { create :completed_order_with_totals }
|
||||
let(:line_item) { order.line_items.first }
|
||||
subject { described_class.new(order) }
|
||||
|
||||
it 'inventory_units_for should return array of units for a given variant' do
|
||||
units = subject.inventory_units_for(line_item.variant)
|
||||
units.map(&:variant_id).should == [line_item.variant.id]
|
||||
end
|
||||
|
||||
context "when order is missing inventory units" do
|
||||
before do
|
||||
line_item.update_column(:quantity, 2)
|
||||
end
|
||||
|
||||
it 'should be a messed up order' do
|
||||
order.shipments.first.inventory_units_for(line_item.variant).size.should == 1
|
||||
line_item.reload.quantity.should == 2
|
||||
end
|
||||
|
||||
it 'should increase the number of inventory units' do
|
||||
subject.verify(line_item)
|
||||
order.reload.shipments.first.inventory_units_for(line_item.variant).size.should == 2
|
||||
end
|
||||
end
|
||||
|
||||
context "#add_to_shipment" do
|
||||
let(:shipment) { order.shipments.first }
|
||||
let(:variant) { create :variant }
|
||||
|
||||
context "order is not completed" do
|
||||
before { order.stub completed?: false }
|
||||
|
||||
it "doesn't unstock items" do
|
||||
shipment.stock_location.should_not_receive(:unstock)
|
||||
subject.send(:add_to_shipment, shipment, variant, 5).should == 5
|
||||
end
|
||||
end
|
||||
|
||||
it 'should create inventory_units in the necessary states' do
|
||||
shipment.stock_location.should_receive(:fill_status).with(variant, 5).and_return([3, 2])
|
||||
|
||||
subject.send(:add_to_shipment, shipment, variant, 5).should == 5
|
||||
|
||||
units = shipment.inventory_units.group_by &:variant_id
|
||||
units = units[variant.id].group_by &:state
|
||||
units['backordered'].size.should == 2
|
||||
units['on_hand'].size.should == 3
|
||||
end
|
||||
|
||||
it 'should create stock_movement' do
|
||||
subject.send(:add_to_shipment, shipment, variant, 5).should == 5
|
||||
|
||||
stock_item = shipment.stock_location.stock_item(variant)
|
||||
movement = stock_item.stock_movements.last
|
||||
# movement.originator.should == shipment
|
||||
movement.quantity.should == -5
|
||||
end
|
||||
end
|
||||
|
||||
context "#determine_target_shipment" do
|
||||
let(:stock_location) { create :stock_location }
|
||||
let(:variant) { line_item.variant }
|
||||
|
||||
before do
|
||||
order.shipments.create(:stock_location_id => stock_location.id)
|
||||
shipped = order.shipments.create(:stock_location_id => order.shipments.first.stock_location.id)
|
||||
shipped.update_column(:state, 'shipped')
|
||||
end
|
||||
|
||||
it 'should select first non-shipped shipment that already contains given variant' do
|
||||
shipment = subject.send(:determine_target_shipment, variant)
|
||||
shipment.shipped?.should be_false
|
||||
shipment.inventory_units_for(variant).should_not be_empty
|
||||
variant.stock_location_ids.include?(shipment.stock_location_id).should be_true
|
||||
end
|
||||
|
||||
context "when no shipments already contain this varint" do
|
||||
it 'selects first non-shipped shipment that leaves from same stock_location' do
|
||||
subject.send(:remove_from_shipment, order.shipments.first, variant, line_item.quantity)
|
||||
|
||||
shipment = subject.send(:determine_target_shipment, variant)
|
||||
shipment.reload
|
||||
shipment.shipped?.should be_false
|
||||
shipment.inventory_units_for(variant).should be_empty
|
||||
variant.stock_location_ids.include?(shipment.stock_location_id).should be_true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when order has too many inventory units' do
|
||||
before do
|
||||
line_item.quantity = 3
|
||||
line_item.save!
|
||||
|
||||
line_item.update_column(:quantity, 2)
|
||||
order.reload
|
||||
end
|
||||
|
||||
it 'should be a messed up order' do
|
||||
order.shipments.first.inventory_units_for(line_item.variant).size.should == 3
|
||||
line_item.quantity.should == 2
|
||||
end
|
||||
|
||||
it 'should decrease the number of inventory units' do
|
||||
subject.verify(line_item)
|
||||
order.reload.shipments.first.inventory_units_for(line_item.variant).size.should == 2
|
||||
end
|
||||
|
||||
context '#remove_from_shipment' do
|
||||
let(:shipment) { order.shipments.first }
|
||||
let(:variant) { order.line_items.first.variant }
|
||||
|
||||
context "order is not completed" do
|
||||
before { order.stub completed?: false }
|
||||
|
||||
it "doesn't restock items" do
|
||||
shipment.stock_location.should_not_receive(:restock)
|
||||
subject.send(:remove_from_shipment, shipment, variant, 1).should == 1
|
||||
end
|
||||
end
|
||||
|
||||
it 'should create stock_movement' do
|
||||
subject.send(:remove_from_shipment, shipment, variant, 1).should == 1
|
||||
|
||||
stock_item = shipment.stock_location.stock_item(variant)
|
||||
movement = stock_item.stock_movements.last
|
||||
# movement.originator.should == shipment
|
||||
movement.quantity.should == 1
|
||||
end
|
||||
|
||||
it 'should destroy backordered units first' do
|
||||
shipment.stub(:inventory_units_for => [ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'backordered'),
|
||||
mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'on_hand'),
|
||||
mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'backordered') ])
|
||||
|
||||
shipment.inventory_units_for[0].should_receive(:destroy)
|
||||
shipment.inventory_units_for[1].should_not_receive(:destroy)
|
||||
shipment.inventory_units_for[2].should_receive(:destroy)
|
||||
|
||||
subject.send(:remove_from_shipment, shipment, variant, 2).should == 2
|
||||
end
|
||||
|
||||
it 'should destroy unshipped units first' do
|
||||
shipment.stub(:inventory_units_for => [ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'shipped'),
|
||||
mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'on_hand') ] )
|
||||
|
||||
shipment.inventory_units_for[0].should_not_receive(:destroy)
|
||||
shipment.inventory_units_for[1].should_receive(:destroy)
|
||||
|
||||
subject.send(:remove_from_shipment, shipment, variant, 1).should == 1
|
||||
end
|
||||
|
||||
it 'only attempts to destroy as many units as are eligible, and return amount destroyed' do
|
||||
shipment.stub(:inventory_units_for => [ mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'shipped'),
|
||||
mock_model(Spree::InventoryUnit, :variant_id => variant.id, :state => 'on_hand') ] )
|
||||
|
||||
shipment.inventory_units_for[0].should_not_receive(:destroy)
|
||||
shipment.inventory_units_for[1].should_receive(:destroy)
|
||||
|
||||
subject.send(:remove_from_shipment, shipment, variant, 1).should == 1
|
||||
end
|
||||
|
||||
it 'should destroy self if not inventory units remain' do
|
||||
shipment.inventory_units.stub(:count => 0)
|
||||
shipment.should_receive(:destroy)
|
||||
|
||||
subject.send(:remove_from_shipment, shipment, variant, 1).should == 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,6 +3,617 @@ require 'spec_helper'
|
||||
describe Spree::Order do
|
||||
include OpenFoodNetwork::EmailHelper
|
||||
|
||||
let(:user) { stub_model(Spree::LegacyUser, :email => "spree@example.com") }
|
||||
let(:order) { stub_model(Spree::Order, :user => user) }
|
||||
|
||||
before do
|
||||
Spree::LegacyUser.stub(:current => mock_model(Spree::LegacyUser, :id => 123))
|
||||
end
|
||||
|
||||
context "#products" do
|
||||
before :each do
|
||||
@variant1 = mock_model(Spree::Variant, :product => "product1")
|
||||
@variant2 = mock_model(Spree::Variant, :product => "product2")
|
||||
@line_items = [mock_model(Spree::LineItem, :product => "product1", :variant => @variant1, :variant_id => @variant1.id, :quantity => 1),
|
||||
mock_model(Spree::LineItem, :product => "product2", :variant => @variant2, :variant_id => @variant2.id, :quantity => 2)]
|
||||
order.stub(:line_items => @line_items)
|
||||
end
|
||||
|
||||
it "should return ordered products" do
|
||||
order.products.should == ['product1', 'product2']
|
||||
end
|
||||
|
||||
it "contains?" do
|
||||
order.contains?(@variant1).should be_true
|
||||
end
|
||||
|
||||
it "gets the quantity of a given variant" do
|
||||
order.quantity_of(@variant1).should == 1
|
||||
|
||||
@variant3 = mock_model(Spree::Variant, :product => "product3")
|
||||
order.quantity_of(@variant3).should == 0
|
||||
end
|
||||
|
||||
it "can find a line item matching a given variant" do
|
||||
order.find_line_item_by_variant(@variant1).should_not be_nil
|
||||
order.find_line_item_by_variant(mock_model(Spree::Variant)).should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "#generate_order_number" do
|
||||
it "should generate a random string" do
|
||||
order.generate_order_number.is_a?(String).should be_true
|
||||
(order.generate_order_number.to_s.length > 0).should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "#associate_user!" do
|
||||
it "should associate a user with a persisted order" do
|
||||
order = FactoryGirl.create(:order_with_line_items, created_by: nil)
|
||||
user = FactoryGirl.create(:user)
|
||||
|
||||
order.user = nil
|
||||
order.email = nil
|
||||
order.associate_user!(user)
|
||||
order.user.should == user
|
||||
order.email.should == user.email
|
||||
order.created_by.should == user
|
||||
|
||||
# verify that the changes we made were persisted
|
||||
order.reload
|
||||
order.user.should == user
|
||||
order.email.should == user.email
|
||||
order.created_by.should == user
|
||||
end
|
||||
|
||||
it "should not overwrite the created_by if it already is set" do
|
||||
creator = create(:user)
|
||||
order = FactoryGirl.create(:order_with_line_items, created_by: creator)
|
||||
user = FactoryGirl.create(:user)
|
||||
|
||||
order.user = nil
|
||||
order.email = nil
|
||||
order.associate_user!(user)
|
||||
order.user.should == user
|
||||
order.email.should == user.email
|
||||
order.created_by.should == creator
|
||||
|
||||
# verify that the changes we made were persisted
|
||||
order.reload
|
||||
order.user.should == user
|
||||
order.email.should == user.email
|
||||
order.created_by.should == creator
|
||||
end
|
||||
|
||||
|
||||
it "should associate a user with a non-persisted order" do
|
||||
order = Spree::Order.new
|
||||
|
||||
expect do
|
||||
order.associate_user!(user)
|
||||
end.to change { [order.user, order.email] }.from([nil, nil]).to([user, user.email])
|
||||
end
|
||||
|
||||
it "should not persist an invalid address" do
|
||||
address = Spree::Address.new
|
||||
order.user = nil
|
||||
order.email = nil
|
||||
order.ship_address = address
|
||||
expect do
|
||||
order.associate_user!(user)
|
||||
end.not_to change { address.persisted? }.from(false)
|
||||
end
|
||||
end
|
||||
|
||||
context "#create" do
|
||||
it "should assign an order number" do
|
||||
order = Spree::Order.create
|
||||
order.number.should_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "#can_ship?" do
|
||||
let(:order) { Spree::Order.create }
|
||||
|
||||
it "should be true for order in the 'complete' state" do
|
||||
order.stub(:complete? => true)
|
||||
order.can_ship?.should be_true
|
||||
end
|
||||
|
||||
it "should be true for order in the 'resumed' state" do
|
||||
order.stub(:resumed? => true)
|
||||
order.can_ship?.should be_true
|
||||
end
|
||||
|
||||
it "should be true for an order in the 'awaiting return' state" do
|
||||
order.stub(:awaiting_return? => true)
|
||||
order.can_ship?.should be_true
|
||||
end
|
||||
|
||||
it "should be true for an order in the 'returned' state" do
|
||||
order.stub(:returned? => true)
|
||||
order.can_ship?.should be_true
|
||||
end
|
||||
|
||||
it "should be false if the order is neither in the 'complete' nor 'resumed' state" do
|
||||
order.stub(:resumed? => false, :complete? => false)
|
||||
order.can_ship?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "checking if order is paid" do
|
||||
context "payment_state is paid" do
|
||||
before { order.stub payment_state: 'paid' }
|
||||
it { expect(order).to be_paid }
|
||||
end
|
||||
|
||||
context "payment_state is credit_owned" do
|
||||
before { order.stub payment_state: 'credit_owed' }
|
||||
it { expect(order).to be_paid }
|
||||
end
|
||||
end
|
||||
|
||||
context "#finalize!" do
|
||||
let(:order) { Spree::Order.create }
|
||||
it "should set completed_at" do
|
||||
order.should_receive(:touch).with(:completed_at)
|
||||
order.finalize!
|
||||
end
|
||||
|
||||
it "should sell inventory units" do
|
||||
order.shipments.each do |shipment|
|
||||
shipment.should_receive(:update!)
|
||||
shipment.should_receive(:finalize!)
|
||||
end
|
||||
order.finalize!
|
||||
end
|
||||
|
||||
it "should decrease the stock for each variant in the shipment" do
|
||||
order.shipments.each do |shipment|
|
||||
shipment.stock_location.should_receive(:decrease_stock_for_variant)
|
||||
end
|
||||
order.finalize!
|
||||
end
|
||||
|
||||
it "should change the shipment state to ready if order is paid" do
|
||||
Spree::Shipment.create(order: order)
|
||||
order.shipments.reload
|
||||
|
||||
order.stub(:paid? => true, :complete? => true)
|
||||
order.finalize!
|
||||
order.reload # reload so we're sure the changes are persisted
|
||||
order.shipment_state.should == 'ready'
|
||||
end
|
||||
|
||||
after { Spree::Config.set :track_inventory_levels => true }
|
||||
it "should not sell inventory units if track_inventory_levels is false" do
|
||||
Spree::Config.set :track_inventory_levels => false
|
||||
Spree::InventoryUnit.should_not_receive(:sell_units)
|
||||
order.finalize!
|
||||
end
|
||||
|
||||
it "should send an order confirmation email" do
|
||||
mail_message = double "Mail::Message"
|
||||
Spree::OrderMailer.should_receive(:confirm_email).with(order.id).and_return mail_message
|
||||
mail_message.should_receive :deliver
|
||||
order.finalize!
|
||||
end
|
||||
|
||||
it "should continue even if confirmation email delivery fails" do
|
||||
Spree::OrderMailer.should_receive(:confirm_email).with(order.id).and_raise 'send failed!'
|
||||
order.finalize!
|
||||
end
|
||||
|
||||
it "should freeze all adjustments" do
|
||||
# Stub this method as it's called due to a callback
|
||||
# and it's irrelevant to this test
|
||||
order.stub :has_available_shipment
|
||||
Spree::OrderMailer.stub_chain :confirm_email, :deliver
|
||||
adjustments = double
|
||||
order.stub :adjustments => adjustments
|
||||
expect(adjustments).to receive(:update_all).with(state: 'closed')
|
||||
order.finalize!
|
||||
end
|
||||
|
||||
it "should log state event" do
|
||||
order.state_changes.should_receive(:create).exactly(3).times #order, shipment & payment state changes
|
||||
order.finalize!
|
||||
end
|
||||
|
||||
it 'calls updater#before_save' do
|
||||
order.updater.should_receive(:before_save_hook)
|
||||
order.finalize!
|
||||
end
|
||||
end
|
||||
|
||||
context "#process_payments!" do
|
||||
let(:payment) { stub_model(Spree::Payment) }
|
||||
before { order.stub :pending_payments => [payment], :total => 10 }
|
||||
|
||||
it "should process the payments" do
|
||||
payment.should_receive(:process!)
|
||||
order.process_payments!.should be_true
|
||||
end
|
||||
|
||||
it "should return false if no pending_payments available" do
|
||||
order.stub :pending_payments => []
|
||||
order.process_payments!.should be_false
|
||||
end
|
||||
|
||||
context "when a payment raises a GatewayError" do
|
||||
before { payment.should_receive(:process!).and_raise(Spree::Core::GatewayError) }
|
||||
|
||||
it "should return true when configured to allow checkout on gateway failures" do
|
||||
Spree::Config.set :allow_checkout_on_gateway_error => true
|
||||
order.process_payments!.should be_true
|
||||
end
|
||||
|
||||
it "should return false when not configured to allow checkout on gateway failures" do
|
||||
Spree::Config.set :allow_checkout_on_gateway_error => false
|
||||
order.process_payments!.should be_false
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
context "#outstanding_balance" do
|
||||
it "should return positive amount when payment_total is less than total" do
|
||||
order.payment_total = 20.20
|
||||
order.total = 30.30
|
||||
order.outstanding_balance.should == 10.10
|
||||
end
|
||||
it "should return negative amount when payment_total is greater than total" do
|
||||
order.total = 8.20
|
||||
order.payment_total = 10.20
|
||||
order.outstanding_balance.should be_within(0.001).of(-2.00)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "#outstanding_balance?" do
|
||||
it "should be true when total greater than payment_total" do
|
||||
order.total = 10.10
|
||||
order.payment_total = 9.50
|
||||
order.outstanding_balance?.should be_true
|
||||
end
|
||||
it "should be true when total less than payment_total" do
|
||||
order.total = 8.25
|
||||
order.payment_total = 10.44
|
||||
order.outstanding_balance?.should be_true
|
||||
end
|
||||
it "should be false when total equals payment_total" do
|
||||
order.total = 10.10
|
||||
order.payment_total = 10.10
|
||||
order.outstanding_balance?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "#completed?" do
|
||||
it "should indicate if order is completed" do
|
||||
order.completed_at = nil
|
||||
order.completed?.should be_false
|
||||
|
||||
order.completed_at = Time.now
|
||||
order.completed?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
it 'is backordered if one of the shipments is backordered' do
|
||||
order.stub(:shipments => [mock_model(Spree::Shipment, :backordered? => false),
|
||||
mock_model(Spree::Shipment, :backordered? => true)])
|
||||
order.should be_backordered
|
||||
end
|
||||
|
||||
context "#allow_checkout?" do
|
||||
it "should be true if there are line_items in the order" do
|
||||
order.stub_chain(:line_items, :count => 1)
|
||||
order.checkout_allowed?.should be_true
|
||||
end
|
||||
it "should be false if there are no line_items in the order" do
|
||||
order.stub_chain(:line_items, :count => 0)
|
||||
order.checkout_allowed?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "#item_count" do
|
||||
before do
|
||||
@order = create(:order, :user => user)
|
||||
@order.line_items = [ create(:line_item, :quantity => 2), create(:line_item, :quantity => 1) ]
|
||||
end
|
||||
it "should return the correct number of items" do
|
||||
@order.item_count.should == 3
|
||||
end
|
||||
end
|
||||
|
||||
context "#amount" do
|
||||
before do
|
||||
@order = create(:order, :user => user)
|
||||
@order.line_items = [create(:line_item, :price => 1.0, :quantity => 2),
|
||||
create(:line_item, :price => 1.0, :quantity => 1)]
|
||||
end
|
||||
it "should return the correct lum sum of items" do
|
||||
@order.amount.should == 3.0
|
||||
end
|
||||
end
|
||||
|
||||
context "#can_cancel?" do
|
||||
it "should be false for completed order in the canceled state" do
|
||||
order.state = 'canceled'
|
||||
order.shipment_state = 'ready'
|
||||
order.completed_at = Time.now
|
||||
order.can_cancel?.should be_false
|
||||
end
|
||||
|
||||
it "should be true for completed order with no shipment" do
|
||||
order.state = 'complete'
|
||||
order.shipment_state = nil
|
||||
order.completed_at = Time.now
|
||||
order.can_cancel?.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
context "insufficient_stock_lines" do
|
||||
let(:line_item) { mock_model Spree::LineItem, :insufficient_stock? => true }
|
||||
|
||||
before { order.stub(:line_items => [line_item]) }
|
||||
|
||||
it "should return line_item that has insufficient stock on hand" do
|
||||
order.insufficient_stock_lines.size.should == 1
|
||||
order.insufficient_stock_lines.include?(line_item).should be_true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "empty!" do
|
||||
it "should clear out all line items and adjustments" do
|
||||
order = stub_model(Spree::Order)
|
||||
order.stub(:line_items => line_items = [])
|
||||
order.stub(:adjustments => adjustments = [])
|
||||
order.line_items.should_receive(:destroy_all)
|
||||
order.adjustments.should_receive(:destroy_all)
|
||||
|
||||
order.empty!
|
||||
end
|
||||
end
|
||||
|
||||
context "#display_outstanding_balance" do
|
||||
it "returns the value as a spree money" do
|
||||
order.stub(:outstanding_balance) { 10.55 }
|
||||
order.display_outstanding_balance.should == Spree::Money.new(10.55)
|
||||
end
|
||||
end
|
||||
|
||||
context "#display_item_total" do
|
||||
it "returns the value as a spree money" do
|
||||
order.stub(:item_total) { 10.55 }
|
||||
order.display_item_total.should == Spree::Money.new(10.55)
|
||||
end
|
||||
end
|
||||
|
||||
context "#display_adjustment_total" do
|
||||
it "returns the value as a spree money" do
|
||||
order.adjustment_total = 10.55
|
||||
order.display_adjustment_total.should == Spree::Money.new(10.55)
|
||||
end
|
||||
end
|
||||
|
||||
context "#display_total" do
|
||||
it "returns the value as a spree money" do
|
||||
order.total = 10.55
|
||||
order.display_total.should == Spree::Money.new(10.55)
|
||||
end
|
||||
end
|
||||
|
||||
context "#currency" do
|
||||
context "when object currency is ABC" do
|
||||
before { order.currency = "ABC" }
|
||||
|
||||
it "returns the currency from the object" do
|
||||
order.currency.should == "ABC"
|
||||
end
|
||||
end
|
||||
|
||||
context "when object currency is nil" do
|
||||
before { order.currency = nil }
|
||||
|
||||
it "returns the globally configured currency" do
|
||||
order.currency.should == "USD"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Regression tests for Spree #2179
|
||||
context "#merge!" do
|
||||
let(:variant) { create(:variant) }
|
||||
let(:order_1) { Spree::Order.create }
|
||||
let(:order_2) { Spree::Order.create }
|
||||
|
||||
it "destroys the other order" do
|
||||
order_1.merge!(order_2)
|
||||
lambda { order_2.reload }.should raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
|
||||
context "merging together two orders with line items for the same variant" do
|
||||
before do
|
||||
order_1.contents.add(variant, 1)
|
||||
order_2.contents.add(variant, 1)
|
||||
end
|
||||
|
||||
specify do
|
||||
order_1.merge!(order_2)
|
||||
order_1.line_items.count.should == 1
|
||||
|
||||
line_item = order_1.line_items.first
|
||||
line_item.quantity.should == 2
|
||||
line_item.variant_id.should == variant.id
|
||||
end
|
||||
end
|
||||
|
||||
context "merging together two orders with different line items" do
|
||||
let(:variant_2) { create(:variant) }
|
||||
|
||||
before do
|
||||
order_1.contents.add(variant, 1)
|
||||
order_2.contents.add(variant_2, 1)
|
||||
end
|
||||
|
||||
specify do
|
||||
order_1.merge!(order_2)
|
||||
line_items = order_1.line_items
|
||||
line_items.count.should == 2
|
||||
|
||||
# No guarantee on ordering of line items, so we do this:
|
||||
line_items.pluck(:quantity).should =~ [1, 1]
|
||||
line_items.pluck(:variant_id).should =~ [variant.id, variant_2.id]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "#confirmation_required?" do
|
||||
it "does not bomb out when an order has an unpersisted payment" do
|
||||
order = Spree::Order.new
|
||||
order.payments.build
|
||||
assert !order.confirmation_required?
|
||||
end
|
||||
end
|
||||
|
||||
# Regression test for Spree #2191
|
||||
context "when an order has an adjustment that zeroes the total, but another adjustment for shipping that raises it above zero" do
|
||||
let!(:persisted_order) { create(:order) }
|
||||
let!(:line_item) { create(:line_item) }
|
||||
let!(:shipping_method) do
|
||||
sm = create(:shipping_method)
|
||||
sm.calculator.preferred_amount = 10
|
||||
sm.save
|
||||
sm
|
||||
end
|
||||
|
||||
before do
|
||||
# Don't care about available payment methods in this test
|
||||
persisted_order.stub(:has_available_payment => false)
|
||||
persisted_order.line_items << line_item
|
||||
persisted_order.adjustments.create(:amount => -line_item.amount, :label => "Promotion")
|
||||
persisted_order.state = 'delivery'
|
||||
persisted_order.save # To ensure new state_change event
|
||||
end
|
||||
|
||||
it "transitions from delivery to payment" do
|
||||
persisted_order.stub(payment_required?: true)
|
||||
persisted_order.next!
|
||||
persisted_order.state.should == "payment"
|
||||
end
|
||||
end
|
||||
|
||||
context "promotion adjustments" do
|
||||
let(:originator) { double("Originator", id: 1) }
|
||||
let(:adjustment) { double("Adjustment", originator: originator) }
|
||||
|
||||
before { order.stub_chain(:adjustments, :includes, :promotion, reload: [adjustment]) }
|
||||
|
||||
context "order has an adjustment from given promo action" do
|
||||
it { expect(order.promotion_credit_exists? originator).to be_true }
|
||||
end
|
||||
|
||||
context "order has no adjustment from given promo action" do
|
||||
before { originator.stub(id: 12) }
|
||||
it { expect(order.promotion_credit_exists? originator).to be_true }
|
||||
end
|
||||
end
|
||||
|
||||
context "payment required?" do
|
||||
let(:order) { Spree::Order.new }
|
||||
|
||||
context "total is zero" do
|
||||
it { order.payment_required?.should be_false }
|
||||
end
|
||||
|
||||
context "total > zero" do
|
||||
before { order.stub(total: 1) }
|
||||
it { order.payment_required?.should be_true }
|
||||
end
|
||||
end
|
||||
|
||||
context "add_update_hook" do
|
||||
before do
|
||||
Spree::Order.class_eval do
|
||||
register_update_hook :add_awesome_sauce
|
||||
end
|
||||
end
|
||||
|
||||
after do
|
||||
Spree::Order.update_hooks = Set.new
|
||||
end
|
||||
|
||||
it "calls hook during update" do
|
||||
order = create(:order)
|
||||
order.should_receive(:add_awesome_sauce)
|
||||
order.update!
|
||||
end
|
||||
|
||||
it "calls hook during finalize" do
|
||||
order = create(:order)
|
||||
order.should_receive(:add_awesome_sauce)
|
||||
order.finalize!
|
||||
end
|
||||
end
|
||||
|
||||
context "ensure shipments will be updated" do
|
||||
before { Spree::Shipment.create!(order: order) }
|
||||
|
||||
it "destroys current shipments" do
|
||||
order.ensure_updated_shipments
|
||||
expect(order.shipments).to be_empty
|
||||
end
|
||||
|
||||
it "puts order back in address state" do
|
||||
order.ensure_updated_shipments
|
||||
expect(order.state).to eql "address"
|
||||
end
|
||||
end
|
||||
|
||||
describe ".tax_address" do
|
||||
before { Spree::Config[:tax_using_ship_address] = tax_using_ship_address }
|
||||
subject { order.tax_address }
|
||||
|
||||
context "when tax_using_ship_address is true" do
|
||||
let(:tax_using_ship_address) { true }
|
||||
|
||||
it 'returns ship_address' do
|
||||
subject.should == order.ship_address
|
||||
end
|
||||
end
|
||||
|
||||
context "when tax_using_ship_address is not true" do
|
||||
let(:tax_using_ship_address) { false }
|
||||
|
||||
it "returns bill_address" do
|
||||
subject.should == order.bill_address
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#updater' do
|
||||
class FakeOrderUpdaterDecorator
|
||||
attr_reader :decorated_object
|
||||
|
||||
def initialize(decorated_object)
|
||||
@decorated_object = decorated_object
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
Spree::Config.stub(:order_updater_decorator) { FakeOrderUpdaterDecorator }
|
||||
end
|
||||
|
||||
it 'returns an order_updater_decorator class' do
|
||||
order.updater.class.should == FakeOrderUpdaterDecorator
|
||||
end
|
||||
|
||||
it 'decorates a Spree::OrderUpdater' do
|
||||
order.updater.decorated_object.class.should == Spree::OrderUpdater
|
||||
end
|
||||
end
|
||||
|
||||
describe "email validation" do
|
||||
let(:order) { build(:order) }
|
||||
|
||||
|
||||
138
spec/models/spree/return_authorization_spec.rb
Normal file
138
spec/models/spree/return_authorization_spec.rb
Normal file
@@ -0,0 +1,138 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Spree::ReturnAuthorization do
|
||||
let(:stock_location) {Spree::StockLocation.create(:name => "test")}
|
||||
let(:order) { FactoryGirl.create(:shipped_order)}
|
||||
let(:variant) { order.shipments.first.inventory_units.first.variant }
|
||||
let(:return_authorization) { Spree::ReturnAuthorization.new(:order => order, :stock_location_id => stock_location.id) }
|
||||
|
||||
context "save" do
|
||||
it "should be invalid when order has no inventory units" do
|
||||
order.shipments.destroy_all
|
||||
return_authorization.save
|
||||
return_authorization.errors[:order].should == ["has no shipped units"]
|
||||
end
|
||||
|
||||
it "should generate RMA number" do
|
||||
return_authorization.should_receive(:generate_number)
|
||||
return_authorization.save
|
||||
end
|
||||
end
|
||||
|
||||
context "add_variant" do
|
||||
context "on empty rma" do
|
||||
it "should associate inventory unit" do
|
||||
return_authorization.add_variant(variant.id, 1)
|
||||
return_authorization.inventory_units.size.should == 1
|
||||
end
|
||||
|
||||
it "should associate inventory units as shipped" do
|
||||
return_authorization.add_variant(variant.id, 1)
|
||||
expect(return_authorization.inventory_units.where(state: 'shipped').size).to eq 1
|
||||
end
|
||||
|
||||
it "should update order state" do
|
||||
order.should_receive(:authorize_return!)
|
||||
return_authorization.add_variant(variant.id, 1)
|
||||
end
|
||||
end
|
||||
|
||||
context "on rma that already has inventory_units" do
|
||||
before do
|
||||
return_authorization.add_variant(variant.id, 1)
|
||||
end
|
||||
|
||||
it "should not associate more inventory units than there are on the order" do
|
||||
return_authorization.add_variant(variant.id, 1)
|
||||
expect(return_authorization.inventory_units.size).to eq 1
|
||||
end
|
||||
|
||||
it "should not update order state" do
|
||||
expect{return_authorization.add_variant(variant.id, 1)}.to_not change{order.state}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "can_receive?" do
|
||||
it "should allow_receive when inventory units assigned" do
|
||||
return_authorization.stub(:inventory_units => [1,2,3])
|
||||
return_authorization.can_receive?.should be_true
|
||||
end
|
||||
|
||||
it "should not allow_receive with no inventory units" do
|
||||
return_authorization.stub(:inventory_units => [])
|
||||
return_authorization.can_receive?.should be_false
|
||||
end
|
||||
end
|
||||
|
||||
context "receive!" do
|
||||
let(:inventory_unit) { order.shipments.first.inventory_units.first }
|
||||
|
||||
before do
|
||||
return_authorization.stub(:inventory_units => [inventory_unit], :amount => -20)
|
||||
Spree::Adjustment.stub(:create)
|
||||
order.stub(:update!)
|
||||
end
|
||||
|
||||
it "should mark all inventory units are returned" do
|
||||
inventory_unit.should_receive(:return!)
|
||||
return_authorization.receive!
|
||||
end
|
||||
|
||||
it "should add credit for specified amount" do
|
||||
return_authorization.amount = 20
|
||||
mock_adjustment = double
|
||||
mock_adjustment.should_receive(:source=).with(return_authorization)
|
||||
mock_adjustment.should_receive(:adjustable=).with(order)
|
||||
mock_adjustment.should_receive(:save)
|
||||
Spree::Adjustment.should_receive(:new).with(:amount => -20, :label => Spree.t(:rma_credit)).and_return(mock_adjustment)
|
||||
return_authorization.receive!
|
||||
end
|
||||
|
||||
it "should update order state" do
|
||||
order.should_receive :update!
|
||||
return_authorization.receive!
|
||||
end
|
||||
end
|
||||
|
||||
context "force_positive_amount" do
|
||||
it "should ensure the amount is always positive" do
|
||||
return_authorization.amount = -10
|
||||
return_authorization.send :force_positive_amount
|
||||
return_authorization.amount.should == 10
|
||||
end
|
||||
end
|
||||
|
||||
context "after_save" do
|
||||
it "should run correct callbacks" do
|
||||
return_authorization.should_receive(:force_positive_amount)
|
||||
return_authorization.run_callbacks(:save)
|
||||
end
|
||||
end
|
||||
|
||||
context "currency" do
|
||||
before { order.stub(:currency) { "ABC" } }
|
||||
it "returns the order currency" do
|
||||
return_authorization.currency.should == "ABC"
|
||||
end
|
||||
end
|
||||
|
||||
context "display_amount" do
|
||||
it "returns a Spree::Money" do
|
||||
return_authorization.amount = 21.22
|
||||
return_authorization.display_amount.should == Spree::Money.new(21.22)
|
||||
end
|
||||
end
|
||||
|
||||
context "returnable_inventory" do
|
||||
pending "should return inventory from shipped shipments" do
|
||||
return_authorization.returnable_inventory.should == [inventory_unit]
|
||||
end
|
||||
|
||||
pending "should not return inventory from unshipped shipments" do
|
||||
return_authorization.returnable_inventory.should == []
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user