spree_core 4.4.0 → 4.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (212) hide show
  1. checksums.yaml +4 -4
  2. data/app/finders/spree/option_values/find_available.rb +1 -1
  3. data/app/finders/spree/product_properties/find_available.rb +1 -1
  4. data/app/finders/spree/products/find.rb +21 -15
  5. data/app/finders/spree/taxons/find.rb +11 -8
  6. data/app/helpers/spree/base_helper.rb +14 -11
  7. data/app/helpers/spree/locale_helper.rb +6 -2
  8. data/app/helpers/spree/products_helper.rb +9 -4
  9. data/app/jobs/spree/variants/remove_from_incomplete_orders_job.rb +9 -0
  10. data/app/jobs/spree/variants/remove_line_item_job.rb +9 -0
  11. data/app/models/concerns/spree/calculated_adjustments.rb +1 -1
  12. data/app/models/concerns/spree/display_link.rb +17 -29
  13. data/app/models/concerns/spree/image_methods.rb +21 -9
  14. data/app/models/concerns/spree/metadata.rb +2 -2
  15. data/app/models/concerns/spree/product_scopes.rb +34 -28
  16. data/app/models/concerns/spree/translatable_resource.rb +25 -0
  17. data/app/models/concerns/spree/translatable_resource_scopes.rb +24 -0
  18. data/app/models/concerns/spree/translatable_resource_slug.rb +17 -0
  19. data/app/models/spree/address.rb +7 -1
  20. data/app/models/spree/asset/support/active_storage.rb +3 -2
  21. data/app/models/spree/asset.rb +3 -0
  22. data/app/models/spree/base.rb +1 -0
  23. data/app/models/spree/cms_page.rb +4 -0
  24. data/app/models/spree/cms_section.rb +12 -12
  25. data/app/models/spree/cms_section_image.rb +15 -0
  26. data/app/models/spree/cms_section_image_one.rb +4 -0
  27. data/app/models/spree/cms_section_image_three.rb +4 -0
  28. data/app/models/spree/cms_section_image_two.rb +4 -0
  29. data/app/models/spree/credit_card.rb +10 -4
  30. data/app/models/spree/customer_return.rb +3 -0
  31. data/app/models/spree/data_feed/google.rb +15 -0
  32. data/app/models/spree/data_feed.rb +40 -0
  33. data/app/models/spree/digital.rb +4 -0
  34. data/app/models/spree/digital_link.rb +7 -0
  35. data/app/models/spree/fulfilment_changer.rb +1 -1
  36. data/app/models/spree/gateway/bogus.rb +1 -1
  37. data/app/models/spree/icon.rb +5 -1
  38. data/app/models/spree/image/configuration/active_storage.rb +5 -1
  39. data/app/models/spree/image.rb +3 -3
  40. data/app/models/spree/inventory_unit.rb +5 -2
  41. data/app/models/spree/legacy_user.rb +1 -2
  42. data/app/models/spree/line_item.rb +4 -1
  43. data/app/models/spree/linkable/homepage.rb +3 -0
  44. data/app/models/spree/linkable/uri.rb +3 -0
  45. data/app/models/spree/log_entry.rb +9 -1
  46. data/app/models/spree/menu.rb +3 -0
  47. data/app/models/spree/menu_item.rb +7 -11
  48. data/app/models/spree/option_type.rb +8 -0
  49. data/app/models/spree/option_value.rb +9 -0
  50. data/app/models/spree/order/address_book.rb +1 -0
  51. data/app/models/spree/order.rb +12 -3
  52. data/app/models/spree/order_merger.rb +1 -1
  53. data/app/models/spree/payment/processing.rb +1 -1
  54. data/app/models/spree/payment.rb +7 -1
  55. data/app/models/spree/payment_capture_event.rb +4 -0
  56. data/app/models/spree/payment_method/store_credit.rb +1 -1
  57. data/app/models/spree/payment_method.rb +3 -0
  58. data/app/models/spree/payment_source.rb +10 -0
  59. data/app/models/spree/preference.rb +4 -0
  60. data/app/models/spree/price.rb +3 -0
  61. data/app/models/spree/product.rb +97 -24
  62. data/app/models/spree/product_property.rb +13 -3
  63. data/app/models/spree/promotion/rules/option_value.rb +2 -2
  64. data/app/models/spree/promotion.rb +6 -0
  65. data/app/models/spree/promotion_rule.rb +1 -1
  66. data/app/models/spree/promotion_rule_user.rb +1 -1
  67. data/app/models/spree/property.rb +10 -1
  68. data/app/models/spree/prototype.rb +3 -0
  69. data/app/models/spree/refund.rb +8 -0
  70. data/app/models/spree/reimbursement.rb +3 -0
  71. data/app/models/spree/return_authorization.rb +3 -0
  72. data/app/models/spree/return_item.rb +4 -0
  73. data/app/models/spree/role.rb +1 -1
  74. data/app/models/spree/role_user.rb +1 -1
  75. data/app/models/spree/shipment.rb +8 -1
  76. data/app/models/spree/shipping_category.rb +3 -0
  77. data/app/models/spree/shipping_method.rb +6 -0
  78. data/app/models/spree/state_change.rb +1 -1
  79. data/app/models/spree/stock/availability_validator.rb +9 -3
  80. data/app/models/spree/stock/content_item.rb +1 -1
  81. data/app/models/spree/stock/quantifier.rb +1 -1
  82. data/app/models/spree/stock_item.rb +5 -0
  83. data/app/models/spree/stock_location.rb +19 -5
  84. data/app/models/spree/stock_movement.rb +4 -0
  85. data/app/models/spree/stock_transfer.rb +3 -0
  86. data/app/models/spree/store.rb +39 -15
  87. data/app/models/spree/store_credit.rb +4 -1
  88. data/app/models/spree/store_favicon_image.rb +17 -0
  89. data/app/models/spree/store_logo.rb +9 -0
  90. data/app/models/spree/store_mailer_logo.rb +13 -0
  91. data/app/models/spree/tax_category.rb +6 -0
  92. data/app/models/spree/tax_rate.rb +6 -1
  93. data/app/models/spree/taxon.rb +26 -7
  94. data/app/models/spree/taxon_image/configuration/active_storage.rb +5 -1
  95. data/app/models/spree/taxon_image.rb +3 -2
  96. data/app/models/spree/taxonomy.rb +8 -1
  97. data/app/models/spree/variant.rb +47 -21
  98. data/app/models/spree/wished_item.rb +4 -0
  99. data/app/models/spree/wishlist.rb +4 -1
  100. data/app/models/spree/zone.rb +3 -0
  101. data/app/services/spree/addresses/create.rb +1 -1
  102. data/app/services/spree/addresses/update.rb +7 -2
  103. data/app/services/spree/cart/remove_line_item.rb +1 -0
  104. data/app/services/spree/data_feeds/google/optional_attributes.rb +23 -0
  105. data/app/services/spree/data_feeds/google/optional_sub_attributes.rb +21 -0
  106. data/app/services/spree/data_feeds/google/products_list.rb +14 -0
  107. data/app/services/spree/data_feeds/google/required_attributes.rb +67 -0
  108. data/app/services/spree/data_feeds/google/rss.rb +107 -0
  109. data/app/services/spree/variants/remove_line_items.rb +15 -0
  110. data/app/sorters/spree/products/sort.rb +23 -0
  111. data/brakeman.ignore +326 -18
  112. data/config/initializers/friendly_id.rb +2 -0
  113. data/config/initializers/mobility.rb +18 -0
  114. data/config/locales/en.yml +6 -2
  115. data/config/routes.rb +43 -0
  116. data/db/migrate/20211201202851_update_linkable_resource_types.rb +10 -0
  117. data/db/migrate/20211203082008_add_settings_to_payment_methods.rb +11 -0
  118. data/db/migrate/20211229162122_disable_propagate_all_variants_by_default.rb +5 -0
  119. data/db/migrate/20220103082046_add_status_and_make_active_at_to_spree_products.rb +7 -0
  120. data/db/migrate/20220106230929_add_internal_note_to_spree_orders.rb +5 -0
  121. data/db/migrate/20220113052823_create_payment_sources.rb +22 -0
  122. data/db/migrate/20220117100333_add_make_active_at_to_spree_products.rb +17 -0
  123. data/db/migrate/20220120092821_add_metadata_to_spree_tax_rates.rb +13 -0
  124. data/db/migrate/20220201103922_add_first_name_and_last_name_to_spree_users.rb +9 -0
  125. data/db/migrate/20220222083546_add_barcode_to_spree_variants.rb +6 -0
  126. data/db/migrate/20220329113557_fix_cms_pages_unique_indexes.rb +8 -0
  127. data/db/migrate/20220613133029_add_metadata_to_spree_stock_items.rb +13 -0
  128. data/db/migrate/20220706112554_create_product_name_and_description_translations_for_mobility_table_backend.rb +27 -0
  129. data/db/migrate/20220715083542_create_spree_product_translations_for_mobility.rb +7 -0
  130. data/db/migrate/20220715120222_change_product_name_null_to_true.rb +5 -0
  131. data/db/migrate/20220718100743_create_spree_taxon_name_and_description_translations_for_mobility_table_backend.rb +27 -0
  132. data/db/migrate/20220718100948_change_taxon_name_null_to_true.rb +5 -0
  133. data/db/migrate/20220802070609_add_locale_to_friendly_id_slugs.rb +11 -0
  134. data/db/migrate/20220802073225_create_spree_product_slug_translations_for_mobility_table_backend.rb +5 -0
  135. data/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb +66 -0
  136. data/db/migrate/20221215151408_add_selected_locale_to_spree_users.rb +8 -0
  137. data/db/migrate/20221219123957_add_deleted_at_to_product_translations.rb +6 -0
  138. data/db/migrate/20221220133432_add_uniqueness_constraint_to_product_translations.rb +5 -0
  139. data/db/migrate/20221229132350_create_spree_data_feed_settings.rb +14 -0
  140. data/db/migrate/20230103144439_create_option_type_translations.rb +26 -0
  141. data/db/migrate/20230103151034_create_option_value_translations.rb +26 -0
  142. data/db/migrate/20230109084253_create_product_property_translations.rb +25 -0
  143. data/db/migrate/20230109094907_transfer_options_data_to_translatable_tables.rb +58 -0
  144. data/db/migrate/20230109105943_create_property_translations.rb +26 -0
  145. data/db/migrate/20230109110840_transfer_property_data_to_translatable_tables.rb +59 -0
  146. data/db/migrate/20230110142344_backfill_friendly_id_slug_locale.rb +15 -0
  147. data/db/migrate/20230111121534_add_additional_taxon_translation_fields.rb +8 -0
  148. data/db/migrate/20230111122511_transfer_product_and_taxon_data_to_translatable_tables.rb +82 -0
  149. data/db/migrate/20230117115531_create_taxonomy_translations.rb +24 -0
  150. data/db/migrate/20230117120430_allow_null_taxonomy_name.rb +5 -0
  151. data/db/migrate/20230117121303_transfer_taxonomy_data_to_translatable_tables.rb +11 -0
  152. data/db/migrate/20230210142732_create_store_translations.rb +50 -0
  153. data/db/migrate/20230210142849_transfer_store_data_to_translatable_tables.rb +11 -0
  154. data/db/migrate/20230210230434_add_deleted_at_to_store_translations.rb +6 -0
  155. data/db/migrate/20230415155958_rename_data_feed_settings_table.rb +5 -0
  156. data/db/migrate/20230415160828_rename_data_feed_table_columns.rb +7 -0
  157. data/db/migrate/20230415161226_add_indexes_to_data_feeds_table.rb +5 -0
  158. data/db/migrate/20230512094803_rename_data_feeds_column_provider_to_type.rb +5 -0
  159. data/db/migrate/20230514162157_add_index_on_locale_and_permalink_to_spree_taxons.rb +5 -0
  160. data/lib/friendly_id/paranoia.rb +4 -0
  161. data/lib/generators/spree/dummy/dummy_generator.rb +13 -2
  162. data/lib/generators/spree/dummy/templates/package.json +12 -0
  163. data/lib/generators/spree/dummy/templates/rails/test.rb +2 -0
  164. data/lib/spree/core/configuration.rb +91 -0
  165. data/lib/spree/core/controller_helpers/auth.rb +3 -1
  166. data/lib/spree/core/controller_helpers/currency.rb +7 -5
  167. data/lib/spree/core/controller_helpers/locale.rb +34 -8
  168. data/lib/spree/core/controller_helpers/order.rb +4 -2
  169. data/lib/spree/core/controller_helpers/search.rb +1 -1
  170. data/lib/spree/core/controller_helpers/store.rb +5 -3
  171. data/lib/spree/core/dependencies.rb +106 -0
  172. data/lib/spree/core/dependencies_helper.rb +19 -0
  173. data/lib/spree/core/engine.rb +53 -38
  174. data/{app/models/spree → lib/spree/core}/preferences/configuration.rb +3 -0
  175. data/{app/models/spree → lib/spree/core}/preferences/preferable.rb +3 -0
  176. data/lib/spree/core/product_duplicator.rb +1 -1
  177. data/lib/spree/core/product_filters.rb +7 -4
  178. data/lib/spree/core/search/base.rb +10 -6
  179. data/lib/spree/core/version.rb +1 -1
  180. data/lib/spree/core.rb +27 -5
  181. data/lib/spree/permitted_attributes.rb +9 -7
  182. data/lib/spree/testing_support/common_rake.rb +1 -0
  183. data/lib/spree/testing_support/factories/favicon_image_factory.rb +9 -0
  184. data/lib/spree/testing_support/factories/google_data_feed_factory.rb +8 -0
  185. data/lib/spree/testing_support/factories/icon_factory.rb +3 -1
  186. data/lib/spree/testing_support/factories/image_factory.rb +3 -1
  187. data/lib/spree/testing_support/factories/menu_item_factory.rb +1 -1
  188. data/lib/spree/testing_support/factories/order_factory.rb +2 -1
  189. data/lib/spree/testing_support/factories/product_factory.rb +12 -1
  190. data/lib/spree/testing_support/factories/product_property_factory.rb +1 -0
  191. data/lib/spree/testing_support/factories/product_translation_factory.rb +6 -0
  192. data/lib/spree/testing_support/factories/refund_factory.rb +1 -1
  193. data/lib/spree/testing_support/factories/return_authorization_factory.rb +1 -1
  194. data/lib/spree/testing_support/factories/role_factory.rb +1 -1
  195. data/lib/spree/testing_support/factories/shipping_category_factory.rb +1 -1
  196. data/lib/spree/testing_support/factories/stock_location_factory.rb +3 -2
  197. data/lib/spree/testing_support/factories/store_factory.rb +2 -1
  198. data/lib/spree/testing_support/factories/taxon_image_factory.rb +3 -1
  199. data/lib/spree/testing_support/factories/user_factory.rb +4 -0
  200. data/lib/spree/testing_support/factories/variant_factory.rb +8 -0
  201. data/lib/spree/translation_migrations.rb +40 -0
  202. data/lib/spree_core.rb +2 -1
  203. data/lib/tasks/core.rake +12 -0
  204. data/spree_core.gemspec +5 -3
  205. metadata +152 -52
  206. data/app/models/friendly_id/slug_decorator.rb +0 -9
  207. data/app/models/spree/app_configuration.rb +0 -86
  208. data/lib/friendly_id/slug_rails5_patch.rb +0 -11
  209. data/lib/spree/core/app_dependencies.rb +0 -126
  210. /data/{app/models/spree → lib/spree/core}/preferences/preferable_class_methods.rb +0 -0
  211. /data/{app/models/spree → lib/spree/core}/preferences/scoped_store.rb +0 -0
  212. /data/{app/models/spree → lib/spree/core}/preferences/store.rb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a07abab7dbe8d8b60a019e561b5668c3f336a7eb6970336b6a94b47046837fc1
4
- data.tar.gz: 212b678f9f9df3a4de9de428bd9291fc87cd1f7020ed0c7f50b97c81fbd68a08
3
+ metadata.gz: 619f5416fb099c1cccaeb2432fd6002b53aa605aff90c9b4078f2a51ba73e89b
4
+ data.tar.gz: e53a5c780f9c4e79c50cc38d2fdd055dc20b04bef93c89e33e88b7a4fd9facce
5
5
  SHA512:
6
- metadata.gz: 81e442e30106ce5756519d41717004ebcff0e6219f0e6fcfb563b3133b5635e5bde772ea3939edffac037f55f2eda42ca8ee69da69feb6f44f79d96f60fc4392
7
- data.tar.gz: 02dd0236576e01b96c237d1989fee5a4ef669f4f4e39764b0a2ebbae26ad3847aca21915e0c6196a60088aa5f76bb817d6b478f9b04459d873f8508c00814b66
6
+ metadata.gz: 7e8cc84789a7c8564b45576c2aa9f8974f62da3b2c752869a9950497b01382b073b50a4d7746d9f2142bee4248115b58a527637b104f3750504499f2a6608459
7
+ data.tar.gz: fab84d0b2eb02221f96209f11c118feb77928d69269b009abb4c9a773089f1a011a96bbb3b731abce9cd8af45208eaabdef464c27244b7fd954554de1203c15b
@@ -9,7 +9,7 @@ module Spree
9
9
  end
10
10
 
11
11
  def execute
12
- find_available(scope, products_scope).select(select_args).order(order_args)
12
+ find_available(scope, products_scope).includes(:translations).select(select_args).order(order_args)
13
13
  end
14
14
 
15
15
  private
@@ -9,7 +9,7 @@ module Spree
9
9
  end
10
10
 
11
11
  def execute
12
- find_available(scope, products_scope)
12
+ find_available(scope, products_scope).includes(:translations)
13
13
  end
14
14
 
15
15
  private
@@ -4,8 +4,6 @@ module Spree
4
4
  def initialize(scope:, params:, current_currency: nil)
5
5
  @scope = scope
6
6
 
7
- ActiveSupport::Deprecation.warn('`current_currency` param is deprecated and will be removed in Spree 5') if current_currency
8
-
9
7
  if current_currency.present?
10
8
  ActiveSupport::Deprecation.warn(<<-DEPRECATION, caller)
11
9
  `current_currency` param is deprecated and will be removed in Spree 5.
@@ -148,7 +146,10 @@ module Spree
148
146
  def by_name(products)
149
147
  return products unless name?
150
148
 
151
- products.like_any([:name], [name])
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}%") }
152
153
  end
153
154
 
154
155
  def by_options(products)
@@ -185,7 +186,7 @@ module Spree
185
186
 
186
187
  next if values.empty?
187
188
 
188
- ids = products.with_property_values(property_filter_param, values).ids
189
+ ids = scope.unscope(:order, :includes).with_property_values(property_filter_param, values).ids
189
190
  product_ids = index == 0 ? ids : product_ids & ids
190
191
  index += 1
191
192
  end
@@ -211,21 +212,19 @@ module Spree
211
212
  products
212
213
  end
213
214
  when 'name-a-z'
214
- products.order(name: :asc)
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)
215
218
  when 'name-z-a'
216
- products.order(name: :desc)
219
+ # workaround for Mobility issue #596
220
+ products.i18n.
221
+ select("#{Product.table_name}.*").select(:name).order(name: :desc)
217
222
  when 'newest-first'
218
223
  products.order(available_on: :desc)
219
224
  when 'price-high-to-low'
220
- products.
221
- select("#{Product.table_name}.*, #{Spree::Price.table_name}.amount").
222
- reorder('').
223
- send(:descend_by_master_price)
225
+ order_by_price(products, :descend_by_master_price)
224
226
  when 'price-low-to-high'
225
- products.
226
- select("#{Product.table_name}.*, #{Spree::Price.table_name}.amount").
227
- reorder('').
228
- send(:ascend_by_master_price)
227
+ order_by_price(products, :ascend_by_master_price)
229
228
  end
230
229
  end
231
230
 
@@ -257,7 +256,7 @@ module Spree
257
256
 
258
257
  def map_prices(prices)
259
258
  prices.map do |price|
260
- price == 'Infinity' ? Float::INFINITY : price.to_f
259
+ price == 'Infinity' ? BigDecimal::INFINITY : price.to_f
261
260
  end
262
261
  end
263
262
 
@@ -267,6 +266,13 @@ module Spree
267
266
  taxons = store.taxons.where(id: taxons_ids.to_s.split(','))
268
267
  taxons.map(&:cached_self_and_descendants_ids).flatten.compact.uniq.map(&:to_s)
269
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
270
276
  end
271
277
  end
272
278
  end
@@ -19,7 +19,7 @@ module Spree
19
19
  taxons = by_roots(taxons)
20
20
  taxons = by_name(taxons)
21
21
 
22
- taxons
22
+ taxons.distinct
23
23
  end
24
24
 
25
25
  private
@@ -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).where(parent: { permalink: parent_permalink })
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").where(["parent_taxon.permalink = ?", parent_permalink])
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
- taxons.where(name_matcher)
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
@@ -61,11 +61,11 @@ module Spree
61
61
  DEPRECATION
62
62
 
63
63
  image_path ||= if current_store.logo.attached? && current_store.logo.variable?
64
- main_app.url_for(current_store.logo.variant(resize: '244x104>'))
64
+ main_app.cdn_image_url(current_store.logo.variant(resize_to_limit: [244, 104]))
65
65
  elsif current_store.logo.attached? && current_store.logo.image?
66
- main_app.url_for(current_store.logo)
66
+ main_app.cdn_image_url(current_store.logo)
67
67
  else
68
- 'logo/spree_50.png'
68
+ 'logo/spree_50.png'
69
69
  end
70
70
 
71
71
  path = spree.respond_to?(:root_path) ? spree.root_path : main_app.root_path
@@ -76,7 +76,11 @@ module Spree
76
76
  end
77
77
 
78
78
  def spree_favicon_path
79
- main_app.url_for(current_store.favicon || 'favicon.ico')
79
+ if current_store.favicon.present?
80
+ main_app.cdn_image_url(current_store.favicon)
81
+ else
82
+ url_for('favicon.ico')
83
+ end
80
84
  end
81
85
 
82
86
  def object
@@ -88,7 +92,7 @@ module Spree
88
92
 
89
93
  if object.is_a? Spree::Product
90
94
  image = default_image_for_product_or_variant(object)
91
- og_meta['og:image'] = main_app.url_for(image.attachment) if image&.attachment
95
+ og_meta['og:image'] = main_app.cdn_image_url(image.attachment) if image&.attachment
92
96
 
93
97
  og_meta['og:url'] = spree.url_for(object) if frontend_available? # url_for product needed
94
98
  og_meta['og:type'] = object.class.name.demodulize.downcase
@@ -109,8 +113,8 @@ module Spree
109
113
  meta = {}
110
114
 
111
115
  if object.is_a? ApplicationRecord
112
- meta[:keywords] = object.meta_keywords if object[:meta_keywords].present?
113
- meta[:description] = object.meta_description if object[:meta_description].present?
116
+ meta[:keywords] = object.meta_keywords if object.try(:meta_keywords).present?
117
+ meta[:description] = object.meta_description if object.try(:meta_description).present?
114
118
  end
115
119
 
116
120
  if meta[:description].blank? && object.is_a?(Spree::Product)
@@ -163,8 +167,7 @@ module Spree
163
167
  end
164
168
 
165
169
  def seo_url(taxon, options = {})
166
- options.merge(locale: locale_param)
167
- spree.nested_taxons_path(taxon.permalink, options)
170
+ spree.nested_taxons_path(taxon.permalink, options.merge(locale: locale_param))
168
171
  end
169
172
 
170
173
  def frontend_available?
@@ -238,7 +241,7 @@ module Spree
238
241
 
239
242
  def create_product_image_tag(image, product, options, style)
240
243
  options[:alt] = image.alt.blank? ? product.name : image.alt
241
- image_tag main_app.url_for(image.url(style)), options
244
+ image_tag main_app.cdn_image_url(image.url(style)), options
242
245
  end
243
246
 
244
247
  def define_image_method(style)
@@ -249,7 +252,7 @@ module Spree
249
252
  img = if image_path.present?
250
253
  create_product_image_tag image_path, product, options, style
251
254
  else
252
- inline_svg_tag "noimage/backend-missing-image.svg", class: "noimage", size: "60%*60%"
255
+ inline_svg_tag 'noimage/backend-missing-image.svg', class: 'noimage', size: '60%*60%'
253
256
  end
254
257
 
255
258
  content_tag(:div, img, class: "admin-product-image-container #{style}-img")
@@ -15,10 +15,14 @@ module Spree
15
15
  end
16
16
 
17
17
  def locale_presentation(locale)
18
- if I18n.exists?('spree.i18n.this_file_language', locale: locale)
18
+ if I18n.exists?('spree.i18n.this_file_language', locale: locale, fallback: false)
19
19
  [locale_full_name(locale), locale.to_s]
20
+ elsif defined?(SpreeI18n::Locale) && (language_name = SpreeI18n::Locale.local_language_name(locale))
21
+ ["#{language_name} (#{locale})", locale.to_s]
22
+ elsif locale.to_s == 'en'
23
+ ['English (US)', 'en']
20
24
  else
21
- locale.to_s == 'en' ? ['English (US)', 'en'] : [locale, locale.to_s]
25
+ [locale, locale.to_s]
22
26
  end
23
27
  end
24
28
 
@@ -76,15 +76,20 @@ module Spree
76
76
 
77
77
  # will return a human readable string
78
78
  def available_status(product)
79
- return Spree.t(:discontinued) if product.discontinued?
79
+ ActiveSupport::Deprecation.warn(<<-DEPRECATION, caller)
80
+ `Spree::ProductsHelper#available_status` method from spree/core is deprecated and will be removed.
81
+ Please use `Spree::Admin::ProductsHelper#available_status` from spree_backend instead.
82
+ DEPRECATION
83
+
84
+ return Spree.t(:archived) if product.discontinued?
80
85
  return Spree.t(:deleted) if product.deleted?
81
86
 
82
87
  if product.available?
83
- Spree.t(:available)
84
- elsif product.available_on&.future?
88
+ Spree.t(:active)
89
+ elsif product.make_active_at&.future?
85
90
  Spree.t(:pending_sale)
86
91
  else
87
- Spree.t(:no_available_date_set)
92
+ Spree.t(:draft)
88
93
  end
89
94
  end
90
95
 
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module Variants
3
+ class RemoveFromIncompleteOrdersJob < Spree::BaseJob
4
+ def perform(variant)
5
+ Spree::Variants::RemoveLineItems.call(variant: variant)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module Variants
3
+ class RemoveLineItemJob < Spree::BaseJob
4
+ def perform(line_item:)
5
+ Spree::Dependencies.cart_remove_line_item_service.constantize.call(order: line_item.order, line_item: line_item)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -18,7 +18,7 @@ module Spree
18
18
 
19
19
  def calculator_type=(calculator_type)
20
20
  klass = calculator_type.constantize if calculator_type
21
- self.calculator = klass.new if klass && !calculator.is_a?(klass)
21
+ self.calculator = klass.new if klass && !calculator.instance_of?(klass)
22
22
  end
23
23
 
24
24
  private
@@ -1,42 +1,30 @@
1
1
  module Spree
2
2
  module DisplayLink
3
- def link
4
- case linked_resource_type
5
- when 'Spree::Taxon'
6
- return if linked_resource&.permalink.blank?
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ belongs_to :linked_resource, polymorphic: true
7
+
8
+ def link
9
+ case linked_resource_type
10
+ when 'Spree::Taxon'
11
+ return if linked_resource&.permalink.blank?
7
12
 
8
- if spree_routes.method_defined?(:nested_taxons_path)
9
- spree_routes.nested_taxons_path(linked_resource.permalink)
10
- else
11
13
  "/#{Spree::Config[:storefront_taxons_path]}/#{linked_resource.permalink}"
12
- end
13
- when 'Spree::Product'
14
- return if linked_resource&.slug.blank?
14
+ when 'Spree::Product'
15
+ return if linked_resource&.slug.blank?
15
16
 
16
- if spree_routes.method_defined?(:products_path)
17
- spree_routes.product_path(linked_resource)
18
- else
19
17
  "/#{Spree::Config[:storefront_products_path]}/#{linked_resource.slug}"
20
- end
21
- when 'Spree::CmsPage'
22
- return if linked_resource&.slug.blank?
18
+ when 'Spree::CmsPage'
19
+ return if linked_resource&.slug.blank?
23
20
 
24
- if spree_routes.method_defined?(:page_path)
25
- spree_routes.page_path(linked_resource.slug)
26
- else
27
21
  "/#{Spree::Config[:storefront_pages_path]}/#{linked_resource.slug}"
22
+ when 'Spree::Linkable::Homepage'
23
+ '/'
24
+ when 'Spree::Linkable::Uri'
25
+ destination
28
26
  end
29
- when 'Home Page'
30
- '/'
31
- when 'URL'
32
- destination
33
27
  end
34
28
  end
35
-
36
- private
37
-
38
- def spree_routes
39
- Spree::Core::Engine.routes.url_helpers
40
- end
41
29
  end
42
30
  end
@@ -2,23 +2,35 @@ module Spree
2
2
  module ImageMethods
3
3
  extend ActiveSupport::Concern
4
4
 
5
- def generate_url(size:, gravity: 'center', quality: 80, background: 'show')
5
+ def generate_url(size:, gravity: 'centre', quality: 80, background: [0, 0, 0])
6
6
  return if size.blank?
7
+
7
8
  size = size.gsub(/\s+/, '')
8
9
 
9
10
  return unless size.match(/(\d+)x(\d+)/)
10
11
 
11
- polymorphic_path(attachment.variant(
12
- gravity: gravity,
13
- resize: size,
14
- extent: size,
15
- background: background,
16
- quality: quality.to_i
17
- ), only_path: true)
12
+ width, height = size.split('x').map(&:to_i)
13
+ gravity = translate_gravity_for_mini_magick(gravity)
14
+
15
+ # FIXME: bring back support for background color
16
+
17
+ cdn_image_url(attachment.variant(resize_and_pad: [width, height, { gravity: gravity }], saver: { quality: quality }))
18
18
  end
19
19
 
20
20
  def original_url
21
- polymorphic_path(attachment, only_path: true)
21
+ cdn_image_url(attachment)
22
+ end
23
+
24
+ private
25
+
26
+ def translate_gravity_for_mini_magick(gravity)
27
+ variant_processor = Rails.application.config.active_storage.variant_processor
28
+
29
+ if gravity.downcase == 'centre' && [:mini_magick, nil].include?(variant_processor)
30
+ 'center'
31
+ else
32
+ gravity
33
+ end
22
34
  end
23
35
  end
24
36
  end
@@ -3,8 +3,8 @@ module Spree
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- attribute :public_metadata, default: {} if Rails.version.to_f >= 6.1
7
- attribute :private_metadata, default: {} if Rails.version.to_f >= 6.1
6
+ attribute :public_metadata, default: {}
7
+ attribute :private_metadata, default: {}
8
8
  serialize :public_metadata, HashSerializer
9
9
  serialize :private_metadata, HashSerializer
10
10
  end
@@ -32,15 +32,16 @@ module Spree
32
32
  end
33
33
 
34
34
  def self.property_conditions(property)
35
- properties = Property.table_name
35
+ properties_table = Property.table_name
36
+ property_translations_table = Property.translation_table_alias
36
37
  case property
37
- when Property then { "#{properties}.id" => property.id }
38
- when Integer then { "#{properties}.id" => property }
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
- ["#{properties.name} = ? OR #{properties.id} = ?", property, property]
42
+ ["#{property_translations_table.name} = ? OR #{properties_table.id} = ?", property, property]
42
43
  else
43
- { "#{properties}.name" => property }
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
- where("#{ProductProperty.table_name}.value = ?", value).
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
- where(Property.table_name => { filter_param: property_filter_param }).
143
- where(ProductProperty.table_name => { filter_param: property_values.map(&:parameterize) })
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).where(spree_option_types: { name: option })
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
- where(Spree::OptionValue.table_name => { name: value, option_type_id: option_type_id })
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:
@@ -236,7 +246,7 @@ module Spree
236
246
 
237
247
  def self.not_discontinued(only_not_discontinued = true)
238
248
  if only_not_discontinued != '0' && only_not_discontinued
239
- where("#{Product.quoted_table_name}.discontinue_on IS NULL or #{Product.quoted_table_name}.discontinue_on >= ?", Time.zone.now)
249
+ where.not(status: 'archived')
240
250
  else
241
251
  all
242
252
  end
@@ -253,9 +263,11 @@ module Spree
253
263
 
254
264
  # Can't use add_search_scope for this as it needs a default argument
255
265
  def self.available(available_on = nil, currency = nil)
256
- available_on ||= Time.current
257
-
258
- scope = not_discontinued.where("#{Product.quoted_table_name}.available_on <= ?", available_on)
266
+ if available_on
267
+ scope = not_discontinued.where("#{Product.quoted_table_name}.available_on <= ?", available_on)
268
+ else
269
+ scope = where(status: 'active')
270
+ end
259
271
 
260
272
  unless Spree::Config.show_products_without_price
261
273
  currency ||= Spree::Store.default.default_currency
@@ -282,7 +294,7 @@ module Spree
282
294
  if user.try(:has_spree_role?, 'admin')
283
295
  with_deleted
284
296
  else
285
- not_deleted.not_discontinued.where("#{Product.quoted_table_name}.available_on <= ?", Time.current)
297
+ not_deleted.where(status: 'active')
286
298
  end
287
299
  end
288
300
 
@@ -293,19 +305,10 @@ module Spree
293
305
  # .search_by_name
294
306
  if defined?(PgSearch)
295
307
  include PgSearch::Model
296
-
297
- if defined?(SpreeGlobalize)
298
- pg_search_scope :search_by_name, associated_against: { translations: :name }, using: :tsearch
299
- else
300
- pg_search_scope :search_by_name, against: :name, using: :tsearch
301
- end
308
+ pg_search_scope :search_by_name, against: :name, using: { tsearch: { any_word: true, prefix: true } }
302
309
  else
303
310
  def self.search_by_name(query)
304
- if defined?(SpreeGlobalize)
305
- joins(:translations).order(:name).where("LOWER(#{Product::Translation.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%").distinct
306
- else
307
- where("LOWER(#{Product.table_name}.name) LIKE LOWER(:query)", query: "%#{query}%")
308
- end
311
+ i18n { name.lower.matches("%#{query.downcase}%") }
309
312
  end
310
313
  end
311
314
  search_scopes << :search_by_name
@@ -337,7 +340,10 @@ module Spree
337
340
  case t
338
341
  when ApplicationRecord then t
339
342
  else
340
- Taxon.where(name: t).or(Taxon.where(id: t)).or(Taxon.where("permalink LIKE ? OR permalink = ?", "%/#{t}/", "#{t}/")).first
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
341
347
  end
342
348
  end.compact.flatten.uniq
343
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