spree_core 5.1.4 → 5.1.6

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/app/jobs/spree/products/touch_taxons_job.rb +1 -0
  3. data/app/models/spree/credit_card.rb +20 -0
  4. data/app/models/spree/order/digital.rb +15 -0
  5. data/app/models/spree/order_inventory.rb +1 -1
  6. data/app/models/spree/page_link.rb +1 -1
  7. data/app/models/spree/page_section.rb +7 -0
  8. data/app/models/spree/page_sections/announcement_bar.rb +0 -2
  9. data/app/models/spree/page_sections/featured_posts.rb +0 -2
  10. data/app/models/spree/page_sections/featured_taxon.rb +5 -2
  11. data/app/models/spree/page_sections/related_products.rb +0 -2
  12. data/app/models/spree/product.rb +7 -6
  13. data/app/models/spree/shipment.rb +21 -5
  14. data/app/models/spree/shipping_method.rb +10 -0
  15. data/app/models/spree/store.rb +1 -1
  16. data/app/models/spree/tax_rate.rb +14 -3
  17. data/app/models/spree/variant.rb +15 -1
  18. data/app/models/spree/zone.rb +7 -0
  19. data/app/services/spree/products/prepare_nested_attributes.rb +12 -2
  20. data/app/services/spree/taxons/add_products.rb +4 -1
  21. data/app/services/spree/taxons/remove_products.rb +4 -1
  22. data/app/views/spree/invitation_mailer/invitation_email.html.erb +1 -1
  23. data/config/importmap.rb +1 -0
  24. data/config/locales/en.yml +4 -0
  25. data/db/migrate/20250304115943_add_performed_by_to_spree_reimbursements.rb +1 -1
  26. data/lib/generators/spree/dummy/dummy_generator.rb +7 -39
  27. data/lib/generators/spree/install/install_generator.rb +0 -19
  28. data/lib/spree/core/configuration.rb +1 -1
  29. data/lib/spree/core/engine.rb +1 -1
  30. data/lib/spree/core/version.rb +1 -1
  31. data/lib/spree/core.rb +1 -1
  32. data/lib/spree/permitted_attributes.rb +2 -2
  33. data/lib/spree/testing_support/common_rake.rb +32 -14
  34. data/vendor/javascript/stimulus-textarea-autogrow.js +4 -0
  35. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90be1a32290303d4feb6a777d2a5ed2d88232edfa9998e748299df632346543f
4
- data.tar.gz: 63b6aebfc73bdb8e56e945471245cb2ac4bff7afb09db4d4377b753ba6bcfe06
3
+ metadata.gz: 8b7ada6c326700f36766e181d422238f5fc9c8e345b92b37df8d5c2ed5e1b56c
4
+ data.tar.gz: 86b6aabcab0463033b6a8e045445b8b7b90109f9f8a7d5e3084ffad2d5093bab
5
5
  SHA512:
6
- metadata.gz: 6f4cd428b66cee1b390d3710ff2d33d71a4d4ffcfa8648672937eb748a6c91993e1ec8d23495b099e25efc8790a8d0a093d849339f5659be6097ffb878bde293
7
- data.tar.gz: 5c7186492fe423d5b8862771dd3767ad9f9d9fb5c00bd71a434c19a5b3d938c9a071579aa54594f235ad16e0c9bac64bfbab8d286a0f40ae5522cffe8c453b82
6
+ metadata.gz: cc6d619e2582cc97f6444f55f49db531cc5adc7dcc9c5349e6401c8d15d26c23b2e46d25219135a2a73841c2ddf207e5ab76d3e6cebcf584128118636bc714a3
7
+ data.tar.gz: ce1337606b76a87689543518feb7dcac21d7ed3b62bfb3d14a1b703a0a90da357c8d9476228971c01a63b850152311ef68c2fdec3f4ee620b0631c9e845e6bf8
@@ -6,6 +6,7 @@ module Spree
6
6
  def perform(taxon_ids, taxonomy_ids)
7
7
  Spree::Taxon.where(id: taxon_ids).update_all(updated_at: Time.current)
8
8
  Spree::Taxonomy.where(id: taxonomy_ids).update_all(updated_at: Time.current)
9
+ Spree::Taxons::TouchFeaturedSections.call(taxon_ids: taxon_ids)
9
10
  end
10
11
  end
11
12
  end
@@ -51,6 +51,14 @@ module Spree
51
51
  # needed for some of the ActiveMerchant gateways (eg. SagePay)
52
52
  alias_attribute :brand, :cc_type
53
53
 
54
+ store_accessor :private_metadata, :wallet
55
+
56
+ # Returns the type of wallet the card is associated with, eg. "apple_pay", "google_pay", etc.
57
+ # @return [String]
58
+ def wallet_type
59
+ wallet&.[]('type')
60
+ end
61
+
54
62
  # ActiveMerchant::Billing::CreditCard added this accessor used by some gateways.
55
63
  # More info: https://github.com/spree/spree/issues/6209
56
64
  #
@@ -116,6 +124,8 @@ module Spree
116
124
  @verification_value = value.to_s.gsub(/\s/, '')
117
125
  end
118
126
 
127
+ # Returns the last 4 digits of the card number.
128
+ # @return [String], eg. "4338"
119
129
  def set_last_digits
120
130
  self.last_digits ||= number.to_s.length <= 4 ? number : number.to_s.slice(-4..-1)
121
131
  end
@@ -130,10 +140,13 @@ module Spree
130
140
  end
131
141
 
132
142
  # Show the card number, with all but last 4 numbers replace with "X". (XXXX-XXXX-XXXX-4338)
143
+ # @return [String]
133
144
  def display_number
134
145
  "XXXX-XXXX-XXXX-#{last_digits}"
135
146
  end
136
147
 
148
+ # Show the card brand, eg. "VISA", "MASTERCARD", etc.
149
+ # @return [String]
137
150
  def display_brand
138
151
  brand.present? ? brand.upcase : Spree.t(:no_cc_type)
139
152
  end
@@ -141,14 +154,21 @@ module Spree
141
154
  # ActiveMerchant needs first_name/last_name because we pass it a Spree::CreditCard and it calls those methods on it.
142
155
  # Looking at the ActiveMerchant source code we should probably be calling #to_active_merchant before passing
143
156
  # the object to ActiveMerchant but this should do for now.
157
+ #
158
+ # Returns the first name of the cardholder.
159
+ # @return [String]
144
160
  def first_name
145
161
  name.to_s.split(/[[:space:]]/, 2)[0]
146
162
  end
147
163
 
164
+ # Returns the last name of the cardholder.
165
+ # @return [String]
148
166
  def last_name
149
167
  name.to_s.split(/[[:space:]]/, 2)[1]
150
168
  end
151
169
 
170
+ # Returns an ActiveMerchant::Billing::CreditCard object.
171
+ # @return [ActiveMerchant::Billing::CreditCard]
152
172
  def to_active_merchant
153
173
  ActiveMerchant::Billing::CreditCard.new(
154
174
  number: number,
@@ -1,6 +1,9 @@
1
1
  module Spree
2
2
  class Order < Spree.base_class
3
3
  module Digital
4
+ # Returns true if all order line items are digital
5
+ #
6
+ # @return [Boolean]
4
7
  def digital?
5
8
  if line_items.empty?
6
9
  false
@@ -9,18 +12,30 @@ module Spree
9
12
  end
10
13
  end
11
14
 
15
+ # Returns true if any order line item is digital
16
+ #
17
+ # @return [Boolean]
12
18
  def some_digital?
13
19
  line_items.any?(&:digital?)
14
20
  end
15
21
 
22
+ # Returns true if any order line item has digital assets
23
+ #
24
+ # @return [Boolean]
16
25
  def with_digital_assets?
17
26
  line_items.any?(&:with_digital_assets?)
18
27
  end
19
28
 
29
+ # Returns all line items with digital assets
30
+ #
31
+ # @return [Array<Spree::LineItem>]
20
32
  def digital_line_items
21
33
  line_items.with_digital_assets.distinct
22
34
  end
23
35
 
36
+ # Returns all digital links for the order
37
+ #
38
+ # @return [Array<Spree::DigitalLink>]
24
39
  def digital_links
25
40
  digital_line_items.map(&:digital_links).flatten
26
41
  end
@@ -84,7 +84,7 @@ module Spree
84
84
  end
85
85
 
86
86
  # adding to this shipment, and removing from stock_location
87
- if order.completed?
87
+ if order.completed? && variant.should_track_inventory?
88
88
  shipment.stock_location.unstock(variant, quantity, shipment)
89
89
  end
90
90
 
@@ -30,7 +30,7 @@ module Spree
30
30
 
31
31
  def formatted_url
32
32
  return if url.blank?
33
- return url if url.start_with?("mailto:")
33
+ return url if %w[mailto: tel:].any? { |protocol| url.start_with?(protocol) }
34
34
 
35
35
  @formatted_url ||= url.match(/http:\/\/|https:\/\//) ? url : "http://#{url}"
36
36
  end
@@ -23,11 +23,18 @@ module Spree
23
23
  has_one_attached :asset, service: Spree.public_storage_service_name
24
24
  alias image asset
25
25
 
26
+ #
27
+ # Rich Text
28
+ #
29
+ has_rich_text :text
30
+ has_rich_text :description
31
+
26
32
  #
27
33
  # Validations
28
34
  #
29
35
  validates :name, :pageable, presence: true
30
36
  validates :asset, content_type: Rails.application.config.active_storage.web_image_content_types
37
+
31
38
  #
32
39
  # Callbacks
33
40
  #
@@ -1,8 +1,6 @@
1
1
  module Spree
2
2
  module PageSections
3
3
  class AnnouncementBar < Spree::PageSection
4
- has_rich_text :text
5
-
6
4
  before_validation :set_default_text, on: :create
7
5
 
8
6
  BACKGROUND_COLOR_DEFAULT = '#F5F5F4'
@@ -1,8 +1,6 @@
1
1
  module Spree
2
2
  module PageSections
3
3
  class FeaturedPosts < Spree::PageSection
4
- has_rich_text :description
5
-
6
4
  before_validation :make_heading_size_valid
7
5
  before_validation :make_max_posts_to_show_valid
8
6
  before_validation :make_alignment_valid
@@ -9,8 +9,6 @@ module Spree
9
9
  queries.reduce(:or)
10
10
  }
11
11
 
12
- has_rich_text :description
13
-
14
12
  before_validation :make_heading_size_valid
15
13
  before_validation :make_alignment_valid
16
14
  before_validation :make_taxon_id_valid
@@ -50,6 +48,11 @@ module Spree
50
48
  end
51
49
 
52
50
  def products(currency)
51
+ Spree::Deprecation.warn(
52
+ 'FeaturedTaxon#products is deprecated and will be removed in Spree 6.0. ' \
53
+ 'Please use taxon_products(featured_taxon.taxon) helper method in views instead'
54
+ )
55
+
53
56
  @products ||= begin
54
57
  finder_params = {
55
58
  store: store,
@@ -1,8 +1,6 @@
1
1
  module Spree
2
2
  module PageSections
3
3
  class RelatedProducts < Spree::PageSection
4
- has_rich_text :description
5
-
6
4
  before_validation :make_heading_size_valid
7
5
  before_validation :make_alignment_valid
8
6
 
@@ -38,7 +38,7 @@ module Spree
38
38
  MEMOIZED_METHODS = %w[total_on_hand taxonomy_ids taxon_and_ancestors category
39
39
  default_variant_id tax_category default_variant
40
40
  default_image secondary_image
41
- purchasable? in_stock? backorderable? has_variants?]
41
+ purchasable? in_stock? backorderable? has_variants? digital?]
42
42
 
43
43
  STATUS_TO_WEBHOOK_EVENT = {
44
44
  'active' => 'activated',
@@ -81,6 +81,7 @@ module Spree
81
81
 
82
82
  belongs_to :tax_category, class_name: 'Spree::TaxCategory'
83
83
  belongs_to :shipping_category, class_name: 'Spree::ShippingCategory', inverse_of: :products
84
+ has_many :shipping_methods, through: :shipping_category, class_name: 'Spree::ShippingMethod'
84
85
 
85
86
  has_one :master,
86
87
  -> { where is_master: true },
@@ -345,11 +346,11 @@ module Spree
345
346
  # Returns default Image for Product
346
347
  # @return [Spree::Image]
347
348
  def default_image
348
- @default_image ||= if images.size.positive?
349
+ @default_image ||= if images.any?
349
350
  images.first
350
- elsif default_variant.images.size.positive?
351
+ elsif default_variant.images.any?
351
352
  default_variant.default_image
352
- elsif variant_images.size.positive?
353
+ elsif variant_images.any?
353
354
  variant_images.first
354
355
  end
355
356
  end
@@ -376,7 +377,7 @@ module Spree
376
377
  end
377
378
 
378
379
  # Returns tax category for Product
379
- # @return [Spree::TaxCategory]
380
+ # @return [Spree::TaxCategory, nil]
380
381
  def tax_category
381
382
  @tax_category ||= super || TaxCategory.default
382
383
  end
@@ -602,7 +603,7 @@ module Spree
602
603
  #
603
604
  # @return [Boolean]
604
605
  def digital?
605
- shipping_category&.shipping_methods&.any? { |method| method.calculator.is_a?(Spree::Calculator::Shipping::DigitalDelivery) }
606
+ @digital ||= shipping_methods&.digital&.exists?
606
607
  end
607
608
 
608
609
  def auto_match_taxons
@@ -124,6 +124,10 @@ module Spree
124
124
  cost
125
125
  end
126
126
 
127
+ def digital?
128
+ shipping_method&.digital? || false
129
+ end
130
+
127
131
  def add_shipping_method(shipping_method, selected = false)
128
132
  shipping_rates.create(shipping_method: shipping_method, selected: selected, cost: cost)
129
133
  end
@@ -200,8 +204,11 @@ module Spree
200
204
  with_free_shipping_promotion?
201
205
  end
202
206
 
207
+ # Returns true if the shipment has a free shipping promotion applied
208
+ #
209
+ # @return [Boolean]
203
210
  def with_free_shipping_promotion?
204
- adjustments.promotion.any? { |p| p.source.type == 'Spree::Promotion::Actions::FreeShipping' }
211
+ adjustments.promotion.includes(:source).any? { |p| p.source.respond_to?(:free_shipping?) && p.source.free_shipping? }
205
212
  end
206
213
 
207
214
  def finalize!
@@ -251,10 +258,6 @@ module Spree
251
258
  inventory_units.includes(:line_item).map(&:line_item).uniq
252
259
  end
253
260
 
254
- def digital?
255
- shipping_method&.calculator&.is_a?(Spree::Calculator::Shipping::DigitalDelivery)
256
- end
257
-
258
261
  ManifestItem = Struct.new(:line_item, :variant, :quantity, :states)
259
262
 
260
263
  def manifest
@@ -358,14 +361,27 @@ module Spree
358
361
  self.shipped_at = Time.current
359
362
  end
360
363
 
364
+ # Returns the shipping method of the selected shipping rate
365
+ #
366
+ # @return [Spree::ShippingMethod]
361
367
  def shipping_method
362
368
  selected_shipping_rate&.shipping_method || shipping_rates.first&.shipping_method
363
369
  end
364
370
 
371
+ # Returns the tax category of the selected shipping rate
372
+ #
373
+ # @return [Spree::TaxCategory]
365
374
  def tax_category
366
375
  selected_shipping_rate.try(:tax_rate).try(:tax_category)
367
376
  end
368
377
 
378
+ # Returns the tax category ID of the selected shipping rate
379
+ #
380
+ # @return [Integer]
381
+ def tax_category_id
382
+ selected_shipping_rate.try(:tax_rate).try(:tax_category_id)
383
+ end
384
+
369
385
  # Only one of either included_tax_total or additional_tax_total is set
370
386
  # This method returns the total of the two. Saves having to check if
371
387
  # tax is included or additional.
@@ -10,9 +10,12 @@ module Spree
10
10
  if defined?(Spree::VendorConcern)
11
11
  include Spree::VendorConcern
12
12
  end
13
+ include Spree::MemoizedData
13
14
 
14
15
  extend Spree::DisplayMoney
15
16
 
17
+ MEMOIZED_METHODS = %w[display_estimated_price digital?]
18
+
16
19
  # Used for #refresh_rates
17
20
  DISPLAY_ON_FRONT_END = 1
18
21
  DISPLAY_ON_BACK_END = 2
@@ -118,6 +121,13 @@ module Spree
118
121
  end
119
122
  end
120
123
 
124
+ # Returns true if the shipping method is digital
125
+ #
126
+ # @return [Boolean]
127
+ def digital?
128
+ @digital ||= calculator.is_a?(Spree::Calculator::Shipping::DigitalDelivery)
129
+ end
130
+
121
131
  private
122
132
 
123
133
  # Some shipping methods are only meant to be set via backend
@@ -339,7 +339,7 @@ module Spree
339
339
  end
340
340
 
341
341
  def supported_shipping_zones
342
- @supported_shipping_zones ||= if checkout_zone_id.present?
342
+ @supported_shipping_zones ||= if checkout_zone.present?
343
343
  [checkout_zone]
344
344
  else
345
345
  Spree::Zone.includes(zone_members: :zoneable).all
@@ -33,6 +33,17 @@ module Spree
33
33
 
34
34
  self.whitelisted_ransackable_attributes = %w[amount zone_id tax_category_id included_in_price name]
35
35
 
36
+ # Virtual attribute for percentage display in admin forms
37
+ def amount_percentage
38
+ return nil if amount.nil?
39
+
40
+ (amount * 100).round(2)
41
+ end
42
+
43
+ def amount_percentage=(value)
44
+ self.amount = value.present? ? (value.to_f / 100) : nil
45
+ end
46
+
36
47
  # Gets the array of TaxRates appropriate for the specified tax zone
37
48
  def self.match(order_tax_zone)
38
49
  return [] unless order_tax_zone
@@ -61,18 +72,18 @@ module Spree
61
72
  # to relevant items.
62
73
  def self.adjust(order, items)
63
74
  rates = match(order.tax_zone)
64
- tax_categories = rates.map(&:tax_category)
75
+ tax_category_ids = rates.map(&:tax_category_id)
65
76
 
66
77
  # using destroy_all to ensure adjustment destroy callback fires.
67
78
  Spree::Adjustment.where(adjustable: items).tax.destroy_all
68
79
 
69
80
  relevant_items = items.select do |item|
70
- tax_categories.include?(item.tax_category)
81
+ tax_category_ids.include?(item.tax_category_id)
71
82
  end
72
83
 
73
84
  relevant_items.each do |item|
74
85
  relevant_rates = rates.select do |rate|
75
- rate.tax_category == item.tax_category
86
+ rate.tax_category_id == item.tax_category_id
76
87
  end
77
88
  store_pre_tax_amount(item, relevant_rates)
78
89
  relevant_rates.each do |rate|
@@ -223,6 +223,8 @@ module Spree
223
223
  self.class.in_stock_or_backorderable.exists?(id: id)
224
224
  end
225
225
 
226
+ # Returns tax category for Variant
227
+ # @return [Spree::TaxCategory]
226
228
  def tax_category
227
229
  @tax_category ||= if self[:tax_category_id].nil?
228
230
  product.tax_category
@@ -231,6 +233,16 @@ module Spree
231
233
  end
232
234
  end
233
235
 
236
+ # Returns tax category ID for Variant
237
+ # @return [Integer]
238
+ def tax_category_id
239
+ @tax_category_id ||= if self[:tax_category_id].nil?
240
+ product.tax_category_id
241
+ else
242
+ self[:tax_category_id]
243
+ end
244
+ end
245
+
234
246
  def options_text
235
247
  @options_text ||= Spree::Variants::OptionsPresenter.new(self).to_sentence
236
248
  end
@@ -254,7 +266,7 @@ module Spree
254
266
  # Returns default Image for Variant
255
267
  # @return [Spree::Image]
256
268
  def default_image
257
- @default_image ||= if images.size.positive?
269
+ @default_image ||= if images.any?
258
270
  images.first
259
271
  else
260
272
  product.default_image
@@ -480,6 +492,8 @@ module Spree
480
492
  end
481
493
 
482
494
  # Is this variant purely digital? (no physical product)
495
+ #
496
+ # @return [Boolean]
483
497
  def digital?
484
498
  product.digital?
485
499
  end
@@ -21,6 +21,7 @@ module Spree
21
21
 
22
22
  after_save :remove_defunct_members
23
23
  after_save :remove_previous_default, if: %i[default_tax? saved_change_to_default_tax?]
24
+ before_destroy :nullify_checkout_zone
24
25
 
25
26
  alias members zone_members
26
27
  accepts_nested_attributes_for :zone_members, allow_destroy: true, reject_if: proc { |a| a['zoneable_id'].blank? }
@@ -205,5 +206,11 @@ module Spree
205
206
  members << member
206
207
  end
207
208
  end
209
+
210
+ def nullify_checkout_zone
211
+ if id == Spree::Store.current.checkout_zone_id
212
+ Spree::Store.current.update(checkout_zone_id: nil)
213
+ end
214
+ end
208
215
  end
209
216
  end
@@ -45,8 +45,6 @@ module Spree
45
45
  end
46
46
  end
47
47
 
48
- params.delete(:variants_attributes) if params[:variants_attributes].blank?
49
-
50
48
  # mark resource properties to be removed
51
49
  # when value is left blank
52
50
  if params[:product_properties_attributes].present?
@@ -62,6 +60,18 @@ module Spree
62
60
  # ensure there is at least one store
63
61
  params[:store_ids] = [store.id] if params[:store_ids].blank?
64
62
 
63
+ # Add empty list for option_type_ids and mark variants as removed if there are no variants and options
64
+ if params[:variants_attributes].blank? && variants_to_remove.any? && !params.key?(:option_type_ids)
65
+ params[:option_type_ids] = []
66
+ params[:variants_attributes] = {}
67
+
68
+ variants_to_remove.each_with_index do |variant_id, index|
69
+ params[:variants_attributes][index.to_s] = { id: variant_id, _destroy: '1' }
70
+ end
71
+
72
+ params[:variants_attributes].permit!
73
+ end
74
+
65
75
  params
66
76
  end
67
77
 
@@ -30,7 +30,10 @@ module Spree
30
30
 
31
31
  # clearing cache
32
32
  Spree::Product.where(id: products.pluck(:id)).touch_all
33
- Spree::Taxon.where(id: taxons.pluck(:id)).touch_all
33
+
34
+ taxon_ids = taxons.pluck(:id)
35
+ Spree::Taxon.where(id: taxon_ids).touch_all
36
+ Spree::Taxons::TouchFeaturedSections.call(taxon_ids: taxon_ids)
34
37
 
35
38
  success(true)
36
39
  end
@@ -44,7 +44,10 @@ module Spree
44
44
 
45
45
  # clear cache
46
46
  Spree::Product.where(id: products.pluck(:id)).touch_all
47
- Spree::Taxon.where(id: taxons.pluck(:id)).touch_all
47
+
48
+ taxon_ids = taxons.pluck(:id)
49
+ Spree::Taxon.where(id: taxon_ids).touch_all
50
+ Spree::Taxons::TouchFeaturedSections.call(taxon_ids: taxon_ids)
48
51
 
49
52
  success(true)
50
53
  end
@@ -10,7 +10,7 @@
10
10
 
11
11
  <% if spree.respond_to?(:admin_invitation_url) %>
12
12
  <p>
13
- <%= link_to Spree.t('invitation_mailer.invitation_email.link_text'), spree.admin_invitation_url(@invitation, token: @invitation.token, host: @invitation.store.formatted_url) %>
13
+ <%= link_to Spree.t(:accept), spree.admin_invitation_url(@invitation, token: @invitation.token, host: @invitation.store.formatted_url) %>
14
14
  </p>
15
15
  <% end %>
16
16
 
data/config/importmap.rb CHANGED
@@ -3,6 +3,7 @@ pin '@rails/request.js', to: '@rails--request.js.js', preload: ['application-spr
3
3
  pin 'tailwindcss-stimulus-components', preload: ['application-spree-storefront', 'application-spree-admin'] # @3.0.4
4
4
  pin 'stimulus-reveal-controller', preload: ['application-spree-admin'] # @4.1.0
5
5
  pin '@stimulus-components/auto-submit', to: '@stimulus-components--auto-submit.js', preload: ['application-spree-admin'] # @6.0.0
6
+ pin 'stimulus-textarea-autogrow', preload: ['application-spree-admin'] # @4.1.0
6
7
 
7
8
  pin_all_from Spree::Core::Engine.root.join('app/javascript/spree/core/controllers'),
8
9
  under: 'spree/core/controllers',
@@ -181,6 +181,7 @@ en:
181
181
  name: Name
182
182
  permalink: Permalink
183
183
  position: Position
184
+ sort_order: Sort Order
184
185
  spree/taxonomy:
185
186
  name: Name
186
187
  spree/user:
@@ -590,6 +591,7 @@ en:
590
591
  add_country: Add Country
591
592
  add_coupon_code: Add Coupon Code
592
593
  add_gift_card: Add Gift Card
594
+ add_link: Add link
593
595
  add_new_address: Add new address
594
596
  add_new_credit_card: Add a new card
595
597
  add_new_header: Add New Header
@@ -874,6 +876,7 @@ en:
874
876
  current: Current
875
877
  current_password: Current password
876
878
  custom_code: Custom code
879
+ custom_domains: Custom domains
877
880
  custom_font_code: Custom font code
878
881
  customer: Customer
879
882
  customer_details: Customer Details
@@ -1854,6 +1857,7 @@ en:
1854
1857
  select_stores: Select Store(s)
1855
1858
  select_user: Select customer
1856
1859
  selected_quantity_not_available: selected of %{item} is not available.
1860
+ send_consumer_transactional_emails: Send Customer Transactional Emails
1857
1861
  send_copy_of_all_mails_to: Send Copy of All Mails To
1858
1862
  send_mails_as: Send Mails As
1859
1863
  send_message: Send message
@@ -1,5 +1,5 @@
1
1
  class AddPerformedByToSpreeReimbursements < ActiveRecord::Migration[6.1]
2
2
  def change
3
- add_column :spree_reimbursements, :performed_by_id, :bigint, index: true, null: true, if_not_exists: true
3
+ add_reference :spree_reimbursements, :performed_by, index: true, null: true unless column_exists?(:spree_reimbursements, :performed_by_id)
4
4
  end
5
5
  end
@@ -39,6 +39,13 @@ module Spree
39
39
  opts[:skip_test] = true
40
40
  opts[:skip_bootsnap] = true
41
41
  opts[:skip_asset_pipeline] = true # skip installing propshaft, we're still using sprockets as a dependency
42
+ opts[:skip_docker] = true
43
+ opts[:skip_rubocop] = true
44
+ opts[:skip_brakeman] = true
45
+ opts[:skip_ci] = true
46
+ opts[:skip_kamal] = true
47
+ opts[:skip_devcontainer] = true
48
+ opts[:skip_solid] = true
42
49
 
43
50
  puts 'Generating dummy Rails application...'
44
51
  invoke Rails::Generators::AppGenerator,
@@ -73,46 +80,11 @@ module Spree
73
80
  end
74
81
  end
75
82
 
76
- def test_dummy_clean
77
- inside dummy_path do
78
- remove_file '.gitignore'
79
- remove_file 'doc'
80
- remove_file 'Gemfile'
81
- remove_file 'lib/tasks'
82
- remove_file 'app/assets/images/rails.png'
83
- remove_file 'app/assets/javascripts/application.js'
84
- remove_file 'public/index.html'
85
- remove_file 'public/robots.txt'
86
- remove_file 'README'
87
- remove_file 'test'
88
- remove_file 'vendor'
89
- remove_file 'spec'
90
- end
91
- end
92
-
93
- def inject_content_security_policy
94
- inside dummy_path do
95
- inject_into_file 'config/initializers/content_security_policy.rb', %Q[
96
- p.script_src :self, :https, :unsafe_inline, :http, :unsafe_eval
97
- ], before: /^end/, verbose: true
98
- end
99
- end
100
-
101
83
  attr_reader :lib_name
102
84
  attr_reader :database
103
85
 
104
86
  protected
105
87
 
106
- def inject_require_for(requirement)
107
- inject_into_file 'config/application.rb', %Q[
108
- begin
109
- require '#{requirement}'
110
- rescue LoadError
111
- # #{requirement} is not available.
112
- end
113
- ], before: /require '#{@lib_name}'/, verbose: true
114
- end
115
-
116
88
  def inject_yaml_permitted_classes
117
89
  inside dummy_path do
118
90
  inject_into_file 'config/application.rb', %Q[
@@ -140,10 +112,6 @@ end
140
112
  end
141
113
  alias store_application_definition! application_definition
142
114
 
143
- def camelized
144
- @camelized ||= name.gsub(/\W/, '_').squeeze('_').camelize
145
- end
146
-
147
115
  def remove_directory_if_exists(path)
148
116
  remove_dir(path) if File.directory?(path)
149
117
  end
@@ -46,24 +46,6 @@ module Spree
46
46
  template 'config/initializers/spree.rb', 'config/initializers/spree.rb'
47
47
  end
48
48
 
49
- def additional_tweaks
50
- return unless File.exist? 'public/robots.txt'
51
-
52
- append_file 'public/robots.txt', <<-ROBOTS.strip_heredoc
53
- User-agent: *
54
- Disallow: /checkout
55
- Disallow: /cart
56
- Disallow: /orders
57
- Disallow: /user
58
- Disallow: /account
59
- Disallow: /api
60
- Disallow: /password
61
- Disallow: /api_tokens
62
- Disallow: /cart_link
63
- Disallow: /account_link
64
- ROBOTS
65
- end
66
-
67
49
  # Currently we only support devise, in the future we will also add support for default Rails authentication
68
50
  def install_authentication
69
51
  if @authentication == 'devise'
@@ -121,7 +103,6 @@ module Spree
121
103
  say_status :copying, 'migrations'
122
104
  silence_stream(STDOUT) do
123
105
  silence_warnings { rake 'active_storage:install:migrations' }
124
- silence_warnings { rake 'action_mailbox:install:migrations' }
125
106
  silence_warnings { rake 'action_text:install:migrations' }
126
107
  silence_warnings { rake 'spree:install:migrations' }
127
108
  silence_warnings { rake 'spree_api:install:migrations' }
@@ -54,7 +54,7 @@ module Spree
54
54
  preference :require_master_price, :boolean, default: false
55
55
  preference :restock_inventory, :boolean, default: true # Determines if a return item is restocked automatically once it has been received
56
56
  preference :return_eligibility_number_of_days, :integer, default: 365
57
- preference :send_core_emails, :boolean, default: true # Default mail headers settings
57
+ preference :send_core_emails, :boolean, default: true, deprecated: true # Default mail headers settings
58
58
  preference :shipping_instructions, :boolean, deprecated: true
59
59
  preference :show_only_complete_orders_by_default, :boolean, deprecated: true
60
60
  preference :show_variant_full_price, :boolean, default: false # Displays variant full price or difference with product price. Default false to be compatible with older behavior
@@ -299,7 +299,7 @@ module Spree
299
299
  end
300
300
 
301
301
  initializer 'spree.core.checking_migrations' do
302
- Migrations.new(config, engine_name).check
302
+ Migrations.new(config, engine_name).check unless Rails.env.test?
303
303
  end
304
304
 
305
305
  initializer 'spree.core.assets' do |app|
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- VERSION = '5.1.4'.freeze
2
+ VERSION = '5.1.6'.freeze
3
3
 
4
4
  def self.version
5
5
  VERSION
data/lib/spree/core.rb CHANGED
@@ -91,7 +91,7 @@ module Spree
91
91
  end
92
92
 
93
93
  def self.root_domain
94
- @@root_domain ||= Rails.application.routes.default_url_options[:host] || 'lvh.me'
94
+ @@root_domain
95
95
  end
96
96
 
97
97
  def self.queues
@@ -257,11 +257,11 @@ module Spree
257
257
 
258
258
  @@store_credit_category_attributes = [:name]
259
259
 
260
- @@taxonomy_attributes = [:name]
260
+ @@taxonomy_attributes = [:name, :position]
261
261
 
262
262
  @@tax_category_attributes = [:name, :tax_code,:description, :is_default]
263
263
 
264
- @@tax_rate_attributes = [:name, :amount, :zone_id, :tax_category_id, :included_in_price, :show_rate_in_label, :calculator_type, calculator_attributes: {}]
264
+ @@tax_rate_attributes = [:name, :amount, :amount_percentage, :zone_id, :tax_category_id, :included_in_price, :show_rate_in_label, :calculator_type, calculator_attributes: {}]
265
265
 
266
266
  @@taxon_attributes = [
267
267
  :name, :parent_id, :position, :icon, :description, :permalink, :hide_from_nav,
@@ -21,16 +21,16 @@ namespace :common do
21
21
 
22
22
  skip_javascript = ['spree/api', 'spree/core', 'spree/sample', 'spree/emails'].include?(ENV['LIB_NAME'])
23
23
 
24
- Spree::DummyGenerator.start [
25
- "--lib_name=#{ENV['LIB_NAME']}",
26
- "--skip_javascript=#{skip_javascript}"
24
+ dummy_app_args = [
25
+ "--lib_name=#{ENV['LIB_NAME']}"
27
26
  ]
27
+ if skip_javascript
28
+ dummy_app_args << '--skip_javascript'
29
+ end
30
+ Spree::DummyGenerator.start dummy_app_args
28
31
 
29
- # install frontend libraries
30
32
  unless skip_javascript
31
- system('bin/rails importmap:install')
32
- system('bin/rails turbo:install')
33
- system('bin/rails stimulus:install')
33
+ system('bin/rails importmap:install turbo:install stimulus:install')
34
34
  end
35
35
 
36
36
  # install devise if it's not the legacy user, useful for testing storefront
@@ -52,21 +52,39 @@ namespace :common do
52
52
  "--authentication=#{args[:authentication]}"
53
53
  ]
54
54
 
55
- puts 'Setting up dummy database...'
56
- system('bin/rails db:environment:set RAILS_ENV=test > /dev/null 2>&1')
57
- system('bundle exec rake db:drop db:create > /dev/null 2>&1')
58
- Spree::DummyModelGenerator.start
59
- system('bundle exec rake db:migrate > /dev/null 2>&1')
55
+ if !skip_javascript || ENV['LIB_NAME'] == 'spree/emails'
56
+ puts 'Precompiling assets...'
57
+ system('bundle exec rake assets:precompile > /dev/null 2>&1')
58
+ end
59
+
60
+ unless ENV['NO_MIGRATE']
61
+ puts 'Setting up dummy database...'
62
+ system('bin/rails db:environment:set RAILS_ENV=test > /dev/null 2>&1')
63
+ system('bundle exec rake db:drop db:create > /dev/null 2>&1')
64
+ Spree::DummyModelGenerator.start
65
+ system('bundle exec rake db:migrate > /dev/null 2>&1')
66
+ end
60
67
 
61
68
  begin
62
69
  require "generators/#{ENV['LIB_NAME']}/install/install_generator"
63
70
  puts 'Running extension installation generator...'
64
- "#{ENV['LIB_NAME'].camelize}::Generators::InstallGenerator".constantize.start(['--auto-run-migrations'])
71
+
72
+ if ENV['NO_MIGRATE']
73
+ "#{ENV['LIB_NAME'].camelize}::Generators::InstallGenerator".constantize.start([])
74
+ else
75
+ "#{ENV['LIB_NAME'].camelize}::Generators::InstallGenerator".constantize.start(['--auto-run-migrations'])
76
+ end
65
77
  rescue LoadError
66
78
  puts 'Skipping installation no generator to run...'
67
79
  end
80
+ end
68
81
 
69
- system('bundle exec rake assets:precompile > /dev/null 2>&1') if !skip_javascript || ENV['LIB_NAME'] == 'spree/emails'
82
+ task :db_setup do |_t|
83
+ puts 'Setting up dummy database...'
84
+ system('bin/rails db:environment:set RAILS_ENV=test > /dev/null 2>&1')
85
+ system('bundle exec rake db:drop db:create > /dev/null 2>&1')
86
+ Spree::DummyModelGenerator.start
87
+ system('bundle exec rake db:migrate > /dev/null 2>&1')
70
88
  end
71
89
 
72
90
  task :seed do |_t|
@@ -0,0 +1,4 @@
1
+ // stimulus-textarea-autogrow@4.1.0 downloaded from https://ga.jspm.io/npm:stimulus-textarea-autogrow@4.1.0/dist/stimulus-textarea-autogrow.mjs
2
+
3
+ import{Controller as e}from"@hotwired/stimulus";function r(e,t){let i;return(...s)=>{const o=this;clearTimeout(i),i=setTimeout((()=>e.apply(o,s)),t)}}class l extends e{initialize(){this.autogrow=this.autogrow.bind(this)}connect(){this.element.style.overflow="hidden";const e=this.resizeDebounceDelayValue;this.onResize=e>0?r(this.autogrow,e):this.autogrow,this.autogrow(),this.element.addEventListener("input",this.autogrow),window.addEventListener("resize",this.onResize)}disconnect(){window.removeEventListener("resize",this.onResize)}autogrow(){this.element.style.height="auto",this.element.style.height=`${this.element.scrollHeight}px`}}l.values={resizeDebounceDelay:{type:Number,default:100}};export{l as default};
4
+
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.1.4
4
+ version: 5.1.6
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: 2025-07-24 00:00:00.000000000 Z
13
+ date: 2025-09-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: i18n-tasks
@@ -1375,6 +1375,7 @@ files:
1375
1375
  - vendor/javascript/@rails--request.js.js
1376
1376
  - vendor/javascript/@stimulus-components--auto-submit.js
1377
1377
  - vendor/javascript/stimulus-reveal-controller.js
1378
+ - vendor/javascript/stimulus-textarea-autogrow.js
1378
1379
  - vendor/javascript/tailwindcss-stimulus-components.js
1379
1380
  homepage: https://spreecommerce.org
1380
1381
  licenses:
@@ -1382,9 +1383,9 @@ licenses:
1382
1383
  - BSD-3-Clause
1383
1384
  metadata:
1384
1385
  bug_tracker_uri: https://github.com/spree/spree/issues
1385
- changelog_uri: https://github.com/spree/spree/releases/tag/v5.1.4
1386
+ changelog_uri: https://github.com/spree/spree/releases/tag/v5.1.6
1386
1387
  documentation_uri: https://docs.spreecommerce.org/
1387
- source_code_uri: https://github.com/spree/spree/tree/v5.1.4
1388
+ source_code_uri: https://github.com/spree/spree/tree/v5.1.6
1388
1389
  post_install_message:
1389
1390
  rdoc_options: []
1390
1391
  require_paths: