mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-04 22:16:08 +00:00
Implement and use scopes for finding products by distributor via order cycle or product distribution
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
require 'open_food_web/queries_product_distribution'
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
protect_from_forgery
|
||||
|
||||
@@ -12,7 +14,7 @@ class ApplicationController < ActionController::Base
|
||||
def load_data_for_sidebar
|
||||
@suppliers = Enterprise.is_primary_producer
|
||||
@order_cycles = OrderCycle.active
|
||||
@distributors = QueriesProductDistribution.active_distributors
|
||||
@distributors = OpenFoodWeb::QueriesProductDistribution.active_distributors
|
||||
end
|
||||
|
||||
# All render calls within the block will be performed with the specified format
|
||||
|
||||
@@ -7,7 +7,12 @@ module Spree
|
||||
css_class = (current_taxon && current_taxon.self_and_ancestors.include?(taxon)) ? 'current' : nil
|
||||
|
||||
products = Product.in_taxon(taxon)
|
||||
products = products.in_distributor(current_distributor) if current_distributor
|
||||
|
||||
#products = products.in_distributor(current_distributor) if current_distributor
|
||||
#products = products.in_order_cycle(current_order_cycle) if current_order_cycle
|
||||
|
||||
products = OpenFoodWeb::QueriesProductDistribution.products_available_for(products, current_distributor, current_order_cycle)
|
||||
|
||||
num_products = products.count
|
||||
|
||||
content_tag :li, :class => css_class do
|
||||
|
||||
@@ -10,36 +10,48 @@ Spree::Product.class_eval do
|
||||
|
||||
validates_presence_of :supplier
|
||||
|
||||
|
||||
# -- Joins
|
||||
scope :with_product_distributions_outer, joins('LEFT OUTER JOIN product_distributions ON product_distributions.product_id = spree_products.id')
|
||||
|
||||
scope :with_order_cycles_outer, joins('LEFT OUTER JOIN spree_variants ON (spree_variants.product_id = spree_products.id)').
|
||||
joins('LEFT OUTER JOIN exchange_variants ON (exchange_variants.variant_id = spree_variants.id)').
|
||||
joins('LEFT OUTER JOIN exchanges ON (exchanges.id = exchange_variants.exchange_id)').
|
||||
joins('LEFT OUTER JOIN order_cycles ON (order_cycles.id = exchanges.order_cycle_id)')
|
||||
|
||||
scope :with_order_cycles_inner, joins('INNER JOIN spree_variants ON (spree_variants.product_id = spree_products.id)').
|
||||
joins('INNER JOIN exchange_variants ON (exchange_variants.variant_id = spree_variants.id)').
|
||||
joins('INNER JOIN exchanges ON (exchanges.id = exchange_variants.exchange_id)').
|
||||
joins('INNER JOIN order_cycles ON (order_cycles.id = exchanges.order_cycle_id)')
|
||||
|
||||
# -- Scopes
|
||||
scope :in_supplier, lambda { |supplier| where(:supplier_id => supplier) }
|
||||
|
||||
scope :in_distributor, lambda { |distributor| joins(:product_distributions).where('product_distributions.distributor_id = ?', (distributor.respond_to?(:id) ? distributor.id : distributor.to_i)) }
|
||||
# Find products that are distributed via the given distributor EITHER through a product distribution OR through an order cycle
|
||||
scope :in_distributor, lambda { |distributor|
|
||||
distributor = distributor.respond_to?(:id) ? distributor.id : distributor.to_i
|
||||
|
||||
scope :in_supplier_or_distributor, lambda { |enterprise| select('distinct spree_products.*').
|
||||
joins('LEFT OUTER JOIN product_distributions ON product_distributions.product_id=spree_products.id').
|
||||
where('supplier_id=? OR product_distributions.distributor_id=?',
|
||||
enterprise.respond_to?(:id) ? enterprise.id : enterprise.to_i,
|
||||
enterprise.respond_to?(:id) ? enterprise.id : enterprise.to_i) }
|
||||
|
||||
scope :in_order_cycle_distributor, lambda { |distributor|
|
||||
joins('INNER JOIN spree_variants ON (spree_variants.product_id = spree_products.id)').
|
||||
joins('INNER JOIN exchange_variants ON (exchange_variants.variant_id=spree_variants.id)').
|
||||
joins('INNER JOIN exchanges ON (exchanges.id = exchange_variants.exchange_id)').
|
||||
joins('INNER JOIN order_cycles ON (order_cycles.id = exchanges.order_cycle_id)').
|
||||
where('exchanges.sender_id = order_cycles.coordinator_id').
|
||||
where('exchanges.receiver_id = ?', (distributor.respond_to?(:id) ? distributor.id : distributor.to_i))
|
||||
with_product_distributions_outer.with_order_cycles_outer.
|
||||
where('product_distributions.distributor_id = ? OR (exchanges.sender_id = order_cycles.coordinator_id AND exchanges.receiver_id = ?)', distributor, distributor).
|
||||
select('distinct spree_products.*')
|
||||
}
|
||||
|
||||
scope :in_supplier_or_order_cycle_distributor, lambda { |enterprise|
|
||||
enterprise_id = enterprise.respond_to?(:id) ? enterprise.id : enterprise.to_i
|
||||
# Find products that are supplied by a given enterprise or distributed via that enterprise EITHER through a product distribution OR through an order cycle
|
||||
scope :in_supplier_or_distributor, lambda { |enterprise|
|
||||
enterprise = enterprise.respond_to?(:id) ? enterprise.id : enterprise.to_i
|
||||
|
||||
select('distinct spree_products.*').
|
||||
joins('LEFT OUTER JOIN spree_variants ON (spree_variants.product_id = spree_products.id)').
|
||||
joins('LEFT OUTER JOIN exchange_variants ON (exchange_variants.variant_id=spree_variants.id)').
|
||||
joins('LEFT OUTER JOIN exchanges ON (exchanges.id = exchange_variants.exchange_id)').
|
||||
joins('LEFT OUTER JOIN order_cycles ON (order_cycles.id = exchanges.order_cycle_id)').
|
||||
where('(exchanges.sender_id = order_cycles.coordinator_id AND exchanges.receiver_id = ?) OR (spree_products.supplier_id=?)', enterprise_id, enterprise_id)
|
||||
with_product_distributions_outer.with_order_cycles_outer.
|
||||
where('spree_products.supplier_id = ? OR product_distributions.distributor_id = ? OR (exchanges.sender_id = order_cycles.coordinator_id AND exchanges.receiver_id = ?)', enterprise, enterprise, enterprise).
|
||||
select('distinct spree_products.*')
|
||||
}
|
||||
|
||||
# Find products that are distributed by the given order cycle
|
||||
scope :in_order_cycle, lambda { |order_cycle| with_order_cycles_inner.
|
||||
where('exchanges.sender_id = order_cycles.coordinator_id').
|
||||
where('order_cycles.id = ?', order_cycle) }
|
||||
|
||||
|
||||
# -- Methods
|
||||
|
||||
def shipping_method_for_distributor(distributor)
|
||||
distribution = self.product_distributions.find_by_distributor_id(distributor)
|
||||
|
||||
@@ -4,6 +4,12 @@ module OpenFoodWeb
|
||||
(active_distributors_for_product_distributions + active_distributors_for_order_cycles).sort_by { |d| d.name }.uniq
|
||||
end
|
||||
|
||||
def self.products_available_for(products, distributor=nil, order_cycle=nil)
|
||||
products = products.in_distributor(distributor) if distributor
|
||||
products = products.in_order_cycle(order_cycle) if order_cycle
|
||||
products
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
@@ -12,6 +18,16 @@ module OpenFoodWeb
|
||||
end
|
||||
|
||||
def self.active_distributors_for_order_cycles
|
||||
# Can I create this with merge scopes?
|
||||
# ie. Enterprise.is_distributor.join(:order_cycle_distributor).merge(OrderCycle.active)
|
||||
|
||||
# Try this:
|
||||
Enterprise.joins('LEFT INNER JOIN exchanges ON (exchanges.receiver_id = enterprises.id)').joins('LEFT INNER JOIN order_cycles ON (order_cycles.id = exchanges.order_cycle.id)').
|
||||
merge(OrderCycle.active).select('DISTINCT enterprises.*')
|
||||
|
||||
# Then I can make each of these methods into a scope on Enterprise, and ultimately a single scope
|
||||
# Then we don't need this class.
|
||||
|
||||
OrderCycle.active.map { |oc| oc.distributors }.flatten.uniq
|
||||
end
|
||||
|
||||
|
||||
@@ -8,7 +8,15 @@ feature %q{
|
||||
include AuthenticationWorkflow
|
||||
include WebHelper
|
||||
|
||||
scenario "viewing product counts when no distributor selected" do
|
||||
# How should this work with distributors/order cycles?
|
||||
# - No distributor or OC selected - all shown
|
||||
# - Distributor selected - any from that distributor in any OC
|
||||
# - OC selected - any in that OC from any distributor
|
||||
# - Both selected - filter for both
|
||||
|
||||
# Also keep specs for distributors outside order cycles.
|
||||
|
||||
scenario "viewing product counts when no distributor or order cycle is selected" do
|
||||
# Given some taxons and some products
|
||||
taxonomy = Spree::Taxonomy.find_by_name('Products') || create(:taxonomy, :name => 'Products')
|
||||
taxonomy_root = taxonomy.root
|
||||
@@ -48,15 +56,56 @@ feature %q{
|
||||
2.times { create(:product, :taxons => [taxon_three], :distributors => [other_distributor]) }
|
||||
2.times { create(:product, :taxons => [taxon_three], :distributors => [my_distributor]) }
|
||||
|
||||
p = create(:product, :taxons => [taxon_one])
|
||||
oc = create(:simple_order_cycle, distributors: [my_distributor], variants: [p.master])
|
||||
|
||||
# When I visit the home page and select my distributor
|
||||
visit spree.select_distributor_order_path(my_distributor)
|
||||
within('nav#filters') { click_link my_distributor.name }
|
||||
page.should have_content 'You are shopping at My Distributor'
|
||||
|
||||
# Then I should see distributor-scoped product counts next to the taxons
|
||||
page.should have_selector 'nav#taxonomies li', :text => 'Taxon one (1)'
|
||||
page.should have_selector 'nav#taxonomies li', :text => 'Taxon two (0)'
|
||||
page.should have_selector 'nav#taxonomies li', :text => 'Taxon three (2)'
|
||||
end
|
||||
|
||||
scenario "viewing product counts when an order cycle is selected" do
|
||||
# Given some taxons and some products and some order cycles
|
||||
taxonomy = Spree::Taxonomy.find_by_name('Products') || create(:taxonomy, :name => 'Products')
|
||||
taxonomy_root = taxonomy.root
|
||||
|
||||
taxon_one = create(:taxon, :name => 'Taxon one', :parent_id => taxonomy_root.id)
|
||||
taxon_two = create(:taxon, :name => 'Taxon two', :parent_id => taxonomy_root.id)
|
||||
taxon_three = create(:taxon, :name => 'Taxon three', :parent_id => taxonomy_root.id)
|
||||
|
||||
supplier = create(:supplier_enterprise, :name => 'My Supplier')
|
||||
distributor = create(:distributor_enterprise, :name => 'My Distributor')
|
||||
|
||||
t1p1 = create(:product, :taxons => [taxon_one])
|
||||
t2p1 = create(:product, :taxons => [taxon_two])
|
||||
t2p2 = create(:product, :taxons => [taxon_two])
|
||||
t3p1 = create(:product, :taxons => [taxon_three])
|
||||
t3p2 = create(:product, :taxons => [taxon_three])
|
||||
|
||||
oc1 = create(:simple_order_cycle, suppliers: [supplier], distributors: [distributor], variants: [t1p1.master, t2p1.master, t2p2.master])
|
||||
oc2 = create(:simple_order_cycle, suppliers: [supplier], distributors: [distributor], variants: [t3p1.master, t3p2.master])
|
||||
|
||||
# When I visit the home page and select my order cycle
|
||||
visit root_path
|
||||
choose oc2.name
|
||||
click_button 'Choose Order Cycle'
|
||||
page.should have_content 'Your order cycle has been selected.'
|
||||
|
||||
pending "TODO: Test that products by ProductDistribution are not shown"
|
||||
|
||||
# Then I should see order cycle-scoped product counts next to the taxons
|
||||
page.should have_selector 'nav#taxonomies li', :text => 'Taxon one (0)'
|
||||
page.should have_selector 'nav#taxonomies li', :text => 'Taxon two (0)'
|
||||
page.should have_selector 'nav#taxonomies li', :text => 'Taxon three (2)'
|
||||
end
|
||||
|
||||
scenario "viewing product counts when both a distributor and an order cycle are selected"
|
||||
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user