spree_core 5.0.3 → 5.1.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.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/logo.png +0 -0
  3. data/app/finders/spree/products/find.rb +28 -1
  4. data/app/finders/spree/taxons/find.rb +1 -1
  5. data/app/helpers/spree/integrations_helper.rb +15 -0
  6. data/app/javascript/spree/core/controllers/disable_submit_button_controller.js +19 -0
  7. data/app/mailers/spree/invitation_mailer.rb +24 -0
  8. data/app/models/concerns/spree/integrations_concern.rb +11 -0
  9. data/app/models/concerns/spree/product_scopes.rb +6 -6
  10. data/app/models/concerns/spree/translatable_resource.rb +4 -0
  11. data/app/models/concerns/spree/translatable_resource_scopes.rb +17 -3
  12. data/app/models/concerns/spree/unique_name.rb +2 -0
  13. data/app/models/concerns/spree/user_management.rb +33 -0
  14. data/app/models/concerns/spree/user_methods.rb +19 -0
  15. data/app/models/concerns/spree/user_roles.rb +43 -17
  16. data/app/models/spree/ability.rb +8 -6
  17. data/app/models/spree/asset.rb +1 -6
  18. data/app/models/spree/base.rb +1 -0
  19. data/app/models/spree/base_analytics_event_handler.rb +7 -2
  20. data/app/models/spree/classification.rb +13 -0
  21. data/app/models/spree/custom_domain.rb +2 -1
  22. data/app/models/spree/export.rb +1 -1
  23. data/app/models/spree/integration.rb +63 -0
  24. data/app/models/spree/invitation.rb +153 -0
  25. data/app/models/spree/invitations/store.rb +6 -0
  26. data/app/models/spree/order.rb +17 -1
  27. data/app/models/spree/order_merger.rb +7 -5
  28. data/app/models/spree/page_blocks/products/buy_buttons.rb +8 -0
  29. data/app/models/spree/page_blocks/products/quantity_selector.rb +4 -0
  30. data/app/models/spree/page_blocks/products/variant_picker.rb +4 -0
  31. data/app/models/spree/page_sections/featured_product.rb +4 -0
  32. data/app/models/spree/page_sections/image_banner.rb +12 -0
  33. data/app/models/spree/page_sections/image_with_text.rb +12 -0
  34. data/app/models/spree/page_sections/newsletter.rb +1 -1
  35. data/app/models/spree/page_sections/rich_text.rb +11 -0
  36. data/app/models/spree/page_sections/video.rb +8 -0
  37. data/app/models/spree/product.rb +10 -2
  38. data/app/models/spree/product_property.rb +1 -1
  39. data/app/models/spree/property.rb +3 -1
  40. data/app/models/spree/reports/sales_total.rb +5 -1
  41. data/app/models/spree/role.rb +16 -0
  42. data/app/models/spree/role_user.rb +32 -1
  43. data/app/models/spree/shipment.rb +1 -1
  44. data/app/models/spree/shipment_handler.rb +1 -0
  45. data/app/models/spree/shipping_method.rb +1 -1
  46. data/app/models/spree/store.rb +11 -4
  47. data/app/models/spree/store_credit_category.rb +4 -0
  48. data/app/models/spree/taxon.rb +4 -3
  49. data/app/models/spree/variant.rb +9 -1
  50. data/app/services/spree/country_to_timezone.rb +273 -0
  51. data/app/services/spree/seeds/admin_user.rb +4 -2
  52. data/app/services/spree/seeds/all.rb +3 -1
  53. data/app/services/spree/seeds/digital_delivery.rb +20 -0
  54. data/app/services/spree/seeds/returns_environment.rb +27 -0
  55. data/app/services/spree/seeds/tax_categories.rb +12 -0
  56. data/app/services/spree/stores/settings_defaults_by_country.rb +38 -0
  57. data/app/services/spree/tags/bulk_add.rb +13 -7
  58. data/app/views/spree/invitation_mailer/invitation_accepted.html.erb +12 -0
  59. data/app/views/spree/invitation_mailer/invitation_email.html.erb +21 -0
  60. data/config/locales/en.yml +48 -9
  61. data/db/migrate/20250407085228_create_spree_integrations.rb +12 -0
  62. data/db/migrate/20250410061306_create_spree_invitations.rb +20 -0
  63. data/db/migrate/20250418174652_add_resource_to_spree_role_users.rb +8 -0
  64. data/db/migrate/20250508060800_add_selected_locale_to_spree_admin_users.rb +8 -0
  65. data/db/migrate/20250509143831_add_session_id_to_spree_assets.rb +5 -0
  66. data/lib/generators/spree/authentication/devise/devise_generator.rb +5 -2
  67. data/lib/generators/spree/authentication/devise/templates/authentication_helpers.rb.tt +3 -3
  68. data/lib/generators/spree/install/install_generator.rb +5 -0
  69. data/lib/spree/core/controller_helpers/auth.rb +16 -14
  70. data/lib/spree/core/controller_helpers/currency.rb +11 -0
  71. data/lib/spree/core/controller_helpers/order.rb +2 -1
  72. data/lib/spree/core/controller_helpers/strong_parameters.rb +3 -2
  73. data/lib/spree/core/engine.rb +13 -2
  74. data/lib/spree/core/version.rb +1 -1
  75. data/lib/spree/core.rb +1 -0
  76. data/lib/spree/permitted_attributes.rb +118 -13
  77. data/lib/spree/testing_support/capybara_config.rb +1 -1
  78. data/lib/spree/testing_support/factories/integration_factory.rb +7 -0
  79. data/lib/spree/testing_support/factories/invitation_factory.rb +6 -0
  80. data/lib/spree/testing_support/factories/promotion_action_factory.rb +4 -0
  81. data/lib/spree/testing_support/factories/stock_item_factory.rb +5 -1
  82. data/lib/spree/testing_support/factories/user_factory.rb +14 -1
  83. data/lib/spree/translation_migrations.rb +27 -15
  84. data/lib/tasks/core.rake +8 -0
  85. metadata +41 -4
@@ -0,0 +1,8 @@
1
+ class AddResourceToSpreeRoleUsers < ActiveRecord::Migration[7.2]
2
+ def change
3
+ add_reference :spree_role_users, :resource, polymorphic: true, null: true
4
+ add_reference :spree_role_users, :invitation, null: true
5
+
6
+ add_index :spree_role_users, [:resource_id, :resource_type, :user_id, :user_type, :role_id], unique: true
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ class AddSelectedLocaleToSpreeAdminUsers < ActiveRecord::Migration[7.2]
2
+ def change
3
+ if Spree.admin_user_class.present?
4
+ users_table_name = Spree.admin_user_class.table_name
5
+ add_column users_table_name, :selected_locale, :string unless column_exists?(users_table_name, :selected_locale)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ class AddSessionIdToSpreeAssets < ActiveRecord::Migration[7.2]
2
+ def change
3
+ add_column :spree_assets, :session_id, :string
4
+ end
5
+ end
@@ -33,6 +33,8 @@ module Spree
33
33
  include Spree::UserPaymentSource
34
34
  RUBY
35
35
  end
36
+ gsub_file user_class_file, "< ApplicationRecord", "< Spree.base_class"
37
+
36
38
  say "Successfully added Spree user modules into #{user_class_file}"
37
39
  else
38
40
  say "Could not locate user model file at #{user_class_file}. Please add these lines manually:", :red
@@ -42,13 +44,14 @@ module Spree
42
44
  include Spree::UserMethods
43
45
  include Spree::UserPaymentSource
44
46
  RUBY
47
+
48
+ say "Please replace < ApplicationRecord with < Spree.base_class in #{user_class_file}"
45
49
  end
46
50
 
47
51
  append_file 'config/initializers/spree.rb' do
48
52
  %Q{
49
53
  if defined?(Devise) && Devise.respond_to?(:parent_controller)
50
- Devise.parent_controller = "Spree::StoreController"
51
- Devise.parent_mailer = "Spree::BaseMailer"
54
+ Devise.parent_controller = "Spree::BaseController"
52
55
  end\n}
53
56
  end
54
57
  end
@@ -38,13 +38,13 @@ module Spree
38
38
  end
39
39
 
40
40
  def spree_admin_login_path(opts = {})
41
- spree_login_path(opts)
41
+ new_session_path(Spree.admin_user_class.model_name.singular_route_key, opts)
42
42
  end
43
43
 
44
44
  def spree_admin_logout_path(opts = {})
45
- spree_logout_path(opts)
45
+ destroy_session_path(Spree.admin_user_class.model_name.singular_route_key, opts)
46
46
  end
47
47
  end
48
48
  end
49
49
 
50
- ApplicationController.include Spree::AuthenticationHelpers if defined?(ApplicationController)
50
+ ApplicationController.include Spree::AuthenticationHelpers if defined?(ApplicationController)
@@ -78,6 +78,11 @@ module Spree
78
78
  def install_storefront
79
79
  if @install_storefront && Spree::Core::Engine.frontend_available?
80
80
  generate 'spree:storefront:install'
81
+
82
+ # generate devise controllers if authentication is devise
83
+ if @authentication == 'devise'
84
+ generate 'spree:storefront:devise'
85
+ end
81
86
  end
82
87
  end
83
88
 
@@ -17,15 +17,16 @@ module Spree
17
17
 
18
18
  # Needs to be overridden so that we use Spree's Ability rather than anyone else's.
19
19
  def current_ability
20
- @current_ability ||= Spree::Dependencies.ability_class.constantize.new(try_spree_current_user)
20
+ @current_ability ||= Spree::Dependencies.ability_class.constantize.new(try_spree_current_user, { store: current_store })
21
21
  end
22
22
 
23
23
  def redirect_back_or_default(default)
24
- redirect_to(session['spree_user_return_to'] || request.env['HTTP_REFERER'] || default)
25
- session['spree_user_return_to'] = nil
24
+ Spree::Deprecation.warn('redirect_back_or_default is deprecated and will be removed in Spree 5.2. Please use redirect_back(fallback_location: default) instead.')
25
+ redirect_back(fallback_location: default)
26
26
  end
27
27
 
28
28
  def set_token
29
+ Spree::Deprecation.warn('set_token is deprecated and will be removed in Spree 5.2. Please use create_token_cookie(token) instead.')
29
30
  cookies.permanent.signed[:token] ||= cookies.signed[:guest_token]
30
31
  cookies.permanent.signed[:token] ||= {
31
32
  value: generate_token,
@@ -43,18 +44,19 @@ module Spree
43
44
  @current_oauth_token ||= get_last_access_token.call(user) || create_access_token.call(user)
44
45
  end
45
46
 
46
- def store_location
47
- # disallow return to login, logout, signup pages
48
- authentication_routes = [:spree_signup_path, :spree_login_path, :spree_logout_path]
49
- disallowed_urls = []
50
- authentication_routes.each do |route|
51
- disallowed_urls << send(route) if respond_to?(route)
52
- end
47
+ # this will work for devise out of the box
48
+ # for other auth systems you will need to override this method
49
+ def store_location(location = nil)
50
+ return if try_spree_current_user
53
51
 
54
- disallowed_urls.map! { |url| url[/\/\w+$/] }
55
- unless disallowed_urls.include?(request.fullpath)
56
- session['spree_user_return_to'] = request.fullpath.gsub('//', '/')
57
- end
52
+ location ||= request.fullpath
53
+ session_key = store_location_session_key
54
+
55
+ session[session_key] = location
56
+ end
57
+
58
+ def store_location_session_key
59
+ "#{Spree.user_class.model_name.singular_route_key.to_sym}_return_to"
58
60
  end
59
61
 
60
62
  # proxy method to *possible* spree_current_user method
@@ -14,6 +14,8 @@ module Spree
14
14
  end
15
15
  end
16
16
 
17
+ # Returns the currently selected currency.
18
+ # @return [String] the currently selected currency, eg. `USD`
17
19
  def current_currency
18
20
  @current_currency ||= if defined?(session) && session.key?(:currency) && supported_currency?(session[:currency])
19
21
  session[:currency]
@@ -26,10 +28,14 @@ module Spree
26
28
  end&.upcase
27
29
  end
28
30
 
31
+ # Returns the list of supported currencies for the current store.
32
+ # @return [Array<Money::Currency>] the list of supported currencies
29
33
  def supported_currencies
30
34
  @supported_currencies ||= current_store&.supported_currencies_list
31
35
  end
32
36
 
37
+ # Returns the list of supported currencies for all stores.
38
+ # @return [Array<String>] the list of supported currencies, eg. `["USD", "EUR"]`
33
39
  def supported_currencies_for_all_stores
34
40
  @supported_currencies_for_all_stores ||= begin
35
41
  (
@@ -39,12 +45,17 @@ module Spree
39
45
  end
40
46
  end
41
47
 
48
+ # Checks if the given currency is supported.
49
+ # @param currency_iso_code [String] the ISO code of the currency, eg. `USD`
50
+ # @return [Boolean] `true` if the currency is supported, `false` otherwise
42
51
  def supported_currency?(currency_iso_code)
43
52
  return false if supported_currencies.nil?
44
53
 
45
54
  supported_currencies.map(&:iso_code).include?(currency_iso_code.upcase)
46
55
  end
47
56
 
57
+ # Returns the currency parameter from the request.
58
+ # @return [String] the currency parameter, eg. `USD`
48
59
  def currency_param
49
60
  return if current_currency == current_store.default_currency
50
61
 
@@ -118,7 +118,8 @@ module Spree
118
118
  value: token,
119
119
  expires: 90.days.from_now,
120
120
  secure: Rails.configuration.force_ssl || Rails.application.config.ssl_options[:secure_cookies],
121
- domain: current_store.url_or_custom_domain
121
+ domain: current_store.url_or_custom_domain,
122
+ httponly: true
122
123
  }
123
124
  end
124
125
 
@@ -33,8 +33,9 @@ module Spree
33
33
 
34
34
  def permitted_product_attributes
35
35
  permitted_attributes.product_attributes + [
36
- :store_id,
37
- product_properties_attributes: permitted_product_properties_attributes
36
+ variants_attributes: permitted_variant_attributes + ['id', :_destroy],
37
+ master_attributes: permitted_variant_attributes + ['id'],
38
+ product_properties_attributes: permitted_product_properties_attributes + ['id', :_destroy]
38
39
  ]
39
40
  end
40
41
 
@@ -21,8 +21,10 @@ module Spree
21
21
  :page_sections,
22
22
  :page_blocks,
23
23
  :reports,
24
+ :translatable_resources,
24
25
  :analytics_events,
25
- :analytics_event_handlers)
26
+ :analytics_event_handlers,
27
+ :integrations)
26
28
  SpreeCalculators = Struct.new(:shipping_methods, :tax_rates, :promotion_actions_create_adjustments, :promotion_actions_create_item_adjustments)
27
29
  PromoEnvironment = Struct.new(:rules, :actions)
28
30
  isolate_namespace Spree
@@ -234,6 +236,13 @@ module Spree
234
236
  Spree::Reports::SalesTotal
235
237
  ]
236
238
 
239
+ Rails.application.config.spree.translatable_resources = [
240
+ Spree::Product,
241
+ Spree::Taxon,
242
+ Spree::Taxonomy,
243
+ Spree::Store
244
+ ]
245
+
237
246
  Rails.application.config.spree.analytics_events = {
238
247
  product_viewed: 'Product Viewed',
239
248
  product_list_viewed: 'Product List Viewed',
@@ -257,9 +266,11 @@ module Spree
257
266
  checkout_email_entered: 'Checkout Email Entered',
258
267
  checkout_step_viewed: 'Checkout Step Viewed',
259
268
  checkout_step_completed: 'Checkout Step Completed',
260
- order_completed: 'Order Completed'
269
+ order_completed: 'Order Completed',
261
270
  }
262
271
  Rails.application.config.spree.analytics_event_handlers = []
272
+
273
+ Rails.application.config.spree.integrations = []
263
274
  end
264
275
 
265
276
  initializer 'spree.promo.register.promotions.actions' do |app|
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- VERSION = '5.0.3'.freeze
2
+ VERSION = '5.1.0.beta'.freeze
3
3
 
4
4
  def self.version
5
5
  VERSION
data/lib/spree/core.rb CHANGED
@@ -31,6 +31,7 @@ require 'request_store'
31
31
  require 'wannabe_bool'
32
32
  require 'geocoder'
33
33
  require 'oembed'
34
+ require 'safely_block'
34
35
 
35
36
  # This is required because ActiveModel::Validations#invalid? conflicts with the
36
37
  # invalid state of a Payment. In the future this should be removed.
@@ -2,38 +2,65 @@ module Spree
2
2
  module PermittedAttributes
3
3
  ATTRIBUTES = [
4
4
  :address_attributes,
5
+ :asset_attributes,
5
6
  :checkout_attributes,
6
7
  :classification_attributes,
7
8
  :cms_page_attributes,
8
9
  :cms_section_attributes,
10
+ :custom_domain_attributes,
9
11
  :customer_return_attributes,
10
12
  :digital_attributes,
11
13
  :digital_link_attributes,
14
+ :export_attributes,
12
15
  :image_attributes,
16
+ :integration_attributes,
13
17
  :inventory_unit_attributes,
18
+ :invitation_attributes,
14
19
  :line_item_attributes,
15
20
  :menu_attributes,
16
21
  :menu_item_attributes,
17
22
  :option_type_attributes,
18
23
  :option_value_attributes,
24
+ :page_attributes,
25
+ :page_link_attributes,
26
+ :page_section_attributes,
19
27
  :payment_attributes,
28
+ :payment_method_attributes,
20
29
  :product_attributes,
30
+ :promotion_attributes,
31
+ :promotion_rule_attributes,
32
+ :promotion_action_attributes,
21
33
  :product_properties_attributes,
22
34
  :property_attributes,
35
+ :refund_attributes,
36
+ :refund_reason_attributes,
37
+ :reimbursement_attributes,
38
+ :reimbursement_type_attributes,
39
+ :report_attributes,
23
40
  :return_authorization_attributes,
41
+ :return_authorization_reason_attributes,
42
+ :role_attributes,
24
43
  :shipment_attributes,
44
+ :shipping_method_attributes,
45
+ :shipping_category_attributes,
25
46
  :source_attributes,
26
47
  :stock_item_attributes,
27
48
  :stock_location_attributes,
28
49
  :stock_movement_attributes,
50
+ :stock_transfer_attributes,
29
51
  :store_attributes,
30
52
  :store_credit_attributes,
53
+ :store_credit_category_attributes,
54
+ :tax_rate_attributes,
55
+ :tax_category_attributes,
31
56
  :taxon_attributes,
32
57
  :taxonomy_attributes,
58
+ :theme_attributes,
33
59
  :user_attributes,
34
60
  :variant_attributes,
35
61
  :wishlist_attributes,
36
- :wished_item_attributes
62
+ :wished_item_attributes,
63
+ :zone_attributes
37
64
  ]
38
65
 
39
66
  mattr_reader(*ATTRIBUTES)
@@ -47,6 +74,8 @@ module Spree
47
74
  state: [:name, :abbr] }
48
75
  ]
49
76
 
77
+ @@asset_attributes = [:type, :viewable_id, :viewable_type, :attachment, :alt, :position]
78
+
50
79
  @@checkout_attributes = [
51
80
  :coupon_code, :email, :shipping_method_id, :special_instructions, :use_billing, :use_shipping,
52
81
  :user_id, :bill_address_id, :ship_address_id, :accept_marketing, :signup_for_an_account
@@ -60,6 +89,8 @@ module Spree
60
89
 
61
90
  @@cms_section_attributes = [:name, :cms_page_id, :fit, :destination, { content: {}, settings: {} }]
62
91
 
92
+ @@custom_domain_attributes = [:url, :default]
93
+
63
94
  @@customer_return_attributes = [:stock_location_id, {
64
95
  return_items_attributes: [:id, :inventory_unit_id, :return_authorization_id, :returned, :pre_tax_amount,
65
96
  :acceptance_status, :exchange_variant_id, :resellable]
@@ -69,24 +100,39 @@ module Spree
69
100
 
70
101
  @@digital_link_attributes = [:access_counter]
71
102
 
103
+ @@export_attributes = [:type, :format, :record_selection, search_params: {}]
104
+
72
105
  @@image_attributes = [:alt, :attachment, :position, :viewable_type, :viewable_id]
73
106
 
107
+ @@integration_attributes = [:type, :active]
108
+
74
109
  @@inventory_unit_attributes = [:shipment, :shipment_id, :variant_id]
75
110
 
111
+ @@invitation_attributes = [:email, :expires_at, :role_id]
112
+
76
113
  @@line_item_attributes = [:id, :variant_id, :quantity]
77
114
 
78
115
  @@menu_attributes = [:name, :locale, :location]
79
116
 
80
- @@menu_item_attributes = [:name, :subtite, :destination, :new_window, :item_type,
117
+ @@menu_item_attributes = [:name, :subtitle, :destination, :new_window, :item_type,
81
118
  :linked_resource_type, :linked_resource_id, :code, :menu_id]
82
119
 
83
- @@option_type_attributes = [:name, :presentation, :option_values_attributes]
120
+ @@option_type_attributes = [:name, :presentation, :position, :filterable,
121
+ option_values_attributes: [:id, :name, :presentation, :position, :_destroy]]
122
+
123
+ @@option_value_attributes = [:name, :presentation, :position]
124
+
125
+ @@page_attributes = [:name, :slug, :meta_title, :meta_description, :meta_keywords]
126
+
127
+ @@page_link_attributes = [:linkable_id, :linkable_type, :position, :label, :url]
84
128
 
85
- @@option_value_attributes = [:name, :presentation]
129
+ @@page_section_attributes = [:type, :name, :position, :asset]
86
130
 
87
131
  @@payment_attributes = [:amount, :payment_method_id, :payment_method]
88
132
 
89
- @@product_properties_attributes = [:property_name, :value, :position]
133
+ @@payment_method_attributes = [:name, :type, :description, :active, :display_on, :auto_capture, :position]
134
+
135
+ @@product_properties_attributes = [:property_name, :property_id, :value, :position, :_destroy]
90
136
 
91
137
  @@product_attributes = [
92
138
  :name, :description, :available_on, :make_active_at, :discontinue_on, :permalink, :meta_description,
@@ -94,24 +140,60 @@ module Spree
94
140
  :option_values_hash, :weight, :height, :width, :depth,
95
141
  :shipping_category_id, :tax_category_id,
96
142
  :cost_currency, :cost_price, :compare_at_price,
97
- :slug,
143
+ :slug, :track_inventory, :backorderable, :barcode, :status,
144
+ :weight_unit, :dimensions_unit,
98
145
  {
99
146
  tag_list: [],
147
+ label_list: [],
100
148
  option_type_ids: [],
101
- taxon_ids: []
149
+ taxon_ids: [],
150
+ store_ids: [],
151
+ product_option_types_attributes: [:id, :option_type_id, :position, :_destroy]
102
152
  }
103
153
  ]
104
154
 
105
- @@property_attributes = [:name, :presentation, :position]
155
+ @@promotion_attributes = [:name, :description, :starts_at, :expires_at, :code, :usage_limit, :path, :match_policy,
156
+ :advertise, :promotion_category_id, :code_prefix, :kind, :number_of_codes, :multi_codes, store_ids: []]
157
+
158
+ @@promotion_rule_attributes = [:type, :preferred_match_policy, user_ids_to_add: [], product_ids_to_add: [], taxon_ids_to_add: []]
159
+
160
+ @@promotion_action_attributes = [:type, :calculator_type, calculator_attributes: {}, promotion_action_line_items_attributes: [:id, :promotion_action_id, :variant_id, :quantity, :_destroy]]
161
+
162
+ @@property_attributes = [:name, :presentation, :position, :kind, :display_on]
163
+
164
+ @@refund_attributes = [:amount, :refund_reason_id]
165
+
166
+ @@refund_reason_attributes = [:name, :active, :mutable]
167
+
168
+ @@reimbursement_attributes = [return_items_attributes: [:id, :override_reimbursement_type_id, :pre_tax_amount, :exchange_variant_id]]
169
+
170
+ @@reimbursement_type_attributes = [:name, :active]
171
+
172
+ @@report_attributes = [:type, :date_from, :date_to, :currency]
106
173
 
107
174
  @@return_authorization_attributes = [:amount, :memo, :stock_location_id, :inventory_units_attributes,
108
- :return_authorization_reason_id]
175
+ :return_authorization_reason_id, {
176
+ return_items_attributes: [:id, :inventory_unit_id, :return_authorization_id, :returned, :pre_tax_amount,
177
+ :acceptance_status, :exchange_variant_id, :resellable]
178
+ }]
179
+
180
+ @@return_authorization_reason_attributes = [:name, :active]
181
+
182
+ @@return_item_attributes = [:inventory_unit_id, :return_authorization_id, :returned, :pre_tax_amount, :acceptance_status, :exchange_variant_id, :resellable]
183
+
184
+ @@role_attributes = [:name]
109
185
 
110
186
  @@shipment_attributes = [
111
187
  :order, :special_instructions, :stock_location_id, :id,
112
188
  :tracking, :address, :inventory_units, :selected_shipping_rate_id
113
189
  ]
114
190
 
191
+ @@shipping_category_attributes = [:name]
192
+
193
+ @@shipping_method_attributes = [:name, :code,:tracking_url, :tax_category_id, :display_on,
194
+ :estimated_transit_business_days_min, :estimated_transit_business_days_max,
195
+ :calculator_type, :preferences, zone_ids: [], shipping_category_ids: [], calculator_attributes: {}]
196
+
115
197
  # month / year may be provided by some sources, or others may elect to use one field
116
198
  @@source_attributes = [
117
199
  :id, :number, :month, :year, :expiry, :verification_value,
@@ -119,7 +201,7 @@ module Spree
119
201
  :gateway_payment_profile_id, :last_digits, :name, :encrypted_data
120
202
  ]
121
203
 
122
- @@stock_item_attributes = [:variant, :stock_location, :backorderable, :variant_id]
204
+ @@stock_item_attributes = [:variant_id, :stock_location_id, :backorderable, :count_on_hand]
123
205
 
124
206
  @@stock_location_attributes = [
125
207
  :name, :active, :address1, :address2, :city, :zipcode,
@@ -131,6 +213,9 @@ module Spree
131
213
  :quantity, :stock_item, :stock_item_id, :originator, :action
132
214
  ]
133
215
 
216
+ @@stock_transfer_attributes = [:source_location_id, :destination_location_id, :reference,
217
+ stock_movements_attributes: [:variant_id, :quantity, :originator_id, :stock_item_id]]
218
+
134
219
  @@store_attributes = [:name, :url, :seo_title, :code, :meta_keywords,
135
220
  :meta_description, :default_currency, :mail_from_address,
136
221
  :customer_support_email, :description, :address, :contact_phone,
@@ -148,28 +233,48 @@ module Spree
148
233
 
149
234
  @@store_credit_attributes = %i[amount currency category_id memo]
150
235
 
236
+ @@store_credit_category_attributes = [:name]
237
+
151
238
  @@taxonomy_attributes = [:name]
152
239
 
240
+ @@tax_category_attributes = [:name, :tax_code,:description, :is_default]
241
+
242
+ @@tax_rate_attributes = [:name, :amount, :zone_id, :tax_category_id, :included_in_price, :show_rate_in_label, :calculator_type, calculator_attributes: {}]
243
+
153
244
  @@taxon_attributes = [
154
245
  :name, :parent_id, :position, :icon, :description, :permalink, :hide_from_nav,
155
- :taxonomy_id, :meta_description, :meta_keywords, :meta_title, :child_index
246
+ :taxonomy_id, :meta_description, :meta_keywords, :meta_title, :child_index,
247
+ :automatic, :rules_match_policy, :sort_order,
248
+ :image, :square_image, :description,
249
+ taxon_rules_attributes: [:id, :type, :value, :match_policy, :_destroy],
156
250
  ]
157
251
 
252
+ @@theme_attributes = [:name, :type, :default]
253
+
158
254
  @@user_attributes = [:email, :bill_address_id, :ship_address_id, :password, :first_name, :last_name,
159
255
  :password_confirmation, :selected_locale, :avatar, :accepts_email_marketing, :phone,
160
256
  { public_metadata: {}, private_metadata: {}, tag_list: [] }]
161
257
 
162
258
  @@variant_attributes = [
163
259
  :name, :presentation, :cost_price, :discontinue_on, :lock_version,
164
- :position, :track_inventory,
260
+ :position, :track_inventory, :tax_category_id,
165
261
  :product_id, :product, :option_values_attributes, :price, :compare_at_price,
166
262
  :weight, :height, :width, :depth, :sku, :barcode, :cost_currency,
167
263
  :weight_unit, :dimensions_unit,
168
- { options: [:name, :value], option_value_ids: [] }
264
+ {
265
+ options: [:id, :name, :value, :position, :_destroy],
266
+ stock_items_attributes: [:id, :count_on_hand, :stock_location_id, :backorderable, :_destroy],
267
+ prices_attributes: [:id, :amount, :compare_at_amount, :currency, :_destroy],
268
+ price: {},
269
+ option_value_variants_attributes: [:id, :option_value_id, :_destroy],
270
+ option_value_ids: []
271
+ }
169
272
  ]
170
273
 
171
274
  @@wishlist_attributes = [:name, :is_default, :is_private]
172
275
 
173
276
  @@wished_item_attributes = [:variant_id, :quantity]
277
+
278
+ @@zone_attributes = [:name, :description, :default_tax, :kind, :states_country_id, country_ids: [], state_ids: []]
174
279
  end
175
280
  end
@@ -20,7 +20,7 @@ Capybara.register_driver :selenium_chrome_headless do |app|
20
20
  options = ::Selenium::WebDriver::Chrome::Options.new
21
21
  options.add_argument '--headless'
22
22
  options.add_argument '--disable-gpu'
23
- options.add_argument '--window-size=1400,900'
23
+ options.add_argument '--window-size=1440,900'
24
24
  options.add_argument '--disable-search-engine-choice-screen'
25
25
 
26
26
  # Disable timers being throttled in background pages/tabs. Useful for parallel test runs.
@@ -0,0 +1,7 @@
1
+ FactoryBot.define do
2
+ factory :integration, class: Spree::Integration do
3
+ type { 'Spree::Integration' }
4
+ store { Spree::Store.default }
5
+ active { true }
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ FactoryBot.define do
2
+ factory :invitation, class: Spree::Invitation do
3
+ email { FFaker::Internet.email }
4
+ inviter { create(:admin_user) }
5
+ end
6
+ end
@@ -7,4 +7,8 @@ FactoryBot.define do
7
7
  association :promotion
8
8
  association :calculator, factory: :flat_rate_calculator
9
9
  end
10
+
11
+ factory :promotion_action_create_line_items, class: Spree::Promotion::Actions::CreateLineItems do
12
+ association :promotion
13
+ end
10
14
  end
@@ -11,6 +11,10 @@ FactoryBot.define do
11
11
  )&.destroy
12
12
  end
13
13
 
14
- after(:create) { |object| object.adjust_count_on_hand(10) }
14
+ transient do
15
+ adjust_count_on_hand { true }
16
+ end
17
+
18
+ after(:create) { |object, evaluator| object.adjust_count_on_hand(10) if evaluator.adjust_count_on_hand }
15
19
  end
16
20
  end
@@ -30,6 +30,19 @@ FactoryBot.define do
30
30
  first_name { FFaker::Name.first_name }
31
31
  last_name { FFaker::Name.last_name }
32
32
 
33
- spree_roles { [Spree::Role.find_by(name: 'admin') || create(:role, name: 'admin')] }
33
+ transient do
34
+ without_admin_role { false }
35
+ end
36
+
37
+ trait :without_admin_role do
38
+ without_admin_role { true }
39
+ end
40
+
41
+ after(:create) do |user, evaluator|
42
+ unless evaluator.without_admin_role
43
+ admin_role = Spree::Role.default_admin_role
44
+ create(:role_user, user: user, role: admin_role) unless user.has_spree_role?(admin_role.name)
45
+ end
46
+ end
34
47
  end
35
48
  end
@@ -12,14 +12,24 @@ module Spree
12
12
  nullify_translatable_fields = @resource_class.translatable_fields.map { |f| "#{f}=null" }.join(', ')
13
13
 
14
14
  unless @resource_class::Translation.exists?
15
- ActiveRecord::Base.connection.execute("
16
- INSERT INTO #{@translations_table} (#{@translatable_fields}, #{@foreign_key}, locale, created_at, updated_at)
17
- SELECT #{@translatable_fields}, id, '#{@default_locale}' as locale, created_at, updated_at FROM #{@resource_class.table_name};
18
- ")
19
- ActiveRecord::Base.connection.execute("
20
- UPDATE #{@resource_class.table_name}
21
- SET #{nullify_translatable_fields};
22
- ")
15
+ # Copy data from main table to translations table
16
+ @resource_class.find_each do |resource|
17
+ translation_attrs = @resource_class.translatable_fields.each_with_object({}) do |field, attrs|
18
+ attrs[field] = resource[field]
19
+ end
20
+
21
+ @resource_class::Translation.create!(
22
+ translation_attrs.merge(
23
+ @foreign_key => resource.id,
24
+ locale: @default_locale,
25
+ created_at: resource.created_at,
26
+ updated_at: resource.updated_at
27
+ )
28
+ )
29
+ end
30
+
31
+ # Nullify translatable fields in main table
32
+ @resource_class.update_all(nullify_translatable_fields)
23
33
  end
24
34
  end
25
35
 
@@ -27,14 +37,16 @@ module Spree
27
37
  translation_table_fields = @resource_class.translatable_fields.map { |f| "#{@translations_table}.#{f}" }.join(', ')
28
38
  row_expression = @resource_class.translatable_fields.count == 1 ? 'ROW' : ''
29
39
 
30
- ActiveRecord::Base.connection.execute("
31
- UPDATE #{@resource_class.table_name}
32
- SET (#{@translatable_fields}) = #{row_expression}(#{translation_table_fields})
33
- FROM #{@translations_table}
34
- WHERE #{@translations_table}.#{@foreign_key} = #{@resource_class.table_name}.id
35
- ")
40
+ # Update main table with translations
41
+ @resource_class::Translation.find_each do |translation|
42
+ resource = @resource_class.find(translation[@foreign_key])
43
+ @resource_class.translatable_fields.each do |field|
44
+ resource.update_column(field, translation[field])
45
+ end
46
+ end
36
47
 
37
- ActiveRecord::Base.connection.execute("TRUNCATE TABLE #{@translations_table}")
48
+ # Clear translations table
49
+ @resource_class::Translation.delete_all
38
50
  end
39
51
  end
40
52
  end