diff --git a/app/services/products_renderer.rb b/app/services/products_renderer.rb index 9db07fa975..bade34a4c2 100644 --- a/app/services/products_renderer.rb +++ b/app/services/products_renderer.rb @@ -3,7 +3,7 @@ require 'open_food_network/scope_product_to_hub' -class ProductsRenderer # rubocop:disable Metrics/ClassLength +class ProductsRenderer include Pagy::Backend class NoProducts < RuntimeError; end @@ -35,8 +35,7 @@ class ProductsRenderer # rubocop:disable Metrics/ClassLength return unless order_cycle @products ||= begin - results = products_relation. - order(Arel.sql(products_order)) + results = distributed_products.products_relation(supplier_properties: supplier_properties_arg) results = filter(results) # Scope results with variant_overrides @@ -52,38 +51,21 @@ class ProductsRenderer # rubocop:disable Metrics/ClassLength OpenFoodNetwork::EnterpriseFeeCalculator.new distributor, order_cycle end - # TODO refactor this, distributed_products should be able to give use the relation based - # on the sorting method, same for ordering. It would prevent the SQL implementation from - # leaking here - def products_relation - if distributor.preferred_shopfront_product_sorting_method == "by_category" && - distributor.preferred_shopfront_taxon_order.present? - return distributed_products.products_taxons_relation - end - - distributed_products.products_supplier_relation - end - - # TODO: refactor to address CyclomaticComplexity - def filter(query) # rubocop:disable Metrics/CyclomaticComplexity - supplier_properties = args[:q]&.slice("with_variants_supplier_properties") + def filter(query) + supplier_properties = supplier_properties_arg ransack_results = query.ransack(args[:q]).result.to_a return ransack_results if supplier_properties.blank? - with_properties = args[:q]&.dig("with_properties") supplier_properties_results = [] - if supplier_properties.present? # We can't search on an association's scope with ransack, a work around is to define # the a scope on the parent (Spree::Product) but because we are joining on "first_variant" # to get the supplier it doesn't work, so we do the filtering manually here # see: - # OrderCycleDistributedProducts#products_supplier_relation - # OrderCycleDistributedProducts#supplier_property_join - supplier_property_ids = supplier_properties["with_variants_supplier_properties"] - supplier_properties_results = distributed_products.supplier_property_join(query). + # OrderCycleDistributedProducts#products_relation + supplier_properties_results = query. where(producer_properties: { property_id: supplier_property_ids }). where(inherits_properties: true) end @@ -101,6 +83,18 @@ class ProductsRenderer # rubocop:disable Metrics/ClassLength ransack_results end + def supplier_properties_arg + args[:q]&.slice("with_variants_supplier_properties") + end + + def supplier_property_ids + supplier_properties_arg["with_variants_supplier_properties"] + end + + def with_properties + args[:q]&.dig("with_properties") + end + def paginate(results) _pagy, paginated_results = pagy_array( results, @@ -115,27 +109,6 @@ class ProductsRenderer # rubocop:disable Metrics/ClassLength OrderCycles::DistributedProductsService.new(distributor, order_cycle, customer) end - # TODO refactor, see above - def products_order - if distributor.preferred_shopfront_product_sorting_method == "by_producer" && - distributor.preferred_shopfront_producer_order.present? - order_by_producer = distributor - .preferred_shopfront_producer_order - .split(",").map { |id| "first_variant.supplier_id=#{id} DESC" } - .join(", ") - "#{order_by_producer}, spree_products.name ASC, spree_products.id ASC" - elsif distributor.preferred_shopfront_product_sorting_method == "by_category" && - distributor.preferred_shopfront_taxon_order.present? - order_by_category = distributor - .preferred_shopfront_taxon_order - .split(",").map { |id| "first_variant.primary_taxon_id=#{id} DESC" } - .join(", ") - "#{order_by_category}, spree_products.name ASC, spree_products.id ASC" - else - "spree_products.name ASC, spree_products.id" - end - end - def variants_for_shop @variants_for_shop ||= begin scoper = OpenFoodNetwork::ScopeVariantToHub.new(distributor) diff --git a/spec/services/products_renderer_spec.rb b/spec/services/products_renderer_spec.rb index 4044b354e6..dfec59bce7 100644 --- a/spec/services/products_renderer_spec.rb +++ b/spec/services/products_renderer_spec.rb @@ -38,34 +38,6 @@ RSpec.describe ProductsRenderer do exchange.variants << product_doughnuts.variants.first end - describe "sorting" do - it "sorts products by the distributor's preferred taxon list" do - allow(distributor) - .to receive(:preferred_shopfront_taxon_order) { "#{cakes.id},#{fruits.id}" } - products = products_renderer.send(:products) - expect(products) - .to eq([product_banana_bread, product_doughnuts, product_apples, product_cherries]) - end - - it "sorts products by the distributor's preferred producer list" do - allow(distributor) - .to receive(:preferred_shopfront_product_sorting_method) { "by_producer" } - allow(distributor).to receive(:preferred_shopfront_producer_order) { - "#{cakes_supplier.id},#{fruits_supplier.id}" - } - products = products_renderer.send(:products) - expect(products) - .to eq([product_banana_bread, product_doughnuts, product_apples, product_cherries]) - end - - it "alphabetizes products by name when taxon list is not set" do - allow(distributor).to receive(:preferred_shopfront_taxon_order) { "" } - products = products_renderer.send(:products) - expect(products) - .to eq([product_apples, product_banana_bread, product_cherries, product_doughnuts]) - end - end - context "filtering" do it "filters products by name_or_meta_keywords_or_variants_display_as_or_" \ "variants_display_name_or_variants_supplier_name_cont" do