spree_core 5.4.3 → 5.5.0.rc2
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/helpers/spree/base_helper.rb +0 -82
- data/app/helpers/spree/currency_helper.rb +0 -12
- data/app/helpers/spree/products_helper.rb +0 -8
- data/app/jobs/spree/base_job.rb +18 -0
- data/app/jobs/spree/events/subscriber_job.rb +2 -1
- data/app/jobs/spree/exports/generate_job.rb +11 -0
- data/app/jobs/spree/images/save_from_url_job.rb +23 -8
- data/app/jobs/spree/imports/assign_tags_job.rb +11 -0
- data/app/jobs/spree/imports/base_job.rb +15 -0
- data/app/jobs/spree/imports/create_categories_job.rb +37 -0
- data/app/jobs/spree/imports/create_rows_job.rb +1 -3
- data/app/jobs/spree/imports/process_group_job.rb +8 -6
- data/app/jobs/spree/imports/process_rows_job.rb +1 -3
- data/app/jobs/spree/media/migrate_product_assets_job.rb +83 -0
- data/app/jobs/spree/products/refresh_metrics_job.rb +15 -4
- data/app/jobs/spree/reports/generate_job.rb +11 -0
- data/app/jobs/spree/search_provider/index_job.rb +5 -1
- data/app/jobs/spree/search_provider/remove_job.rb +4 -0
- data/app/jobs/spree/stock_reservations/expire_job.rb +11 -0
- data/app/models/concerns/spree/calculated_adjustments.rb +34 -1
- data/app/models/concerns/spree/display_on.rb +31 -0
- data/app/models/concerns/spree/metafields.rb +167 -5
- data/app/models/concerns/spree/preference_schema.rb +191 -0
- data/app/models/concerns/spree/prefixed_id.rb +94 -11
- data/app/models/concerns/spree/product_scopes.rb +36 -17
- data/app/models/concerns/spree/ransackable_attributes.rb +5 -1
- data/app/models/concerns/spree/search_indexable.rb +8 -7
- data/app/models/concerns/spree/searchable.rb +11 -2
- data/app/models/concerns/spree/stores/channels.rb +20 -0
- data/app/models/concerns/spree/stores/markets.rb +21 -5
- data/app/models/concerns/spree/typed_associations.rb +120 -0
- data/app/models/concerns/spree/user_methods.rb +71 -12
- data/app/models/spree/ability.rb +4 -117
- data/app/models/spree/api_key.rb +60 -0
- data/app/models/spree/asset.rb +28 -5
- data/app/models/spree/authentication/strategy_registry.rb +72 -0
- data/app/models/spree/base.rb +18 -1
- data/app/models/spree/channel.rb +159 -0
- data/app/models/spree/country.rb +2 -0
- data/app/models/spree/current.rb +7 -3
- data/app/models/spree/custom_field.rb +9 -0
- data/app/models/spree/custom_field_definition.rb +7 -0
- data/app/models/spree/customer_group.rb +8 -2
- data/app/models/spree/export.rb +45 -3
- data/app/models/spree/exports/coupon_codes.rb +4 -0
- data/app/models/spree/exports/newsletter_subscribers.rb +4 -0
- data/app/models/spree/exports/product_translations.rb +4 -0
- data/app/models/spree/gateway.rb +25 -0
- data/app/models/spree/gift_card.rb +1 -1
- data/app/models/spree/gift_card_batch.rb +4 -1
- data/app/models/spree/import.rb +5 -0
- data/app/models/spree/import_row.rb +12 -0
- data/app/models/spree/line_item.rb +6 -1
- data/app/models/spree/market.rb +32 -1
- data/app/models/spree/metafield.rb +38 -0
- data/app/models/spree/metafield_definition.rb +29 -6
- data/app/models/spree/metafields/json.rb +10 -0
- data/app/models/spree/newsletter_subscriber.rb +19 -3
- data/app/models/spree/option_type.rb +48 -7
- data/app/models/spree/order/checkout.rb +3 -3
- data/app/models/spree/order.rb +102 -6
- data/app/models/spree/order_approval.rb +19 -0
- data/app/models/spree/order_cancellation.rb +19 -0
- data/app/models/spree/order_routing/has_strategy_preference.rb +28 -0
- data/app/models/spree/order_routing/rules/default_location.rb +16 -0
- data/app/models/spree/order_routing/rules/minimize_splits.rb +45 -0
- data/app/models/spree/order_routing/rules/preferred_location.rb +22 -0
- data/app/models/spree/order_routing/strategy/base.rb +47 -0
- data/app/models/spree/order_routing/strategy/legacy.rb +33 -0
- data/app/models/spree/order_routing/strategy/reducer.rb +68 -0
- data/app/models/spree/order_routing/strategy/rules.rb +83 -0
- data/app/models/spree/order_routing_rule.rb +75 -0
- data/app/models/spree/permission_sets/configuration_management.rb +16 -0
- data/app/models/spree/permission_sets/product_display.rb +2 -0
- data/app/models/spree/permission_sets/product_management.rb +2 -0
- data/app/models/spree/price.rb +14 -1
- data/app/models/spree/price_list.rb +129 -17
- data/app/models/spree/price_rule.rb +11 -1
- data/app/models/spree/price_rules/customer_group_rule.rb +15 -1
- data/app/models/spree/price_rules/market_rule.rb +16 -1
- data/app/models/spree/price_rules/user_rule.rb +21 -2
- data/app/models/spree/product/channels.rb +149 -0
- data/app/models/spree/product/legacy_multi_store_support.rb +40 -0
- data/app/models/spree/product/slugs.rb +1 -1
- data/app/models/spree/product.rb +172 -31
- data/app/models/spree/product_publication.rb +43 -0
- data/app/models/spree/promotion/actions/create_adjustment.rb +4 -0
- data/app/models/spree/promotion/actions/create_item_adjustments.rb +4 -0
- data/app/models/spree/promotion/actions/create_line_items.rb +32 -14
- data/app/models/spree/promotion/rules/country.rb +40 -18
- data/app/models/spree/promotion/rules/customer_group.rb +10 -1
- data/app/models/spree/promotion/rules/product.rb +4 -0
- data/app/models/spree/promotion/rules/taxon.rb +24 -1
- data/app/models/spree/promotion/rules/user.rb +21 -0
- data/app/models/spree/promotion/rules/user_logged_in.rb +6 -0
- data/app/models/spree/promotion.rb +22 -1
- data/app/models/spree/promotion_action.rb +17 -11
- data/app/models/spree/promotion_rule.rb +17 -18
- data/app/models/spree/search_provider/meilisearch.rb +12 -2
- data/app/models/spree/stock/availability_validator.rb +1 -1
- data/app/models/spree/stock/quantifier.rb +89 -9
- data/app/models/spree/stock_item.rb +36 -0
- data/app/models/spree/stock_location.rb +52 -0
- data/app/models/spree/stock_reservation.rb +38 -0
- data/app/models/spree/stock_reservations/insufficient_stock_error.rb +12 -0
- data/app/models/spree/store.rb +18 -72
- data/app/models/spree/store_credit.rb +0 -8
- data/app/models/spree/store_product.rb +11 -23
- data/app/models/spree/taxon.rb +0 -5
- data/app/models/spree/user_identity.rb +1 -2
- data/app/models/spree/variant.rb +132 -18
- data/app/models/spree/variant_media.rb +46 -0
- data/app/models/spree/webhook_delivery.rb +1 -1
- data/app/models/spree/webhook_endpoint.rb +24 -0
- data/app/models/spree/wished_item.rb +0 -13
- data/app/presenters/spree/csv/product_variant_presenter.rb +23 -3
- data/app/presenters/spree/search_provider/product_presenter.rb +11 -4
- data/app/presenters/spree/variant_presenter.rb +4 -3
- data/app/services/spree/addresses/update.rb +6 -8
- data/app/services/spree/cart/add_item.rb +10 -0
- data/app/services/spree/cart/empty.rb +2 -0
- data/app/services/spree/cart/remove_line_item.rb +10 -0
- data/app/services/spree/cart/remove_out_of_stock_items.rb +1 -1
- data/app/services/spree/cart/set_quantity.rb +10 -0
- data/app/services/spree/carts/complete.rb +1 -0
- data/app/services/spree/carts/create.rb +1 -0
- data/app/services/spree/carts/update.rb +18 -2
- data/app/services/spree/carts/upsert_items.rb +6 -6
- data/app/services/spree/imports/row_processors/customer.rb +4 -1
- data/app/services/spree/imports/row_processors/product_variant.rb +95 -57
- data/app/services/spree/newsletter/link_user.rb +53 -0
- data/app/services/spree/newsletter/subscribe.rb +31 -9
- data/app/services/spree/orders/approve.rb +27 -6
- data/app/services/spree/orders/build_shipments.rb +29 -0
- data/app/services/spree/orders/cancel.rb +34 -3
- data/app/services/spree/orders/complete.rb +53 -0
- data/app/services/spree/orders/create.rb +156 -0
- data/app/services/spree/orders/update.rb +51 -0
- data/app/services/spree/orders/upsert_items.rb +70 -0
- data/app/services/spree/prices/bulk_upsert.rb +201 -0
- data/app/services/spree/products/duplicator.rb +1 -1
- data/app/services/spree/products/prepare_nested_attributes.rb +2 -30
- data/app/services/spree/sample_data/loader.rb +30 -0
- data/app/services/spree/stock_reservations/extend.rb +19 -0
- data/app/services/spree/stock_reservations/release.rb +12 -0
- data/app/services/spree/stock_reservations/reserve.rb +103 -0
- data/app/services/spree/taxons/remove_products.rb +7 -1
- data/app/subscribers/spree/product_metrics_subscriber.rb +3 -7
- data/app/views/spree/invitation_mailer/invitation_email.html.erb +4 -0
- data/config/locales/en.yml +28 -10
- data/config/routes.rb +9 -0
- data/db/migrate/20260429000001_create_spree_order_cancellations.rb +25 -0
- data/db/migrate/20260429000002_create_spree_order_approvals.rb +22 -0
- data/db/migrate/20260429000003_add_status_to_spree_orders.rb +6 -0
- data/db/migrate/20260429000004_add_scopes_to_spree_api_keys.rb +11 -0
- data/db/migrate/20260501000001_create_spree_stock_reservations.rb +19 -0
- data/db/migrate/20260507162651_create_spree_variant_media.rb +23 -0
- data/db/migrate/20260508175303_add_pickup_to_spree_stock_locations.rb +12 -0
- data/db/migrate/20260508204040_create_spree_channels.rb +18 -0
- data/db/migrate/20260508204041_create_spree_order_routing_rules.rb +18 -0
- data/db/migrate/20260508204042_add_preferred_stock_location_to_spree_orders.rb +5 -0
- data/db/migrate/20260508204043_add_channel_id_to_spree_orders.rb +10 -0
- data/db/migrate/20260511000001_backfill_status_on_spree_orders.rb +57 -0
- data/db/migrate/20260515000001_add_store_id_to_spree_newsletter_subscribers.rb +25 -0
- data/db/migrate/20260529000001_add_unique_index_to_spree_price_rules.rb +41 -0
- data/db/migrate/20260529000002_add_unique_index_to_spree_promotion_rules.rb +37 -0
- data/db/migrate/20260601000001_create_spree_product_publications.rb +14 -0
- data/db/migrate/20260601000002_add_store_id_to_spree_products.rb +16 -0
- data/db/migrate/20260602000001_add_default_to_spree_channels.rb +14 -0
- data/db/migrate/20260612000001_change_spree_user_identities_info_to_jsonb.rb +13 -0
- data/db/sample_data/channels.rb +12 -0
- data/db/sample_data/orders.rb +1 -1
- data/db/sample_data/products.csv +212 -212
- data/lib/generators/spree/api_resource/api_resource_generator.rb +353 -0
- data/lib/generators/spree/api_resource/templates/admin_controller.rb.tt +23 -0
- data/lib/generators/spree/api_resource/templates/admin_controller_spec.rb.tt +59 -0
- data/lib/generators/spree/api_resource/templates/admin_serializer.rb.tt +11 -0
- data/lib/generators/spree/api_resource/templates/factory.rb.tt +26 -0
- data/lib/generators/spree/api_resource/templates/store_aliased_serializer.rb.tt +12 -0
- data/lib/generators/spree/api_resource/templates/store_controller.rb.tt +31 -0
- data/lib/generators/spree/api_resource/templates/store_controller_spec.rb.tt +61 -0
- data/lib/generators/spree/api_resource/templates/store_serializer.rb.tt +17 -0
- data/lib/generators/spree/controller_decorator/controller_decorator_generator.rb +66 -0
- data/lib/generators/spree/controller_decorator/templates/controller_decorator.rb.tt +25 -0
- data/lib/generators/spree/model/model_generator.rb +73 -7
- data/lib/generators/spree/model/templates/create_table_migration.rb.tt +40 -0
- data/lib/generators/spree/model/templates/model.rb.tt +28 -2
- data/lib/generators/spree/subscriber/subscriber_generator.rb +116 -0
- data/lib/generators/spree/subscriber/templates/subscriber.rb.tt +17 -0
- data/lib/generators/spree/subscriber/templates/subscriber_spec.rb.tt +9 -0
- data/lib/spree/core/configuration.rb +7 -0
- data/lib/spree/core/controller_helpers/auth.rb +0 -12
- data/lib/spree/core/controller_helpers/currency.rb +0 -17
- data/lib/spree/core/controller_helpers/order.rb +0 -19
- data/lib/spree/core/dependencies.rb +5 -2
- data/lib/spree/core/engine.rb +54 -7
- data/lib/spree/core/permission_configuration.rb +15 -0
- data/lib/spree/core/preferences/masking.rb +47 -0
- data/lib/spree/core/preferences/preferable_class_methods.rb +7 -1
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +56 -5
- data/lib/spree/permitted_attributes.rb +9 -7
- data/lib/spree/testing_support/factories/address_factory.rb +16 -9
- data/lib/spree/testing_support/factories/api_key_factory.rb +1 -0
- data/lib/spree/testing_support/factories/channel_factory.rb +8 -0
- data/lib/spree/testing_support/factories/line_item_factory.rb +2 -8
- data/lib/spree/testing_support/factories/newsletter_subscriber_factory.rb +2 -0
- data/lib/spree/testing_support/factories/product_factory.rb +16 -7
- data/lib/spree/testing_support/factories/product_publication_factory.rb +6 -0
- data/lib/spree/testing_support/factories/refresh_token_factory.rb +15 -0
- data/lib/spree/testing_support/factories/stock_location_factory.rb +2 -2
- data/lib/spree/testing_support/factories/stock_reservation_factory.rb +31 -0
- data/lib/spree/testing_support/factories/variant_factory.rb +3 -3
- data/lib/spree/testing_support/order_walkthrough.rb +1 -1
- data/lib/spree/testing_support/store.rb +10 -0
- data/lib/spree/upgrades/5_4_to_5_5/manifest.yml +53 -0
- data/lib/tasks/channels.rake +94 -0
- data/lib/tasks/cli.rake +2 -1
- data/lib/tasks/core.rake +1 -0
- data/lib/tasks/media.rake +27 -0
- data/lib/tasks/products.rake +4 -6
- data/lib/tasks/publications.rake +60 -0
- data/lib/tasks/upgrade.rake +211 -0
- metadata +87 -18
- data/app/finders/spree/variants/visible_finder.rb +0 -23
- data/app/paginators/spree/shared/paginate.rb +0 -30
- data/app/presenters/spree/filters/price_presenter.rb +0 -23
- data/app/presenters/spree/filters/price_range_presenter.rb +0 -30
- data/app/presenters/spree/filters/quantified_price_range_presenter.rb +0 -45
- data/app/presenters/spree/product_summary_presenter.rb +0 -27
- data/app/presenters/spree/variants/options_presenter.rb +0 -82
- data/app/services/spree/classifications/reposition.rb +0 -23
- data/app/sorters/spree/orders/sort.rb +0 -10
- data/lib/spree/core/controller_helpers/common.rb +0 -14
- data/lib/spree/core/token_generator.rb +0 -23
- data/lib/spree/database_type_utilities.rb +0 -22
- data/lib/spree/testing_support/bar_ability.rb +0 -14
- data/lib/spree/testing_support/factories/store_product_factory.rb +0 -6
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spree
|
|
4
|
+
module Preferences
|
|
5
|
+
# Masks `:password`-typed preferences so secrets (API keys, OAuth
|
|
6
|
+
# tokens, signing secrets, …) never leave the server in plaintext.
|
|
7
|
+
#
|
|
8
|
+
# The mask token is a bullet sequence followed by the last 4
|
|
9
|
+
# characters of the original value — Stripe's "stored, here's the
|
|
10
|
+
# last 4" pattern.
|
|
11
|
+
module Masking
|
|
12
|
+
TOKEN = '••••'
|
|
13
|
+
|
|
14
|
+
# @param value [Object] the preference value to mask
|
|
15
|
+
# @return [String, nil] masked string, or nil if value is blank
|
|
16
|
+
def self.mask(value)
|
|
17
|
+
return nil if value.blank?
|
|
18
|
+
|
|
19
|
+
"#{TOKEN}#{value.to_s.last(4)}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @param value [Object] a value previously returned by `mask`
|
|
23
|
+
# @return [Boolean] true if value carries the mask token
|
|
24
|
+
def self.masked?(value)
|
|
25
|
+
value.is_a?(String) && value.start_with?(TOKEN)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Serializes a Preferable's `preferences` hash for the wire,
|
|
29
|
+
# masking `:password` values. Keys are stringified to match the
|
|
30
|
+
# wire shape expected by JSON clients — schema entries built by
|
|
31
|
+
# `compute_preference_schema` cache `:key_string` to avoid a
|
|
32
|
+
# `to_s` allocation per field per request.
|
|
33
|
+
#
|
|
34
|
+
# @param preferable [#preferences, #preference_schema, nil] any object
|
|
35
|
+
# that includes `Spree::Preferences::Preferable` and `Spree::PreferenceSchema`
|
|
36
|
+
# @return [Hash{String => Object}]
|
|
37
|
+
def self.serialize(preferable)
|
|
38
|
+
return {} if preferable.nil?
|
|
39
|
+
|
|
40
|
+
preferable.preference_schema.each_with_object({}) do |field, hash|
|
|
41
|
+
value = preferable.preferences[field[:key]]
|
|
42
|
+
hash[field[:key_string] || field[:key].to_s] = field[:type] == :password ? mask(value) : value
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -18,7 +18,13 @@ module Spree::Preferences
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
define_method preference_setter_method(name) do |value|
|
|
21
|
-
|
|
21
|
+
if parse_on_set.is_a?(Proc)
|
|
22
|
+
# Procs that accept more than one arg opt into receiving the
|
|
23
|
+
# owning record so they can scope (e.g. `normalize_id_preference`
|
|
24
|
+
# rejecting cross-store IDs). `arity.abs > 1` covers both the
|
|
25
|
+
# `(value, owner)` and `(value, owner = nil)` shapes.
|
|
26
|
+
value = parse_on_set.arity.abs > 1 ? parse_on_set.call(value, self) : parse_on_set.call(value)
|
|
27
|
+
end
|
|
22
28
|
value = convert_preference_value(value, type, nullable: nullable)
|
|
23
29
|
preferences[name] = value
|
|
24
30
|
|
data/lib/spree/core/version.rb
CHANGED
data/lib/spree/core.rb
CHANGED
|
@@ -112,7 +112,8 @@ module Spree
|
|
|
112
112
|
webhooks: :default,
|
|
113
113
|
payment_webhooks: :default,
|
|
114
114
|
api_keys: :default,
|
|
115
|
-
search: :default
|
|
115
|
+
search: :default,
|
|
116
|
+
stock_reservations: :default
|
|
116
117
|
)
|
|
117
118
|
end
|
|
118
119
|
|
|
@@ -241,6 +242,14 @@ module Spree
|
|
|
241
242
|
Rails.application.config.spree.stock_splitters = value
|
|
242
243
|
end
|
|
243
244
|
|
|
245
|
+
def self.order_routing
|
|
246
|
+
Rails.application.config.spree.order_routing
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def self.order_routing=(value)
|
|
250
|
+
Rails.application.config.spree.order_routing = value
|
|
251
|
+
end
|
|
252
|
+
|
|
244
253
|
def self.promotions
|
|
245
254
|
Rails.application.config.spree.promotions
|
|
246
255
|
end
|
|
@@ -289,6 +298,21 @@ module Spree
|
|
|
289
298
|
Rails.application.config.spree.taxon_rules = value
|
|
290
299
|
end
|
|
291
300
|
|
|
301
|
+
# Class-name strings (`'Spree::Product'`, `'Spree::Order'`,
|
|
302
|
+
# `Spree.user_class.to_s`, plus any registered by apps) for resources that
|
|
303
|
+
# expose tags via `acts_as_taggable_on :tags`. Used by the Admin API
|
|
304
|
+
# `/tags` autocomplete endpoint to validate `taggable_type`. Apps extend
|
|
305
|
+
# the list in an initializer:
|
|
306
|
+
#
|
|
307
|
+
# Spree.taggable_types << 'MyApp::Vendor'
|
|
308
|
+
def self.taggable_types
|
|
309
|
+
Rails.application.config.spree.taggable_types
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def self.taggable_types=(value)
|
|
313
|
+
Rails.application.config.spree.taggable_types = value
|
|
314
|
+
end
|
|
315
|
+
|
|
292
316
|
def self.reports
|
|
293
317
|
Rails.application.config.spree.reports
|
|
294
318
|
end
|
|
@@ -338,6 +362,36 @@ module Spree
|
|
|
338
362
|
Rails.application.config.spree.pricing = value
|
|
339
363
|
end
|
|
340
364
|
|
|
365
|
+
# Registry of authentication strategy classes for the Store API.
|
|
366
|
+
# @return [Spree::Authentication::StrategyRegistry]
|
|
367
|
+
# @example Registering a third-party identity provider
|
|
368
|
+
# Spree.store_authentication_strategies.add(:auth0, MyApp::Auth::Auth0Strategy)
|
|
369
|
+
# @example Removing a strategy
|
|
370
|
+
# Spree.store_authentication_strategies.remove(:email)
|
|
371
|
+
def self.store_authentication_strategies
|
|
372
|
+
Rails.application.config.spree.store_authentication_strategies
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# @param value [Spree::Authentication::StrategyRegistry] the registry to use for Store API authentication dispatch
|
|
376
|
+
# @return [Spree::Authentication::StrategyRegistry] the assigned registry
|
|
377
|
+
def self.store_authentication_strategies=(value)
|
|
378
|
+
Rails.application.config.spree.store_authentication_strategies = value
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
# Registry of authentication strategy classes for the Admin API.
|
|
382
|
+
# @return [Spree::Authentication::StrategyRegistry]
|
|
383
|
+
# @example Registering an SSO strategy for admin users
|
|
384
|
+
# Spree.admin_authentication_strategies.add(:okta, MyApp::Auth::OktaStrategy)
|
|
385
|
+
def self.admin_authentication_strategies
|
|
386
|
+
Rails.application.config.spree.admin_authentication_strategies
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
# @param value [Spree::Authentication::StrategyRegistry] the registry to use for Admin API authentication dispatch
|
|
390
|
+
# @return [Spree::Authentication::StrategyRegistry] the assigned registry
|
|
391
|
+
def self.admin_authentication_strategies=(value)
|
|
392
|
+
Rails.application.config.spree.admin_authentication_strategies = value
|
|
393
|
+
end
|
|
394
|
+
|
|
341
395
|
def self.analytics
|
|
342
396
|
@analytics ||= AnalyticsConfig.new
|
|
343
397
|
end
|
|
@@ -425,8 +479,6 @@ module Spree
|
|
|
425
479
|
end
|
|
426
480
|
|
|
427
481
|
module Core
|
|
428
|
-
autoload :TokenGenerator, 'spree/core/token_generator'
|
|
429
|
-
|
|
430
482
|
class GatewayError < RuntimeError; end
|
|
431
483
|
class DestroyWithOrdersError < StandardError; end
|
|
432
484
|
end
|
|
@@ -444,14 +496,12 @@ require 'spree/localized_number'
|
|
|
444
496
|
require 'spree/money'
|
|
445
497
|
require 'spree/permitted_attributes'
|
|
446
498
|
require 'spree/service_module'
|
|
447
|
-
require 'spree/database_type_utilities'
|
|
448
499
|
require 'spree/analytics'
|
|
449
500
|
require 'spree/events'
|
|
450
501
|
require 'spree/webhooks'
|
|
451
502
|
|
|
452
503
|
require 'spree/core/partials'
|
|
453
504
|
require 'spree/core/controller_helpers/auth'
|
|
454
|
-
require 'spree/core/controller_helpers/common'
|
|
455
505
|
require 'spree/core/controller_helpers/order'
|
|
456
506
|
require 'spree/core/controller_helpers/store'
|
|
457
507
|
require 'spree/core/controller_helpers/strong_parameters'
|
|
@@ -462,6 +512,7 @@ require 'spree/core/controller_helpers/turbo'
|
|
|
462
512
|
require 'spree/core/preferences/store'
|
|
463
513
|
require 'spree/core/preferences/scoped_store'
|
|
464
514
|
require 'spree/core/preferences/runtime_configuration'
|
|
515
|
+
require 'spree/core/preferences/masking'
|
|
465
516
|
|
|
466
517
|
require 'spree/core/permission_configuration'
|
|
467
518
|
require 'spree/core/ransack_configuration'
|
|
@@ -56,6 +56,7 @@ module Spree
|
|
|
56
56
|
:shipment_attributes,
|
|
57
57
|
:shipping_method_attributes,
|
|
58
58
|
:shipping_category_attributes,
|
|
59
|
+
:channel_attributes,
|
|
59
60
|
:source_attributes,
|
|
60
61
|
:stock_item_attributes,
|
|
61
62
|
:stock_location_attributes,
|
|
@@ -90,10 +91,9 @@ module Spree
|
|
|
90
91
|
|
|
91
92
|
@@allowed_origin_attributes = [:origin]
|
|
92
93
|
|
|
93
|
-
@@api_key_attributes = [:name, :key_type]
|
|
94
|
+
@@api_key_attributes = [:name, :key_type, { scopes: [] }]
|
|
94
95
|
|
|
95
|
-
@@asset_attributes = [:type, :viewable_id, :viewable_type, :attachment, :alt, :position,
|
|
96
|
-
:media_type, :focal_point_x, :focal_point_y, :external_video_url]
|
|
96
|
+
@@asset_attributes = [:type, :viewable_id, :viewable_type, :attachment, :alt, :position, :url, :signed_id]
|
|
97
97
|
|
|
98
98
|
@@checkout_attributes = [
|
|
99
99
|
:coupon_code, :email, :shipping_method_id, :special_instructions, :use_billing, :use_shipping,
|
|
@@ -169,7 +169,7 @@ module Spree
|
|
|
169
169
|
|
|
170
170
|
@@payment_attributes = [:amount, :payment_method_id, :payment_method]
|
|
171
171
|
|
|
172
|
-
@@payment_method_attributes = [:name, :type, :description, :active, :display_on, :auto_capture, :position]
|
|
172
|
+
@@payment_method_attributes = [:name, :type, :description, :active, :display_on, :auto_capture, :position, { metadata: {}, preferences: {} }]
|
|
173
173
|
|
|
174
174
|
@@payment_session_attributes = [:amount, :payment_method_id, { external_data: {} }]
|
|
175
175
|
|
|
@@ -192,8 +192,8 @@ module Spree
|
|
|
192
192
|
label_list: [],
|
|
193
193
|
option_type_ids: [],
|
|
194
194
|
taxon_ids: [],
|
|
195
|
-
|
|
196
|
-
|
|
195
|
+
product_option_types_attributes: [:id, :option_type_id, :position, :_destroy],
|
|
196
|
+
legacy_product_publications_attributes: [:id, :channel_id, :published_at, :unpublished_at, :_destroy]
|
|
197
197
|
}
|
|
198
198
|
]
|
|
199
199
|
|
|
@@ -240,6 +240,8 @@ module Spree
|
|
|
240
240
|
|
|
241
241
|
@@shipping_category_attributes = [:name]
|
|
242
242
|
|
|
243
|
+
@@channel_attributes = [:name, :code, :active, :default, :preferred_order_routing_strategy]
|
|
244
|
+
|
|
243
245
|
@@shipping_method_attributes = [:name, :admin_name, :code, :tracking_url, :tax_category_id, :display_on,
|
|
244
246
|
:estimated_transit_business_days_min, :estimated_transit_business_days_max,
|
|
245
247
|
:calculator_type, :preferences, zone_ids: [], shipping_category_ids: [], calculator_attributes: {}]
|
|
@@ -251,7 +253,7 @@ module Spree
|
|
|
251
253
|
:gateway_payment_profile_id, :last_digits, :name, :encrypted_data
|
|
252
254
|
]
|
|
253
255
|
|
|
254
|
-
@@stock_item_attributes = [:variant_id, :stock_location_id, :backorderable, :count_on_hand]
|
|
256
|
+
@@stock_item_attributes = [:variant_id, :stock_location_id, :backorderable, :count_on_hand, { metadata: {} }]
|
|
255
257
|
|
|
256
258
|
@@stock_location_attributes = [
|
|
257
259
|
:name, :active, :address1, :address2, :city, :zipcode, :company,
|
|
@@ -5,19 +5,26 @@ FactoryBot.define do
|
|
|
5
5
|
company { 'Company' }
|
|
6
6
|
sequence(:address1) { |n| "#{n} Lovely Street" }
|
|
7
7
|
address2 { 'Northwest' }
|
|
8
|
-
city { '
|
|
9
|
-
zipcode { '
|
|
8
|
+
city { 'New York' }
|
|
9
|
+
zipcode { '10118' }
|
|
10
10
|
phone { '555-555-0199' }
|
|
11
11
|
alternative_phone { '555-555-0199' }
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
country
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
# Default to a real US/NY pair (cached via find_or_create_by) so generated
|
|
14
|
+
# OpenAPI examples carry plausible country/state fields. Tests that need a
|
|
15
|
+
# different state/country pass them explicitly.
|
|
16
|
+
country do
|
|
17
|
+
Spree::Country.find_or_create_by!(iso: 'US') do |c|
|
|
18
|
+
c.iso3 = 'USA'
|
|
19
|
+
c.name = 'United States of America'
|
|
20
|
+
c.iso_name = 'UNITED STATES'
|
|
21
|
+
c.numcode = 840
|
|
22
|
+
c.states_required = true
|
|
20
23
|
end
|
|
21
24
|
end
|
|
25
|
+
|
|
26
|
+
state do |address|
|
|
27
|
+
(address.country || Spree::Country.find_by(iso: 'US'))&.states&.find_or_create_by!(abbr: 'NY') { |s| s.name = 'New York' }
|
|
28
|
+
end
|
|
22
29
|
end
|
|
23
30
|
end
|
|
@@ -8,14 +8,8 @@ FactoryBot.define do
|
|
|
8
8
|
product { nil }
|
|
9
9
|
end
|
|
10
10
|
variant do
|
|
11
|
-
resolved_product = product ||
|
|
12
|
-
|
|
13
|
-
create(:product, stores: [order.store])
|
|
14
|
-
else
|
|
15
|
-
create(:product)
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
resolved_product.master
|
|
11
|
+
resolved_product = product || create(:product)
|
|
12
|
+
resolved_product.default_variant
|
|
19
13
|
end
|
|
20
14
|
end
|
|
21
15
|
end
|
|
@@ -4,12 +4,10 @@ FactoryBot.define do
|
|
|
4
4
|
description { generate(:random_description) }
|
|
5
5
|
cost_price { 17.00 }
|
|
6
6
|
sku { generate(:sku) }
|
|
7
|
-
available_on { 1.year.ago }
|
|
8
|
-
make_active_at { 1.year.ago }
|
|
9
7
|
deleted_at { nil }
|
|
10
8
|
shipping_category { |r| Spree::ShippingCategory.first || r.association(:shipping_category) }
|
|
11
9
|
status { 'active' }
|
|
12
|
-
|
|
10
|
+
store { Spree::Store.default || association(:store) }
|
|
13
11
|
|
|
14
12
|
transient do
|
|
15
13
|
price { 19.99 }
|
|
@@ -17,11 +15,8 @@ FactoryBot.define do
|
|
|
17
15
|
currency { nil }
|
|
18
16
|
end
|
|
19
17
|
|
|
20
|
-
# ensure stock item will be created for this products master
|
|
21
|
-
# also attach this product to the default store if no stores are passed in
|
|
22
18
|
before(:create) do |_product|
|
|
23
19
|
create(:stock_location) unless Spree::StockLocation.any?
|
|
24
|
-
create(:store, default: true) unless Spree::Store.any?
|
|
25
20
|
end
|
|
26
21
|
after(:create) do |product, evaluator|
|
|
27
22
|
existing_location_ids = product.master.stock_items.pluck(:stock_location_id)
|
|
@@ -30,9 +25,23 @@ FactoryBot.define do
|
|
|
30
25
|
end
|
|
31
26
|
|
|
32
27
|
if evaluator.price.present?
|
|
33
|
-
price_currency = evaluator.currency || product.
|
|
28
|
+
price_currency = evaluator.currency || product.store&.default_currency || 'USD'
|
|
34
29
|
product.master.set_price(price_currency, evaluator.price, evaluator.compare_at_price)
|
|
35
30
|
end
|
|
31
|
+
|
|
32
|
+
# Test convenience only: auto-publish each product on its store's
|
|
33
|
+
# default channel so legacy spec assertions that depend on
|
|
34
|
+
# current-channel visibility (.active, .available, .not_discontinued)
|
|
35
|
+
# keep passing. Production callers must publish explicitly via the
|
|
36
|
+
# Admin SDK / Dashboard create form.
|
|
37
|
+
if product.store&.default_channel && product.product_publications.empty?
|
|
38
|
+
Spree::ProductPublication.create!(
|
|
39
|
+
product: product,
|
|
40
|
+
channel: product.store.default_channel,
|
|
41
|
+
published_at: product.available_on,
|
|
42
|
+
unpublished_at: product.discontinue_on
|
|
43
|
+
)
|
|
44
|
+
end
|
|
36
45
|
end
|
|
37
46
|
|
|
38
47
|
factory :custom_product do
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
FactoryBot.define do
|
|
2
|
+
factory :refresh_token, class: 'Spree::RefreshToken' do
|
|
3
|
+
association :user, factory: :user
|
|
4
|
+
user_type { user.class.to_s }
|
|
5
|
+
expires_at { Spree::RefreshToken.default_expiry.from_now }
|
|
6
|
+
|
|
7
|
+
trait :for_admin do
|
|
8
|
+
association :user, factory: :admin_user
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
trait :expired do
|
|
12
|
+
expires_at { 1.minute.ago }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -19,8 +19,8 @@ FactoryBot.define do
|
|
|
19
19
|
# variant will add itself to all stock_locations in an after_create
|
|
20
20
|
# creating a product will automatically create a master variant
|
|
21
21
|
store = Spree::Store.first || create(:store)
|
|
22
|
-
product_1 = create(:product
|
|
23
|
-
product_2 = create(:product
|
|
22
|
+
product_1 = create(:product)
|
|
23
|
+
product_2 = create(:product)
|
|
24
24
|
|
|
25
25
|
stock_location.stock_item_or_create(product_1.master).adjust_count_on_hand(10)
|
|
26
26
|
stock_location.stock_item_or_create(product_2.master).adjust_count_on_hand(20)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
FactoryBot.define do
|
|
2
|
+
factory :stock_reservation, class: Spree::StockReservation do
|
|
3
|
+
quantity { 1 }
|
|
4
|
+
expires_at { 10.minutes.from_now }
|
|
5
|
+
|
|
6
|
+
transient do
|
|
7
|
+
order { nil }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Build the order first (with at least one line_item), then derive
|
|
11
|
+
# stock_item from that line_item's variant so the three FKs reference the
|
|
12
|
+
# same variant. Callers can override stock_item:/line_item:/order: to wire
|
|
13
|
+
# up a specific scenario.
|
|
14
|
+
after(:build) do |reservation, evaluator|
|
|
15
|
+
reservation.order ||= evaluator.order || create(:order_with_line_items, line_items_count: 1)
|
|
16
|
+
|
|
17
|
+
if reservation.line_item.nil?
|
|
18
|
+
reservation.line_item = reservation.order.line_items.first ||
|
|
19
|
+
create(:line_item, order: reservation.order)
|
|
20
|
+
reservation.order.line_items.reload
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
reservation.stock_item ||= reservation.line_item.variant.stock_items.first ||
|
|
24
|
+
create(:stock_item, variant: reservation.line_item.variant)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
trait :expired do
|
|
28
|
+
expires_at { 1.minute.ago }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -11,7 +11,7 @@ FactoryBot.define do
|
|
|
11
11
|
is_master { 0 }
|
|
12
12
|
track_inventory { true }
|
|
13
13
|
|
|
14
|
-
product { |p| p.association(:base_product
|
|
14
|
+
product { |p| p.association(:base_product) }
|
|
15
15
|
option_values { [build(:option_value)] }
|
|
16
16
|
|
|
17
17
|
transient do
|
|
@@ -35,14 +35,14 @@ FactoryBot.define do
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
if evaluator.price.present?
|
|
38
|
-
price_currency = evaluator.currency || variant.product&.
|
|
38
|
+
price_currency = evaluator.currency || variant.product&.store&.default_currency || 'USD'
|
|
39
39
|
variant.set_price(price_currency, evaluator.price, evaluator.compare_at_price)
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
factory :variant do
|
|
44
44
|
# on_hand 5
|
|
45
|
-
product { |p| p.association(:product
|
|
45
|
+
product { |p| p.association(:product) }
|
|
46
46
|
|
|
47
47
|
factory :with_image_variant do
|
|
48
48
|
images { create_list(:image, 1) }
|
|
@@ -4,7 +4,7 @@ class OrderWalkthrough
|
|
|
4
4
|
|
|
5
5
|
# A payment method must exist for an order to proceed through the Address state
|
|
6
6
|
unless Spree::PaymentMethod.exists?
|
|
7
|
-
FactoryBot.create(:check_payment_method
|
|
7
|
+
FactoryBot.create(:check_payment_method)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
# Need to create a valid zone too...
|
|
@@ -31,6 +31,16 @@ RSpec.configure do |config|
|
|
|
31
31
|
@default_store&.promotions = []
|
|
32
32
|
@default_store&.update_column(:checkout_zone_id, nil) if @default_store&.read_attribute(:checkout_zone_id).present?
|
|
33
33
|
@default_store&.payment_methods = []
|
|
34
|
+
# The shared +@default_store+ Ruby object lives across the whole
|
|
35
|
+
# +before(:all)+ block, so AR association caches (+default_market+,
|
|
36
|
+
# +channels+, etc.) and per-instance memos (+@has_markets+) need to
|
|
37
|
+
# be cleared between examples or stale +nil+s leak across tests.
|
|
38
|
+
if @default_store
|
|
39
|
+
@default_store.association(:default_market).reset if @default_store.association_cached?(:default_market)
|
|
40
|
+
@default_store.association(:markets).reset if @default_store.association_cached?(:markets)
|
|
41
|
+
@default_store.remove_instance_variable(:@has_markets) if @default_store.instance_variable_defined?(:@has_markets)
|
|
42
|
+
@default_store.reload
|
|
43
|
+
end
|
|
34
44
|
end
|
|
35
45
|
end
|
|
36
46
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Spree 5.4 → 5.5 upgrade manifest.
|
|
2
|
+
#
|
|
3
|
+
# Lists ONLY the version-specific rake tasks that perform data backfills.
|
|
4
|
+
# Universal upgrade steps (bundle update, db:migrate, scheduling cron jobs,
|
|
5
|
+
# reviewing breaking changes) are NOT in this file:
|
|
6
|
+
#
|
|
7
|
+
# - `bundle update` + `db:migrate` are handled by your deploy pipeline
|
|
8
|
+
# (Heroku release phase, K8s init container, Render auto-migrate,
|
|
9
|
+
# Capistrano deploy hook, etc.) and by the @spree/cli's `spree upgrade`
|
|
10
|
+
# wrapper for local development.
|
|
11
|
+
# - Cron scheduling, optional tunings, and human-readable behavior changes
|
|
12
|
+
# live in the upgrade doc at docs/developer/upgrades/5.4-to-5.5.mdx.
|
|
13
|
+
#
|
|
14
|
+
# This manifest is the machine-runnable shape — what `bin/rake spree:upgrade`
|
|
15
|
+
# (in production) and `spree upgrade` (in dev) execute. Every step must be a
|
|
16
|
+
# rake task and must be idempotent. Re-running the full manifest is safe.
|
|
17
|
+
---
|
|
18
|
+
from: "5.4"
|
|
19
|
+
to: "5.5"
|
|
20
|
+
docs: "https://spreecommerce.org/docs/developer/upgrades/5.4-to-5.5"
|
|
21
|
+
|
|
22
|
+
steps:
|
|
23
|
+
- id: media
|
|
24
|
+
name: "Migrate legacy variant-pinned images to product-level media"
|
|
25
|
+
task: "spree:media:migrate_master_images_to_product_media"
|
|
26
|
+
notes: |
|
|
27
|
+
Enqueues one `Spree::Media::MigrateProductAssetsJob` per product onto
|
|
28
|
+
the `images` queue — confirm your job runner is processing that queue.
|
|
29
|
+
Storefront keeps working while jobs drain (old assets stay variant-pinned
|
|
30
|
+
until each job finishes). For large catalogs, tune with BATCH_SIZE=1000.
|
|
31
|
+
|
|
32
|
+
- id: channels
|
|
33
|
+
name: "Run the Channels upgrade (creates default channels, publications, order channel ids)"
|
|
34
|
+
task: "spree:channels:upgrade"
|
|
35
|
+
notes: |
|
|
36
|
+
Aggregator that runs four sub-tasks in order:
|
|
37
|
+
1. spree:channels:create_defaults
|
|
38
|
+
2. spree:upgrade:populate_publications
|
|
39
|
+
3. spree:channels:backfill_order_channel_ids
|
|
40
|
+
4. spree:channels:backfill_product_publication_dates
|
|
41
|
+
Until this runs, every product has store_id IS NULL and is invisible
|
|
42
|
+
to Product.for_store — admin lists, storefront catalog, and search
|
|
43
|
+
indexer all return empty.
|
|
44
|
+
|
|
45
|
+
- id: reindex
|
|
46
|
+
name: "Reindex products against the configured search provider"
|
|
47
|
+
task: "spree:search:reindex"
|
|
48
|
+
notes: |
|
|
49
|
+
No-op for the default Database provider. For Meilisearch (or any other
|
|
50
|
+
external search provider), this is required after the channels upgrade
|
|
51
|
+
because products only become visible to Product.for_store once they
|
|
52
|
+
have a store_id — reindexing before the channels step would index 0
|
|
53
|
+
products. Must run AFTER `channels`.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
namespace :spree do
|
|
2
|
+
namespace :channels do
|
|
3
|
+
desc 'Create the default channel for every existing store (idempotent — calls Store#ensure_default_channel).'
|
|
4
|
+
task create_defaults: :environment do
|
|
5
|
+
created = 0
|
|
6
|
+
Spree::Store.find_each do |store|
|
|
7
|
+
next if store.default_channel
|
|
8
|
+
|
|
9
|
+
store.ensure_default_channel
|
|
10
|
+
created += 1
|
|
11
|
+
puts " Created default channel for store '#{store.name}'"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
puts created.zero? ? ' All stores already have a default channel.' : " Created #{created} default channel(s)."
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
desc 'Backfill spree_orders.channel_id from the legacy spree_orders.channel string column'
|
|
18
|
+
task backfill_order_channel_ids: :environment do
|
|
19
|
+
# Idempotent: only touches orders where channel_id is nil. Safe to
|
|
20
|
+
# re-run after partial completion. Returns gracefully if the legacy
|
|
21
|
+
# string column has already been dropped.
|
|
22
|
+
unless legacy_channel_column?
|
|
23
|
+
puts 'Legacy channel column not present — backfill is unnecessary.'
|
|
24
|
+
next
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Spree::Store.find_each do |store|
|
|
28
|
+
legacy_codes = Spree::Order.where(store_id: store.id, channel_id: nil)
|
|
29
|
+
.distinct
|
|
30
|
+
.pluck(Arel.sql('channel'))
|
|
31
|
+
.compact_blank
|
|
32
|
+
|
|
33
|
+
codes_to_process = legacy_codes.uniq
|
|
34
|
+
codes_to_process << Spree::Channel::DEFAULT_CODE unless codes_to_process.include?(Spree::Channel::DEFAULT_CODE)
|
|
35
|
+
|
|
36
|
+
codes_to_process.each do |code|
|
|
37
|
+
channel = store.channels.find_or_create_by!(code: code) do |c|
|
|
38
|
+
c.name = code.titleize
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
scope = Spree::Order.where(store_id: store.id, channel_id: nil)
|
|
42
|
+
scope = if code == Spree::Channel::DEFAULT_CODE
|
|
43
|
+
# Only the default channel claims NULL/blank rows.
|
|
44
|
+
scope.where(Arel.sql("channel = ? OR channel IS NULL OR channel = ''"), code)
|
|
45
|
+
else
|
|
46
|
+
scope.where(Arel.sql('channel = ?'), code)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
updated = scope.update_all(channel_id: channel.id)
|
|
50
|
+
|
|
51
|
+
next if updated.zero?
|
|
52
|
+
|
|
53
|
+
puts " Store '#{store.name}': mapped #{updated} orders with channel='#{code}' → #{channel.name} (#{channel.code})"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
desc 'Backfill published_at and unpublished_at on ProductPublications from the legacy Product.available_on / discontinue_on columns'
|
|
59
|
+
task backfill_product_publication_dates: :environment do
|
|
60
|
+
# Per-product loop (not join-update) for SQLite/MySQL/Postgres portability.
|
|
61
|
+
published = 0
|
|
62
|
+
unpublished = 0
|
|
63
|
+
|
|
64
|
+
products_with_dates = Spree::Product.where.not(available_on: nil).or(Spree::Product.where.not(discontinue_on: nil))
|
|
65
|
+
|
|
66
|
+
products_with_dates.find_each(batch_size: 500) do |product|
|
|
67
|
+
publications = Spree::ProductPublication.where(product_id: product.id)
|
|
68
|
+
# Read raw columns — +product.available_on+ / +product.discontinue_on+
|
|
69
|
+
# go through +Product::Channels+'s reader override which prefers the
|
|
70
|
+
# current-channel publication's date (which is nil pre-backfill).
|
|
71
|
+
legacy_available_on = product[:available_on]
|
|
72
|
+
legacy_discontinue_on = product[:discontinue_on]
|
|
73
|
+
|
|
74
|
+
published += publications.where(published_at: nil).update_all(published_at: legacy_available_on) if legacy_available_on
|
|
75
|
+
unpublished += publications.where(unpublished_at: nil).update_all(unpublished_at: legacy_discontinue_on) if legacy_discontinue_on
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
total = published + unpublished
|
|
79
|
+
puts total.zero? ? ' All product-publication dates already populated.' : " Backfilled dates on #{published} published_at + #{unpublished} unpublished_at column(s)."
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
desc 'Run the full 5.4 → 5.5 channel upgrade: create default channels, backfill products to store_id and publications, backfill order channels, backfill publication date windows'
|
|
83
|
+
task upgrade: [
|
|
84
|
+
:create_defaults,
|
|
85
|
+
'spree:upgrade:populate_publications',
|
|
86
|
+
:backfill_order_channel_ids,
|
|
87
|
+
:backfill_product_publication_dates
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
def legacy_channel_column?
|
|
91
|
+
ActiveRecord::Base.connection.column_exists?(:spree_orders, :channel)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
data/lib/tasks/cli.rake
CHANGED
|
@@ -12,8 +12,9 @@ namespace :spree do
|
|
|
12
12
|
task create_api_key: :environment do
|
|
13
13
|
name = ENV.fetch('NAME')
|
|
14
14
|
key_type = ENV.fetch('KEY_TYPE')
|
|
15
|
+
scopes = ENV.fetch('SCOPES', '').split(',').map(&:strip).reject(&:empty?)
|
|
15
16
|
store = Spree::Store.default
|
|
16
|
-
key = store.api_keys.create!(name: name, key_type: key_type)
|
|
17
|
+
key = store.api_keys.create!(name: name, key_type: key_type, scopes: scopes)
|
|
17
18
|
print key.plaintext_token
|
|
18
19
|
end
|
|
19
20
|
|