spree_core 5.4.1 → 5.4.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/app/jobs/spree/events/subscriber_job.rb +1 -1
  3. data/app/jobs/spree/imports/process_group_job.rb +45 -0
  4. data/app/jobs/spree/imports/process_rows_job.rb +51 -5
  5. data/app/models/concerns/spree/payment_source_concern.rb +21 -0
  6. data/app/models/concerns/spree/publishable.rb +1 -1
  7. data/app/models/spree/address.rb +1 -1
  8. data/app/models/spree/asset.rb +9 -9
  9. data/app/models/spree/event.rb +6 -6
  10. data/app/models/spree/export.rb +2 -2
  11. data/app/models/spree/exports/product_translations.rb +1 -1
  12. data/app/models/spree/gateway/bogus.rb +16 -7
  13. data/app/models/spree/import.rb +15 -0
  14. data/app/models/spree/import_row.rb +14 -2
  15. data/app/models/spree/imports/product_translations.rb +4 -0
  16. data/app/models/spree/imports/products.rb +5 -0
  17. data/app/models/spree/line_item.rb +1 -1
  18. data/app/models/spree/market.rb +25 -0
  19. data/app/models/spree/order_inventory.rb +24 -2
  20. data/app/models/spree/payment.rb +1 -0
  21. data/app/models/spree/payment_session.rb +5 -0
  22. data/app/models/spree/payment_setup_sessions/bogus.rb +4 -0
  23. data/app/models/spree/product.rb +5 -10
  24. data/app/models/spree/search_provider/base.rb +13 -1
  25. data/app/models/spree/search_provider/database.rb +44 -29
  26. data/app/models/spree/search_provider/filters_result.rb +5 -0
  27. data/app/models/spree/search_provider/meilisearch.rb +99 -82
  28. data/app/models/spree/search_provider/search_result.rb +1 -1
  29. data/app/models/spree/shipment.rb +10 -4
  30. data/app/models/spree/subscriber.rb +12 -12
  31. data/app/presenters/spree/csv/formula_sanitizer.rb +28 -0
  32. data/app/services/spree/credit_cards/destroy.rb +10 -26
  33. data/app/services/spree/gift_cards/apply.rb +5 -1
  34. data/app/services/spree/imports/row_processors/base.rb +19 -2
  35. data/app/services/spree/imports/row_processors/product_translation.rb +1 -1
  36. data/app/services/spree/imports/row_processors/product_variant.rb +1 -1
  37. data/app/services/spree/payments/handle_webhook.rb +8 -9
  38. data/app/subscribers/spree/event_log_subscriber.rb +10 -8
  39. data/config/initializers/carmen.rb +23 -0
  40. data/config/locales/en.yml +8 -1
  41. data/db/migrate/20260424000001_add_unique_index_to_spree_payments_response_code.rb +51 -0
  42. data/db/migrate/20260424100000_add_processing_groups_to_spree_imports.rb +6 -0
  43. data/db/migrate/20260504103113_add_type_to_spree_payment_setup_sessions.rb +6 -0
  44. data/db/sample_data/orders.rb +1 -1
  45. data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
  46. data/lib/spree/core/configuration.rb +3 -0
  47. data/lib/spree/core/engine.rb +3 -6
  48. data/lib/spree/core/version.rb +1 -1
  49. data/lib/spree/events/adapters/active_support_notifications.rb +1 -1
  50. data/lib/spree/events/adapters/base.rb +3 -3
  51. data/lib/spree/events/registry.rb +1 -1
  52. data/lib/spree/events.rb +7 -1
  53. data/lib/spree/testing_support/factories/payment_factory.rb +1 -1
  54. metadata +16 -8
@@ -0,0 +1,23 @@
1
+ # Patches Carmen::Querying#normalise_name to avoid the deprecated
2
+ # ActiveSupport::Multibyte::Chars API (mb_chars), which will be removed in
3
+ # Rails 8.2.
4
+ #
5
+ # In Ruby 2.4+, String#downcase is already Unicode-aware, making the mb_chars
6
+ # call redundant. Since Spree requires Ruby >= 3.2, we can drop it safely.
7
+ #
8
+ # This patch can be removed once the upstream gem is fixed.
9
+ #
10
+ # See: https://github.com/carmen-ruby/carmen/issues/304
11
+ require 'carmen'
12
+
13
+ module Spree
14
+ module CarmenQueryingPatch
15
+ private
16
+
17
+ def normalise_name(name)
18
+ name.downcase.unicode_normalize(:nfkc)
19
+ end
20
+ end
21
+ end
22
+
23
+ Carmen::Querying.prepend(Spree::CarmenQueryingPatch)
@@ -299,6 +299,11 @@ en:
299
299
  attributes:
300
300
  currency:
301
301
  must_match_order_currency: Must match order currency
302
+ spree/market:
303
+ attributes:
304
+ base:
305
+ cannot_destroy_default_market: Cannot delete the default market.
306
+ cannot_destroy_last_market: Cannot delete the only market.
302
307
  spree/market_country:
303
308
  attributes:
304
309
  country:
@@ -1311,6 +1316,9 @@ en:
1311
1316
  inventory_error_flash_for_insufficient_quantity: An item in your cart has become unavailable.
1312
1317
  inventory_state: Inventory State
1313
1318
  invitation_accepted: Invitation accepted!
1319
+ invitation_expired:
1320
+ body: This invitation link is no longer valid. Please ask the person who invited you to send a new one.
1321
+ heading: Invitation invalid or expired
1314
1322
  invitation_mailer:
1315
1323
  greeting: Hi %{user_name},
1316
1324
  invitation_accepted:
@@ -1342,7 +1350,6 @@ en:
1342
1350
  items_in_rmas: Items in Return Authorizations
1343
1351
  items_reimbursed: Items reimbursed
1344
1352
  items_to_be_reimbursed: Items to be reimbursed
1345
- join_slack: Join Slack
1346
1353
  key: Key
1347
1354
  kind: Kind
1348
1355
  label: Label
@@ -0,0 +1,51 @@
1
+ class AddUniqueIndexToSpreePaymentsResponseCode < ActiveRecord::Migration[7.2]
2
+ def up
3
+ # Remove duplicate payments per (order, payment_method, response_code),
4
+ # preferring to keep completed payments over incomplete ones.
5
+ # Among same-state duplicates, keeps the most recent (highest id).
6
+ # Uses derived table for MySQL compatibility.
7
+ execute <<~SQL
8
+ DELETE FROM spree_payments
9
+ WHERE response_code IS NOT NULL
10
+ AND id NOT IN (
11
+ SELECT keeper_id FROM (
12
+ SELECT (
13
+ SELECT id FROM spree_payments p2
14
+ WHERE p2.order_id = p1.order_id
15
+ AND p2.payment_method_id = p1.payment_method_id
16
+ AND p2.response_code = p1.response_code
17
+ ORDER BY
18
+ CASE p2.state
19
+ WHEN 'completed' THEN 0
20
+ WHEN 'pending' THEN 1
21
+ WHEN 'processing' THEN 2
22
+ ELSE 3
23
+ END,
24
+ p2.id DESC
25
+ LIMIT 1
26
+ ) AS keeper_id
27
+ FROM spree_payments p1
28
+ WHERE p1.response_code IS NOT NULL
29
+ GROUP BY p1.order_id, p1.payment_method_id, p1.response_code
30
+ ) AS keeper_ids
31
+ )
32
+ SQL
33
+
34
+ if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
35
+ # MySQL doesn't support partial indexes, but treats NULL as distinct
36
+ # in unique indexes so multiple payments with NULL response_code are allowed
37
+ add_index :spree_payments, [:order_id, :payment_method_id, :response_code],
38
+ unique: true,
39
+ name: 'idx_payments_order_method_response_code'
40
+ else
41
+ add_index :spree_payments, [:order_id, :payment_method_id, :response_code],
42
+ unique: true,
43
+ where: 'response_code IS NOT NULL',
44
+ name: 'idx_payments_order_method_response_code'
45
+ end
46
+ end
47
+
48
+ def down
49
+ remove_index :spree_payments, name: 'idx_payments_order_method_response_code'
50
+ end
51
+ end
@@ -0,0 +1,6 @@
1
+ class AddProcessingGroupsToSpreeImports < ActiveRecord::Migration[7.2]
2
+ def change
3
+ add_column :spree_imports, :processing_groups_count, :integer, default: 0
4
+ add_column :spree_imports, :completed_groups_count, :integer, default: 0
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class AddTypeToSpreePaymentSetupSessions < ActiveRecord::Migration[7.2]
2
+ def change
3
+ add_column :spree_payment_setup_sessions, :type, :string
4
+ add_index :spree_payment_setup_sessions, :type
5
+ end
6
+ end
@@ -122,7 +122,7 @@ if method
122
122
  source: credit_card.clone,
123
123
  payment_method: method
124
124
  ).first_or_create!
125
- payment.update_columns(state: 'pending', response_code: '12345')
125
+ payment.update_columns(state: 'pending', response_code: "BGS-#{SecureRandom.hex(6)}")
126
126
  end
127
127
  end
128
128
 
@@ -106,7 +106,7 @@ module Spree
106
106
  def inject_yaml_permitted_classes
107
107
  inside dummy_path do
108
108
  inject_into_file 'config/application.rb', %Q[
109
- config.active_record.yaml_column_permitted_classes = [Symbol, BigDecimal, ActiveSupport::HashWithIndifferentAccess, ActiveSupport::TimeWithZone]
109
+ config.active_record.yaml_column_permitted_classes = [Symbol, BigDecimal, ActiveSupport::HashWithIndifferentAccess, ActiveSupport::TimeWithZone, ActiveSupport::TimeZone, Time]
110
110
  ], after: /config\.load_defaults.*$/, verbose: true
111
111
  end
112
112
  end
@@ -117,6 +117,9 @@ module Spree
117
117
  preference :gift_card_batch_web_limit, :integer, default: 500 # number of gift card codes to be generated in the web process, more than this will be generated in a background job
118
118
  preference :gift_card_batch_limit, :integer, default: 50_000
119
119
 
120
+ # imports
121
+ preference :large_import_threshold, :integer, default: 500 # imports with more rows than this skip per-row UI broadcasts and use bulk processing
122
+
120
123
  end
121
124
  end
122
125
  end
@@ -47,7 +47,7 @@ module Spree
47
47
  app.config.spree = Environment.new(SpreeCalculators.new, SpreeValidators.new, Spree::Core::Configuration.new, Spree::Core::Dependencies.new)
48
48
 
49
49
  app.config.active_record.yaml_column_permitted_classes ||= []
50
- app.config.active_record.yaml_column_permitted_classes.concat([Symbol, BigDecimal, ActiveSupport::HashWithIndifferentAccess, ActiveSupport::TimeWithZone])
50
+ app.config.active_record.yaml_column_permitted_classes.concat([Symbol, BigDecimal, ActiveSupport::HashWithIndifferentAccess, ActiveSupport::TimeWithZone, ActiveSupport::TimeZone, Time])
51
51
  Spree::Config = app.config.spree.preferences
52
52
  Spree::RuntimeConfig = app.config.spree.preferences # for compatibility
53
53
  Spree::Dependencies = app.config.spree.dependencies
@@ -289,13 +289,10 @@ module Spree
289
289
  Spree::Addresses::PhoneValidator
290
290
  ]
291
291
 
292
- # Attach event log subscriber if enabled
293
- if Spree::Config.events_log_enabled
294
- Spree::EventLogSubscriber.attach_to_notifications
295
- end
296
-
297
292
  # Add core event subscribers
298
293
  # Other engines add their subscribers in their own after_initialize blocks
294
+ # Note: Spree::EventLogSubscriber is attached in to_prepare (below) so it
295
+ # survives Zeitwerk code reloads in development.
299
296
  Spree.subscribers.concat [
300
297
  Spree::ExportSubscriber,
301
298
  Spree::ReportSubscriber,
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- VERSION = '5.4.1'.freeze
2
+ VERSION = '5.4.3'.freeze
3
3
 
4
4
  def self.version
5
5
  VERSION
@@ -12,7 +12,7 @@ module Spree
12
12
  #
13
13
  # @example Publishing an event
14
14
  # adapter = ActiveSupportNotifications.new(registry)
15
- # adapter.publish('order.complete', { id: 1 })
15
+ # adapter.publish('order.completed', { id: 1 })
16
16
  #
17
17
  class ActiveSupportNotifications < Base
18
18
  NAMESPACE = 'spree'
@@ -43,13 +43,13 @@ module Spree
43
43
 
44
44
  # Publish an event to all matching subscribers.
45
45
  #
46
- # @param event_name [String] the event name (e.g., 'order.complete')
46
+ # @param event_name [String] the event name (e.g., 'order.completed')
47
47
  # @param payload [Hash] the event payload (should be serializable)
48
48
  # @param metadata [Hash] additional metadata for the event
49
49
  # @return [Spree::Event] the published event
50
50
  #
51
51
  # @example
52
- # adapter.publish('order.complete', order.serializable_hash, { user_id: 1 })
52
+ # adapter.publish('order.completed', order.serializable_hash, { user_id: 1 })
53
53
  #
54
54
  def publish(event_name, payload, metadata = {})
55
55
  raise NotImplementedError, "#{self.class}#publish must be implemented"
@@ -67,7 +67,7 @@ module Spree
67
67
  # @option options [Boolean] :async (true) whether to run async via ActiveJob
68
68
  #
69
69
  # @example
70
- # adapter.subscribe('order.complete', MySubscriber)
70
+ # adapter.subscribe('order.completed', MySubscriber)
71
71
  # adapter.subscribe('order.*', AuditLogger, async: false)
72
72
  #
73
73
  def subscribe(pattern, subscriber, options = {})
@@ -15,7 +15,7 @@ module Spree
15
15
  # @example
16
16
  # registry = Spree::Events::Registry.new
17
17
  # registry.register('order.*', MySubscriber, async: true)
18
- # registry.subscriptions_for('order.complete') # => [Subscription]
18
+ # registry.subscriptions_for('order.completed') # => [Subscription]
19
19
  #
20
20
  class Registry
21
21
  # Immutable subscription data using Ruby 3.2+ Data class
data/lib/spree/events.rb CHANGED
@@ -28,9 +28,15 @@ module Spree
28
28
  #
29
29
  module Events
30
30
  class << self
31
+ # Reference to the AS::N subscription created by Spree::EventLogSubscriber.
32
+ # Stored here (on a module in lib/, not reloaded by Zeitwerk) so that code
33
+ # reloads in development don't orphan the subscription and cause events to
34
+ # be logged multiple times.
35
+ attr_accessor :log_subscription
36
+
31
37
  # Publish an event to all matching subscribers
32
38
  #
33
- # @param name [String] The event name (e.g., 'order.complete')
39
+ # @param name [String] The event name (e.g., 'order.completed')
34
40
  # @param payload [Hash] The event payload (should be serializable)
35
41
  # @param metadata [Hash] Additional metadata for the event
36
42
  # @return [Spree::Event] The published event
@@ -3,7 +3,7 @@ FactoryBot.define do
3
3
  order { create(:order, total: amount) }
4
4
  amount { 45.75 }
5
5
  state { 'checkout' }
6
- response_code { '12345' }
6
+ response_code { "BGS-#{SecureRandom.hex(6)}" }
7
7
 
8
8
  payment_method { create(:credit_card_payment_method, stores: [order.store]) }
9
9
  association(:source, factory: :credit_card)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.1
4
+ version: 5.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sean Schofield
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2026-04-14 00:00:00.000000000 Z
13
+ date: 2026-05-19 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: i18n-tasks
@@ -590,16 +590,16 @@ dependencies:
590
590
  name: pagy
591
591
  requirement: !ruby/object:Gem::Requirement
592
592
  requirements:
593
- - - "~>"
593
+ - - ">="
594
594
  - !ruby/object:Gem::Version
595
- version: '43.0'
595
+ version: '43.3'
596
596
  type: :runtime
597
597
  prerelease: false
598
598
  version_requirements: !ruby/object:Gem::Requirement
599
599
  requirements:
600
- - - "~>"
600
+ - - ">="
601
601
  - !ruby/object:Gem::Version
602
- version: '43.0'
602
+ version: '43.3'
603
603
  description: Spree Models, Helpers, Services and core libraries
604
604
  email: hello@spreecommerce.org
605
605
  executables: []
@@ -865,6 +865,7 @@ files:
865
865
  - app/jobs/spree/gift_cards/bulk_generate_job.rb
866
866
  - app/jobs/spree/images/save_from_url_job.rb
867
867
  - app/jobs/spree/imports/create_rows_job.rb
868
+ - app/jobs/spree/imports/process_group_job.rb
868
869
  - app/jobs/spree/imports/process_rows_job.rb
869
870
  - app/jobs/spree/payments/handle_webhook_job.rb
870
871
  - app/jobs/spree/products/auto_match_taxons_job.rb
@@ -1051,6 +1052,7 @@ files:
1051
1052
  - app/models/spree/payment_session.rb
1052
1053
  - app/models/spree/payment_sessions/bogus.rb
1053
1054
  - app/models/spree/payment_setup_session.rb
1055
+ - app/models/spree/payment_setup_sessions/bogus.rb
1054
1056
  - app/models/spree/payment_source.rb
1055
1057
  - app/models/spree/permission_sets/base.rb
1056
1058
  - app/models/spree/permission_sets/configuration_management.rb
@@ -1150,6 +1152,7 @@ files:
1150
1152
  - app/models/spree/role_user.rb
1151
1153
  - app/models/spree/search_provider/base.rb
1152
1154
  - app/models/spree/search_provider/database.rb
1155
+ - app/models/spree/search_provider/filters_result.rb
1153
1156
  - app/models/spree/search_provider/meilisearch.rb
1154
1157
  - app/models/spree/search_provider/search_result.rb
1155
1158
  - app/models/spree/shipment.rb
@@ -1216,6 +1219,7 @@ files:
1216
1219
  - app/paginators/spree/shared/paginate.rb
1217
1220
  - app/presenters/spree/csv/coupon_code_presenter.rb
1218
1221
  - app/presenters/spree/csv/customer_presenter.rb
1222
+ - app/presenters/spree/csv/formula_sanitizer.rb
1219
1223
  - app/presenters/spree/csv/gift_card_presenter.rb
1220
1224
  - app/presenters/spree/csv/metafields_helper.rb
1221
1225
  - app/presenters/spree/csv/newsletter_subscriber_presenter.rb
@@ -1365,6 +1369,7 @@ files:
1365
1369
  - config/importmap.rb
1366
1370
  - config/initializers/active_storage.rb
1367
1371
  - config/initializers/acts_as_taggable_on.rb
1372
+ - config/initializers/carmen.rb
1368
1373
  - config/initializers/friendly_id.rb
1369
1374
  - config/initializers/inflections.rb
1370
1375
  - config/initializers/mobility.rb
@@ -1509,6 +1514,9 @@ files:
1509
1514
  - db/migrate/20260402000002_add_color_code_to_spree_option_values.rb
1510
1515
  - db/migrate/20260403000000_add_market_to_spree_orders.rb
1511
1516
  - db/migrate/20260408000001_add_unique_index_to_spree_zone_members.rb
1517
+ - db/migrate/20260424000001_add_unique_index_to_spree_payments_response_code.rb
1518
+ - db/migrate/20260424100000_add_processing_groups_to_spree_imports.rb
1519
+ - db/migrate/20260504103113_add_type_to_spree_payment_setup_sessions.rb
1512
1520
  - db/sample_data/customers.csv
1513
1521
  - db/sample_data/markets.rb
1514
1522
  - db/sample_data/metafield_definitions.rb
@@ -1739,9 +1747,9 @@ licenses:
1739
1747
  - BSD-3-Clause
1740
1748
  metadata:
1741
1749
  bug_tracker_uri: https://github.com/spree/spree/issues
1742
- changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.1
1750
+ changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.3
1743
1751
  documentation_uri: https://docs.spreecommerce.org/
1744
- source_code_uri: https://github.com/spree/spree/tree/v5.4.1
1752
+ source_code_uri: https://github.com/spree/spree/tree/v5.4.3
1745
1753
  post_install_message:
1746
1754
  rdoc_options: []
1747
1755
  require_paths: