mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Add tag_rules logic to main query before pagination
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
# The stock-checking includes on_demand and stock level overrides from variant_overrides.
|
||||
|
||||
class OrderCycleDistributedProducts
|
||||
def initialize(distributor, order_cycle)
|
||||
def initialize(distributor, order_cycle, customer)
|
||||
@distributor = distributor
|
||||
@order_cycle = order_cycle
|
||||
@customer = customer
|
||||
end
|
||||
|
||||
def products_relation
|
||||
@@ -12,26 +13,97 @@ class OrderCycleDistributedProducts
|
||||
end
|
||||
|
||||
def variants_relation
|
||||
@order_cycle.
|
||||
variants_distributed_by(@distributor).
|
||||
order_cycle.
|
||||
variants_distributed_by(distributor).
|
||||
merge(stocked_variants_and_overrides)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :distributor, :order_cycle, :customer
|
||||
|
||||
def stocked_products
|
||||
@order_cycle.
|
||||
variants_distributed_by(@distributor).
|
||||
order_cycle.
|
||||
variants_distributed_by(distributor).
|
||||
merge(stocked_variants_and_overrides).
|
||||
select("DISTINCT spree_variants.product_id")
|
||||
end
|
||||
|
||||
def stocked_variants_and_overrides
|
||||
Spree::Variant.
|
||||
stocked_variants = Spree::Variant.
|
||||
joins("LEFT OUTER JOIN variant_overrides ON variant_overrides.variant_id = spree_variants.id
|
||||
AND variant_overrides.hub_id = #{@distributor.id}").
|
||||
AND variant_overrides.hub_id = #{distributor.id}").
|
||||
joins(:stock_items).
|
||||
where(query_stock_with_overrides)
|
||||
|
||||
if distributor_rules.any?
|
||||
stocked_variants = apply_tag_rules(stocked_variants)
|
||||
end
|
||||
|
||||
stocked_variants
|
||||
end
|
||||
|
||||
def apply_tag_rules(stocked_variants)
|
||||
stocked_variants.where(query_with_tag_rules)
|
||||
end
|
||||
|
||||
def distributor_rules
|
||||
@distributor_rules ||= TagRule::FilterProducts.prioritised.for(distributor)
|
||||
end
|
||||
|
||||
def customer_tag_list
|
||||
customer.andand.tag_list || []
|
||||
end
|
||||
|
||||
def default_rule_tags
|
||||
default_rules.map(&:preferred_variant_tags)
|
||||
end
|
||||
|
||||
def hide_rule_tags
|
||||
hide_rules.map(&:preferred_variant_tags)
|
||||
end
|
||||
|
||||
def show_rule_tags
|
||||
show_rules.map(&:preferred_variant_tags)
|
||||
end
|
||||
|
||||
def overrides_to_hide
|
||||
@overrides_to_hide = VariantOverride.where(hub_id: distributor.id).
|
||||
tagged_with(default_rule_tags + hide_rule_tags, any: true).
|
||||
pluck(:id)
|
||||
end
|
||||
|
||||
def overrides_to_show
|
||||
@overrides_to_show = VariantOverride.where(hub_id: distributor.id).
|
||||
tagged_with(show_rule_tags, any: true).
|
||||
pluck(:id)
|
||||
end
|
||||
|
||||
def customer_applicable_rules
|
||||
# Rules which apply specifically to the current customer
|
||||
@customer_applicable_rules ||= non_default_rules.select{ |rule| customer_tagged?(rule) }
|
||||
end
|
||||
|
||||
def default_rules
|
||||
# These rules hide a variant_override with tag X
|
||||
distributor_rules.select(&:is_default?)
|
||||
end
|
||||
|
||||
def non_default_rules
|
||||
# These rules show or hide a variant_override with tag X for customer with tag Y
|
||||
distributor_rules.reject(&:is_default?)
|
||||
end
|
||||
|
||||
def hide_rules
|
||||
@hide_rules ||= customer_applicable_rules.select{ |rule| rule.preferred_matched_variants_visibility == 'hidden'}
|
||||
end
|
||||
|
||||
def show_rules
|
||||
customer_applicable_rules - hide_rules
|
||||
end
|
||||
|
||||
def customer_tagged?(rule)
|
||||
customer_tag_list.include? rule.preferred_customer_tags
|
||||
end
|
||||
|
||||
def query_stock_with_overrides
|
||||
@@ -42,6 +114,22 @@ class OrderCycleDistributedProducts
|
||||
AND #{variant_not_on_demand} AND #{variant_in_stock} ) )"
|
||||
end
|
||||
|
||||
def query_with_tag_rules
|
||||
"#{variant_not_overriden} OR ( #{variant_overriden}
|
||||
AND ( #{override_not_hidden_by_rule}
|
||||
OR #{override_shown_by_rule} ) )"
|
||||
end
|
||||
|
||||
def override_not_hidden_by_rule
|
||||
return "FALSE" unless overrides_to_hide.any?
|
||||
"variant_overrides.id NOT IN (#{overrides_to_hide.join(',')})"
|
||||
end
|
||||
|
||||
def override_shown_by_rule
|
||||
return "FALSE" unless overrides_to_show.any?
|
||||
"variant_overrides.id IN (#{overrides_to_show.join(',')})"
|
||||
end
|
||||
|
||||
def variant_not_overriden
|
||||
"variant_overrides.id IS NULL"
|
||||
end
|
||||
|
||||
@@ -4,9 +4,10 @@ module OpenFoodNetwork
|
||||
class ProductsRenderer
|
||||
class NoProducts < RuntimeError; end
|
||||
|
||||
def initialize(distributor, order_cycle, params = {})
|
||||
def initialize(distributor, order_cycle, customer, params = {})
|
||||
@distributor = distributor
|
||||
@order_cycle = order_cycle
|
||||
@customer = customer
|
||||
@params = params
|
||||
end
|
||||
|
||||
@@ -28,7 +29,7 @@ module OpenFoodNetwork
|
||||
|
||||
private
|
||||
|
||||
attr_reader :order_cycle, :distributor, :params
|
||||
attr_reader :order_cycle, :distributor, :customer, :params
|
||||
|
||||
def products
|
||||
return unless order_cycle
|
||||
@@ -44,7 +45,7 @@ module OpenFoodNetwork
|
||||
end
|
||||
|
||||
def distributed_products
|
||||
OrderCycleDistributedProducts.new(distributor, order_cycle)
|
||||
OrderCycleDistributedProducts.new(distributor, order_cycle, customer)
|
||||
end
|
||||
|
||||
def taxon_order
|
||||
|
||||
@@ -6,7 +6,8 @@ module OpenFoodNetwork
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let(:order_cycle) { create(:simple_order_cycle, distributors: [distributor]) }
|
||||
let(:exchange) { order_cycle.exchanges.to_enterprises(distributor).outgoing.first }
|
||||
let(:pr) { ProductsRenderer.new(distributor, order_cycle) }
|
||||
let(:customer) { create(:customer) }
|
||||
let(:pr) { ProductsRenderer.new(distributor, order_cycle, customer) }
|
||||
|
||||
describe "sorting" do
|
||||
let(:t1) { create(:taxon) }
|
||||
@@ -89,7 +90,7 @@ module OpenFoodNetwork
|
||||
let!(:v2) { create(:variant, product: p, unit_value: 5) } # Not in exchange
|
||||
let!(:v3) { create(:variant, product: p, unit_value: 7, inventory_items: [create(:inventory_item, enterprise: hub, visible: true)]) }
|
||||
let!(:v4) { create(:variant, product: p, unit_value: 9, inventory_items: [create(:inventory_item, enterprise: hub, visible: false)]) }
|
||||
let(:pr) { ProductsRenderer.new(hub, oc) }
|
||||
let(:pr) { ProductsRenderer.new(hub, oc, customer) }
|
||||
let(:variants) { pr.send(:variants_for_shop_by_id) }
|
||||
|
||||
it "scopes variants to distribution" do
|
||||
|
||||
@@ -5,13 +5,14 @@ describe OrderCycleDistributedProducts do
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let(:product) { create(:product) }
|
||||
let(:variant) { product.variants.first }
|
||||
let(:customer) { create(:customer) }
|
||||
let(:order_cycle) do
|
||||
create(:simple_order_cycle, distributors: [distributor], variants: [variant])
|
||||
end
|
||||
|
||||
describe "product distributed by distributor in the OC" do
|
||||
it "returns products" do
|
||||
expect(described_class.new(distributor, order_cycle).products_relation).to eq([product])
|
||||
expect(described_class.new(distributor, order_cycle, customer).products_relation).to eq([product])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -25,7 +26,7 @@ describe OrderCycleDistributedProducts do
|
||||
end
|
||||
|
||||
it "does not return product" do
|
||||
expect(described_class.new(distributor, order_cycle).products_relation).to_not include product
|
||||
expect(described_class.new(distributor, order_cycle, customer).products_relation).to_not include product
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,19 +37,19 @@ describe OrderCycleDistributedProducts do
|
||||
end
|
||||
|
||||
it "does not return product" do
|
||||
expect(described_class.new(distributor, order_cycle).products_relation).to_not include product
|
||||
expect(described_class.new(distributor, order_cycle, customer).products_relation).to_not include product
|
||||
end
|
||||
end
|
||||
|
||||
describe "filtering products that are out of stock" do
|
||||
context "with regular variants" do
|
||||
it "returns product when variant is in stock" do
|
||||
expect(described_class.new(distributor, order_cycle).products_relation).to include product
|
||||
expect(described_class.new(distributor, order_cycle, customer).products_relation).to include product
|
||||
end
|
||||
|
||||
it "does not return product when variant is out of stock" do
|
||||
variant.update_attribute(:on_hand, 0)
|
||||
expect(described_class.new(distributor, order_cycle).products_relation).to_not include product
|
||||
expect(described_class.new(distributor, order_cycle, customer).products_relation).to_not include product
|
||||
end
|
||||
end
|
||||
|
||||
@@ -56,13 +57,13 @@ describe OrderCycleDistributedProducts do
|
||||
let!(:override) { create(:variant_override, hub: distributor, variant: variant, count_on_hand: 0) }
|
||||
|
||||
it "does not return product when an override is out of stock" do
|
||||
expect(described_class.new(distributor, order_cycle).products_relation).to_not include product
|
||||
expect(described_class.new(distributor, order_cycle, customer).products_relation).to_not include product
|
||||
end
|
||||
|
||||
it "returns product when an override is in stock" do
|
||||
variant.update_attribute(:on_hand, 0)
|
||||
override.update_attribute(:count_on_hand, 10)
|
||||
expect(described_class.new(distributor, order_cycle).products_relation).to include product
|
||||
expect(described_class.new(distributor, order_cycle, customer).products_relation).to include product
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -71,12 +72,13 @@ describe OrderCycleDistributedProducts do
|
||||
describe "#variants_relation" do
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let(:oc) { create(:simple_order_cycle, distributors: [distributor], variants: [v1, v3]) }
|
||||
let(:customer) { create(:customer) }
|
||||
let(:product) { create(:simple_product) }
|
||||
let!(:v1) { create(:variant, product: product) }
|
||||
let!(:v2) { create(:variant, product: product) }
|
||||
let!(:v3) { create(:variant, product: product) }
|
||||
let!(:vo) { create(:variant_override, hub: distributor, variant_id: v3.id, count_on_hand: 0) }
|
||||
let(:variants) { described_class.new(distributor, oc).variants_relation }
|
||||
let(:variants) { described_class.new(distributor, oc, customer).variants_relation }
|
||||
|
||||
it "returns variants in the oc" do
|
||||
expect(variants).to include v1
|
||||
|
||||
Reference in New Issue
Block a user