spree_core 5.4.0.beta4 → 5.4.0.beta5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29b95e3e3222214cdeef8094a1a9553636c875d88857244241431196d06399d2
4
- data.tar.gz: 93c9f4d387fce7ba5e2e9f4b6454f9c46f1b8a15cfe180a16739c17bf76a5125
3
+ metadata.gz: a2a4eae0b4e102ba4160e435fe81d656ced27b014ed013670226bb8a522b5996
4
+ data.tar.gz: c8c6737253472a4456f29b06f1ae028b2c4144732fba6dae7d8dd8c5e2b92d8f
5
5
  SHA512:
6
- metadata.gz: 5c8a23c3edd35dacb0493c5435e28d114fc2611b4b25a0d85b4b5e4579f38402fb61a3a65a9f3b361fae8f67d5f58ac73984b6ab2cd4bcbb0326813589a18330
7
- data.tar.gz: 1fabd1160061e412e2e9a4a1e92083686938a5313c3b29193e410bc07d6118d60af4bd7c2951794273c20f8b053f1dfc5acba8dfe748a722f5895aacc17d33d9
6
+ metadata.gz: ec9479d52b6bcbd036354511897d0ee360da7784aef051f20affe23991b1eaebe8525b7a0173fbc7cdc1310a977909e4b78a33b0cd677869d579d1666bbada7a
7
+ data.tar.gz: 44b40ddca311ed24ae26cd99b5455a7259a0aa986cb8a9a76598101e4c42ea48042b8f1256365b2734c7e43218337ec7963c78b0bcffc5ab70f62e0f794d4b9e
@@ -1,12 +1,15 @@
1
1
  require 'open-uri'
2
2
  require 'openssl'
3
+ require 'ssrf_filter'
4
+ require 'tempfile'
3
5
 
4
6
  module Spree
5
7
  module Images
6
8
  class SaveFromUrlJob < ::Spree::BaseJob
7
9
  queue_as Spree.queues.images
8
- retry_on ActiveRecord::RecordInvalid, OpenURI::HTTPError, wait: :polynomially_longer, attempts: Spree::Config.images_save_from_url_job_attempts.to_i
10
+ retry_on ActiveRecord::RecordInvalid, wait: :polynomially_longer, attempts: Spree::Config.images_save_from_url_job_attempts.to_i
9
11
  discard_on URI::InvalidURIError
12
+ discard_on SsrfFilter::Error
10
13
 
11
14
  def perform(viewable_id, viewable_type, external_url, external_id = nil, position = nil)
12
15
  viewable = viewable_type.safe_constantize.find(viewable_id)
@@ -29,34 +32,55 @@ module Spree
29
32
  # still trigger save! if position has changed
30
33
  image.save! and return if image_already_saved?(image, external_url)
31
34
 
32
- uri = URI.parse(external_url)
33
- unless %w[http https].include?(uri.scheme)
34
- raise URI::InvalidURIError, "Invalid URL scheme: #{uri.scheme}. Only http and https are allowed."
35
- end
36
-
37
- file = uri.open(
38
- 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
39
- 'Accept' => 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
40
- 'Accept-Language' => 'en-US,en;q=0.9',
41
- 'Accept-Encoding' => 'gzip, deflate, br',
42
- 'Cache-Control' => 'no-cache',
43
- 'Pragma' => 'no-cache',
44
- read_timeout: 60,
45
- ssl_verify_mode: OpenSSL::SSL::VERIFY_PEER,
46
- redirect: true
47
- )
48
- filename = File.basename(uri.path)
49
-
50
- image.attachment.attach(io: file, filename: filename)
51
- image.external_url = external_url
52
- image.external_id = external_id if external_id.present? && image.respond_to?(:external_id)
53
- image.save!
35
+ download_and_attach_image(external_url, image, external_id)
54
36
  rescue ActiveStorage::IntegrityError => e
55
37
  raise e unless Rails.env.test?
56
38
  end
57
39
 
58
40
  private
59
41
 
42
+ def download_and_attach_image(external_url, image, external_id)
43
+ max_size = Spree::Config.max_image_download_size
44
+
45
+ response = SsrfFilter.get(
46
+ external_url,
47
+ headers: {
48
+ 'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
49
+ 'Accept' => 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
50
+ 'Accept-Language' => 'en-US,en;q=0.9',
51
+ 'Accept-Encoding' => 'gzip, deflate, br',
52
+ 'Cache-Control' => 'no-cache',
53
+ 'Pragma' => 'no-cache'
54
+ },
55
+ http_options: {
56
+ read_timeout: 60,
57
+ open_timeout: 30
58
+ }
59
+ )
60
+
61
+ body = response.body
62
+ if body.bytesize > max_size
63
+ raise StandardError, "Image file size exceeds the maximum allowed size of #{max_size} bytes"
64
+ end
65
+
66
+ uri = URI.parse(external_url)
67
+ filename = File.basename(uri.path)
68
+ tempfile = Tempfile.new(['spree_image', File.extname(uri.path)], binmode: true)
69
+
70
+ begin
71
+ tempfile.write(body)
72
+ tempfile.rewind
73
+
74
+ image.attachment.attach(io: tempfile, filename: filename)
75
+ image.external_url = external_url
76
+ image.external_id = external_id if external_id.present? && image.respond_to?(:external_id)
77
+ image.save!
78
+ ensure
79
+ tempfile.close
80
+ tempfile.unlink
81
+ end
82
+ end
83
+
60
84
  def image_already_saved?(image, external_url)
61
85
  image.persisted? && image.attachment.attached? && image.external_url.present? && external_url == image.external_url
62
86
  end
@@ -41,32 +41,38 @@ module Spree
41
41
  order(price_table_name => { amount: :desc })
42
42
  end
43
43
 
44
- # Price sorting scopes that use subqueries to get prices across all variants
45
- # These ensure products with only variant prices (no master price) are included in results
44
+ # Price sorting scopes that use a derived table JOIN to get prices across all variants.
45
+ # These ensure products with only variant prices (no master price) are included in results.
46
+ #
47
+ # Uses Arel::Nodes::As for select expressions so that:
48
+ # - PG allows ORDER BY with DISTINCT (expressions must appear in SELECT list)
49
+ # - Mobility's select_for_count can safely call .right on all select_values
46
50
  add_search_scope :ascend_by_price do
47
- price_subquery = Price
48
- .non_zero
49
- .joins(:variant)
50
- .where("#{Variant.table_name}.product_id = #{Product.table_name}.id")
51
- .select('MIN(amount)')
51
+ price_agg_sql = Price.non_zero.joins(:variant)
52
+ .select("#{Variant.table_name}.product_id AS product_id, MIN(#{Price.table_name}.amount) AS agg_price")
53
+ .group("#{Variant.table_name}.product_id")
54
+ .to_sql
52
55
 
53
- price_sort_sql = "COALESCE((#{price_subquery.to_sql}), 999999999)"
56
+ price_expr = Arel.sql('COALESCE(price_agg.agg_price, 999999999)')
54
57
 
55
- select("#{Product.table_name}.*", "#{price_sort_sql} AS min_price").
56
- order(Arel.sql("#{price_sort_sql} ASC"))
58
+ joins("LEFT JOIN (#{price_agg_sql}) AS price_agg ON price_agg.product_id = #{Product.table_name}.id").
59
+ select("#{Product.table_name}.*").
60
+ select(Arel::Nodes::As.new(price_expr, Arel.sql('min_price'))).
61
+ order(price_expr.asc)
57
62
  end
58
63
 
59
64
  add_search_scope :descend_by_price do
60
- price_subquery = Price
61
- .non_zero
62
- .joins(:variant)
63
- .where("#{Variant.table_name}.product_id = #{Product.table_name}.id")
64
- .select('MAX(amount)')
65
+ price_agg_sql = Price.non_zero.joins(:variant)
66
+ .select("#{Variant.table_name}.product_id AS product_id, MAX(#{Price.table_name}.amount) AS agg_price")
67
+ .group("#{Variant.table_name}.product_id")
68
+ .to_sql
65
69
 
66
- price_sort_sql = "COALESCE((#{price_subquery.to_sql}), 0)"
70
+ price_expr = Arel.sql('COALESCE(price_agg.agg_price, 0)')
67
71
 
68
- select("#{Product.table_name}.*", "#{price_sort_sql} AS max_price").
69
- order(Arel.sql("#{price_sort_sql} DESC"))
72
+ joins("LEFT JOIN (#{price_agg_sql}) AS price_agg ON price_agg.product_id = #{Product.table_name}.id").
73
+ select("#{Product.table_name}.*").
74
+ select(Arel::Nodes::As.new(price_expr, Arel.sql('max_price'))).
75
+ order(price_expr.desc)
70
76
  end
71
77
 
72
78
  add_search_scope :price_between do |low, high|
@@ -81,6 +87,25 @@ module Spree
81
87
  where(Price.table_name => { amount: price.. })
82
88
  end
83
89
 
90
+ # Joins spree_variants and spree_stock_items directly (without association
91
+ # aliases) so that the table names stay as-is. This avoids alias conflicts
92
+ # when combined with other scopes (e.g., price sorting) that also join
93
+ # spree_variants through associations which generate aliases.
94
+ def self.join_variants_and_stock_items
95
+ joins("INNER JOIN #{Variant.table_name} ON #{Variant.table_name}.deleted_at IS NULL AND #{Variant.table_name}.product_id = #{Product.table_name}.id").
96
+ joins("LEFT OUTER JOIN #{StockItem.table_name} ON #{StockItem.table_name}.deleted_at IS NULL AND #{StockItem.table_name}.variant_id = #{Variant.table_name}.id")
97
+ end
98
+ private_class_method :join_variants_and_stock_items
99
+
100
+ # Mirrors Spree::Variant.in_stock_or_backorderable logic using raw table
101
+ # names (to pair with join_variants_and_stock_items).
102
+ scope :in_stock_or_backorderable_condition, -> {
103
+ where(
104
+ "#{Variant.table_name}.track_inventory = ? OR #{StockItem.table_name}.count_on_hand > ? OR #{StockItem.table_name}.backorderable = ?",
105
+ false, 0, true
106
+ )
107
+ }
108
+
84
109
  # Can't use add_search_scope for this as it needs a default argument
85
110
  # Ransack calls with '1' to activate, '0' or nil to skip
86
111
  # In Ruby code: in_stock(true) for in-stock, in_stock(false) for out-of-stock
@@ -88,7 +113,7 @@ module Spree
88
113
  if in_stock == '0' || !in_stock
89
114
  all
90
115
  else
91
- joins(:variants_including_master).merge(Spree::Variant.in_stock_or_backorderable)
116
+ join_variants_and_stock_items.in_stock_or_backorderable_condition
92
117
  end
93
118
  end
94
119
 
@@ -105,17 +130,17 @@ module Spree
105
130
  if out_of_stock == '0' || !out_of_stock
106
131
  all
107
132
  else
108
- where.not(id: joins(:variants_including_master).merge(Spree::Variant.in_stock_or_backorderable))
133
+ where.not(id: join_variants_and_stock_items.in_stock_or_backorderable_condition)
109
134
  end
110
135
  end
111
136
  search_scopes << :out_of_stock
112
137
 
113
138
  add_search_scope :backorderable do
114
- joins(:variants_including_master).merge(Spree::Variant.backorderable)
139
+ join_variants_and_stock_items.where(StockItem.table_name => { backorderable: true })
115
140
  end
116
141
 
117
142
  add_search_scope :in_stock_or_backorderable do
118
- joins(:variants_including_master).merge(Spree::Variant.in_stock_or_backorderable)
143
+ join_variants_and_stock_items.in_stock_or_backorderable_condition
119
144
  end
120
145
 
121
146
  # This scope selects products in taxon AND all its descendants
@@ -140,6 +165,11 @@ module Spree
140
165
  where("#{Classification.table_name}.taxon_id" => taxon.cached_self_and_descendants_ids).distinct
141
166
  end
142
167
 
168
+ # Alias for in_taxon — public API name
169
+ add_search_scope :in_category do |category|
170
+ in_taxon(category)
171
+ end
172
+
143
173
  # This scope selects products in all taxons AND all its descendants
144
174
  # If you need products only within one taxon use
145
175
  #
@@ -204,9 +234,7 @@ module Spree
204
234
 
205
235
  return none if actual_ids.empty?
206
236
 
207
- group("#{Spree::Product.table_name}.id").
208
- joins(variants: :option_values).
209
- where(Spree::OptionValue.table_name => { id: actual_ids })
237
+ joins(variants: :option_values).where(Spree::OptionValue.table_name => { id: actual_ids })
210
238
  end
211
239
 
212
240
  # Finds all products which have an option value with the name matching the one given
@@ -325,25 +353,22 @@ module Spree
325
353
  end
326
354
 
327
355
  # Orders products by best selling based on units_sold_count and revenue
328
- # stored in spree_products_stores table.
329
- #
330
- # These metrics are updated asynchronously when orders are completed
331
- # via the ProductMetricsSubscriber.
356
+ # from spree_products_stores (already joined via store.products).
332
357
  #
333
- # @param order_direction [Symbol] :desc (default) or :asc
334
- # @return [ActiveRecord::Relation]
358
+ # Uses Arel::Nodes::As so that ORDER BY expressions appear in SELECT
359
+ # and work with DISTINCT (same pattern as the price sorting scopes).
335
360
  add_search_scope :by_best_selling do |order_direction = :desc|
336
- store_id = Spree::Current.store&.id
337
- sp_table = StoreProduct.arel_table
338
- products_table = Product.arel_table
339
-
340
- conditions = sp_table[:product_id].eq(products_table[:id]).and(sp_table[:store_id].eq(store_id))
341
-
342
- units_sold = Arel::Nodes::NamedFunction.new('COALESCE', [sp_table.project(sp_table[:units_sold_count]).where(conditions), 0])
343
- revenue = Arel::Nodes::NamedFunction.new('COALESCE', [sp_table.project(sp_table[:revenue]).where(conditions), 0])
361
+ sp_table = StoreProduct.table_name
362
+ units_expr = Arel.sql("COALESCE(#{sp_table}.units_sold_count, 0)")
363
+ revenue_expr = Arel.sql("COALESCE(#{sp_table}.revenue, 0)")
344
364
 
345
365
  order_dir = order_direction == :desc ? :desc : :asc
346
- order(units_sold.send(order_dir)).order(revenue.send(order_dir))
366
+
367
+ select("#{Product.table_name}.*").
368
+ select(Arel::Nodes::As.new(units_expr, Arel.sql('best_selling_units'))).
369
+ select(Arel::Nodes::As.new(revenue_expr, Arel.sql('best_selling_revenue'))).
370
+ order(units_expr.send(order_dir)).
371
+ order(revenue_expr.send(order_dir))
347
372
  end
348
373
 
349
374
  # .search_by_name
@@ -4,6 +4,7 @@ module Spree
4
4
 
5
5
  include Spree::PrefixedId
6
6
  include Spree::Metafields
7
+ include Spree::Metadata
7
8
  include Spree::UserPaymentSource
8
9
  include Spree::UserReporting
9
10
  include Spree::UserRoles
@@ -0,0 +1,6 @@
1
+ module Spree
2
+ # Public API name for Taxon. Will become the base class in 6.0
3
+ # when spree_taxons table is renamed to spree_categories.
4
+ class Category < Taxon
5
+ end
6
+ end
@@ -34,6 +34,10 @@ module Spree
34
34
  payment.number
35
35
  end
36
36
 
37
+ def idempotency_key
38
+ "spree-#{payment.number}"
39
+ end
40
+
37
41
  def shipping
38
42
  order.ship_total * exchange_multiplier
39
43
  end
@@ -66,6 +70,7 @@ module Spree
66
70
  :ip,
67
71
  :order_id,
68
72
  :payment_id,
73
+ :idempotency_key,
69
74
  :shipping,
70
75
  :tax,
71
76
  :subtotal,
@@ -40,9 +40,9 @@ module Spree
40
40
 
41
41
  publishes_lifecycle_events
42
42
 
43
- MEMOIZED_METHODS = %w[total_on_hand taxonomy_ids taxon_and_ancestors category
43
+ MEMOIZED_METHODS = %w[total_on_hand taxonomy_ids taxon_and_ancestors
44
44
  default_variant_id tax_category default_variant variant_for_images
45
- category_taxon brand_taxon main_taxon
45
+ brand_taxon main_taxon
46
46
  purchasable? in_stock? backorderable? digital?]
47
47
 
48
48
  STATUSES = %w[draft active archived].freeze
@@ -74,6 +74,7 @@ module Spree
74
74
  has_many :option_types, through: :product_option_types
75
75
  has_many :classifications, -> { order(created_at: :asc) }, dependent: :delete_all, inverse_of: :product
76
76
  has_many :taxons, through: :classifications, before_remove: :remove_taxon
77
+ has_many :categories, through: :classifications, class_name: 'Spree::Category', source: :taxon
77
78
  has_many :taxonomies, through: :taxons
78
79
 
79
80
  has_many :product_promotion_rules, class_name: 'Spree::ProductPromotionRule'
@@ -217,7 +218,7 @@ module Spree
217
218
  alias options product_option_types
218
219
 
219
220
  self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on status available_on created_at updated_at]
220
- self.whitelisted_ransackable_associations = %w[taxons stores variants_including_master master variants tags labels
221
+ self.whitelisted_ransackable_associations = %w[taxons categories stores variants_including_master master variants tags labels
221
222
  shipping_category classifications option_types]
222
223
  self.whitelisted_ransackable_scopes = %w[not_discontinued search_by_name in_taxon price_between
223
224
  price_lte price_gte
@@ -556,40 +557,10 @@ module Spree
556
557
  brand&.name
557
558
  end
558
559
 
559
- # Returns the category for the product
560
- # If a category association is defined (e.g., belongs_to :category), it will be used
561
- # Otherwise, falls back to category_taxon for compatibility
562
- # @return [Spree::Category, Spree::Taxon]
563
- def category
564
- if self.class.reflect_on_association(:category)
565
- super
566
- else
567
- Spree::Deprecation.warn('Spree::Product#category is deprecated and will be removed in Spree 5.5. Please use Spree::Product#category_taxon instead.')
568
- category_taxon
569
- end
570
- end
571
-
572
- # Returns the category taxon for the product
573
- # @return [Spree::Taxon]
574
- def category_taxon
575
- @category_taxon ||= if classification_count.zero?
576
- nil
577
- elsif Spree.use_translations?
578
- taxons.joins(:taxonomy).
579
- join_translation_table(Taxonomy).
580
- order(depth: :desc).
581
- find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_categories_name) })
582
- elsif taxons.loaded?
583
- taxons.find { |taxon| taxon.taxonomy.name == Spree.t(:taxonomy_categories_name) }
584
- else
585
- taxons.joins(:taxonomy).order(depth: :desc).find_by(Taxonomy.table_name => { name: Spree.t(:taxonomy_categories_name) })
586
- end
587
- end
588
-
589
560
  def main_taxon
590
561
  return if classification_count.zero?
591
562
 
592
- @main_taxon ||= category_taxon || taxons.first
563
+ @main_taxon ||= taxons.first
593
564
  end
594
565
 
595
566
  def taxons_for_store(store)
@@ -1,15 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
 
3
5
  module Spree
4
6
  class Store < Spree.base_class
5
- has_prefix_id :store # Spree-specific: store
7
+ has_prefix_id :store # Spree-specific: store
6
8
 
7
9
  include FriendlyId
8
10
  include Spree::TranslatableResource
9
11
  include Spree::Metafields
10
12
  include Spree::Metadata
11
13
  include Spree::Stores::Setup
12
- include Spree::Stores::Socials
13
14
  include Spree::Stores::Markets
14
15
  include Spree::Security::Stores if defined?(Spree::Security::Stores)
15
16
  include Spree::UserManagement
@@ -23,8 +24,7 @@ module Spree
23
24
  #
24
25
  # Translations
25
26
  #
26
- TRANSLATABLE_FIELDS = %i[name meta_description meta_keywords seo_title facebook
27
- twitter instagram customer_support_email
27
+ TRANSLATABLE_FIELDS = %i[name meta_description meta_keywords seo_title customer_support_email
28
28
  address contact_phone].freeze
29
29
  translates(*TRANSLATABLE_FIELDS, column_fallback: !Spree.always_use_translations?)
30
30
  self::Translation.class_eval do
@@ -43,9 +43,6 @@ module Spree
43
43
  preference :unit_system, :string, default: 'imperial'
44
44
  # email preferences
45
45
  preference :send_consumer_transactional_emails, :boolean, default: true
46
- # SEO preferences
47
- preference :index_in_search_engines, :boolean, default: false
48
- preference :password_protected, :boolean, default: false
49
46
  # Checkout preferences
50
47
  preference :guest_checkout, :boolean, default: true
51
48
  preference :special_instructions_enabled, :boolean, default: false
@@ -86,6 +83,7 @@ module Spree
86
83
 
87
84
  has_many :taxonomies, class_name: 'Spree::Taxonomy'
88
85
  has_many :taxons, through: :taxonomies, class_name: 'Spree::Taxon'
86
+ has_many :categories, through: :taxonomies, class_name: 'Spree::Category', source: :taxons
89
87
 
90
88
  has_many :store_promotions, class_name: 'Spree::StorePromotion'
91
89
  has_many :promotions, through: :store_promotions, class_name: 'Spree::Promotion'
@@ -111,21 +109,6 @@ module Spree
111
109
 
112
110
  has_many :api_keys, class_name: 'Spree::ApiKey', dependent: :destroy
113
111
 
114
-
115
- #
116
- # ActionText
117
- #
118
- has_rich_text :checkout_message
119
- has_rich_text :customer_terms_of_service
120
- has_rich_text :customer_privacy_policy
121
- has_rich_text :customer_returns_policy
122
- has_rich_text :customer_shipping_policy
123
-
124
- #
125
- # Virtual attributes
126
- #
127
- store_accessor :private_metadata, :storefront_password
128
-
129
112
  #
130
113
  # Validations
131
114
  #
@@ -137,19 +120,17 @@ module Spree
137
120
  validates :mail_from_address, email: { allow_blank: false }
138
121
  # FIXME: we should remove this condition in v5
139
122
  if !ENV['SPREE_DISABLE_DB_CONNECTION'] &&
140
- connected? &&
141
- table_exists? &&
142
- connection.column_exists?(:spree_stores, :new_order_notifications_email)
123
+ connected? &&
124
+ table_exists? &&
125
+ connection.column_exists?(:spree_stores, :new_order_notifications_email)
143
126
  validates :new_order_notifications_email, email: { allow_blank: true }
144
127
  end
145
- validates :favicon_image, :social_image, :mailer_logo, content_type: Rails.application.config.active_storage.web_image_content_types
128
+ validates :mailer_logo, content_type: Rails.application.config.active_storage.web_image_content_types
146
129
 
147
130
  #
148
131
  # Attachments
149
132
  #
150
133
  has_one_attached :logo, service: Spree.public_storage_service_name
151
- has_one_attached :favicon_image, service: Spree.public_storage_service_name
152
- has_one_attached :social_image, service: Spree.public_storage_service_name
153
134
  has_one_attached :mailer_logo, service: Spree.public_storage_service_name
154
135
 
155
136
  #
@@ -157,8 +138,6 @@ module Spree
157
138
  before_validation :set_default_code, on: :create
158
139
  before_save :ensure_default_exists_and_is_unique
159
140
  after_create :ensure_default_market
160
- after_create :ensure_default_taxonomies_are_created
161
- after_create :ensure_default_automatic_taxons
162
141
  after_create :create_default_policies
163
142
 
164
143
  #
@@ -233,16 +212,6 @@ module Spree
233
212
  @default_country_for_market = country
234
213
  end
235
214
 
236
- def seo_meta_description
237
- if meta_description.present?
238
- meta_description
239
- elsif seo_title.present?
240
- seo_title
241
- else
242
- name
243
- end
244
- end
245
-
246
215
  def unique_name
247
216
  @unique_name ||= "#{name} (#{code})"
248
217
  end
@@ -312,18 +281,18 @@ module Spree
312
281
  # @return [ActiveRecord::Relation<Spree::Country>]
313
282
  def countries_with_shipping_coverage
314
283
  zone_ids = Spree::Zone
315
- .joins(:shipping_methods)
316
- .select(:id)
284
+ .joins(:shipping_methods)
285
+ .select(:id)
317
286
 
318
287
  country_zone_country_ids = Spree::ZoneMember
319
- .where(zone_id: zone_ids, zoneable_type: 'Spree::Country')
320
- .select(:zoneable_id)
288
+ .where(zone_id: zone_ids, zoneable_type: 'Spree::Country')
289
+ .select(:zoneable_id)
321
290
 
322
291
  state_zone_country_ids = Spree::State
323
- .where(id: Spree::ZoneMember
324
- .where(zone_id: zone_ids, zoneable_type: 'Spree::State')
325
- .select(:zoneable_id))
326
- .select(:country_id)
292
+ .where(id: Spree::ZoneMember
293
+ .where(zone_id: zone_ids, zoneable_type: 'Spree::State')
294
+ .select(:zoneable_id))
295
+ .select(:country_id)
327
296
 
328
297
  Spree::Country
329
298
  .where(id: country_zone_country_ids)
@@ -337,7 +306,8 @@ module Spree
337
306
  @default_stock_location ||= begin
338
307
  stock_location_scope = Spree::StockLocation.where(default: true)
339
308
  stock_location_scope.first || ActiveRecord::Base.connected_to(role: :writing) do
340
- stock_location_scope.create(default: true, name: Spree.t(:default_stock_location_name), country: default_country)
309
+ stock_location_scope.create(default: true, name: Spree.t(:default_stock_location_name),
310
+ country: default_country)
341
311
  end
342
312
  end
343
313
  end
@@ -348,12 +318,6 @@ module Spree
348
318
  users
349
319
  end
350
320
 
351
- def favicon
352
- return unless favicon_image.attached? && favicon_image.variable?
353
-
354
- favicon_image.variant(resize_to_limit: [32, 32])
355
- end
356
-
357
321
  def metric_unit_system?
358
322
  preferred_unit_system == 'metric'
359
323
  end
@@ -366,14 +330,6 @@ module Spree
366
330
  @digital_shipping_category ||= ShippingCategory.find_or_create_by(name: 'Digital')
367
331
  end
368
332
 
369
- %w[customer_terms_of_service customer_privacy_policy customer_returns_policy customer_shipping_policy].each do |policy_method|
370
- define_method policy_method do
371
- Spree::Deprecation.warn("Store##{policy_method} is deprecated and will be removed in Spree 5.5. Please use Store#policies instead.")
372
-
373
- ActionText::RichText.find_by(name: policy_method, record: self)
374
- end
375
- end
376
-
377
333
  private
378
334
 
379
335
  def ensure_default_market
@@ -395,7 +351,25 @@ module Spree
395
351
  end
396
352
  end
397
353
 
354
+ def create_default_policies
355
+ Spree::Events.disable do
356
+ [
357
+ translate_with_store_locale_fallback('spree.terms_of_service'),
358
+ translate_with_store_locale_fallback('spree.privacy_policy'),
359
+ translate_with_store_locale_fallback('spree.returns_policy'),
360
+ translate_with_store_locale_fallback('spree.shipping_policy')
361
+ ].each do |policy_name|
362
+ # Manual exists?/create to work around Mobility bug with find_or_create_by
363
+ next if policies.with_matching_name(policy_name).exists?
364
+
365
+ policies.create(name: policy_name)
366
+ end
367
+ end
368
+ end
369
+
398
370
  def ensure_default_taxonomies_are_created
371
+ Spree::Deprecation.warn('Store#ensure_default_taxonomies_are_created is deprecated and will be removed in Spree 5.5. Please remove it from your codebase')
372
+
399
373
  Spree::Events.disable do
400
374
  [
401
375
  translate_with_store_locale_fallback('spree.taxonomy_categories_name'),
@@ -411,13 +385,16 @@ module Spree
411
385
  end
412
386
 
413
387
  def ensure_default_automatic_taxons
388
+ Spree::Deprecation.warn('Store#ensure_default_automatic_taxons is deprecated and will be removed in Spree 5.5. Please remove it from your codebase')
389
+
414
390
  Spree::Events.disable do
415
391
  # Use Mobility-safe lookup for taxonomy
416
392
  collections_taxonomy = taxonomies.with_matching_name(translate_with_store_locale_fallback('spree.taxonomy_collections_name')).first
417
393
  return unless collections_taxonomy.present?
418
394
 
419
395
  automatic_taxons_config = [
420
- { name: translate_with_store_locale_fallback('spree.automatic_taxon_names.on_sale'), rule_type: 'Spree::TaxonRules::Sale', rule_value: 'true' },
396
+ { name: translate_with_store_locale_fallback('spree.automatic_taxon_names.on_sale'),
397
+ rule_type: 'Spree::TaxonRules::Sale', rule_value: 'true' },
421
398
  { name: translate_with_store_locale_fallback('spree.automatic_taxon_names.new_arrivals'), rule_type: 'Spree::TaxonRules::AvailableOn', rule_value: 30 }
422
399
  ]
423
400
 
@@ -439,22 +416,6 @@ module Spree
439
416
  end
440
417
  end
441
418
 
442
- def create_default_policies
443
- Spree::Events.disable do
444
- [
445
- translate_with_store_locale_fallback('spree.terms_of_service'),
446
- translate_with_store_locale_fallback('spree.privacy_policy'),
447
- translate_with_store_locale_fallback('spree.returns_policy'),
448
- translate_with_store_locale_fallback('spree.shipping_policy')
449
- ].each do |policy_name|
450
- # Manual exists?/create to work around Mobility bug with find_or_create_by
451
- next if policies.with_matching_name(policy_name).exists?
452
-
453
- policies.create(name: policy_name)
454
- end
455
- end
456
- end
457
-
458
419
  # Translates a key using the store's default locale with fallback to :en
459
420
  def translate_with_store_locale_fallback(key)
460
421
  locale = default_locale.presence&.to_sym || :en