diff --git a/app/helpers/injection_helper.rb b/app/helpers/injection_helper.rb index 63a0797992..519dc6dcaf 100644 --- a/app/helpers/injection_helper.rb +++ b/app/helpers/injection_helper.rb @@ -8,11 +8,15 @@ module InjectionHelper include OrderCyclesHelper def inject_enterprises(enterprises = nil) + enterprises ||= default_enterprise_query + + # make sure the query is performed now so it is only performed once + enterprises = enterprises.to_a inject_json_array( "enterprises", - enterprises || default_enterprise_query, + enterprises, Api::EnterpriseSerializer, - enterprise_injection_data, + enterprise_injection_data(enterprises.map(&:id)), ) end @@ -52,20 +56,22 @@ module InjectionHelper relatives_including_self. activated. includes(:properties, address: [:state, :country], supplied_products: :properties). - all + all. + to_a inject_json_array "enterprises", enterprises_and_relatives, Api::EnterpriseSerializer, - enterprise_injection_data + enterprise_injection_data(enterprises_and_relatives.map(&:id)) end def inject_group_enterprises(group) + enterprises = group.enterprises.activated.visible.all.to_a inject_json_array( "enterprises", - group.enterprises.activated.visible.all, + enterprises, Api::EnterpriseSerializer, - enterprise_injection_data, + enterprise_injection_data(enterprises.map(&:id)), ) end @@ -73,7 +79,7 @@ module InjectionHelper inject_json "currentHub", current_distributor, Api::EnterpriseSerializer, - enterprise_injection_data + enterprise_injection_data(current_distributor ? [current_distributor.id] : nil) end def inject_current_order @@ -153,7 +159,9 @@ module InjectionHelper Enterprise.activated.includes(address: [:state, :country]).all end - def enterprise_injection_data - @enterprise_injection_data ||= { data: OpenFoodNetwork::EnterpriseInjectionData.new } + def enterprise_injection_data(enterprise_ids) + { + data: OpenFoodNetwork::EnterpriseInjectionData.new(enterprise_ids) + } end end diff --git a/app/models/order_cycle.rb b/app/models/order_cycle.rb index 70194c8110..06e205c220 100644 --- a/app/models/order_cycle.rb +++ b/app/models/order_cycle.rb @@ -148,16 +148,20 @@ class OrderCycle < ApplicationRecord # Find the earliest closing times for each distributor in an active order cycle, and return # them in the format {distributor_id => closing_time, ...} - def self.earliest_closing_times - Hash[ - Exchange. - outgoing. - joins(:order_cycle). - merge(OrderCycle.active). - group('exchanges.receiver_id'). - pluck(Arel.sql("exchanges.receiver_id AS receiver_id"), - Arel.sql("MIN(order_cycles.orders_close_at) AS earliest_close_at")) - ] + # + # Optionally, specify some distributor_ids as a parameter to scope the results + def self.earliest_closing_times(distributor_ids = nil) + cycles = Exchange. + outgoing. + joins(:order_cycle). + merge(OrderCycle.active). + group('exchanges.receiver_id') + + cycles = cycles.where(receiver_id: distributor_ids) if distributor_ids.present? + + cycles.pluck("exchanges.receiver_id AS receiver_id", + "MIN(order_cycles.orders_close_at) AS earliest_close_at") + .to_h end def attachable_distributor_payment_methods diff --git a/app/models/spree/shipping_method.rb b/app/models/spree/shipping_method.rb index 68f2d19015..204dbc8b73 100644 --- a/app/models/spree/shipping_method.rb +++ b/app/models/spree/shipping_method.rb @@ -87,16 +87,20 @@ module Spree # Return the services (pickup, delivery) that different distributors provide, in the format: # {distributor_id => {pickup: true, delivery: false}, ...} - def self.services - Hash[ - Spree::ShippingMethod. - joins(:distributor_shipping_methods). - group('distributor_id'). - select("distributor_id"). - select("BOOL_OR(spree_shipping_methods.require_ship_address = 'f') AS pickup"). - select("BOOL_OR(spree_shipping_methods.require_ship_address = 't') AS delivery"). - map { |sm| [sm.distributor_id.to_i, { pickup: sm.pickup, delivery: sm.delivery }] } - ] + # + # Optionally, specify some distributor_ids as a parameter to scope the results + def self.services(distributor_ids = nil) + methods = Spree::ShippingMethod.joins(:distributor_shipping_methods).group('distributor_id') + + if distributor_ids.present? + methods = methods.where(distributor_shipping_methods: { distributor_id: distributor_ids }) + end + + methods. + pluck(Arel.sql("distributor_id"), + Arel.sql("BOOL_OR(spree_shipping_methods.require_ship_address = 'f') AS pickup"), + Arel.sql("BOOL_OR(spree_shipping_methods.require_ship_address = 't') AS delivery")). + to_h { |(distributor_id, pickup, delivery)| [distributor_id.to_i, { pickup:, delivery: }] } end def self.backend diff --git a/app/models/spree/taxon.rb b/app/models/spree/taxon.rb index 6c4c38290d..57d4c94e97 100644 --- a/app/models/spree/taxon.rb +++ b/app/models/spree/taxon.rb @@ -25,18 +25,19 @@ module Spree # Find all the taxons of supplied products for each enterprise, indexed by enterprise. # Format: {enterprise_id => [taxon_id, ...]} - def self.supplied_taxons - taxons = {} - - Spree::Taxon. + # + # Optionally, specify some enterprise_ids to scope the results + def self.supplied_taxons(enterprise_ids = nil) + taxons = Spree::Taxon. joins(variants: :supplier). - select('spree_taxons.*, enterprises.id AS enterprise_id'). - each do |t| - taxons[t.enterprise_id.to_i] ||= Set.new - taxons[t.enterprise_id.to_i] << t.id - end + select('spree_taxons.*, enterprises.id AS enterprise_id') - taxons + taxons = taxons.where(enterprises: { id: enterprise_ids }) if enterprise_ids.present? + + taxons.each_with_object({}) do |t, collection| + collection[t.enterprise_id.to_i] ||= Set.new + collection[t.enterprise_id.to_i] << t.id + end end # Find all the taxons of distributed products for each enterprise, indexed by enterprise. @@ -44,7 +45,9 @@ module Spree # or :current taxons (distributed in an open order cycle). # # Format: {enterprise_id => [taxon_id, ...]} - def self.distributed_taxons(which_taxons = :all) + # + # Optionally, specify some enterprise_ids to scope the results + def self.distributed_taxons(which_taxons = :all, enterprise_ids = nil) ents_and_vars = ExchangeVariant.joins(exchange: :order_cycle).merge(Exchange.outgoing) .select("DISTINCT variant_id, receiver_id AS enterprise_id") @@ -57,6 +60,10 @@ module Spree INNER JOIN (#{ents_and_vars.to_sql}) AS ents_and_vars ON spree_variants.id = ents_and_vars.variant_id") + if enterprise_ids.present? + taxons = taxons.where(ents_and_vars: { enterprise_id: enterprise_ids }) + end + taxons.each_with_object({}) do |t, ts| ts[t.enterprise_id.to_i] ||= Set.new ts[t.enterprise_id.to_i] << t.id diff --git a/lib/open_food_network/enterprise_injection_data.rb b/lib/open_food_network/enterprise_injection_data.rb index 31801c63f9..98121ed324 100644 --- a/lib/open_food_network/enterprise_injection_data.rb +++ b/lib/open_food_network/enterprise_injection_data.rb @@ -2,13 +2,23 @@ module OpenFoodNetwork class EnterpriseInjectionData + # By default, data is fetched for *every* enterprise in the DB, but we specify some ids of + # enterprises that we are interested in, there is a lot less data to fetch + def initialize(enterprise_ids = nil) + @enterprise_ids = enterprise_ids + end + def active_distributor_ids @active_distributor_ids ||= - Enterprise.distributors_with_active_order_cycles.ready_for_checkout.pluck(:id) + begin + enterprises = Enterprise.distributors_with_active_order_cycles.ready_for_checkout + enterprises = enterprises.where(id: @enterprise_ids) if @enterprise_ids.present? + enterprises.pluck(:id) + end end def earliest_closing_times - @earliest_closing_times ||= OrderCycle.earliest_closing_times + @earliest_closing_times ||= OrderCycle.earliest_closing_times(@enterprise_ids) end def shipping_method_services @@ -16,7 +26,7 @@ module OpenFoodNetwork Spree::ShippingMethod) do # This result relies on a simple join with DistributorShippingMethod. # Updated DistributorShippingMethod records touch their associated Spree::ShippingMethod. - Spree::ShippingMethod.services + Spree::ShippingMethod.services(@enterprise_ids) end end @@ -26,16 +36,16 @@ module OpenFoodNetwork # class Classification which maps the relationship. Classification records touch # their associated Spree::Taxon when updated. A Spree::Product's primary_taxon # is also touched when changed. - Spree::Taxon.supplied_taxons + Spree::Taxon.supplied_taxons(@enterprise_ids) end end def all_distributed_taxons - @all_distributed_taxons ||= Spree::Taxon.distributed_taxons(:all) + @all_distributed_taxons ||= Spree::Taxon.distributed_taxons(:all, @enterprise_ids) end def current_distributed_taxons - @current_distributed_taxons ||= Spree::Taxon.distributed_taxons(:current) + @current_distributed_taxons ||= Spree::Taxon.distributed_taxons(:current, @enterprise_ids) end end end