diff --git a/app/models/spree/product.rb b/app/models/spree/product.rb index dc8ba0c7a9..6742ab6e34 100755 --- a/app/models/spree/product.rb +++ b/app/models/spree/product.rb @@ -32,7 +32,7 @@ module Spree searchable_attributes :supplier_id, :primary_taxon_id, :meta_keywords searchable_associations :supplier, :properties, :primary_taxon, :variants, :master - searchable_scopes :active + searchable_scopes :active, :with_properties has_many :product_option_types, dependent: :destroy # We have an after_destroy callback on Spree::ProductOptionType. However, if we @@ -70,6 +70,19 @@ module Spree has_many :stock_items, through: :variants + has_many :supplier_properties, through: :supplier, source: :properties + + scope :with_properties, ->(*property_ids) { + left_outer_joins(:product_properties). + left_outer_joins(:supplier_properties). + where(inherits_properties: true). + where(producer_properties: { property_id: property_ids }). + or( + where(spree_product_properties: { property_id: property_ids }) + ). + distinct + } + delegate_belongs_to :master, :sku, :price, :currency, :display_amount, :display_price, :weight, :height, :width, :depth, :is_master, :cost_currency, :price_in, :amount_in, :unit_value, :unit_description diff --git a/spec/models/spree/product_spec.rb b/spec/models/spree/product_spec.rb index 4ca904fa14..65781c515b 100644 --- a/spec/models/spree/product_spec.rb +++ b/spec/models/spree/product_spec.rb @@ -199,6 +199,51 @@ module Spree end end + describe "supplier properties" do + subject { create(:product) } + + it "has no supplier properties to start with" do + expect(subject.supplier_properties).to eq [] + end + + it "doesn't include product properties" do + subject.set_property("certified", "organic") + expect(subject.supplier_properties).to eq [] + end + + it "includes the supplier's properties" do + subject.supplier.set_producer_property("certified", "yes") + expect(subject.supplier_properties.map(&:presentation)).to eq ["certified"] + end + end + + describe ".with_properties scope" do + let!(:product_without_wanted_property_on_supplier) { create(:product, supplier: supplier_without_wanted_property) } + let!(:product_with_wanted_property_on_supplier) { create(:product, supplier: supplier_with_wanted_property) } + let!(:product_with_wanted_property) { create(:product, properties: [wanted_property]) } + let!(:product_without_wanted_property_property) { create(:product, properties: [unwanted_property]) } + let!(:product_with_wanted_property_and_on_supplier) { create(:product, properties: [wanted_property], supplier: supplier_with_wanted_property) } + let!(:product_ignoring_property) { create(:product, supplier: supplier_with_wanted_property, inherits_properties: false) } + let(:supplier_with_wanted_property) { create(:supplier_enterprise, properties: [wanted_property]) } + let(:supplier_without_wanted_property) { create(:supplier_enterprise, properties: [unwanted_property]) } + let(:wanted_property) { create(:property, presentation: 'Certified Organic') } + let(:unwanted_property) { create(:property, presentation: 'Latest Hype') } + + it "returns no products without a property id" do + expect(Spree::Product.with_properties([])).to eq [] + end + + it "returns only products with the wanted property set both on supplier and on the product itself" do + expect( + Spree::Product.with_properties([wanted_property.id]) + ).to match_array [ + product_with_wanted_property_on_supplier, + product_with_wanted_property, + product_with_wanted_property_and_on_supplier + ] + end + end + # Regression tests for Spree #2352 context "classifications and taxons" do it "is joined through classifications" do