spree_core 4.5.0 → 4.7.3

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.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. data/app/finders/spree/countries/find.rb +1 -1
  3. data/app/finders/spree/option_values/find_available.rb +1 -1
  4. data/app/finders/spree/product_properties/find_available.rb +1 -1
  5. data/app/finders/spree/products/find.rb +21 -13
  6. data/app/finders/spree/taxons/find.rb +7 -10
  7. data/app/helpers/spree/base_helper.rb +3 -7
  8. data/app/helpers/spree/products_helper.rb +3 -3
  9. data/app/models/concerns/spree/metadata.rb +7 -2
  10. data/app/models/concerns/spree/named_type.rb +1 -1
  11. data/app/models/concerns/spree/product_scopes.rb +27 -23
  12. data/app/models/concerns/spree/translatable_resource.rb +25 -0
  13. data/app/models/concerns/spree/translatable_resource_scopes.rb +24 -0
  14. data/app/models/concerns/spree/translatable_resource_slug.rb +15 -0
  15. data/app/models/concerns/spree/user_roles.rb +3 -3
  16. data/app/models/spree/address.rb +6 -4
  17. data/app/models/spree/asset.rb +1 -1
  18. data/app/models/spree/base.rb +6 -1
  19. data/app/models/spree/calculator/default_tax.rb +1 -1
  20. data/app/models/spree/cms/sections/image_gallery.rb +1 -7
  21. data/app/models/spree/cms/sections/side_by_side_images.rb +1 -7
  22. data/app/models/spree/cms_page.rb +2 -2
  23. data/app/models/spree/cms_section.rb +1 -1
  24. data/app/models/spree/country.rb +2 -2
  25. data/app/models/spree/credit_card.rb +1 -1
  26. data/app/models/spree/customer_return.rb +2 -2
  27. data/app/models/spree/data_feed/google.rb +15 -0
  28. data/app/models/spree/data_feed.rb +40 -0
  29. data/app/models/spree/digital_link.rb +5 -1
  30. data/app/models/spree/image.rb +2 -2
  31. data/app/models/spree/legacy_user.rb +3 -3
  32. data/app/models/spree/line_item.rb +1 -1
  33. data/app/models/spree/log_entry.rb +5 -1
  34. data/app/models/spree/menu.rb +1 -1
  35. data/app/models/spree/option_type.rb +6 -2
  36. data/app/models/spree/option_value.rb +5 -1
  37. data/app/models/spree/order/store_credit.rb +8 -0
  38. data/app/models/spree/order.rb +9 -9
  39. data/app/models/spree/order_contents.rb +31 -0
  40. data/app/models/spree/payment.rb +7 -15
  41. data/app/models/spree/payment_method.rb +1 -1
  42. data/app/models/spree/payment_source.rb +1 -1
  43. data/app/models/spree/preference.rb +5 -1
  44. data/app/models/spree/price.rb +1 -1
  45. data/app/models/spree/product.rb +64 -25
  46. data/app/models/spree/product_property.rb +13 -4
  47. data/app/models/spree/promotion.rb +2 -2
  48. data/app/models/spree/property.rb +8 -2
  49. data/app/models/spree/prototype.rb +1 -1
  50. data/app/models/spree/refund.rb +1 -1
  51. data/app/models/spree/reimbursement.rb +1 -1
  52. data/app/models/spree/return_authorization.rb +1 -1
  53. data/app/models/spree/return_item.rb +5 -1
  54. data/app/models/spree/role.rb +1 -1
  55. data/app/models/spree/shipment.rb +5 -5
  56. data/app/models/spree/shipping_category.rb +1 -1
  57. data/app/models/spree/shipping_method.rb +1 -1
  58. data/app/models/spree/stock/estimator.rb +1 -1
  59. data/app/models/spree/stock/splitter/weight.rb +1 -1
  60. data/app/models/spree/stock_item.rb +1 -1
  61. data/app/models/spree/stock_location.rb +1 -1
  62. data/app/models/spree/stock_transfer.rb +3 -3
  63. data/app/models/spree/store.rb +22 -3
  64. data/app/models/spree/store_credit.rb +2 -2
  65. data/app/models/spree/taxon.rb +47 -7
  66. data/app/models/spree/taxon_image.rb +2 -2
  67. data/app/models/spree/taxonomy.rb +5 -1
  68. data/app/models/spree/variant.rb +6 -9
  69. data/app/models/spree/wishlist.rb +6 -2
  70. data/app/models/spree/zone.rb +2 -2
  71. data/app/services/spree/data_feeds/google/optional_attributes.rb +23 -0
  72. data/app/services/spree/data_feeds/google/optional_sub_attributes.rb +21 -0
  73. data/app/services/spree/data_feeds/google/products_list.rb +14 -0
  74. data/app/services/spree/data_feeds/google/required_attributes.rb +67 -0
  75. data/app/services/spree/data_feeds/google/rss.rb +107 -0
  76. data/app/services/spree/locales/set_fallback_locale_for_store.rb +16 -0
  77. data/app/services/spree/seeds/countries.rb +12 -27
  78. data/app/services/spree/seeds/states.rb +8 -17
  79. data/app/services/spree/stock_locations/stock_items/create.rb +12 -18
  80. data/app/sorters/spree/products/sort.rb +23 -0
  81. data/app/validators/db_maximum_length_validator.rb +2 -6
  82. data/brakeman.ignore +326 -18
  83. data/config/initializers/friendly_id.rb +2 -0
  84. data/config/initializers/mobility.rb +16 -0
  85. data/config/initializers/rails61_fixes.rb +1 -3
  86. data/config/locales/en.yml +7 -0
  87. data/db/migrate/20220706112554_create_product_name_and_description_translations_for_mobility_table_backend.rb +27 -0
  88. data/db/migrate/20220715083542_create_spree_product_translations_for_mobility.rb +7 -0
  89. data/db/migrate/20220715120222_change_product_name_null_to_true.rb +5 -0
  90. data/db/migrate/20220718100743_create_spree_taxon_name_and_description_translations_for_mobility_table_backend.rb +27 -0
  91. data/db/migrate/20220718100948_change_taxon_name_null_to_true.rb +5 -0
  92. data/db/migrate/20220802070609_add_locale_to_friendly_id_slugs.rb +11 -0
  93. data/db/migrate/20220802073225_create_spree_product_slug_translations_for_mobility_table_backend.rb +5 -0
  94. data/db/migrate/20220804073928_transfer_data_to_translatable_tables.rb +66 -0
  95. data/db/migrate/20221215151408_add_selected_locale_to_spree_users.rb +8 -0
  96. data/db/migrate/20221219123957_add_deleted_at_to_product_translations.rb +6 -0
  97. data/db/migrate/20221220133432_add_uniqueness_constraint_to_product_translations.rb +5 -0
  98. data/db/migrate/20221229132350_create_spree_data_feed_settings.rb +14 -0
  99. data/db/migrate/20230103144439_create_option_type_translations.rb +26 -0
  100. data/db/migrate/20230103151034_create_option_value_translations.rb +26 -0
  101. data/db/migrate/20230109084253_create_product_property_translations.rb +25 -0
  102. data/db/migrate/20230109094907_transfer_options_data_to_translatable_tables.rb +58 -0
  103. data/db/migrate/20230109105943_create_property_translations.rb +26 -0
  104. data/db/migrate/20230109110840_transfer_property_data_to_translatable_tables.rb +59 -0
  105. data/db/migrate/20230110142344_backfill_friendly_id_slug_locale.rb +15 -0
  106. data/db/migrate/20230111121534_add_additional_taxon_translation_fields.rb +8 -0
  107. data/db/migrate/20230111122511_transfer_product_and_taxon_data_to_translatable_tables.rb +82 -0
  108. data/db/migrate/20230117115531_create_taxonomy_translations.rb +24 -0
  109. data/db/migrate/20230117120430_allow_null_taxonomy_name.rb +5 -0
  110. data/db/migrate/20230117121303_transfer_taxonomy_data_to_translatable_tables.rb +11 -0
  111. data/db/migrate/20230210142732_create_store_translations.rb +50 -0
  112. data/db/migrate/20230210142849_transfer_store_data_to_translatable_tables.rb +11 -0
  113. data/db/migrate/20230210230434_add_deleted_at_to_store_translations.rb +6 -0
  114. data/db/migrate/20230415155958_rename_data_feed_settings_table.rb +5 -0
  115. data/db/migrate/20230415160828_rename_data_feed_table_columns.rb +7 -0
  116. data/db/migrate/20230415161226_add_indexes_to_data_feeds_table.rb +5 -0
  117. data/db/migrate/20230512094803_rename_data_feeds_column_provider_to_type.rb +5 -0
  118. data/db/migrate/20230514162157_add_index_on_locale_and_permalink_to_spree_taxons.rb +5 -0
  119. data/lib/mobility/plugins/store_based_fallbacks.rb +55 -0
  120. data/lib/spree/core/configuration.rb +2 -1
  121. data/lib/spree/core/controller_helpers/auth.rb +1 -1
  122. data/lib/spree/core/controller_helpers/common.rb +5 -5
  123. data/lib/spree/core/controller_helpers/locale.rb +33 -2
  124. data/lib/spree/core/dependencies.rb +70 -94
  125. data/lib/spree/core/dependencies_helper.rb +19 -0
  126. data/lib/spree/core/engine.rb +7 -1
  127. data/lib/spree/core/preferences/preferable_class_methods.rb +1 -1
  128. data/lib/spree/core/product_duplicator.rb +4 -1
  129. data/lib/spree/core/product_filters.rb +7 -4
  130. data/lib/spree/core/search/base.rb +1 -1
  131. data/lib/spree/core/version.rb +1 -1
  132. data/lib/spree/core.rb +2 -0
  133. data/lib/spree/permitted_attributes.rb +1 -1
  134. data/lib/spree/testing_support/controller_requests.rb +10 -10
  135. data/lib/spree/testing_support/factories/google_data_feed_factory.rb +8 -0
  136. data/lib/spree/testing_support/factories/product_factory.rb +6 -0
  137. data/lib/spree/testing_support/factories/product_translation_factory.rb +6 -0
  138. data/lib/spree/testing_support/factories/store_factory.rb +3 -0
  139. data/lib/spree/testing_support/factories/variant_factory.rb +4 -0
  140. data/lib/spree/translation_migrations.rb +40 -0
  141. data/lib/spree_core.rb +1 -0
  142. data/spree_core.gemspec +6 -3
  143. metadata +147 -14
@@ -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
@@ -1,6 +1,10 @@
1
1
  module Spree
2
2
  class DigitalLink < Spree::Base
3
- has_secure_token
3
+ if Rails::VERSION::STRING >= '7.1.0'
4
+ has_secure_token on: :save
5
+ else
6
+ has_secure_token
7
+ end
4
8
 
5
9
  if defined?(Spree::Webhooks)
6
10
  include Spree::Webhooks::HasWebhooks
@@ -1,8 +1,8 @@
1
1
  module Spree
2
2
  class Image < Asset
3
- include Configuration::ActiveStorage
3
+ include Spree::Image::Configuration::ActiveStorage
4
4
  include Rails.application.routes.url_helpers
5
- include ::Spree::ImageMethods
5
+ include Spree::ImageMethods
6
6
 
7
7
  # In Rails 5.x class constants are being undefined/redefined during the code reloading process
8
8
  # in a rails development environment, after which the actual ruby objects stored in those class constants
@@ -1,9 +1,9 @@
1
1
  # Default implementation of User. This class is intended to be modified by extensions (ex. spree_auth_devise)
2
2
  module Spree
3
3
  class LegacyUser < Spree::Base
4
- include UserAddress
5
- include UserPaymentSource
6
- include UserMethods
4
+ include Spree::UserAddress
5
+ include Spree::UserPaymentSource
6
+ include Spree::UserMethods
7
7
  include Spree::Metadata
8
8
 
9
9
  self.table_name = 'spree_users'
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class LineItem < Spree::Base
3
- include Metadata
3
+ include Spree::Metadata
4
4
  if defined?(Spree::Webhooks)
5
5
  include Spree::Webhooks::HasWebhooks
6
6
  end
@@ -15,7 +15,11 @@ module Spree
15
15
  end
16
16
 
17
17
  def parsed_details
18
- @details ||= YAML.safe_load(details, [ActiveMerchant::Billing::Response])
18
+ @details ||= if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.1.0')
19
+ YAML.safe_load(details, permitted_classes: [ActiveMerchant::Billing::Response])
20
+ else
21
+ YAML.safe_load(details, [ActiveMerchant::Billing::Response])
22
+ end
19
23
  end
20
24
  end
21
25
  end
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class Menu < Spree::Base
3
- include SingleStoreResource
3
+ include Spree::SingleStoreResource
4
4
  if defined?(Spree::Webhooks)
5
5
  include Spree::Webhooks::HasWebhooks
6
6
  end
@@ -1,11 +1,15 @@
1
1
  module Spree
2
2
  class OptionType < Spree::Base
3
- include UniqueName
4
- include Metadata
3
+ include Spree::UniqueName
4
+ include Spree::Metadata
5
+ include Spree::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
- include Metadata
3
+ include Spree::Metadata
4
+ include Spree::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
@@ -1,6 +1,14 @@
1
1
  module Spree
2
2
  class Order < Spree::Base
3
3
  module StoreCredit
4
+ def add_store_credit_payments(amount = nil)
5
+ Spree::Dependencies.checkout_add_store_credit_service.constantize.call(order: self, amount: amount)
6
+ end
7
+
8
+ def remove_store_credit_payments
9
+ Spree::Dependencies.checkout_remove_store_credit_service.constantize.call(order: self)
10
+ end
11
+
4
12
  def covered_by_store_credit?
5
13
  return false unless user
6
14
 
@@ -20,11 +20,11 @@ module Spree
20
20
  include Spree::Core::NumberGenerator.new(prefix: 'R')
21
21
  include Spree::Core::TokenGenerator
22
22
 
23
- include NumberIdentifier
24
- include NumberAsParam
25
- include SingleStoreResource
26
- include MemoizedData
27
- include Metadata
23
+ include Spree::NumberIdentifier
24
+ include Spree::NumberAsParam
25
+ include Spree::SingleStoreResource
26
+ include Spree::MemoizedData
27
+ include Spree::Metadata
28
28
  if defined?(Spree::Webhooks)
29
29
  include Spree::Webhooks::HasWebhooks
30
30
  end
@@ -415,7 +415,7 @@ module Spree
415
415
 
416
416
  def available_payment_methods(store = nil)
417
417
  if store.present?
418
- ActiveSupport::Deprecation.warn('The `store` parameter is deprecated and will be removed in Spree 5. Order is already associated with Store')
418
+ Spree::Deprecation.warn('The `store` parameter is deprecated and will be removed in Spree 5. Order is already associated with Store')
419
419
  end
420
420
 
421
421
  @available_payment_methods ||= collect_payment_methods(store)
@@ -449,7 +449,7 @@ module Spree
449
449
  end
450
450
 
451
451
  def empty!
452
- ActiveSupport::Deprecation.warn(<<-DEPRECATION, caller)
452
+ Spree::Deprecation.warn(<<-DEPRECATION, caller)
453
453
  `Order#empty!` is deprecated and will be removed in Spree 5.0.
454
454
  Please use `Spree::Cart::Empty.call(order: order)` instead.
455
455
  DEPRECATION
@@ -647,7 +647,7 @@ module Spree
647
647
  end
648
648
 
649
649
  def validate_payments_attributes(attributes)
650
- ActiveSupport::Deprecation.warn('`Order#validate_payments_attributes` is deprecated and will be removed in Spree 5')
650
+ Spree::Deprecation.warn('`Order#validate_payments_attributes` is deprecated and will be removed in Spree 5')
651
651
 
652
652
  # Ensure the payment methods specified are allowed for this user
653
653
  payment_method_ids = available_payment_methods.map(&:id).map(&:to_s)
@@ -745,7 +745,7 @@ module Spree
745
745
 
746
746
  def collect_payment_methods(store = nil)
747
747
  if store.present?
748
- ActiveSupport::Deprecation.warn('The `store` parameter is deprecated and will be removed in Spree 5. Order is already associated with Store')
748
+ Spree::Deprecation.warn('The `store` parameter is deprecated and will be removed in Spree 5. Order is already associated with Store')
749
749
  end
750
750
  store ||= self.store
751
751
 
@@ -0,0 +1,31 @@
1
+ module Spree
2
+ class OrderContents
3
+ attr_accessor :order, :currency
4
+
5
+ def initialize(order)
6
+ @order = order
7
+ end
8
+
9
+ def add(variant, quantity = 1, options = {})
10
+ Spree::Dependencies.cart_add_item_service.constantize.call(order: order,
11
+ variant: variant,
12
+ quantity: quantity,
13
+ options: options).value
14
+ end
15
+
16
+ def remove(variant, quantity = 1, options = {})
17
+ Spree::Dependencies.cart_remove_item_service.constantize.call(order: order,
18
+ variant: variant,
19
+ quantity: quantity,
20
+ options: options).value
21
+ end
22
+
23
+ def remove_line_item(line_item, options = {})
24
+ Spree::Cart::RemoveLineItem.call(order: @order, line_item: line_item, options: options).value
25
+ end
26
+
27
+ def update_cart(params)
28
+ Spree::Dependencies.cart_update_service.constantize.call(order: order, params: params).value
29
+ end
30
+ end
31
+ end
@@ -3,9 +3,9 @@ require_dependency 'spree/payment/processing'
3
3
  module Spree
4
4
  class Payment < Spree::Base
5
5
  include Spree::Core::NumberGenerator.new(prefix: 'P', letters: true, length: 7)
6
- include NumberIdentifier
7
- include NumberAsParam
8
- include Metadata
6
+ include Spree::NumberIdentifier
7
+ include Spree::NumberAsParam
8
+ include Spree::Metadata
9
9
  if defined?(Spree::Webhooks)
10
10
  include Spree::Webhooks::HasWebhooks
11
11
  end
@@ -222,18 +222,10 @@ module Spree
222
222
 
223
223
  def validate_source
224
224
  if source && !source.valid?
225
- if Rails::VERSION::STRING >= '6.1'
226
- source.errors.map { |error| { field: error.attribute, message: error&.message } }.each do |err|
227
- next if err[:field].blank? || err[:message].blank?
228
-
229
- add_source_error(err[:field], err[:message])
230
- end
231
- else
232
- source.errors.messages.each do |field, error|
233
- next if field.blank? || error.empty?
234
-
235
- add_source_error(field, error.first)
236
- end
225
+ source.errors.map { |error| { field: error.attribute, message: error&.message } }.each do |err|
226
+ next if err[:field].blank? || err[:message].blank?
227
+
228
+ add_source_error(err[:field], err[:message])
237
229
  end
238
230
  end
239
231
  !errors.present?
@@ -3,7 +3,7 @@ module Spree
3
3
  acts_as_paranoid
4
4
  acts_as_list
5
5
 
6
- include MultiStoreResource
6
+ include Spree::MultiStoreResource
7
7
  include Spree::Metadata
8
8
  if defined?(Spree::Security::PaymentMethods)
9
9
  include Spree::Security::PaymentMethods
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class PaymentSource < Spree::Base
3
- include Metadata
3
+ include Spree::Metadata
4
4
 
5
5
  belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
6
6
  belongs_to :user, class_name: 'Spree::User', optional: true
@@ -1,5 +1,9 @@
1
1
  class Spree::Preference < Spree::Base
2
- serialize :value
2
+ if Rails::VERSION::STRING >= '7.1.0'
3
+ serialize :value, coder: YAML
4
+ else
5
+ serialize :value
6
+ end
3
7
 
4
8
  validates :key, presence: true,
5
9
  uniqueness: { case_sensitive: false, allow_blank: true, scope: spree_base_uniqueness_scope }
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class Price < Spree::Base
3
- include VatPriceCalculation
3
+ include Spree::VatPriceCalculation
4
4
  if defined?(Spree::Webhooks)
5
5
  include Spree::Webhooks::HasWebhooks
6
6
  end
@@ -21,10 +21,12 @@
21
21
  module Spree
22
22
  class Product < Spree::Base
23
23
  extend FriendlyId
24
- include ProductScopes
25
- include MultiStoreResource
26
- include MemoizedData
27
- include Metadata
24
+ include Spree::ProductScopes
25
+ include Spree::MultiStoreResource
26
+ include Spree::TranslatableResource
27
+ include Spree::TranslatableResourceSlug
28
+ include Spree::MemoizedData
29
+ include Spree::Metadata
28
30
  if defined?(Spree::Webhooks)
29
31
  include Spree::Webhooks::HasWebhooks
30
32
  end
@@ -32,12 +34,36 @@ module Spree
32
34
  include Spree::VendorConcern
33
35
  end
34
36
 
35
- MEMOIZED_METHODS = %w(total_on_hand taxonomy_ids taxon_and_ancestors category
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?]
40
+
41
+ TRANSLATABLE_FIELDS = %i[name description slug meta_description meta_keywords meta_title].freeze
42
+ translates(*TRANSLATABLE_FIELDS)
43
+
44
+ self::Translation.class_eval do
45
+ before_save :set_slug
46
+ acts_as_paranoid
47
+ # deleted translation values also need to be accessible for index views listing deleted resources
48
+ default_scope { unscope(where: :deleted_at) }
49
+ def set_slug
50
+ self.slug = generate_slug
51
+ end
52
+
53
+ private
38
54
 
39
- friendly_id :slug_candidates, use: :history
55
+ def generate_slug
56
+ if name.blank? && slug.blank?
57
+ translated_model.name.to_url
58
+ elsif slug.blank?
59
+ name.to_url
60
+ else
61
+ slug.to_url
62
+ end
63
+ end
64
+ end
40
65
 
66
+ friendly_id :slug_candidates, use: [:history, :mobility]
41
67
  acts_as_paranoid
42
68
  auto_strip_attributes :name
43
69
 
@@ -306,14 +332,26 @@ module Spree
306
332
  end
307
333
 
308
334
  def property(property_name)
309
- product_properties.joins(:property).find_by(spree_properties: { name: property_name }).try(:value)
335
+ product_properties.joins(:property).
336
+ join_translation_table(Property).
337
+ find_by(Property.translation_table_alias => { name: property_name }).try(:value)
310
338
  end
311
339
 
312
340
  def set_property(property_name, property_value, property_presentation = property_name)
313
341
  ApplicationRecord.transaction do
314
- # Works around spree_i18n #301
315
- property = Property.create_with(presentation: property_presentation).find_or_create_by(name: property_name)
316
- product_property = ProductProperty.where(product: self, property: property).first_or_initialize
342
+ # Manual first_or_create to work around Mobility bug
343
+ property = if Property.where(name: property_name).exists?
344
+ Property.where(name: property_name).first
345
+ else
346
+ Property.create(name: property_name, presentation: property_presentation)
347
+ end
348
+
349
+ product_property = if ProductProperty.where(product: self, property: property).exists?
350
+ ProductProperty.where(product: self, property: property).first
351
+ else
352
+ ProductProperty.create(product: self, property: property)
353
+ end
354
+
317
355
  product_property.value = property_value
318
356
  product_property.save!
319
357
  end
@@ -337,11 +375,16 @@ module Spree
337
375
  end
338
376
 
339
377
  def brand
340
- @brand ||= taxons.joins(:taxonomy).find_by(spree_taxonomies: { name: Spree.t(:taxonomy_brands_name) })
378
+ @brand ||= taxons.joins(:taxonomy).
379
+ join_translation_table(Taxonomy).
380
+ find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_brands_name) })
341
381
  end
342
382
 
343
383
  def category
344
- @category ||= taxons.joins(:taxonomy).order(depth: :desc).find_by(spree_taxonomies: { name: Spree.t(:taxonomy_categories_name) })
384
+ @category ||= taxons.joins(:taxonomy).
385
+ join_translation_table(Taxonomy).
386
+ order(depth: :desc).
387
+ find_by(Taxonomy.translation_table_alias => { name: Spree.t(:taxonomy_categories_name) })
345
388
  end
346
389
 
347
390
  def taxons_for_store(store)
@@ -415,7 +458,11 @@ module Spree
415
458
 
416
459
  def punch_slug
417
460
  # punch slug with date prefix to allow reuse of original
418
- update_column :slug, "#{Time.current.to_i}_#{slug}"[0..254] unless frozen?
461
+ return if frozen?
462
+
463
+ translations.with_deleted.each do |t|
464
+ t.update_column :slug, "#{Time.current.to_i}_#{t.slug}"[0..254]
465
+ end
419
466
  end
420
467
 
421
468
  def update_slug_history
@@ -460,18 +507,10 @@ module Spree
460
507
  # We call master.default_price here to ensure price is initialized.
461
508
  # Required to avoid Variant#check_price validation failing on create.
462
509
  unless master.default_price && master.valid?
463
- if Rails::VERSION::STRING >= '6.1'
464
- master.errors.map { |error| { field: error.attribute, message: error&.message } }.each do |err|
465
- next if err[:field].blank? || err[:message].blank?
466
-
467
- errors.add(err[:field], err[:message])
468
- end
469
- else
470
- master.errors.messages.each do |field, error|
471
- next if field.blank? || error.empty?
510
+ master.errors.map { |error| { field: error.attribute, message: error&.message } }.each do |err|
511
+ next if err[:field].blank? || err[:message].blank?
472
512
 
473
- errors.add(field, error.first)
474
- end
513
+ errors.add(err[:field], err[:message])
475
514
  end
476
515
  end
477
516
  end
@@ -1,8 +1,14 @@
1
1
  module Spree
2
2
  class ProductProperty < Spree::Base
3
3
  include Spree::FilterParam
4
+ include Spree::TranslatableResource
4
5
 
5
- auto_strip_attributes :value
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
 
@@ -27,12 +33,15 @@ module Spree
27
33
  delegate :name, :presentation, to: :property, prefix: true, allow_nil: true
28
34
 
29
35
  def property_name=(name)
30
- ActiveSupport::Deprecation.warn(<<-DEPRECATION, caller)
36
+ Spree::Deprecation.warn(<<-DEPRECATION, caller)
31
37
  `ProductProperty#property_name=` is deprecated and will be removed in Spree 5.0.
32
38
  DEPRECATION
33
39
  if name.present?
34
- # don't use `find_by :name` to workaround globalize/globalize#423 bug
35
- self.property = Property.where(name: name).first_or_create(presentation: name)
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
 
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  class Promotion < Spree::Base
3
- include MultiStoreResource
4
- include Metadata
3
+ include Spree::MultiStoreResource
4
+ include Spree::Metadata
5
5
  if defined?(Spree::Webhooks)
6
6
  include Spree::Webhooks::HasWebhooks
7
7
  end
@@ -1,12 +1,18 @@
1
1
  module Spree
2
2
  class Property < Spree::Base
3
3
  include Spree::FilterParam
4
- include Metadata
4
+ include Spree::Metadata
5
+ include Spree::TranslatableResource
5
6
  if defined?(Spree::Webhooks)
6
7
  include Spree::Webhooks::HasWebhooks
7
8
  end
8
9
 
9
- auto_strip_attributes :name, :presentation
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'
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class Prototype < Spree::Base
3
- include Metadata
3
+ include Spree::Metadata
4
4
  if defined?(Spree::Webhooks)
5
5
  include Spree::Webhooks::HasWebhooks
6
6
  end
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class Refund < Spree::Base
3
- include Metadata
3
+ include Spree::Metadata
4
4
  if defined?(Spree::Webhooks)
5
5
  include Spree::Webhooks::HasWebhooks
6
6
  end
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  class Reimbursement < Spree::Base
3
3
  include Spree::Core::NumberGenerator.new(prefix: 'RI', length: 9)
4
- include NumberIdentifier
4
+ include Spree::NumberIdentifier
5
5
  if defined?(Spree::Webhooks)
6
6
  include Spree::Webhooks::HasWebhooks
7
7
  end
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  class ReturnAuthorization < Spree::Base
3
3
  include Spree::Core::NumberGenerator.new(prefix: 'RA', length: 9)
4
- include NumberIdentifier
4
+ include Spree::NumberIdentifier
5
5
  if defined?(Spree::Webhooks)
6
6
  include Spree::Webhooks::HasWebhooks
7
7
  end
@@ -62,7 +62,11 @@ module Spree
62
62
  scope :exchange_required, -> { eager_load(:exchange_inventory_units).where(spree_inventory_units: { original_return_item_id: nil }).distinct }
63
63
  scope :resellable, -> { where resellable: true }
64
64
 
65
- serialize :acceptance_status_errors
65
+ if Rails::VERSION::STRING >= '7.1.0'
66
+ serialize :acceptance_status_errors, coder: YAML
67
+ else
68
+ serialize :acceptance_status_errors
69
+ end
66
70
 
67
71
  delegate :eligible_for_return?, :requires_manual_intervention?, to: :validator
68
72
  delegate :variant, to: :inventory_unit
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class Role < Spree::Base
3
- include UniqueName
3
+ include Spree::UniqueName
4
4
 
5
5
  has_many :role_users, class_name: 'Spree::RoleUser', dependent: :destroy
6
6
  has_many :users, through: :role_users, class_name: "::#{Spree.user_class}"
@@ -3,9 +3,9 @@ require 'ostruct'
3
3
  module Spree
4
4
  class Shipment < Spree::Base
5
5
  include Spree::Core::NumberGenerator.new(prefix: 'H', length: 11)
6
- include NumberIdentifier
7
- include NumberAsParam
8
- include Metadata
6
+ include Spree::NumberIdentifier
7
+ include Spree::NumberAsParam
8
+ include Spree::Metadata
9
9
  if defined?(Spree::Webhooks)
10
10
  include Spree::Webhooks::HasWebhooks
11
11
  end
@@ -249,8 +249,8 @@ module Spree
249
249
  end
250
250
 
251
251
  def selected_shipping_rate_id=(id)
252
- shipping_rates.update_all(selected: false)
253
- shipping_rates.touch_all # Bust cache dependent on "updated_at" timestamp
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
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class ShippingCategory < Spree::Base
3
- include UniqueName
3
+ include Spree::UniqueName
4
4
  if defined?(Spree::Webhooks)
5
5
  include Spree::Webhooks::HasWebhooks
6
6
  end
@@ -2,7 +2,7 @@ module Spree
2
2
  class ShippingMethod < Spree::Base
3
3
  acts_as_paranoid
4
4
  include Spree::CalculatedAdjustments
5
- include Metadata
5
+ include Spree::Metadata
6
6
  if defined?(Spree::Webhooks)
7
7
  include Spree::Webhooks::HasWebhooks
8
8
  end
@@ -1,7 +1,7 @@
1
1
  module Spree
2
2
  module Stock
3
3
  class Estimator
4
- include VatPriceCalculation
4
+ include Spree::VatPriceCalculation
5
5
 
6
6
  attr_reader :order, :currency
7
7
 
@@ -15,7 +15,7 @@ module Spree
15
15
  private
16
16
 
17
17
  def reduce(package)
18
- contents = split_package_contents_over_threshold(package).sort { |x, y| y.weight <=> x.weight }
18
+ contents = split_package_contents_over_threshold(package).sort_by(&:weight).reverse
19
19
  # Treat current package as one of the generated packages for convenience and add the heaviest item
20
20
  # This also prevents an additional package if no fit is possible
21
21
  package.contents.clear