/controllers/spree/order_populator_decorator (with a class_eval) is now /services/CartService with no dependency to Spree::OrderPopulator.

This commit is contained in:
luisramos0
2018-08-12 20:56:44 +01:00
parent 6caa361354
commit 05bfc098ff
7 changed files with 365 additions and 356 deletions

View File

@@ -9,16 +9,16 @@ class CartController < BaseController
# costly Spree::Order#update!, which only needs to be run once. We avoid this by disabling
# callbacks on Spree::Adjustment and then manually invoke Spree::Order#update! on success.
Spree::Adjustment.without_callbacks do
populator = Spree::OrderPopulator.new(current_order(true), current_currency)
cart_service = CartService.new(current_order(true), current_currency)
if populator.populate(params.slice(:products, :variants, :quantity), true)
if cart_service.populate(params.slice(:products, :variants, :quantity), true)
fire_event('spree.cart.add')
fire_event('spree.order.contents_changed')
current_order.cap_quantity_at_stock!
current_order.update!
variant_ids = variant_ids_in(populator.variants_h)
variant_ids = variant_ids_in(cart_service.variants_h)
render json: { error: false, stock_levels: stock_levels(current_order, variant_ids) },
status: 200

View File

@@ -1,7 +1,15 @@
require 'open_food_network/scope_variant_to_hub'
Spree::OrderPopulator.class_eval do
class CartService
attr_accessor :order, :currency
attr_reader :variants_h
attr_reader :errors
def initialize(order, currency)
@order = order
@currency = currency
@errors = ActiveModel::Errors.new(self)
end
def populate(from_hash, overwrite = false)
@distributor, @order_cycle = distributor_and_order_cycle
@@ -32,27 +40,6 @@ Spree::OrderPopulator.class_eval do
valid?
end
def read_variants(data)
@variants_h = read_products_hash(data) +
read_variants_hash(data)
end
def read_products_hash(data)
(data[:products] || []).map do |product_id, variant_id|
{variant_id: variant_id, quantity: data[:quantity]}
end
end
def read_variants_hash(data)
(data[:variants] || []).map do |variant_id, quantity|
if quantity.is_a?(Hash)
{variant_id: variant_id, quantity: quantity[:quantity], max_quantity: quantity[:max_quantity]}
else
{variant_id: variant_id, quantity: quantity}
end
end
end
def attempt_cart_add(variant_id, quantity, max_quantity = nil)
quantity = quantity.to_i
max_quantity = max_quantity.to_i if max_quantity
@@ -82,14 +69,38 @@ Spree::OrderPopulator.class_eval do
[quantity_to_add, max_quantity_to_add]
end
private
def read_variants(data)
@variants_h = read_products_hash(data) +
read_variants_hash(data)
end
def read_products_hash(data)
(data[:products] || []).map do |product_id, variant_id|
{variant_id: variant_id, quantity: data[:quantity]}
end
end
def read_variants_hash(data)
(data[:variants] || []).map do |variant_id, quantity|
if quantity.is_a?(Hash)
{variant_id: variant_id, quantity: quantity[:quantity], max_quantity: quantity[:max_quantity]}
else
{variant_id: variant_id, quantity: quantity}
end
end
end
def valid?
errors.empty?
end
def cart_remove(variant_id)
variant = Spree::Variant.find(variant_id)
@order.remove_variant(variant)
end
private
def distributor_and_order_cycle
[@order.distributor, @order.order_cycle]
end

View File

@@ -9,9 +9,9 @@ describe CartController, type: :controller do
it "returns stock levels as JSON" do
controller.stub(:variant_ids_in) { [123] }
controller.stub(:stock_levels) { 'my_stock_levels' }
Spree::OrderPopulator.stub(:new).and_return(populator = double())
populator.stub(:populate) { true }
populator.stub(:variants_h) { {} }
CartService.stub(:new).and_return(cart_service = double())
cart_service.stub(:populate) { true }
cart_service.stub(:variants_h) { {} }
xhr :post, :populate, use_route: :spree, format: :json
@@ -56,7 +56,7 @@ describe CartController, type: :controller do
end
end
it "extracts variant ids from the populator" do
it "extracts variant ids from the cart service" do
variants_h = [{:variant_id=>"900", :quantity=>2, :max_quantity=>nil},
{:variant_id=>"940", :quantity=>3, :max_quantity=>3}]
@@ -80,23 +80,23 @@ describe CartController, type: :controller do
end
it "returns HTTP success when successful" do
Spree::OrderPopulator.stub(:new).and_return(populator = double())
populator.stub(:populate) { true }
populator.stub(:variants_h) { {} }
CartService.stub(:new).and_return(cart_service = double())
cart_service.stub(:populate) { true }
cart_service.stub(:variants_h) { {} }
xhr :post, :populate, use_route: :spree, format: :json
response.status.should == 200
end
it "returns failure when unsuccessful" do
Spree::OrderPopulator.stub(:new).and_return(populator = double())
populator.stub(:populate).and_return false
CartService.stub(:new).and_return(cart_service = double())
cart_service.stub(:populate).and_return false
xhr :post, :populate, use_route: :spree, format: :json
response.status.should == 412
end
it "tells populator to overwrite" do
Spree::OrderPopulator.stub(:new).and_return(populator = double())
populator.should_receive(:populate).with({}, true)
it "tells cart_service to overwrite" do
CartService.stub(:new).and_return(cart_service = double())
cart_service.should_receive(:populate).with({}, true)
xhr :post, :populate, use_route: :spree, format: :json
end
end

View File

@@ -36,8 +36,8 @@ describe ProductDistribution do
# When I add the product to the order, an adjustment should be made
expect do
op = Spree::OrderPopulator.new order, 'AU'
op.populate products: {product.id => product.master.id}, quantity: 1, distributor_id: distributor.id
cart_service = CartService.new order, 'AU'
cart_service.populate products: {product.id => product.master.id}, quantity: 1, distributor_id: distributor.id
# Normally the controller would fire this event when the order's contents are changed
fire_order_contents_changed_event(order.user, order)

View File

@@ -1,312 +0,0 @@
require 'spec_helper'
module Spree
describe OrderPopulator do
let(:order) { double(:order, id: 123) }
let(:currency) { double(:currency) }
let(:params) { {} }
let(:distributor) { double(:distributor) }
let(:order_cycle) { double(:order_cycle) }
let(:op) { OrderPopulator.new(order, currency) }
context "end-to-end" do
let(:order) { create(:order, distributor: distributor, order_cycle: order_cycle) }
let(:distributor) { create(:distributor_enterprise) }
let(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], variants: [v]) }
let(:op) { OrderPopulator.new(order, nil) }
let(:v) { create(:variant) }
describe "populate" do
it "adds a variant" do
op.populate({variants: {v.id.to_s => {quantity: '1', max_quantity: '2'}}}, true)
li = order.find_line_item_by_variant(v)
li.should be
li.quantity.should == 1
li.max_quantity.should == 2
li.final_weight_volume.should == 1.0
end
it "updates a variant's quantity, max quantity and final_weight_volume" do
order.add_variant v, 1, 2
op.populate({variants: {v.id.to_s => {quantity: '2', max_quantity: '3'}}}, true)
li = order.find_line_item_by_variant(v)
li.should be
li.quantity.should == 2
li.max_quantity.should == 3
li.final_weight_volume.should == 2.0
end
it "removes a variant" do
order.add_variant v, 1, 2
op.populate({variants: {}}, true)
order.line_items(:reload)
li = order.find_line_item_by_variant(v)
li.should_not be
end
end
end
describe "populate" do
before do
op.should_receive(:distributor_and_order_cycle).
and_return([distributor, order_cycle])
end
it "checks that distribution can supply all products in the cart" do
op.should_receive(:distribution_can_supply_products_in_cart).
with(distributor, order_cycle).and_return(false)
op.populate(params).should be false
op.errors.to_a.should == ["That distributor or order cycle can't supply all the products in your cart. Please choose another."]
end
it "locks the order" do
op.stub(:distribution_can_supply_products_in_cart).and_return(true)
order.should_receive(:with_lock)
op.populate(params, true)
end
it "attempts cart add with max_quantity" do
op.stub(:distribution_can_supply_products_in_cart).and_return true
params = {variants: {"1" => {quantity: 1, max_quantity: 2}}}
order.stub(:with_lock).and_yield
op.stub(:varies_from_cart) { true }
op.stub(:variants_removed) { [] }
op.should_receive(:attempt_cart_add).with("1", 1, 2).and_return true
op.populate(params, true)
end
end
describe "varies_from_cart" do
let(:variant) { double(:variant, id: 123) }
it "returns true when item is not in cart and a quantity is specified" do
op.should_receive(:line_item_for_variant_id).with(variant.id).and_return(nil)
op.send(:varies_from_cart, {variant_id: variant.id, quantity: '2'}).should be true
end
it "returns true when item is not in cart and a max_quantity is specified" do
op.should_receive(:line_item_for_variant_id).with(variant.id).and_return(nil)
op.send(:varies_from_cart, {variant_id: variant.id, quantity: '0', max_quantity: '2'}).should be true
end
it "returns false when item is not in cart and no quantity or max_quantity are specified" do
op.should_receive(:line_item_for_variant_id).with(variant.id).and_return(nil)
op.send(:varies_from_cart, {variant_id: variant.id, quantity: '0'}).should be false
end
it "returns true when quantity varies" do
li = double(:line_item, quantity: 1, max_quantity: nil)
op.stub(:line_item_for_variant_id) { li }
op.send(:varies_from_cart, {variant_id: variant.id, quantity: '2'}).should be true
end
it "returns true when max_quantity varies" do
li = double(:line_item, quantity: 1, max_quantity: nil)
op.stub(:line_item_for_variant_id) { li }
op.send(:varies_from_cart, {variant_id: variant.id, quantity: '1', max_quantity: '3'}).should be true
end
it "returns false when max_quantity varies only in nil vs 0" do
li = double(:line_item, quantity: 1, max_quantity: nil)
op.stub(:line_item_for_variant_id) { li }
op.send(:varies_from_cart, {variant_id: variant.id, quantity: '1'}).should be false
end
it "returns false when both are specified and neither varies" do
li = double(:line_item, quantity: 1, max_quantity: 2)
op.stub(:line_item_for_variant_id) { li }
op.send(:varies_from_cart, {variant_id: variant.id, quantity: '1', max_quantity: '2'}).should be false
end
end
describe "variants_removed" do
it "returns the variant ids when one is in the cart but not in those given" do
op.stub(:variant_ids_in_cart) { [123] }
op.send(:variants_removed, []).should == [123]
end
it "returns nothing when all items in the cart are provided" do
op.stub(:variant_ids_in_cart) { [123] }
op.send(:variants_removed, [{variant_id: '123'}]).should == []
end
it "returns nothing when items are added to cart" do
op.stub(:variant_ids_in_cart) { [123] }
op.send(:variants_removed, [{variant_id: '123'}, {variant_id: '456'}]).should == []
end
it "does not return duplicates" do
op.stub(:variant_ids_in_cart) { [123, 123] }
op.send(:variants_removed, []).should == [123]
end
end
describe "attempt_cart_add" do
let(:variant) { double(:variant, on_hand: 250) }
let(:quantity) { 123 }
before do
Spree::Variant.stub(:find).and_return(variant)
VariantOverride.stub(:for).and_return(nil)
end
it "performs additional validations" do
op.should_receive(:check_order_cycle_provided_for).with(variant).and_return(true)
op.should_receive(:check_variant_available_under_distribution).with(variant).
and_return(true)
order.should_receive(:add_variant).with(variant, quantity, nil, currency)
op.attempt_cart_add(333, quantity.to_s)
end
it "filters quantities through #quantities_to_add" do
op.should_receive(:quantities_to_add).with(variant, 123, 123).
and_return([5, 5])
op.stub(:check_order_cycle_provided_for) { true }
op.stub(:check_variant_available_under_distribution) { true }
order.should_receive(:add_variant).with(variant, 5, 5, currency)
op.attempt_cart_add(333, quantity.to_s, quantity.to_s)
end
it "removes variants which have become out of stock" do
op.should_receive(:quantities_to_add).with(variant, 123, 123).
and_return([0, 0])
op.stub(:check_order_cycle_provided_for) { true }
op.stub(:check_variant_available_under_distribution) { true }
order.should_receive(:remove_variant).with(variant)
order.should_receive(:add_variant).never
op.attempt_cart_add(333, quantity.to_s, quantity.to_s)
end
end
describe "quantities_to_add" do
let(:v) { double(:variant, on_hand: 10) }
context "when backorders are not allowed" do
context "when max_quantity is not provided" do
it "returns full amount when available" do
op.quantities_to_add(v, 5, nil).should == [5, nil]
end
it "returns a limited amount when not entirely available" do
op.quantities_to_add(v, 15, nil).should == [10, nil]
end
end
context "when max_quantity is provided" do
it "returns full amount when available" do
op.quantities_to_add(v, 5, 6).should == [5, 6]
end
it "also returns the full amount when not entirely available" do
op.quantities_to_add(v, 15, 16).should == [10, 16]
end
end
end
context "when backorders are allowed" do
before do
Spree::Config.allow_backorders = true
end
it "does not limit quantity" do
op.quantities_to_add(v, 15, nil).should == [15, nil]
end
it "does not limit max_quantity" do
op.quantities_to_add(v, 15, 16).should == [15, 16]
end
end
end
describe "validations" do
describe "determining if distributor can supply products in cart" do
it "delegates to DistributionChangeValidator" do
dcv = double(:dcv)
dcv.should_receive(:can_change_to_distribution?).with(distributor, order_cycle).and_return(true)
DistributionChangeValidator.should_receive(:new).with(order).and_return(dcv)
op.send(:distribution_can_supply_products_in_cart, distributor, order_cycle).should be true
end
end
describe "checking order cycle is provided for a variant, OR is not needed" do
let(:variant) { double(:variant) }
it "returns false and errors when order cycle is not provided and is required" do
op.stub(:order_cycle_required_for).and_return true
op.send(:check_order_cycle_provided_for, variant).should be false
op.errors.to_a.should == ["Please choose an order cycle for this order."]
end
it "returns true when order cycle is provided" do
op.stub(:order_cycle_required_for).and_return true
op.instance_variable_set :@order_cycle, double(:order_cycle)
op.send(:check_order_cycle_provided_for, variant).should be true
end
it "returns true when order cycle is not required" do
op.stub(:order_cycle_required_for).and_return false
op.send(:check_order_cycle_provided_for, variant).should be true
end
end
describe "checking variant is available under the distributor" do
let(:product) { double(:product) }
let(:variant) { double(:variant, product: product) }
it "delegates to DistributionChangeValidator, returning true when available" do
dcv = double(:dcv)
dcv.should_receive(:variants_available_for_distribution).with(123, 234).and_return([variant])
DistributionChangeValidator.should_receive(:new).with(order).and_return(dcv)
op.instance_eval { @distributor = 123; @order_cycle = 234 }
op.send(:check_variant_available_under_distribution, variant).should be true
op.errors.should be_empty
end
it "delegates to DistributionChangeValidator, returning false and erroring otherwise" do
dcv = double(:dcv)
dcv.should_receive(:variants_available_for_distribution).with(123, 234).and_return([])
DistributionChangeValidator.should_receive(:new).with(order).and_return(dcv)
op.instance_eval { @distributor = 123; @order_cycle = 234 }
op.send(:check_variant_available_under_distribution, variant).should be false
op.errors.to_a.should == ["That product is not available from the chosen distributor or order cycle."]
end
end
end
describe "support" do
describe "checking if order cycle is required for a variant" do
it "requires an order cycle when the product has no product distributions" do
product = double(:product, product_distributions: [])
variant = double(:variant, product: product)
op.send(:order_cycle_required_for, variant).should be true
end
it "does not require an order cycle when the product has product distributions" do
product = double(:product, product_distributions: [1])
variant = double(:variant, product: product)
op.send(:order_cycle_required_for, variant).should be false
end
end
it "provides the distributor and order cycle for the order" do
order.should_receive(:distributor).and_return(distributor)
order.should_receive(:order_cycle).and_return(order_cycle)
op.send(:distributor_and_order_cycle).should == [distributor,
order_cycle]
end
end
end
end

View File

@@ -0,0 +1,310 @@
require 'spec_helper'
describe CartService do
let(:order) { double(:order, id: 123) }
let(:currency) { double(:currency) }
let(:params) { {} }
let(:distributor) { double(:distributor) }
let(:order_cycle) { double(:order_cycle) }
let(:cart_service) { CartService.new(order, currency) }
context "end-to-end" do
let(:order) { create(:order, distributor: distributor, order_cycle: order_cycle) }
let(:distributor) { create(:distributor_enterprise) }
let(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], variants: [v]) }
let(:cart_service) { CartService.new(order, nil) }
let(:v) { create(:variant) }
describe "populate" do
it "adds a variant" do
cart_service.populate({variants: {v.id.to_s => {quantity: '1', max_quantity: '2'}}}, true)
li = order.find_line_item_by_variant(v)
li.should be
li.quantity.should == 1
li.max_quantity.should == 2
li.final_weight_volume.should == 1.0
end
it "updates a variant's quantity, max quantity and final_weight_volume" do
order.add_variant v, 1, 2
cart_service.populate({variants: {v.id.to_s => {quantity: '2', max_quantity: '3'}}}, true)
li = order.find_line_item_by_variant(v)
li.should be
li.quantity.should == 2
li.max_quantity.should == 3
li.final_weight_volume.should == 2.0
end
it "removes a variant" do
order.add_variant v, 1, 2
cart_service.populate({variants: {}}, true)
order.line_items(:reload)
li = order.find_line_item_by_variant(v)
li.should_not be
end
end
end
describe "populate" do
before do
cart_service.should_receive(:distributor_and_order_cycle).
and_return([distributor, order_cycle])
end
it "checks that distribution can supply all products in the cart" do
cart_service.should_receive(:distribution_can_supply_products_in_cart).
with(distributor, order_cycle).and_return(false)
cart_service.populate(params).should be false
cart_service.errors.to_a.should == ["That distributor or order cycle can't supply all the products in your cart. Please choose another."]
end
it "locks the order" do
cart_service.stub(:distribution_can_supply_products_in_cart).and_return(true)
order.should_receive(:with_lock)
cart_service.populate(params, true)
end
it "attempts cart add with max_quantity" do
cart_service.stub(:distribution_can_supply_products_in_cart).and_return true
params = {variants: {"1" => {quantity: 1, max_quantity: 2}}}
order.stub(:with_lock).and_yield
cart_service.stub(:varies_from_cart) { true }
cart_service.stub(:variants_removed) { [] }
cart_service.should_receive(:attempt_cart_add).with("1", 1, 2).and_return true
cart_service.populate(params, true)
end
end
describe "varies_from_cart" do
let(:variant) { double(:variant, id: 123) }
it "returns true when item is not in cart and a quantity is specified" do
cart_service.should_receive(:line_item_for_variant_id).with(variant.id).and_return(nil)
cart_service.send(:varies_from_cart, {variant_id: variant.id, quantity: '2'}).should be true
end
it "returns true when item is not in cart and a max_quantity is specified" do
cart_service.should_receive(:line_item_for_variant_id).with(variant.id).and_return(nil)
cart_service.send(:varies_from_cart, {variant_id: variant.id, quantity: '0', max_quantity: '2'}).should be true
end
it "returns false when item is not in cart and no quantity or max_quantity are specified" do
cart_service.should_receive(:line_item_for_variant_id).with(variant.id).and_return(nil)
cart_service.send(:varies_from_cart, {variant_id: variant.id, quantity: '0'}).should be false
end
it "returns true when quantity varies" do
li = double(:line_item, quantity: 1, max_quantity: nil)
cart_service.stub(:line_item_for_variant_id) { li }
cart_service.send(:varies_from_cart, {variant_id: variant.id, quantity: '2'}).should be true
end
it "returns true when max_quantity varies" do
li = double(:line_item, quantity: 1, max_quantity: nil)
cart_service.stub(:line_item_for_variant_id) { li }
cart_service.send(:varies_from_cart, {variant_id: variant.id, quantity: '1', max_quantity: '3'}).should be true
end
it "returns false when max_quantity varies only in nil vs 0" do
li = double(:line_item, quantity: 1, max_quantity: nil)
cart_service.stub(:line_item_for_variant_id) { li }
cart_service.send(:varies_from_cart, {variant_id: variant.id, quantity: '1'}).should be false
end
it "returns false when both are specified and neither varies" do
li = double(:line_item, quantity: 1, max_quantity: 2)
cart_service.stub(:line_item_for_variant_id) { li }
cart_service.send(:varies_from_cart, {variant_id: variant.id, quantity: '1', max_quantity: '2'}).should be false
end
end
describe "variants_removed" do
it "returns the variant ids when one is in the cart but not in those given" do
cart_service.stub(:variant_ids_in_cart) { [123] }
cart_service.send(:variants_removed, []).should == [123]
end
it "returns nothing when all items in the cart are provided" do
cart_service.stub(:variant_ids_in_cart) { [123] }
cart_service.send(:variants_removed, [{variant_id: '123'}]).should == []
end
it "returns nothing when items are added to cart" do
cart_service.stub(:variant_ids_in_cart) { [123] }
cart_service.send(:variants_removed, [{variant_id: '123'}, {variant_id: '456'}]).should == []
end
it "does not return duplicates" do
cart_service.stub(:variant_ids_in_cart) { [123, 123] }
cart_service.send(:variants_removed, []).should == [123]
end
end
describe "attempt_cart_add" do
let(:variant) { double(:variant, on_hand: 250) }
let(:quantity) { 123 }
before do
Spree::Variant.stub(:find).and_return(variant)
VariantOverride.stub(:for).and_return(nil)
end
it "performs additional validations" do
cart_service.should_receive(:check_order_cycle_provided_for).with(variant).and_return(true)
cart_service.should_receive(:check_variant_available_under_distribution).with(variant).
and_return(true)
order.should_receive(:add_variant).with(variant, quantity, nil, currency)
cart_service.attempt_cart_add(333, quantity.to_s)
end
it "filters quantities through #quantities_to_add" do
cart_service.should_receive(:quantities_to_add).with(variant, 123, 123).
and_return([5, 5])
cart_service.stub(:check_order_cycle_provided_for) { true }
cart_service.stub(:check_variant_available_under_distribution) { true }
order.should_receive(:add_variant).with(variant, 5, 5, currency)
cart_service.attempt_cart_add(333, quantity.to_s, quantity.to_s)
end
it "removes variants which have become out of stock" do
cart_service.should_receive(:quantities_to_add).with(variant, 123, 123).
and_return([0, 0])
cart_service.stub(:check_order_cycle_provided_for) { true }
cart_service.stub(:check_variant_available_under_distribution) { true }
order.should_receive(:remove_variant).with(variant)
order.should_receive(:add_variant).never
cart_service.attempt_cart_add(333, quantity.to_s, quantity.to_s)
end
end
describe "quantities_to_add" do
let(:v) { double(:variant, on_hand: 10) }
context "when backorders are not allowed" do
context "when max_quantity is not provided" do
it "returns full amount when available" do
cart_service.quantities_to_add(v, 5, nil).should == [5, nil]
end
it "returns a limited amount when not entirely available" do
cart_service.quantities_to_add(v, 15, nil).should == [10, nil]
end
end
context "when max_quantity is provided" do
it "returns full amount when available" do
cart_service.quantities_to_add(v, 5, 6).should == [5, 6]
end
it "also returns the full amount when not entirely available" do
cart_service.quantities_to_add(v, 15, 16).should == [10, 16]
end
end
end
context "when backorders are allowed" do
before do
Spree::Config.allow_backorders = true
end
it "does not limit quantity" do
cart_service.quantities_to_add(v, 15, nil).should == [15, nil]
end
it "does not limit max_quantity" do
cart_service.quantities_to_add(v, 15, 16).should == [15, 16]
end
end
end
describe "validations" do
describe "determining if distributor can supply products in cart" do
it "delegates to DistributionChangeValidator" do
dcv = double(:dcv)
dcv.should_receive(:can_change_to_distribution?).with(distributor, order_cycle).and_return(true)
DistributionChangeValidator.should_receive(:new).with(order).and_return(dcv)
cart_service.send(:distribution_can_supply_products_in_cart, distributor, order_cycle).should be true
end
end
describe "checking order cycle is provided for a variant, OR is not needed" do
let(:variant) { double(:variant) }
it "returns false and errors when order cycle is not provided and is required" do
cart_service.stub(:order_cycle_required_for).and_return true
cart_service.send(:check_order_cycle_provided_for, variant).should be false
cart_service.errors.to_a.should == ["Please choose an order cycle for this order."]
end
it "returns true when order cycle is provided" do
cart_service.stub(:order_cycle_required_for).and_return true
cart_service.instance_variable_set :@order_cycle, double(:order_cycle)
cart_service.send(:check_order_cycle_provided_for, variant).should be true
end
it "returns true when order cycle is not required" do
cart_service.stub(:order_cycle_required_for).and_return false
cart_service.send(:check_order_cycle_provided_for, variant).should be true
end
end
describe "checking variant is available under the distributor" do
let(:product) { double(:product) }
let(:variant) { double(:variant, product: product) }
it "delegates to DistributionChangeValidator, returning true when available" do
dcv = double(:dcv)
dcv.should_receive(:variants_available_for_distribution).with(123, 234).and_return([variant])
DistributionChangeValidator.should_receive(:new).with(order).and_return(dcv)
cart_service.instance_eval { @distributor = 123; @order_cycle = 234 }
cart_service.send(:check_variant_available_under_distribution, variant).should be true
cart_service.errors.should be_empty
end
it "delegates to DistributionChangeValidator, returning false and erroring otherwise" do
dcv = double(:dcv)
dcv.should_receive(:variants_available_for_distribution).with(123, 234).and_return([])
DistributionChangeValidator.should_receive(:new).with(order).and_return(dcv)
cart_service.instance_eval { @distributor = 123; @order_cycle = 234 }
cart_service.send(:check_variant_available_under_distribution, variant).should be false
cart_service.errors.to_a.should == ["That product is not available from the chosen distributor or order cycle."]
end
end
end
describe "support" do
describe "checking if order cycle is required for a variant" do
it "requires an order cycle when the product has no product distributions" do
product = double(:product, product_distributions: [])
variant = double(:variant, product: product)
cart_service.send(:order_cycle_required_for, variant).should be true
end
it "does not require an order cycle when the product has product distributions" do
product = double(:product, product_distributions: [1])
variant = double(:variant, product: product)
cart_service.send(:order_cycle_required_for, variant).should be false
end
end
it "provides the distributor and order cycle for the order" do
order.should_receive(:distributor).and_return(distributor)
order.should_receive(:order_cycle).and_return(order_cycle)
cart_service.send(:distributor_and_order_cycle).should == [distributor,
order_cycle]
end
end
end

View File

@@ -17,8 +17,8 @@ module ShopWorkflow
end
def add_product_to_cart(order, product, quantity: 1)
populator = Spree::OrderPopulator.new(order, order.currency)
populator.populate(variants: {product.variants.first.id => quantity})
cart_service = CartService.new(order, order.currency)
cart_service.populate(variants: {product.variants.first.id => quantity})
# Recalculate fee totals
order.update_distribution_charge!