Bring estimator from spree_core

This commit is contained in:
Luis Ramos
2020-07-01 16:38:50 +01:00
parent 4711a7469a
commit 8c3b8c4db5
2 changed files with 150 additions and 0 deletions

View 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

View 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