mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-02 21:57:17 +00:00
Move OFN::SubscriptionService to SubscriptionVariantsService
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
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
|
||||
@@ -54,7 +53,7 @@ module Admin
|
||||
end
|
||||
|
||||
def variant_if_eligible(variant_id)
|
||||
OpenFoodNetwork::SubscriptionService.eligible_variants(@shop).find_by_id(variant_id)
|
||||
SubscriptionVariantsService.eligible_variants(@shop).find_by_id(variant_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,9 +13,9 @@ module Api
|
||||
end
|
||||
|
||||
def in_open_and_upcoming_order_cycles
|
||||
OpenFoodNetwork::SubscriptionService
|
||||
.in_open_and_upcoming_order_cycles?(option_or_assigned_shop, option_or_assigned_schedule,
|
||||
object.variant)
|
||||
SubscriptionVariantsService.in_open_and_upcoming_order_cycles?(option_or_assigned_shop,
|
||||
option_or_assigned_schedule,
|
||||
object.variant)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
# 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
|
||||
@@ -103,7 +101,7 @@ class SubscriptionValidator
|
||||
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)
|
||||
@available_variant_ids = SubscriptionVariantsService.eligible_variants(shop)
|
||||
.where(id: subscription_variant_ids).pluck(:id)
|
||||
end
|
||||
|
||||
|
||||
34
app/services/subscription_variants_service.rb
Normal file
34
app/services/subscription_variants_service.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
class SubscriptionVariantsService
|
||||
# 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
|
||||
|
||||
def self.in_open_and_upcoming_order_cycles?(distributor, schedule, variant)
|
||||
scope = ExchangeVariant.joins(exchange: { order_cycle: :schedules })
|
||||
.where(variant_id: variant, exchanges: { incoming: false, receiver_id: distributor })
|
||||
.merge(OrderCycle.not_closed)
|
||||
scope = scope.where(schedules: { id: schedule })
|
||||
scope.any?
|
||||
end
|
||||
end
|
||||
@@ -5,8 +5,6 @@ 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)
|
||||
@@ -61,7 +59,7 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
def scope_to_eligible_for_subscriptions_in_distributor
|
||||
eligible_variants_scope = OpenFoodNetwork::SubscriptionService.eligible_variants(distributor)
|
||||
eligible_variants_scope = SubscriptionVariantsService.eligible_variants(distributor)
|
||||
@variants = @variants.merge(eligible_variants_scope)
|
||||
scope_variants_to_distributor(@variants, distributor)
|
||||
end
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
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
|
||||
|
||||
def self.in_open_and_upcoming_order_cycles?(distributor, schedule, variant)
|
||||
scope = ExchangeVariant.joins(exchange: { order_cycle: :schedules })
|
||||
.where(variant_id: variant, exchanges: { incoming: false, receiver_id: distributor })
|
||||
.merge(OrderCycle.not_closed)
|
||||
scope = scope.where(schedules: { id: schedule })
|
||||
scope.any?
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,133 +0,0 @@
|
||||
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
|
||||
|
||||
describe "checking if variant in open and upcoming order cycles" do
|
||||
let!(:shop) { create(:enterprise) }
|
||||
let!(:product) { create(:product) }
|
||||
let!(:variant) { product.variants.first }
|
||||
let!(:schedule) { create(:schedule) }
|
||||
|
||||
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 is false" do
|
||||
expect(described_class).not_to be_in_open_and_upcoming_order_cycles(shop, schedule, 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]) }
|
||||
|
||||
it "is true" do
|
||||
expect(described_class).to be_in_open_and_upcoming_order_cycles(shop, schedule, variant)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "if the variant is unrelated" do
|
||||
it "is false" do
|
||||
expect(described_class).to_not be_in_open_and_upcoming_order_cycles(shop, schedule, variant)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
130
spec/services/subscription_variants_service_spec.rb
Normal file
130
spec/services/subscription_variants_service_spec.rb
Normal file
@@ -0,0 +1,130 @@
|
||||
require "spec_helper"
|
||||
|
||||
describe SubscriptionVariantsService 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
|
||||
|
||||
describe "checking if variant in open and upcoming order cycles" do
|
||||
let!(:shop) { create(:enterprise) }
|
||||
let!(:product) { create(:product) }
|
||||
let!(:variant) { product.variants.first }
|
||||
let!(:schedule) { create(:schedule) }
|
||||
|
||||
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 is false" do
|
||||
expect(described_class).not_to be_in_open_and_upcoming_order_cycles(shop, schedule, 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]) }
|
||||
|
||||
it "is true" do
|
||||
expect(described_class).to be_in_open_and_upcoming_order_cycles(shop, schedule, variant)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "if the variant is unrelated" do
|
||||
it "is false" do
|
||||
expect(described_class).to_not be_in_open_and_upcoming_order_cycles(shop, schedule, variant)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user