spree_core 5.3.5 → 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/jobs/spree/images/save_from_url_job.rb +23 -47
- 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 -4
- 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 +75 -47
- 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 -4
- 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 -4
- 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 -17
- 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/data_feeds/google/required_attributes.rb +8 -3
- data/app/services/spree/gift_cards/apply.rb +4 -5
- 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 -5
- 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 -1
- 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 +88 -62
- 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
data/app/models/spree/store.rb
CHANGED
|
@@ -2,9 +2,7 @@ require 'uri'
|
|
|
2
2
|
|
|
3
3
|
module Spree
|
|
4
4
|
class Store < Spree.base_class
|
|
5
|
-
|
|
6
|
-
admin default app api www cdn files assets checkout account auth login user
|
|
7
|
-
)
|
|
5
|
+
has_prefix_id :store # Spree-specific: store
|
|
8
6
|
|
|
9
7
|
include FriendlyId
|
|
10
8
|
include Spree::TranslatableResource
|
|
@@ -12,6 +10,7 @@ module Spree
|
|
|
12
10
|
include Spree::Metadata
|
|
13
11
|
include Spree::Stores::Setup
|
|
14
12
|
include Spree::Stores::Socials
|
|
13
|
+
include Spree::Stores::Markets
|
|
15
14
|
include Spree::Security::Stores if defined?(Spree::Security::Stores)
|
|
16
15
|
include Spree::UserManagement
|
|
17
16
|
|
|
@@ -19,7 +18,7 @@ module Spree
|
|
|
19
18
|
# Magic methods
|
|
20
19
|
#
|
|
21
20
|
acts_as_paranoid
|
|
22
|
-
friendly_id :
|
|
21
|
+
friendly_id :code, use: [:slugged], slug_column: :code, routes: :normal
|
|
23
22
|
|
|
24
23
|
#
|
|
25
24
|
# Translations
|
|
@@ -38,6 +37,7 @@ module Spree
|
|
|
38
37
|
# Preferences
|
|
39
38
|
#
|
|
40
39
|
# general preferences
|
|
40
|
+
preference :admin_locale, :string
|
|
41
41
|
preference :timezone, :string, default: Time.zone.name
|
|
42
42
|
preference :weight_unit, :string, default: 'lb'
|
|
43
43
|
preference :unit_system, :string, default: 'imperial'
|
|
@@ -101,9 +101,6 @@ module Spree
|
|
|
101
101
|
has_many :reports, class_name: 'Spree::Report'
|
|
102
102
|
has_many :exports, class_name: 'Spree::Export'
|
|
103
103
|
|
|
104
|
-
has_many :custom_domains, class_name: 'Spree::CustomDomain', dependent: :destroy
|
|
105
|
-
has_one :default_custom_domain, -> { where(default: true) }, class_name: 'Spree::CustomDomain'
|
|
106
|
-
|
|
107
104
|
has_many :posts, class_name: 'Spree::Post', dependent: :destroy, inverse_of: :store
|
|
108
105
|
has_many :post_categories, class_name: 'Spree::PostCategory', dependent: :destroy, inverse_of: :store
|
|
109
106
|
|
|
@@ -118,6 +115,9 @@ module Spree
|
|
|
118
115
|
|
|
119
116
|
has_many :customer_groups, class_name: 'Spree::CustomerGroup', dependent: :destroy, inverse_of: :store
|
|
120
117
|
|
|
118
|
+
has_many :api_keys, class_name: 'Spree::ApiKey', dependent: :destroy
|
|
119
|
+
|
|
120
|
+
|
|
121
121
|
#
|
|
122
122
|
# ActionText
|
|
123
123
|
#
|
|
@@ -130,20 +130,16 @@ module Spree
|
|
|
130
130
|
#
|
|
131
131
|
# Virtual attributes
|
|
132
132
|
#
|
|
133
|
-
attribute :import_products_from_store_id, :string, default: nil
|
|
134
|
-
attribute :import_payment_methods_from_store_id, :string, default: nil
|
|
135
|
-
attr_accessor :skip_validate_not_last
|
|
136
133
|
store_accessor :private_metadata, :storefront_password
|
|
137
134
|
|
|
138
135
|
#
|
|
139
136
|
# Validations
|
|
140
137
|
#
|
|
141
138
|
with_options presence: true do
|
|
142
|
-
validates :name, :url, :mail_from_address, :
|
|
139
|
+
validates :name, :url, :mail_from_address, :code
|
|
143
140
|
end
|
|
144
141
|
validates :preferred_digital_asset_authorized_clicks, numericality: { only_integer: true, greater_than: 0 }
|
|
145
142
|
validates :preferred_digital_asset_authorized_days, numericality: { only_integer: true, greater_than: 0 }
|
|
146
|
-
validates :code, uniqueness: { case_sensitive: false, conditions: -> { with_deleted } }, exclusion: RESERVED_CODES
|
|
147
143
|
validates :mail_from_address, email: { allow_blank: false }
|
|
148
144
|
# FIXME: we should remove this condition in v5
|
|
149
145
|
if !ENV['SPREE_DISABLE_DB_CONNECTION'] &&
|
|
@@ -164,59 +160,64 @@ module Spree
|
|
|
164
160
|
|
|
165
161
|
#
|
|
166
162
|
# Callbacks
|
|
167
|
-
before_validation :
|
|
168
|
-
before_validation :set_code, on: :create
|
|
169
|
-
before_validation :set_url
|
|
163
|
+
before_validation :set_default_code, on: :create
|
|
170
164
|
before_save :ensure_default_exists_and_is_unique
|
|
171
|
-
|
|
165
|
+
after_create :ensure_default_market
|
|
172
166
|
after_create :ensure_default_taxonomies_are_created
|
|
173
167
|
after_create :ensure_default_automatic_taxons
|
|
174
168
|
after_create :ensure_default_post_categories_are_created
|
|
175
|
-
after_create :import_products_from_store, if: -> { import_products_from_store_id.present? }
|
|
176
|
-
after_create :import_payment_methods_from_store, if: -> { import_payment_methods_from_store_id.present? }
|
|
177
169
|
after_create :create_default_policies
|
|
178
|
-
before_destroy :validate_not_last, unless: :skip_validate_not_last
|
|
179
|
-
before_destroy :pass_default_flag_to_other_store
|
|
180
170
|
after_commit :clear_cache
|
|
181
|
-
after_commit :handle_code_changes, on: :update, if: -> { code_previously_changed? }
|
|
182
171
|
|
|
183
172
|
#
|
|
184
173
|
# Scopes
|
|
185
174
|
#
|
|
186
175
|
default_scope { order(created_at: :asc) }
|
|
187
|
-
scope :by_custom_domain, ->(url) { left_joins(:custom_domains).where("#{Spree::CustomDomain.table_name}.url" => url) }
|
|
188
|
-
scope :by_url, ->(url) { where(url: url).or(where("#{table_name}.url like ?", "%#{url}%")) }
|
|
189
176
|
|
|
190
177
|
#
|
|
191
178
|
# Delegations
|
|
192
179
|
#
|
|
193
|
-
delegate :iso, to: :default_country, prefix: true, allow_nil: true
|
|
194
180
|
|
|
195
|
-
def self.current(
|
|
196
|
-
|
|
197
|
-
Spree.current_store_finder.new(url: url).execute
|
|
198
|
-
else
|
|
199
|
-
Spree::Current.store
|
|
200
|
-
end
|
|
181
|
+
def self.current(_url = nil)
|
|
182
|
+
Spree::Current.store
|
|
201
183
|
end
|
|
202
184
|
|
|
203
|
-
#
|
|
204
|
-
# this behaviour is very buggy and unpredictable
|
|
185
|
+
# @deprecated The or_initialize behavior will be removed in Spree 5.5.
|
|
205
186
|
def self.default
|
|
206
187
|
Rails.cache.fetch('default_store') do
|
|
207
188
|
# workaround for Mobility bug with first_or_initialize
|
|
208
189
|
if where(default: true).any?
|
|
209
190
|
where(default: true).first
|
|
210
191
|
else
|
|
192
|
+
Spree::Deprecation.warn(
|
|
193
|
+
'Spree::Store.default returning a new unpersisted store when no default store exists is deprecated ' \
|
|
194
|
+
'and will be removed in Spree 5.5. Please ensure a default store is created before calling Store.default.'
|
|
195
|
+
)
|
|
211
196
|
new(default: true)
|
|
212
197
|
end
|
|
213
198
|
end
|
|
214
199
|
end
|
|
215
200
|
|
|
216
201
|
def self.available_locales
|
|
217
|
-
Spree::Store.
|
|
202
|
+
Spree::Store.default&.supported_locales_list || []
|
|
218
203
|
end
|
|
219
204
|
|
|
205
|
+
# @deprecated Use Markets instead. Will be removed in Spree 5.5.
|
|
206
|
+
def checkout_zone
|
|
207
|
+
Spree::Deprecation.warn('Store#checkout_zone is deprecated and will be removed in Spree 5.5. Use Markets instead.')
|
|
208
|
+
super
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# @deprecated Use Markets instead. Will be removed in Spree 5.5.
|
|
212
|
+
def checkout_zone=(zone)
|
|
213
|
+
Spree::Deprecation.warn('Store#checkout_zone= is deprecated and will be removed in Spree 5.5. Use Markets instead.')
|
|
214
|
+
super
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# Virtual attribute — sets the country for the default market created on store creation.
|
|
218
|
+
# Not persisted on the store itself; only used by the after_create callback.
|
|
219
|
+
attr_reader :default_country_iso
|
|
220
|
+
|
|
220
221
|
def default_country_iso=(iso)
|
|
221
222
|
return if iso.blank?
|
|
222
223
|
|
|
@@ -224,10 +225,11 @@ module Spree
|
|
|
224
225
|
|
|
225
226
|
country = Spree::Country.by_iso(iso)
|
|
226
227
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
unless country
|
|
229
|
+
iso_country = ::Country[iso]
|
|
230
|
+
return unless iso_country
|
|
231
|
+
|
|
232
|
+
country = Spree::Country.create!(
|
|
231
233
|
iso_name: iso_country.local_name&.upcase,
|
|
232
234
|
iso: iso_country.alpha2,
|
|
233
235
|
iso3: iso_country.alpha3,
|
|
@@ -236,15 +238,9 @@ module Spree
|
|
|
236
238
|
states_required: Spree::Address::STATES_REQUIRED.include?(iso),
|
|
237
239
|
zipcode_required: !Spree::Address::NO_ZIPCODE_ISO_CODES.include?(iso)
|
|
238
240
|
)
|
|
239
|
-
|
|
240
|
-
self.default_country = new_country
|
|
241
241
|
end
|
|
242
|
-
end
|
|
243
242
|
|
|
244
|
-
|
|
245
|
-
@supported_currencies_list ||= ([default_currency] + read_attribute(:supported_currencies).to_s.split(',')).uniq.map(&:to_s).map do |code|
|
|
246
|
-
::Money::Currency.find(code.strip)
|
|
247
|
-
end.compact.sort_by { |currency| currency.iso_code == default_currency ? 0 : 1 }
|
|
243
|
+
@default_country_for_market = country
|
|
248
244
|
end
|
|
249
245
|
|
|
250
246
|
def seo_meta_description
|
|
@@ -257,10 +253,6 @@ module Spree
|
|
|
257
253
|
end
|
|
258
254
|
end
|
|
259
255
|
|
|
260
|
-
def supported_locales_list
|
|
261
|
-
@supported_locales_list ||= (read_attribute(:supported_locales).to_s.split(',') << default_locale).compact.uniq.sort
|
|
262
|
-
end
|
|
263
|
-
|
|
264
256
|
def unique_name
|
|
265
257
|
@unique_name ||= "#{name} (#{code})"
|
|
266
258
|
end
|
|
@@ -292,51 +284,63 @@ module Spree
|
|
|
292
284
|
end
|
|
293
285
|
end
|
|
294
286
|
|
|
295
|
-
def formatted_custom_domain
|
|
296
|
-
return unless default_custom_domain
|
|
297
|
-
|
|
298
|
-
@formatted_custom_domain ||= if Rails.env.development? || Rails.env.test?
|
|
299
|
-
URI::Generic.build(
|
|
300
|
-
scheme: Rails.application.routes.default_url_options[:protocol] || 'http',
|
|
301
|
-
host: default_custom_domain.url,
|
|
302
|
-
port: Rails.application.routes.default_url_options[:port]
|
|
303
|
-
).to_s
|
|
304
|
-
else
|
|
305
|
-
URI::HTTPS.build(host: default_custom_domain.url).to_s
|
|
306
|
-
end
|
|
307
|
-
end
|
|
308
|
-
|
|
309
287
|
def url_or_custom_domain
|
|
310
|
-
|
|
288
|
+
url
|
|
311
289
|
end
|
|
312
290
|
|
|
313
291
|
def formatted_url_or_custom_domain
|
|
314
|
-
|
|
292
|
+
formatted_url
|
|
315
293
|
end
|
|
316
294
|
|
|
317
|
-
# Returns the
|
|
318
|
-
# @return [Array<Spree::Country>]
|
|
319
|
-
def countries_available_for_checkout
|
|
320
|
-
@countries_available_for_checkout ||= Rails.cache.fetch(countries_available_for_checkout_cache_key) do
|
|
321
|
-
(checkout_zone.try(:country_list) || Spree::Country.all).to_a
|
|
322
|
-
end
|
|
323
|
-
end
|
|
324
|
-
|
|
325
|
-
# Returns the states available for checkout for the store or creates a new one if it doesn't exist
|
|
295
|
+
# Returns the states available for checkout for the store
|
|
326
296
|
# @param country [Spree::Country] the country to get the states for
|
|
327
297
|
# @return [Array<Spree::State>]
|
|
328
298
|
def states_available_for_checkout(country)
|
|
329
299
|
Rails.cache.fetch(states_available_for_checkout_cache_key(country)) do
|
|
330
|
-
|
|
300
|
+
country.states.to_a
|
|
331
301
|
end
|
|
332
302
|
end
|
|
333
303
|
|
|
304
|
+
# @deprecated Use {Spree::Zone.all} or {#countries_with_shipping_coverage} instead.
|
|
305
|
+
# Will be removed in Spree 5.5.
|
|
334
306
|
def supported_shipping_zones
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
307
|
+
Spree::Deprecation.warn(
|
|
308
|
+
'Store#supported_shipping_zones is deprecated and will be removed in Spree 5.5. ' \
|
|
309
|
+
'Use Spree::Zone.all or Store#countries_with_shipping_coverage instead.'
|
|
310
|
+
)
|
|
311
|
+
zone = Spree::Zone.find_by(id: read_attribute(:checkout_zone_id))
|
|
312
|
+
if zone.present?
|
|
313
|
+
[zone]
|
|
314
|
+
else
|
|
315
|
+
Spree::Zone.includes(zone_members: :zoneable).all
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
# Returns countries covered by at least one shipping zone
|
|
320
|
+
# that has an active shipping method attached.
|
|
321
|
+
# Handles both country-type zones (direct membership) and
|
|
322
|
+
# state-type zones (country inferred from state).
|
|
323
|
+
#
|
|
324
|
+
# @return [ActiveRecord::Relation<Spree::Country>]
|
|
325
|
+
def countries_with_shipping_coverage
|
|
326
|
+
zone_ids = Spree::Zone
|
|
327
|
+
.joins(:shipping_methods)
|
|
328
|
+
.select(:id)
|
|
329
|
+
|
|
330
|
+
country_zone_country_ids = Spree::ZoneMember
|
|
331
|
+
.where(zone_id: zone_ids, zoneable_type: 'Spree::Country')
|
|
332
|
+
.select(:zoneable_id)
|
|
333
|
+
|
|
334
|
+
state_zone_country_ids = Spree::State
|
|
335
|
+
.where(id: Spree::ZoneMember
|
|
336
|
+
.where(zone_id: zone_ids, zoneable_type: 'Spree::State')
|
|
337
|
+
.select(:zoneable_id))
|
|
338
|
+
.select(:country_id)
|
|
339
|
+
|
|
340
|
+
Spree::Country
|
|
341
|
+
.where(id: country_zone_country_ids)
|
|
342
|
+
.or(Spree::Country.where(id: state_zone_country_ids))
|
|
343
|
+
.order(:name)
|
|
340
344
|
end
|
|
341
345
|
|
|
342
346
|
# Returns the default stock location for the store or creates a new one if it doesn't exist
|
|
@@ -362,10 +366,6 @@ module Spree
|
|
|
362
366
|
favicon_image.variant(resize_to_limit: [32, 32])
|
|
363
367
|
end
|
|
364
368
|
|
|
365
|
-
def can_be_deleted?
|
|
366
|
-
self.class.where.not(id: id).any?
|
|
367
|
-
end
|
|
368
|
-
|
|
369
369
|
def metric_unit_system?
|
|
370
370
|
preferred_unit_system == 'metric'
|
|
371
371
|
end
|
|
@@ -378,24 +378,6 @@ module Spree
|
|
|
378
378
|
@digital_shipping_category ||= ShippingCategory.find_or_create_by(name: 'Digital')
|
|
379
379
|
end
|
|
380
380
|
|
|
381
|
-
def import_products_from_store
|
|
382
|
-
store = Store.find(import_products_from_store_id)
|
|
383
|
-
product_ids = store.products.pluck(:id)
|
|
384
|
-
|
|
385
|
-
return if product_ids.empty?
|
|
386
|
-
|
|
387
|
-
StoreProduct.insert_all(product_ids.map { |product_id| { store_id: id, product_id: product_id } })
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
def import_payment_methods_from_store
|
|
391
|
-
store = Store.find(import_payment_methods_from_store_id)
|
|
392
|
-
payment_method_ids = store.payment_method_ids
|
|
393
|
-
|
|
394
|
-
return if payment_method_ids.empty?
|
|
395
|
-
|
|
396
|
-
StorePaymentMethod.insert_all(payment_method_ids.map { |payment_method_id| { store_id: id, payment_method_id: payment_method_id } })
|
|
397
|
-
end
|
|
398
|
-
|
|
399
381
|
%w[customer_terms_of_service customer_privacy_policy customer_returns_policy customer_shipping_policy].each do |policy_method|
|
|
400
382
|
define_method policy_method do
|
|
401
383
|
Spree::Deprecation.warn("Store##{policy_method} is deprecated and will be removed in Spree 5.5. Please use Store#policies instead.")
|
|
@@ -407,65 +389,36 @@ module Spree
|
|
|
407
389
|
private
|
|
408
390
|
|
|
409
391
|
def countries_available_for_checkout_cache_key
|
|
410
|
-
"#{cache_key_with_version}
|
|
392
|
+
"#{cache_key_with_version}/countries_available_for_checkout"
|
|
411
393
|
end
|
|
412
394
|
|
|
413
395
|
def states_available_for_checkout_cache_key(country)
|
|
414
|
-
"#{cache_key_with_version}
|
|
415
|
-
end
|
|
416
|
-
|
|
417
|
-
def ensure_default_exists_and_is_unique
|
|
418
|
-
if default
|
|
419
|
-
Store.where.not(id: id).update_all(default: false)
|
|
420
|
-
elsif Store.where(default: true).count.zero?
|
|
421
|
-
self.default = true
|
|
422
|
-
end
|
|
396
|
+
"#{cache_key_with_version}/states_available_for_checkout/#{country&.cache_key_with_version}"
|
|
423
397
|
end
|
|
424
398
|
|
|
425
|
-
def
|
|
426
|
-
|
|
427
|
-
return if supported_locales.present?
|
|
428
|
-
return if default_locale.blank?
|
|
429
|
-
|
|
430
|
-
self.supported_locales = default_locale
|
|
399
|
+
def clear_cache
|
|
400
|
+
Rails.cache.delete('default_store')
|
|
431
401
|
end
|
|
432
402
|
|
|
433
|
-
def
|
|
434
|
-
return
|
|
435
|
-
return if supported_currencies.present?
|
|
436
|
-
return if default_currency.blank?
|
|
403
|
+
def ensure_default_market
|
|
404
|
+
return if markets.exists?
|
|
437
405
|
|
|
438
|
-
|
|
439
|
-
|
|
406
|
+
country = @default_country_for_market
|
|
407
|
+
return if country.blank?
|
|
440
408
|
|
|
441
|
-
|
|
442
|
-
unless can_be_deleted?
|
|
443
|
-
errors.add(:base, :cannot_destroy_only_store)
|
|
444
|
-
throw(:abort)
|
|
445
|
-
end
|
|
446
|
-
end
|
|
409
|
+
iso_country = ISO3166::Country[country.iso]
|
|
447
410
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
411
|
+
Spree::Events.disable do
|
|
412
|
+
markets.create!(
|
|
413
|
+
name: country.name,
|
|
414
|
+
currency: iso_country&.currency_code || read_attribute(:default_currency) || 'USD',
|
|
415
|
+
default_locale: iso_country&.languages_official&.first || read_attribute(:default_locale) || 'en',
|
|
416
|
+
default: true,
|
|
417
|
+
countries: [country]
|
|
418
|
+
)
|
|
452
419
|
end
|
|
453
420
|
end
|
|
454
421
|
|
|
455
|
-
def clear_cache
|
|
456
|
-
Rails.cache.delete('default_store')
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
def ensure_default_country
|
|
460
|
-
return if default_country.present? && (checkout_zone.blank? || checkout_zone.country_list.blank? || checkout_zone.country_list.include?(default_country))
|
|
461
|
-
|
|
462
|
-
self.default_country = if checkout_zone.present? && checkout_zone.country_list.any?
|
|
463
|
-
checkout_zone.country_list.first
|
|
464
|
-
else
|
|
465
|
-
Country.find_by(iso: 'US') || Country.first
|
|
466
|
-
end
|
|
467
|
-
end
|
|
468
|
-
|
|
469
422
|
def ensure_default_taxonomies_are_created
|
|
470
423
|
Spree::Events.disable do
|
|
471
424
|
[
|
|
@@ -547,42 +500,20 @@ module Spree
|
|
|
547
500
|
I18n.t(key, locale: locale, default: I18n.t(key, locale: :en))
|
|
548
501
|
end
|
|
549
502
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
def slug_candidates
|
|
557
|
-
[]
|
|
558
|
-
end
|
|
559
|
-
|
|
560
|
-
def handle_code_changes
|
|
561
|
-
# implement your custom logic here
|
|
503
|
+
def ensure_default_exists_and_is_unique
|
|
504
|
+
if default
|
|
505
|
+
Spree::Store.where.not(id: id).update_all(default: false)
|
|
506
|
+
elsif Spree::Store.where(default: true).count.zero?
|
|
507
|
+
self.default = true
|
|
508
|
+
end
|
|
562
509
|
end
|
|
563
510
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
def set_code
|
|
567
|
-
self.code = if code.present?
|
|
568
|
-
code.parameterize.strip
|
|
569
|
-
elsif name.present?
|
|
570
|
-
name.parameterize.strip
|
|
571
|
-
end
|
|
572
|
-
|
|
573
|
-
return if self.code.blank?
|
|
574
|
-
|
|
575
|
-
# ensure code is unique
|
|
576
|
-
self.code = [name.parameterize, rand(9999)].join('-') while Spree::Store.with_deleted.where(code: self.code).exists?
|
|
511
|
+
def should_generate_new_friendly_id?
|
|
512
|
+
false
|
|
577
513
|
end
|
|
578
514
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
return if url_changed?
|
|
582
|
-
return unless code_changed?
|
|
583
|
-
return unless Spree.root_domain.present?
|
|
584
|
-
|
|
585
|
-
self.url = [code, Spree.root_domain].join('.')
|
|
515
|
+
def set_default_code
|
|
516
|
+
self.code = 'default' if code.blank?
|
|
586
517
|
end
|
|
587
518
|
end
|
|
588
519
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
module Spree
|
|
2
2
|
class StoreCredit < Spree.base_class
|
|
3
|
+
has_prefix_id :credit
|
|
4
|
+
|
|
3
5
|
include Spree::SingleStoreResource
|
|
4
6
|
include Spree::Metafields
|
|
5
7
|
include Spree::Metadata
|
|
@@ -52,10 +54,6 @@ module Spree
|
|
|
52
54
|
extend Spree::DisplayMoney
|
|
53
55
|
money_methods :amount, :amount_used, :amount_remaining, :amount_authorized
|
|
54
56
|
|
|
55
|
-
def amount=(amount)
|
|
56
|
-
self[:amount] = Spree::LocalizedNumber.parse(amount)
|
|
57
|
-
end
|
|
58
|
-
|
|
59
57
|
self.whitelisted_ransackable_attributes = %w[user_id created_by_id amount currency type_id]
|
|
60
58
|
self.whitelisted_ransackable_associations = %w[type user created_by]
|
|
61
59
|
|
data/app/models/spree/taxon.rb
CHANGED
|
@@ -2,6 +2,8 @@ require 'stringex'
|
|
|
2
2
|
|
|
3
3
|
module Spree
|
|
4
4
|
class Taxon < Spree.base_class
|
|
5
|
+
has_prefix_id :txn # Spree-specific: taxon
|
|
6
|
+
|
|
5
7
|
RULES_MATCH_POLICIES = %w[all any].freeze
|
|
6
8
|
SORT_ORDERS = %w[
|
|
7
9
|
manual
|
|
@@ -36,7 +38,8 @@ module Spree
|
|
|
36
38
|
has_one :store, through: :taxonomy
|
|
37
39
|
has_many :classifications, -> { order(:position) }, dependent: :destroy_async, inverse_of: :taxon
|
|
38
40
|
has_many :products, through: :classifications
|
|
39
|
-
|
|
41
|
+
# @deprecated Use Spree::Taxon#image (Active Storage) instead. Will be removed in Spree 5.5.
|
|
42
|
+
has_one :icon, as: :viewable, dependent: :destroy, class_name: 'Spree::TaxonImage'
|
|
40
43
|
|
|
41
44
|
has_many :prototype_taxons, class_name: 'Spree::PrototypeTaxon', dependent: :destroy
|
|
42
45
|
has_many :prototypes, through: :prototype_taxons, class_name: 'Spree::Prototype'
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
module Spree
|
|
2
|
+
# @deprecated Use Spree::Taxon#image (Active Storage) instead. Will be removed in Spree 5.5.
|
|
2
3
|
class TaxonImage < Asset
|
|
3
4
|
include Spree::TaxonImage::Configuration::ActiveStorage
|
|
4
5
|
include Rails.application.routes.url_helpers
|
|
5
6
|
include Spree::ImageMethods
|
|
6
7
|
|
|
8
|
+
after_initialize do
|
|
9
|
+
Spree::Deprecation.warn(
|
|
10
|
+
'Spree::TaxonImage is deprecated and will be removed in Spree 5.5. ' \
|
|
11
|
+
'Please use Spree::Taxon#image (Active Storage) instead.'
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
|
|
7
15
|
def styles
|
|
8
16
|
self.class.styles.map do |_, size|
|
|
9
17
|
width, height = size[/(\d+)x(\d+)/].split('x').map(&:to_i)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
class UserIdentity < Spree::Base
|
|
3
|
+
has_prefix_id :uid
|
|
4
|
+
|
|
5
|
+
belongs_to :user, polymorphic: true, optional: false
|
|
6
|
+
|
|
7
|
+
validates :provider, presence: true
|
|
8
|
+
validates :uid, presence: true, uniqueness: { scope: [:provider, :user_type] }
|
|
9
|
+
|
|
10
|
+
validates :provider, inclusion: {
|
|
11
|
+
in: ->(_record) {
|
|
12
|
+
config = Rails.application.config.spree
|
|
13
|
+
(config.store_authentication_strategies.keys + config.admin_authentication_strategies.keys).uniq.map(&:to_s)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# Store provider-specific data
|
|
18
|
+
# info: JSON field with provider-specific data (name, avatar, etc)
|
|
19
|
+
# access_token: encrypted OAuth access token
|
|
20
|
+
# refresh_token: encrypted OAuth refresh token
|
|
21
|
+
# expires_at: token expiration timestamp
|
|
22
|
+
|
|
23
|
+
# Find or create user from OAuth data
|
|
24
|
+
def self.find_or_create_from_oauth(provider:, uid:, info:, tokens: {}, user_class: nil)
|
|
25
|
+
user_class ||= Spree.user_class
|
|
26
|
+
user_type = user_class.name
|
|
27
|
+
|
|
28
|
+
identity = find_by(provider: provider, uid: uid, user_type: user_type)
|
|
29
|
+
|
|
30
|
+
if identity
|
|
31
|
+
# Update existing identity with fresh tokens
|
|
32
|
+
identity.update(
|
|
33
|
+
info: info,
|
|
34
|
+
access_token: tokens[:access_token],
|
|
35
|
+
refresh_token: tokens[:refresh_token],
|
|
36
|
+
expires_at: tokens[:expires_at]
|
|
37
|
+
)
|
|
38
|
+
identity.user
|
|
39
|
+
else
|
|
40
|
+
# Create new user and identity
|
|
41
|
+
create_user_from_oauth(
|
|
42
|
+
provider: provider,
|
|
43
|
+
uid: uid,
|
|
44
|
+
info: info,
|
|
45
|
+
tokens: tokens,
|
|
46
|
+
user_class: user_class
|
|
47
|
+
)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.create_user_from_oauth(provider:, uid:, info:, tokens: {}, user_class: nil)
|
|
52
|
+
user_class ||= Spree.user_class
|
|
53
|
+
|
|
54
|
+
user = user_class.create!(
|
|
55
|
+
email: info[:email] || generate_temp_email(provider, uid),
|
|
56
|
+
password: SecureRandom.hex(32), # Random password for OAuth users
|
|
57
|
+
first_name: info[:first_name],
|
|
58
|
+
last_name: info[:last_name]
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
user.identities.create!(
|
|
62
|
+
provider: provider,
|
|
63
|
+
uid: uid,
|
|
64
|
+
info: info,
|
|
65
|
+
access_token: tokens[:access_token],
|
|
66
|
+
refresh_token: tokens[:refresh_token],
|
|
67
|
+
expires_at: tokens[:expires_at]
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
user
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.generate_temp_email(provider, uid)
|
|
74
|
+
"#{provider}-#{uid}@temporary.example.com"
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def expired?
|
|
78
|
+
expires_at && expires_at < Time.current
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|