spree_core 5.4.0.beta → 5.4.0.beta2

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/app/finders/spree/products/find.rb +1 -28
  3. data/app/helpers/spree/base_helper.rb +1 -54
  4. data/app/mailers/spree/base_mailer.rb +4 -3
  5. data/app/models/concerns/spree/adjustment_source.rb +0 -8
  6. data/app/models/concerns/spree/admin_user_methods.rb +0 -2
  7. data/app/models/concerns/spree/image_methods.rb +4 -0
  8. data/app/models/concerns/spree/metadata.rb +10 -0
  9. data/app/models/concerns/spree/product_scopes.rb +2 -47
  10. data/app/models/concerns/spree/stores/markets.rb +7 -7
  11. data/app/models/concerns/spree/vat_price_calculation.rb +2 -2
  12. data/app/models/spree/ability.rb +5 -5
  13. data/app/models/spree/address.rb +3 -2
  14. data/app/models/spree/adjustable/promotion_accumulator.rb +1 -1
  15. data/app/models/spree/adjustment.rb +1 -20
  16. data/app/models/spree/api_key.rb +57 -2
  17. data/app/models/spree/country.rb +7 -3
  18. data/app/models/spree/credit_card.rb +0 -27
  19. data/app/models/spree/current.rb +38 -2
  20. data/app/models/spree/exports/products.rb +0 -6
  21. data/app/models/spree/gateway/bogus.rb +9 -9
  22. data/app/models/spree/gateway.rb +0 -3
  23. data/app/models/spree/gift_card_batch.rb +4 -0
  24. data/app/models/spree/image/configuration/active_storage.rb +0 -2
  25. data/app/models/spree/image.rb +7 -31
  26. data/app/models/spree/log_entry.rb +8 -5
  27. data/app/models/spree/order/checkout.rb +0 -18
  28. data/app/models/spree/order.rb +20 -11
  29. data/app/models/spree/payment/gateway_options.rb +2 -2
  30. data/app/models/spree/payment/processing.rb +5 -5
  31. data/app/models/spree/payment.rb +1 -1
  32. data/app/models/spree/payment_connection_error.rb +3 -0
  33. data/app/models/spree/payment_method/check.rb +1 -1
  34. data/app/models/spree/payment_method/store_credit.rb +5 -5
  35. data/app/models/spree/payment_response.rb +70 -0
  36. data/app/models/spree/permission_sets/default_customer.rb +0 -5
  37. data/app/models/spree/permission_sets/product_display.rb +0 -2
  38. data/app/models/spree/permission_sets/product_management.rb +0 -2
  39. data/app/models/spree/product.rb +4 -72
  40. data/app/models/spree/promotion.rb +2 -14
  41. data/app/models/spree/promotion_handler/coupon.rb +3 -3
  42. data/app/models/spree/prototype.rb +0 -3
  43. data/app/models/spree/refund.rb +6 -2
  44. data/app/models/spree/shipment/emails.rb +1 -0
  45. data/app/models/spree/shipping_category.rb +3 -3
  46. data/app/models/spree/store.rb +10 -49
  47. data/app/models/spree/store_credit.rb +4 -0
  48. data/app/models/spree/tax_category.rb +1 -11
  49. data/app/models/spree/taxon.rb +0 -16
  50. data/app/models/spree/variant.rb +2 -40
  51. data/app/models/spree/zone.rb +1 -4
  52. data/app/services/spree/cart/add_item.rb +8 -4
  53. data/app/services/spree/cart/create.rb +13 -2
  54. data/app/services/spree/products/duplicator.rb +0 -12
  55. data/app/services/spree/products/prepare_nested_attributes.rb +0 -12
  56. data/config/locales/en.yml +3 -20
  57. data/db/migrate/20210914000000_spree_four_three.rb +0 -38
  58. data/db/migrate/20210915064329_add_metadata_to_spree_multiple_tables.rb +0 -1
  59. data/db/migrate/20260226000000_add_locale_to_spree_orders.rb +5 -0
  60. data/db/migrate/20260226100000_add_token_digest_to_spree_api_keys.rb +21 -0
  61. data/lib/generators/spree/cursor_rules/templates/spree_rules.mdc +1 -3
  62. data/lib/spree/core/configuration.rb +0 -3
  63. data/lib/spree/core/controller_helpers/strong_parameters.rb +1 -2
  64. data/lib/spree/core/dependencies.rb +2 -10
  65. data/lib/spree/core/engine.rb +0 -13
  66. data/lib/spree/core/pricing/resolver.rb +1 -9
  67. data/lib/spree/core/version.rb +1 -1
  68. data/lib/spree/core.rb +10 -25
  69. data/lib/spree/permitted_attributes.rb +2 -14
  70. data/lib/spree/testing_support/factories/order_factory.rb +1 -0
  71. data/lib/spree/testing_support/factories/payment_method_factory.rb +1 -6
  72. data/lib/spree/testing_support/factories/product_factory.rb +0 -7
  73. data/lib/spree/testing_support/factories/prototype_factory.rb +0 -2
  74. data/lib/tasks/core.rake +0 -265
  75. metadata +8 -101
  76. data/app/finders/spree/posts/find.rb +0 -137
  77. data/app/finders/spree/product_properties/find_available.rb +0 -20
  78. data/app/helpers/spree/mail_helper.rb +0 -27
  79. data/app/jobs/spree/api_key_touch_job.rb +0 -9
  80. data/app/mailers/spree/test_mailer.rb +0 -8
  81. data/app/models/action_text/video_embed.rb +0 -13
  82. data/app/models/concerns/spree/has_one_link.rb +0 -42
  83. data/app/models/concerns/spree/linkable.rb +0 -9
  84. data/app/models/concerns/spree/previewable.rb +0 -17
  85. data/app/models/spree/data_feed/google.rb +0 -15
  86. data/app/models/spree/data_feed.rb +0 -42
  87. data/app/models/spree/gateway/bogus_simple.rb +0 -24
  88. data/app/models/spree/post.rb +0 -108
  89. data/app/models/spree/post_category.rb +0 -46
  90. data/app/models/spree/product_property.rb +0 -51
  91. data/app/models/spree/property.rb +0 -86
  92. data/app/models/spree/property_prototype.rb +0 -9
  93. data/app/models/spree/store_favicon_image.rb +0 -20
  94. data/app/models/spree/store_logo.rb +0 -4
  95. data/app/models/spree/store_mailer_logo.rb +0 -7
  96. data/app/models/spree/taxon_image/configuration/active_storage.rb +0 -26
  97. data/app/models/spree/taxon_image.rb +0 -28
  98. data/app/presenters/spree/filters/properties_presenter.rb +0 -23
  99. data/app/presenters/spree/filters/property_presenter.rb +0 -42
  100. data/app/services/spree/data_feeds/google/optional_attributes.rb +0 -23
  101. data/app/services/spree/data_feeds/google/optional_sub_attributes.rb +0 -21
  102. data/app/services/spree/data_feeds/google/products_list.rb +0 -14
  103. data/app/services/spree/data_feeds/google/required_attributes.rb +0 -68
  104. data/app/services/spree/data_feeds/google/rss.rb +0 -109
  105. data/app/sorters/spree/posts/sort.rb +0 -40
  106. data/app/views/action_text/video_embeds/_thumbnail.html.erb +0 -1
  107. data/app/views/action_text/video_embeds/_video_embed.html.erb +0 -3
  108. data/app/views/layouts/action_text/contents/_content.html.erb +0 -3
  109. data/app/views/spree/test_mailer/test_email.html.erb +0 -40
  110. data/app/views/spree/test_mailer/test_email.text.erb +0 -4
  111. data/config/initializers/oembed.rb +0 -1
  112. data/db/migrate/20221229132350_create_spree_data_feed_settings.rb +0 -14
  113. data/db/migrate/20230109084253_create_product_property_translations.rb +0 -24
  114. data/db/migrate/20230109105943_create_property_translations.rb +0 -24
  115. data/db/migrate/20230415155958_rename_data_feed_settings_table.rb +0 -5
  116. data/db/migrate/20230415160828_rename_data_feed_table_columns.rb +0 -7
  117. data/db/migrate/20230415161226_add_indexes_to_data_feeds_table.rb +0 -5
  118. data/db/migrate/20230512094803_rename_data_feeds_column_provider_to_type.rb +0 -5
  119. data/db/migrate/20240914153106_add_display_on_to_spree_properties.rb +0 -5
  120. data/db/migrate/20240915144935_add_position_to_spree_properties.rb +0 -6
  121. data/db/migrate/20250121160028_create_spree_posts_and_spree_post_categories.rb +0 -33
  122. data/db/migrate/20250127083740_add_kind_to_spree_properties.rb +0 -5
  123. data/db/migrate/20250217171018_create_action_text_video_embeds.rb +0 -11
  124. data/db/migrate/20250305121657_remove_spree_posts_indices.rb +0 -7
  125. data/db/migrate/20250730154601_add_unique_index_on_spree_properties_name.rb +0 -24
  126. data/db/sample_data/posts.rb +0 -7
  127. data/lib/spree/core/controller_helpers/search.rb +0 -17
  128. data/lib/spree/core/product_filters.rb +0 -218
  129. data/lib/spree/core/query_filters/comparable.rb +0 -50
  130. data/lib/spree/core/query_filters/date.rb +0 -8
  131. data/lib/spree/core/query_filters/number.rb +0 -8
  132. data/lib/spree/core/query_filters/text.rb +0 -36
  133. data/lib/spree/core/query_filters.rb +0 -11
  134. data/lib/spree/core/search/base.rb +0 -144
  135. data/lib/spree/testing_support/factories/favicon_image_factory.rb +0 -9
  136. data/lib/spree/testing_support/factories/google_data_feed_factory.rb +0 -7
  137. data/lib/spree/testing_support/factories/post_category_factory.rb +0 -7
  138. data/lib/spree/testing_support/factories/post_factory.rb +0 -22
  139. data/lib/spree/testing_support/factories/product_property_factory.rb +0 -7
  140. data/lib/spree/testing_support/factories/property_factory.rb +0 -28
  141. data/lib/spree/testing_support/factories/taxon_image_factory.rb +0 -9
  142. data/lib/spree/testing_support/flash.rb +0 -25
  143. data/lib/spree/testing_support/flatpickr_capybara.rb +0 -124
  144. data/lib/tasks/exchanges.rake +0 -66
@@ -72,9 +72,6 @@ module Spree
72
72
 
73
73
  has_many :product_option_types, -> { order(:position) }, dependent: :destroy, inverse_of: :product
74
74
  has_many :option_types, through: :product_option_types
75
- has_many :product_properties, dependent: :destroy, inverse_of: :product
76
- has_many :properties, through: :product_properties
77
-
78
75
  has_many :classifications, -> { order(created_at: :asc) }, dependent: :delete_all, inverse_of: :product
79
76
  has_many :taxons, through: :classifications, before_remove: :remove_taxon
80
77
  has_many :taxonomies, through: :taxons
@@ -215,9 +212,6 @@ module Spree
215
212
 
216
213
  attr_accessor :option_values_hash
217
214
 
218
- accepts_nested_attributes_for :product_properties, allow_destroy: true, reject_if: lambda { |pp|
219
- pp[:property_id].blank? || (pp[:id].blank? && pp[:value].blank?)
220
- }
221
215
  accepts_nested_attributes_for(
222
216
  :variants,
223
217
  allow_destroy: true,
@@ -236,7 +230,7 @@ module Spree
236
230
 
237
231
  self.whitelisted_ransackable_attributes = %w[description name slug discontinue_on status available_on created_at updated_at]
238
232
  self.whitelisted_ransackable_associations = %w[taxons stores variants_including_master master variants tags labels
239
- shipping_category classifications option_types properties]
233
+ shipping_category classifications option_types]
240
234
  self.whitelisted_ransackable_scopes = %w[not_discontinued search_by_name in_taxon price_between
241
235
  multi_search in_stock_items out_of_stock_items with_option_value_ids
242
236
  ascend_by_price descend_by_price]
@@ -417,7 +411,7 @@ module Spree
417
411
  # Returns the short description for the product
418
412
  # @return [String]
419
413
  def storefront_description
420
- property('short_description') || description
414
+ description
421
415
  end
422
416
 
423
417
  # Returns tax category for Product
@@ -479,13 +473,6 @@ module Spree
479
473
  Products::Duplicator.call(product: self)
480
474
  end
481
475
 
482
- # use deleted? rather than checking the attribute directly. this
483
- # allows extensions to override deleted? if they want to provide
484
- # their own definition.
485
- def deleted?
486
- !!deleted_at
487
- end
488
-
489
476
  # determine if product is available.
490
477
  # deleted products and products with status different than active
491
478
  # are not available
@@ -513,14 +500,6 @@ module Spree
513
500
  variants_including_master.any?(&:backordered?)
514
501
  end
515
502
 
516
- # split variants list into hash which shows mapping of opt value onto matching variants
517
- # eg categorise_variants_from_option(color) => {"red" -> [...], "blue" -> [...]}
518
- def categorise_variants_from_option(opt_type)
519
- return {} unless option_types.include?(opt_type)
520
-
521
- variants.active.group_by { |v| v.option_values.detect { |o| o.option_type == opt_type } }
522
- end
523
-
524
503
  def self.like_any(fields, values)
525
504
  conditions = fields.product(values).map do |(field, value)|
526
505
  arel_table[field].matches("%#{value}%")
@@ -537,48 +516,6 @@ module Spree
537
516
  variants.active(current_currency).joins(:option_value_variants)
538
517
  end
539
518
 
540
- def empty_option_values?
541
- options.empty? || options.any? do |opt|
542
- opt.option_type.option_values.empty?
543
- end
544
- end
545
-
546
- def property(property_name)
547
- if product_properties.loaded?
548
- product_properties.detect { |property| property.property.name == property_name }.try(:value)
549
- else
550
- product_properties.joins(:property).find_by(spree_properties: { name: property_name }).try(:value)
551
- end
552
- end
553
-
554
- def set_property(property_name, property_value, property_presentation = property_name)
555
- property_name = property_name.to_s.parameterize
556
- ApplicationRecord.transaction do
557
- # Manual first_or_create to work around Mobility bug
558
- property = if Property.where(name: property_name).exists?
559
- existing_property = Property.where(name: property_name).first
560
- existing_property.presentation ||= property_presentation
561
- existing_property.save
562
- existing_property
563
- else
564
- Property.create(name: property_name, presentation: property_presentation)
565
- end
566
-
567
- product_property = if ProductProperty.where(product: self, property: property).exists?
568
- ProductProperty.where(product: self, property: property).first
569
- else
570
- ProductProperty.new(product: self, property: property)
571
- end
572
-
573
- product_property.value = property_value
574
- product_property.save!
575
- end
576
- end
577
-
578
- def remove_property(property_name)
579
- product_properties.joins(:property).find_by(spree_properties: { name: property_name.parameterize })&.destroy
580
- end
581
-
582
519
  def total_on_hand
583
520
  @total_on_hand ||= if any_variants_not_track_inventory?
584
521
  BigDecimal::INFINITY
@@ -668,9 +605,7 @@ module Spree
668
605
  def taxons_for_store(store)
669
606
  return if classification_count.zero?
670
607
 
671
- Rails.cache.fetch("#{cache_key_with_version}/taxons-per-store/#{store.id}") do
672
- taxons.loaded? ? taxons.find_all { |taxon| taxon.taxonomy.store_id == store.id } : taxons.for_store(store)
673
- end
608
+ taxons.loaded? ? taxons.find_all { |taxon| taxon.taxonomy.store_id == store.id } : taxons.for_store(store)
674
609
  end
675
610
 
676
611
  def any_variant_in_stock_or_backorderable?
@@ -702,7 +637,7 @@ module Spree
702
637
 
703
638
  def to_csv(store = nil)
704
639
  store ||= stores.default || stores.first
705
- properties_for_csv = if Spree::Config[:product_properties_enabled]
640
+ properties_for_csv = if respond_to?(:product_properties) && Spree::Config.respond_to?(:product_properties_enabled) && Spree::Config[:product_properties_enabled]
706
641
  Spree::Property.order(:position).flat_map do |property|
707
642
  [
708
643
  property.name,
@@ -746,9 +681,6 @@ module Spree
746
681
 
747
682
  def add_associations_from_prototype
748
683
  if prototype_id && prototype = Spree::Prototype.find_by(id: prototype_id)
749
- prototype.properties.each do |property|
750
- product_properties.create(property: property, value: 'Placeholder')
751
- end
752
684
  self.option_types = prototype.option_types
753
685
  self.taxons = prototype.taxons
754
686
  end
@@ -190,26 +190,14 @@ module Spree
190
190
  !!eligible_rules(promotable, options)
191
191
  end
192
192
 
193
- # We cache the rules to avoid multiple database queries
194
- # this is useful for orders with many line items
195
- #
196
- # @return [Array<Spree::PromotionRule>]
197
- def cached_rules
198
- Rails.cache.fetch("#{cache_key_with_version}/rules") do
199
- rules.to_a
200
- end
201
- rescue TypeError # when using null_store in test environment
202
- rules.to_a
203
- end
204
-
205
193
  # eligible_rules returns an array of promotion rules where eligible? is true for the promotable
206
194
  # if there are no such rules, an empty array is returned
207
195
  # if the rules make this promotable ineligible, then nil is returned (i.e. this promotable is not eligible)
208
196
  def eligible_rules(promotable, options = {})
209
197
  # Promotions without rules are eligible by default.
210
- return [] if cached_rules.none?
198
+ return [] if rules.none?
211
199
 
212
- specific_rules = cached_rules.select { |rule| rule.applicable?(promotable) }
200
+ specific_rules = rules.select { |rule| rule.applicable?(promotable) }
213
201
  return [] if specific_rules.none?
214
202
 
215
203
  rule_eligibility = Hash[specific_rules.map do |rule|
@@ -177,8 +177,8 @@ module Spree
177
177
 
178
178
  # Check for applied adjustments.
179
179
  discount = order.all_adjustments.promotion.eligible.detect do |p|
180
- p.cached_source.promotion.code.try(:downcase) == coupon_code ||
181
- Spree::CouponCode.unused.where(promotion_id: p.cached_source.promotion_id, code: coupon_code).exists?
180
+ p.source.promotion.code.try(:downcase) == coupon_code ||
181
+ Spree::CouponCode.unused.where(promotion_id: p.source.promotion_id, code: coupon_code).exists?
182
182
  end
183
183
 
184
184
  # Check for applied line items.
@@ -209,7 +209,7 @@ module Spree
209
209
  end
210
210
 
211
211
  def handle_coupon_code(discount, coupon_code)
212
- Spree::CouponCode.unused.find_by(promotion_id: discount.cached_source.promotion_id, code: coupon_code)&.apply_order!(order)
212
+ Spree::CouponCode.unused.find_by(promotion_id: discount.source.promotion_id, code: coupon_code)&.apply_order!(order)
213
213
  end
214
214
 
215
215
  def load_gift_card_code
@@ -4,9 +4,6 @@ module Spree
4
4
 
5
5
  include Spree::Metadata
6
6
 
7
- has_many :property_prototypes, class_name: 'Spree::PropertyPrototype'
8
- has_many :properties, through: :property_prototypes, class_name: 'Spree::Property'
9
-
10
7
  has_many :option_type_prototypes, class_name: 'Spree::OptionTypePrototype'
11
8
  has_many :option_types, through: :option_type_prototypes, class_name: 'Spree::OptionType'
12
9
 
@@ -36,6 +36,10 @@ module Spree
36
36
 
37
37
  delegate :order, :currency, to: :payment
38
38
 
39
+ def amount=(amount)
40
+ self[:amount] = Spree::LocalizedNumber.parse(amount)
41
+ end
42
+
39
43
  def money
40
44
  Spree::Money.new(amount, currency: currency)
41
45
  end
@@ -83,7 +87,7 @@ module Spree
83
87
  update_order
84
88
  end
85
89
 
86
- # return an activemerchant response object if successful or else raise an error
90
+ # return a payment response object if successful or else raise an error
87
91
  def process!(credit_cents)
88
92
  refund_total_in_cents = calculate_refund_amount(credit_cents)
89
93
 
@@ -102,7 +106,7 @@ module Spree
102
106
  end
103
107
 
104
108
  response
105
- rescue ActiveMerchant::ConnectionError => e
109
+ rescue Spree::PaymentConnectionError => e
106
110
  Rails.logger.error(Spree.t(:gateway_error) + " #{e.inspect}")
107
111
  raise Core::GatewayError, Spree.t(:unable_to_connect_to_gateway)
108
112
  end
@@ -2,6 +2,7 @@ module Spree
2
2
  class Shipment < Spree.base_class
3
3
  module Emails
4
4
  def send_shipped_email
5
+ Spree::Deprecation.warn("Shipment#send_shipped_email is deprecated and will be removed in Spree 5.5. Please use events")
5
6
  # you can overwrite this method in your application / extension to send out the confirmation email
6
7
  # or use `spree_emails` gem
7
8
  # YourEmailVendor.deliver_shipment_notification_email(@shipment.id)
@@ -16,10 +16,10 @@ module Spree
16
16
  find_by(name: DIGITAL_NAME)
17
17
  end
18
18
 
19
+ # Returns true if this shipping category includes a digital shipping method
20
+ # @return [Boolean]
19
21
  def includes_digital_shipping_method?
20
- Rails.cache.fetch("#{cache_key_with_version}/includes-digital-shipping-method") do
21
- shipping_methods.digital.exists?
22
- end
22
+ @includes_digital_shipping_method ||= shipping_methods.digital.exists?
23
23
  end
24
24
  end
25
25
  end
@@ -75,7 +75,6 @@ module Spree
75
75
 
76
76
  has_many :store_products, class_name: 'Spree::StoreProduct'
77
77
  has_many :products, through: :store_products, class_name: 'Spree::Product'
78
- has_many :product_properties, through: :products, class_name: 'Spree::ProductProperty'
79
78
  has_many :variants, through: :products, class_name: 'Spree::Variant', source: :variants_including_master
80
79
  has_many :stock_items, through: :variants, class_name: 'Spree::StockItem'
81
80
  has_many :inventory_units, through: :variants, class_name: 'Spree::InventoryUnit'
@@ -93,17 +92,12 @@ module Spree
93
92
 
94
93
  has_many :wishlists, class_name: 'Spree::Wishlist'
95
94
 
96
- has_many :data_feeds, class_name: 'Spree::DataFeed'
97
-
98
95
  belongs_to :default_country, class_name: 'Spree::Country'
99
96
  belongs_to :checkout_zone, class_name: 'Spree::Zone'
100
97
 
101
98
  has_many :reports, class_name: 'Spree::Report'
102
99
  has_many :exports, class_name: 'Spree::Export'
103
100
 
104
- has_many :posts, class_name: 'Spree::Post', dependent: :destroy, inverse_of: :store
105
- has_many :post_categories, class_name: 'Spree::PostCategory', dependent: :destroy, inverse_of: :store
106
-
107
101
  has_many :integrations, class_name: 'Spree::Integration'
108
102
 
109
103
  has_many :gift_cards, class_name: 'Spree::GiftCard', dependent: :destroy
@@ -165,9 +159,7 @@ module Spree
165
159
  after_create :ensure_default_market
166
160
  after_create :ensure_default_taxonomies_are_created
167
161
  after_create :ensure_default_automatic_taxons
168
- after_create :ensure_default_post_categories_are_created
169
162
  after_create :create_default_policies
170
- after_commit :clear_cache
171
163
 
172
164
  #
173
165
  # Scopes
@@ -184,17 +176,15 @@ module Spree
184
176
 
185
177
  # @deprecated The or_initialize behavior will be removed in Spree 5.5.
186
178
  def self.default
187
- Rails.cache.fetch('default_store') do
188
- # workaround for Mobility bug with first_or_initialize
189
- if where(default: true).any?
190
- where(default: true).first
191
- else
192
- Spree::Deprecation.warn(
193
- 'Spree::Store.default returning a new unpersisted store when no default store exists is deprecated ' \
194
- 'and will be removed in Spree 5.5. Please ensure a default store is created before calling Store.default.'
195
- )
196
- new(default: true)
197
- end
179
+ # workaround for Mobility bug with first_or_initialize
180
+ if where(default: true).any?
181
+ where(default: true).first
182
+ else
183
+ Spree::Deprecation.warn(
184
+ 'Spree::Store.default returning a new unpersisted store when no default store exists is deprecated ' \
185
+ 'and will be removed in Spree 5.5. Please ensure a default store is created before calling Store.default.'
186
+ )
187
+ new(default: true)
198
188
  end
199
189
  end
200
190
 
@@ -296,9 +286,7 @@ module Spree
296
286
  # @param country [Spree::Country] the country to get the states for
297
287
  # @return [Array<Spree::State>]
298
288
  def states_available_for_checkout(country)
299
- Rails.cache.fetch(states_available_for_checkout_cache_key(country)) do
300
- country.states.to_a
301
- end
289
+ country.states.to_a
302
290
  end
303
291
 
304
292
  # @deprecated Use {Spree::Zone.all} or {#countries_with_shipping_coverage} instead.
@@ -388,18 +376,6 @@ module Spree
388
376
 
389
377
  private
390
378
 
391
- def countries_available_for_checkout_cache_key
392
- "#{cache_key_with_version}/countries_available_for_checkout"
393
- end
394
-
395
- def states_available_for_checkout_cache_key(country)
396
- "#{cache_key_with_version}/states_available_for_checkout/#{country&.cache_key_with_version}"
397
- end
398
-
399
- def clear_cache
400
- Rails.cache.delete('default_store')
401
- end
402
-
403
379
  def ensure_default_market
404
380
  return if markets.exists?
405
381
 
@@ -463,21 +439,6 @@ module Spree
463
439
  end
464
440
  end
465
441
 
466
- def ensure_default_post_categories_are_created
467
- Spree::Events.disable do
468
- [
469
- translate_with_store_locale_fallback('spree.default_post_categories.resources'),
470
- translate_with_store_locale_fallback('spree.default_post_categories.articles'),
471
- translate_with_store_locale_fallback('spree.default_post_categories.news')
472
- ].each do |category_title|
473
- # Use exists?/create pattern for safety
474
- next if post_categories.where(title: category_title).exists?
475
-
476
- post_categories.create(title: category_title)
477
- end
478
- end
479
- end
480
-
481
442
  def create_default_policies
482
443
  Spree::Events.disable do
483
444
  [
@@ -54,6 +54,10 @@ module Spree
54
54
  extend Spree::DisplayMoney
55
55
  money_methods :amount, :amount_used, :amount_remaining, :amount_authorized
56
56
 
57
+ def amount=(amount)
58
+ self[:amount] = Spree::LocalizedNumber.parse(amount)
59
+ end
60
+
57
61
  self.whitelisted_ransackable_attributes = %w[user_id created_by_id amount currency type_id]
58
62
  self.whitelisted_ransackable_associations = %w[type user created_by]
59
63
 
@@ -10,15 +10,11 @@ module Spree
10
10
  has_many :variants, dependent: :nullify
11
11
 
12
12
  before_save :set_default_category
13
- after_update :delete_cache
14
- after_create :delete_cache
15
13
 
16
14
  self.whitelisted_ransackable_attributes = %w[name is_default tax_code]
17
15
 
18
16
  def self.default
19
- Rails.cache.fetch('default_tax_category') do
20
- find_by(is_default: true)
21
- end
17
+ find_by(is_default: true)
22
18
  end
23
19
 
24
20
  def set_default_category
@@ -28,11 +24,5 @@ module Spree
28
24
  tax_category.update_columns(is_default: false, updated_at: Time.current)
29
25
  end
30
26
  end
31
-
32
- private
33
-
34
- def delete_cache
35
- Rails.cache.delete('default_tax_category')
36
- end
37
27
  end
38
28
  end
@@ -38,8 +38,6 @@ module Spree
38
38
  has_one :store, through: :taxonomy
39
39
  has_many :classifications, -> { order(:position) }, dependent: :destroy_async, inverse_of: :taxon
40
40
  has_many :products, through: :classifications
41
- # @deprecated Use Spree::Taxon#image (Active Storage) instead. Will be removed in Spree 5.5.
42
- has_one :icon, as: :viewable, dependent: :destroy, class_name: 'Spree::TaxonImage'
43
41
 
44
42
  has_many :prototype_taxons, class_name: 'Spree::PrototypeTaxon', dependent: :destroy
45
43
  has_many :prototypes, through: :prototype_taxons, class_name: 'Spree::Prototype'
@@ -60,7 +58,6 @@ module Spree
60
58
  validates :taxonomy, presence: true
61
59
  validates :permalink, uniqueness: { case_sensitive: false, scope: [:parent_id, :taxonomy_id] }
62
60
  validates :hide_from_nav, inclusion: { in: [true, false] }
63
- validates_associated :icon
64
61
  validate :check_for_root, on: :create
65
62
  validate :parent_belongs_to_same_taxonomy
66
63
  with_options length: { maximum: 255 }, allow_blank: true do
@@ -312,19 +309,6 @@ module Spree
312
309
  end
313
310
  end
314
311
 
315
- # indicate which filters should be used for a taxon
316
- # this method should be customized to your own site
317
- def applicable_filters
318
- Spree::Deprecation.warn('applicable_filters is deprecated and will be removed in Spree 5.5')
319
- fs = []
320
- # fs << ProductFilters.taxons_below(self)
321
- ## unless it's a root taxon? left open for demo purposes
322
-
323
- fs << Spree::Core::ProductFilters.price_filter if Spree::Core::ProductFilters.respond_to?(:price_filter)
324
- fs << Spree::Core::ProductFilters.brand_filter if Spree::Core::ProductFilters.respond_to?(:brand_filter)
325
- fs
326
- end
327
-
328
312
  # Return meta_title if set otherwise generates from taxon name
329
313
  def seo_title
330
314
  meta_title.blank? ? name : meta_title
@@ -88,8 +88,6 @@ module Spree
88
88
  after_create :increment_product_variant_count, unless: :is_master?
89
89
  after_destroy :decrement_product_variant_count, unless: :is_master?
90
90
 
91
- after_touch :clear_in_stock_cache
92
-
93
91
  scope :in_stock, -> { left_joins(:stock_items).where("#{Spree::Variant.table_name}.track_inventory = ? OR #{Spree::StockItem.table_name}.count_on_hand > ?", false, 0) }
94
92
  scope :backorderable, -> { left_joins(:stock_items).where(spree_stock_items: { backorderable: true }) }
95
93
  scope :in_stock_or_backorderable, -> { in_stock.or(backorderable) }
@@ -281,14 +279,6 @@ module Spree
281
279
  is_master? ? name + ' - Master' : name + ' - ' + options_text
282
280
  end
283
281
 
284
- # use deleted? rather than checking the attribute directly. this
285
- # allows extensions to override deleted? if they want to provide
286
- # their own definition.
287
- # @return [Boolean] true if the variant is deleted.
288
- def deleted?
289
- !!deleted_at
290
- end
291
-
292
282
  # Returns true if the variant has images.
293
283
  # Uses loaded association when available, otherwise falls back to counter cache.
294
284
  # @return [Boolean]
@@ -532,36 +522,16 @@ module Spree
532
522
  @compare_at_price ||= price_in(cost_currency).try(:compare_at_amount)
533
523
  end
534
524
 
535
- # Returns the name and sku of the variant.
536
- # @return [String] the name and sku of the variant
537
- def name_and_sku
538
- "#{name} - #{sku}"
539
- end
540
-
541
- # Returns the sku and options text of the variant.
542
- # @return [String] the sku and options text of the variant
543
- def sku_and_options_text
544
- "#{sku} #{options_text}".strip
545
- end
546
-
547
525
  # Returns true if the variant is in stock.
548
526
  # @return [Boolean] true if the variant is in stock
549
527
  def in_stock?
550
- @in_stock ||= if association(:stock_items).loaded? && association(:stock_locations).loaded?
551
- total_on_hand.positive?
552
- else
553
- Rails.cache.fetch(in_stock_cache_key, version: cache_version) do
554
- total_on_hand.positive?
555
- end
556
- end
528
+ @in_stock ||= total_on_hand.positive?
557
529
  end
558
530
 
559
531
  # Returns true if the variant is backorderable.
560
532
  # @return [Boolean] true if the variant is backorderable
561
533
  def backorderable?
562
- @backorderable ||= Rails.cache.fetch(['variant-backorderable', cache_key_with_version]) do
563
- quantifier.backorderable?
564
- end
534
+ @backorderable ||= quantifier.backorderable?
565
535
  end
566
536
 
567
537
  def on_sale?(currency)
@@ -619,10 +589,6 @@ module Spree
619
589
  digitals.any?
620
590
  end
621
591
 
622
- def clear_in_stock_cache
623
- Rails.cache.delete(in_stock_cache_key)
624
- end
625
-
626
592
  private
627
593
 
628
594
  def ensure_not_in_complete_orders
@@ -674,10 +640,6 @@ module Spree
674
640
  end
675
641
  end
676
642
 
677
- def in_stock_cache_key
678
- "variant-#{id}-in_stock"
679
- end
680
-
681
643
  def disable_sku_validation?
682
644
  Spree::Config[:disable_sku_validation]
683
645
  end
@@ -27,9 +27,7 @@ module Spree
27
27
  self.whitelisted_ransackable_attributes = ['description']
28
28
 
29
29
  def self.default_tax
30
- Rails.cache.fetch('default_tax') do
31
- find_by(default_tax: true)
32
- end
30
+ Spree::Current.default_tax_zone
33
31
  end
34
32
 
35
33
  def self.potential_matching_zones(zone)
@@ -186,7 +184,6 @@ module Spree
186
184
 
187
185
  def remove_previous_default
188
186
  Spree::Zone.with_default_tax.where.not(id: id).update_all(default_tax: false)
189
- Rails.cache.delete('default_zone')
190
187
  end
191
188
 
192
189
  def set_zone_members(ids, type)
@@ -3,7 +3,7 @@ module Spree
3
3
  class AddItem
4
4
  prepend Spree::ServiceModule::Base
5
5
 
6
- def call(order:, variant:, quantity: nil, public_metadata: {}, private_metadata: {}, options: {})
6
+ def call(order:, variant:, quantity: nil, metadata: {}, public_metadata: {}, private_metadata: {}, options: {})
7
7
  ApplicationRecord.transaction do
8
8
  run :add_to_line_item
9
9
  run Spree.cart_recalculate_service
@@ -12,7 +12,7 @@ module Spree
12
12
 
13
13
  private
14
14
 
15
- def add_to_line_item(order:, variant:, quantity: nil, public_metadata: {}, private_metadata: {}, options: {})
15
+ def add_to_line_item(order:, variant:, quantity: nil, metadata: {}, public_metadata: {}, private_metadata: {}, options: {})
16
16
  options ||= {}
17
17
  quantity ||= 1
18
18
 
@@ -34,8 +34,12 @@ module Spree
34
34
  end
35
35
 
36
36
  line_item.target_shipment = options[:shipment] if options.key? :shipment
37
- line_item.public_metadata = public_metadata.to_h if public_metadata
38
- line_item.private_metadata = private_metadata.to_h if private_metadata
37
+
38
+ # `metadata` is the primary API param (maps to private_metadata).
39
+ # Legacy `public_metadata`/`private_metadata` params kept for backward compatibility.
40
+ resolved_metadata = metadata.presence || private_metadata
41
+ line_item.metadata = resolved_metadata.to_h if resolved_metadata.present?
42
+ line_item.public_metadata = public_metadata.to_h if public_metadata.present?
39
43
 
40
44
  return failure(line_item) unless line_item.save
41
45
 
@@ -3,18 +3,29 @@ module Spree
3
3
  class Create
4
4
  prepend Spree::ServiceModule::Base
5
5
 
6
- def call(user:, store:, currency:, public_metadata: {}, private_metadata: {}, order_params: {})
6
+ # @param user [Spree.user_class, nil] the user to associate with the cart
7
+ # @param store [Spree::Store] the store for the cart
8
+ # @param currency [String, nil] ISO currency code, defaults to store's default currency
9
+ # @param locale [String, nil] locale for the cart (e.g. 'en', 'fr'), defaults to Spree::Current.locale
10
+ # @param public_metadata [Hash] public metadata for the order
11
+ # @param private_metadata [Hash] private metadata for the order
12
+ # @param order_params [Hash] additional order attributes
13
+ # @return [Spree::ServiceModule::Result]
14
+ def call(user:, store:, currency:, locale: nil, metadata: {}, public_metadata: {}, private_metadata: {}, order_params: {})
7
15
  order_params ||= {}
8
16
 
9
17
  # we cannot create an order without store
10
18
  return failure(:store_is_required) if store.nil?
11
19
 
20
+ resolved_metadata = metadata.presence || private_metadata
21
+
12
22
  default_params = {
13
23
  user: user,
14
24
  currency: currency || store.default_currency,
25
+ locale: locale || Spree::Current.locale,
15
26
  token: Spree::GenerateToken.new.call(Spree::Order),
16
27
  public_metadata: public_metadata.to_h,
17
- private_metadata: private_metadata.to_h
28
+ private_metadata: resolved_metadata.to_h
18
29
  }
19
30
 
20
31
  order = store.orders.create!(default_params.merge(order_params))
@@ -13,8 +13,6 @@ module Spree
13
13
  new_product.send(:duplicate_extra, product) if new_product.respond_to?(:duplicate_extra)
14
14
  new_product.save
15
15
 
16
- new_product.product_properties = duplicate_properties(product.product_properties) if new_product.persisted?
17
-
18
16
  new_product.persisted? ? success(new_product) : failure(new_product, duplicate_error_message(new_product))
19
17
  end
20
18
 
@@ -89,16 +87,6 @@ module Spree
89
87
  new_image
90
88
  end
91
89
 
92
- def duplicate_properties(product_properties)
93
- product_properties.map do |prop|
94
- new_prop = prop.dup
95
- new_prop.product = nil
96
- new_prop.created_at = nil
97
- new_prop.updated_at = nil
98
- new_prop
99
- end
100
- end
101
-
102
90
  def sku_generator(sku)
103
91
  return '' if sku.blank?
104
92
 
@@ -61,18 +61,6 @@ module Spree
61
61
  end
62
62
  end
63
63
 
64
- # mark resource properties to be removed
65
- # when value is left blank
66
- if params[:product_properties_attributes].present?
67
- params[:product_properties_attributes].each do |key, product_property_params|
68
- next unless product_property_params[:id].present?
69
- next if product_property_params[:value].present?
70
-
71
- # https://api.rubyonrails.org/v7.1.3.4/classes/ActiveRecord/NestedAttributes/ClassMethods.html
72
- params[:product_properties_attributes][key]['_destroy'] = '1'
73
- end
74
- end
75
-
76
64
  # ensure there is at least one store
77
65
  params[:store_ids] = [store.id] if params[:store_ids].blank?
78
66