mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-01 02:03:22 +00:00
Re-apply shop property filters - including performance regression
This reverts commit 7d149ed198.
This commit is contained in:
@@ -1,13 +1,17 @@
|
||||
Darkswarm.filter 'properties', ->
|
||||
# Filter anything that responds to object.supplied_properties
|
||||
(objects, ids) ->
|
||||
(objects, ids, source) ->
|
||||
objects ||= []
|
||||
ids ?= []
|
||||
|
||||
source ||= 'properties'
|
||||
return [] unless source in ['properties', 'supplied_properties', 'distributed_properties']
|
||||
|
||||
if ids.length == 0
|
||||
# No properties selected, pass all objects through.
|
||||
objects
|
||||
else
|
||||
objects.filter (obj) ->
|
||||
properties = obj.supplied_properties || obj.properties
|
||||
properties = obj[source]
|
||||
properties.some (property) ->
|
||||
property.id in ids
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Darkswarm.filter 'propertiesOf', ->
|
||||
(objects) ->
|
||||
(objects, source) ->
|
||||
source ||= 'properties'
|
||||
return {} unless source in ['properties', 'supplied_properties', 'distributed_properties']
|
||||
|
||||
properties = {}
|
||||
for object in objects
|
||||
if object.supplied_properties?
|
||||
for property in object.supplied_properties
|
||||
properties[property.id] = property
|
||||
else
|
||||
for property in object.properties
|
||||
if object[source]?
|
||||
for property in object[source]
|
||||
properties[property.id] = property
|
||||
|
||||
properties
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
// content. Ensure that the dropdown appears above the content.
|
||||
.filter-row
|
||||
position: relative
|
||||
z-index: 100
|
||||
z-index: 90
|
||||
|
||||
.filter-shopfront
|
||||
&.taxon-selectors, &.property-selectors
|
||||
|
||||
@@ -45,7 +45,7 @@ module InjectionHelper
|
||||
end
|
||||
|
||||
def inject_properties
|
||||
inject_json_ams "properties", Spree::Property.all, Api::IdNameSerializer
|
||||
inject_json_ams "properties", Spree::Property.all, Api::PropertySerializer
|
||||
end
|
||||
|
||||
def inject_currency_config
|
||||
|
||||
6
app/helpers/serializer_helper.rb
Normal file
6
app/helpers/serializer_helper.rb
Normal file
@@ -0,0 +1,6 @@
|
||||
module SerializerHelper
|
||||
def ids_to_objs(ids)
|
||||
return [] if ids.blank?
|
||||
ids.map { |id| {id: id} }
|
||||
end
|
||||
end
|
||||
@@ -8,14 +8,18 @@ class ProducerProperty < ActiveRecord::Base
|
||||
after_destroy :refresh_products_cache_from_destroy
|
||||
|
||||
|
||||
scope :sold_by, ->(shop) {
|
||||
scope :ever_sold_by, ->(shop) {
|
||||
joins(producer: {supplied_products: {variants: {exchanges: :order_cycle}}}).
|
||||
merge(Exchange.outgoing).
|
||||
merge(Exchange.to_enterprise(shop)).
|
||||
merge(OrderCycle.active).
|
||||
select('DISTINCT producer_properties.*')
|
||||
}
|
||||
|
||||
scope :currently_sold_by, ->(shop) {
|
||||
ever_sold_by(shop).
|
||||
merge(OrderCycle.active)
|
||||
}
|
||||
|
||||
|
||||
def property_name
|
||||
property.name if property
|
||||
|
||||
@@ -8,14 +8,18 @@ module Spree
|
||||
where('spree_product_properties.product_id IN (?)', enterprise.supplied_product_ids)
|
||||
}
|
||||
|
||||
scope :sold_by, ->(shop) {
|
||||
scope :ever_sold_by, ->(shop) {
|
||||
joins(products: {variants: {exchanges: :order_cycle}}).
|
||||
merge(Exchange.outgoing).
|
||||
merge(Exchange.to_enterprise(shop)).
|
||||
merge(OrderCycle.active).
|
||||
select('DISTINCT spree_properties.*')
|
||||
}
|
||||
|
||||
scope :currently_sold_by, ->(shop) {
|
||||
ever_sold_by(shop).
|
||||
merge(OrderCycle.active)
|
||||
}
|
||||
|
||||
|
||||
after_save :refresh_products_cache
|
||||
|
||||
|
||||
@@ -32,21 +32,24 @@ Spree::Taxon.class_eval do
|
||||
end
|
||||
|
||||
# Find all the taxons of distributed products for each enterprise, indexed by enterprise.
|
||||
# May return :all taxons (distributed in open and closed order cycles),
|
||||
# or :current taxons (distributed in an open order cycle).
|
||||
#
|
||||
# Format: {enterprise_id => [taxon_id, ...]}
|
||||
def self.distributed_taxons
|
||||
taxons = {}
|
||||
def self.distributed_taxons(which_taxons=:all)
|
||||
# TODO: Why can't we merge(Spree::Product.with_order_cycles_inner) here?
|
||||
taxons = Spree::Taxon.
|
||||
joins(products: {variants_including_master: {exchanges: :order_cycle}}).
|
||||
merge(Exchange.outgoing).
|
||||
select('spree_taxons.*, exchanges.receiver_id AS enterprise_id')
|
||||
|
||||
Spree::Taxon.
|
||||
joins(:products).
|
||||
merge(Spree::Product.with_order_cycles_outer).
|
||||
where('o_exchanges.incoming = ?', false).
|
||||
select('spree_taxons.*, o_exchanges.receiver_id AS enterprise_id').
|
||||
each do |t|
|
||||
taxons[t.enterprise_id.to_i] ||= Set.new
|
||||
taxons[t.enterprise_id.to_i] << t.id
|
||||
end
|
||||
taxons = taxons.merge(OrderCycle.active) if which_taxons == :current
|
||||
|
||||
taxons
|
||||
taxons.inject({}) do |ts, t|
|
||||
ts[t.enterprise_id.to_i] ||= Set.new
|
||||
ts[t.enterprise_id.to_i] << t.id
|
||||
ts
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,10 @@ class Api::EnterpriseSerializer < ActiveModel::Serializer
|
||||
end
|
||||
|
||||
class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
include SerializerHelper
|
||||
|
||||
attributes :orders_close_at, :active
|
||||
attributes :taxons, :supplied_taxons
|
||||
has_many :supplied_properties, serializer: Api::PropertySerializer
|
||||
has_many :distributed_properties, serializer: Api::PropertySerializer
|
||||
|
||||
@@ -42,15 +45,37 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
|
||||
def distributed_properties
|
||||
# This results in 3 queries per enterprise
|
||||
product_properties = Spree::Property.sold_by(object)
|
||||
ids = ProducerProperty.sold_by(object).pluck(:property_id)
|
||||
producer_properties = Spree::Property.where(id: ids)
|
||||
|
||||
if active
|
||||
product_properties = Spree::Property.currently_sold_by(object)
|
||||
producer_property_ids = ProducerProperty.currently_sold_by(object).pluck(:property_id)
|
||||
|
||||
else
|
||||
product_properties = Spree::Property.ever_sold_by(object)
|
||||
producer_property_ids = ProducerProperty.ever_sold_by(object).pluck(:property_id)
|
||||
end
|
||||
|
||||
producer_properties = Spree::Property.where(id: producer_property_ids)
|
||||
|
||||
OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties
|
||||
end
|
||||
|
||||
def taxons
|
||||
if active
|
||||
ids_to_objs options[:data].current_distributed_taxons[object.id]
|
||||
else
|
||||
ids_to_objs options[:data].all_distributed_taxons[object.id]
|
||||
end
|
||||
end
|
||||
|
||||
def supplied_taxons
|
||||
ids_to_objs options[:data].supplied_taxons[object.id]
|
||||
end
|
||||
end
|
||||
|
||||
class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
include SerializerHelper
|
||||
|
||||
cached
|
||||
#delegate :cache_key, to: :object
|
||||
|
||||
@@ -65,16 +90,7 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
:email_address, :hash, :logo, :promo_image, :path, :pickup, :delivery,
|
||||
:icon, :icon_font, :producer_icon_font, :category, :producers, :hubs
|
||||
|
||||
attributes :taxons, :supplied_taxons
|
||||
|
||||
has_one :address, serializer: Api::AddressSerializer
|
||||
def taxons
|
||||
ids_to_objs options[:data].distributed_taxons[object.id]
|
||||
end
|
||||
|
||||
def supplied_taxons
|
||||
ids_to_objs options[:data].supplied_taxons[object.id]
|
||||
end
|
||||
|
||||
def pickup
|
||||
services = options[:data].shipping_method_services[object.id]
|
||||
@@ -153,12 +169,4 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
}
|
||||
icon_fonts[object.category]
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def ids_to_objs(ids)
|
||||
return [] if ids.blank?
|
||||
ids.map { |id| {id: id} }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
class Api::PropertySerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :presentation
|
||||
|
||||
# Client-side we don't care about the property name. Send the presentation
|
||||
# since this is what we want to show to the user.
|
||||
def name
|
||||
object.presentation
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
.row
|
||||
= render partial: 'shared/components/filter_controls'
|
||||
= render partial: 'shared/components/show_profiles'
|
||||
|
||||
.row.animate-show{"ng-show" => "filtersActive"}
|
||||
.small-12.columns
|
||||
.row.filter-box
|
||||
.small-12.large-9.columns
|
||||
%h5.tdhead
|
||||
.light
|
||||
= t :hubs_filter_by
|
||||
= t :hubs_filter_type
|
||||
%filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{"selector-set" => "filterSelectors", objects: "group_hubs | searchEnterprises:query | shipping:shippingTypes | showHubProfiles:show_profiles | taxonsOf", "active-selectors" => "activeTaxons"}
|
||||
.small-12.large-3.columns
|
||||
%h5.tdhead
|
||||
.light
|
||||
= t :hubs_filter_by
|
||||
= t :hubs_filter_delivery
|
||||
%shipping-type-selector
|
||||
|
||||
= render partial: 'shared/components/filter_box'
|
||||
@@ -60,23 +60,23 @@
|
||||
.small-12.columns
|
||||
%h1
|
||||
= t :groups_producers
|
||||
= render partial: "shared/components/enterprise_search"
|
||||
= render partial: "producers/filters"
|
||||
= render "shared/components/enterprise_search"
|
||||
= render "producers/filters"
|
||||
|
||||
.row
|
||||
.small-12.columns
|
||||
.active_table
|
||||
%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}",
|
||||
"ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)",
|
||||
"ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties:'supplied_properties')",
|
||||
"ng-controller" => "GroupEnterpriseNodeCtrl",
|
||||
"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}",
|
||||
id: "{{producer.hash}}"}
|
||||
|
||||
.small-12.columns
|
||||
= render partial: 'producers/skinny'
|
||||
= render partial: 'producers/fat'
|
||||
= render "producers/skinny"
|
||||
= render "producers/fat"
|
||||
|
||||
= render partial: 'shared/components/enterprise_no_results'
|
||||
= render 'shared/components/enterprise_no_results'
|
||||
|
||||
%tab{heading: t(:groups_hubs),
|
||||
active: "tabs.hubs.active",
|
||||
@@ -87,24 +87,24 @@
|
||||
%h1
|
||||
= t :groups_hubs
|
||||
|
||||
= render partial: "shared/components/enterprise_search"
|
||||
= render partial: "hub_filters"
|
||||
= render "shared/components/enterprise_search"
|
||||
= render "shops/filters", resource: "group_hubs", property_filters: "| searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles"
|
||||
|
||||
.row
|
||||
.small-12.columns
|
||||
.active_table
|
||||
%hub.active_table_node.row.animate-repeat{id: "{{hub.hash}}",
|
||||
"ng-repeat" => "hub in filteredEnterprises = (group_hubs | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+orders_close_at'])",
|
||||
"ng-repeat" => "hub in filteredEnterprises = (group_hubs | searchEnterprises:query | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | properties:activeProperties:'distributed_properties' | orderBy:['-active', '+orders_close_at'])",
|
||||
"ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}",
|
||||
"ng-controller" => "GroupEnterpriseNodeCtrl"}
|
||||
.small-12.columns
|
||||
= render partial: 'home/skinny'
|
||||
= render partial: 'home/fat'
|
||||
= render 'shops/skinny'
|
||||
= render 'shops/fat'
|
||||
|
||||
= render partial: 'shared/components/enterprise_no_results'
|
||||
= render 'shared/components/enterprise_no_results'
|
||||
|
||||
.small-12.medium-12.large-3.columns
|
||||
= render partial: 'contact'
|
||||
= render 'contact'
|
||||
|
||||
.small-12.columns.pad-top
|
||||
.row.pad-top
|
||||
@@ -122,4 +122,4 @@
|
||||
%p
|
||||
|
||||
|
||||
= render partial: "shared/footer"
|
||||
= render "shared/footer"
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
.row
|
||||
= render partial: 'shared/components/filter_controls'
|
||||
-# .small-12.medium-6.columns
|
||||
= render partial: 'shared/components/show_profiles'
|
||||
|
||||
.row.animate-show{"ng-show" => "filtersActive"}
|
||||
.small-12.columns
|
||||
.row.filter-box
|
||||
.small-12.large-9.columns
|
||||
%h5.tdhead
|
||||
.light
|
||||
= t :hubs_filter_by
|
||||
= t :hubs_filter_type
|
||||
%filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ "selector-set" => "filterSelectors", objects: "visibleMatches | visible | taxonsOf", "active-selectors" => "activeTaxons" }
|
||||
.small-12.large-3.columns
|
||||
%h5.tdhead
|
||||
.light
|
||||
= t :hubs_filter_by
|
||||
= t :hubs_filter_delivery
|
||||
%shipping-type-selector
|
||||
|
||||
= render partial: 'shared/components/filter_box'
|
||||
@@ -18,6 +18,6 @@
|
||||
= t :producers_filter
|
||||
= t :producers_filter_property
|
||||
.filter-shopfront.property-selectors
|
||||
%single-line-selectors{ selectors: "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | propertiesOf", "active-selectors" => "activeProperties"}
|
||||
%filter-selector{ "selector-set" => "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | taxons:activeTaxons | propertiesOf:'supplied_properties'", "active-selectors" => "activeProperties"}
|
||||
|
||||
= render partial: 'shared/components/filter_box'
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.small-12.columns
|
||||
.active_table
|
||||
%producer.active_table_node.row.animate-repeat{id: "{{producer.path}}",
|
||||
"ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)",
|
||||
"ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties:'supplied_properties')",
|
||||
"ng-controller" => "ProducerNodeCtrl",
|
||||
"ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}",
|
||||
id: "{{producer.hash}}"}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.filter-shopfront.taxon-selectors.text-right
|
||||
%single-line-selectors{ selectors: "taxonSelectors", objects: "Products.products | products:query | properties: activeProperties | taxonsOf", "active-selectors" => "activeTaxons"}
|
||||
%single-line-selectors{ selectors: "taxonSelectors", objects: "Products.products | products:query | properties:activeProperties | taxonsOf", "active-selectors" => "activeTaxons"}
|
||||
|
||||
.filter-shopfront.property-selectors.text-right
|
||||
%single-line-selectors{ selectors: "propertySelectors", objects: "Products.products | products:query | taxons:activeTaxons | propertiesOf", "active-selectors" => "activeProperties"}
|
||||
|
||||
34
app/views/shops/_filters.html.haml
Normal file
34
app/views/shops/_filters.html.haml
Normal file
@@ -0,0 +1,34 @@
|
||||
- resource ||= "visibleMatches"
|
||||
- property_filters ||= "| filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles"
|
||||
|
||||
.row
|
||||
= render 'shared/components/filter_controls'
|
||||
-# .small-12.medium-6.columns
|
||||
= render 'shared/components/show_profiles'
|
||||
|
||||
.row.animate-show.filter-row{"ng-show" => "filtersActive"}
|
||||
.small-12.columns
|
||||
.row.filter-box
|
||||
.small-12.large-9.columns
|
||||
%h5.tdhead
|
||||
.light
|
||||
= t :hubs_filter_by
|
||||
= t :hubs_filter_type
|
||||
|
||||
%filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ "selector-set" => "filterSelectors", objects: "#{resource} | visible | taxonsOf", "active-selectors" => "activeTaxons" }
|
||||
.small-12.large-3.columns
|
||||
%h5.tdhead
|
||||
.light
|
||||
= t :hubs_filter_by
|
||||
= t :hubs_filter_delivery
|
||||
%shipping-type-selector
|
||||
|
||||
.small-12.large-12.columns
|
||||
%h5.tdhead
|
||||
.light
|
||||
= t :hubs_filter_by
|
||||
= t :hubs_filter_property
|
||||
.filter-shopfront.property-selectors
|
||||
%filter-selector{ "selector-set" => "filterSelectors", objects: "#{resource} #{property_filters} | propertiesOf:'distributed_properties'", "active-selectors" => "activeProperties"}
|
||||
|
||||
= render 'shared/components/filter_box'
|
||||
@@ -7,14 +7,14 @@
|
||||
= t :hubs_intro
|
||||
|
||||
= render "shared/components/enterprise_search"
|
||||
= render "home/filters"
|
||||
= render "filters"
|
||||
|
||||
.row
|
||||
.small-12.columns
|
||||
.name-matches{"ng-show" => "nameMatchesFiltered.length > 0"}
|
||||
%h2
|
||||
= t :hubs_matches
|
||||
= render "home/hubs_table", enterprises: "nameMatches"
|
||||
= render "hubs_table", enterprises: "nameMatches"
|
||||
|
||||
.distance-matches{"ng-if" => "nameMatchesFiltered.length == 0 || distanceMatchesShown"}
|
||||
%h2{"ng-show" => "nameMatchesFiltered.length > 0 || query.length > 0"}
|
||||
@@ -22,7 +22,7 @@
|
||||
%span{"ng-show" => "nameMatchesFiltered.length > 0"} {{ nameMatchesFiltered[0].name }}...
|
||||
%span{"ng-hide" => "nameMatchesFiltered.length > 0"} {{ query }}...
|
||||
|
||||
= render "home/hubs_table", enterprises: "distanceMatches"
|
||||
= render "hubs_table", enterprises: "distanceMatches"
|
||||
|
||||
.show-distance-matches{"ng-show" => "nameMatchesFiltered.length > 0 && !distanceMatchesShown"}
|
||||
%a{href: "", "ng-click" => "showDistanceMatches()"}
|
||||
@@ -1,10 +1,10 @@
|
||||
.active_table
|
||||
%hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])",
|
||||
%hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | filter:filterExpression | taxons:activeTaxons | properties:activeProperties:'distributed_properties' | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])",
|
||||
"ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}",
|
||||
"ng-controller" => "HubNodeCtrl",
|
||||
id: "{{hub.hash}}"}
|
||||
.small-12.columns
|
||||
= render 'home/skinny'
|
||||
= render 'home/fat'
|
||||
= render 'skinny'
|
||||
= render 'fat'
|
||||
|
||||
= render 'shared/components/enterprise_no_results', enterprises: "#{enterprises}Filtered"
|
||||
@@ -10,5 +10,5 @@
|
||||
%p.text-big
|
||||
= t :shops_text
|
||||
|
||||
= render partial: "home/hubs"
|
||||
= render partial: "shared/footer"
|
||||
= render "hubs"
|
||||
= render "shared/footer"
|
||||
|
||||
@@ -513,6 +513,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
hubs_filter_by: "Filter by"
|
||||
hubs_filter_type: "Type"
|
||||
hubs_filter_delivery: "Delivery"
|
||||
hubs_filter_property: "Property"
|
||||
hubs_matches: "Did you mean?"
|
||||
hubs_intro: Shop in your local area
|
||||
hubs_distance: Closest to
|
||||
|
||||
@@ -20,8 +20,12 @@ module OpenFoodNetwork
|
||||
@supplied_taxons ||= Spree::Taxon.supplied_taxons
|
||||
end
|
||||
|
||||
def distributed_taxons
|
||||
@distributed_taxons ||= Spree::Taxon.distributed_taxons
|
||||
def all_distributed_taxons
|
||||
@all_distributed_taxons ||= Spree::Taxon.distributed_taxons(:all)
|
||||
end
|
||||
|
||||
def current_distributed_taxons
|
||||
@current_distributed_taxons ||= Spree::Taxon.distributed_taxons(:current)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -54,4 +54,43 @@ feature 'Groups', js: true do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "shops" do
|
||||
describe "filtering by product property" do
|
||||
let!(:group) { create(:enterprise_group, enterprises: [d1, d2], on_front_page: true) }
|
||||
let!(:order_cycle) { create(:simple_order_cycle, distributors: [d1, d2], coordinator: create(:distributor_enterprise)) }
|
||||
let(:producer) { create(:supplier_enterprise) }
|
||||
let(:d1) { create(:distributor_enterprise) }
|
||||
let(:d2) { create(:distributor_enterprise) }
|
||||
let(:p1) { create(:simple_product, supplier: producer) }
|
||||
let(:p2) { create(:simple_product, supplier: create(:supplier_enterprise)) }
|
||||
let(:ex_d1) { order_cycle.exchanges.outgoing.where(receiver_id: d1).first }
|
||||
let(:ex_d2) { order_cycle.exchanges.outgoing.where(receiver_id: d2).first }
|
||||
|
||||
before do
|
||||
producer.set_producer_property 'Organic', 'NASAA 12345'
|
||||
p2.set_property 'Local', 'XYZ 123'
|
||||
|
||||
ex_d1.variants << p1.variants.first
|
||||
ex_d2.variants << p2.variants.first
|
||||
|
||||
visit group_path(group, anchor: "/hubs")
|
||||
end
|
||||
|
||||
it "filters" do
|
||||
toggle_filters
|
||||
|
||||
toggle_filter 'Organic'
|
||||
|
||||
expect(page).to have_content d1.name
|
||||
expect(page).not_to have_content d2.name
|
||||
|
||||
toggle_filter 'Organic'
|
||||
toggle_filter 'Local'
|
||||
|
||||
expect(page).not_to have_content d1.name
|
||||
expect(page).to have_content d2.name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -47,7 +47,7 @@ feature 'Shops', js: true do
|
||||
it "should show closed shops after clicking the button" do
|
||||
create(:simple_product, distributors: [d1, d2])
|
||||
visit shops_path
|
||||
click_link_and_ensure("Show closed shops", -> { page.has_selector? 'hub.inactive' })
|
||||
click_link_and_ensure("Show Closed Shops", -> { page.has_selector? 'hub.inactive' })
|
||||
page.should have_selector 'hub.inactive', text: d2.name
|
||||
end
|
||||
|
||||
@@ -56,6 +56,67 @@ feature 'Shops', js: true do
|
||||
expect(page).to have_current_path enterprise_shop_path(distributor)
|
||||
end
|
||||
|
||||
describe "filtering by product property" do
|
||||
let!(:order_cycle) { create(:simple_order_cycle, distributors: [d1, d2], coordinator: create(:distributor_enterprise)) }
|
||||
let!(:p1) { create(:simple_product, supplier: producer) }
|
||||
let!(:p2) { create(:simple_product, supplier: create(:supplier_enterprise)) }
|
||||
let(:ex_d1) { order_cycle.exchanges.outgoing.where(receiver_id: d1).first }
|
||||
let(:ex_d2) { order_cycle.exchanges.outgoing.where(receiver_id: d2).first }
|
||||
|
||||
before do
|
||||
p2.set_property 'Local', 'XYZ 123'
|
||||
|
||||
ex_d1.variants << p1.variants.first
|
||||
ex_d2.variants << p2.variants.first
|
||||
|
||||
visit shops_path
|
||||
end
|
||||
|
||||
it "filters" do
|
||||
toggle_filters
|
||||
|
||||
toggle_filter 'Organic'
|
||||
|
||||
expect(page).to have_content d1.name
|
||||
expect(page).not_to have_content d2.name
|
||||
|
||||
toggle_filter 'Organic'
|
||||
toggle_filter 'Local'
|
||||
|
||||
expect(page).not_to have_content d1.name
|
||||
expect(page).to have_content d2.name
|
||||
end
|
||||
end
|
||||
|
||||
describe "taxon badges" do
|
||||
let!(:closed_oc) { create(:closed_order_cycle, distributors: [shop], variants: [p_closed.variants.first]) }
|
||||
let!(:p_closed) { create(:simple_product, taxons: [taxon_closed]) }
|
||||
let(:shop) { create(:distributor_enterprise) }
|
||||
let(:taxon_closed) { create(:taxon, name: 'Closed') }
|
||||
|
||||
describe "open shops" do
|
||||
let!(:open_oc) { create(:open_order_cycle, distributors: [shop], variants: [p_open.variants.first]) }
|
||||
let!(:p_open) { create(:simple_product, taxons: [taxon_open]) }
|
||||
let(:taxon_open) { create(:taxon, name: 'Open') }
|
||||
|
||||
it "shows taxons for open order cycles only" do
|
||||
visit shops_path
|
||||
expand_active_table_node shop.name
|
||||
expect(page).to have_selector '.fat-taxons', text: 'Open'
|
||||
expect(page).not_to have_selector '.fat-taxons', text: 'Closed'
|
||||
end
|
||||
end
|
||||
|
||||
describe "closed shops" do
|
||||
it "shows taxons for any order cycle" do
|
||||
visit shops_path
|
||||
click_link 'Show Closed Shops'
|
||||
expand_active_table_node shop.name
|
||||
expect(page).to have_selector '.fat-taxons', text: 'Closed'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "property badges" do
|
||||
let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) }
|
||||
let(:product) { create(:simple_product, supplier: producer) }
|
||||
|
||||
@@ -8,7 +8,7 @@ describe ProducerProperty do
|
||||
producer.set_producer_property 'Organic Certified', 'NASAA 54321'
|
||||
end
|
||||
|
||||
describe ".sold_by" do
|
||||
describe ".currently_sold_by and .ever_sold_by" do
|
||||
let!(:shop) { create(:distributor_enterprise) }
|
||||
let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) }
|
||||
let(:product) { create(:simple_product, supplier: producer) }
|
||||
@@ -22,7 +22,8 @@ describe ProducerProperty do
|
||||
|
||||
describe "with an associated producer property" do
|
||||
it "returns the producer property" do
|
||||
expect(ProducerProperty.sold_by(shop)).to eq [pp]
|
||||
expect(ProducerProperty.currently_sold_by(shop)).to eq [pp]
|
||||
expect(ProducerProperty.ever_sold_by(shop)).to eq [pp]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,7 +31,8 @@ describe ProducerProperty do
|
||||
let!(:exchange) { create(:exchange, order_cycle: oc, incoming: true, sender: producer_other, receiver: oc.coordinator) }
|
||||
|
||||
it "doesn't return the producer property" do
|
||||
expect(ProducerProperty.sold_by(shop)).not_to include pp_other
|
||||
expect(ProducerProperty.currently_sold_by(shop)).not_to include pp_other
|
||||
expect(ProducerProperty.ever_sold_by(shop)).not_to include pp_other
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,7 +42,8 @@ describe ProducerProperty do
|
||||
let!(:exchange) { create(:exchange, order_cycle: oc, incoming: false, sender: oc.coordinator, receiver: shop_other, variants: [product_other.variants.first]) }
|
||||
|
||||
it "doesn't return the producer property" do
|
||||
expect(ProducerProperty.sold_by(shop)).not_to include pp_other
|
||||
expect(ProducerProperty.currently_sold_by(shop)).not_to include pp_other
|
||||
expect(ProducerProperty.ever_sold_by(shop)).not_to include pp_other
|
||||
end
|
||||
end
|
||||
|
||||
@@ -49,8 +52,12 @@ describe ProducerProperty do
|
||||
oc.update_attributes! orders_close_at: 1.week.ago
|
||||
end
|
||||
|
||||
it "doesn't return the producer property" do
|
||||
expect(ProducerProperty.sold_by(shop)).not_to include pp
|
||||
it "doesn't return the producer property for .currently_sold_by" do
|
||||
expect(ProducerProperty.currently_sold_by(shop)).not_to include pp
|
||||
end
|
||||
|
||||
it "returns the producer property for .ever_sold_by" do
|
||||
expect(ProducerProperty.ever_sold_by(shop)).to include pp
|
||||
end
|
||||
end
|
||||
|
||||
@@ -59,7 +66,8 @@ describe ProducerProperty do
|
||||
let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first, product2.variants.first]) }
|
||||
|
||||
it "doesn't return duplicates" do
|
||||
expect(ProducerProperty.sold_by(shop).to_a.count).to eq 1
|
||||
expect(ProducerProperty.currently_sold_by(shop).to_a.count).to eq 1
|
||||
expect(ProducerProperty.ever_sold_by(shop).to_a.count).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -31,42 +31,53 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
describe ".sold_by" do
|
||||
describe ".currently_sold_by and .ever_sold_by" do
|
||||
let!(:shop) { create(:distributor_enterprise) }
|
||||
let!(:shop_other) { create(:distributor_enterprise) }
|
||||
let!(:product) { create(:simple_product) }
|
||||
let!(:product_other_ex) { create(:simple_product) }
|
||||
let!(:product_no_oc) { create(:simple_product) }
|
||||
let!(:product_closed_oc) { create(:simple_product) }
|
||||
let!(:oc) { create(:simple_order_cycle, distributors: [shop], variants: [product.variants.first]) }
|
||||
let!(:oc_closed) { create(:closed_order_cycle, distributors: [shop], variants: [product_closed_oc.variants.first]) }
|
||||
let!(:exchange_other_shop) { create(:exchange, order_cycle: oc, sender: oc.coordinator, receiver: shop_other, variants: [product_other_ex.variants.first]) }
|
||||
let(:property) { product.properties.last }
|
||||
let(:property_other_ex) { product_other_ex.properties.last }
|
||||
let(:property_no_oc) { product_no_oc.properties.last }
|
||||
let(:property_closed_oc) { product_closed_oc.properties.last }
|
||||
|
||||
before do
|
||||
product.set_property 'Organic', 'NASAA 12345'
|
||||
product_other_ex.set_property 'Biodynamic', 'ASDF 12345'
|
||||
product_no_oc.set_property 'Shiny', 'Very'
|
||||
product_closed_oc.set_property 'Spiffy', 'Ooh yeah'
|
||||
end
|
||||
|
||||
it "returns the property" do
|
||||
expect(Property.sold_by(shop)).to eq [property]
|
||||
expect(Property.currently_sold_by(shop)).to eq [property]
|
||||
expect(Property.ever_sold_by(shop)).to eq [property]
|
||||
end
|
||||
|
||||
it "doesn't return the property from another exchange" do
|
||||
expect(Property.sold_by(shop)).not_to include property_other_ex
|
||||
expect(Property.currently_sold_by(shop)).not_to include property_other_ex
|
||||
expect(Property.ever_sold_by(shop)).not_to include property_other_ex
|
||||
end
|
||||
|
||||
it "doesn't return the property with no order cycle" do
|
||||
expect(Property.sold_by(shop)).not_to include property_no_oc
|
||||
expect(Property.currently_sold_by(shop)).not_to include property_no_oc
|
||||
expect(Property.ever_sold_by(shop)).not_to include property_no_oc
|
||||
end
|
||||
|
||||
it "doesn't return the property from a closed order cycle" do
|
||||
expect(Property.sold_by(shop)).not_to include property_closed_oc
|
||||
describe "closed order cyces" do
|
||||
let!(:product_closed_oc) { create(:simple_product) }
|
||||
let!(:oc_closed) { create(:closed_order_cycle, distributors: [shop], variants: [product_closed_oc.variants.first]) }
|
||||
let(:property_closed_oc) { product_closed_oc.properties.last }
|
||||
|
||||
before { product_closed_oc.set_property 'Spiffy', 'Ooh yeah' }
|
||||
|
||||
it "doesn't return the property for .currently_sold_by" do
|
||||
expect(Property.currently_sold_by(shop)).not_to include property_closed_oc
|
||||
end
|
||||
|
||||
it "returns the property for .ever_sold_by" do
|
||||
expect(Property.ever_sold_by(shop)).to include property_closed_oc
|
||||
end
|
||||
end
|
||||
|
||||
context "with another product in the order cycle" do
|
||||
@@ -78,7 +89,8 @@ module Spree
|
||||
end
|
||||
|
||||
it "doesn't return duplicates" do
|
||||
expect(Property.sold_by(shop).to_a.count).to eq 1
|
||||
expect(Property.currently_sold_by(shop).to_a.count).to eq 1
|
||||
expect(Property.ever_sold_by(shop).to_a.count).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -29,13 +29,18 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
describe "finding all distributed taxons" do
|
||||
let!(:oc) { create(:simple_order_cycle, distributors: [e], variants: [p1.master]) }
|
||||
let!(:s) { create(:supplier_enterprise) }
|
||||
let!(:p1) { create(:simple_product, supplier: s, taxons: [t1, t2]) }
|
||||
describe "finding distributed taxons" do
|
||||
let!(:oc_open) { create(:open_order_cycle, distributors: [e], variants: [p_open.variants.first]) }
|
||||
let!(:oc_closed) { create(:closed_order_cycle, distributors: [e], variants: [p_closed.variants.first]) }
|
||||
let!(:p_open) { create(:simple_product, primary_taxon: t1) }
|
||||
let!(:p_closed) { create(:simple_product, primary_taxon: t2) }
|
||||
|
||||
it "finds taxons" do
|
||||
Taxon.distributed_taxons.should == {e.id => Set.new(p1.taxons.map(&:id))}
|
||||
it "finds all distributed taxons" do
|
||||
expect(Taxon.distributed_taxons(:all)).to eq({e.id => Set.new([t1.id, t2.id])})
|
||||
end
|
||||
|
||||
it "finds currently distributed taxons" do
|
||||
expect(Taxon.distributed_taxons(:current)).to eq({e.id => Set.new([t1.id])})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,7 +6,8 @@ describe Api::EnterpriseSerializer do
|
||||
let(:taxon) { create(:taxon) }
|
||||
let(:data) { OpenStruct.new(earliest_closing_times: {},
|
||||
active_distributors: [],
|
||||
distributed_taxons: {enterprise.id => [123]},
|
||||
all_distributed_taxons: {enterprise.id => [123]},
|
||||
current_distributed_taxons: {enterprise.id => [123]},
|
||||
supplied_taxons: {enterprise.id => [456]},
|
||||
shipping_method_services: {},
|
||||
relatives: {enterprise.id => {producers: [123], distributors: [456]}}) }
|
||||
|
||||
Reference in New Issue
Block a user