mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-26 20:56:48 +00:00
The way we set up email sending completely changes with Spree 2. This change encapsulates that code in a single method so that it can be changed easily and doesn't create further merge conflicts while we are still working on the master branch and the Spree upgrade.
903 lines
32 KiB
Ruby
903 lines
32 KiB
Ruby
require 'spec_helper'
|
|
|
|
describe Spree::Order do
|
|
include OpenFoodNetwork::EmailHelper
|
|
|
|
describe "setting variant attributes" do
|
|
it "sets attributes on line items for variants" do
|
|
d = create(:distributor_enterprise)
|
|
p = create(:product, :distributors => [d])
|
|
|
|
subject.distributor = d
|
|
subject.save!
|
|
|
|
subject.add_variant(p.master, 1, 3)
|
|
|
|
li = Spree::LineItem.last
|
|
li.max_quantity.should == 3
|
|
end
|
|
|
|
it "does nothing when the line item is not found" do
|
|
p = create(:simple_product)
|
|
subject.set_variant_attributes(p.master, {'max_quantity' => '3'}.with_indifferent_access)
|
|
end
|
|
end
|
|
|
|
describe "updating the distribution charge" do
|
|
let(:order) { build(:order) }
|
|
|
|
it "clears all enterprise fee adjustments on the order" do
|
|
EnterpriseFee.should_receive(:clear_all_adjustments_on_order).with(subject)
|
|
subject.update_distribution_charge!
|
|
end
|
|
|
|
it "ensures the correct adjustment(s) are created for the product distribution" do
|
|
EnterpriseFee.stub(:clear_all_adjustments_on_order)
|
|
line_item = double(:line_item)
|
|
subject.stub(:line_items) { [line_item] }
|
|
subject.stub(:provided_by_order_cycle?) { false }
|
|
|
|
product_distribution = double(:product_distribution)
|
|
product_distribution.should_receive(:create_adjustment_for).with(line_item)
|
|
subject.stub(:product_distribution_for) { product_distribution }
|
|
|
|
|
|
subject.update_distribution_charge!
|
|
end
|
|
|
|
it "skips line items that don't have a product distribution" do
|
|
EnterpriseFee.stub(:clear_all_adjustments_on_order)
|
|
line_item = double(:line_item)
|
|
subject.stub(:line_items) { [line_item] }
|
|
subject.stub(:provided_by_order_cycle?) { false }
|
|
|
|
subject.stub(:product_distribution_for) { nil }
|
|
|
|
subject.update_distribution_charge!
|
|
end
|
|
|
|
it "skips order cycle per-order adjustments for orders that don't have an order cycle" do
|
|
EnterpriseFee.stub(:clear_all_adjustments_on_order)
|
|
subject.stub(:line_items) { [] }
|
|
|
|
subject.stub(:order_cycle) { nil }
|
|
|
|
subject.update_distribution_charge!
|
|
end
|
|
|
|
it "ensures the correct adjustment(s) are created for order cycles" do
|
|
EnterpriseFee.stub(:clear_all_adjustments_on_order)
|
|
line_item = double(:line_item)
|
|
subject.stub(:line_items) { [line_item] }
|
|
subject.stub(:provided_by_order_cycle?) { true }
|
|
|
|
order_cycle = double(:order_cycle)
|
|
OpenFoodNetwork::EnterpriseFeeCalculator.any_instance.
|
|
should_receive(:create_line_item_adjustments_for).
|
|
with(line_item)
|
|
OpenFoodNetwork::EnterpriseFeeCalculator.any_instance.stub(:create_order_adjustments_for)
|
|
subject.stub(:order_cycle) { order_cycle }
|
|
|
|
subject.update_distribution_charge!
|
|
end
|
|
|
|
it "ensures the correct per-order adjustment(s) are created for order cycles" do
|
|
EnterpriseFee.stub(:clear_all_adjustments_on_order)
|
|
subject.stub(:line_items) { [] }
|
|
|
|
order_cycle = double(:order_cycle)
|
|
OpenFoodNetwork::EnterpriseFeeCalculator.any_instance.
|
|
should_receive(:create_order_adjustments_for).
|
|
with(subject)
|
|
|
|
subject.stub(:order_cycle) { order_cycle }
|
|
|
|
subject.update_distribution_charge!
|
|
end
|
|
end
|
|
|
|
describe "looking up whether a line item can be provided by an order cycle" do
|
|
it "returns true when the variant is provided" do
|
|
v = double(:variant)
|
|
line_item = double(:line_item, variant: v)
|
|
order_cycle = double(:order_cycle, variants: [v])
|
|
subject.stub(:order_cycle) { order_cycle }
|
|
|
|
subject.send(:provided_by_order_cycle?, line_item).should be true
|
|
end
|
|
|
|
it "returns false otherwise" do
|
|
v = double(:variant)
|
|
line_item = double(:line_item, variant: v)
|
|
order_cycle = double(:order_cycle, variants: [])
|
|
subject.stub(:order_cycle) { order_cycle }
|
|
|
|
subject.send(:provided_by_order_cycle?, line_item).should be false
|
|
end
|
|
|
|
it "returns false when there is no order cycle" do
|
|
v = double(:variant)
|
|
line_item = double(:line_item, variant: v)
|
|
subject.stub(:order_cycle) { nil }
|
|
|
|
subject.send(:provided_by_order_cycle?, line_item).should be false
|
|
end
|
|
end
|
|
|
|
it "looks up product distribution enterprise fees for a line item" do
|
|
product = double(:product)
|
|
variant = double(:variant, product: product)
|
|
line_item = double(:line_item, variant: variant)
|
|
|
|
product_distribution = double(:product_distribution)
|
|
product.should_receive(:product_distribution_for).with(subject.distributor) { product_distribution }
|
|
|
|
subject.send(:product_distribution_for, line_item).should == product_distribution
|
|
end
|
|
|
|
describe "getting the admin and handling charge" do
|
|
let(:o) { create(:order) }
|
|
let(:li) { create(:line_item, order: o) }
|
|
|
|
it "returns the sum of eligible enterprise fee adjustments" do
|
|
ef = create(:enterprise_fee, calculator: Spree::Calculator::FlatRate.new )
|
|
ef.calculator.set_preference :amount, 123.45
|
|
a = ef.create_adjustment("adjustment", o, o, true)
|
|
|
|
o.admin_and_handling_total.should == 123.45
|
|
end
|
|
|
|
it "does not include ineligible adjustments" do
|
|
ef = create(:enterprise_fee, calculator: Spree::Calculator::FlatRate.new )
|
|
ef.calculator.set_preference :amount, 123.45
|
|
a = ef.create_adjustment("adjustment", o, o, true)
|
|
|
|
a.update_column :eligible, false
|
|
|
|
o.admin_and_handling_total.should == 0
|
|
end
|
|
|
|
it "does not include adjustments that do not originate from enterprise fees" do
|
|
sm = create(:shipping_method, calculator: Spree::Calculator::FlatRate.new )
|
|
sm.calculator.set_preference :amount, 123.45
|
|
sm.create_adjustment("adjustment", o, o, true)
|
|
|
|
o.admin_and_handling_total.should == 0
|
|
end
|
|
|
|
it "does not include adjustments whose source is a line item" do
|
|
ef = create(:enterprise_fee, calculator: Spree::Calculator::PerItem.new )
|
|
ef.calculator.set_preference :amount, 123.45
|
|
ef.create_adjustment("adjustment", li.order, li, true)
|
|
|
|
o.admin_and_handling_total.should == 0
|
|
end
|
|
end
|
|
|
|
describe "an order without shipping method" do
|
|
let(:order) { create(:order) }
|
|
|
|
it "cannot be shipped" do
|
|
order.ready_to_ship?.should == false
|
|
end
|
|
end
|
|
|
|
describe "an unpaid order with a shipment" do
|
|
let(:order) { create(:order_with_totals, shipping_method: shipping_method) }
|
|
let(:shipping_method) { create(:shipping_method) }
|
|
|
|
before do
|
|
order.create_shipment!
|
|
order.reload
|
|
order.state = 'complete'
|
|
order.shipment.update!(order)
|
|
end
|
|
|
|
it "cannot be shipped" do
|
|
order.ready_to_ship?.should == false
|
|
end
|
|
end
|
|
|
|
describe "a paid order without a shipment" do
|
|
let(:order) { create(:order) }
|
|
|
|
before do
|
|
order.payment_state = 'paid'
|
|
order.state = 'complete'
|
|
end
|
|
|
|
it "cannot be shipped" do
|
|
order.ready_to_ship?.should == false
|
|
end
|
|
end
|
|
|
|
describe "a paid order with a shipment" do
|
|
let(:order) { create(:order, shipping_method: shipping_method) }
|
|
let(:shipping_method) { create(:shipping_method) }
|
|
|
|
before do
|
|
order.create_shipment!
|
|
order.payment_state = 'paid'
|
|
order.state = 'complete'
|
|
order.shipment.update!(order)
|
|
end
|
|
|
|
it "can be shipped" do
|
|
order.ready_to_ship?.should == true
|
|
end
|
|
end
|
|
|
|
describe "getting the shipping tax" do
|
|
let(:order) { create(:order, shipping_method: shipping_method) }
|
|
let(:shipping_method) { create(:shipping_method, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 50.0)) }
|
|
|
|
context "with a taxed shipment" do
|
|
before do
|
|
Spree::Config.shipment_inc_vat = true
|
|
Spree::Config.shipping_tax_rate = 0.25
|
|
order.create_shipment!
|
|
end
|
|
|
|
it "returns the shipping tax" do
|
|
order.shipping_tax.should == 10
|
|
end
|
|
end
|
|
|
|
it "returns zero when the order has not been shipped" do
|
|
order.shipping_tax.should == 0
|
|
end
|
|
end
|
|
|
|
describe "getting the enterprise fee tax" do
|
|
let!(:order) { create(:order) }
|
|
let(:enterprise_fee1) { create(:enterprise_fee) }
|
|
let(:enterprise_fee2) { create(:enterprise_fee) }
|
|
let!(:adjustment1) { create(:adjustment, adjustable: order, originator: enterprise_fee1, label: "EF 1", amount: 123, included_tax: 10.00) }
|
|
let!(:adjustment2) { create(:adjustment, adjustable: order, originator: enterprise_fee2, label: "EF 2", amount: 123, included_tax: 2.00) }
|
|
|
|
it "returns a sum of the tax included in all enterprise fees" do
|
|
order.reload.enterprise_fee_tax.should == 12
|
|
end
|
|
end
|
|
|
|
describe "getting the total tax" do
|
|
let(:order) { create(:order, shipping_method: shipping_method) }
|
|
let(:shipping_method) { create(:shipping_method, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 50.0)) }
|
|
let(:enterprise_fee) { create(:enterprise_fee) }
|
|
let!(:adjustment) { create(:adjustment, adjustable: order, originator: enterprise_fee, label: "EF", amount: 123, included_tax: 2) }
|
|
|
|
before do
|
|
Spree::Config.shipment_inc_vat = true
|
|
Spree::Config.shipping_tax_rate = 0.25
|
|
order.create_shipment!
|
|
order.reload
|
|
end
|
|
|
|
it "returns a sum of all tax on the order" do
|
|
order.total_tax.should == 12
|
|
end
|
|
end
|
|
|
|
describe "getting a hash of all taxes" do
|
|
let(:zone) { create(:zone_with_member) }
|
|
let(:coordinator) { create(:distributor_enterprise, charges_sales_tax: true) }
|
|
|
|
let(:tax_rate10) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.1, zone: zone) }
|
|
let(:tax_rate15) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.15, zone: zone) }
|
|
let(:tax_rate20) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.2, zone: zone) }
|
|
let(:tax_rate25) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.25, zone: zone) }
|
|
let(:tax_category10) { create(:tax_category, tax_rates: [tax_rate10]) }
|
|
let(:tax_category15) { create(:tax_category, tax_rates: [tax_rate15]) }
|
|
let(:tax_category20) { create(:tax_category, tax_rates: [tax_rate20]) }
|
|
let(:tax_category25) { create(:tax_category, tax_rates: [tax_rate25]) }
|
|
|
|
let(:variant) { create(:variant, product: create(:product, tax_category: tax_category10)) }
|
|
let(:shipping_method) { create(:shipping_method, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 46.0)) }
|
|
let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: tax_category20, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 48.0)) }
|
|
let(:additional_adjustment) { create(:adjustment, amount: 50.0, included_tax: tax_rate25.compute_tax(50.0)) }
|
|
|
|
let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, coordinator_fees: [enterprise_fee], distributors: [coordinator], variants: [variant]) }
|
|
let!(:order) { create(:order, shipping_method: shipping_method, bill_address: create(:address), order_cycle: order_cycle, distributor: coordinator, adjustments: [additional_adjustment]) }
|
|
let!(:line_item) { create(:line_item, order: order, variant: variant, price: 44.0) }
|
|
|
|
before do
|
|
Spree::Config.shipment_inc_vat = true
|
|
Spree::Config.shipping_tax_rate = tax_rate15.amount
|
|
order.create_shipment!
|
|
Spree::TaxRate.adjust(order)
|
|
order.reload.update_distribution_charge!
|
|
end
|
|
|
|
it "returns a hash with all 3 taxes" do
|
|
expect(order.tax_adjustment_totals.size).to eq(4)
|
|
end
|
|
|
|
it "contains tax on line_item" do
|
|
expect(order.tax_adjustment_totals[tax_rate10]).to eq(4.0)
|
|
end
|
|
|
|
it "contains tax on shipping_fee" do
|
|
expect(order.tax_adjustment_totals[tax_rate15]).to eq(6.0)
|
|
end
|
|
|
|
it "contains tax on enterprise_fee" do
|
|
expect(order.tax_adjustment_totals[tax_rate20]).to eq(8.0)
|
|
end
|
|
|
|
it "contains tax on order adjustment" do
|
|
expect(order.tax_adjustment_totals[tax_rate25]).to eq(10.0)
|
|
end
|
|
end
|
|
|
|
describe "setting the distributor" do
|
|
it "sets the distributor when no order cycle is set" do
|
|
d = create(:distributor_enterprise)
|
|
subject.set_distributor! d
|
|
subject.distributor.should == d
|
|
end
|
|
|
|
it "keeps the order cycle when it is available at the new distributor" do
|
|
d = create(:distributor_enterprise)
|
|
oc = create(:simple_order_cycle)
|
|
create(:exchange, order_cycle: oc, sender: oc.coordinator, receiver: d, incoming: false)
|
|
|
|
subject.order_cycle = oc
|
|
subject.set_distributor! d
|
|
|
|
subject.distributor.should == d
|
|
subject.order_cycle.should == oc
|
|
end
|
|
|
|
it "clears the order cycle if it is not available at that distributor" do
|
|
d = create(:distributor_enterprise)
|
|
oc = create(:simple_order_cycle)
|
|
|
|
subject.order_cycle = oc
|
|
subject.set_distributor! d
|
|
|
|
subject.distributor.should == d
|
|
subject.order_cycle.should be_nil
|
|
end
|
|
|
|
it "clears the distributor when setting to nil" do
|
|
d = create(:distributor_enterprise)
|
|
subject.set_distributor! d
|
|
subject.set_distributor! nil
|
|
|
|
subject.distributor.should be_nil
|
|
end
|
|
end
|
|
|
|
describe "removing an item from the order" do
|
|
let(:order) { create(:order) }
|
|
let(:v1) { create(:variant) }
|
|
let(:v2) { create(:variant) }
|
|
let(:v3) { create(:variant) }
|
|
|
|
before do
|
|
order.add_variant v1
|
|
order.add_variant v2
|
|
end
|
|
|
|
it "removes the variant's line item" do
|
|
order.remove_variant v1
|
|
order.line_items(:reload).map(&:variant).should == [v2]
|
|
end
|
|
|
|
it "does nothing when there is no matching line item" do
|
|
expect do
|
|
order.remove_variant v3
|
|
end.to change(order.line_items(:reload), :count).by(0)
|
|
end
|
|
end
|
|
|
|
describe "emptying the order" do
|
|
it "removes shipping method" do
|
|
subject.shipping_method = create(:shipping_method)
|
|
subject.save!
|
|
subject.empty!
|
|
subject.shipping_method.should == nil
|
|
end
|
|
|
|
it "removes payments" do
|
|
subject.payments << create(:payment)
|
|
subject.save!
|
|
subject.empty!
|
|
subject.payments.should == []
|
|
end
|
|
end
|
|
|
|
describe "setting the order cycle" do
|
|
let(:oc) { create(:simple_order_cycle) }
|
|
|
|
it "empties the cart when changing the order cycle" do
|
|
subject.should_receive(:empty!)
|
|
subject.set_order_cycle! oc
|
|
end
|
|
|
|
it "doesn't empty the cart if the order cycle is not different" do
|
|
subject.should_not_receive(:empty!)
|
|
subject.set_order_cycle! subject.order_cycle
|
|
end
|
|
|
|
it "sets the order cycle when no distributor is set" do
|
|
subject.set_order_cycle! oc
|
|
subject.order_cycle.should == oc
|
|
end
|
|
|
|
it "keeps the distributor when it is available in the new order cycle" do
|
|
d = create(:distributor_enterprise)
|
|
create(:exchange, order_cycle: oc, sender: oc.coordinator, receiver: d, incoming: false)
|
|
|
|
subject.distributor = d
|
|
subject.set_order_cycle! oc
|
|
|
|
subject.order_cycle.should == oc
|
|
subject.distributor.should == d
|
|
end
|
|
|
|
it "clears the distributor if it is not available at that order cycle" do
|
|
d = create(:distributor_enterprise)
|
|
|
|
subject.distributor = d
|
|
subject.set_order_cycle! oc
|
|
|
|
subject.order_cycle.should == oc
|
|
subject.distributor.should be_nil
|
|
end
|
|
|
|
it "clears the order cycle when setting to nil" do
|
|
d = create(:distributor_enterprise)
|
|
subject.set_order_cycle! oc
|
|
subject.distributor = d
|
|
|
|
subject.set_order_cycle! nil
|
|
|
|
subject.order_cycle.should be_nil
|
|
subject.distributor.should == d
|
|
end
|
|
end
|
|
|
|
context "validating distributor changes" do
|
|
it "checks that a distributor is available when changing" do
|
|
set_feature_toggle :order_cycles, false
|
|
order_enterprise = FactoryBot.create(:enterprise, id: 1, :name => "Order Enterprise")
|
|
subject.distributor = order_enterprise
|
|
product1 = FactoryBot.create(:product)
|
|
product2 = FactoryBot.create(:product)
|
|
product3 = FactoryBot.create(:product)
|
|
variant11 = FactoryBot.create(:variant, product: product1)
|
|
variant12 = FactoryBot.create(:variant, product: product1)
|
|
variant21 = FactoryBot.create(:variant, product: product2)
|
|
variant31 = FactoryBot.create(:variant, product: product3)
|
|
variant32 = FactoryBot.create(:variant, product: product3)
|
|
|
|
# Product Distributions
|
|
# Order Enterprise sells product 1 and product 3
|
|
FactoryBot.create(:product_distribution, product: product1, distributor: order_enterprise)
|
|
FactoryBot.create(:product_distribution, product: product3, distributor: order_enterprise)
|
|
|
|
# Build the current order
|
|
line_item1 = FactoryBot.create(:line_item, order: subject, variant: variant11)
|
|
line_item2 = FactoryBot.create(:line_item, order: subject, variant: variant12)
|
|
line_item3 = FactoryBot.create(:line_item, order: subject, variant: variant31)
|
|
subject.reload
|
|
subject.line_items = [line_item1,line_item2,line_item3]
|
|
|
|
test_enterprise = FactoryBot.create(:enterprise, id: 2, :name => "Test Enterprise")
|
|
# Test Enterprise sells only product 1
|
|
FactoryBot.create(:product_distribution, product: product1, distributor: test_enterprise)
|
|
|
|
subject.distributor = test_enterprise
|
|
subject.should_not be_valid
|
|
subject.errors.messages.should == {:base => ["Distributor or order cycle cannot supply the products in your cart"]}
|
|
end
|
|
end
|
|
|
|
describe "scopes" do
|
|
describe "not_state" do
|
|
before do
|
|
setup_email
|
|
end
|
|
|
|
it "finds only orders not in specified state" do
|
|
o = FactoryBot.create(:completed_order_with_totals)
|
|
o.cancel!
|
|
Spree::Order.not_state(:canceled).should_not include o
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "shipping address prepopulation" do
|
|
let(:distributor) { create(:distributor_enterprise) }
|
|
let(:order) { build(:order, distributor: distributor) }
|
|
|
|
before do
|
|
order.ship_address = distributor.address.clone
|
|
order.save # just to trigger our autopopulate the first time ;)
|
|
end
|
|
|
|
it "autopopulates the shipping address on save" do
|
|
order.should_receive(:shipping_address_from_distributor).and_return true
|
|
order.save
|
|
end
|
|
|
|
it "populates the shipping address if the shipping method doesn't require a delivery address" do
|
|
order.shipping_method = create(:shipping_method, require_ship_address: false)
|
|
order.ship_address.update_attribute :firstname, "will"
|
|
order.save
|
|
order.ship_address.firstname.should == distributor.address.firstname
|
|
end
|
|
|
|
it "does not populate the shipping address if the shipping method requires a delivery address" do
|
|
order.shipping_method = create(:shipping_method, require_ship_address: true)
|
|
order.ship_address.update_attribute :firstname, "will"
|
|
order.save
|
|
order.ship_address.firstname.should == "will"
|
|
end
|
|
|
|
it "doesn't attempt to create a shipment if the order is not yet valid" do
|
|
order.shipping_method = create(:shipping_method, require_ship_address: false)
|
|
#Shipment.should_not_r
|
|
order.create_shipment!
|
|
end
|
|
end
|
|
|
|
describe "checking if an order is an account invoice" do
|
|
let(:accounts_distributor) { create(:distributor_enterprise) }
|
|
let(:order_account_invoice) { create(:order, distributor: accounts_distributor) }
|
|
let(:order_general) { create(:order, distributor: create(:distributor_enterprise)) }
|
|
|
|
before do
|
|
Spree::Config.accounts_distributor_id = accounts_distributor.id
|
|
end
|
|
|
|
it "returns true when the order is distributed by the accounts distributor" do
|
|
order_account_invoice.should be_account_invoice
|
|
end
|
|
|
|
it "returns false otherwise" do
|
|
order_general.should_not be_account_invoice
|
|
end
|
|
end
|
|
|
|
describe "sending confirmation emails" do
|
|
let!(:distributor) { create(:distributor_enterprise) }
|
|
let!(:order) { create(:order, distributor: distributor) }
|
|
|
|
it "sends confirmation emails" do
|
|
expect do
|
|
order.deliver_order_confirmation_email
|
|
end.to enqueue_job ConfirmOrderJob
|
|
end
|
|
|
|
it "does not send confirmation emails when distributor is the accounts_distributor" do
|
|
Spree::Config.set({ accounts_distributor_id: distributor.id })
|
|
|
|
expect do
|
|
order.deliver_order_confirmation_email
|
|
end.to_not enqueue_job ConfirmOrderJob
|
|
end
|
|
|
|
it "does not send confirmation emails when the order belongs to a subscription" do
|
|
create(:proxy_order, order: order)
|
|
|
|
expect do
|
|
order.deliver_order_confirmation_email
|
|
end.to_not enqueue_job ConfirmOrderJob
|
|
end
|
|
end
|
|
|
|
describe "associating a customer" do
|
|
let(:distributor) { create(:distributor_enterprise) }
|
|
let!(:order) { create(:order, distributor: distributor) }
|
|
|
|
context "when an email address is available for the order" do
|
|
before { allow(order).to receive(:email_for_customer) { "existing@email.com" }}
|
|
|
|
context "and a customer for order.distributor and order#email_for_customer already exists" do
|
|
let!(:customer) { create(:customer, enterprise: distributor, email: "existing@email.com" ) }
|
|
|
|
it "associates the order with the existing customer, and returns the customer" do
|
|
result = order.send(:associate_customer)
|
|
expect(order.customer).to eq customer
|
|
expect(result).to eq customer
|
|
end
|
|
end
|
|
|
|
context "and a customer for order.distributor and order.user.email does not alread exist" do
|
|
let!(:customer) { create(:customer, enterprise: distributor, email: 'some-other-email@email.com') }
|
|
|
|
it "does not set the customer and returns nil" do
|
|
result = order.send(:associate_customer)
|
|
expect(order.customer).to be_nil
|
|
expect(result).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
context "when an email address is not available for the order" do
|
|
let!(:customer) { create(:customer, enterprise: distributor) }
|
|
before { allow(order).to receive(:email_for_customer) { nil }}
|
|
|
|
it "does not set the customer and returns nil" do
|
|
result = order.send(:associate_customer)
|
|
expect(order.customer).to be_nil
|
|
expect(result).to be_nil
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "ensuring a customer is linked" do
|
|
let(:distributor) { create(:distributor_enterprise) }
|
|
let!(:order) { create(:order, distributor: distributor) }
|
|
|
|
context "when a customer has already been linked to the order" do
|
|
let!(:customer) { create(:customer, enterprise: distributor, email: "existing@email.com" ) }
|
|
before { order.update_attribute(:customer_id, customer.id) }
|
|
|
|
it "does nothing" do
|
|
order.send(:ensure_customer)
|
|
expect(order.customer).to eq customer
|
|
end
|
|
end
|
|
|
|
context "when a customer not been linked to the order" do
|
|
context "but one matching order#email_for_customer already exists" do
|
|
let!(:customer) { create(:customer, enterprise: distributor, email: 'some-other-email@email.com') }
|
|
before { allow(order).to receive(:email_for_customer) { 'some-other-email@email.com' } }
|
|
|
|
it "links the customer customer to the order" do
|
|
expect(order.customer).to be_nil
|
|
expect{order.send(:ensure_customer)}.to_not change{Customer.count}
|
|
expect(order.customer).to eq customer
|
|
end
|
|
end
|
|
|
|
context "and order#email_for_customer does not match any existing customers" do
|
|
before {
|
|
order.bill_address = create(:address)
|
|
order.ship_address = create(:address)
|
|
}
|
|
it "creates a new customer with defaut name and addresses" do
|
|
expect(order.customer).to be_nil
|
|
expect{order.send(:ensure_customer)}.to change{Customer.count}.by 1
|
|
expect(order.customer).to be_a Customer
|
|
|
|
expect(order.customer.name).to eq order.bill_address.full_name
|
|
expect(order.customer.bill_address.same_as?(order.bill_address)).to be true
|
|
expect(order.customer.ship_address.same_as?(order.ship_address)).to be true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "when a guest order is placed with a registered email" do
|
|
let(:order) { create(:order_with_totals_and_distribution, user: nil) }
|
|
let(:payment_method) { create(:payment_method, distributors: [order.distributor]) }
|
|
let(:shipping_method) { create(:shipping_method, distributors: [order.distributor]) }
|
|
let(:user) { create(:user, email: 'registered@email.com') }
|
|
|
|
before do
|
|
order.bill_address = create(:address)
|
|
order.ship_address = create(:address)
|
|
order.shipping_method = shipping_method
|
|
order.email = user.email
|
|
order.user = nil
|
|
order.state = 'cart'
|
|
end
|
|
|
|
it "returns a validation error" do
|
|
expect{order.next}.to change(order.errors, :count).from(0).to(1)
|
|
expect(order.errors.messages[:base]).to eq [ I18n.t('devise.failure.already_registered') ]
|
|
expect(order.state).to eq 'cart'
|
|
end
|
|
end
|
|
|
|
describe "a completed order with shipping and transaction fees" do
|
|
let(:distributor) { create(:distributor_enterprise, charges_sales_tax: true, allow_order_changes: true) }
|
|
let(:order) { create(:completed_order_with_fees, distributor: distributor, shipping_fee: shipping_fee, payment_fee: payment_fee) }
|
|
let(:shipping_fee) { 3 }
|
|
let(:payment_fee) { 5 }
|
|
let(:item_num) { order.line_items.length }
|
|
let(:expected_fees) { item_num * (shipping_fee + payment_fee) }
|
|
|
|
before do
|
|
Spree::Config.shipment_inc_vat = true
|
|
Spree::Config.shipping_tax_rate = 0.25
|
|
|
|
# Sanity check the fees
|
|
expect(order.adjustments.length).to eq 2
|
|
expect(item_num).to eq 2
|
|
expect(order.adjustment_total).to eq expected_fees
|
|
expect(order.shipment.adjustment.included_tax).to eq 1.2
|
|
end
|
|
|
|
context "removing line_items" do
|
|
it "updates shipping and transaction fees" do
|
|
# Setting quantity of an item to zero
|
|
order.update_attributes(line_items_attributes: [{id: order.line_items.first.id, quantity: 0}])
|
|
|
|
# Check if fees got updated
|
|
order.reload
|
|
expect(order.adjustment_total).to eq expected_fees - shipping_fee - payment_fee
|
|
expect(order.shipment.adjustment.included_tax).to eq 0.6
|
|
end
|
|
|
|
context "when finalized fee adjustments exist on the order" do
|
|
let(:payment_fee_adjustment) { order.adjustments.payment_fee.first }
|
|
let(:shipping_fee_adjustment) { order.adjustments.shipping.first }
|
|
|
|
before do
|
|
payment_fee_adjustment.finalize!
|
|
shipping_fee_adjustment.finalize!
|
|
order.reload
|
|
end
|
|
|
|
it "does not attempt to update such adjustments" do
|
|
order.update_attributes(line_items_attributes: [{id: order.line_items.first.id, quantity: 0}])
|
|
|
|
# Check if fees got updated
|
|
order.reload
|
|
expect(order.adjustment_total).to eq expected_fees
|
|
expect(order.shipment.adjustment.included_tax).to eq 1.2
|
|
end
|
|
end
|
|
end
|
|
|
|
context "changing the shipping method to one without fees" do
|
|
let(:shipping_method) { create(:shipping_method, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 0)) }
|
|
|
|
it "updates shipping fees" do
|
|
# Change the shipping method
|
|
order.shipment.update_attributes(shipping_method_id: shipping_method.id)
|
|
order.save
|
|
|
|
# Check if fees got updated
|
|
order.reload
|
|
expect(order.adjustment_total).to eq expected_fees - (item_num * shipping_fee)
|
|
expect(order.shipment.adjustment.included_tax).to eq 0
|
|
end
|
|
end
|
|
|
|
context "changing the payment method to one without fees" do
|
|
let(:payment_method) { create(:payment_method, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 0)) }
|
|
|
|
it "removes transaction fees" do
|
|
# Change the payment method
|
|
order.payments.first.update_attributes(payment_method_id: payment_method.id)
|
|
order.save
|
|
|
|
# Check if fees got updated
|
|
order.reload
|
|
expect(order.adjustment_total).to eq expected_fees - (item_num * payment_fee)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "retrieving previously ordered items" do
|
|
let(:distributor) { create(:distributor_enterprise) }
|
|
let(:order_cycle) { create(:simple_order_cycle) }
|
|
let!(:order) { create(:order, distributor: distributor, order_cycle: order_cycle) }
|
|
|
|
it "returns no items if nothing has been ordered" do
|
|
expect(order.finalised_line_items).to eq []
|
|
end
|
|
|
|
context "when no order has been finalised in this order cycle" do
|
|
let(:product) { create(:product) }
|
|
|
|
it "returns no items even though the cart contains items" do
|
|
order.add_variant(product.master, 1, 3)
|
|
expect(order.finalised_line_items).to eq []
|
|
end
|
|
end
|
|
|
|
context "when an order has been finalised in this order cycle" do
|
|
let!(:prev_order) { create(:completed_order_with_totals, distributor: distributor, order_cycle: order_cycle, user: order.user) }
|
|
let!(:prev_order2) { create(:completed_order_with_totals, distributor: distributor, order_cycle: order_cycle, user: order.user) }
|
|
let(:product) { create(:product) }
|
|
|
|
it "returns previous items" do
|
|
prev_order.add_variant(product.master, 1, 3)
|
|
prev_order2.reload # to get the right response from line_items
|
|
expect(order.finalised_line_items.length).to eq 3
|
|
expect(order.finalised_line_items).to match_array(prev_order.line_items + prev_order2.line_items)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "determining checkout steps for an order" do
|
|
let!(:enterprise) { create(:enterprise) }
|
|
let!(:order) { create(:order, distributor: enterprise) }
|
|
let!(:payment_method) { create(:stripe_payment_method, distributor_ids: [enterprise.id], preferred_enterprise_id: enterprise.id) }
|
|
let!(:payment) { create(:payment, order: order, payment_method: payment_method) }
|
|
|
|
it "does not include the :confirm step" do
|
|
expect(order.checkout_steps).to_not include "confirm"
|
|
end
|
|
end
|
|
|
|
describe "finding pending_payments" do
|
|
let!(:order) { create(:order ) }
|
|
let!(:payment) { create(:payment, order: order, state: 'checkout') }
|
|
|
|
context "when the order is not a subscription" do
|
|
it "returns the payments on the order" do
|
|
expect(order.reload.pending_payments).to eq [payment]
|
|
end
|
|
end
|
|
|
|
context "when the order is a subscription" do
|
|
let!(:proxy_order) { create(:proxy_order, order: order) }
|
|
let!(:order_cycle) { proxy_order.order_cycle }
|
|
|
|
context "and order_cycle has no order_close_at set" do
|
|
before { order.order_cycle.update_attributes(orders_close_at: nil) }
|
|
|
|
it "returns the payments on the order" do
|
|
expect(order.reload.pending_payments).to eq [payment]
|
|
end
|
|
end
|
|
|
|
context "and the order_cycle has closed" do
|
|
before { order.order_cycle.update_attributes(orders_close_at: 5.minutes.ago) }
|
|
|
|
it "returns the payments on the order" do
|
|
expect(order.reload.pending_payments).to eq [payment]
|
|
end
|
|
end
|
|
|
|
context "and the order_cycle has not yet closed" do
|
|
before { order.order_cycle.update_attributes(orders_close_at: 5.minutes.from_now) }
|
|
|
|
it "returns an empty array" do
|
|
expect(order.reload.pending_payments).to eq []
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#restart_checkout!' do
|
|
let(:order) { build(:order) }
|
|
|
|
context 'when the order is complete' do
|
|
before { order.completed_at = Time.zone.now }
|
|
|
|
it 'raises' do
|
|
expect { order.restart_checkout! }
|
|
.to raise_error(StateMachine::InvalidTransition)
|
|
end
|
|
end
|
|
|
|
context 'when the is not complete' do
|
|
before { order.completed_at = nil }
|
|
|
|
it 'transitions to :cart state' do
|
|
order.restart_checkout!
|
|
expect(order.state).to eq('cart')
|
|
end
|
|
end
|
|
end
|
|
|
|
describe '#charge_shipping_and_payment_fees!' do
|
|
let(:order) do
|
|
build(:order, shipping_method: build(:shipping_method))
|
|
end
|
|
|
|
context 'after transitioning to payment' do
|
|
before do
|
|
order.state = 'delivery' # payment's previous state
|
|
|
|
allow(order).to receive(:payment_required?) { true }
|
|
allow(order).to receive(:charge_shipping_and_payment_fees!)
|
|
end
|
|
|
|
it 'calls charge_shipping_and_payment_fees!' do
|
|
order.next
|
|
expect(order).to have_received(:charge_shipping_and_payment_fees!)
|
|
end
|
|
end
|
|
end
|
|
end
|