      def self.property_filter(property, sym_name, taxon_id = 1)
          product_properties = Spree::ProductProperty.where(property_id: property.id).pluck(:value).uniq.map(&:to_s)
          pp = Spree::ProductProperty.arel_table
          conds = Hash[*product_properties.map { |b| [b, pp[:value].eq(b)] }.flatten]

          taxon ||= Spree::Taxon.find(taxon_id)
          search_property = Spree::Property.find_by(name: property.name)
          scope = Spree::ProductProperty.where(property: search_property).
              joins(product: :taxons).
              where("#{Spree::Taxon.table_name}.id" => [taxon] + taxon.descendants)
          labels = scope.pluck(:value).uniq

          labels = labels.partition { |x| x.to_i.to_s == x }
          labels = labels.first.sort_by(&:to_i) + labels.last.sort
          {
              name:   property.name,
              scope:  sym_name,
              conds:  conds,
              labels: labels.map { |k| [k, k] }
          }
      end

      def self.all_properties_filter(taxon)
        Rails.cache.fetch("#{taxon.id}_#{taxon.updated_at}/all_properties_filter", expires_in: 72.hours) do
          Spree::Property.all.map do |property|

            sym_name = ('property_' + property.id.to_s + '_filter').to_sym

            taxon_id = taxon.id
            property_filter(property, sym_name, taxon_id)
          end
        end
      end

      Spree::Property.all.each do |property|

        scope_name = 'property_' + property.id.to_s + '_filter'

        Spree::Product.add_search_scope scope_name do |*opts|
          conds = opts.map { |o| ProductFilters.property_filter(property, scope_name)[:conds][o] }.reject(&:nil?)
          scope = conds.shift
          conds.each do |new_scope|
            scope = scope.or(new_scope)
          end
          Spree::Product.with_property(property.name).where(scope)
        end
      end
