diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb
index 866fd94334..5812d2395c 100644
--- a/app/controllers/admin/order_cycles_controller.rb
+++ b/app/controllers/admin/order_cycles_controller.rb
@@ -2,10 +2,10 @@
module Admin
class OrderCyclesController < Admin::ResourceController
- include OrderCyclesHelper
+ include ::OrderCyclesHelper
include PaperTrailLogging
- prepend_before_action :set_order_cycle_id, only: [:incoming, :outgoing]
+ prepend_before_action :set_order_cycle_id, only: [:incoming, :outgoing, :checkout_options]
before_action :load_data_for_index, only: :index
before_action :require_coordinator, only: :new
before_action :remove_protected_attrs, only: [:update]
@@ -67,10 +67,12 @@ module Admin
update_nil_subscription_line_items_price_estimate(@order_cycle)
respond_to do |format|
flash[:notice] = I18n.t(:order_cycles_update_notice) if params[:reloading] == '1'
- format.html { redirect_back(fallback_location: root_path) }
+ format.html { redirect_to_after_update_path }
format.json { render json: { success: true } }
end
- else
+ elsif request.format.html?
+ render :checkout_options
+ elsif request.format.json?
render json: { errors: @order_cycle.errors.full_messages }, status: :unprocessable_entity
end
end
@@ -190,6 +192,16 @@ module Admin
end
end
+ def redirect_to_after_update_path
+ if params[:context] == "checkout_options" && params[:save]
+ redirect_to main_app.admin_order_cycle_checkout_options_path(@order_cycle)
+ elsif params[:context] == "checkout_options" && params[:save_and_back_to_list]
+ redirect_to main_app.admin_order_cycles_path
+ else
+ redirect_back(fallback_location: root_path)
+ end
+ end
+
def require_coordinator
@order_cycle.coordinator =
permitted_coordinating_enterprises_for(@order_cycle).find_by(id: params[:coordinator_id])
diff --git a/app/helpers/admin/order_cycles_helper.rb b/app/helpers/admin/order_cycles_helper.rb
new file mode 100644
index 0000000000..c046ded504
--- /dev/null
+++ b/app/helpers/admin/order_cycles_helper.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+module Admin
+ module OrderCyclesHelper
+ def order_cycle_shared_payment_methods(order_cycle)
+ order_cycle.attachable_payment_methods.select do |payment_method|
+ (payment_method.distributor_ids & order_cycle.distributor_ids).many?
+ end
+ end
+
+ def order_cycle_shared_shipping_methods(order_cycle)
+ order_cycle.attachable_shipping_methods.select do |shipping_method|
+ (shipping_method.distributor_ids & order_cycle.distributor_ids).many?
+ end
+ end
+ end
+end
diff --git a/app/models/order_cycle.rb b/app/models/order_cycle.rb
index 86f1a14a54..84800086c9 100644
--- a/app/models/order_cycle.rb
+++ b/app/models/order_cycle.rb
@@ -156,6 +156,23 @@ class OrderCycle < ApplicationRecord
]
end
+ def attachable_payment_methods
+ Spree::PaymentMethod.available(:both).
+ joins("INNER JOIN distributors_payment_methods
+ ON payment_method_id = spree_payment_methods.id").
+ where("distributor_id IN (?)", distributor_ids).
+ distinct
+ end
+
+ def attachable_shipping_methods
+ return Spree::ShippingMethod.none if simple? || !shipping_methods_customisable?
+
+ Spree::ShippingMethod.frontend.
+ joins(:distributor_shipping_methods).
+ where("distributor_id IN (?)", distributor_ids).
+ distinct
+ end
+
def clone!
oc = dup
oc.name = I18n.t("models.order_cycle.cloned_order_cycle_name", order_cycle: oc.name)
diff --git a/app/models/spree/ability.rb b/app/models/spree/ability.rb
index 2e9aec849f..63857559cd 100644
--- a/app/models/spree/ability.rb
+++ b/app/models/spree/ability.rb
@@ -243,7 +243,9 @@ module Spree
end
def add_order_cycle_management_abilities(user)
- can [:admin, :index, :read, :edit, :update, :incoming, :outgoing], OrderCycle do |order_cycle|
+ can [
+ :admin, :index, :read, :edit, :update, :incoming, :outgoing, :checkout_options
+ ], OrderCycle do |order_cycle|
OrderCycle.visible_by(user).include? order_cycle
end
can [:admin, :index, :create], Schedule
diff --git a/app/services/order_available_shipping_methods.rb b/app/services/order_available_shipping_methods.rb
new file mode 100644
index 0000000000..3c815d19a0
--- /dev/null
+++ b/app/services/order_available_shipping_methods.rb
@@ -0,0 +1,29 @@
+# frozen_string_literal: true
+
+class OrderAvailableShippingMethods < Struct.new(:order, :customer)
+ delegate :distributor,
+ :order_cycle,
+ to: :order
+
+ def to_a
+ return [] if distributor.blank?
+
+ shipping_methods = shipping_methods_before_tag_rules_applied
+
+ applicator = OpenFoodNetwork::TagRuleApplicator.new(distributor,
+ "FilterShippingMethods", customer&.tag_list)
+ applicator.filter!(shipping_methods)
+
+ shipping_methods.uniq
+ end
+
+ private
+
+ def shipping_methods_before_tag_rules_applied
+ if order_cycle.nil? || order_cycle.simple?
+ distributor.shipping_methods
+ else
+ distributor.shipping_methods.where(id: order_cycle.shipping_methods.select(:id))
+ end.frontend.to_a
+ end
+end
diff --git a/app/services/permitted_attributes/order_cycle.rb b/app/services/permitted_attributes/order_cycle.rb
index dd74607168..97282acabf 100644
--- a/app/services/permitted_attributes/order_cycle.rb
+++ b/app/services/permitted_attributes/order_cycle.rb
@@ -17,7 +17,7 @@ module PermittedAttributes
:name, :orders_open_at, :orders_close_at, :coordinator_id,
:preferred_product_selection_from_coordinator_inventory_only,
:automatic_notifications,
- { schedule_ids: [], coordinator_fee_ids: [] }
+ { schedule_ids: [], shipping_method_ids: [], coordinator_fee_ids: [] }
]
end
diff --git a/app/views/admin/order_cycles/_wizard_progress.html.haml b/app/views/admin/order_cycles/_wizard_progress.html.haml
index 3224324ca6..cc13adcebf 100644
--- a/app/views/admin/order_cycles/_wizard_progress.html.haml
+++ b/app/views/admin/order_cycles/_wizard_progress.html.haml
@@ -6,6 +6,8 @@
= t("admin.order_cycles.wizard_progress.incoming")
%li
= t("admin.order_cycles.wizard_progress.outgoing")
+ %li
+ = t("admin.order_cycles.wizard_progress.checkout_options")
- else
%li{ class: "#{'current' if action_name == 'edit'}" }
%a{ href: main_app.edit_admin_order_cycle_path(@order_cycle) }
@@ -16,3 +18,6 @@
%li{ class: "#{'current' if action_name == 'outgoing'}" }
%a{ href: main_app.admin_order_cycle_outgoing_path(@order_cycle) }
= t("admin.order_cycles.wizard_progress.outgoing")
+ %li{ class: "#{'current' if action_name == 'checkout_options'}" }
+ %a{ href: main_app.admin_order_cycle_checkout_options_path(@order_cycle) }
+ = t("admin.order_cycles.wizard_progress.checkout_options")
diff --git a/app/views/admin/order_cycles/checkout_options.html.haml b/app/views/admin/order_cycles/checkout_options.html.haml
new file mode 100644
index 0000000000..97f436308c
--- /dev/null
+++ b/app/views/admin/order_cycles/checkout_options.html.haml
@@ -0,0 +1,83 @@
+= render partial: "/admin/order_cycles/order_cycle_top_buttons"
+
+- content_for :page_title do
+ = t :edit_order_cycle
+
+- shared_payment_methods = order_cycle_shared_payment_methods(@order_cycle)
+- shared_shipping_methods = order_cycle_shared_shipping_methods(@order_cycle)
+
+= form_for [main_app, :admin, @order_cycle], html: { class: "order_cycle" } do |f|
+
+ = render 'wizard_progress'
+
+ %fieldset.no-border-bottom
+ %legend{ align: 'center'}= t('.checkout_options')
+
+ %table.checkout-options
+ %thead
+ %tr
+ %th= t('.distributor')
+ %th= t('.shipping_methods')
+ %th= t('.payment_methods')
+ - @order_cycle.distributors.each do |distributor|
+ - payment_methods = @order_cycle.attachable_payment_methods.where("distributor_id = ?", distributor.id).reject { |payment_method| shared_payment_methods.include?(payment_method) }
+ - shipping_methods = @order_cycle.attachable_shipping_methods.where("distributor_id = ?", distributor.id).reject { |shipping_method| shared_shipping_methods.include?(shipping_method) }
+ %tr
+ %td= distributor.name
+ %td
+ - shipping_methods.each do |shipping_method|
+ %p
+ %label
+ = check_box_tag "order_cycle[preferred_shipping_method_ids][]",
+ shipping_method.id, @order_cycle.shipping_methods.include?(shipping_method),
+ id: "order_cycle_preferred_shipping_method_ids_#{shipping_method.id}"
+ = shipping_method.name
+ - distributor.shipping_methods.backend.each do |shipping_method|
+ %label.disabled
+ = check_box_tag nil, nil, false, disabled: true
+ = shipping_method.name
+ = "(#{t('.back_end')})"
+ - if shipping_methods.none? && distributor.shipping_methods.backend.none?
+ %p.text-center
+ = t('.no_shipping_methods')
+ %td
+ - if payment_methods.any?
+ %ul
+ - payment_methods.each do |payment_method|
+ %li= payment_method.name
+ - else
+ %p.text-center
+ = t('.no_payment_methods')
+ - if shared_payment_methods.any? || shared_shipping_methods.any?
+ %tr
+ %td= t('.shared')
+ %td
+ - if shared_shipping_methods.any?
+ = f.collection_check_boxes :shipping_method_ids, shared_shipping_methods, :id, :name do |input|
+ - shared_shipping_method = input.object
+ %p
+ = input.check_box
+ = input.label
+ %p
+ = "—#{shared_shipping_method.distributors.where(id: @order_cycle.distributor_ids).map(&:name).join(", ")}".html_safe
+ %td
+ - if shared_payment_methods.any?
+ %ul
+ - shared_payment_methods.each do |shared_payment_method|
+ %li
+ = shared_payment_method.name
+ %p
+ = "—#{shared_payment_method.distributors.where(id: @order_cycle.distributor_ids).map(&:name).join(", ")}".html_safe
+
+ %div#save-bar
+ %div.container
+ %div.seven.columns.alpha
+ - if @order_cycle.errors.any?
+ %h5#status-message.error
+ = @order_cycle.errors.to_a.to_sentence
+ %div.nine.columns.omega.text-right
+ = hidden_field_tag :context, :checkout_options
+ = f.submit t('.save'), class: "red", name: :save
+ = f.submit t('.save_and_back_to_list'), class: "red", name: :save_and_back_to_list
+ %a.button.cancel{ href: main_app.admin_order_cycles_path }
+ = t('.cancel')
diff --git a/app/views/admin/order_cycles/outgoing.html.haml b/app/views/admin/order_cycles/outgoing.html.haml
index 9924e3dae9..e7756a713d 100644
--- a/app/views/admin/order_cycles/outgoing.html.haml
+++ b/app/views/admin/order_cycles/outgoing.html.haml
@@ -10,7 +10,8 @@
%save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" }
%input.red{ type: "button", value: t('.save'), ng: { click: "submit($event, null)", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
- %input.red{ type: "button", value: t('.save_and_back_to_list'), ng: { click: "submit($event, '#{main_app.admin_order_cycles_path}')", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
+ %input.red{ type: "button", value: t('.save_and_next'), ng: { click: "submit($event, '#{main_app.admin_order_cycle_checkout_options_path(@order_cycle)}')", disabled: "!order_cycle_form.$dirty || order_cycle_form.$invalid" } }
+ %input{ type: "button", value: t('.next'), ng: { click: "cancel('#{main_app.admin_order_cycle_checkout_options_path(@order_cycle)}')", disabled: "order_cycle_form.$dirty" } }
%input{ type: "button", ng: { value: "order_cycle_form.$dirty ? '#{t('.cancel')}' : '#{t('.back_to_list')}'", click: "cancel('#{main_app.admin_order_cycles_path}')" } }
%fieldset.no-border-bottom
diff --git a/app/webpacker/css/admin/components/save_bar.scss b/app/webpacker/css/admin/components/save_bar.scss
index 70f906119f..b60482de11 100644
--- a/app/webpacker/css/admin/components/save_bar.scss
+++ b/app/webpacker/css/admin/components/save_bar.scss
@@ -11,6 +11,10 @@
h5 {
color: $spree-blue;
+
+ &.error {
+ color: $red-500;
+ }
}
input {
diff --git a/app/webpacker/css/admin/openfoodnetwork.scss b/app/webpacker/css/admin/openfoodnetwork.scss
index 636b938d6d..aa22632fd0 100644
--- a/app/webpacker/css/admin/openfoodnetwork.scss
+++ b/app/webpacker/css/admin/openfoodnetwork.scss
@@ -96,6 +96,14 @@ form.order_cycle {
.icon-question-sign {
font-size: 18px;
}
+ table.checkout-options {
+ ul {
+ margin-left: 1em;
+ }
+ p, li {
+ margin: 0.5em 0;
+ }
+ }
table.exchanges {
tr td.active {
width: 20px;
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 7c25622af2..ef52faec39 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -1173,15 +1173,29 @@ en:
tags: "Tags"
delivery_details: "Delivery Details"
fees: "Fees"
+ next: "Next"
previous: "Previous"
save: "Save"
- save_and_back_to_list: "Save and Back to List"
+ save_and_next: "Save and Next"
cancel: "Cancel"
back_to_list: "Back To List"
+ checkout_options:
+ back_end: "Back office only"
+ cancel: "Cancel"
+ checkout_options: "Checkout options"
+ distributor: "Distributor"
+ no_payment_methods: Each distributor on this order cycle requires at least one payment method.
+ no_shipping_methods: Each distributor on this order cycle requires at least one shipping method.
+ payment_methods: "Payment Methods"
+ save: "Save"
+ save_and_back_to_list: "Save and Back to List"
+ shared: "Shared"
+ shipping_methods: "Shipping Methods"
wizard_progress:
edit: "1. General Settings"
incoming: "2. Incoming Products"
outgoing: "3. Outgoing Products"
+ checkout_options: "4. Checkout Options"
exchange_form:
pickup_time_tip: When orders from this OC will be ready for the customer
pickup_instructions_placeholder: "Pick-up instructions"
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index 7fc4afcd8f..99beb534d0 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -15,6 +15,7 @@ Openfoodnetwork::Application.routes.draw do
post :bulk_update, on: :collection, as: :bulk_update
get :incoming
get :outgoing
+ get :checkout_options
member do
get :clone
diff --git a/spec/models/order_cycle_spec.rb b/spec/models/order_cycle_spec.rb
index 16d21fdabd..06443fb7ef 100644
--- a/spec/models/order_cycle_spec.rb
+++ b/spec/models/order_cycle_spec.rb
@@ -677,6 +677,24 @@ describe OrderCycle do
end
end
+ describe "#attachable_shipping_methods" do
+ it "includes shipping methods from the distributors on the order cycle" do
+ shipping_method = create(:shipping_method)
+ enterprise = create(:enterprise, shipping_methods: [shipping_method])
+ oc = create(:simple_order_cycle, distributors: [enterprise])
+
+ expect(oc.attachable_shipping_methods).to eq([shipping_method])
+ end
+
+ it "does not include backoffice only shipping methods" do
+ shipping_method = create(:shipping_method, display_on: "back_end")
+ enterprise = create(:enterprise, shipping_methods: [shipping_method])
+ oc = create(:simple_order_cycle, distributors: [enterprise])
+
+ expect(oc.attachable_shipping_methods).to be_empty
+ end
+ end
+
describe "#simple?" do
it "returns true if the coordinator sells their own products i.e. shops" do
order_cycle = build(:simple_order_cycle, coordinator: build(:enterprise, sells: "own"))
diff --git a/spec/services/order_available_shipping_methods_spec.rb b/spec/services/order_available_shipping_methods_spec.rb
new file mode 100644
index 0000000000..814853d6eb
--- /dev/null
+++ b/spec/services/order_available_shipping_methods_spec.rb
@@ -0,0 +1,269 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe OrderAvailableShippingMethods do
+ context "when the order has no current_distributor" do
+ it "returns an empty array" do
+ order_cycle = create(:sells_own_order_cycle)
+ order = build(:order, distributor: nil, order_cycle: order_cycle)
+
+ expect(OrderAvailableShippingMethods.new(order).to_a).to eq []
+ end
+ end
+
+ it "does not return 'back office only' shipping method" do
+ distributor = create(:distributor_enterprise)
+ frontend_shipping_method = create(:shipping_method, distributors: [distributor])
+ backoffice_only_shipping_method = create(:shipping_method,
+ distributors: [distributor], display_on: 'back_end')
+ order_cycle = create(:sells_own_order_cycle)
+ order = build(:order, distributor: distributor, order_cycle: order_cycle)
+
+ available_shipping_methods = OrderAvailableShippingMethods.new(order).to_a
+
+ expect(available_shipping_methods).to eq [frontend_shipping_method]
+ end
+
+ context "when no tag rules are in effect" do
+ context "order cycle selling own produce only i.e. shipping methods cannot be customised" do
+ it "returns all shipping methods belonging to the enterprise" do
+ order_cycle = create(:sells_own_order_cycle)
+ enterprise = order_cycle.coordinator
+ shipping_method = create(:shipping_method, distributors: [enterprise])
+ other_enterprise = create(:enterprise)
+ other_enterprise_shipping_method = create(:shipping_method,
+ distributors: [other_enterprise])
+ order = build(:order, distributor: enterprise, order_cycle: order_cycle)
+
+ available_shipping_methods = OrderAvailableShippingMethods.new(order).to_a
+
+ expect(order_cycle.shipping_methods).to be_empty
+ expect(available_shipping_methods).to eq [shipping_method]
+ end
+ end
+
+ context "distributor order cycle" do
+ it "only returns shipping methods which belong to the order distributor
+ and have been added to the order cycle" do
+ distributor = create(:distributor_enterprise)
+ shipping_method_i = create(:shipping_method, distributors: [distributor])
+ shipping_method_ii = create(:shipping_method, distributors: [distributor])
+ order_cycle = create(:simple_order_cycle,
+ distributors: [distributor], shipping_methods: [shipping_method_i])
+ order = build(:order, distributor: distributor, order_cycle: order_cycle)
+
+ available_shipping_methods = OrderAvailableShippingMethods.new(order).to_a
+
+ expect(available_shipping_methods).to eq order_cycle.shipping_methods
+ expect(available_shipping_methods).to eq [shipping_method_i]
+ end
+
+ it "doesn't return shipping methods which have been added to the order cycle
+ when they don't belong to the order distributor" do
+ distributor_i = create(:distributor_enterprise)
+ distributor_ii = create(:distributor_enterprise)
+ shipping_method_i = create(:shipping_method, distributors: [distributor_i])
+ shipping_method_ii = create(:shipping_method, distributors: [distributor_ii])
+ order_cycle = create(:simple_order_cycle,
+ distributors: [distributor_i, distributor_ii],
+ shipping_methods: [shipping_method_i, shipping_method_ii])
+ order = build(:order, distributor: distributor_ii, order_cycle: order_cycle)
+
+ available_shipping_methods = OrderAvailableShippingMethods.new(order).to_a
+
+ expect(available_shipping_methods).not_to eq order_cycle.shipping_methods
+ expect(available_shipping_methods).to eq [shipping_method_ii]
+ end
+ end
+ end
+
+ context "when FilterShippingMethods tag rules are in effect" do
+ let(:user) { create(:user) }
+ let(:distributor) { create(:distributor_enterprise) }
+ let(:other_distributor) { create(:distributor_enterprise) }
+ let!(:distributor_shipping_method) { create(:shipping_method, distributors: [distributor]) }
+ let!(:other_distributor_shipping_method) do
+ create(:shipping_method, distributors: [other_distributor])
+ end
+ let(:customer) { create(:customer, user: user, enterprise: distributor) }
+ let!(:tag_rule) {
+ create(:filter_shipping_methods_tag_rule,
+ enterprise: distributor,
+ preferred_customer_tags: "local",
+ preferred_shipping_method_tags: "local-delivery")
+ }
+ let!(:default_tag_rule) {
+ create(:filter_shipping_methods_tag_rule,
+ enterprise: distributor,
+ is_default: true,
+ preferred_shipping_method_tags: "local-delivery")
+ }
+ let!(:tagged_sm) { distributor_shipping_method }
+ let!(:untagged_sm) { other_distributor_shipping_method }
+
+ before do
+ tagged_sm.update_attribute(:tag_list, 'local-delivery')
+ distributor.shipping_methods = [tagged_sm, untagged_sm]
+ end
+
+ context "with a preferred visiblity of 'visible', default visibility of 'hidden'" do
+ before {
+ tag_rule.update_attribute(:preferred_matched_shipping_methods_visibility, 'visible')
+ }
+ before {
+ default_tag_rule.update_attribute(:preferred_matched_shipping_methods_visibility,
+ 'hidden')
+ }
+
+ context "order cycle selling own produce only" do
+ let(:order_cycle) { create(:sells_own_order_cycle) }
+ let(:order) { build(:order, distributor: distributor, order_cycle: order_cycle) }
+
+ context "when the customer is nil" do
+ let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order).to_a }
+
+ it "applies default action (hide)" do
+ expect(available_shipping_methods).to include untagged_sm
+ expect(available_shipping_methods).to_not include tagged_sm
+ end
+ end
+
+ context "when a customer is present" do
+ let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order, customer).to_a }
+
+ context "and the customer's tags match" do
+ before do
+ customer.update_attribute(:tag_list, 'local')
+ end
+
+ it "applies the action (show)" do
+ expect(available_shipping_methods).to include tagged_sm, untagged_sm
+ end
+ end
+
+ context "and the customer's tags don't match" do
+ before do
+ customer.update_attribute(:tag_list, 'something')
+ end
+
+ it "applies the default action (hide)" do
+ expect(available_shipping_methods).to include untagged_sm
+ expect(available_shipping_methods).to_not include tagged_sm
+ end
+ end
+ end
+ end
+
+ context "distributor order cycle" do
+ context "when the shipping method without the tag rule is attached to the order cycle
+ and the shipping method with the tag rule is not" do
+ let(:order_cycle) do
+ create(:distributor_order_cycle,
+ distributors: [distributor], shipping_methods: [untagged_sm])
+ end
+ let(:order) { build(:order, distributor: distributor, order_cycle: order_cycle) }
+ let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order, customer).to_a }
+
+ context "when the customer's tags match" do
+ before do
+ customer.update_attribute(:tag_list, 'local')
+ end
+
+ it "doesn't display the shipping method with the prefered visibility 'visible' tag
+ even though the customer's tags match
+ because it hasn't been attached to the order cycle" do
+ expect(available_shipping_methods).to include untagged_sm
+ expect(available_shipping_methods).to_not include tagged_sm
+ end
+ end
+ end
+ end
+ end
+
+ context "with a preferred visiblity of 'hidden', default visibility of 'visible'" do
+ before {
+ tag_rule.update_attribute(:preferred_matched_shipping_methods_visibility, 'hidden')
+ }
+ before {
+ default_tag_rule.update_attribute(:preferred_matched_shipping_methods_visibility,
+ 'visible')
+ }
+
+ context "order cycle selling own produce only" do
+ let(:order_cycle) { create(:sells_own_order_cycle) }
+ let(:order) { build(:order, distributor: distributor, order_cycle: order_cycle) }
+
+ context "when the customer is nil" do
+ let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order).to_a }
+
+ it "applies default action (show)" do
+ expect(available_shipping_methods).to include tagged_sm, untagged_sm
+ end
+ end
+
+ context "when a customer is present" do
+ let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order, customer).to_a }
+
+ context "and the customer's tags match" do
+ before do
+ customer.update_attribute(:tag_list, 'local')
+ end
+
+ it "applies the action (hide)" do
+ expect(available_shipping_methods).to include untagged_sm
+ expect(available_shipping_methods).to_not include tagged_sm
+ end
+ end
+
+ context "and the customer's tags don't match" do
+ before do
+ customer.update_attribute(:tag_list, 'something')
+ end
+
+ it "applies the default action (show)" do
+ expect(available_shipping_methods).to include tagged_sm, untagged_sm
+ end
+ end
+ end
+ end
+
+ context "distributor order cycle" do
+ context "when the shipping method without the tag rule is attached to the order cycle
+ and the shipping method with the tag rule is not" do
+ let(:order_cycle) do
+ create(:distributor_order_cycle,
+ distributors: [distributor], shipping_methods: [untagged_sm])
+ end
+ let(:order) { build(:order, distributor: distributor, order_cycle: order_cycle) }
+
+ context "when the customer is nil" do
+ let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order).to_a }
+
+ it "doesn't display the shipping method tagged to be visible by default
+ because it is not attached to the order cycle" do
+ expect(available_shipping_methods).to include untagged_sm
+ expect(available_shipping_methods).to_not include tagged_sm
+ end
+ end
+
+ context "when a customer is present" do
+ let(:available_shipping_methods) { OrderAvailableShippingMethods.new(order, customer).to_a }
+
+ context "when the customer's tags don't match" do
+ before do
+ customer.update_attribute(:tag_list, 'something')
+ end
+
+ it "doesn't display the shipping method tagged to be visible by default
+ because it is not attached to the order cycle" do
+ expect(available_shipping_methods).to include untagged_sm
+ expect(available_shipping_methods).to_not include tagged_sm
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/system/admin/order_cycles/complex_creating_specific_time_spec.rb b/spec/system/admin/order_cycles/complex_creating_specific_time_spec.rb
index e16d86796f..19ab92a0bb 100644
--- a/spec/system/admin/order_cycles/complex_creating_specific_time_spec.rb
+++ b/spec/system/admin/order_cycles/complex_creating_specific_time_spec.rb
@@ -22,6 +22,8 @@ describe '
v2 = create(:variant, product: product)
distributor = create(:distributor_enterprise, name: 'My distributor',
with_payment_and_shipping: true)
+ shipping_method_i = distributor.shipping_methods.first
+ shipping_method_ii = create(:shipping_method, distributors: [distributor])
# Relationships required for interface to work
create(:enterprise_relationship, parent: supplier, child: coordinator,
@@ -129,6 +131,12 @@ describe '
select 'Distributor fee',
from: 'order_cycle_outgoing_exchange_0_enterprise_fees_0_enterprise_fee_id'
+ click_button 'Save and Next'
+
+ # And I select preferred shipping methods
+ check "order_cycle_preferred_shipping_method_ids_#{shipping_method_i.id}"
+ uncheck "order_cycle_preferred_shipping_method_ids_#{shipping_method_ii.id}"
+
click_button 'Save and Back to List'
oc = OrderCycle.last
@@ -161,5 +169,8 @@ describe '
expect(exchange.pickup_time).to eq('pickup time')
expect(exchange.pickup_instructions).to eq('pickup instructions')
expect(exchange.tag_list).to eq(['wholesale'])
+
+ # And the shipping method should be attached
+ expect(oc.shipping_methods).to eq([shipping_method_i])
end
end