Reduce restrictions for creating subscriptions

Allow the following variants:

* Variants of permitted producers
* Variants of hub
* Variants that are in outgoing exchanges where the hub is receiver
This commit is contained in:
Kristina Lim
2019-01-20 17:51:37 +08:00
parent 57f6a7a3b9
commit 929290fc77
11 changed files with 296 additions and 121 deletions

View File

@@ -6,7 +6,11 @@ angular.module("admin.subscriptions").controller "SubscriptionController", ($sco
$scope.schedules = Schedules.all
$scope.paymentMethods = PaymentMethods.all
$scope.shippingMethods = ShippingMethods.all
$scope.distributor_id = $scope.subscription.shop_id # variant selector requires distributor_id
# Variant selector requires these
$scope.distributor_id = $scope.subscription.shop_id
$scope.eligible_for_subscriptions = true
$scope.view = if $scope.subscription.id? then 'review' else 'details'
$scope.nextCallbacks = {}
$scope.backCallbacks = {}

View File

@@ -22,6 +22,7 @@ angular.module("admin.utils").directive "variantAutocomplete", ($timeout) ->
q: term
distributor_id: scope.distributor_id
order_cycle_id: scope.order_cycle_id
eligible_for_subscriptions: scope.eligible_for_subscriptions
results: (data, page) ->
results: data
formatResult: (variant) ->

View File

@@ -1,6 +1,7 @@
require 'open_food_network/permissions'
require 'open_food_network/order_cycle_permissions'
require 'open_food_network/scope_variant_to_hub'
require "open_food_network/subscription_service"
module Admin
class SubscriptionLineItemsController < ResourceController
@@ -26,7 +27,7 @@ module Admin
@shop = Enterprise.managed_by(spree_current_user).find_by_id(params[:shop_id])
@schedule = permissions.editable_schedules.find_by_id(params[:schedule_id])
@order_cycle = @schedule.andand.current_or_next_order_cycle
@variant = Spree::Variant.stockable_by(@shop).find_by_id(params[:subscription_line_item][:variant_id])
@variant = variant_if_eligible(params[:subscription_line_item][:variant_id]) if @shop.present?
end
def new_actions
@@ -50,5 +51,9 @@ module Admin
OpenFoodNetwork::ScopeVariantToHub.new(@shop).scope(@variant)
@variant.price + fee_calculator.indexed_fees_for(@variant)
end
def variant_if_eligible(variant_id)
OpenFoodNetwork::SubscriptionService.eligible_variants(@shop).find_by_id(variant_id)
end
end
end

View File

@@ -2,6 +2,8 @@
# Public interface consists of #valid? method provided by ActiveModel::Validations
# and #json_errors which compiles a serializable hash of errors
require "open_food_network/subscription_service"
class SubscriptionValidator
include ActiveModel::Naming
include ActiveModel::Conversion
@@ -97,15 +99,12 @@ class SubscriptionValidator
errors.add(:subscription_line_items, :not_available, name: name)
end
# TODO: Extract this into a separate class
def available_variant_ids
@available_variant_ids ||=
Spree::Variant.joins(exchanges: { order_cycle: :schedules })
.where(id: subscription_line_items.map(&:variant_id))
.where(schedules: { id: schedule }, exchanges: { incoming: false, receiver_id: shop })
.merge(OrderCycle.not_closed)
.select('DISTINCT spree_variants.id')
.pluck(:id)
return @available_variant_ids if @available_variant_ids.present?
subscription_variant_ids = subscription_line_items.map(&:variant_id)
@available_variant_ids = OpenFoodNetwork::SubscriptionService.eligible_variants(shop)
.where(id: subscription_variant_ids).pluck(:id)
end
def build_msg_from(k, msg)

View File

@@ -5,6 +5,8 @@ require 'open_food_network/scope_variant_to_hub'
# Further restrictions on the schedule, order_cycle or distributor through which the
# products are available are also possible
require "open_food_network/subscription_service"
module OpenFoodNetwork
class ScopeVariantsForSearch
def initialize(params)
@@ -33,6 +35,10 @@ module OpenFoodNetwork
Spree::Variant.where(is_master: false).ransack(search_params.merge(m: 'or')).result
end
def distributor
Enterprise.find params[:distributor_id]
end
def scope_to_schedule
@variants = @variants.in_schedule(params[:schedule_id])
end
@@ -42,12 +48,29 @@ module OpenFoodNetwork
end
def scope_to_distributor
distributor = Enterprise.find params[:distributor_id]
if params[:eligible_for_subscriptions]
scope_to_eligible_for_subscriptions_in_distributor
else
scope_to_available_for_orders_in_distributor
end
end
def scope_to_available_for_orders_in_distributor
@variants = @variants.in_distributor(distributor)
scope_variants_to_distributor(@variants, distributor)
end
def scope_to_eligible_for_subscriptions_in_distributor
eligible_variants_scope = OpenFoodNetwork::SubscriptionService.eligible_variants(distributor)
@variants = @variants.merge(eligible_variants_scope)
scope_variants_to_distributor(@variants, distributor)
end
def scope_variants_to_distributor(variants, distributor)
scoper = OpenFoodNetwork::ScopeVariantToHub.new(distributor)
# Perform scoping after all filtering is done.
# Filtering could be a problem on scoped variants.
@variants.each { |v| scoper.scope(v) }
variants.each { |v| scoper.scope(v) }
end
end
end

View File

@@ -0,0 +1,28 @@
module OpenFoodNetwork
class SubscriptionService
# Includes the following variants:
# - Variants of permitted producers
# - Variants of hub
# - Variants that are in outgoing exchanges where the hub is receiver
def self.eligible_variants(distributor)
permitted_order_cycle_enterprise_ids = EnterpriseRelationship.permitting(distributor)
.with_permission(:add_to_order_cycle).pluck(:parent_id)
permitted_producer_ids = Enterprise.is_primary_producer
.where('enterprises.id IN (?)', permitted_order_cycle_enterprise_ids).pluck(:id)
outgoing_exchange_variant_ids = ExchangeVariant
.select("DISTINCT exchange_variants.variant_id")
.joins(:exchange)
.where(exchanges: { incoming: false, receiver_id: distributor.id })
.pluck(:variant_id)
variant_conditions = ["spree_products.supplier_id IN (?)", permitted_producer_ids | [distributor.id]]
if outgoing_exchange_variant_ids.present?
variant_conditions[0] << " OR spree_variants.id IN (?)"
variant_conditions << outgoing_exchange_variant_ids
end
Spree::Variant.joins(:product).where(is_master: false).where(*variant_conditions)
end
end
end

View File

@@ -10,9 +10,9 @@ describe Admin::SubscriptionLineItemsController, type: :controller do
let(:unmanaged_shop) { create(:enterprise) }
let!(:product) { create(:product) }
let!(:variant) { create(:variant, product: product, unit_value: '100', price: 15.00, option_values: []) }
let!(:outgoing_exchange) { order_cycle.exchanges.create(sender: shop, receiver: shop, variants: [variant], enterprise_fees: [enterprise_fee]) }
let!(:enterprise_fee) { create(:enterprise_fee, amount: 3.50) }
let!(:order_cycle) { create(:simple_order_cycle, coordinator: shop, orders_open_at: 2.days.from_now, orders_close_at: 7.days.from_now) }
let!(:outgoing_exchange) { order_cycle.exchanges.create(sender: shop, receiver: shop, variants: [variant], enterprise_fees: [enterprise_fee]) }
let!(:schedule) { create(:schedule, order_cycles: [order_cycle]) }
let(:unmanaged_schedule) { create(:schedule, order_cycles: [create(:simple_order_cycle, coordinator: unmanaged_shop)]) }
@@ -42,6 +42,8 @@ describe Admin::SubscriptionLineItemsController, type: :controller do
before { params.merge!(shop_id: shop.id) }
context "but the shop doesn't have permission to sell product in question" do
let!(:outgoing_exchange) { }
it "returns an error" do
spree_post :build, params
json_response = JSON.parse(response.body)

View File

@@ -341,7 +341,7 @@ describe Admin::SubscriptionsController, type: :controller do
end
context 'with subscription_line_items params' do
let!(:product2) { create(:product, supplier: shop) }
let!(:product2) { create(:product) }
let!(:variant2) { create(:variant, product: product2, unit_value: '1000', price: 6.00, option_values: []) }
before do

View File

@@ -145,13 +145,13 @@ feature 'Subscriptions' do
let!(:customer_user) { create(:user) }
let!(:credit_card1) { create(:credit_card, user: customer_user, cc_type: 'visa', last_digits: 1111, month: 10, year: 2030) }
let!(:customer) { create(:customer, enterprise: shop, bill_address: address, user: customer_user, allow_charges: true) }
let!(:product1) { create(:product, supplier: shop) }
let!(:product2) { create(:product, supplier: shop) }
let!(:variant1) { create(:variant, product: product1, unit_value: '100', price: 12.00, option_values: []) }
let!(:variant2) { create(:variant, product: product2, unit_value: '1000', price: 6.00, option_values: []) }
let!(:test_product) { create(:product, supplier: shop, distributors: []) }
let!(:test_variant) { create(:variant, product: test_product, unit_value: "100", price: 12.00, option_values: []) }
let!(:shop_product) { create(:product, supplier: shop, distributors: [shop]) }
let!(:shop_variant) { create(:variant, product: shop_product, unit_value: "1000", price: 6.00, option_values: []) }
let!(:enterprise_fee) { create(:enterprise_fee, amount: 1.75) }
let!(:order_cycle) { create(:simple_order_cycle, coordinator: shop, orders_open_at: 2.days.from_now, orders_close_at: 7.days.from_now) }
let!(:outgoing_exchange) { order_cycle.exchanges.create(sender: shop, receiver: shop, variants: [variant1, variant2], enterprise_fees: [enterprise_fee]) }
let!(:outgoing_exchange) { order_cycle.exchanges.create(sender: shop, receiver: shop, variants: [test_variant, shop_variant], enterprise_fees: [enterprise_fee]) }
let!(:schedule) { create(:schedule, order_cycles: [order_cycle]) }
let!(:payment_method) { create(:stripe_payment_method, name: 'Credit Card', distributors: [shop], preferred_enterprise_id: shop.id) }
let!(:shipping_method) { create(:shipping_method, distributors: [shop]) }
@@ -217,11 +217,9 @@ feature 'Subscriptions' do
expect(page).to have_content 'Please add at least one product'
# Adding a product and getting a price estimate
select2_search_async product1.name, from: I18n.t(:name_or_sku), dropdown_css: '.select2-drop'
fill_in 'add_quantity', with: 2
click_link 'Add'
add_variant_to_subscription test_variant, 2
within 'table#subscription-line-items tr.item', match: :first do
expect(page).to have_selector 'td.description', text: "#{product1.name} - #{variant1.full_name}"
expect(page).to have_selector '.description', text: "#{test_product.name} - #{test_variant.full_name}"
expect(page).to have_selector 'td.price', text: "$13.75"
expect(page).to have_input 'quantity', with: "2"
expect(page).to have_selector 'td.total', text: "$27.50"
@@ -243,11 +241,9 @@ feature 'Subscriptions' do
click_button('edit-products')
# Adding a new product
select2_search_async product2.name, from: I18n.t(:name_or_sku), dropdown_css: '.select2-drop'
fill_in 'add_quantity', with: 3
click_link 'Add'
add_variant_to_subscription shop_variant, 3
within 'table#subscription-line-items tr.item', match: :first do
expect(page).to have_selector 'td.description', text: "#{product2.name} - #{variant2.full_name}"
expect(page).to have_selector '.description', text: "#{shop_product.name} - #{shop_variant.full_name}"
expect(page).to have_selector 'td.price', text: "$7.75"
expect(page).to have_input 'quantity', with: "3"
expect(page).to have_selector 'td.total', text: "$23.25"
@@ -266,7 +262,7 @@ feature 'Subscriptions' do
# Prices are shown in the index
within 'table#subscription-line-items tr.item', match: :first do
expect(page).to have_selector 'td.description', text: "#{product2.name} - #{variant2.full_name}"
expect(page).to have_selector '.description', text: "#{shop_product.name} - #{shop_variant.full_name}"
expect(page).to have_selector 'td.price', text: "$7.75"
expect(page).to have_input 'quantity', with: "3"
expect(page).to have_selector 'td.total', text: "$23.25"
@@ -284,7 +280,7 @@ feature 'Subscriptions' do
# Standing Line Items are created
expect(subscription.subscription_line_items.count).to eq 1
subscription_line_item = subscription.subscription_line_items.first
expect(subscription_line_item.variant).to eq variant2
expect(subscription_line_item.variant).to eq shop_variant
expect(subscription_line_item.quantity).to eq 3
end
end
@@ -336,7 +332,7 @@ feature 'Subscriptions' do
# Existing products should be visible
click_button 'edit-products'
within "#sli_0" do
expect(page).to have_selector 'td.description', text: "#{product1.name} - #{variant1.full_name}"
expect(page).to have_selector '.description', text: "#{product1.name} - #{variant1.full_name}"
expect(page).to have_selector 'td.price', text: "$13.75"
expect(page).to have_input 'quantity', with: "2"
expect(page).to have_selector 'td.total', text: "$27.50"
@@ -350,11 +346,9 @@ feature 'Subscriptions' do
expect(page).to have_content 'Please add at least one product'
# Add variant2 to the subscription
select2_search_async product2.name, from: I18n.t(:name_or_sku), dropdown_css: '.select2-drop'
fill_in 'add_quantity', with: 1
click_link 'Add'
add_variant_to_subscription(variant2, 1)
within "#sli_0" do
expect(page).to have_selector 'td.description', text: "#{product2.name} - #{variant2.full_name}"
expect(page).to have_selector '.description', text: "#{product2.name} - #{variant2.full_name}"
expect(page).to have_selector 'td.price', text: "$7.75"
expect(page).to have_input 'quantity', with: "1"
expect(page).to have_selector 'td.total', text: "$7.75"
@@ -364,11 +358,9 @@ feature 'Subscriptions' do
expect(page).to have_selector '#order_form_total', text: "$7.75"
# Add variant3 to the subscription (even though it is not available)
select2_search_async product3.name, from: I18n.t(:name_or_sku), dropdown_css: '.select2-drop'
fill_in 'add_quantity', with: 1
click_link 'Add'
add_variant_to_subscription(variant3, 1)
within "#sli_1" do
expect(page).to have_selector 'td.description', text: "#{product3.name} - #{variant3.full_name}"
expect(page).to have_selector '.description', text: "#{product3.name} - #{variant3.full_name}"
expect(page).to have_selector 'td.price', text: "$22.00"
expect(page).to have_input 'quantity', with: "1"
expect(page).to have_selector 'td.total', text: "$22.00"
@@ -377,9 +369,6 @@ feature 'Subscriptions' do
# Total should be $29.75
expect(page).to have_selector '#order_form_total', text: "$29.75"
click_button 'Save Changes'
expect(page).to have_content "#{product3.name} - #{variant3.full_name} is not available from the selected schedule"
# Remove variant3 from the subscription
within '#sli_1' do
find("a.delete-item").click
@@ -421,5 +410,103 @@ feature 'Subscriptions' do
end
end
end
describe "allowed variants" do
let!(:customer) { create(:customer, enterprise: shop, allow_charges: true) }
let!(:credit_card) { create(:credit_card, user: customer.user) }
let!(:shop_product) { create(:product, supplier: shop, distributors: [shop]) }
let!(:shop_variant) { create(:variant, product: shop_product, unit_value: "2000") }
let!(:permitted_supplier) do
create(:supplier_enterprise).tap do |supplier|
create(:enterprise_relationship, child: shop, parent: supplier, permissions_list: [:add_to_order_cycle])
end
end
let!(:permitted_supplier_product) { create(:product, supplier: permitted_supplier, distributors: [shop]) }
let!(:permitted_supplier_variant) { create(:variant, product: permitted_supplier_product, unit_value: "2000") }
let!(:incoming_exchange_product) { create(:product, distributors: [shop]) }
let!(:incoming_exchange_variant) do
create(:variant, product: incoming_exchange_product, unit_value: "2000").tap do |variant|
create(:exchange, order_cycle: order_cycle, incoming: true, receiver: shop, variants: [variant])
end
end
let!(:outgoing_exchange_product) { create(:product, distributors: [shop]) }
let!(:outgoing_exchange_variant) do
create(:variant, product: outgoing_exchange_product, unit_value: "2000").tap do |variant|
create(:exchange, order_cycle: order_cycle, incoming: false, receiver: shop, variants: [variant])
end
end
let!(:enterprise_fee) { create(:enterprise_fee, amount: 1.75) }
let!(:order_cycle) { create(:simple_order_cycle, coordinator: shop) }
let!(:schedule) { create(:schedule, order_cycles: [order_cycle]) }
let!(:payment_method) { create(:stripe_payment_method, distributors: [shop], preferred_enterprise_id: shop.id) }
let!(:shipping_method) { create(:shipping_method, distributors: [shop]) }
before do
visit admin_subscriptions_path
click_link "New Subscription"
select2_select shop.name, from: "new_subscription_shop_id"
click_button "Continue"
end
it "permit creating and editing of the subscription" do
select2_select customer.email, from: "customer_id"
select2_select schedule.name, from: "schedule_id"
select2_select payment_method.name, from: "payment_method_id"
select2_select shipping_method.name, from: "shipping_method_id"
find_field("begins_at").click
within(".ui-datepicker-calendar") do
find(".ui-datepicker-today").click
end
click_button "Next"
expect(page).to have_content "BILLING ADDRESS"
click_button "Next"
# Add products
expect(page).to have_content "NAME OR SKU"
add_variant_to_subscription shop_variant, 3
add_variant_to_subscription permitted_supplier_variant, 4
add_variant_to_subscription incoming_exchange_variant, 5
add_variant_to_subscription outgoing_exchange_variant, 6
click_button "Next"
# Submit form
expect {
click_button "Create Subscription"
expect(page).to have_current_path admin_subscriptions_path
}.to change(Subscription, :count).by(1)
# Subscription line items are created
subscription = Subscription.last
expect(subscription.subscription_line_items.count).to eq 4
# Edit the subscription
visit edit_admin_subscription_path(subscription)
# Remove shop_variant from the subscription
click_button "edit-products"
within "#sli_0" do
expect(page).to have_selector ".description", text: shop_variant.name
find("a.delete-item").click
end
# Submit form
click_button "Save Changes"
expect(page).to have_current_path admin_subscriptions_path
# Subscription is saved
visit edit_admin_subscription_path(subscription)
expect(page).to have_selector "#subscription-line-items .item", count: 3
end
end
end
def add_variant_to_subscription(variant, quantity)
row_count = all("#subscription-line-items .item").length
variant_name = variant.full_name.present? ? "#{variant.name} - #{variant.full_name}" : variant.name
select2_search variant.name, from: I18n.t(:name_or_sku), dropdown_css: ".select2-drop", select_text: variant_name
fill_in "add_quantity", with: quantity
click_link "Add"
expect(page).to have_selector("#subscription-line-items .item", count: row_count + 1)
end
end

View File

@@ -0,0 +1,99 @@
require "spec_helper"
require "open_food_network/subscription_service"
module OpenFoodNetwork
describe SubscriptionService do
describe "variant eligibility for subscription" do
let!(:shop) { create(:distributor_enterprise) }
let!(:producer) { create(:supplier_enterprise) }
let!(:product) { create(:product, supplier: producer) }
let!(:variant) { product.variants.first }
let!(:schedule) { create(:schedule, order_cycles: [order_cycle]) }
let!(:subscription) { create(:subscription, shop: shop, schedule: schedule) }
let!(:subscription_line_item) do
create(:subscription_line_item, subscription: subscription, variant: variant)
end
let(:current_order_cycle) do
create(:simple_order_cycle, coordinator: shop, orders_open_at: 1.week.ago,
orders_close_at: 1.week.from_now)
end
let(:future_order_cycle) do
create(:simple_order_cycle, coordinator: shop, orders_open_at: 1.week.from_now,
orders_close_at: 2.weeks.from_now)
end
let(:past_order_cycle) do
create(:simple_order_cycle, coordinator: shop, orders_open_at: 2.weeks.ago,
orders_close_at: 1.week.ago)
end
let!(:order_cycle) { current_order_cycle }
context "if the shop is the supplier for the product" do
let!(:producer) { shop }
it "is eligible" do
expect(described_class.eligible_variants(shop)).to include(variant)
end
end
context "if the supplier is permitted for the shop" do
let!(:enterprise_relationship) { create(:enterprise_relationship, child: shop, parent: product.supplier, permissions_list: [:add_to_order_cycle]) }
it "is eligible" do
expect(described_class.eligible_variants(shop)).to include(variant)
end
end
context "if the variant is involved in an exchange" do
let!(:order_cycle) { create(:simple_order_cycle, coordinator: shop) }
let!(:schedule) { create(:schedule, order_cycles: [order_cycle]) }
context "if it is an incoming exchange where the shop is the receiver" do
let!(:incoming_exchange) { order_cycle.exchanges.create(sender: product.supplier, receiver: shop, incoming: true, variants: [variant]) }
it "is not eligible" do
expect(described_class.eligible_variants(shop)).to_not include(variant)
end
end
context "if it is an outgoing exchange where the shop is the receiver" do
let!(:outgoing_exchange) { order_cycle.exchanges.create(sender: product.supplier, receiver: shop, incoming: false, variants: [variant]) }
context "if the order cycle is currently open" do
let!(:order_cycle) { current_order_cycle }
it "is eligible" do
expect(described_class.eligible_variants(shop)).to include(variant)
end
end
context "if the order cycle opens in the future" do
let!(:order_cycle) { future_order_cycle }
it "is eligible" do
expect(described_class.eligible_variants(shop)).to include(variant)
end
end
context "if the order cycle closed in the past" do
let!(:order_cycle) { past_order_cycle }
it "is eligible" do
expect(described_class.eligible_variants(shop)).to include(variant)
end
end
end
end
context "if the variant is unrelated" do
it "is not eligible" do
expect(described_class.eligible_variants(shop)).to_not include(variant)
end
end
end
end
end

View File

@@ -1,10 +1,11 @@
require "spec_helper"
describe SubscriptionValidator do
let(:shop) { instance_double(Enterprise, name: "Shop") }
let(:owner) { create(:user) }
let(:shop) { create(:enterprise, name: "Shop", owner: owner) }
describe "delegation" do
let(:subscription) { create(:subscription) }
let(:subscription) { create(:subscription, shop: shop) }
let(:validator) { SubscriptionValidator.new(subscription) }
it "delegates to subscription" do
@@ -440,6 +441,7 @@ describe SubscriptionValidator do
context "but some variants are unavailable" do
let(:product) { instance_double(Spree::Product, name: "some_name") }
before do
allow(validator).to receive(:available_variant_ids) { [variant2.id] }
allow(variant1).to receive(:product) { product }
@@ -453,7 +455,9 @@ describe SubscriptionValidator do
end
context "and all requested variants are available" do
before { allow(validator).to receive(:available_variant_ids) { [variant1.id, variant2.id] } }
before do
allow(validator).to receive(:available_variant_ids) { [variant1.id, variant2.id] }
end
it "returns true" do
expect(validator.valid?).to be true
@@ -463,81 +467,4 @@ describe SubscriptionValidator do
end
end
end
describe "variant eligibility for subscription" do
let!(:shop) { create(:distributor_enterprise) }
let!(:producer) { create(:supplier_enterprise) }
let!(:product) { create(:product, supplier: producer) }
let!(:variant) { product.variants.first }
let!(:order_cycle) { current_order_cycle }
let!(:schedule) { create(:schedule, order_cycles: [order_cycle]) }
let!(:subscription) { create(:subscription, shop: shop, schedule: schedule) }
let!(:subscription_line_item) do
create(:subscription_line_item, subscription: subscription, variant: variant)
end
let(:current_order_cycle) do
create(:simple_order_cycle, coordinator: shop, orders_open_at: 1.week.ago,
orders_close_at: 1.week.from_now)
end
let(:future_order_cycle) do
create(:simple_order_cycle, coordinator: shop, orders_open_at: 1.week.from_now,
orders_close_at: 2.weeks.from_now)
end
let(:past_order_cycle) do
create(:simple_order_cycle, coordinator: shop, orders_open_at: 2.weeks.ago,
orders_close_at: 1.week.ago)
end
let(:validator) { SubscriptionValidator.new(subscription) }
context "if it is not in an exchange" do
it "is not eligible" do
expect(validator.__send__(:available_variant_ids)).to_not include(variant.id)
end
end
context "if it is only in an incoming exchange" do
let!(:incoming_exchange) do
create(:exchange, order_cycle: order_cycle, sender: producer, receiver: shop,
incoming: true, variants: [variant])
end
it "is not eligible" do
expect(validator.__send__(:available_variant_ids)).to_not include(variant.id)
end
end
context "if is an outgoing exchange where the shop is the receiver" do
let!(:outgoing_exchange) do
create(:exchange, order_cycle: order_cycle, sender: shop, receiver: shop,
incoming: false, variants: [variant])
end
context "if the order cycle is currently open" do
it "is eligible" do
expect(validator.__send__(:available_variant_ids)).to include(variant.id)
end
end
context "if the order cycle opens in the future" do
let!(:order_cycle) { future_order_cycle }
it "is eligible" do
expect(validator.__send__(:available_variant_ids)).to include(variant.id)
end
end
context "if the order cycle closed in the past" do
let!(:order_cycle) { past_order_cycle }
it "is not eligible" do
expect(validator.__send__(:available_variant_ids)).to_not include(variant.id)
end
end
end
end
end