mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Extract #load_products logic into a new service
This commit is contained in:
70
app/services/shop_products_service.rb
Normal file
70
app/services/shop_products_service.rb
Normal file
@@ -0,0 +1,70 @@
|
||||
# Returns a (paginatable) AR object for the products in stock for a given distributor and OC.
|
||||
# The stock-checking includes on_demand and stock level overrides from variant_overrides.
|
||||
|
||||
class ShopProductsService
|
||||
def initialize(distributor, order_cycle)
|
||||
@distributor = distributor
|
||||
@order_cycle = order_cycle
|
||||
end
|
||||
|
||||
def relation
|
||||
Spree::Product.where(id: distributed_products)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def distributed_products
|
||||
@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.
|
||||
joins("LEFT OUTER JOIN variant_overrides ON variant_overrides.variant_id = spree_variants.id
|
||||
AND variant_overrides.hub_id = #{@distributor.id}").
|
||||
joins(:stock_items).
|
||||
where(query_stock_with_overrides)
|
||||
end
|
||||
|
||||
def query_stock_with_overrides
|
||||
"( #{variant_not_overriden} AND ( #{variant_on_demand} OR #{variant_in_stock} ) )
|
||||
OR ( #{variant_overriden} AND ( #{override_on_demand} OR #{override_in_stock} ) )
|
||||
OR ( #{variant_overriden} AND ( #{override_on_demand_null} AND #{variant_on_demand} ) )
|
||||
OR ( #{variant_overriden} AND ( #{override_on_demand_null}
|
||||
AND #{variant_not_on_demand} AND #{variant_in_stock} ) )"
|
||||
end
|
||||
|
||||
def variant_not_overriden
|
||||
"variant_overrides.id IS NULL"
|
||||
end
|
||||
|
||||
def variant_overriden
|
||||
"variant_overrides.id IS NOT NULL"
|
||||
end
|
||||
|
||||
def variant_in_stock
|
||||
"spree_stock_items.count_on_hand > 0"
|
||||
end
|
||||
|
||||
def variant_on_demand
|
||||
"spree_stock_items.backorderable IS TRUE"
|
||||
end
|
||||
|
||||
def variant_not_on_demand
|
||||
"spree_stock_items.backorderable IS FALSE"
|
||||
end
|
||||
|
||||
def override_on_demand
|
||||
"variant_overrides.on_demand IS TRUE"
|
||||
end
|
||||
|
||||
def override_in_stock
|
||||
"variant_overrides.count_on_hand > 0"
|
||||
end
|
||||
|
||||
def override_on_demand_null
|
||||
"variant_overrides.on_demand IS NULL"
|
||||
end
|
||||
end
|
||||
@@ -32,64 +32,11 @@ module OpenFoodNetwork
|
||||
def load_products
|
||||
return unless @order_cycle
|
||||
|
||||
Spree::Product.where(id: distributed_products).
|
||||
ShopProductsService.new(@distributor, @order_cycle).relation.
|
||||
order(taxon_order).
|
||||
each { |product| scoper.scope(product) }
|
||||
end
|
||||
|
||||
def distributed_products
|
||||
@order_cycle.
|
||||
variants_distributed_by(@distributor).
|
||||
merge(stocked_variants_with_overrides).
|
||||
select("DISTINCT spree_variants.product_id")
|
||||
end
|
||||
|
||||
def stocked_variants_with_overrides
|
||||
Spree::Variant.
|
||||
joins("LEFT OUTER JOIN variant_overrides ON variant_overrides.variant_id = spree_variants.id AND variant_overrides.hub_id = #{@distributor.id}").
|
||||
joins(:stock_items).
|
||||
where(query_stock_with_overrides)
|
||||
end
|
||||
|
||||
def query_stock_with_overrides
|
||||
"( #{variant_not_overriden} AND ( #{variant_in_stock} OR #{variant_on_demand} ) )
|
||||
OR ( #{variant_overriden} AND ( #{override_on_demand} OR #{override_in_stock} ) )
|
||||
OR ( #{variant_overriden} AND ( #{override_on_demand_null} AND #{variant_on_demand} ) )
|
||||
OR ( #{variant_overriden} AND ( #{override_on_demand_null} AND #{variant_not_on_demand} AND #{variant_in_stock} ) )"
|
||||
end
|
||||
|
||||
def variant_not_overriden
|
||||
"variant_overrides.id IS NULL"
|
||||
end
|
||||
|
||||
def variant_overriden
|
||||
"variant_overrides.id IS NOT NULL"
|
||||
end
|
||||
|
||||
def variant_in_stock
|
||||
"spree_stock_items.count_on_hand > 0"
|
||||
end
|
||||
|
||||
def variant_on_demand
|
||||
"spree_stock_items.backorderable IS TRUE"
|
||||
end
|
||||
|
||||
def variant_not_on_demand
|
||||
"spree_stock_items.backorderable IS FALSE"
|
||||
end
|
||||
|
||||
def override_on_demand
|
||||
"variant_overrides.on_demand IS TRUE"
|
||||
end
|
||||
|
||||
def override_in_stock
|
||||
"variant_overrides.count_on_hand > 0"
|
||||
end
|
||||
|
||||
def override_on_demand_null
|
||||
"variant_overrides.on_demand IS NULL"
|
||||
end
|
||||
|
||||
def scoper
|
||||
ScopeProductToHub.new(@distributor)
|
||||
end
|
||||
|
||||
68
spec/services/shop_products_service_spec.rb
Normal file
68
spec/services/shop_products_service_spec.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe ShopProductsService do
|
||||
let(:distributor) { create(:distributor_enterprise) }
|
||||
let(:product) { create(:product) }
|
||||
let(:variant) { product.variants.first }
|
||||
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).relation).to eq([product])
|
||||
end
|
||||
end
|
||||
|
||||
describe "product distributed by distributor in another OC" do
|
||||
let(:reference_variant) { create(:product).variants.first }
|
||||
let(:order_cycle) do
|
||||
create(:simple_order_cycle, distributors: [distributor], variants: [reference_variant])
|
||||
end
|
||||
let(:another_order_cycle) do
|
||||
create(:simple_order_cycle, distributors: [distributor], variants: [variant])
|
||||
end
|
||||
|
||||
it "does not return product" do
|
||||
expect(described_class.new(distributor, order_cycle).relation).to_not include product
|
||||
end
|
||||
end
|
||||
|
||||
describe "product distributed by another distributor in the OC" do
|
||||
let(:another_distributor) { create(:distributor_enterprise) }
|
||||
let(:order_cycle) do
|
||||
create(:simple_order_cycle, distributors: [another_distributor], variants: [variant])
|
||||
end
|
||||
|
||||
it "does not return product" do
|
||||
expect(described_class.new(distributor, order_cycle).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).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).relation).to_not include product
|
||||
end
|
||||
end
|
||||
|
||||
context "with variant overrides" 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).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).relation).to include product
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user