mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-26 01:33:22 +00:00
Bring estimator from spree_core
This commit is contained in:
50
app/models/spree/stock/estimator.rb
Normal file
50
app/models/spree/stock/estimator.rb
Normal file
@@ -0,0 +1,50 @@
|
||||
module Spree
|
||||
module Stock
|
||||
class Estimator
|
||||
attr_reader :order, :currency
|
||||
|
||||
def initialize(order)
|
||||
@order = order
|
||||
@currency = order.currency
|
||||
end
|
||||
|
||||
def shipping_rates(package, frontend_only = true)
|
||||
shipping_rates = Array.new
|
||||
shipping_methods = shipping_methods(package)
|
||||
return [] unless shipping_methods
|
||||
|
||||
shipping_methods.each do |shipping_method|
|
||||
cost = calculate_cost(shipping_method, package)
|
||||
shipping_rates << shipping_method.shipping_rates.new(:cost => cost) unless cost.nil?
|
||||
end
|
||||
|
||||
shipping_rates.sort_by! { |r| r.cost || 0 }
|
||||
|
||||
unless shipping_rates.empty?
|
||||
if frontend_only
|
||||
shipping_rates.each do |rate|
|
||||
rate.selected = true and break if rate.shipping_method.frontend?
|
||||
end
|
||||
else
|
||||
shipping_rates.first.selected = true
|
||||
end
|
||||
end
|
||||
|
||||
shipping_rates
|
||||
end
|
||||
|
||||
private
|
||||
def shipping_methods(package)
|
||||
shipping_methods = package.shipping_methods
|
||||
shipping_methods.delete_if { |ship_method| !ship_method.calculator.available?(package) }
|
||||
shipping_methods.delete_if { |ship_method| !ship_method.include?(order.ship_address) }
|
||||
shipping_methods.delete_if { |ship_method| !(ship_method.calculator.preferences[:currency].nil? || ship_method.calculator.preferences[:currency] == currency) }
|
||||
shipping_methods
|
||||
end
|
||||
|
||||
def calculate_cost(shipping_method, package)
|
||||
shipping_method.calculator.compute(package)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
100
spec/models/spree/stock/estimator_spec.rb
Normal file
100
spec/models/spree/stock/estimator_spec.rb
Normal file
@@ -0,0 +1,100 @@
|
||||
require 'spec_helper'
|
||||
|
||||
module Spree
|
||||
module Stock
|
||||
describe Estimator do
|
||||
let!(:shipping_method) { create(:shipping_method) }
|
||||
let(:package) { build(:stock_package_fulfilled) }
|
||||
let(:order) { package.order }
|
||||
subject { Estimator.new(order) }
|
||||
|
||||
context "#shipping rates" do
|
||||
before(:each) do
|
||||
shipping_method.zones.first.members.create(:zoneable => order.ship_address.country)
|
||||
ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(true)
|
||||
ShippingMethod.any_instance.stub_chain(:calculator, :compute).and_return(4.00)
|
||||
ShippingMethod.any_instance.stub_chain(:calculator, :preferences).and_return({:currency => "USD"})
|
||||
ShippingMethod.any_instance.stub_chain(:calculator, :marked_for_destruction?)
|
||||
|
||||
package.stub(:shipping_methods => [shipping_method])
|
||||
end
|
||||
|
||||
it "returns shipping rates from a shipping method if the order's ship address is in the same zone" do
|
||||
shipping_rates = subject.shipping_rates(package)
|
||||
shipping_rates.first.cost.should eq 4.00
|
||||
end
|
||||
|
||||
it "does not return shipping rates from a shipping method if the order's ship address is in a different zone" do
|
||||
shipping_method.zones.each{|z| z.members.delete_all}
|
||||
shipping_rates = subject.shipping_rates(package)
|
||||
shipping_rates.should == []
|
||||
end
|
||||
|
||||
it "does not return shipping rates from a shipping method if the calculator is not available for that order" do
|
||||
ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(false)
|
||||
shipping_rates = subject.shipping_rates(package)
|
||||
shipping_rates.should == []
|
||||
end
|
||||
|
||||
it "returns shipping rates from a shipping method if the currency matches the order's currency" do
|
||||
shipping_rates = subject.shipping_rates(package)
|
||||
shipping_rates.first.cost.should eq 4.00
|
||||
end
|
||||
|
||||
it "does not return shipping rates from a shipping method if the currency is different than the order's currency" do
|
||||
order.currency = "GBP"
|
||||
shipping_rates = subject.shipping_rates(package)
|
||||
shipping_rates.should == []
|
||||
end
|
||||
|
||||
it "sorts shipping rates by cost" do
|
||||
shipping_methods = 3.times.map { create(:shipping_method) }
|
||||
shipping_methods[0].stub_chain(:calculator, :compute).and_return(5.00)
|
||||
shipping_methods[1].stub_chain(:calculator, :compute).and_return(3.00)
|
||||
shipping_methods[2].stub_chain(:calculator, :compute).and_return(4.00)
|
||||
|
||||
subject.stub(:shipping_methods).and_return(shipping_methods)
|
||||
|
||||
expect(subject.shipping_rates(package).map(&:cost)).to eq %w[3.00 4.00 5.00].map(&BigDecimal.method(:new))
|
||||
end
|
||||
|
||||
context "general shipping methods" do
|
||||
let(:shipping_methods) { 2.times.map { create(:shipping_method) } }
|
||||
|
||||
it "selects the most affordable shipping rate" do
|
||||
shipping_methods[0].stub_chain(:calculator, :compute).and_return(5.00)
|
||||
shipping_methods[1].stub_chain(:calculator, :compute).and_return(3.00)
|
||||
|
||||
subject.stub(:shipping_methods).and_return(shipping_methods)
|
||||
|
||||
expect(subject.shipping_rates(package).sort_by(&:cost).map(&:selected)).to eq [true, false]
|
||||
end
|
||||
|
||||
it "selects the most affordable shipping rate and doesn't raise exception over nil cost" do
|
||||
shipping_methods[0].stub_chain(:calculator, :compute).and_return(1.00)
|
||||
shipping_methods[1].stub_chain(:calculator, :compute).and_return(nil)
|
||||
|
||||
subject.stub(:shipping_methods).and_return(shipping_methods)
|
||||
|
||||
subject.shipping_rates(package)
|
||||
end
|
||||
end
|
||||
|
||||
context "involves backend only shipping methods" do
|
||||
let(:backend_method) { create(:shipping_method, display_on: "back_end") }
|
||||
let(:generic_method) { create(:shipping_method) }
|
||||
|
||||
# regression for #3287
|
||||
it "doesn't select backend rates even if they're more affordable" do
|
||||
backend_method.stub_chain(:calculator, :compute).and_return(0.00)
|
||||
generic_method.stub_chain(:calculator, :compute).and_return(5.00)
|
||||
|
||||
subject.stub(:shipping_methods).and_return([backend_method, generic_method])
|
||||
|
||||
expect(subject.shipping_rates(package).map(&:selected)).to eq [false, true]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user