Add ability to change distributor based on whether products in the cart are available

This commit is contained in:
Rob H
2012-12-07 11:56:40 +11:00
parent ef22168349
commit 46abc2fc42
6 changed files with 117 additions and 10 deletions

View File

@@ -35,7 +35,7 @@ Spree::OrdersController.class_eval do
order = current_order(true)
if order.can_change_distributor?
if order.can_change_to_distributor?(distributor)
order.distributor = distributor
order.save!
end

View File

@@ -2,17 +2,43 @@ Spree::Order.class_eval do
belongs_to :distributor, :class_name => 'Enterprise'
before_validation :shipping_address_from_distributor
validate :can_change_distributor?, :if => :distributor_id_changed?
validate :change_distributor_validation, :if => :distributor_id_changed?
attr_accessible :distributor_id
after_create :set_default_shipping_method
def change_distributor_validation
# Check that the line_items in the current order are available from a newly selected distributor
errors.add(:distributor_id, "The products in your cart are not available from '" + distributor.name + "'") unless can_change_to_distributor? distributor
end
def can_change_to_distributor? distributor
# Distributor may not be changed once an item has been added to the cart/order, unless all items are available from the specified distributor
line_items.empty? || (available_distributors || []).include?(distributor)
end
def can_change_distributor?
# Distributor may not be changed once an item has been added to the cart/order
line_items.empty?
end
def available_distributors
# Find all other enterprises which offer all product variants contained within the current order
distributors_with_all_variants = get_distributors_with_all_variants(Enterprise.all)
end
def get_distributors_with_all_variants(enterprises)
variants_in_current_order = line_items.map{ |li| li.variant }
distributors_with_all_variants = []
enterprises.each do |e|
variants_available_from_enterprise = ProductDistribution.find_all_by_distributor_id( e.id ).map{ |pd| pd.product.variants }.flatten
distributors_with_all_variants << e if ( variants_in_current_order - variants_available_from_enterprise ).empty?
end
distributors_with_all_variants
end
def distributor=(distributor)
raise "You cannot change the distributor of an order with products" unless distributor == self.distributor || can_change_distributor?
raise "You cannot change the distributor of an order with products" unless distributor == self.distributor || can_change_to_distributor?(distributor)
super(distributor)
end
@@ -21,9 +47,9 @@ Spree::Order.class_eval do
save!
end
def can_add_product_to_cart?(product)
can_change_distributor? || product.distributors.include?(distributor)
# Products may be added if no line items are currently in the cart or if the product is available from the current distributor
line_items.empty? || product.distributors.include?(distributor)
end
def set_variant_attributes(variant, attributes)

View File

@@ -1,4 +1,9 @@
Deface::Override.new(:virtual_path => "spree/checkout/_address",
:replace => "[data-hook='shipping_fieldset_wrapper']",
:partial => "spree/checkout/distributor",
:name => "delivery_address")
:replace => "[data-hook='shipping_fieldset_wrapper']",
:partial => "spree/checkout/distributor",
:name => "replace_shipping_form")
Deface::Override.new(:virtual_path => "spree/checkout/edit",
:insert_after => "[data-hook='checkout_summary_box']",
:partial => "spree/checkout/other_available_distributors",
:name => "other_available_distributors")

View File

@@ -0,0 +1,16 @@
<div class="columns omega four" style="padding-top: 30px">
<%
other_available_distributors = @order.available_distributors
other_available_distributors.delete(@order.distributor)
unless other_available_distributors.empty?
%>
<%= form_for(@order) do |f| %>
<%= f.label :distributor_label, "Alternative distributors for this order:" %>
<% available_distributors_array = other_available_distributors.map { |distributor| [distributor.name + ": " + distributor.address.address1 + ", " + distributor.address.city, distributor.id.to_i] } %>
<%= f.select :distributor_id, options_for_select( available_distributors_array ) %>
<%= f.submit "Change Distributor" %>
<% end %>
<% else %>
No alternative distributors available.
<% end %>
</div>

View File

@@ -11,7 +11,7 @@
- order = current_order(false)
- @distributors.each do |distributor|
%li.nowrap
- if order.nil? || order.can_change_distributor?
- if order.nil? || order.can_change_to_distributor?(distributor)
= link_to distributor.name, select_distributor_order_path(distributor)
- elsif order.distributor == distributor
= link_to distributor.name, [main_app, distributor]

View File

@@ -26,7 +26,7 @@ describe Spree::Order do
subject.can_change_distributor?.should be_false
end
it "raises an exception if distributor is changed without permission" do
it "checks that distributor is available when changing, and raises an exception if distributor is changed without permission" do
d = create(:distributor_enterprise)
p = create(:product, :distributors => [d])
subject.distributor = d
@@ -34,6 +34,7 @@ describe Spree::Order do
subject.add_variant(p.master, 1)
subject.can_change_distributor?.should be_false
subject.should_receive(:available_distributors)
expect do
subject.distributor = nil
@@ -79,4 +80,63 @@ describe Spree::Order do
li = Spree::LineItem.last
li.max_quantity.should == 3
end
context "finding alternative distributors" do
it "checks that variants are available" do
distributors_with_all_variants = double(:distributors_with_all_variants)
subject.should_receive(:get_distributors_with_all_variants).with(Enterprise.all)
subject.available_distributors
end
context "finding distributors which have the same variants" do
before(:each) do
@enterprise1 = FactoryGirl.create(:enterprise, id: 1)
subject.distributor = @enterprise1
@product1 = FactoryGirl.create(:product)
@product2 = FactoryGirl.create(:product)
@product3 = FactoryGirl.create(:product)
variant11 = FactoryGirl.create(:variant, product: @product1)
variant12 = FactoryGirl.create(:variant, product: @product1)
variant21 = FactoryGirl.create(:variant, product: @product2)
variant31 = FactoryGirl.create(:variant, product: @product3)
variant32 = FactoryGirl.create(:variant, product: @product3)
# Product Distributions
# Enterprise 1 sells product 1 and product 3
FactoryGirl.create(:product_distribution, product: @product1, distributor: @enterprise1)
FactoryGirl.create(:product_distribution, product: @product3, distributor: @enterprise1)
# Build the current order
line_item1 = FactoryGirl.create(:line_item, order: subject, variant: variant11)
line_item2 = FactoryGirl.create(:line_item, order: subject, variant: variant12)
line_item3 = FactoryGirl.create(:line_item, order: subject, variant: variant31)
subject.line_items = [line_item1,line_item2,line_item3]
end
it "matches the distributor enterprise of the current order" do
subject.get_distributors_with_all_variants([@enterprise1]).should == [@enterprise1]
end
it "does not match enterprises with no products available" do
test_enterprise = FactoryGirl.create(:enterprise, id: 2)
subject.get_distributors_with_all_variants([@enterprise1, test_enterprise]).should_not include test_enterprise
end
it "does not match enterprises with only some of the same variants in the current order available" do
test_enterprise = FactoryGirl.create(:enterprise, id: 2)
# Test Enterprise sells only product 1
FactoryGirl.create(:product_distribution, product: @product1, distributor: test_enterprise)
subject.get_distributors_with_all_variants([@enterprise1, test_enterprise]).should_not include test_enterprise
end
it "matches enteprises which offer all products in the current order" do
test_enterprise = FactoryGirl.create(:enterprise, id: 2)
# Enterprise 3 Sells Products 1, 2 and 3
FactoryGirl.create(:product_distribution, product: @product1, distributor: test_enterprise)
FactoryGirl.create(:product_distribution, product: @product2, distributor: test_enterprise)
FactoryGirl.create(:product_distribution, product: @product3, distributor: test_enterprise)
subject.get_distributors_with_all_variants([@enterprise1, test_enterprise]).should include test_enterprise
end
end
end
end