Refactor ProductRenderer

The sorting logic has been moved to
OrderCycles::DistributedProductsService#product_relations

Plus hopefully fix the spec flackiness
This commit is contained in:
Gaetan Craig-Riou
2024-06-17 16:10:00 +10:00
parent 79a22aefc3
commit c372bf746a
2 changed files with 18 additions and 73 deletions

View File

@@ -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)

View File

@@ -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