From 87c5d7b30666f5606bb57f4a99aa4dbc8ac3147e Mon Sep 17 00:00:00 2001 From: Adam Mueller Date: Fri, 2 Feb 2018 14:30:25 -0800 Subject: [PATCH 1/3] Add association between stores and shipping Like payment methods, shipping methods are typically store specific. Solidus sites running multiple stores are likely to want the ability to scope shipping methods to specific stores in a similar manner. This only adds the join table between the two models. --- core/app/models/spree/shipping_method.rb | 3 +++ core/app/models/spree/store.rb | 4 ++++ core/app/models/spree/store_shipping_method.rb | 6 ++++++ .../20180202222641_create_store_shipping_methods.rb | 10 ++++++++++ 4 files changed, 23 insertions(+) create mode 100644 core/app/models/spree/store_shipping_method.rb create mode 100644 core/db/migrate/20180202222641_create_store_shipping_methods.rb diff --git a/core/app/models/spree/shipping_method.rb b/core/app/models/spree/shipping_method.rb index 4e04709bdf2..c5f232b0f3c 100644 --- a/core/app/models/spree/shipping_method.rb +++ b/core/app/models/spree/shipping_method.rb @@ -30,6 +30,9 @@ class ShippingMethod < Spree::Base has_many :shipping_method_stock_locations, dependent: :destroy, class_name: "Spree::ShippingMethodStockLocation" has_many :stock_locations, through: :shipping_method_stock_locations + has_many :store_shipping_methods, inverse_of: :shipping_method + has_many :stores, through: :store_shipping_methods + validates :name, presence: true validate :at_least_one_shipping_category diff --git a/core/app/models/spree/store.rb b/core/app/models/spree/store.rb index 273b104828a..305fd5c4a53 100644 --- a/core/app/models/spree/store.rb +++ b/core/app/models/spree/store.rb @@ -9,6 +9,10 @@ module Spree class Store < Spree::Base has_many :store_payment_methods, inverse_of: :store has_many :payment_methods, through: :store_payment_methods + + has_many :store_shipping_methods, inverse_of: :store + has_many :shipping_methods, through: :store_shipping_methods + has_many :orders, class_name: "Spree::Order" validates :code, presence: true, uniqueness: { allow_blank: true } diff --git a/core/app/models/spree/store_shipping_method.rb b/core/app/models/spree/store_shipping_method.rb new file mode 100644 index 00000000000..91913791e98 --- /dev/null +++ b/core/app/models/spree/store_shipping_method.rb @@ -0,0 +1,6 @@ +module Spree + class StoreShippingMethod < Spree::Base + belongs_to :store, inverse_of: :store_shipping_methods + belongs_to :shipping_method, inverse_of: :store_shipping_methods + end +end diff --git a/core/db/migrate/20180202222641_create_store_shipping_methods.rb b/core/db/migrate/20180202222641_create_store_shipping_methods.rb new file mode 100644 index 00000000000..1673bf57a89 --- /dev/null +++ b/core/db/migrate/20180202222641_create_store_shipping_methods.rb @@ -0,0 +1,10 @@ +class CreateStoreShippingMethods < ActiveRecord::Migration[5.1] + def change + create_table :spree_store_shipping_methods do |t| + t.references :store, foreign_key: { to_table: "spree_stores" } + t.references :shipping_method, foreign_key: { to_table: "spree_shipping_methods" } + + t.timestamps + end + end +end From 63bee49bf62316b348fe2c0248b9690637681b45 Mon Sep 17 00:00:00 2001 From: Adam Mueller Date: Tue, 6 Feb 2018 10:51:06 -0800 Subject: [PATCH 2/3] Only use shipping methods associated to same store When estimating rates, we only want shipping methods available to the same store that the order was placed in to be used. --- core/app/models/spree/shipping_method.rb | 5 ++++ core/app/models/spree/stock/estimator.rb | 1 + .../spec/models/spree/stock/estimator_spec.rb | 28 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/core/app/models/spree/shipping_method.rb b/core/app/models/spree/shipping_method.rb index c5f232b0f3c..f3760199caf 100644 --- a/core/app/models/spree/shipping_method.rb +++ b/core/app/models/spree/shipping_method.rb @@ -37,6 +37,11 @@ class ShippingMethod < Spree::Base validate :at_least_one_shipping_category + scope :available_to_store, ->(store) do + raise ArgumentError, "You must provide a store" if store.nil? + store.shipping_methods.empty? ? all : where(id: store.shipping_method_ids) + end + # @param shipping_category_ids [Array] ids of desired shipping categories # @return [ActiveRecord::Relation] shipping methods which are associated # with all of the provided shipping categories diff --git a/core/app/models/spree/stock/estimator.rb b/core/app/models/spree/stock/estimator.rb index 9746972982f..712175e33c7 100644 --- a/core/app/models/spree/stock/estimator.rb +++ b/core/app/models/spree/stock/estimator.rb @@ -53,6 +53,7 @@ def calculate_shipping_rates(package) def shipping_methods(package) package.shipping_methods + .available_to_store(package.shipment.order.store) .available_for_address(package.shipment.order.ship_address) .includes(:calculator) .to_a diff --git a/core/spec/models/spree/stock/estimator_spec.rb b/core/spec/models/spree/stock/estimator_spec.rb index f06e7f66307..1ce519d19cb 100644 --- a/core/spec/models/spree/stock/estimator_spec.rb +++ b/core/spec/models/spree/stock/estimator_spec.rb @@ -139,6 +139,34 @@ module Stock end end + context "excludes shipping methods from other stores" do + before{ Spree::ShippingMethod.all.each(&:really_destroy!) } + + let!(:other_method) do + create( + :shipping_method, + cost: 0.00, + stores: [build(:store, name: "Other")] + ) + end + + let!(:main_method) do + create( + :shipping_method, + cost: 5.00, + stores: [order.store] + ) + end + + it "does not return the other rate at all" do + expect(subject.shipping_rates(package).map(&:shipping_method_id)).to eq([main_method.id]) + end + + it "doesn't select the other rate even if it's more affordable" do + expect(subject.shipping_rates(package).map(&:selected)).to eq [true] + end + end + context "includes tax adjustments if applicable" do let(:zone) { create(:zone, countries: [order.tax_address.country])} From d304dea3ebe7e64492bfff5a196fa597177634e8 Mon Sep 17 00:00:00 2001 From: Adam Mueller Date: Tue, 6 Feb 2018 11:17:30 -0800 Subject: [PATCH 3/3] Add interface for store to shipping methods This adds a select field allowing us to easily control the association between shipping methods and stores. --- .../app/views/spree/admin/shipping_methods/_form.html.erb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/app/views/spree/admin/shipping_methods/_form.html.erb b/backend/app/views/spree/admin/shipping_methods/_form.html.erb index a1c3b9fb5bb..c3ad43653c9 100644 --- a/backend/app/views/spree/admin/shipping_methods/_form.html.erb +++ b/backend/app/views/spree/admin/shipping_methods/_form.html.erb @@ -39,6 +39,14 @@ <% end %> +
+ <%= f.field_container :store_ids do %> + <%= f.label :store_ids, plural_resource_name(Spree::Store) %> + <%= f.collection_select :store_ids, Spree::Store.all, :id, :name, {}, multiple: true, class: "select2 fullwidth" %> + <%= error_message_on :shipping_method, :store_ids %> + <% end %> +
+
<%= f.field_container :tracking_url do %> <%= f.label :tracking_url %>