spree_core 4.5.3 → 4.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/finders/spree/option_values/find_available.rb +1 -1
- data/app/finders/spree/product_properties/find_available.rb +1 -1
- data/app/finders/spree/products/find.rb +20 -12
- data/app/finders/spree/taxons/find.rb +10 -7
- data/app/helpers/spree/base_helper.rb +2 -2
- data/app/models/concerns/spree/product_scopes.rb +27 -23
- data/app/models/concerns/spree/translatable_resource.rb +25 -0
- data/app/models/concerns/spree/translatable_resource_scopes.rb +24 -0
- data/app/models/concerns/spree/translatable_resource_slug.rb +17 -0
- data/app/models/spree/base.rb +1 -0
- data/app/models/spree/data_feed/google.rb +15 -0
- data/app/models/spree/data_feed.rb +40 -0
- data/app/models/spree/option_type.rb +4 -0
- data/app/models/spree/option_value.rb +4 -0
- data/app/models/spree/product.rb +41 -10
- data/app/models/spree/product_property.rb +12 -3
- data/app/models/spree/property.rb +7 -1
- data/app/models/spree/shipment.rb +2 -2
- data/app/models/spree/store.rb +20 -1
- data/app/models/spree/taxon.rb +22 -6
- data/app/models/spree/taxonomy.rb +4 -0
- data/app/models/spree/variant.rb +4 -7
- data/app/services/spree/data_feeds/google/optional_attributes.rb +23 -0
- data/app/services/spree/data_feeds/google/optional_sub_attributes.rb +21 -0
- data/app/services/spree/data_feeds/google/products_list.rb +14 -0
- data/app/services/spree/data_feeds/google/required_attributes.rb +67 -0
- data/app/services/spree/data_feeds/google/rss.rb +107 -0
- data/app/sorters/spree/products/sort.rb +23 -0
- data/brakeman.ignore +326 -18
- data/config/initializers/friendly_id.rb +2 -0
- data/config/initializers/mobility.rb +18 -0
- data/config/locales/en.yml +1 -0
- data/db/migrate/20220706112554_create_product_name_and_description_translations_for_mobility_table_backend.rb +27 -0
- data/db/migrate/20220715083542_create_spree_product_translations_for_mobility.rb +7 -0
- data/db/migrate/20220715120222_change_product_name_null_to_true.rb +5 -0
- data/db/migrate/20220718100743_create_spree_taxon_name_and_description_translations_for_mobility_table_backend.rb +27 -0
- data/db/migrate/20220718100948_change_taxon_name_null_to_true.rb +5 -0
- data/db/migrate/20220802070609_add_locale_to_friendly_id_slugs.rb +11 -0
- data/db/migrate/20220802073225_create_spree_product_slug_translations_for_mobility_table_backend.rb +5 -0
- data/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb +66 -0
- data/db/migrate/20221215151408_add_selected_locale_to_spree_users.rb +8 -0
- data/db/migrate/20221219123957_add_deleted_at_to_product_translations.rb +6 -0
- data/db/migrate/20221220133432_add_uniqueness_constraint_to_product_translations.rb +5 -0
- data/db/migrate/20221229132350_create_spree_data_feed_settings.rb +14 -0
- data/db/migrate/20230103144439_create_option_type_translations.rb +26 -0
- data/db/migrate/20230103151034_create_option_value_translations.rb +26 -0
- data/db/migrate/20230109084253_create_product_property_translations.rb +25 -0
- data/db/migrate/20230109094907_transfer_options_data_to_translatable_tables.rb +58 -0
- data/db/migrate/20230109105943_create_property_translations.rb +26 -0
- data/db/migrate/20230109110840_transfer_property_data_to_translatable_tables.rb +59 -0
- data/db/migrate/20230110142344_backfill_friendly_id_slug_locale.rb +15 -0
- data/db/migrate/20230111121534_add_additional_taxon_translation_fields.rb +8 -0
- data/db/migrate/20230111122511_transfer_product_and_taxon_data_to_translatable_tables.rb +82 -0
- data/db/migrate/20230117115531_create_taxonomy_translations.rb +24 -0
- data/db/migrate/20230117120430_allow_null_taxonomy_name.rb +5 -0
- data/db/migrate/20230117121303_transfer_taxonomy_data_to_translatable_tables.rb +11 -0
- data/db/migrate/20230210142732_create_store_translations.rb +50 -0
- data/db/migrate/20230210142849_transfer_store_data_to_translatable_tables.rb +11 -0
- data/db/migrate/20230210230434_add_deleted_at_to_store_translations.rb +6 -0
- data/db/migrate/20230415155958_rename_data_feed_settings_table.rb +5 -0
- data/db/migrate/20230415160828_rename_data_feed_table_columns.rb +7 -0
- data/db/migrate/20230415161226_add_indexes_to_data_feeds_table.rb +5 -0
- data/db/migrate/20230512094803_rename_data_feeds_column_provider_to_type.rb +5 -0
- data/db/migrate/20230514162157_add_index_on_locale_and_permalink_to_spree_taxons.rb +5 -0
- data/lib/spree/core/configuration.rb +1 -0
- data/lib/spree/core/controller_helpers/locale.rb +26 -2
- data/lib/spree/core/dependencies.rb +70 -94
- data/lib/spree/core/dependencies_helper.rb +19 -0
- data/lib/spree/core/engine.rb +6 -1
- data/lib/spree/core/product_duplicator.rb +1 -1
- data/lib/spree/core/product_filters.rb +7 -4
- data/lib/spree/core/search/base.rb +1 -1
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +2 -0
- data/lib/spree/permitted_attributes.rb +1 -1
- data/lib/spree/testing_support/factories/google_data_feed_factory.rb +8 -0
- data/lib/spree/testing_support/factories/product_factory.rb +6 -0
- data/lib/spree/testing_support/factories/product_translation_factory.rb +6 -0
- data/lib/spree/testing_support/factories/store_factory.rb +1 -0
- data/lib/spree/testing_support/factories/variant_factory.rb +4 -0
- data/lib/spree/translation_migrations.rb +40 -0
- data/spree_core.gemspec +3 -0
- metadata +92 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 619f5416fb099c1cccaeb2432fd6002b53aa605aff90c9b4078f2a51ba73e89b
|
4
|
+
data.tar.gz: e53a5c780f9c4e79c50cc38d2fdd055dc20b04bef93c89e33e88b7a4fd9facce
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e8cc84789a7c8564b45576c2aa9f8974f62da3b2c752869a9950497b01382b073b50a4d7746d9f2142bee4248115b58a527637b104f3750504499f2a6608459
|
7
|
+
data.tar.gz: fab84d0b2eb02221f96209f11c118feb77928d69269b009abb4c9a773089f1a011a96bbb3b731abce9cd8af45208eaabdef464c27244b7fd954554de1203c15b
|
@@ -146,7 +146,10 @@ module Spree
|
|
146
146
|
def by_name(products)
|
147
147
|
return products unless name?
|
148
148
|
|
149
|
-
|
149
|
+
product_name = name
|
150
|
+
|
151
|
+
# i18n mobility scope doesn't automatically get set for query blocks (Mobility issue #599) - set it explicitly
|
152
|
+
products.i18n { name.matches("%#{product_name}%") }
|
150
153
|
end
|
151
154
|
|
152
155
|
def by_options(products)
|
@@ -183,7 +186,7 @@ module Spree
|
|
183
186
|
|
184
187
|
next if values.empty?
|
185
188
|
|
186
|
-
ids =
|
189
|
+
ids = scope.unscope(:order, :includes).with_property_values(property_filter_param, values).ids
|
187
190
|
product_ids = index == 0 ? ids : product_ids & ids
|
188
191
|
index += 1
|
189
192
|
end
|
@@ -209,21 +212,19 @@ module Spree
|
|
209
212
|
products
|
210
213
|
end
|
211
214
|
when 'name-a-z'
|
212
|
-
|
215
|
+
# workaround for Mobility issue #596 - explicitly select fields to avoid error when selecting distinct
|
216
|
+
products.i18n.
|
217
|
+
select("#{Product.table_name}.*").select(:name).order(name: :asc)
|
213
218
|
when 'name-z-a'
|
214
|
-
|
219
|
+
# workaround for Mobility issue #596
|
220
|
+
products.i18n.
|
221
|
+
select("#{Product.table_name}.*").select(:name).order(name: :desc)
|
215
222
|
when 'newest-first'
|
216
223
|
products.order(available_on: :desc)
|
217
224
|
when 'price-high-to-low'
|
218
|
-
products
|
219
|
-
select("#{Product.table_name}.*, #{Spree::Price.table_name}.amount").
|
220
|
-
reorder('').
|
221
|
-
send(:descend_by_master_price)
|
225
|
+
order_by_price(products, :descend_by_master_price)
|
222
226
|
when 'price-low-to-high'
|
223
|
-
products
|
224
|
-
select("#{Product.table_name}.*, #{Spree::Price.table_name}.amount").
|
225
|
-
reorder('').
|
226
|
-
send(:ascend_by_master_price)
|
227
|
+
order_by_price(products, :ascend_by_master_price)
|
227
228
|
end
|
228
229
|
end
|
229
230
|
|
@@ -265,6 +266,13 @@ module Spree
|
|
265
266
|
taxons = store.taxons.where(id: taxons_ids.to_s.split(','))
|
266
267
|
taxons.map(&:cached_self_and_descendants_ids).flatten.compact.uniq.map(&:to_s)
|
267
268
|
end
|
269
|
+
|
270
|
+
def order_by_price(scope, order_type)
|
271
|
+
scope.
|
272
|
+
select("#{Product.table_name}.*, #{Spree::Price.table_name}.amount").
|
273
|
+
reorder('').
|
274
|
+
send(order_type)
|
275
|
+
end
|
268
276
|
end
|
269
277
|
end
|
270
278
|
end
|
@@ -50,10 +50,6 @@ module Spree
|
|
50
50
|
name.present?
|
51
51
|
end
|
52
52
|
|
53
|
-
def name_matcher
|
54
|
-
Spree::Taxon.arel_table[:name].matches("%#{name}%")
|
55
|
-
end
|
56
|
-
|
57
53
|
def by_ids(taxons)
|
58
54
|
return taxons unless ids?
|
59
55
|
|
@@ -70,9 +66,13 @@ module Spree
|
|
70
66
|
return taxons unless parent_permalink?
|
71
67
|
|
72
68
|
if Rails::VERSION::STRING >= '6.1'
|
73
|
-
taxons.joins(:parent).
|
69
|
+
taxons.joins(:parent).
|
70
|
+
join_translation_table(Taxon, 'parents_spree_taxons').
|
71
|
+
where(["#{Taxon.translation_table_alias}.permalink = ?", parent_permalink])
|
74
72
|
else
|
75
|
-
taxons.joins("INNER JOIN #{Spree::Taxon.table_name} AS parent_taxon ON parent_taxon.id = #{Spree::Taxon.table_name}.parent_id").
|
73
|
+
taxons.joins("INNER JOIN #{Spree::Taxon.table_name} AS parent_taxon ON parent_taxon.id = #{Spree::Taxon.table_name}.parent_id").
|
74
|
+
join_translation_table(Taxon, 'parent_taxon').
|
75
|
+
where(["#{Taxon.translation_table_alias}.permalink = ?", parent_permalink])
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
@@ -91,7 +91,10 @@ module Spree
|
|
91
91
|
def by_name(taxons)
|
92
92
|
return taxons unless name?
|
93
93
|
|
94
|
-
|
94
|
+
taxon_name = name
|
95
|
+
|
96
|
+
# i18n mobility scope doesn't automatically get set for query blocks (Mobility issue #599) - set it explicitly
|
97
|
+
taxons.i18n { name.matches("%#{taxon_name}%") }
|
95
98
|
end
|
96
99
|
end
|
97
100
|
end
|
@@ -113,8 +113,8 @@ module Spree
|
|
113
113
|
meta = {}
|
114
114
|
|
115
115
|
if object.is_a? ApplicationRecord
|
116
|
-
meta[:keywords] = object.meta_keywords if object
|
117
|
-
meta[:description] = object.meta_description if object
|
116
|
+
meta[:keywords] = object.meta_keywords if object.try(:meta_keywords).present?
|
117
|
+
meta[:description] = object.meta_description if object.try(:meta_description).present?
|
118
118
|
end
|
119
119
|
|
120
120
|
if meta[:description].blank? && object.is_a?(Spree::Product)
|
@@ -32,15 +32,16 @@ module Spree
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def self.property_conditions(property)
|
35
|
-
|
35
|
+
properties_table = Property.table_name
|
36
|
+
property_translations_table = Property.translation_table_alias
|
36
37
|
case property
|
37
|
-
when Property then { "#{
|
38
|
-
when Integer then { "#{
|
38
|
+
when Property then { "#{properties_table}.id" => property.id }
|
39
|
+
when Integer then { "#{properties_table}.id" => property }
|
39
40
|
else
|
40
41
|
if Property.column_for_attribute('id').type == :uuid
|
41
|
-
["#{
|
42
|
+
["#{property_translations_table.name} = ? OR #{properties_table.id} = ?", property, property]
|
42
43
|
else
|
43
|
-
{ "#{
|
44
|
+
{ "#{property_translations_table}.name" => property }
|
44
45
|
end
|
45
46
|
end
|
46
47
|
end
|
@@ -126,21 +127,25 @@ module Spree
|
|
126
127
|
|
127
128
|
# a scope that finds all products having property specified by name, object or id
|
128
129
|
add_search_scope :with_property do |property|
|
129
|
-
joins(:properties).where(property_conditions(property))
|
130
|
+
joins(:properties).join_translation_table(Property).where(property_conditions(property))
|
130
131
|
end
|
131
132
|
|
132
133
|
# a simple test for product with a certain property-value pairing
|
133
134
|
# note that it can test for properties with NULL values, but not for absent values
|
134
135
|
add_search_scope :with_property_value do |property, value|
|
135
136
|
joins(:properties).
|
136
|
-
|
137
|
+
join_translation_table(Property).
|
138
|
+
join_translation_table(ProductProperty).
|
139
|
+
where("#{ProductProperty.translation_table_alias}.value = ?", value).
|
137
140
|
where(property_conditions(property))
|
138
141
|
end
|
139
142
|
|
140
143
|
add_search_scope :with_property_values do |property_filter_param, property_values|
|
141
144
|
joins(product_properties: :property).
|
142
|
-
|
143
|
-
|
145
|
+
join_translation_table(Property).
|
146
|
+
join_translation_table(ProductProperty).
|
147
|
+
where(Property.translation_table_alias => { filter_param: property_filter_param }).
|
148
|
+
where(ProductProperty.translation_table_alias => { filter_param: property_values.map(&:parameterize) })
|
144
149
|
end
|
145
150
|
|
146
151
|
add_search_scope :with_option do |option|
|
@@ -151,7 +156,9 @@ module Spree
|
|
151
156
|
elsif OptionType.column_for_attribute('id').type == :uuid
|
152
157
|
joins(:option_types).where(spree_option_types: { name: option }).or(Product.joins(:option_types).where(spree_option_types: { id: option }))
|
153
158
|
else
|
154
|
-
joins(:option_types).
|
159
|
+
joins(:option_types).
|
160
|
+
join_translation_table(OptionType).
|
161
|
+
where(OptionType.translation_table_alias => { name: option })
|
155
162
|
end
|
156
163
|
end
|
157
164
|
|
@@ -164,6 +171,7 @@ module Spree
|
|
164
171
|
OptionType.where(id: option).or(OptionType.where(name: option))&.first&.id
|
165
172
|
else
|
166
173
|
OptionType.where(name: option)&.first&.id
|
174
|
+
OptionType.where(name: option)&.first&.id
|
167
175
|
end
|
168
176
|
end
|
169
177
|
|
@@ -171,7 +179,9 @@ module Spree
|
|
171
179
|
|
172
180
|
group("#{Spree::Product.table_name}.id").
|
173
181
|
joins(variants_including_master: :option_values).
|
174
|
-
|
182
|
+
join_translation_table(Spree::OptionValue).
|
183
|
+
where(Spree::OptionValue.translation_table_alias => { name: value },
|
184
|
+
Spree::OptionValue.table_name => { option_type_id: option_type_id })
|
175
185
|
end
|
176
186
|
|
177
187
|
# Finds all products which have either:
|
@@ -295,19 +305,10 @@ module Spree
|
|
295
305
|
# .search_by_name
|
296
306
|
if defined?(PgSearch)
|
297
307
|
include PgSearch::Model
|
298
|
-
|
299
|
-
if defined?(SpreeGlobalize)
|
300
|
-
pg_search_scope :search_by_name, associated_against: { translations: :name }, using: { tsearch: { any_word: true, prefix: true } }
|
301
|
-
else
|
302
|
-
pg_search_scope :search_by_name, against: :name, using: { tsearch: { any_word: true, prefix: true } }
|
303
|
-
end
|
308
|
+
pg_search_scope :search_by_name, against: :name, using: { tsearch: { any_word: true, prefix: true } }
|
304
309
|
else
|
305
310
|
def self.search_by_name(query)
|
306
|
-
|
307
|
-
joins(:translations).order(:name).where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%").distinct
|
308
|
-
else
|
309
|
-
where("LOWER(#{Product.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%")
|
310
|
-
end
|
311
|
+
i18n { name.lower.matches("%#{query.downcase}%") }
|
311
312
|
end
|
312
313
|
end
|
313
314
|
search_scopes << :search_by_name
|
@@ -339,7 +340,10 @@ module Spree
|
|
339
340
|
case t
|
340
341
|
when ApplicationRecord then t
|
341
342
|
else
|
342
|
-
Taxon.where(
|
343
|
+
Taxon.where(name: t).
|
344
|
+
or(Taxon.where(Taxon.arel_table[:id].eq(t))).
|
345
|
+
or(Taxon.where(Taxon.arel_table[:permalink].matches("%/#{t}/"))).
|
346
|
+
or(Taxon.where(Taxon.arel_table[:permalink].matches("#{t}/"))).first
|
343
347
|
end
|
344
348
|
end.compact.flatten.uniq
|
345
349
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Spree
|
2
|
+
module TranslatableResource
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
extend Mobility
|
7
|
+
default_scope { i18n }
|
8
|
+
|
9
|
+
def get_field_with_locale(locale, field_name, fallback: false)
|
10
|
+
# method will return nil if no translation is present due to fallback: false setting
|
11
|
+
public_send(field_name, locale: locale, fallback: fallback)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class_methods do
|
16
|
+
def translatable_fields
|
17
|
+
const_get(:TRANSLATABLE_FIELDS)
|
18
|
+
end
|
19
|
+
|
20
|
+
def translation_table_alias
|
21
|
+
"#{self::Translation.table_name}_#{Mobility.locale}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Spree
|
2
|
+
module TranslatableResourceScopes
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class_methods do
|
6
|
+
# To be used when joining on the resource itself does not automatically join on its translations table
|
7
|
+
# This method is to be used when you've already joined on the translatable table itself
|
8
|
+
#
|
9
|
+
# If the resource table is aliased, pass the alias to `join_on_table_alias`, otherwise omit the param
|
10
|
+
def join_translation_table(translatable_class, join_on_table_alias = nil)
|
11
|
+
join_on_table_name = if join_on_table_alias.nil?
|
12
|
+
translatable_class.table_name
|
13
|
+
else
|
14
|
+
join_on_table_alias
|
15
|
+
end
|
16
|
+
translatable_class_foreign_key = "#{translatable_class.table_name.singularize}_id"
|
17
|
+
|
18
|
+
joins("LEFT OUTER JOIN #{translatable_class::Translation.table_name} #{translatable_class.translation_table_alias}
|
19
|
+
ON #{translatable_class.translation_table_alias}.#{translatable_class_foreign_key} = #{join_on_table_name}.id
|
20
|
+
AND #{translatable_class.translation_table_alias}.locale = '#{Mobility.locale}'")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Spree
|
2
|
+
module TranslatableResourceSlug
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
def localized_slugs_for_store(store)
|
7
|
+
localized_slugs = Hash[translations.pluck(:locale, :slug)]
|
8
|
+
default_locale = store.default_locale
|
9
|
+
supported_locales = store.supported_locales_list
|
10
|
+
|
11
|
+
supported_locales.each_with_object({}) do |locale, hash|
|
12
|
+
hash[locale] = localized_slugs[locale] || localized_slugs[default_locale]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/app/models/spree/base.rb
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Spree
|
2
|
+
class DataFeed < Base
|
3
|
+
belongs_to :store, class_name: 'Spree::Store', foreign_key: 'store_id'
|
4
|
+
|
5
|
+
scope :for_store, ->(store) { where(store: store) }
|
6
|
+
|
7
|
+
before_validation :generate_slug
|
8
|
+
|
9
|
+
with_options presence: true do
|
10
|
+
validates :store
|
11
|
+
validates :name, uniqueness: true
|
12
|
+
validates :slug, uniqueness: { scope: :store_id }
|
13
|
+
end
|
14
|
+
|
15
|
+
def formatted_url
|
16
|
+
"#{store.formatted_url}/api/v2/data_feeds/#{self.class.provider_name}/#{slug}.rss"
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def generate_slug
|
22
|
+
new_slug = slug.blank? ? SecureRandom.uuid : slug.parameterize
|
23
|
+
write_attribute(:slug, new_slug)
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def label
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
30
|
+
|
31
|
+
def provider_name
|
32
|
+
raise NotImplementedError
|
33
|
+
end
|
34
|
+
|
35
|
+
def available_types
|
36
|
+
Rails.application.config.spree.data_feed_types
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -2,10 +2,14 @@ module Spree
|
|
2
2
|
class OptionType < Spree::Base
|
3
3
|
include UniqueName
|
4
4
|
include Metadata
|
5
|
+
include TranslatableResource
|
5
6
|
if defined?(Spree::Webhooks)
|
6
7
|
include Spree::Webhooks::HasWebhooks
|
7
8
|
end
|
8
9
|
|
10
|
+
TRANSLATABLE_FIELDS = %i[name presentation].freeze
|
11
|
+
translates(*TRANSLATABLE_FIELDS)
|
12
|
+
|
9
13
|
acts_as_list
|
10
14
|
auto_strip_attributes :name, :presentation
|
11
15
|
|
@@ -1,10 +1,14 @@
|
|
1
1
|
module Spree
|
2
2
|
class OptionValue < Spree::Base
|
3
3
|
include Metadata
|
4
|
+
include TranslatableResource
|
4
5
|
if defined?(Spree::Webhooks)
|
5
6
|
include Spree::Webhooks::HasWebhooks
|
6
7
|
end
|
7
8
|
|
9
|
+
TRANSLATABLE_FIELDS = %i[name presentation].freeze
|
10
|
+
translates(*TRANSLATABLE_FIELDS)
|
11
|
+
|
8
12
|
belongs_to :option_type, class_name: 'Spree::OptionType', touch: true, inverse_of: :option_values
|
9
13
|
|
10
14
|
acts_as_list scope: :option_type
|
data/app/models/spree/product.rb
CHANGED
@@ -23,6 +23,8 @@ module Spree
|
|
23
23
|
extend FriendlyId
|
24
24
|
include ProductScopes
|
25
25
|
include MultiStoreResource
|
26
|
+
include TranslatableResource
|
27
|
+
include TranslatableResourceSlug
|
26
28
|
include MemoizedData
|
27
29
|
include Metadata
|
28
30
|
if defined?(Spree::Webhooks)
|
@@ -32,12 +34,20 @@ module Spree
|
|
32
34
|
include Spree::VendorConcern
|
33
35
|
end
|
34
36
|
|
35
|
-
MEMOIZED_METHODS = %w
|
37
|
+
MEMOIZED_METHODS = %w[total_on_hand taxonomy_ids taxon_and_ancestors category
|
36
38
|
default_variant_id tax_category default_variant
|
37
|
-
purchasable? in_stock? backorderable?
|
39
|
+
purchasable? in_stock? backorderable?]
|
38
40
|
|
39
|
-
|
41
|
+
TRANSLATABLE_FIELDS = %i[name description slug meta_description meta_keywords meta_title].freeze
|
42
|
+
translates(*TRANSLATABLE_FIELDS)
|
40
43
|
|
44
|
+
self::Translation.class_eval do
|
45
|
+
acts_as_paranoid
|
46
|
+
# deleted translation values also need to be accessible for index views listing deleted resources
|
47
|
+
default_scope { unscope(where: :deleted_at) }
|
48
|
+
end
|
49
|
+
|
50
|
+
friendly_id :slug_candidates, use: [:history, :mobility]
|
41
51
|
acts_as_paranoid
|
42
52
|
auto_strip_attributes :name
|
43
53
|
|
@@ -306,14 +316,26 @@ module Spree
|
|
306
316
|
end
|
307
317
|
|
308
318
|
def property(property_name)
|
309
|
-
product_properties.joins(:property).
|
319
|
+
product_properties.joins(:property).
|
320
|
+
join_translation_table(Property).
|
321
|
+
find_by(Property.translation_table_alias => { name: property_name }).try(:value)
|
310
322
|
end
|
311
323
|
|
312
324
|
def set_property(property_name, property_value, property_presentation = property_name)
|
313
325
|
ApplicationRecord.transaction do
|
314
|
-
#
|
315
|
-
property = Property.
|
316
|
-
|
326
|
+
# Manual first_or_create to work around Mobility bug
|
327
|
+
property = if Property.where(name: property_name).exists?
|
328
|
+
Property.where(name: property_name).first
|
329
|
+
else
|
330
|
+
Property.create(name: property_name, presentation: property_presentation)
|
331
|
+
end
|
332
|
+
|
333
|
+
product_property = if ProductProperty.where(product: self, property: property).exists?
|
334
|
+
ProductProperty.where(product: self, property: property).first
|
335
|
+
else
|
336
|
+
ProductProperty.create(product: self, property: property)
|
337
|
+
end
|
338
|
+
|
317
339
|
product_property.value = property_value
|
318
340
|
product_property.save!
|
319
341
|
end
|
@@ -337,11 +359,16 @@ module Spree
|
|
337
359
|
end
|
338
360
|
|
339
361
|
def brand
|
340
|
-
@brand ||= taxons.joins(:taxonomy).
|
362
|
+
@brand ||= taxons.joins(:taxonomy).
|
363
|
+
join_translation_table(Taxonomy).
|
364
|
+
find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_brands_name) })
|
341
365
|
end
|
342
366
|
|
343
367
|
def category
|
344
|
-
@category ||= taxons.joins(:taxonomy).
|
368
|
+
@category ||= taxons.joins(:taxonomy).
|
369
|
+
join_translation_table(Taxonomy).
|
370
|
+
order(depth: :desc).
|
371
|
+
find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_categories_name) })
|
345
372
|
end
|
346
373
|
|
347
374
|
def taxons_for_store(store)
|
@@ -415,7 +442,11 @@ module Spree
|
|
415
442
|
|
416
443
|
def punch_slug
|
417
444
|
# punch slug with date prefix to allow reuse of original
|
418
|
-
|
445
|
+
return if frozen?
|
446
|
+
|
447
|
+
translations.with_deleted.each do |t|
|
448
|
+
t.update_column :slug, "#{Time.current.to_i}_#{t.slug}"[0..254]
|
449
|
+
end
|
419
450
|
end
|
420
451
|
|
421
452
|
def update_slug_history
|
@@ -1,8 +1,14 @@
|
|
1
1
|
module Spree
|
2
2
|
class ProductProperty < Spree::Base
|
3
3
|
include Spree::FilterParam
|
4
|
+
include TranslatableResource
|
4
5
|
|
5
|
-
|
6
|
+
TRANSLATABLE_FIELDS = %i[value filter_param].freeze
|
7
|
+
translates(*TRANSLATABLE_FIELDS)
|
8
|
+
|
9
|
+
self::Translation.class_eval do
|
10
|
+
auto_strip_attributes :value
|
11
|
+
end
|
6
12
|
|
7
13
|
acts_as_list scope: :product
|
8
14
|
|
@@ -31,8 +37,11 @@ module Spree
|
|
31
37
|
`ProductProperty#property_name=` is deprecated and will be removed in Spree 5.0.
|
32
38
|
DEPRECATION
|
33
39
|
if name.present?
|
34
|
-
|
35
|
-
|
40
|
+
self.property = if Property.where(name: name).exists?
|
41
|
+
Property.where(name: name).first
|
42
|
+
else
|
43
|
+
Property.create(name: name, presentation: name)
|
44
|
+
end
|
36
45
|
end
|
37
46
|
end
|
38
47
|
|
@@ -2,11 +2,17 @@ module Spree
|
|
2
2
|
class Property < Spree::Base
|
3
3
|
include Spree::FilterParam
|
4
4
|
include Metadata
|
5
|
+
include TranslatableResource
|
5
6
|
if defined?(Spree::Webhooks)
|
6
7
|
include Spree::Webhooks::HasWebhooks
|
7
8
|
end
|
8
9
|
|
9
|
-
|
10
|
+
TRANSLATABLE_FIELDS = %i[name presentation filter_param].freeze
|
11
|
+
translates(*TRANSLATABLE_FIELDS)
|
12
|
+
|
13
|
+
self::Translation.class_eval do
|
14
|
+
auto_strip_attributes :name, :presentation
|
15
|
+
end
|
10
16
|
|
11
17
|
has_many :property_prototypes, class_name: 'Spree::PropertyPrototype'
|
12
18
|
has_many :prototypes, through: :property_prototypes, class_name: 'Spree::Prototype'
|
@@ -249,8 +249,8 @@ module Spree
|
|
249
249
|
end
|
250
250
|
|
251
251
|
def selected_shipping_rate_id=(id)
|
252
|
-
|
253
|
-
shipping_rates.
|
252
|
+
# Explicitly updates the timestamp in order to bust cache dependent on "updated_at"
|
253
|
+
shipping_rates.update_all(selected: false, updated_at: Time.current)
|
254
254
|
shipping_rates.update(id, selected: true)
|
255
255
|
save!
|
256
256
|
end
|
data/app/models/spree/store.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module Spree
|
2
2
|
class Store < Spree::Base
|
3
|
+
include TranslatableResource
|
3
4
|
if defined?(Spree::Webhooks)
|
4
5
|
include Spree::Webhooks::HasWebhooks
|
5
6
|
end
|
@@ -7,6 +8,17 @@ module Spree
|
|
7
8
|
include Spree::Security::Stores
|
8
9
|
end
|
9
10
|
|
11
|
+
TRANSLATABLE_FIELDS = %i[name meta_description meta_keywords seo_title facebook
|
12
|
+
twitter instagram customer_support_email description
|
13
|
+
address contact_phone new_order_notifications_email].freeze
|
14
|
+
translates(*TRANSLATABLE_FIELDS)
|
15
|
+
|
16
|
+
self::Translation.class_eval do
|
17
|
+
acts_as_paranoid
|
18
|
+
# deleted translation values still need to be accessible - remove deleted_at scope
|
19
|
+
default_scope { unscope(where: :deleted_at) }
|
20
|
+
end
|
21
|
+
|
10
22
|
typed_store :settings, coder: ActiveRecord::TypedStore::IdentityCoder do |s|
|
11
23
|
# Spree Digital Asset Configurations
|
12
24
|
s.boolean :limit_digital_download_count, default: true, null: false
|
@@ -55,6 +67,8 @@ module Spree
|
|
55
67
|
|
56
68
|
has_many :wishlists, class_name: 'Spree::Wishlist'
|
57
69
|
|
70
|
+
has_many :data_feeds, class_name: 'Spree::DataFeed'
|
71
|
+
|
58
72
|
belongs_to :default_country, class_name: 'Spree::Country'
|
59
73
|
belongs_to :checkout_zone, class_name: 'Spree::Zone'
|
60
74
|
|
@@ -109,7 +123,12 @@ module Spree
|
|
109
123
|
# this behaviour is very buggy and unpredictable
|
110
124
|
def self.default
|
111
125
|
Rails.cache.fetch('default_store') do
|
112
|
-
|
126
|
+
# workaround for Mobility bug with first_or_initialize
|
127
|
+
if where(default: true).any?
|
128
|
+
where(default: true).first
|
129
|
+
else
|
130
|
+
new(default: true)
|
131
|
+
end
|
113
132
|
end
|
114
133
|
end
|
115
134
|
|