mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
Create line item adjustments for product distributions
This commit is contained in:
@@ -7,4 +7,30 @@ class ProductDistribution < ActiveRecord::Base
|
||||
validates_presence_of :product_id, :on => :update
|
||||
validates_presence_of :distributor_id, :shipping_method_id
|
||||
validates_uniqueness_of :product_id, :scope => :distributor_id
|
||||
|
||||
|
||||
def ensure_correct_adjustment_for(line_item)
|
||||
if enterprise_fee
|
||||
adjustment = adjustment_on line_item
|
||||
create_adjustment_on line_item unless adjustment
|
||||
end
|
||||
end
|
||||
|
||||
def adjustment_on(line_item)
|
||||
adjustments = line_item.adjustments.where(source_id: enterprise_fee)
|
||||
|
||||
raise "Multiple adjustments for this enterprise fee on this line item. This method is not designed to deal with this scenario." if adjustments.count > 1
|
||||
|
||||
adjustments.first
|
||||
end
|
||||
|
||||
def create_adjustment_on(line_item)
|
||||
enterprise_fee.create_adjustment(adjustment_label, line_item, enterprise_fee, true)
|
||||
end
|
||||
|
||||
|
||||
def adjustment_label
|
||||
"Product distribution by #{distributor.name}"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -13,6 +13,8 @@ Spree::Order.class_eval do
|
||||
before_save :update_line_item_shipping_methods
|
||||
after_create :set_default_shipping_method
|
||||
|
||||
register_update_hook :update_distribution_charge!
|
||||
|
||||
# -- Scopes
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
@@ -22,6 +24,7 @@ Spree::Order.class_eval do
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
# -- Methods
|
||||
def products_available_from_new_distribution
|
||||
# Check that the line_items in the current order are available from a newly selected distribution
|
||||
@@ -56,6 +59,13 @@ Spree::Order.class_eval do
|
||||
save!
|
||||
end
|
||||
|
||||
def update_distribution_charge!
|
||||
line_items.each do |line_item|
|
||||
pd = product_distribution_for line_item
|
||||
pd.ensure_correct_adjustment_for line_item
|
||||
end
|
||||
end
|
||||
|
||||
def set_variant_attributes(variant, attributes)
|
||||
line_item = find_line_item_by_variant(variant)
|
||||
|
||||
@@ -113,4 +123,9 @@ Spree::Order.class_eval do
|
||||
self.update!
|
||||
end
|
||||
end
|
||||
|
||||
def product_distribution_for(line_item)
|
||||
line_item.variant.product.product_distribution_for self.distributor
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -89,6 +89,7 @@ FactoryGirl.define do
|
||||
product { |pd| Spree::Product.first || FactoryGirl.create(:product) }
|
||||
distributor { |pd| Enterprise.is_distributor.first || FactoryGirl.create(:distributor_enterprise) }
|
||||
shipping_method { |pd| Spree::ShippingMethod.where("name != 'Delivery'").first || FactoryGirl.create(:shipping_method) }
|
||||
enterprise_fee { |pd| FactoryGirl.create(:enterprise_fee, enterprise: pd.distributor) }
|
||||
end
|
||||
|
||||
factory :itemwise_shipping_method, :parent => :shipping_method do
|
||||
|
||||
@@ -28,6 +28,37 @@ describe Spree::Order do
|
||||
li.max_quantity.should == 3
|
||||
end
|
||||
|
||||
describe "updating the distribution charge" do
|
||||
let(:order) { build(:order) }
|
||||
|
||||
it "updates distribution charge after save" do
|
||||
order.should_receive(:update_distribution_charge!).at_least(:once)
|
||||
order.save!
|
||||
end
|
||||
|
||||
it "ensures the correct adjustment(s) are created for the product distribution" do
|
||||
line_item = double(:line_item)
|
||||
subject.stub(:line_items) { [line_item] }
|
||||
|
||||
product_distribution = double(:product_distribution)
|
||||
product_distribution.should_receive(:ensure_correct_adjustment_for).with(line_item)
|
||||
subject.stub(:product_distribution_for) { product_distribution }
|
||||
|
||||
subject.send(:update_distribution_charge!)
|
||||
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
|
||||
end
|
||||
|
||||
describe "setting the distributor" do
|
||||
it "sets the distributor when no order cycle is set" do
|
||||
d = create(:distributor_enterprise)
|
||||
|
||||
@@ -20,4 +20,135 @@ describe ProductDistribution do
|
||||
pd2 = build(:product_distribution, :product => new_product, :distributor => new_distributor)
|
||||
pd2.should be_valid
|
||||
end
|
||||
|
||||
|
||||
describe "adjusting orders" do
|
||||
context "integration" do
|
||||
it "creates an adjustment for product distributions" do
|
||||
# Given an order
|
||||
distributor = create(:distributor_enterprise)
|
||||
order = create(:order, distributor: distributor)
|
||||
|
||||
# And a product with a product distribution with an enterprise fee
|
||||
product = create(:product)
|
||||
enterprise_fee = create(:enterprise_fee, calculator: build(:calculator))
|
||||
enterprise_fee.calculator.preferred_amount = 1.23
|
||||
enterprise_fee.calculator.save!
|
||||
create(:product_distribution, product: product, distributor: distributor, enterprise_fee: enterprise_fee)
|
||||
|
||||
# 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
|
||||
end.to change(Spree::Adjustment, :count).by(1)
|
||||
|
||||
# And it should have the correct data
|
||||
order.reload
|
||||
order.line_items.count.should == 1
|
||||
order.line_items.last.adjustments.count.should == 1
|
||||
adjustment = order.line_items.last.adjustments.last
|
||||
|
||||
adjustment.source.should == enterprise_fee
|
||||
adjustment.originator.should == enterprise_fee
|
||||
adjustment.label.should == "Product distribution by #{distributor.name}"
|
||||
adjustment.amount.should == 1.23
|
||||
|
||||
# And it should have some associated metadata
|
||||
pending 'Needs metadata spec'
|
||||
end
|
||||
end
|
||||
|
||||
describe "ensuring that a line item has the correct adjustment" do
|
||||
let(:enterprise_fee) { EnterpriseFee.new }
|
||||
let(:pd) { ProductDistribution.new enterprise_fee: enterprise_fee }
|
||||
let(:line_item) { double(:line_item) }
|
||||
let(:adjustment) { double(:adjustment) }
|
||||
|
||||
# TODO: This spec will go away once enterprise_fee is required
|
||||
it "does nothing if there is no enterprise fee set" do
|
||||
pd.enterprise_fee = nil
|
||||
pd.should_receive(:adjustment_on).never
|
||||
pd.ensure_correct_adjustment_for line_item
|
||||
end
|
||||
|
||||
describe "adding items to cart" do
|
||||
it "creates an adjustment for the new item" do
|
||||
pd.stub(:adjustment_on) { nil }
|
||||
pd.should_receive(:create_adjustment_on).with(line_item)
|
||||
|
||||
pd.ensure_correct_adjustment_for line_item
|
||||
end
|
||||
|
||||
it "makes no change to the adjustment of existing items" do
|
||||
pd.stub(:adjustment_on) { adjustment }
|
||||
pd.should_receive(:create_adjustment_on).never
|
||||
|
||||
pd.ensure_correct_adjustment_for line_item
|
||||
end
|
||||
end
|
||||
|
||||
describe "changing distributor" do
|
||||
it "clears and re-creates the adjustment on the line item"
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding our adjustment on a line item" do
|
||||
it "returns nil when not present" do
|
||||
line_item = build(:line_item)
|
||||
pd = ProductDistribution.new
|
||||
pd.send(:adjustment_on, line_item).should be_nil
|
||||
end
|
||||
|
||||
it "returns the adjustment when present" do
|
||||
# TODO: This spec can be simplified (ie. use the default ProductDistribution factory)
|
||||
# once Spree's calculators are compatible with LineItem targets, not just Orders.
|
||||
distributor = create(:distributor_enterprise)
|
||||
enterprise_fee = create(:enterprise_fee, enterprise: distributor, calculator: build(:calculator))
|
||||
|
||||
pd = create(:product_distribution, distributor: distributor, enterprise_fee: enterprise_fee)
|
||||
line_item = create(:line_item)
|
||||
adjustment = pd.enterprise_fee.create_adjustment('foo', line_item, pd.enterprise_fee, true)
|
||||
|
||||
pd.send(:adjustment_on, line_item).should == adjustment
|
||||
end
|
||||
|
||||
it "raises an error when there are multiple adjustments for this enterprise fee" do
|
||||
# TODO: This spec can be simplified (ie. use the default ProductDistribution factory)
|
||||
# once Spree's calculators are compatible with LineItem targets, not just Orders.
|
||||
distributor = create(:distributor_enterprise)
|
||||
enterprise_fee = create(:enterprise_fee, enterprise: distributor, calculator: build(:calculator))
|
||||
|
||||
pd = create(:product_distribution, distributor: distributor, enterprise_fee: enterprise_fee)
|
||||
line_item = create(:line_item)
|
||||
pd.enterprise_fee.create_adjustment('one', line_item, pd.enterprise_fee, true)
|
||||
pd.enterprise_fee.create_adjustment('two', line_item, pd.enterprise_fee, true)
|
||||
|
||||
expect do
|
||||
pd.send(:adjustment_on, line_item)
|
||||
end.to raise_error "Multiple adjustments for this enterprise fee on this line item. This method is not designed to deal with this scenario."
|
||||
end
|
||||
end
|
||||
|
||||
describe "creating an adjustment on a line item" do
|
||||
it "creates the adjustment via the enterprise fee" do
|
||||
# TODO: This spec can be simplified (ie. use the default ProductDistribution factory)
|
||||
# once Spree's calculators are compatible with LineItem targets, not just Orders.
|
||||
distributor = create(:distributor_enterprise)
|
||||
enterprise_fee = create(:enterprise_fee, enterprise: distributor, calculator: build(:calculator))
|
||||
pd = create(:product_distribution, distributor: distributor, enterprise_fee: enterprise_fee)
|
||||
|
||||
pd.stub(:adjustment_label) { 'label' }
|
||||
line_item = create(:line_item)
|
||||
|
||||
expect { pd.send(:create_adjustment_on, line_item) }.to change(Spree::Adjustment, :count).by(1)
|
||||
|
||||
adjustment = Spree::Adjustment.last
|
||||
adjustment.label.should == 'label'
|
||||
adjustment.adjustable.should == line_item
|
||||
adjustment.source.should == enterprise_fee
|
||||
adjustment.originator.should == enterprise_fee
|
||||
adjustment.should be_mandatory
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user