require 'spec_helper' describe Effective::Order do let(:cart) { FactoryGirl.create(:cart) } let(:order) { FactoryGirl.create(:order) } let(:user) { FactoryGirl.create(:user) } let(:product) { FactoryGirl.create(:product) } let(:product2) { FactoryGirl.create(:product) } it 'calculates dollars based on its order items' do order.total.should eq order.order_items.collect(&:total).sum order.subtotal.should eq order.order_items.collect(&:subtotal).sum order.tax.should eq order.order_items.collect(&:tax).sum order.num_items.should eq order.order_items.collect(&:quantity).sum end describe '#initialize' do it 'creates appropriate OrderItems when initialized with a Cart' do order = Effective::Order.new(cart) order.order_items.each_with_index do |order_item, x| order_item.title.should eq cart.cart_items[x].title order_item.price.should eq cart.cart_items[x].price order_item.quantity.should eq cart.cart_items[x].quantity order_item.purchasable.should eq cart.cart_items[x].purchasable end order.order_items.length.should eq cart.cart_items.length order.total.should eq cart.total order.subtotal.should eq cart.subtotal order.tax.should eq cart.tax end it 'creates appropriate OrderItems when initialized with an array of purchasables' do order = Effective::Order.new([product, product2]) order.order_items.size.should eq 2 order.subtotal.should eq (product.price + product2.price) order.total.should eq ((product.price + product2.price) * 1.05) end it 'creates appropriate OrderItems when initialized with a single purchasable' do order = Effective::Order.new(product) order.order_items.size.should eq 1 order_item = order.order_items.first order_item.title.should eq product.title order_item.price.should eq product.price order_item.purchasable.should eq product order_item.quantity.should eq 1 end it 'throws an ArgumentError when passed something unexpected' do expect { Effective::Order.new(Object.new()) }.to raise_error(ArgumentError) end end describe 'minimum zero math' do it 'has a minimum order total of 0' do order.order_items.each { |order_item| order_item.stub(:total).and_return(-1000) } order.order_items.collect(&:total).sum.should eq -3000 order.total.should eq 0 end it 'has no minimum subtotal' do order.order_items.each { |order_item| order_item.stub(:subtotal).and_return(-1000) } order.order_items.collect(&:subtotal).sum.should eq -3000 order.subtotal.should eq -3000 end it 'has a minimum order tax of 0.00' do order.order_items.each { |order_item| order_item.stub(:tax).and_return(-1000) } order.order_items.collect(&:tax).sum.should eq -3000 order.tax.should eq 0 end end describe 'user=' do it 'assigns the user' do order = Effective::Order.new() order.user = user order.user.should eq user end it 'assigns addresses from the user' do order = Effective::Order.new() user.billing_address = FactoryGirl.create(:address, :category => :billing) user.shipping_address = FactoryGirl.create(:address, :category => :shipping) order.user = user order.billing_address.should eq user.billing_address order.save_billing_address.should eq true order.shipping_address.should eq user.shipping_address order.save_shipping_address.should eq true end end describe 'validations' do it 'should be invalid without a user or order_items' do order = Effective::Order.new() order.valid?.should eq false order.errors[:user_id].present?.should eq true order.errors[:order_items].present?.should eq true end it 'should be invalid when user is invalid' do order.user.stub(:valid?).and_return(false) order.valid?.should eq false order.errors[:user].present?.should eq true end it 'should be invalid when an order_item is invalid' do order.order_items.first.stub(:valid?).and_return(false) order.valid?.should eq false order.errors[:order_items].present?.should eq true end it 'should be invalid when less than the minimum charge' do order.stub(:total).and_return(49) order.valid?.should eq false order.errors[:total].present?.should eq true order.errors[:total].first.downcase.include?('minimum order of 50 is required').should eq true end it 'should be valid when >= minimum charge' do order.stub(:total).and_return(50) order.valid?.should eq true order.stub(:total).and_return(51) order.valid?.should eq true end it 'should be valid for a free order' do order.order_items.each { |order_item| order_item.stub(:total).and_return(0) } order.valid?.should eq true order.errors[:total].present?.should eq false end end describe 'purchase!' do it 'assigns the purchase_state, purchase_at and payment' do order.purchase!('by a test').should eq true order.purchase_state.should eq EffectiveOrders::PURCHASED order.purchased_at.kind_of?(Time).should eq true order.payment[:details].should eq 'by a test' end it 'sends purchased callback to all order_items' do order.order_items.each { |oi| oi.purchasable.should_receive(:purchased!).with(order, oi) } order.purchase!('by a test') end it 'throws an error when purchased twice' do order.purchase!('first time') expect { order.purchase!('second time') }.to raise_error(EffectiveOrders::AlreadyPurchasedException) end it 'sends emails to the admin, buyer and seller' do Effective::OrdersMailer.deliveries.clear order.purchase!('by a test') Effective::OrdersMailer.deliveries.length.should eq 2 Effective::OrdersMailer.deliveries[0].to.first.should eq 'admin@example.com' Effective::OrdersMailer.deliveries[0].subject.include?("Order ##{order.to_param} Receipt").should eq true Effective::OrdersMailer.deliveries[1].to.first.should eq order.user.email Effective::OrdersMailer.deliveries[1].subject.include?("Order ##{order.to_param} Receipt").should eq true end it 'does not send email if passed :email => false' do Effective::OrdersMailer.deliveries.clear order.purchase!('by a test', :email => false) Effective::OrdersMailer.deliveries.length.should eq 0 end it 'is included with the purchased scope' do order.purchase!('by a test') Effective::Order.purchased.to_a.include?(order).should eq true Effective::Order.purchased_by(order.user).to_a.include?(order).should eq true end it 'is not included with the declined scope' do order.purchase!('by a test') Effective::Order.declined.to_a.include?(order).should eq false end it 'should return false when the Order is invalid' do order.stub(:valid?).and_return(false) expect { order.purchase!('by a test') }.to raise_exception end it 'should return true when the Order is invalid and :validate => false is passed' do order.stub(:valid?).and_return(false) order.purchase!('by a test', :validate => false).should eq true end end describe 'purchased?' do it 'returns true when a purchased order' do order.purchase!('by a test') order.purchased?.should eq true end it 'returns false when not purchased' do order.purchased?.should eq false end it 'returns false when declined' do order.decline!('by a test') order.purchased?.should eq false end end describe 'decline!' do it 'assigns the purchase_state' do order.decline!('by a test').should eq true order.purchase_state.should eq EffectiveOrders::DECLINED order.payment[:details].should eq 'by a test' order.purchased_at.should eq nil end it 'sends declined callback to all order_items' do order.order_items.each { |oi| oi.purchasable.should_receive(:declined!).with(order, oi) } order.decline!('by a test') end it 'throws an error when declined twice' do order.decline!('first time') expect { order.decline!('second time') }.to raise_error(EffectiveOrders::AlreadyDeclinedException) end it 'is included with the declined scope' do order.decline!('by a test') Effective::Order.declined.to_a.include?(order).should eq true end it 'is not included with the purchased scope' do order.decline!('by a test') Effective::Order.purchased.to_a.include?(order).should eq false Effective::Order.purchased_by(order.user).to_a.include?(order).should eq false end end describe 'declined?' do it 'returns true when a declined order' do order.decline!('by a test') order.declined?.should eq true end it 'returns false when not declined' do order.declined?.should eq false end it 'returns false when purchased' do order.purchase!('by a test') order.declined?.should eq false end end describe '#save_billing_address?' do it 'is true when save_billing_address is 1' do order.save_billing_address = '1' order.save_billing_address?.should eq true end it 'is false when save_billing_address is 0' do order.save_billing_address = '0' order.save_billing_address?.should eq false end it 'is false when save_billing_address is nil' do order.save_billing_address = nil order.save_billing_address?.should eq false end end describe '#save_shipping_address?' do it 'is true when save_shipping_address is 1' do order.save_shipping_address = '1' order.save_shipping_address?.should eq true end it 'is false when save_shipping_address is 0' do order.save_shipping_address = '0' order.save_shipping_address?.should eq false end it 'is false when save_shipping_address is nil' do order.save_shipping_address = nil order.save_shipping_address?.should eq false end end describe '#to_param' do it 'returns an obfuscated ID' do (order.to_param.length >= 10).should eq true end end end