spree_core 5.4.0.beta4 → 5.4.0.beta6

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.
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'stringex'
2
4
 
3
5
  module Spree
4
6
  class Taxon < Spree.base_class
5
- has_prefix_id :txn # Spree-specific: taxon
7
+ has_prefix_id :ctg
6
8
 
7
9
  RULES_MATCH_POLICIES = %w[all any].freeze
8
10
  SORT_ORDERS = [
@@ -54,9 +56,9 @@ module Spree
54
56
  #
55
57
  # Validations
56
58
  #
57
- validates :name, presence: true, uniqueness: { scope: [:parent_id, :taxonomy_id], case_sensitive: false }
59
+ validates :name, presence: true, uniqueness: { scope: %i[parent_id taxonomy_id], case_sensitive: false }
58
60
  validates :taxonomy, presence: true
59
- validates :permalink, uniqueness: { case_sensitive: false, scope: [:parent_id, :taxonomy_id] }
61
+ validates :permalink, uniqueness: { case_sensitive: false, scope: %i[parent_id taxonomy_id] }
60
62
  validates :hide_from_nav, inclusion: { in: [true, false] }
61
63
  validate :check_for_root, on: :create
62
64
  validate :parent_belongs_to_same_taxonomy
@@ -88,9 +90,9 @@ module Spree
88
90
  scope :for_stores, ->(stores) { joins(:taxonomy).where(spree_taxonomies: { store_id: stores.ids }) }
89
91
  scope :for_taxonomy, lambda { |taxonomy_name|
90
92
  if Spree.use_translations?
91
- joins(:taxonomy).
92
- join_translation_table(Taxonomy).
93
- where(
93
+ joins(:taxonomy)
94
+ .join_translation_table(Taxonomy)
95
+ .where(
94
96
  Taxonomy.arel_table_alias[:name].lower.matches(taxonomy_name.downcase.strip)
95
97
  )
96
98
  else
@@ -110,7 +112,7 @@ module Spree
110
112
  end
111
113
  end
112
114
 
113
- scope :with_matching_name, ->(name_to_match) do
115
+ scope :with_matching_name, lambda { |name_to_match|
114
116
  value = name_to_match.to_s.strip.downcase
115
117
 
116
118
  if Spree.use_translations?
@@ -118,13 +120,14 @@ module Spree
118
120
  else
119
121
  where(arel_table[:name].lower.eq(value))
120
122
  end
121
- end
123
+ }
122
124
 
123
125
  #
124
126
  # Ransack
125
127
  #
126
- self.whitelisted_ransackable_associations = %w[taxonomy]
127
- self.whitelisted_ransackable_attributes = %w[name permalink automatic]
128
+ self.whitelisted_ransackable_associations = %w[taxonomy parent]
129
+ self.whitelisted_ransackable_attributes = %w[name permalink automatic depth is_root children_count
130
+ classification_count hide_from_nav parent_id]
128
131
 
129
132
  #
130
133
  # Translations
@@ -142,7 +145,9 @@ module Spree
142
145
  validates :sort_order, inclusion: { in: SORT_ORDERS }, presence: true
143
146
 
144
147
  has_many :taxon_rules, class_name: 'Spree::TaxonRule', dependent: :destroy
145
- accepts_nested_attributes_for :taxon_rules, allow_destroy: true, reject_if: proc { |attributes| attributes['value'].blank? }
148
+ accepts_nested_attributes_for :taxon_rules, allow_destroy: true, reject_if: proc { |attributes|
149
+ attributes['value'].blank?
150
+ }
146
151
  alias rules taxon_rules
147
152
 
148
153
  scope :manual, -> { where.not(automatic: true) }
@@ -160,14 +165,14 @@ module Spree
160
165
  end
161
166
 
162
167
  def active_products_with_descendants
163
- @active_products_with_descendants ||= store.products.
164
- joins(:classifications).
165
- active.
166
- where(
167
- Spree::Classification.table_name => {
168
- taxon_id: descendants.ids + [id]
169
- }
170
- )
168
+ @active_products_with_descendants ||= store.products
169
+ .joins(:classifications)
170
+ .active
171
+ .where(
172
+ Spree::Classification.table_name => {
173
+ taxon_id: descendants.ids + [id]
174
+ }
175
+ )
171
176
  end
172
177
 
173
178
  def products_matching_rules(opts = {})
@@ -209,10 +214,10 @@ module Spree
209
214
  # so we can later use them for product filtering and so on
210
215
  # if we want to fire the service once during object lifecycle - pass only_once: true
211
216
  def regenerate_taxon_products(only_once: false)
212
- if marked_for_regenerate_taxon_products?
213
- Spree::Taxons::RegenerateProducts.call(taxon: self)
214
- self.marked_for_regenerate_taxon_products = false if !frozen? && only_once
215
- end
217
+ return unless marked_for_regenerate_taxon_products?
218
+
219
+ Spree::Taxons::RegenerateProducts.call(taxon: self)
220
+ self.marked_for_regenerate_taxon_products = false if !frozen? && only_once
216
221
  end
217
222
 
218
223
  def slug
@@ -283,7 +288,8 @@ module Spree
283
288
  end
284
289
 
285
290
  def generate_permalink_including_parent
286
- [parent_permalink_with_fallback, (permalink.blank? ? name_with_fallback.to_url : permalink.split('/').last.to_url)].join('/')
291
+ [parent_permalink_with_fallback,
292
+ (permalink.blank? ? name_with_fallback.to_url : permalink.split('/').last.to_url)].join('/')
287
293
  end
288
294
 
289
295
  def generate_pretty_name_including_parent
@@ -384,11 +390,10 @@ module Spree
384
390
  end
385
391
 
386
392
  def sync_taxonomy_name
387
- if saved_changes.key?(:name) && root?
388
- return if taxonomy.name.to_s == name.to_s
393
+ return unless saved_changes.key?(:name) && root?
394
+ return if taxonomy.name.to_s == name.to_s
389
395
 
390
- taxonomy.update(name: name)
391
- end
396
+ taxonomy.update(name: name)
392
397
  end
393
398
 
394
399
  def touch_ancestors_and_taxonomy
@@ -399,15 +404,15 @@ module Spree
399
404
  end
400
405
 
401
406
  def check_for_root
402
- if taxonomy.try(:root).present? && parent_id.nil?
403
- errors.add(:root_conflict, 'this taxonomy already has a root taxon')
404
- end
407
+ return unless taxonomy.try(:root).present? && parent_id.nil?
408
+
409
+ errors.add(:root_conflict, 'this taxonomy already has a root taxon')
405
410
  end
406
411
 
407
412
  def parent_belongs_to_same_taxonomy
408
- if parent.present? && parent.taxonomy_id != taxonomy_id
409
- errors.add(:parent, 'must belong to the same taxonomy')
410
- end
413
+ return unless parent.present? && parent.taxonomy_id != taxonomy_id
414
+
415
+ errors.add(:parent, 'must belong to the same taxonomy')
411
416
  end
412
417
 
413
418
  def copy_taxonomy_from_parent
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'ssrf_filter'
4
+ require 'resolv'
5
+
3
6
  module Spree
4
7
  class WebhookEndpoint < Spree.base_class
5
8
  has_prefix_id :whe # Stripe: we_
@@ -8,12 +11,15 @@ module Spree
8
11
 
9
12
  include Spree::SingleStoreResource
10
13
 
14
+ encrypts :secret_key, deterministic: true if Rails.configuration.active_record.encryption.include?(:primary_key)
15
+
11
16
  belongs_to :store, class_name: 'Spree::Store'
12
17
  has_many :webhook_deliveries, class_name: 'Spree::WebhookDelivery', dependent: :destroy_async
13
18
 
14
19
  validates :store, :url, presence: true
15
20
  validates :url, format: { with: URI::DEFAULT_PARSER.make_regexp(%w[http https]), message: :invalid_url }
16
21
  validates :active, inclusion: { in: [true, false] }
22
+ validate :url_must_not_resolve_to_private_ip, if: -> { url.present? && url_changed? }
17
23
 
18
24
  before_create :generate_secret_key
19
25
 
@@ -51,5 +57,16 @@ module Spree
51
57
  def generate_secret_key
52
58
  self.secret_key ||= SecureRandom.hex(32)
53
59
  end
60
+
61
+ def url_must_not_resolve_to_private_ip
62
+ uri = URI.parse(url)
63
+ blacklist = SsrfFilter::IPV4_BLACKLIST + SsrfFilter::IPV6_BLACKLIST
64
+ addresses = Resolv.getaddresses(uri.host)
65
+ if addresses.any? { |addr| blacklist.any? { |range| range.include?(IPAddr.new(addr)) } }
66
+ errors.add(:url, :internal_address_not_allowed)
67
+ end
68
+ rescue URI::InvalidURIError, Resolv::ResolvError, IPAddr::InvalidAddressError, ArgumentError
69
+ # URI format validation handles invalid URLs; DNS failures are not SSRF
70
+ end
54
71
  end
55
72
  end
@@ -10,9 +10,11 @@ module Spree
10
10
  # @param public_metadata [Hash] public metadata for the order
11
11
  # @param private_metadata [Hash] private metadata for the order
12
12
  # @param order_params [Hash] additional order attributes
13
+ # @param line_items [Array<Hash>] line items to add, each with :variant_id (prefixed) and :quantity
13
14
  # @return [Spree::ServiceModule::Result]
14
- def call(user:, store:, currency:, locale: nil, metadata: {}, public_metadata: {}, private_metadata: {}, order_params: {})
15
+ def call(user:, store:, currency:, locale: nil, metadata: {}, public_metadata: {}, private_metadata: {}, order_params: {}, line_items: [])
15
16
  order_params ||= {}
17
+ line_items ||= []
16
18
 
17
19
  # we cannot create an order without store
18
20
  return failure(:store_is_required) if store.nil?
@@ -28,8 +30,22 @@ module Spree
28
30
  private_metadata: resolved_metadata.to_h
29
31
  }
30
32
 
31
- order = store.orders.create!(default_params.merge(order_params))
33
+ order = nil
34
+
35
+ ApplicationRecord.transaction do
36
+ order = store.orders.create!(default_params.merge(order_params))
37
+
38
+ if line_items.present?
39
+ result = Spree.cart_upsert_items_service.call(order: order, line_items: line_items)
40
+ raise StandardError, result.error.to_s if result.failure?
41
+ end
42
+ end
43
+
32
44
  success(order)
45
+ rescue ActiveRecord::RecordNotFound
46
+ raise
47
+ rescue StandardError => e
48
+ failure(order, e.message)
33
49
  end
34
50
  end
35
51
  end
@@ -0,0 +1,80 @@
1
+ module Spree
2
+ module Cart
3
+ # Bulk upsert line items on an order.
4
+ #
5
+ # For each entry in +line_items+:
6
+ # - If a line item for the variant already exists → sets its quantity
7
+ # - If no line item exists → creates one with the given quantity
8
+ #
9
+ # After all items are processed the order is recalculated once.
10
+ #
11
+ # Price calculation and tax adjustments are handled by LineItem model callbacks
12
+ # (copy_price, update_adjustments, update_tax_charge), so we only need to
13
+ # save each item and run a single order recalculation at the end.
14
+ #
15
+ # @example
16
+ # Spree::Cart::UpsertItems.call(
17
+ # order: order,
18
+ # line_items: [
19
+ # { variant_id: "variant_k5nR8xLq", quantity: 2 },
20
+ # { variant_id: "variant_m3Rp9wXz", quantity: 1 }
21
+ # ]
22
+ # )
23
+ #
24
+ class UpsertItems
25
+ prepend Spree::ServiceModule::Base
26
+
27
+ def call(order:, line_items:)
28
+ line_items = Array(line_items)
29
+ return success(order) if line_items.empty?
30
+
31
+ store = order.store || Spree::Current.store
32
+
33
+ ApplicationRecord.transaction do
34
+ line_items.each do |item_params|
35
+ item_params = item_params.to_h.deep_symbolize_keys
36
+ variant = resolve_variant(store, item_params[:variant_id])
37
+ next unless variant
38
+
39
+ quantity = (item_params[:quantity] || 1).to_i
40
+
41
+ return failure(variant, "#{variant.name} is not available in #{order.currency}") if variant.amount_in(order.currency).nil?
42
+
43
+ line_item = Spree.line_item_by_variant_finder.new.execute(order: order, variant: variant)
44
+
45
+ if line_item
46
+ line_item.quantity = quantity
47
+ line_item.metadata = line_item.metadata.merge(item_params[:metadata].to_h) if item_params[:metadata].present?
48
+ else
49
+ line_item = order.line_items.new(quantity: quantity, variant: variant, options: { currency: order.currency })
50
+ line_item.metadata = item_params[:metadata].to_h if item_params[:metadata].present?
51
+ end
52
+
53
+ return failure(line_item) unless line_item.save
54
+ end
55
+
56
+ order.update_with_updater!
57
+ end
58
+
59
+ success(order)
60
+ end
61
+
62
+ private
63
+
64
+ def resolve_variant(store, prefixed_id)
65
+ return nil if prefixed_id.blank?
66
+
67
+ variant = store.variants.find_by_prefix_id(prefixed_id)
68
+
69
+ raise ActiveRecord::RecordNotFound.new(
70
+ "Variant '#{prefixed_id}' not found in this store",
71
+ 'Spree::Variant',
72
+ 'prefix_id',
73
+ prefixed_id
74
+ ) unless variant
75
+
76
+ variant
77
+ end
78
+ end
79
+ end
80
+ end
@@ -25,15 +25,16 @@ module Spree
25
25
  return failure(:gift_card_mismatched_customer) if gift_card.user != order.user
26
26
  end
27
27
 
28
- amount = [gift_card.amount_remaining, order.total].min
29
28
  store = order.store
30
29
 
31
- return failure(:gift_card_no_amount_remaining) unless amount.positive? || order.total.zero?
32
-
33
30
  payment_method = ensure_store_credit_payment_method!(store)
34
31
 
35
- gift_card.lock!
36
32
  order.with_lock do
33
+ gift_card.lock!
34
+ amount = [gift_card.amount_remaining, order.total].min
35
+
36
+ return failure(:gift_card_no_amount_remaining) unless amount.positive? || order.total.zero?
37
+
37
38
  store_credit = gift_card.store_credits.create!(
38
39
  store: store,
39
40
  user: order.user,
@@ -0,0 +1,121 @@
1
+ module Spree
2
+ module Orders
3
+ # Core order update service with modern conventions:
4
+ # - Flat parameter structure (no wrapping in "order" key)
5
+ # - snake_case field names without "_attributes" suffix
6
+ # - Automatic state management based on what's being updated
7
+ # - Support for line_items with prefixed variant IDs
8
+ #
9
+ # @example Update order with line items
10
+ # Spree::Orders::Update.call(
11
+ # order: order,
12
+ # params: {
13
+ # email: "customer@example.com",
14
+ # line_items: [
15
+ # { variant_id: "variant_123", quantity: 2 },
16
+ # { variant_id: "variant_456", quantity: 1 }
17
+ # ],
18
+ # ship_address: {
19
+ # firstname: "John",
20
+ # lastname: "Doe",
21
+ # address1: "123 Main St",
22
+ # city: "New York",
23
+ # zipcode: "10001",
24
+ # country_iso: "US",
25
+ # state_abbr: "NY"
26
+ # }
27
+ # }
28
+ # )
29
+ #
30
+ class Update
31
+ prepend Spree::ServiceModule::Base
32
+
33
+ def call(order:, params:)
34
+ @order = order
35
+ @params = params.to_h.deep_symbolize_keys
36
+
37
+ ApplicationRecord.transaction do
38
+ assign_order_attributes
39
+ assign_address(:ship_address)
40
+ assign_address(:bill_address)
41
+
42
+ order.save!
43
+
44
+ process_line_items
45
+ end
46
+
47
+ success(order.reload)
48
+ rescue ActiveRecord::RecordNotFound
49
+ raise
50
+ rescue ActiveRecord::RecordInvalid => e
51
+ failure(order, e.record.errors.full_messages.to_sentence)
52
+ rescue StandardError => e
53
+ failure(order, e.message)
54
+ end
55
+
56
+ private
57
+
58
+ attr_reader :order, :params
59
+
60
+ def assign_order_attributes
61
+ order.email = params[:email] if params[:email].present?
62
+ order.special_instructions = params[:special_instructions] if params.key?(:special_instructions)
63
+ order.currency = params[:currency].upcase if params[:currency].present?
64
+ order.locale = params[:locale] if params[:locale].present?
65
+ order.metadata = order.metadata.merge(params[:metadata].to_h) if params[:metadata].present?
66
+ end
67
+
68
+ def assign_address(address_type)
69
+ address_id_param = params[:"#{address_type}_id"]
70
+ address_params = params[address_type]
71
+
72
+ # Priority 1: Direct address ID reference (ship_address_id / bill_address_id)
73
+ if address_id_param.present?
74
+ address_id = resolve_address_id(address_id_param)
75
+ order.public_send(:"#{address_type}_id=", address_id) if address_id
76
+ return
77
+ end
78
+
79
+ # Priority 2: Nested address params (ship_address / bill_address)
80
+ return unless address_params.is_a?(Hash)
81
+
82
+ if address_params[:id].present?
83
+ # Using existing address by ID within nested params
84
+ address_id = resolve_address_id(address_params[:id])
85
+ order.public_send(:"#{address_type}_id=", address_id) if address_id
86
+ else
87
+ # Creating/updating address with provided attributes
88
+ revert_to_address_state if order.has_checkout_step?('address')
89
+ order.public_send(:"#{address_type}_attributes=", address_params)
90
+ end
91
+ end
92
+
93
+ def process_line_items
94
+ return unless params[:line_items].is_a?(Array)
95
+
96
+ result = Spree.cart_upsert_items_service.call(
97
+ order: order,
98
+ line_items: params[:line_items]
99
+ )
100
+
101
+ raise StandardError, result.error.to_s if result.failure?
102
+ end
103
+
104
+ # Translate prefixed ID to internal id
105
+ def resolve_address_id(prefixed_id)
106
+ return unless order.user
107
+
108
+ decoded = Spree::Address.decode_prefixed_id(prefixed_id)
109
+ decoded ? order.user.addresses.find_by(id: decoded)&.id : nil
110
+ end
111
+
112
+ # Revert order state to 'address' when address changes
113
+ # This ensures shipments are recreated when transitioning back to delivery
114
+ def revert_to_address_state
115
+ return if ['cart', 'address'].include?(order.state)
116
+
117
+ order.state = 'address'
118
+ end
119
+ end
120
+ end
121
+ end
@@ -17,11 +17,14 @@ module Spree
17
17
  # prepared_params = service.call
18
18
  #
19
19
  class PrepareNestedAttributes
20
+ attr_reader :variants_to_discontinue
21
+
20
22
  def initialize(product, store, params, ability)
21
23
  @product = product
22
24
  @store = store
23
25
  @params = params
24
26
  @ability = ability
27
+ @variants_to_discontinue = []
25
28
  end
26
29
 
27
30
  def call
@@ -75,7 +78,8 @@ module Spree
75
78
  params[:option_type_ids] = []
76
79
  params[:variants_attributes] = {}
77
80
 
78
- variants_to_remove.each_with_index do |variant_id, index|
81
+ populate_variants_to_discontinue
82
+ variant_ids_to_destroy.each_with_index do |variant_id, index|
79
83
  params[:variants_attributes][index.to_s] = { id: variant_id, _destroy: '1' }
80
84
  end
81
85
 
@@ -122,15 +126,37 @@ module Spree
122
126
  def removed_variants_attributes
123
127
  return {} unless can_remove_variants?
124
128
 
129
+ populate_variants_to_discontinue
130
+
125
131
  attributes = {}
126
132
  last_index = params[:variants_attributes].keys.map(&:to_i).max
127
- variants_to_remove.each_with_index do |variant_id, index|
128
- attributes[(index + last_index + 1).to_s] = { id: variant_id, _destroy: '1' }
133
+ variant_ids_to_destroy.each_with_index do |variant_id, index|
134
+ attributes[(last_index + 1 + index).to_s] = { id: variant_id, _destroy: '1' }
129
135
  end
130
136
 
131
137
  attributes
132
138
  end
133
139
 
140
+ def populate_variants_to_discontinue
141
+ ids = variants_to_remove.select { |vid| variant_ids_with_completed_orders.include?(vid) }
142
+ @variants_to_discontinue = product.variants.where(id: ids).to_a if ids.any?
143
+ end
144
+
145
+ def variant_ids_to_destroy
146
+ variants_to_remove - variant_ids_with_completed_orders
147
+ end
148
+
149
+ def variant_ids_with_completed_orders
150
+ @variant_ids_with_completed_orders ||=
151
+ product.variants
152
+ .joins(:orders)
153
+ .merge(Spree::Order.complete)
154
+ .reorder(nil)
155
+ .distinct
156
+ .pluck(:id)
157
+ .map(&:to_s)
158
+ end
159
+
134
160
  def removed_product_option_types_attributes
135
161
  return {} unless can_manage_option_types?
136
162
 
@@ -363,6 +363,10 @@ en:
363
363
  cannot_destroy_if_attached_to_line_items: Cannot delete Variants that are added to placed Orders. In such cases, please discontinue them.
364
364
  must_supply_price_for_variant_or_master: Must supply price for variant or master price for product.
365
365
  no_master_variant_found_to_infer_price: No master variant found to infer price
366
+ spree/webhook_endpoint:
367
+ attributes:
368
+ url:
369
+ internal_address_not_allowed: must not point to an internal or private network address
366
370
  spree/wished_item:
367
371
  attributes:
368
372
  variant:
@@ -1231,6 +1235,7 @@ en:
1231
1235
  this_file_language: English (US)
1232
1236
  translations: Translations
1233
1237
  icon: Icon
1238
+ idempotency_key_reused: This Idempotency-Key has already been used with different request parameters.
1234
1239
  image: Image
1235
1240
  image_alt_text: Add Alt text to your image
1236
1241
  images: Images
@@ -47,6 +47,7 @@ module Spree
47
47
  preference :expedited_exchanges_days_window, :integer, default: 14 # the amount of days the customer has to return their item after the expedited exchange is shipped in order to avoid being charged
48
48
  preference :geocode_addresses, :boolean, default: true
49
49
  preference :images_save_from_url_job_attempts, :integer, default: 5
50
+ preference :max_image_download_size, :integer, default: 20_971_520 # 20 MB in bytes
50
51
 
51
52
  # Preprocessed product image variant sizes at 2x retina resolution.
52
53
  # These variants are generated on upload to reduce runtime processing.
@@ -39,7 +39,7 @@ module Spree
39
39
  end
40
40
 
41
41
  def permitted_store_attributes
42
- permitted_attributes.store_attributes + Spree::Store::SUPPORTED_SOCIAL_NETWORKS.map { |social| "store_#{social}" }
42
+ permitted_attributes.store_attributes
43
43
  end
44
44
  end
45
45
  end
@@ -16,6 +16,7 @@ module Spree
16
16
  cart_remove_item_service: 'Spree::Cart::RemoveItem',
17
17
  cart_remove_line_item_service: 'Spree::Cart::RemoveLineItem',
18
18
  cart_set_item_quantity_service: 'Spree::Cart::SetQuantity',
19
+ cart_upsert_items_service: 'Spree::Cart::UpsertItems',
19
20
  cart_estimate_shipping_rates_service: 'Spree::Cart::EstimateShippingRates',
20
21
  cart_empty_service: 'Spree::Cart::Empty',
21
22
  cart_destroy_service: 'Spree::Cart::Destroy',
@@ -41,6 +42,7 @@ module Spree
41
42
  # order
42
43
  order_approve_service: 'Spree::Orders::Approve',
43
44
  order_cancel_service: 'Spree::Orders::Cancel',
45
+ order_update_service: 'Spree::Orders::Update',
44
46
  order_updater: 'Spree::OrderUpdater',
45
47
 
46
48
  # shipment
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- VERSION = '5.4.0.beta4'.freeze
2
+ VERSION = '5.4.0.beta6'.freeze
3
3
 
4
4
  def self.version
5
5
  VERSION
@@ -266,15 +266,13 @@ module Spree
266
266
  :meta_description, :default_currency, :default_country_iso, :mail_from_address,
267
267
  :customer_support_email, :description, :address, :contact_phone,
268
268
  :supported_locales, :default_locale, :supported_currencies,
269
- :new_order_notifications_email, :seo_robots,
269
+ :new_order_notifications_email,
270
270
  :preferred_admin_locale, :preferred_timezone, :preferred_weight_unit, :preferred_unit_system,
271
271
  :preferred_digital_asset_authorized_clicks, :preferred_digital_asset_authorized_days,
272
272
  :preferred_limit_digital_download_count, :preferred_limit_digital_download_days,
273
273
  :preferred_digital_asset_link_expire_time,
274
- :logo, :mailer_logo, :social_logo, :favicon_image,
275
- :checkout_message, :preferred_guest_checkout,
276
- :customer_terms_of_service, :customer_privacy_policy,
277
- :customer_returns_policy, :customer_shipping_policy]
274
+ :logo, :mailer_logo,
275
+ :preferred_guest_checkout]
278
276
 
279
277
  @@store_credit_attributes = %i[amount currency category_id memo]
280
278
 
@@ -14,14 +14,5 @@ FactoryBot.define do
14
14
  instagram { 'spreecommerce' }
15
15
  meta_description { 'Sample store description.' }
16
16
 
17
- trait :with_favicon do
18
- after(:build) do |store|
19
- store.favicon_image.attach(
20
- io: File.open(Spree::Core::Engine.root.join('spec', 'fixtures', 'thinking-cat.jpg')),
21
- filename: 'thinking-cat.jpg',
22
- content_type: 'image/jpeg'
23
- )
24
- end
25
- end
26
17
  end
27
18
  end
data/lib/tasks/core.rake CHANGED
@@ -8,34 +8,6 @@ namespace :db do
8
8
  end
9
9
  end
10
10
 
11
- desc 'Migrate policies to store policies'
12
- task migrate_policies: :environment do |_t, _args|
13
- # Helper to consistently derive policy name
14
- derive_policy_name = lambda do |name_str|
15
- name_str.to_s.gsub(/customer_/, '').gsub(/_policy$/, '')
16
- end
17
-
18
- # Check if migration has already been run
19
- if Spree::Policy.any?
20
- puts "Policies already exist. Skipping migration to prevent duplicates."
21
- exit
22
- end
23
-
24
- Spree::Store.all.each do |store|
25
- %w[customer_terms_of_service customer_privacy_policy customer_returns_policy customer_shipping_policy].each do |policy_slug|
26
- policy = store.send(policy_slug)
27
- next unless policy.present?
28
-
29
- store.policies.create(
30
- name: Spree.t(derive_policy_name.call(policy_slug)),
31
- body: policy.body
32
- )
33
-
34
- puts "Migrated #{policy_slug} to store #{store.id}"
35
- end
36
- end
37
- end
38
-
39
11
  end
40
12
 
41
13
  namespace :core do