spree_core 5.3.4 → 5.4.0.beta
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/orders/find_complete.rb +33 -2
- data/app/finders/spree/stores/find_default.rb +17 -0
- data/app/finders/spree/variants/visible_finder.rb +1 -0
- data/app/helpers/spree/addresses_helper.rb +1 -2
- data/app/helpers/spree/base_helper.rb +5 -4
- data/app/jobs/spree/api_key_touch_job.rb +9 -0
- data/app/models/concerns/spree/admin_user_methods.rb +32 -0
- data/app/models/concerns/spree/number_as_param.rb +5 -3
- data/app/models/concerns/spree/prefixed_id.rb +82 -0
- data/app/models/concerns/spree/product_scopes.rb +33 -18
- data/app/models/concerns/spree/publishable.rb +47 -47
- data/app/models/concerns/spree/{multi_store_resource.rb → store_scoped_resource.rb} +1 -10
- data/app/models/concerns/spree/stores/markets.rb +124 -0
- data/app/models/concerns/spree/user_methods.rb +7 -7
- data/app/models/concerns/spree/user_payment_source.rb +2 -0
- data/app/models/concerns/spree/user_roles.rb +1 -0
- data/app/models/spree/ability.rb +13 -0
- data/app/models/spree/address.rb +30 -0
- data/app/models/spree/adjustment.rb +2 -0
- data/app/models/spree/api_key.rb +47 -0
- data/app/models/spree/asset.rb +2 -0
- data/app/models/spree/authentication/strategies/base_strategy.rb +55 -0
- data/app/models/spree/authentication/strategies/email_password_strategy.rb +47 -0
- data/app/models/spree/base.rb +1 -0
- data/app/models/spree/calculator.rb +2 -0
- data/app/models/spree/country.rb +56 -0
- data/app/models/spree/coupon_code.rb +2 -0
- data/app/models/spree/credit_card.rb +2 -0
- data/app/models/spree/current.rb +9 -4
- data/app/models/spree/customer_group.rb +2 -0
- data/app/models/spree/customer_return.rb +2 -0
- data/app/models/spree/data_feed.rb +2 -0
- data/app/models/spree/digital.rb +2 -0
- data/app/models/spree/digital_link.rb +2 -0
- data/app/models/spree/export.rb +3 -2
- data/app/models/spree/fulfilment_changer.rb +8 -2
- data/app/models/spree/gateway/bogus.rb +60 -0
- data/app/models/spree/gateway_customer.rb +2 -0
- data/app/models/spree/gift_card.rb +2 -0
- data/app/models/spree/gift_card_batch.rb +2 -0
- data/app/models/spree/image.rb +18 -0
- data/app/models/spree/import.rb +5 -3
- data/app/models/spree/import_mapping.rb +2 -0
- data/app/models/spree/import_row.rb +2 -0
- data/app/models/spree/import_schemas/customers.rb +21 -0
- data/app/models/spree/imports/customers.rb +9 -0
- data/app/models/spree/integration.rb +2 -0
- data/app/models/spree/inventory_unit.rb +2 -0
- data/app/models/spree/invitation.rb +6 -6
- data/app/models/spree/legacy_admin_user.rb +31 -0
- data/app/models/spree/legacy_user.rb +19 -1
- data/app/models/spree/line_item.rb +15 -4
- data/app/models/spree/log_entry.rb +2 -0
- data/app/models/spree/market.rb +83 -0
- data/app/models/spree/market_country.rb +25 -0
- data/app/models/spree/metafield.rb +2 -0
- data/app/models/spree/metafield_definition.rb +2 -0
- data/app/models/spree/newsletter_subscriber.rb +2 -0
- data/app/models/spree/option_type.rb +2 -0
- data/app/models/spree/option_value.rb +2 -0
- data/app/models/spree/order/address_book.rb +2 -1
- data/app/models/spree/order.rb +73 -45
- data/app/models/spree/payment.rb +6 -1
- data/app/models/spree/payment_capture_event.rb +2 -0
- data/app/models/spree/payment_method.rb +59 -1
- data/app/models/spree/payment_session.rb +109 -0
- data/app/models/spree/payment_sessions/bogus.rb +4 -0
- data/app/models/spree/payment_setup_session.rb +79 -0
- data/app/models/spree/payment_source.rb +2 -0
- data/app/models/spree/permission_sets/default_customer.rb +19 -0
- data/app/models/spree/policy.rb +2 -0
- data/app/models/spree/post.rb +2 -0
- data/app/models/spree/post_category.rb +2 -0
- data/app/models/spree/price.rb +26 -2
- data/app/models/spree/price_list.rb +2 -0
- data/app/models/spree/price_rule.rb +2 -0
- data/app/models/spree/price_rules/market_rule.rb +19 -0
- data/app/models/spree/product.rb +41 -29
- data/app/models/spree/promotion/rules/country.rb +1 -1
- data/app/models/spree/promotion.rb +3 -1
- data/app/models/spree/promotion_action.rb +2 -0
- data/app/models/spree/promotion_category.rb +2 -0
- data/app/models/spree/promotion_rule.rb +2 -0
- data/app/models/spree/prototype.rb +2 -0
- data/app/models/spree/refund.rb +2 -0
- data/app/models/spree/refund_reason.rb +2 -0
- data/app/models/spree/reimbursement/credit.rb +2 -0
- data/app/models/spree/reimbursement.rb +2 -0
- data/app/models/spree/reimbursement_type.rb +2 -0
- data/app/models/spree/report.rb +3 -1
- data/app/models/spree/return_authorization.rb +2 -0
- data/app/models/spree/return_authorization_reason.rb +2 -0
- data/app/models/spree/return_item.rb +2 -0
- data/app/models/spree/role.rb +2 -0
- data/app/models/spree/shipment.rb +11 -1
- data/app/models/spree/shipping_category.rb +2 -0
- data/app/models/spree/shipping_method.rb +2 -0
- data/app/models/spree/shipping_method_category.rb +2 -0
- data/app/models/spree/shipping_rate.rb +2 -0
- data/app/models/spree/state_change.rb +2 -0
- data/app/models/spree/stock_item.rb +2 -0
- data/app/models/spree/stock_location.rb +2 -0
- data/app/models/spree/stock_movement.rb +2 -0
- data/app/models/spree/stock_transfer.rb +2 -1
- data/app/models/spree/store.rb +110 -179
- data/app/models/spree/store_credit.rb +2 -0
- data/app/models/spree/store_credit_category.rb +2 -0
- data/app/models/spree/store_credit_event.rb +2 -0
- data/app/models/spree/store_credit_type.rb +2 -0
- data/app/models/spree/store_product.rb +2 -0
- data/app/models/spree/tax_category.rb +2 -0
- data/app/models/spree/tax_rate.rb +2 -0
- data/app/models/spree/taxon.rb +4 -1
- data/app/models/spree/taxon_image.rb +8 -0
- data/app/models/spree/taxon_rule.rb +2 -0
- data/app/models/spree/taxonomy.rb +2 -0
- data/app/models/spree/user_identity.rb +81 -0
- data/app/models/spree/variant.rb +13 -3
- data/app/models/spree/webhook_delivery.rb +2 -0
- data/app/models/spree/webhook_endpoint.rb +2 -0
- data/app/models/spree/wished_item.rb +15 -0
- data/app/models/spree/wishlist.rb +2 -8
- data/app/models/spree/zone.rb +2 -6
- data/app/presenters/spree/filters/price_presenter.rb +1 -0
- data/app/presenters/spree/filters/price_range_presenter.rb +1 -0
- data/app/presenters/spree/filters/quantified_price_range_presenter.rb +1 -0
- data/app/presenters/spree/product_summary_presenter.rb +1 -0
- data/app/services/spree/addresses/helper.rb +22 -3
- data/app/services/spree/cart/associate.rb +19 -6
- data/app/services/spree/checkout/select_shipping_method.rb +13 -1
- data/app/services/spree/classifications/reposition.rb +5 -0
- data/app/services/spree/imports/row_processors/customer.rb +70 -0
- data/app/services/spree/orders/approve.rb +5 -3
- data/app/services/spree/orders/cancel.rb +9 -4
- data/app/services/spree/products/prepare_nested_attributes.rb +1 -1
- data/app/services/spree/sample_data/import_runner.rb +54 -0
- data/app/services/spree/sample_data/loader.rb +78 -0
- data/app/services/spree/seeds/admin_user.rb +2 -3
- data/app/services/spree/seeds/all.rb +1 -0
- data/app/services/spree/seeds/api_keys.rb +16 -0
- data/app/services/spree/seeds/stores.rb +2 -4
- data/app/sorters/spree/orders/sort.rb +4 -0
- data/app/subscribers/spree/product_metrics_subscriber.rb +4 -4
- data/config/brakeman.ignore +120 -0
- data/config/locales/en.yml +20 -1
- data/db/migrate/20250923141900_create_spree_user_identities.rb +17 -0
- data/db/migrate/20260123000000_create_spree_api_keys.rb +19 -0
- data/db/migrate/20260131000000_add_thumbnail_id_to_spree_variants_and_products.rb +9 -0
- data/db/migrate/20260213000000_create_spree_payment_sessions.rb +27 -0
- data/db/migrate/20260218000000_create_spree_payment_setup_sessions.rb +24 -0
- data/db/migrate/20260220000000_create_spree_markets.rb +29 -0
- data/db/sample_data/customers.csv +21 -0
- data/db/sample_data/metafield_definitions.rb +7 -0
- data/db/sample_data/orders.rb +131 -0
- data/db/sample_data/payment_methods.rb +17 -0
- data/db/sample_data/posts.rb +7 -0
- data/db/sample_data/products.csv +1083 -0
- data/db/sample_data/promotions.rb +8 -0
- data/db/sample_data/shipping_methods.rb +39 -0
- data/lib/generators/spree/authentication/devise/devise_generator.rb +2 -2
- data/lib/generators/spree/authentication/dummy/dummy_generator.rb +54 -0
- data/lib/generators/spree/authentication/dummy/templates/authentication_helpers.rb.tt +52 -0
- data/lib/generators/spree/authentication/dummy/templates/create_spree_admin_users.rb.tt +33 -0
- data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
- data/lib/spree/core/configuration.rb +1 -0
- data/lib/spree/core/controller_helpers/common.rb +6 -0
- data/lib/spree/core/controller_helpers/currency.rb +5 -0
- data/lib/spree/core/controller_helpers/order.rb +5 -1
- data/lib/spree/core/controller_helpers/store.rb +1 -1
- data/lib/spree/core/dependencies.rb +1 -1
- data/lib/spree/core/engine.rb +17 -4
- data/lib/spree/core/pricing/context.rb +6 -3
- data/lib/spree/core/product_filters.rb +14 -0
- data/lib/spree/core/query_filters/comparable.rb +4 -0
- data/lib/spree/core/query_filters/text.rb +4 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/spree/core.rb +4 -4
- data/lib/spree/database_type_utilities.rb +7 -0
- data/lib/spree/events.rb +17 -10
- data/lib/spree/money.rb +2 -9
- data/lib/spree/permitted_attributes.rb +19 -7
- data/lib/spree/testing_support/capybara_config.rb +2 -2
- data/lib/spree/testing_support/common_rake.rb +15 -4
- data/lib/spree/testing_support/factories/api_key_factory.rb +19 -0
- data/lib/spree/testing_support/factories/custom_domain_factory.rb +7 -5
- data/lib/spree/testing_support/factories/import_factory.rb +12 -0
- data/lib/spree/testing_support/factories/market_factory.rb +35 -0
- data/lib/spree/testing_support/factories/order_factory.rb +3 -1
- data/lib/spree/testing_support/factories/payment_method_factory.rb +2 -0
- data/lib/spree/testing_support/factories/payment_session_factory.rb +47 -0
- data/lib/spree/testing_support/factories/payment_setup_session_factory.rb +31 -0
- data/lib/spree/testing_support/factories/price_rule_factory.rb +10 -0
- data/lib/spree/testing_support/factories/user_identity_factory.rb +15 -0
- data/lib/spree/testing_support/store.rb +3 -2
- data/lib/spree/webhooks.rb +7 -7
- data/lib/tasks/images.rake +20 -0
- data/lib/tasks/markets.rake +40 -0
- data/lib/tasks/sample_data.rake +15 -0
- data/spec/fixtures/files/customers_import.csv +4 -0
- metadata +99 -59
- data/LICENSE.md +0 -57
- data/app/finders/spree/stores/find_current.rb +0 -28
- data/app/models/spree/custom_domain.rb +0 -59
- data/app/serializers/spree/events/asset_serializer.rb +0 -22
- data/app/serializers/spree/events/base_serializer.rb +0 -61
- data/app/serializers/spree/events/customer_return_serializer.rb +0 -20
- data/app/serializers/spree/events/digital_link_serializer.rb +0 -20
- data/app/serializers/spree/events/digital_serializer.rb +0 -18
- data/app/serializers/spree/events/export_serializer.rb +0 -22
- data/app/serializers/spree/events/gift_card_batch_serializer.rb +0 -24
- data/app/serializers/spree/events/gift_card_serializer.rb +0 -29
- data/app/serializers/spree/events/image_serializer.rb +0 -9
- data/app/serializers/spree/events/import_row_serializer.rb +0 -23
- data/app/serializers/spree/events/import_serializer.rb +0 -24
- data/app/serializers/spree/events/invitation_serializer.rb +0 -28
- data/app/serializers/spree/events/line_item_serializer.rb +0 -31
- data/app/serializers/spree/events/newsletter_subscriber_serializer.rb +0 -21
- data/app/serializers/spree/events/order_serializer.rb +0 -39
- data/app/serializers/spree/events/payment_serializer.rb +0 -24
- data/app/serializers/spree/events/post_category_serializer.rb +0 -20
- data/app/serializers/spree/events/post_serializer.rb +0 -26
- data/app/serializers/spree/events/price_serializer.rb +0 -22
- data/app/serializers/spree/events/product_serializer.rb +0 -24
- data/app/serializers/spree/events/promotion_serializer.rb +0 -32
- data/app/serializers/spree/events/refund_serializer.rb +0 -23
- data/app/serializers/spree/events/reimbursement_serializer.rb +0 -22
- data/app/serializers/spree/events/report_serializer.rb +0 -23
- data/app/serializers/spree/events/return_authorization_serializer.rb +0 -22
- data/app/serializers/spree/events/return_item_serializer.rb +0 -27
- data/app/serializers/spree/events/shipment_serializer.rb +0 -24
- data/app/serializers/spree/events/stock_item_serializer.rb +0 -22
- data/app/serializers/spree/events/stock_movement_serializer.rb +0 -22
- data/app/serializers/spree/events/stock_transfer_serializer.rb +0 -22
- data/app/serializers/spree/events/store_credit_serializer.rb +0 -30
- data/app/serializers/spree/events/user_serializer.rb +0 -18
- data/app/serializers/spree/events/variant_serializer.rb +0 -34
- data/app/serializers/spree/events/wished_item_serializer.rb +0 -20
- data/app/serializers/spree/events/wishlist_serializer.rb +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6991203c2954ac7663c4dfadd8362bee850faf1a1888166cd9c7ed0100167398
|
|
4
|
+
data.tar.gz: ec6feab9591d268f2a6f3efd7d5a1557e383e600fb32088c3e09e03abd937ba1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2a58de3390d7466d547af3ff46f6d661776e6b4c9790d02da9d7d90c0b96883647dcea51fb27f75110e1083c8e9dc7075b6bbee49499bfd189ce39bb7235362d
|
|
7
|
+
data.tar.gz: 37fcc6d23c1e9ebf36314be3b85aea5c612eb7eb75a5fa0c2bd10f4c18ff1877298554f45fa80f8d6b841670e5004c1d953df068bebc2a45b59c4495edc10c2e
|
|
@@ -3,11 +3,13 @@ module Spree
|
|
|
3
3
|
class FindComplete
|
|
4
4
|
include Spree::Orders::FinderHelper
|
|
5
5
|
|
|
6
|
-
attr_reader :user, :number, :token, :store, :email
|
|
6
|
+
attr_reader :user, :number, :prefix_id, :param, :token, :store, :email
|
|
7
7
|
|
|
8
|
-
def initialize(user: nil, number: nil, token: nil, store: nil, email: nil)
|
|
8
|
+
def initialize(user: nil, number: nil, prefix_id: nil, param: nil, token: nil, store: nil, email: nil)
|
|
9
9
|
@user = user
|
|
10
10
|
@number = number
|
|
11
|
+
@prefix_id = prefix_id
|
|
12
|
+
@param = param
|
|
11
13
|
@token = token
|
|
12
14
|
@store = store
|
|
13
15
|
@email = email
|
|
@@ -16,6 +18,8 @@ module Spree
|
|
|
16
18
|
def execute
|
|
17
19
|
orders = by_user(scope)
|
|
18
20
|
orders = by_number(orders)
|
|
21
|
+
orders = by_prefix_id(orders)
|
|
22
|
+
orders = by_param(orders)
|
|
19
23
|
orders = by_token(orders)
|
|
20
24
|
orders = by_store(orders)
|
|
21
25
|
orders = by_email(orders)
|
|
@@ -37,6 +41,14 @@ module Spree
|
|
|
37
41
|
number.present?
|
|
38
42
|
end
|
|
39
43
|
|
|
44
|
+
def prefix_id?
|
|
45
|
+
prefix_id.present?
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def param?
|
|
49
|
+
param.present?
|
|
50
|
+
end
|
|
51
|
+
|
|
40
52
|
def token?
|
|
41
53
|
token.present?
|
|
42
54
|
end
|
|
@@ -61,6 +73,25 @@ module Spree
|
|
|
61
73
|
orders.where(number: number)
|
|
62
74
|
end
|
|
63
75
|
|
|
76
|
+
def by_prefix_id(orders)
|
|
77
|
+
return orders unless prefix_id?
|
|
78
|
+
|
|
79
|
+
decoded = Spree::Order.decode_prefixed_id(prefix_id)
|
|
80
|
+
orders.where(id: decoded)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Find by param - tries prefixed ID first, then number for backwards compatibility
|
|
84
|
+
def by_param(orders)
|
|
85
|
+
return orders unless param?
|
|
86
|
+
|
|
87
|
+
decoded = Spree::Order.decode_prefixed_id(param)
|
|
88
|
+
if decoded
|
|
89
|
+
orders.where(id: decoded)
|
|
90
|
+
else
|
|
91
|
+
orders.where(number: param)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
64
95
|
def by_token(orders)
|
|
65
96
|
return orders unless token?
|
|
66
97
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Stores
|
|
3
|
+
class FindDefault
|
|
4
|
+
def initialize(scope: nil, url: nil)
|
|
5
|
+
@scope = scope || Spree::Store
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def execute
|
|
9
|
+
store = @scope.where(default: true).first || @scope.first
|
|
10
|
+
return if store.nil?
|
|
11
|
+
|
|
12
|
+
Spree::Current.store = store
|
|
13
|
+
store
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -4,8 +4,7 @@ module Spree
|
|
|
4
4
|
def address_form_countries_states_cache_key
|
|
5
5
|
@address_form_countries_states_cache_key ||= [
|
|
6
6
|
I18n.locale,
|
|
7
|
-
current_store.cache_key_with_version
|
|
8
|
-
current_store.checkout_zone&.cache_key_with_version
|
|
7
|
+
current_store.cache_key_with_version
|
|
9
8
|
].compact
|
|
10
9
|
end
|
|
11
10
|
|
|
@@ -134,10 +134,10 @@ module Spree
|
|
|
134
134
|
|
|
135
135
|
base_url = if options[:relative]
|
|
136
136
|
''
|
|
137
|
-
elsif store.formatted_custom_domain.
|
|
138
|
-
store.formatted_url
|
|
139
|
-
else
|
|
137
|
+
elsif store.respond_to?(:formatted_custom_domain) && store.formatted_custom_domain.present?
|
|
140
138
|
store.formatted_custom_domain
|
|
139
|
+
else
|
|
140
|
+
store.formatted_url
|
|
141
141
|
end
|
|
142
142
|
|
|
143
143
|
localize = if options[:locale].present?
|
|
@@ -204,7 +204,8 @@ module Spree
|
|
|
204
204
|
end
|
|
205
205
|
|
|
206
206
|
def maximum_quantity
|
|
207
|
-
Spree::
|
|
207
|
+
Spree::Deprecation.warn('BaseHelper#maximum_quantity is deprecated and will be removed in Spree 5.5')
|
|
208
|
+
Spree::DatabaseTypeUtilities::INTEGER_MAX
|
|
208
209
|
end
|
|
209
210
|
|
|
210
211
|
def payment_method_icon_tag(payment_method, opts = {})
|
|
@@ -2,8 +2,19 @@ module Spree
|
|
|
2
2
|
module AdminUserMethods
|
|
3
3
|
extend ActiveSupport::Concern
|
|
4
4
|
|
|
5
|
+
include Spree::PrefixedId
|
|
6
|
+
include Spree::UserRoles
|
|
7
|
+
include Spree::RansackableAttributes
|
|
8
|
+
|
|
5
9
|
included do
|
|
10
|
+
has_prefix_id :admin
|
|
11
|
+
|
|
12
|
+
has_person_name
|
|
13
|
+
|
|
14
|
+
normalizes :email, :first_name, :last_name, with: ->(value) { value&.to_s&.squish&.presence }
|
|
15
|
+
|
|
6
16
|
# Associations
|
|
17
|
+
has_many :identities, class_name: 'Spree::UserIdentity', as: :user, dependent: :destroy
|
|
7
18
|
has_many :canceled_orders, class_name: 'Spree::Order', foreign_key: :canceler_id
|
|
8
19
|
has_many :created_orders, class_name: 'Spree::Order', foreign_key: :created_by_id
|
|
9
20
|
has_many :approved_orders, class_name: 'Spree::Order', foreign_key: :approver_id
|
|
@@ -19,6 +30,27 @@ module Spree
|
|
|
19
30
|
# Callbacks
|
|
20
31
|
after_destroy :nullify_approver_id_in_approved_orders
|
|
21
32
|
after_destroy :cleanup_admin_user_resources
|
|
33
|
+
|
|
34
|
+
# Attachments
|
|
35
|
+
has_one_attached :avatar, service: Spree.public_storage_service_name
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# Attributes
|
|
39
|
+
#
|
|
40
|
+
attr_accessor :confirm_email
|
|
41
|
+
|
|
42
|
+
self.whitelisted_ransackable_associations = %w[spree_roles]
|
|
43
|
+
self.whitelisted_ransackable_attributes = %w[id email first_name last_name]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def can_be_deleted?
|
|
47
|
+
Spree::Store.current.users.where.not(id: id).exists?
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Returns the full name of the user
|
|
51
|
+
# @return [String]
|
|
52
|
+
def full_name
|
|
53
|
+
name&.full
|
|
22
54
|
end
|
|
23
55
|
|
|
24
56
|
private
|
|
@@ -3,9 +3,11 @@ module Spree
|
|
|
3
3
|
extend ActiveSupport::Concern
|
|
4
4
|
|
|
5
5
|
included do
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
Spree::Deprecation.warn(
|
|
7
|
+
'Spree::NumberAsParam is deprecated and will be removed in Spree 6.0. ' \
|
|
8
|
+
'Models now use Spree::PrefixedId with Sqids-based prefixed_id method instead. ' \
|
|
9
|
+
'This concern no longer provides any functionality and can be safely removed.'
|
|
10
|
+
)
|
|
9
11
|
end
|
|
10
12
|
end
|
|
11
13
|
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'sqids'
|
|
4
|
+
|
|
5
|
+
module Spree
|
|
6
|
+
# Adds Stripe-style prefixed IDs to Spree models using Sqids encoding.
|
|
7
|
+
# IDs are computed on the fly from integer primary keys -- no database column needed.
|
|
8
|
+
#
|
|
9
|
+
# e.g., Product with id=12345 -> "prod_86Rf07xd4z"
|
|
10
|
+
#
|
|
11
|
+
# class Product < Spree.base_class
|
|
12
|
+
# has_prefix_id :prod
|
|
13
|
+
# end
|
|
14
|
+
module PrefixedId
|
|
15
|
+
extend ActiveSupport::Concern
|
|
16
|
+
|
|
17
|
+
SQIDS = Sqids.new(min_length: 10)
|
|
18
|
+
|
|
19
|
+
included do
|
|
20
|
+
class_attribute :_prefix_id_prefix, instance_writer: false
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Returns the Stripe-style prefixed ID, or nil for unsaved records.
|
|
24
|
+
def prefixed_id
|
|
25
|
+
return nil unless id.present?
|
|
26
|
+
|
|
27
|
+
"#{self.class._prefix_id_prefix}_#{Spree::PrefixedId::SQIDS.encode([id])}"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Use prefixed_id for URL params when available.
|
|
31
|
+
# Skip if FriendlyId is used (it has its own to_param using slug).
|
|
32
|
+
def to_param
|
|
33
|
+
return super if self.class.respond_to?(:friendly_id_config)
|
|
34
|
+
return super unless self.class._prefix_id_prefix.present?
|
|
35
|
+
|
|
36
|
+
prefixed_id.presence || super
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
class_methods do
|
|
40
|
+
def has_prefix_id(prefix)
|
|
41
|
+
self._prefix_id_prefix = prefix.to_s
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def find_by_prefix_id!(prefixed_id)
|
|
45
|
+
decoded = decode_prefixed_id(prefixed_id)
|
|
46
|
+
raise ActiveRecord::RecordNotFound.new("Couldn't find #{name} with prefixed id=#{prefixed_id}", name) unless decoded
|
|
47
|
+
|
|
48
|
+
find(decoded)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def find_by_prefix_id(prefixed_id)
|
|
52
|
+
decoded = decode_prefixed_id(prefixed_id)
|
|
53
|
+
return nil unless decoded
|
|
54
|
+
|
|
55
|
+
find_by(id: decoded)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Decode a prefixed ID string (e.g., "prod_86Rf07xd4z") to the integer primary key.
|
|
59
|
+
def decode_prefixed_id(prefixed_id_string)
|
|
60
|
+
return nil if prefixed_id_string.blank?
|
|
61
|
+
|
|
62
|
+
parts = prefixed_id_string.to_s.split('_', 2)
|
|
63
|
+
return nil if parts.length != 2
|
|
64
|
+
|
|
65
|
+
_prefix, encoded = parts
|
|
66
|
+
ids = Spree::PrefixedId::SQIDS.decode(encoded)
|
|
67
|
+
ids.first
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Find by prefixed ID first, falling back to integer id for backwards compatibility.
|
|
71
|
+
def find_by_param(param)
|
|
72
|
+
return nil if param.blank?
|
|
73
|
+
|
|
74
|
+
find_by_prefix_id(param) || (find_by(id: param) if param.to_s.match?(/\A\d+\z/))
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def find_by_param!(param)
|
|
78
|
+
find_by_param(param) || raise(ActiveRecord::RecordNotFound.new("Couldn't find #{name} with param=#{param}", name))
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -126,9 +126,8 @@ module Spree
|
|
|
126
126
|
#
|
|
127
127
|
# SELECT COUNT(*) ...
|
|
128
128
|
add_search_scope :in_taxon do |taxon|
|
|
129
|
-
|
|
130
|
-
where(
|
|
131
|
-
order('spree_products_taxons.position ASC')
|
|
129
|
+
joins(:classifications).
|
|
130
|
+
where("#{Classification.table_name}.taxon_id" => taxon.cached_self_and_descendants_ids).distinct
|
|
132
131
|
end
|
|
133
132
|
|
|
134
133
|
# This scope selects products in all taxons AND all its descendants
|
|
@@ -205,15 +204,33 @@ module Spree
|
|
|
205
204
|
return Product.group("#{Spree::Product.table_name}.id").none if option_type_id.blank?
|
|
206
205
|
|
|
207
206
|
group("#{Spree::Product.table_name}.id").
|
|
208
|
-
joins(
|
|
207
|
+
joins(variants: :option_values).
|
|
209
208
|
where(Spree::OptionValue.table_name => { name: value, option_type_id: option_type_id })
|
|
210
209
|
end
|
|
211
210
|
|
|
211
|
+
# Filters products by option value IDs (prefix IDs like 'optval_xxx')
|
|
212
|
+
# Accepts an array of option value IDs
|
|
213
|
+
add_search_scope :with_option_value_ids do |*ids|
|
|
214
|
+
ids = ids.flatten.compact
|
|
215
|
+
return none if ids.empty?
|
|
216
|
+
|
|
217
|
+
# Handle prefixed IDs (optval_xxx) by decoding to actual IDs
|
|
218
|
+
actual_ids = ids.map do |id|
|
|
219
|
+
id.to_s.include?('_') ? OptionValue.decode_prefixed_id(id) : id
|
|
220
|
+
end.compact
|
|
221
|
+
|
|
222
|
+
return none if actual_ids.empty?
|
|
223
|
+
|
|
224
|
+
group("#{Spree::Product.table_name}.id").
|
|
225
|
+
joins(variants: :option_values).
|
|
226
|
+
where(Spree::OptionValue.table_name => { id: actual_ids })
|
|
227
|
+
end
|
|
228
|
+
|
|
212
229
|
# Finds all products which have either:
|
|
213
230
|
# 1) have an option value with the name matching the one given
|
|
214
231
|
# 2) have a product property with a value matching the one given
|
|
215
232
|
add_search_scope :with do |value|
|
|
216
|
-
includes(
|
|
233
|
+
includes(variants: :option_values).
|
|
217
234
|
includes(:product_properties).
|
|
218
235
|
where("#{OptionValue.table_name}.name = ? OR #{ProductProperty.table_name}.value = ?", value, value)
|
|
219
236
|
end
|
|
@@ -288,11 +305,8 @@ module Spree
|
|
|
288
305
|
|
|
289
306
|
# Can't use add_search_scope for this as it needs a default argument
|
|
290
307
|
def self.available(available_on = nil, currency = nil)
|
|
291
|
-
scope =
|
|
292
|
-
|
|
293
|
-
else
|
|
294
|
-
not_discontinued.where(status: 'active')
|
|
295
|
-
end
|
|
308
|
+
scope = not_discontinued.where(status: 'active')
|
|
309
|
+
scope = scope.where("#{Product.quoted_table_name}.available_on <= ?", available_on) if available_on
|
|
296
310
|
|
|
297
311
|
unless Spree::Config.show_products_without_price
|
|
298
312
|
currency ||= Spree::Store.default.default_currency
|
|
@@ -336,16 +350,17 @@ module Spree
|
|
|
336
350
|
# @param order_direction [Symbol] :desc (default) or :asc
|
|
337
351
|
# @return [ActiveRecord::Relation]
|
|
338
352
|
add_search_scope :by_best_selling do |order_direction = :desc|
|
|
339
|
-
order_dir = order_direction == :desc ? 'DESC' : 'ASC'
|
|
340
353
|
store_id = Spree::Current.store&.id
|
|
354
|
+
sp_table = StoreProduct.arel_table
|
|
355
|
+
products_table = Product.arel_table
|
|
356
|
+
|
|
357
|
+
conditions = sp_table[:product_id].eq(products_table[:id]).and(sp_table[:store_id].eq(store_id))
|
|
358
|
+
|
|
359
|
+
units_sold = Arel::Nodes::NamedFunction.new('COALESCE', [sp_table.project(sp_table[:units_sold_count]).where(conditions), 0])
|
|
360
|
+
revenue = Arel::Nodes::NamedFunction.new('COALESCE', [sp_table.project(sp_table[:revenue]).where(conditions), 0])
|
|
341
361
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
.select("#{Product.table_name}.*",
|
|
345
|
-
"#{StoreProduct.table_name}.units_sold_count",
|
|
346
|
-
"#{StoreProduct.table_name}.revenue")
|
|
347
|
-
.order(Arel.sql("#{StoreProduct.table_name}.units_sold_count #{order_dir}"))
|
|
348
|
-
.order(Arel.sql("#{StoreProduct.table_name}.revenue #{order_dir}"))
|
|
362
|
+
order_dir = order_direction == :desc ? :desc : :asc
|
|
363
|
+
order(units_sold.send(order_dir)).order(revenue.send(order_dir))
|
|
349
364
|
end
|
|
350
365
|
|
|
351
366
|
# .search_by_name
|
|
@@ -4,8 +4,14 @@ module Spree
|
|
|
4
4
|
# Concern for models that publish events.
|
|
5
5
|
#
|
|
6
6
|
# This concern is included in Spree::Base, so all Spree models
|
|
7
|
-
# can emit events. Event payloads are generated using
|
|
8
|
-
#
|
|
7
|
+
# can emit events. Event payloads are generated using V3 API serializers
|
|
8
|
+
# resolved by convention: Spree::Order → Spree::Api::V3::OrderSerializer.
|
|
9
|
+
#
|
|
10
|
+
# Models without a V3 serializer get a minimal fallback payload:
|
|
11
|
+
# { id: prefixed_id, created_at: ..., updated_at: ... }
|
|
12
|
+
#
|
|
13
|
+
# STI models (e.g., Spree::Exports::Products) can override
|
|
14
|
+
# event_serializer_class to point to the parent serializer.
|
|
9
15
|
#
|
|
10
16
|
# @example Disabling events for a specific model
|
|
11
17
|
# class Spree::LogEntry < Spree.base_class
|
|
@@ -20,46 +26,16 @@ module Spree
|
|
|
20
26
|
# end
|
|
21
27
|
# end
|
|
22
28
|
#
|
|
23
|
-
# @example
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# def attributes
|
|
29
|
-
# {
|
|
30
|
-
# id: resource.id,
|
|
31
|
-
# number: resource.number,
|
|
32
|
-
# state: resource.state.to_s,
|
|
33
|
-
# # ... other attributes
|
|
34
|
-
# }
|
|
29
|
+
# @example Overriding the serializer for STI models
|
|
30
|
+
# class Spree::Export < Spree.base_class
|
|
31
|
+
# def event_serializer_class
|
|
32
|
+
# Spree::Api::V3::ExportSerializer
|
|
35
33
|
# end
|
|
36
34
|
# end
|
|
37
35
|
#
|
|
38
36
|
module Publishable
|
|
39
37
|
extend ActiveSupport::Concern
|
|
40
38
|
|
|
41
|
-
# Error raised when a model tries to publish an event but has no serializer defined
|
|
42
|
-
class MissingSerializerError < StandardError
|
|
43
|
-
def initialize(model_class)
|
|
44
|
-
serializer_name = "Spree::Events::#{model_class.name.demodulize}Serializer"
|
|
45
|
-
super(
|
|
46
|
-
"Missing event serializer for #{model_class.name}. " \
|
|
47
|
-
"Please create #{serializer_name} that inherits from Spree::Events::BaseSerializer. " \
|
|
48
|
-
"Example:\n\n" \
|
|
49
|
-
" class #{serializer_name} < Spree::Events::BaseSerializer\n" \
|
|
50
|
-
" protected\n\n" \
|
|
51
|
-
" def attributes\n" \
|
|
52
|
-
" {\n" \
|
|
53
|
-
" id: resource.id,\n" \
|
|
54
|
-
" # add other attributes here\n" \
|
|
55
|
-
" updated_at: timestamp(resource.updated_at)\n" \
|
|
56
|
-
" }\n" \
|
|
57
|
-
" end\n" \
|
|
58
|
-
" end"
|
|
59
|
-
)
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
39
|
included do
|
|
64
40
|
class_attribute :publish_events, default: true
|
|
65
41
|
class_attribute :lifecycle_events_enabled, default: false
|
|
@@ -168,36 +144,44 @@ module Spree
|
|
|
168
144
|
|
|
169
145
|
# Get the payload for events
|
|
170
146
|
#
|
|
171
|
-
# Uses
|
|
172
|
-
#
|
|
147
|
+
# Uses the V3 serializer resolved by convention.
|
|
148
|
+
# Falls back to a minimal payload if no serializer is found.
|
|
173
149
|
#
|
|
174
150
|
# @return [Hash]
|
|
175
|
-
# @raise [MissingSerializerError] if no serializer is defined for this model
|
|
176
151
|
def event_payload
|
|
177
152
|
serializer = event_serializer_class
|
|
178
153
|
|
|
179
|
-
|
|
154
|
+
unless serializer
|
|
155
|
+
return {
|
|
156
|
+
id: respond_to?(:prefixed_id) ? prefixed_id : id,
|
|
157
|
+
created_at: created_at&.iso8601,
|
|
158
|
+
updated_at: updated_at&.iso8601
|
|
159
|
+
}
|
|
160
|
+
end
|
|
180
161
|
|
|
181
|
-
|
|
162
|
+
# Use as_json to ensure all values are JSON-safe primitives.
|
|
163
|
+
# Alba's to_h can return raw Ruby objects (e.g., Spree::Money) which
|
|
164
|
+
# ActiveJob cannot serialize for async event subscribers.
|
|
165
|
+
serializer.new(self, params: event_serializer_params).to_h.as_json
|
|
182
166
|
end
|
|
183
167
|
|
|
184
168
|
# Find the event serializer class for this model
|
|
185
169
|
#
|
|
186
|
-
# Looks for Spree::
|
|
187
|
-
#
|
|
188
|
-
#
|
|
170
|
+
# Looks for Spree::Api::V3::ModelNameSerializer by convention.
|
|
171
|
+
# Walks up the class hierarchy to support STI models.
|
|
172
|
+
#
|
|
173
|
+
# Models can override this method to specify a custom serializer,
|
|
174
|
+
# which is useful for STI models like Export, Import, Report.
|
|
189
175
|
#
|
|
190
176
|
# @return [Class, nil] The serializer class or nil if not found
|
|
191
177
|
def event_serializer_class
|
|
192
178
|
return nil unless self.class.name
|
|
193
179
|
|
|
194
|
-
# Try this class and walk up the hierarchy
|
|
195
180
|
klass = self.class
|
|
196
181
|
while klass && klass != Object && klass != BasicObject
|
|
197
182
|
class_name = klass.name&.demodulize
|
|
198
|
-
# Skip looking for BaseSerializer - that's the parent class for all serializers
|
|
199
183
|
if class_name.present? && class_name != 'Base'
|
|
200
|
-
serializer = "Spree::
|
|
184
|
+
serializer = "Spree::Api::V3::#{class_name}Serializer".safe_constantize
|
|
201
185
|
return serializer if serializer
|
|
202
186
|
end
|
|
203
187
|
|
|
@@ -227,6 +211,22 @@ module Spree
|
|
|
227
211
|
|
|
228
212
|
private
|
|
229
213
|
|
|
214
|
+
# Build params for V3 serializers
|
|
215
|
+
#
|
|
216
|
+
# @return [Hash]
|
|
217
|
+
def event_serializer_params
|
|
218
|
+
store = respond_to?(:store) ? self.store : nil
|
|
219
|
+
store ||= Spree::Current.store
|
|
220
|
+
|
|
221
|
+
{
|
|
222
|
+
store: store,
|
|
223
|
+
currency: Spree::Current.currency,
|
|
224
|
+
user: nil,
|
|
225
|
+
locale: nil,
|
|
226
|
+
includes: []
|
|
227
|
+
}
|
|
228
|
+
end
|
|
229
|
+
|
|
230
230
|
def should_publish_events?
|
|
231
231
|
self.class.publish_events && Spree::Events.enabled?
|
|
232
232
|
end
|
|
@@ -1,23 +1,15 @@
|
|
|
1
1
|
module Spree
|
|
2
|
-
module
|
|
2
|
+
module StoreScopedResource
|
|
3
3
|
extend ActiveSupport::Concern
|
|
4
4
|
|
|
5
5
|
included do
|
|
6
6
|
scope :for_store, ->(store) { joins(:stores).where(Store.table_name => { id: store.id }) }
|
|
7
7
|
|
|
8
8
|
before_validation :set_default_store, if: :new_record?
|
|
9
|
-
|
|
10
|
-
validate :must_have_one_store, unless: :disable_store_presence_validation?
|
|
11
9
|
end
|
|
12
10
|
|
|
13
11
|
protected
|
|
14
12
|
|
|
15
|
-
def must_have_one_store
|
|
16
|
-
return if stores.any?
|
|
17
|
-
|
|
18
|
-
errors.add(:stores, Spree.t(:must_have_one_store))
|
|
19
|
-
end
|
|
20
|
-
|
|
21
13
|
def set_default_store
|
|
22
14
|
return if disable_store_presence_validation?
|
|
23
15
|
return if stores.any?
|
|
@@ -25,7 +17,6 @@ module Spree
|
|
|
25
17
|
stores << Spree::Store.default
|
|
26
18
|
end
|
|
27
19
|
|
|
28
|
-
# this can be overridden on model basis
|
|
29
20
|
def disable_store_presence_validation?
|
|
30
21
|
Spree::Config[:disable_store_presence_validation]
|
|
31
22
|
end
|