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.
- checksums.yaml +4 -4
- data/app/finders/spree/products/find.rb +1 -28
- data/app/helpers/spree/base_helper.rb +1 -54
- data/app/mailers/spree/base_mailer.rb +4 -3
- data/app/models/concerns/spree/adjustment_source.rb +0 -8
- data/app/models/concerns/spree/admin_user_methods.rb +0 -2
- data/app/models/concerns/spree/image_methods.rb +4 -0
- data/app/models/concerns/spree/metadata.rb +10 -0
- data/app/models/concerns/spree/product_scopes.rb +2 -47
- data/app/models/concerns/spree/stores/markets.rb +7 -7
- data/app/models/concerns/spree/vat_price_calculation.rb +2 -2
- data/app/models/spree/ability.rb +5 -5
- data/app/models/spree/address.rb +3 -2
- data/app/models/spree/adjustable/promotion_accumulator.rb +1 -1
- data/app/models/spree/adjustment.rb +1 -20
- data/app/models/spree/api_key.rb +57 -2
- data/app/models/spree/country.rb +7 -3
- data/app/models/spree/credit_card.rb +0 -27
- data/app/models/spree/current.rb +38 -2
- data/app/models/spree/exports/products.rb +0 -6
- data/app/models/spree/gateway/bogus.rb +9 -9
- data/app/models/spree/gateway.rb +0 -3
- data/app/models/spree/gift_card_batch.rb +4 -0
- data/app/models/spree/image/configuration/active_storage.rb +0 -2
- data/app/models/spree/image.rb +7 -31
- data/app/models/spree/log_entry.rb +8 -5
- data/app/models/spree/order/checkout.rb +0 -18
- data/app/models/spree/order.rb +20 -11
- data/app/models/spree/payment/gateway_options.rb +2 -2
- data/app/models/spree/payment/processing.rb +5 -5
- data/app/models/spree/payment.rb +1 -1
- data/app/models/spree/payment_connection_error.rb +3 -0
- data/app/models/spree/payment_method/check.rb +1 -1
- data/app/models/spree/payment_method/store_credit.rb +5 -5
- data/app/models/spree/payment_response.rb +70 -0
- data/app/models/spree/permission_sets/default_customer.rb +0 -5
- data/app/models/spree/permission_sets/product_display.rb +0 -2
- data/app/models/spree/permission_sets/product_management.rb +0 -2
- data/app/models/spree/product.rb +4 -72
- data/app/models/spree/promotion.rb +2 -14
- data/app/models/spree/promotion_handler/coupon.rb +3 -3
- data/app/models/spree/prototype.rb +0 -3
- data/app/models/spree/refund.rb +6 -2
- data/app/models/spree/shipment/emails.rb +1 -0
- data/app/models/spree/shipping_category.rb +3 -3
- data/app/models/spree/store.rb +10 -49
- data/app/models/spree/store_credit.rb +4 -0
- data/app/models/spree/tax_category.rb +1 -11
- data/app/models/spree/taxon.rb +0 -16
- data/app/models/spree/variant.rb +2 -40
- data/app/models/spree/zone.rb +1 -4
- data/app/services/spree/cart/add_item.rb +8 -4
- data/app/services/spree/cart/create.rb +13 -2
- data/app/services/spree/products/duplicator.rb +0 -12
- data/app/services/spree/products/prepare_nested_attributes.rb +0 -12
- data/config/locales/en.yml +3 -20
- data/db/migrate/20210914000000_spree_four_three.rb +0 -38
- data/db/migrate/20210915064329_add_metadata_to_spree_multiple_tables.rb +0 -1
- data/db/migrate/20260226000000_add_locale_to_spree_orders.rb +5 -0
- data/db/migrate/20260226100000_add_token_digest_to_spree_api_keys.rb +21 -0
- data/lib/generators/spree/cursor_rules/templates/spree_rules.mdc +1 -3
- data/lib/spree/core/configuration.rb +0 -3
- data/lib/spree/core/controller_helpers/strong_parameters.rb +1 -2
- data/lib/spree/core/dependencies.rb +2 -10
- data/lib/spree/core/engine.rb +0 -13
- data/lib/spree/core/pricing/resolver.rb +1 -9
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +10 -25
- data/lib/spree/permitted_attributes.rb +2 -14
- data/lib/spree/testing_support/factories/order_factory.rb +1 -0
- data/lib/spree/testing_support/factories/payment_method_factory.rb +1 -6
- data/lib/spree/testing_support/factories/product_factory.rb +0 -7
- data/lib/spree/testing_support/factories/prototype_factory.rb +0 -2
- data/lib/tasks/core.rake +0 -265
- metadata +8 -101
- data/app/finders/spree/posts/find.rb +0 -137
- data/app/finders/spree/product_properties/find_available.rb +0 -20
- data/app/helpers/spree/mail_helper.rb +0 -27
- data/app/jobs/spree/api_key_touch_job.rb +0 -9
- data/app/mailers/spree/test_mailer.rb +0 -8
- data/app/models/action_text/video_embed.rb +0 -13
- data/app/models/concerns/spree/has_one_link.rb +0 -42
- data/app/models/concerns/spree/linkable.rb +0 -9
- data/app/models/concerns/spree/previewable.rb +0 -17
- data/app/models/spree/data_feed/google.rb +0 -15
- data/app/models/spree/data_feed.rb +0 -42
- data/app/models/spree/gateway/bogus_simple.rb +0 -24
- data/app/models/spree/post.rb +0 -108
- data/app/models/spree/post_category.rb +0 -46
- data/app/models/spree/product_property.rb +0 -51
- data/app/models/spree/property.rb +0 -86
- data/app/models/spree/property_prototype.rb +0 -9
- data/app/models/spree/store_favicon_image.rb +0 -20
- data/app/models/spree/store_logo.rb +0 -4
- data/app/models/spree/store_mailer_logo.rb +0 -7
- data/app/models/spree/taxon_image/configuration/active_storage.rb +0 -26
- data/app/models/spree/taxon_image.rb +0 -28
- data/app/presenters/spree/filters/properties_presenter.rb +0 -23
- data/app/presenters/spree/filters/property_presenter.rb +0 -42
- data/app/services/spree/data_feeds/google/optional_attributes.rb +0 -23
- data/app/services/spree/data_feeds/google/optional_sub_attributes.rb +0 -21
- data/app/services/spree/data_feeds/google/products_list.rb +0 -14
- data/app/services/spree/data_feeds/google/required_attributes.rb +0 -68
- data/app/services/spree/data_feeds/google/rss.rb +0 -109
- data/app/sorters/spree/posts/sort.rb +0 -40
- data/app/views/action_text/video_embeds/_thumbnail.html.erb +0 -1
- data/app/views/action_text/video_embeds/_video_embed.html.erb +0 -3
- data/app/views/layouts/action_text/contents/_content.html.erb +0 -3
- data/app/views/spree/test_mailer/test_email.html.erb +0 -40
- data/app/views/spree/test_mailer/test_email.text.erb +0 -4
- data/config/initializers/oembed.rb +0 -1
- data/db/migrate/20221229132350_create_spree_data_feed_settings.rb +0 -14
- data/db/migrate/20230109084253_create_product_property_translations.rb +0 -24
- data/db/migrate/20230109105943_create_property_translations.rb +0 -24
- data/db/migrate/20230415155958_rename_data_feed_settings_table.rb +0 -5
- data/db/migrate/20230415160828_rename_data_feed_table_columns.rb +0 -7
- data/db/migrate/20230415161226_add_indexes_to_data_feeds_table.rb +0 -5
- data/db/migrate/20230512094803_rename_data_feeds_column_provider_to_type.rb +0 -5
- data/db/migrate/20240914153106_add_display_on_to_spree_properties.rb +0 -5
- data/db/migrate/20240915144935_add_position_to_spree_properties.rb +0 -6
- data/db/migrate/20250121160028_create_spree_posts_and_spree_post_categories.rb +0 -33
- data/db/migrate/20250127083740_add_kind_to_spree_properties.rb +0 -5
- data/db/migrate/20250217171018_create_action_text_video_embeds.rb +0 -11
- data/db/migrate/20250305121657_remove_spree_posts_indices.rb +0 -7
- data/db/migrate/20250730154601_add_unique_index_on_spree_properties_name.rb +0 -24
- data/db/sample_data/posts.rb +0 -7
- data/lib/spree/core/controller_helpers/search.rb +0 -17
- data/lib/spree/core/product_filters.rb +0 -218
- data/lib/spree/core/query_filters/comparable.rb +0 -50
- data/lib/spree/core/query_filters/date.rb +0 -8
- data/lib/spree/core/query_filters/number.rb +0 -8
- data/lib/spree/core/query_filters/text.rb +0 -36
- data/lib/spree/core/query_filters.rb +0 -11
- data/lib/spree/core/search/base.rb +0 -144
- data/lib/spree/testing_support/factories/favicon_image_factory.rb +0 -9
- data/lib/spree/testing_support/factories/google_data_feed_factory.rb +0 -7
- data/lib/spree/testing_support/factories/post_category_factory.rb +0 -7
- data/lib/spree/testing_support/factories/post_factory.rb +0 -22
- data/lib/spree/testing_support/factories/product_property_factory.rb +0 -7
- data/lib/spree/testing_support/factories/property_factory.rb +0 -28
- data/lib/spree/testing_support/factories/taxon_image_factory.rb +0 -9
- data/lib/spree/testing_support/flash.rb +0 -25
- data/lib/spree/testing_support/flatpickr_capybara.rb +0 -124
- data/lib/tasks/exchanges.rake +0 -66
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: af6f55a25483bfb02dab0b15f67356a2732cbeb190074b9ddb75a1692594fb7a
|
|
4
|
+
data.tar.gz: 8f0b8f77983432ef1e1baa52def6ed2674f9e0794bc632dd91757551c4ee71c4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 46c6fc812dc90ba1ae3061b2e4066df5e9dd8ad530fde2db85095a7b5cb444fec2d51f4736a528c61ee4423e64d986478fdcf5478c40888e99818b849e444d60
|
|
7
|
+
data.tar.gz: aa2913c4e9882dd0e77d03ddcfae4f8277e4657b807080ce2d3549fd63f5c6da18448e2574b7742ad82b227a299dccfce3717a7df504be4442e3c7f0bf21629e
|
|
@@ -19,7 +19,6 @@ module Spree
|
|
|
19
19
|
@sort_by = params.dig(:sort_by)
|
|
20
20
|
@deleted = params.dig(:filter, :show_deleted)
|
|
21
21
|
@discontinued = params.dig(:filter, :show_discontinued)
|
|
22
|
-
@properties = params.dig(:filter, :properties)
|
|
23
22
|
@in_stock = params.dig(:filter, :in_stock)
|
|
24
23
|
@backorderable = params.dig(:filter, :backorderable)
|
|
25
24
|
@purchasable = params.dig(:filter, :purchasable)
|
|
@@ -46,7 +45,6 @@ module Spree
|
|
|
46
45
|
products = by_slug(products)
|
|
47
46
|
products = by_options(products)
|
|
48
47
|
products = by_option_value_ids(products)
|
|
49
|
-
products = by_properties(products)
|
|
50
48
|
products = by_tags(products)
|
|
51
49
|
products = include_deleted(products)
|
|
52
50
|
products = show_only_stock(products)
|
|
@@ -63,7 +61,7 @@ module Spree
|
|
|
63
61
|
private
|
|
64
62
|
|
|
65
63
|
attr_reader :ids, :skus, :price, :currency, :taxons, :concat_taxons, :name, :options, :option_value_ids, :scope,
|
|
66
|
-
:sort_by, :deleted, :discontinued, :
|
|
64
|
+
:sort_by, :deleted, :discontinued, :store, :in_stock, :backorderable, :purchasable, :tags,
|
|
67
65
|
:query, :vendor_ids, :out_of_stock, :slug, :taxonomies
|
|
68
66
|
|
|
69
67
|
def query?
|
|
@@ -114,10 +112,6 @@ module Spree
|
|
|
114
112
|
sort_by.present?
|
|
115
113
|
end
|
|
116
114
|
|
|
117
|
-
def properties?
|
|
118
|
-
properties.present? && properties.values.reject(&:empty?).present?
|
|
119
|
-
end
|
|
120
|
-
|
|
121
115
|
def vendor_ids?
|
|
122
116
|
vendor_ids.present?
|
|
123
117
|
end
|
|
@@ -224,27 +218,6 @@ module Spree
|
|
|
224
218
|
products.where(id: product_ids)
|
|
225
219
|
end
|
|
226
220
|
|
|
227
|
-
def by_properties(products)
|
|
228
|
-
return products unless properties?
|
|
229
|
-
|
|
230
|
-
product_ids = []
|
|
231
|
-
index = 0
|
|
232
|
-
|
|
233
|
-
properties.to_unsafe_hash.each do |property_filter_param, product_properties_values|
|
|
234
|
-
next if property_filter_param.blank? || product_properties_values.empty?
|
|
235
|
-
|
|
236
|
-
values = product_properties_values.split(',').reject(&:empty?).uniq.map(&:parameterize)
|
|
237
|
-
|
|
238
|
-
next if values.empty?
|
|
239
|
-
|
|
240
|
-
ids = scope.unscope(:order, :includes).with_property_values(property_filter_param, values).ids
|
|
241
|
-
product_ids = index == 0 ? ids : product_ids & ids
|
|
242
|
-
index += 1
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
products.where(id: product_ids)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
221
|
def by_tags(products)
|
|
249
222
|
return products if tags.empty?
|
|
250
223
|
|
|
@@ -68,30 +68,10 @@ module Spree
|
|
|
68
68
|
end
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
def spree_favicon_path
|
|
72
|
-
Spree::Deprecation.warn('BaseHelper#spree_favicon_path is deprecated and will be removed in Spree 5.5. Please use Active Storage URL helpers instead.')
|
|
73
|
-
|
|
74
|
-
if current_store.favicon.present?
|
|
75
|
-
main_app.cdn_image_url(current_store.favicon)
|
|
76
|
-
else
|
|
77
|
-
url_for('favicon.ico')
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
71
|
def object
|
|
82
72
|
instance_variable_get('@' + controller_name.singularize)
|
|
83
73
|
end
|
|
84
74
|
|
|
85
|
-
def method_missing(method_name, *args, &block)
|
|
86
|
-
if image_style = image_style_from_method_name(method_name)
|
|
87
|
-
Spree::Deprecation.warn("#{BaseHelper.name}##{method_name} is deprecated and will be removed in Spree 5.5. Please use spree_image_tag instead - https://spreecommerce.org/docs/developer/core-concepts/images-assets#preprocessed-named-variants")
|
|
88
|
-
define_image_method(image_style)
|
|
89
|
-
send(method_name, *args)
|
|
90
|
-
else
|
|
91
|
-
super
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
|
95
75
|
def pretty_time(time)
|
|
96
76
|
return '' if time.blank?
|
|
97
77
|
|
|
@@ -119,7 +99,7 @@ module Spree
|
|
|
119
99
|
end
|
|
120
100
|
|
|
121
101
|
# returns the URL of an object on the storefront
|
|
122
|
-
# @param resource [Spree::Product, Spree::
|
|
102
|
+
# @param resource [Spree::Product, Spree::Taxon, Spree::Page] the resource to get the URL for
|
|
123
103
|
# @param options [Hash] the options for the URL
|
|
124
104
|
# @option options [String] :locale the locale of the resource, defaults to I18n.locale
|
|
125
105
|
# @option options [String] :store the store of the resource, defaults to current_store
|
|
@@ -155,9 +135,6 @@ module Spree
|
|
|
155
135
|
params = "?#{params}" if params.present?
|
|
156
136
|
|
|
157
137
|
"#{base_url + localize}/products/#{resource.slug}#{params}"
|
|
158
|
-
elsif defined?(Spree::Post) && resource.is_a?(Spree::Post)
|
|
159
|
-
preview_id = options[:preview_id].present? ? "?preview_id=#{options[:preview_id]}" : ''
|
|
160
|
-
"#{base_url + localize}/posts/#{resource.slug}#{preview_id}"
|
|
161
138
|
elsif resource.is_a?(Spree::Taxon)
|
|
162
139
|
"#{base_url + localize}/t/#{resource.permalink}"
|
|
163
140
|
elsif defined?(Spree::Page) && (resource.is_a?(Spree::Page) || resource.is_a?(Spree::Policy))
|
|
@@ -221,36 +198,6 @@ module Spree
|
|
|
221
198
|
|
|
222
199
|
private
|
|
223
200
|
|
|
224
|
-
def create_product_image_tag(image, product, options, style)
|
|
225
|
-
options[:alt] = image.alt.blank? ? product.name : image.alt
|
|
226
|
-
image_tag main_app.cdn_image_url(image.url(style)), options
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
def define_image_method(style)
|
|
230
|
-
self.class.send :define_method, "#{style}_image" do |product, *options|
|
|
231
|
-
options = options.first || {}
|
|
232
|
-
options[:alt] ||= product.name
|
|
233
|
-
image_path = default_image_for_product_or_variant(product)
|
|
234
|
-
img = if image_path.present?
|
|
235
|
-
create_product_image_tag image_path, product, options, style
|
|
236
|
-
else
|
|
237
|
-
width = style.to_s.split('x').first.to_i
|
|
238
|
-
height = style.to_s.split('x').last.to_i
|
|
239
|
-
content_tag(:div, width: width, height: height, style: "background-color: #f0f0f0;")
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
content_tag(:div, img, class: "admin-product-image-container #{style}-img")
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
# Returns style of image or nil
|
|
247
|
-
def image_style_from_method_name(method_name)
|
|
248
|
-
style = method_name.to_s.sub(/_image$/, '')
|
|
249
|
-
if method_name.to_s.match(/_image$/) && Spree::Image.styles.keys.map(&:to_s).include?(style)
|
|
250
|
-
style
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
|
|
254
201
|
I18N_PLURAL_MANY_COUNT = 2.1
|
|
255
202
|
def plural_resource_name(resource_class)
|
|
256
203
|
resource_class.model_name.human(count: I18N_PLURAL_MANY_COUNT)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class BaseMailer < ActionMailer::Base
|
|
3
|
-
helper Spree::MailHelper
|
|
4
|
-
|
|
5
3
|
def current_store
|
|
6
4
|
@current_store ||= @order&.store.presence || Spree::Store.current || Spree::Store.default
|
|
7
5
|
end
|
|
@@ -47,8 +45,11 @@ module Spree
|
|
|
47
45
|
ActionMailer::Base.default_url_options[:host] = host_url
|
|
48
46
|
end
|
|
49
47
|
|
|
48
|
+
# Sets the I18n locale for the email.
|
|
49
|
+
# Prefers the order's locale (the language the customer used),
|
|
50
|
+
# falls back to the store's default locale.
|
|
50
51
|
def set_email_locale
|
|
51
|
-
locale = @order&.store&.default_locale || current_store&.default_locale
|
|
52
|
+
locale = @order&.locale.presence || @order&.store&.default_locale || current_store&.default_locale
|
|
52
53
|
I18n.locale = locale if locale.present?
|
|
53
54
|
end
|
|
54
55
|
end
|
|
@@ -5,7 +5,6 @@ module Spree
|
|
|
5
5
|
included do
|
|
6
6
|
has_many :adjustments, as: :source
|
|
7
7
|
before_destroy :deals_with_adjustments_for_deleted_source
|
|
8
|
-
after_commit :clear_adjustment_source_cache
|
|
9
8
|
end
|
|
10
9
|
|
|
11
10
|
protected
|
|
@@ -55,12 +54,5 @@ module Spree
|
|
|
55
54
|
# This would mean that the order's total is not altered at all.
|
|
56
55
|
adjustments.for_complete_order.update_all(source_id: nil, updated_at: Time.current)
|
|
57
56
|
end
|
|
58
|
-
|
|
59
|
-
def clear_adjustment_source_cache
|
|
60
|
-
# Use base_class.name to match the polymorphic_name stored in source_type
|
|
61
|
-
# For STI models like PromotionAction subclasses, this ensures cache key consistency
|
|
62
|
-
cache_class_name = self.class.polymorphic_name
|
|
63
|
-
Rails.cache.delete("spree/adjustment_source/#{cache_class_name}/#{id}")
|
|
64
|
-
end
|
|
65
57
|
end
|
|
66
58
|
end
|
|
@@ -22,7 +22,6 @@ module Spree
|
|
|
22
22
|
has_many :created_gift_card_batches, class_name: 'Spree::GiftCardBatch', foreign_key: :created_by_id
|
|
23
23
|
has_many :refunded_refunds, class_name: 'Spree::Refund', foreign_key: :refunder_id
|
|
24
24
|
has_many :performed_reimbursements, class_name: 'Spree::Reimbursement', foreign_key: :performed_by_id
|
|
25
|
-
has_many :authored_posts, class_name: 'Spree::Post', foreign_key: :author_id
|
|
26
25
|
has_many :created_store_credits, class_name: 'Spree::StoreCredit', foreign_key: :created_by_id
|
|
27
26
|
has_many :reports, class_name: 'Spree::Report', foreign_key: :user_id
|
|
28
27
|
has_many :exports, class_name: 'Spree::Export', foreign_key: :user_id
|
|
@@ -73,7 +72,6 @@ module Spree
|
|
|
73
72
|
created_gift_card_batches.update_all(created_by_id: nil, updated_at: Time.current)
|
|
74
73
|
refunded_refunds.update_all(refunder_id: nil, updated_at: Time.current)
|
|
75
74
|
performed_reimbursements.update_all(performed_by_id: nil, updated_at: Time.current)
|
|
76
|
-
authored_posts.update_all(author_id: nil, updated_at: Time.current)
|
|
77
75
|
created_store_credits.update_all(created_by_id: nil, updated_at: Time.current)
|
|
78
76
|
|
|
79
77
|
# resources to destroy
|
|
@@ -3,6 +3,8 @@ module Spree
|
|
|
3
3
|
extend ActiveSupport::Concern
|
|
4
4
|
|
|
5
5
|
def generate_url(size:, gravity: 'centre', quality: 80, background: [0, 0, 0])
|
|
6
|
+
Spree::Deprecation.warn("ImageMethods#generate_url is deprecated and will be removed in Spree 6.0. Please use active storage variants with cdn_image_url")
|
|
7
|
+
|
|
6
8
|
return if size.blank?
|
|
7
9
|
|
|
8
10
|
size = size.gsub(/\s+/, '')
|
|
@@ -18,6 +20,8 @@ module Spree
|
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def original_url
|
|
23
|
+
Spree::Deprecation.warn("ImageMethods#original_url is deprecated and will be removed in Spree 6.0. Please use active storage variants with cdn_image_url")
|
|
24
|
+
|
|
21
25
|
cdn_image_url(attachment)
|
|
22
26
|
end
|
|
23
27
|
|
|
@@ -12,6 +12,16 @@ module Spree
|
|
|
12
12
|
serialize :private_metadata, coder: HashSerializer
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
# `metadata` is the primary API-facing accessor.
|
|
16
|
+
# It maps to `private_metadata` under the hood (Stripe-style: write-only, never returned in Store API).
|
|
17
|
+
def metadata
|
|
18
|
+
private_metadata
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def metadata=(value)
|
|
22
|
+
self.private_metadata = value
|
|
23
|
+
end
|
|
24
|
+
|
|
15
25
|
# https://nandovieira.com/using-postgresql-and-jsonb-with-ruby-on-rails
|
|
16
26
|
class HashSerializer
|
|
17
27
|
def self.dump(hash)
|
|
@@ -31,21 +31,6 @@ module Spree
|
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
def self.property_conditions(property)
|
|
35
|
-
properties_table = Property.table_name
|
|
36
|
-
|
|
37
|
-
case property
|
|
38
|
-
when Property then { "#{properties_table}.id" => property.id }
|
|
39
|
-
when Integer then { "#{properties_table}.id" => property }
|
|
40
|
-
else
|
|
41
|
-
if Property.column_for_attribute('id').type == :uuid
|
|
42
|
-
["#{properties_table}.name = ? OR #{properties_table}.id = ?", property, property]
|
|
43
|
-
else
|
|
44
|
-
{ "#{properties_table}.name" => property }
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
|
|
49
34
|
add_simple_scopes simple_scopes
|
|
50
35
|
|
|
51
36
|
add_search_scope :ascend_by_master_price do
|
|
@@ -149,33 +134,6 @@ module Spree
|
|
|
149
134
|
order(Arel.sql("#{min_position_sql} ASC"))
|
|
150
135
|
end
|
|
151
136
|
|
|
152
|
-
# a scope that finds all products having property specified by name, object or id
|
|
153
|
-
add_search_scope :with_property do |property|
|
|
154
|
-
joins(:properties).where(property_conditions(property))
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
# a simple test for product with a certain property-value pairing
|
|
158
|
-
# note that it can test for properties with NULL values, but not for absent values
|
|
159
|
-
add_search_scope :with_property_value do |property, value|
|
|
160
|
-
if Spree.use_translations?
|
|
161
|
-
joins(:properties).
|
|
162
|
-
join_translation_table(Property).
|
|
163
|
-
join_translation_table(ProductProperty).
|
|
164
|
-
where(ProductProperty.translation_table_alias => { value: value }).
|
|
165
|
-
where(property_conditions(property))
|
|
166
|
-
else
|
|
167
|
-
joins(:properties).
|
|
168
|
-
where(ProductProperty.table_name => { value: value }).
|
|
169
|
-
where(property_conditions(property))
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
add_search_scope :with_property_values do |property_filter_param, property_values|
|
|
174
|
-
joins(product_properties: :property).
|
|
175
|
-
where(Property.table_name => { filter_param: property_filter_param }).
|
|
176
|
-
where(ProductProperty.table_name => { filter_param: property_values.map(&:parameterize) })
|
|
177
|
-
end
|
|
178
|
-
|
|
179
137
|
add_search_scope :with_option do |option|
|
|
180
138
|
if option.is_a?(OptionType)
|
|
181
139
|
joins(:option_types).where(spree_option_types: { id: option.id })
|
|
@@ -226,13 +184,10 @@ module Spree
|
|
|
226
184
|
where(Spree::OptionValue.table_name => { id: actual_ids })
|
|
227
185
|
end
|
|
228
186
|
|
|
229
|
-
# Finds all products which have
|
|
230
|
-
# 1) have an option value with the name matching the one given
|
|
231
|
-
# 2) have a product property with a value matching the one given
|
|
187
|
+
# Finds all products which have an option value with the name matching the one given
|
|
232
188
|
add_search_scope :with do |value|
|
|
233
189
|
includes(variants: :option_values).
|
|
234
|
-
|
|
235
|
-
where("#{OptionValue.table_name}.name = ? OR #{ProductProperty.table_name}.value = ?", value, value)
|
|
190
|
+
where("#{OptionValue.table_name}.name = ?", value)
|
|
236
191
|
end
|
|
237
192
|
|
|
238
193
|
# Finds all products that have a name containing the given words.
|
|
@@ -66,15 +66,15 @@ module Spree
|
|
|
66
66
|
# @return [ActiveRecord::Relation<Spree::Country>]
|
|
67
67
|
def countries_from_markets
|
|
68
68
|
Spree::Country
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
.where(id: Spree::Country.joins(market_countries: :market).where(Spree::Market.table_name => { store_id: id, deleted_at: nil }).select(:id))
|
|
70
|
+
.order(:name)
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
# Returns the countries available for checkout, derived from markets
|
|
74
74
|
# @return [Array<Spree::Country>]
|
|
75
75
|
def countries_available_for_checkout
|
|
76
|
-
@countries_available_for_checkout
|
|
77
|
-
if
|
|
76
|
+
@countries_available_for_checkout = begin
|
|
77
|
+
if has_markets?
|
|
78
78
|
markets.flat_map(&:countries).uniq.sort_by(&:name)
|
|
79
79
|
else
|
|
80
80
|
Spree::Country.all.to_a
|
|
@@ -85,7 +85,7 @@ module Spree
|
|
|
85
85
|
# Returns supported currencies derived from markets, falling back to store attributes
|
|
86
86
|
# @return [Array<Money::Currency>]
|
|
87
87
|
def supported_currencies_list
|
|
88
|
-
@supported_currencies_list ||= if
|
|
88
|
+
@supported_currencies_list ||= if has_markets?
|
|
89
89
|
markets.pluck(:currency).uniq.map do |code|
|
|
90
90
|
::Money::Currency.find(code)
|
|
91
91
|
end.compact.sort_by { |c| c.iso_code == default_currency ? 0 : 1 }
|
|
@@ -97,7 +97,7 @@ module Spree
|
|
|
97
97
|
# Returns supported locales derived from markets, falling back to store attributes
|
|
98
98
|
# @return [Array<String>]
|
|
99
99
|
def supported_locales_list
|
|
100
|
-
@supported_locales_list ||= if
|
|
100
|
+
@supported_locales_list ||= if has_markets?
|
|
101
101
|
(markets.flat_map(&:supported_locales_list) << default_locale).compact.uniq.sort
|
|
102
102
|
else
|
|
103
103
|
legacy_supported_locales_list
|
|
@@ -107,7 +107,7 @@ module Spree
|
|
|
107
107
|
private
|
|
108
108
|
|
|
109
109
|
def has_markets?
|
|
110
|
-
persisted? && (markets.loaded? ? markets.any? : markets.exists?)
|
|
110
|
+
@has_markets ||= persisted? && (markets.loaded? ? markets.any? : markets.exists?)
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
def legacy_supported_currencies_list
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
module VatPriceCalculation
|
|
3
3
|
def gross_amount(amount, price_options)
|
|
4
|
-
return amount
|
|
4
|
+
return amount if amount.nil? || !outside_default_vat_zone?(price_options)
|
|
5
5
|
|
|
6
6
|
round_to_two_places(add_foreign_vat_for(amount, price_options))
|
|
7
7
|
end
|
|
@@ -38,7 +38,7 @@ module Spree
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def default_zone
|
|
41
|
-
@
|
|
41
|
+
@default_zone ||= Spree::Zone.default_tax
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
def round_to_two_places(amount)
|
data/app/models/spree/ability.rb
CHANGED
|
@@ -59,6 +59,8 @@ module Spree
|
|
|
59
59
|
# Include any abilities registered by extensions, etc.
|
|
60
60
|
# this is legacy behaviour and should be removed in Spree 5.0
|
|
61
61
|
Ability.abilities.merge(abilities_to_register).each do |clazz|
|
|
62
|
+
Spree::Deprecation.warn("Ability merging is deprecated and will be removed in Spree 5.5. Please use Permission Sets")
|
|
63
|
+
|
|
62
64
|
merge clazz.new(@user)
|
|
63
65
|
end
|
|
64
66
|
end
|
|
@@ -133,6 +135,7 @@ module Spree
|
|
|
133
135
|
end
|
|
134
136
|
|
|
135
137
|
def apply_admin_permissions(_user, _options)
|
|
138
|
+
Spree::Deprecation.warn("Ability#apply_admin_permissions is deprecated and will be removed in Spree 5.5. Please use Permission Sets")
|
|
136
139
|
can :manage, :all
|
|
137
140
|
cannot :cancel, Spree::Order
|
|
138
141
|
can :cancel, Spree::Order, &:allow_cancel?
|
|
@@ -143,6 +146,8 @@ module Spree
|
|
|
143
146
|
end
|
|
144
147
|
|
|
145
148
|
def apply_user_permissions(user, _options)
|
|
149
|
+
Spree::Deprecation.warn("Ability#apply_user_permissions is deprecated and will be removed in Spree 5.5. Please use Permission Sets")
|
|
150
|
+
|
|
146
151
|
can :read, ::Spree::Country
|
|
147
152
|
can :read, ::Spree::OptionType
|
|
148
153
|
can :read, ::Spree::OptionValue
|
|
@@ -157,8 +162,6 @@ module Spree
|
|
|
157
162
|
can :manage, ::Spree::Address, user_id: user.id if user.persisted?
|
|
158
163
|
can [:read, :destroy], ::Spree::CreditCard, user_id: user.id
|
|
159
164
|
can :read, ::Spree::Product
|
|
160
|
-
can :read, ::Spree::ProductProperty
|
|
161
|
-
can :read, ::Spree::Property
|
|
162
165
|
can :create, ::Spree.user_class
|
|
163
166
|
can [:show, :update, :destroy], ::Spree.user_class, id: user.id
|
|
164
167
|
can :read, ::Spree::State
|
|
@@ -179,9 +182,6 @@ module Spree
|
|
|
179
182
|
digital_link.token == token
|
|
180
183
|
end
|
|
181
184
|
can :read, ::Spree::Policy
|
|
182
|
-
can :read, ::Spree::Page if defined?(Spree::Page)
|
|
183
|
-
can :read, ::Spree::Post if defined?(Spree::Post)
|
|
184
|
-
can :read, ::Spree::PostCategory if defined?(Spree::PostCategory)
|
|
185
185
|
end
|
|
186
186
|
|
|
187
187
|
def protect_admin_role
|
data/app/models/spree/address.rb
CHANGED
|
@@ -175,8 +175,8 @@ module Spree
|
|
|
175
175
|
attributes.except('id', 'created_at', 'updated_at', 'country_id').all? { |_, v| v.nil? }
|
|
176
176
|
end
|
|
177
177
|
|
|
178
|
-
# Generates an
|
|
179
|
-
def
|
|
178
|
+
# Generates an address hash for payment gateway options
|
|
179
|
+
def gateway_hash
|
|
180
180
|
{
|
|
181
181
|
name: full_name,
|
|
182
182
|
address1: address1,
|
|
@@ -188,6 +188,7 @@ module Spree
|
|
|
188
188
|
phone: phone
|
|
189
189
|
}
|
|
190
190
|
end
|
|
191
|
+
alias_method :active_merchant_hash, :gateway_hash
|
|
191
192
|
|
|
192
193
|
def require_phone?
|
|
193
194
|
# We want to collect phone number for quick checkout but not to validate it
|
|
@@ -25,7 +25,7 @@ module Spree
|
|
|
25
25
|
def add_adjustment(adjustment, opts = {})
|
|
26
26
|
return unless adjustment.promotion?
|
|
27
27
|
|
|
28
|
-
source = opts[:source] || adjustment.
|
|
28
|
+
source = opts[:source] || adjustment.source
|
|
29
29
|
promotion = opts[:promotion] || source.promotion
|
|
30
30
|
|
|
31
31
|
add(adjustments, adjustment, adjustment.id)
|
|
@@ -98,30 +98,11 @@ module Spree
|
|
|
98
98
|
!included?
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
-
# Returns the source using Rails.cache to avoid repeated database lookups.
|
|
102
|
-
# Sources are cached by their type and ID combination.
|
|
103
|
-
# Cache is automatically invalidated when the source is saved (see AdjustmentSource concern).
|
|
104
|
-
#
|
|
105
|
-
# @return [Object, nil] The source object (TaxRate, PromotionAction, etc.)
|
|
106
|
-
def cached_source
|
|
107
|
-
return nil if source_type.blank? || source_id.blank?
|
|
108
|
-
|
|
109
|
-
Rails.cache.fetch(source_cache_key) { source }
|
|
110
|
-
rescue TypeError
|
|
111
|
-
# Handle objects that can't be serialized (e.g., mock objects in tests)
|
|
112
|
-
source
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Cache key for the source object
|
|
116
|
-
def source_cache_key
|
|
117
|
-
"spree/adjustment_source/#{source_type}/#{source_id}"
|
|
118
|
-
end
|
|
119
|
-
|
|
120
101
|
# Passing a target here would always be recommended as it would avoid
|
|
121
102
|
# hitting the database again and would ensure you're compute values over
|
|
122
103
|
# the specific object amount passed here.
|
|
123
104
|
def update!(target = adjustable)
|
|
124
|
-
src =
|
|
105
|
+
src = source
|
|
125
106
|
return amount if closed? || src.blank?
|
|
126
107
|
|
|
127
108
|
new_amount = src.compute_amount(target)
|
data/app/models/spree/api_key.rb
CHANGED
|
@@ -6,13 +6,21 @@ module Spree
|
|
|
6
6
|
PREFIXES = { 'publishable' => 'pk_', 'secret' => 'sk_' }.freeze
|
|
7
7
|
TOKEN_LENGTH = 24
|
|
8
8
|
|
|
9
|
+
# @!attribute [r] plaintext_token
|
|
10
|
+
# The raw token value, only available in memory immediately after creation
|
|
11
|
+
# of a secret key. Not persisted to the database.
|
|
12
|
+
# @return [String, nil]
|
|
13
|
+
attr_reader :plaintext_token
|
|
14
|
+
|
|
9
15
|
belongs_to :store, class_name: 'Spree::Store'
|
|
10
16
|
belongs_to :created_by, polymorphic: true, optional: true
|
|
11
17
|
belongs_to :revoked_by, polymorphic: true, optional: true
|
|
12
18
|
|
|
13
19
|
validates :name, presence: true
|
|
14
20
|
validates :key_type, presence: true, inclusion: { in: KEY_TYPES }
|
|
15
|
-
validates :token, presence: true, uniqueness: { scope: spree_base_uniqueness_scope }
|
|
21
|
+
validates :token, presence: true, uniqueness: { scope: spree_base_uniqueness_scope }, if: :publishable?
|
|
22
|
+
validates :token_digest, presence: true, uniqueness: true, if: :secret?
|
|
23
|
+
validates :token_prefix, presence: true, if: :secret?
|
|
16
24
|
validates :store, presence: true
|
|
17
25
|
|
|
18
26
|
before_validation :generate_token, on: :create
|
|
@@ -22,26 +30,73 @@ module Spree
|
|
|
22
30
|
scope :publishable, -> { where(key_type: 'publishable') }
|
|
23
31
|
scope :secret, -> { where(key_type: 'secret') }
|
|
24
32
|
|
|
33
|
+
# Finds an active secret API key by computing the HMAC-SHA256 digest
|
|
34
|
+
# of the provided plaintext token and looking up by +token_digest+.
|
|
35
|
+
#
|
|
36
|
+
# @param plaintext [String] the raw secret key (e.g. "sk_abc123...")
|
|
37
|
+
# @return [Spree::ApiKey, nil] the matching active secret key, or nil
|
|
38
|
+
def self.find_by_secret_token(plaintext)
|
|
39
|
+
return nil if plaintext.blank?
|
|
40
|
+
|
|
41
|
+
digest = compute_token_digest(plaintext)
|
|
42
|
+
active.secret.find_by(token_digest: digest)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Computes the HMAC-SHA256 hex digest for a given plaintext token.
|
|
46
|
+
#
|
|
47
|
+
# @param plaintext [String] the raw token value
|
|
48
|
+
# @return [String] the hex-encoded HMAC-SHA256 digest
|
|
49
|
+
def self.compute_token_digest(plaintext)
|
|
50
|
+
OpenSSL::HMAC.hexdigest('SHA256', hmac_secret, plaintext)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns the HMAC secret used for token hashing.
|
|
54
|
+
#
|
|
55
|
+
# @return [String] the application's secret key base
|
|
56
|
+
def self.hmac_secret
|
|
57
|
+
Rails.application.secret_key_base
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# @return [Boolean] whether this is a publishable (Store API) key
|
|
25
61
|
def publishable?
|
|
26
62
|
key_type == 'publishable'
|
|
27
63
|
end
|
|
28
64
|
|
|
65
|
+
# @return [Boolean] whether this is a secret (Admin API) key
|
|
29
66
|
def secret?
|
|
30
67
|
key_type == 'secret'
|
|
31
68
|
end
|
|
32
69
|
|
|
70
|
+
# @return [Boolean] whether this key has not been revoked
|
|
33
71
|
def active?
|
|
34
72
|
revoked_at.nil?
|
|
35
73
|
end
|
|
36
74
|
|
|
75
|
+
# Revokes this API key by setting +revoked_at+ to the current time.
|
|
76
|
+
#
|
|
77
|
+
# @param user [Object, nil] the user who performed the revocation
|
|
78
|
+
# @return [Boolean] true if the update succeeded
|
|
37
79
|
def revoke!(user = nil)
|
|
38
80
|
update!(revoked_at: Time.current, revoked_by: user)
|
|
39
81
|
end
|
|
40
82
|
|
|
41
83
|
private
|
|
42
84
|
|
|
85
|
+
# Generates the token on creation. For publishable keys, stores the raw token
|
|
86
|
+
# in the +token+ column. For secret keys, computes an HMAC-SHA256 digest stored
|
|
87
|
+
# in +token_digest+, saves the first 12 characters as +token_prefix+ for display,
|
|
88
|
+
# and exposes the raw value via {#plaintext_token} (available only in memory).
|
|
43
89
|
def generate_token
|
|
44
|
-
|
|
90
|
+
raw_token = "#{PREFIXES[key_type]}#{SecureRandom.base58(TOKEN_LENGTH)}"
|
|
91
|
+
|
|
92
|
+
if secret?
|
|
93
|
+
@plaintext_token = raw_token
|
|
94
|
+
self.token_prefix = raw_token[0, 12]
|
|
95
|
+
self.token_digest = self.class.compute_token_digest(raw_token)
|
|
96
|
+
self.token = nil
|
|
97
|
+
else
|
|
98
|
+
self.token ||= raw_token
|
|
99
|
+
end
|
|
45
100
|
end
|
|
46
101
|
end
|
|
47
102
|
end
|
data/app/models/spree/country.rb
CHANGED
|
@@ -43,7 +43,7 @@ module Spree
|
|
|
43
43
|
#
|
|
44
44
|
# @return [String, nil] currency code (e.g., 'USD', 'EUR') or nil if no market found
|
|
45
45
|
def market_currency
|
|
46
|
-
|
|
46
|
+
current_market&.currency
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
# Returns the default locale for this country from its market in the current store.
|
|
@@ -51,14 +51,18 @@ module Spree
|
|
|
51
51
|
#
|
|
52
52
|
# @return [String, nil] locale code (e.g., 'en', 'de') or nil if no market found
|
|
53
53
|
def market_locale
|
|
54
|
-
|
|
54
|
+
current_market&.default_locale
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
# Returns the supported locales for this country from its market in the current store.
|
|
58
58
|
#
|
|
59
59
|
# @return [Array<String>] locale codes (e.g., ['en', 'fr']) or empty array if no market found
|
|
60
60
|
def market_supported_locales
|
|
61
|
-
|
|
61
|
+
current_market&.supported_locales_list || []
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def current_market
|
|
65
|
+
@current_market ||= Spree::Current.store&.market_for_country(self)
|
|
62
66
|
end
|
|
63
67
|
|
|
64
68
|
def <=>(other)
|