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.
Files changed (242) hide show
  1. checksums.yaml +4 -4
  2. data/app/finders/spree/orders/find_complete.rb +33 -2
  3. data/app/finders/spree/stores/find_default.rb +17 -0
  4. data/app/finders/spree/variants/visible_finder.rb +1 -0
  5. data/app/helpers/spree/addresses_helper.rb +1 -2
  6. data/app/helpers/spree/base_helper.rb +5 -4
  7. data/app/jobs/spree/api_key_touch_job.rb +9 -0
  8. data/app/jobs/spree/images/save_from_url_job.rb +23 -47
  9. data/app/models/concerns/spree/admin_user_methods.rb +32 -0
  10. data/app/models/concerns/spree/number_as_param.rb +5 -3
  11. data/app/models/concerns/spree/prefixed_id.rb +82 -0
  12. data/app/models/concerns/spree/product_scopes.rb +33 -18
  13. data/app/models/concerns/spree/publishable.rb +47 -47
  14. data/app/models/concerns/spree/{multi_store_resource.rb → store_scoped_resource.rb} +1 -10
  15. data/app/models/concerns/spree/stores/markets.rb +124 -0
  16. data/app/models/concerns/spree/user_methods.rb +7 -7
  17. data/app/models/concerns/spree/user_payment_source.rb +2 -0
  18. data/app/models/concerns/spree/user_roles.rb +1 -0
  19. data/app/models/spree/ability.rb +13 -0
  20. data/app/models/spree/address.rb +30 -0
  21. data/app/models/spree/adjustment.rb +2 -0
  22. data/app/models/spree/api_key.rb +47 -0
  23. data/app/models/spree/asset.rb +2 -0
  24. data/app/models/spree/authentication/strategies/base_strategy.rb +55 -0
  25. data/app/models/spree/authentication/strategies/email_password_strategy.rb +47 -0
  26. data/app/models/spree/base.rb +1 -0
  27. data/app/models/spree/calculator.rb +2 -0
  28. data/app/models/spree/country.rb +56 -0
  29. data/app/models/spree/coupon_code.rb +2 -0
  30. data/app/models/spree/credit_card.rb +2 -0
  31. data/app/models/spree/current.rb +9 -4
  32. data/app/models/spree/customer_group.rb +2 -0
  33. data/app/models/spree/customer_return.rb +2 -0
  34. data/app/models/spree/data_feed.rb +2 -0
  35. data/app/models/spree/digital.rb +2 -0
  36. data/app/models/spree/digital_link.rb +2 -0
  37. data/app/models/spree/export.rb +3 -2
  38. data/app/models/spree/fulfilment_changer.rb +8 -2
  39. data/app/models/spree/gateway/bogus.rb +60 -0
  40. data/app/models/spree/gateway_customer.rb +2 -0
  41. data/app/models/spree/gift_card.rb +2 -0
  42. data/app/models/spree/gift_card_batch.rb +2 -4
  43. data/app/models/spree/image.rb +18 -0
  44. data/app/models/spree/import.rb +5 -3
  45. data/app/models/spree/import_mapping.rb +2 -0
  46. data/app/models/spree/import_row.rb +2 -0
  47. data/app/models/spree/import_schemas/customers.rb +21 -0
  48. data/app/models/spree/imports/customers.rb +9 -0
  49. data/app/models/spree/integration.rb +2 -0
  50. data/app/models/spree/inventory_unit.rb +2 -0
  51. data/app/models/spree/invitation.rb +6 -6
  52. data/app/models/spree/legacy_admin_user.rb +31 -0
  53. data/app/models/spree/legacy_user.rb +19 -1
  54. data/app/models/spree/line_item.rb +15 -4
  55. data/app/models/spree/log_entry.rb +2 -0
  56. data/app/models/spree/market.rb +83 -0
  57. data/app/models/spree/market_country.rb +25 -0
  58. data/app/models/spree/metafield.rb +2 -0
  59. data/app/models/spree/metafield_definition.rb +2 -0
  60. data/app/models/spree/newsletter_subscriber.rb +2 -0
  61. data/app/models/spree/option_type.rb +2 -0
  62. data/app/models/spree/option_value.rb +2 -0
  63. data/app/models/spree/order/address_book.rb +2 -1
  64. data/app/models/spree/order.rb +75 -47
  65. data/app/models/spree/payment.rb +6 -1
  66. data/app/models/spree/payment_capture_event.rb +2 -0
  67. data/app/models/spree/payment_method.rb +59 -1
  68. data/app/models/spree/payment_session.rb +109 -0
  69. data/app/models/spree/payment_sessions/bogus.rb +4 -0
  70. data/app/models/spree/payment_setup_session.rb +79 -0
  71. data/app/models/spree/payment_source.rb +2 -0
  72. data/app/models/spree/permission_sets/default_customer.rb +19 -0
  73. data/app/models/spree/policy.rb +2 -0
  74. data/app/models/spree/post.rb +2 -0
  75. data/app/models/spree/post_category.rb +2 -0
  76. data/app/models/spree/price.rb +26 -2
  77. data/app/models/spree/price_list.rb +2 -0
  78. data/app/models/spree/price_rule.rb +2 -0
  79. data/app/models/spree/price_rules/market_rule.rb +19 -0
  80. data/app/models/spree/product.rb +41 -29
  81. data/app/models/spree/promotion/rules/country.rb +1 -1
  82. data/app/models/spree/promotion.rb +3 -1
  83. data/app/models/spree/promotion_action.rb +2 -0
  84. data/app/models/spree/promotion_category.rb +2 -0
  85. data/app/models/spree/promotion_rule.rb +2 -0
  86. data/app/models/spree/prototype.rb +2 -0
  87. data/app/models/spree/refund.rb +2 -4
  88. data/app/models/spree/refund_reason.rb +2 -0
  89. data/app/models/spree/reimbursement/credit.rb +2 -0
  90. data/app/models/spree/reimbursement.rb +2 -0
  91. data/app/models/spree/reimbursement_type.rb +2 -0
  92. data/app/models/spree/report.rb +3 -1
  93. data/app/models/spree/return_authorization.rb +2 -0
  94. data/app/models/spree/return_authorization_reason.rb +2 -0
  95. data/app/models/spree/return_item.rb +2 -0
  96. data/app/models/spree/role.rb +2 -0
  97. data/app/models/spree/shipment.rb +11 -1
  98. data/app/models/spree/shipping_category.rb +2 -0
  99. data/app/models/spree/shipping_method.rb +2 -0
  100. data/app/models/spree/shipping_method_category.rb +2 -0
  101. data/app/models/spree/shipping_rate.rb +2 -0
  102. data/app/models/spree/state_change.rb +2 -0
  103. data/app/models/spree/stock_item.rb +2 -0
  104. data/app/models/spree/stock_location.rb +2 -0
  105. data/app/models/spree/stock_movement.rb +2 -0
  106. data/app/models/spree/stock_transfer.rb +2 -1
  107. data/app/models/spree/store.rb +110 -179
  108. data/app/models/spree/store_credit.rb +2 -4
  109. data/app/models/spree/store_credit_category.rb +2 -0
  110. data/app/models/spree/store_credit_event.rb +2 -0
  111. data/app/models/spree/store_credit_type.rb +2 -0
  112. data/app/models/spree/store_product.rb +2 -0
  113. data/app/models/spree/tax_category.rb +2 -0
  114. data/app/models/spree/tax_rate.rb +2 -0
  115. data/app/models/spree/taxon.rb +4 -1
  116. data/app/models/spree/taxon_image.rb +8 -0
  117. data/app/models/spree/taxon_rule.rb +2 -0
  118. data/app/models/spree/taxonomy.rb +2 -0
  119. data/app/models/spree/user_identity.rb +81 -0
  120. data/app/models/spree/variant.rb +13 -3
  121. data/app/models/spree/webhook_delivery.rb +2 -0
  122. data/app/models/spree/webhook_endpoint.rb +2 -17
  123. data/app/models/spree/wished_item.rb +15 -0
  124. data/app/models/spree/wishlist.rb +2 -8
  125. data/app/models/spree/zone.rb +2 -6
  126. data/app/presenters/spree/filters/price_presenter.rb +1 -0
  127. data/app/presenters/spree/filters/price_range_presenter.rb +1 -0
  128. data/app/presenters/spree/filters/quantified_price_range_presenter.rb +1 -0
  129. data/app/presenters/spree/product_summary_presenter.rb +1 -0
  130. data/app/services/spree/addresses/helper.rb +22 -3
  131. data/app/services/spree/cart/associate.rb +19 -6
  132. data/app/services/spree/checkout/select_shipping_method.rb +13 -1
  133. data/app/services/spree/classifications/reposition.rb +5 -0
  134. data/app/services/spree/data_feeds/google/required_attributes.rb +8 -3
  135. data/app/services/spree/gift_cards/apply.rb +4 -5
  136. data/app/services/spree/imports/row_processors/customer.rb +70 -0
  137. data/app/services/spree/orders/approve.rb +5 -3
  138. data/app/services/spree/orders/cancel.rb +9 -4
  139. data/app/services/spree/products/prepare_nested_attributes.rb +1 -1
  140. data/app/services/spree/sample_data/import_runner.rb +54 -0
  141. data/app/services/spree/sample_data/loader.rb +78 -0
  142. data/app/services/spree/seeds/admin_user.rb +2 -3
  143. data/app/services/spree/seeds/all.rb +1 -0
  144. data/app/services/spree/seeds/api_keys.rb +16 -0
  145. data/app/services/spree/seeds/stores.rb +2 -4
  146. data/app/sorters/spree/orders/sort.rb +4 -0
  147. data/app/subscribers/spree/product_metrics_subscriber.rb +4 -4
  148. data/config/brakeman.ignore +120 -0
  149. data/config/locales/en.yml +20 -5
  150. data/db/migrate/20250923141900_create_spree_user_identities.rb +17 -0
  151. data/db/migrate/20260123000000_create_spree_api_keys.rb +19 -0
  152. data/db/migrate/20260131000000_add_thumbnail_id_to_spree_variants_and_products.rb +9 -0
  153. data/db/migrate/20260213000000_create_spree_payment_sessions.rb +27 -0
  154. data/db/migrate/20260218000000_create_spree_payment_setup_sessions.rb +24 -0
  155. data/db/migrate/20260220000000_create_spree_markets.rb +29 -0
  156. data/db/sample_data/customers.csv +21 -0
  157. data/db/sample_data/metafield_definitions.rb +7 -0
  158. data/db/sample_data/orders.rb +131 -0
  159. data/db/sample_data/payment_methods.rb +17 -0
  160. data/db/sample_data/posts.rb +7 -0
  161. data/db/sample_data/products.csv +1083 -0
  162. data/db/sample_data/promotions.rb +8 -0
  163. data/db/sample_data/shipping_methods.rb +39 -0
  164. data/lib/generators/spree/authentication/devise/devise_generator.rb +2 -2
  165. data/lib/generators/spree/authentication/dummy/dummy_generator.rb +54 -0
  166. data/lib/generators/spree/authentication/dummy/templates/authentication_helpers.rb.tt +52 -0
  167. data/lib/generators/spree/authentication/dummy/templates/create_spree_admin_users.rb.tt +33 -0
  168. data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
  169. data/lib/spree/core/configuration.rb +1 -1
  170. data/lib/spree/core/controller_helpers/common.rb +6 -0
  171. data/lib/spree/core/controller_helpers/currency.rb +5 -0
  172. data/lib/spree/core/controller_helpers/order.rb +5 -1
  173. data/lib/spree/core/controller_helpers/store.rb +1 -1
  174. data/lib/spree/core/dependencies.rb +1 -1
  175. data/lib/spree/core/engine.rb +17 -4
  176. data/lib/spree/core/pricing/context.rb +6 -3
  177. data/lib/spree/core/product_filters.rb +14 -0
  178. data/lib/spree/core/query_filters/comparable.rb +4 -0
  179. data/lib/spree/core/query_filters/text.rb +4 -0
  180. data/lib/spree/core/version.rb +1 -1
  181. data/lib/spree/core.rb +4 -4
  182. data/lib/spree/database_type_utilities.rb +7 -0
  183. data/lib/spree/events.rb +17 -10
  184. data/lib/spree/money.rb +2 -9
  185. data/lib/spree/permitted_attributes.rb +19 -7
  186. data/lib/spree/testing_support/capybara_config.rb +2 -2
  187. data/lib/spree/testing_support/common_rake.rb +15 -4
  188. data/lib/spree/testing_support/factories/api_key_factory.rb +19 -0
  189. data/lib/spree/testing_support/factories/custom_domain_factory.rb +7 -5
  190. data/lib/spree/testing_support/factories/import_factory.rb +12 -0
  191. data/lib/spree/testing_support/factories/market_factory.rb +35 -0
  192. data/lib/spree/testing_support/factories/order_factory.rb +3 -1
  193. data/lib/spree/testing_support/factories/payment_method_factory.rb +2 -0
  194. data/lib/spree/testing_support/factories/payment_session_factory.rb +47 -0
  195. data/lib/spree/testing_support/factories/payment_setup_session_factory.rb +31 -0
  196. data/lib/spree/testing_support/factories/price_rule_factory.rb +10 -0
  197. data/lib/spree/testing_support/factories/user_identity_factory.rb +15 -0
  198. data/lib/spree/testing_support/store.rb +3 -2
  199. data/lib/spree/webhooks.rb +7 -7
  200. data/lib/tasks/images.rake +20 -0
  201. data/lib/tasks/markets.rake +40 -0
  202. data/lib/tasks/sample_data.rake +15 -0
  203. data/spec/fixtures/files/customers_import.csv +4 -0
  204. metadata +88 -62
  205. data/LICENSE.md +0 -57
  206. data/app/finders/spree/stores/find_current.rb +0 -28
  207. data/app/models/spree/custom_domain.rb +0 -59
  208. data/app/serializers/spree/events/asset_serializer.rb +0 -22
  209. data/app/serializers/spree/events/base_serializer.rb +0 -61
  210. data/app/serializers/spree/events/customer_return_serializer.rb +0 -20
  211. data/app/serializers/spree/events/digital_link_serializer.rb +0 -20
  212. data/app/serializers/spree/events/digital_serializer.rb +0 -18
  213. data/app/serializers/spree/events/export_serializer.rb +0 -22
  214. data/app/serializers/spree/events/gift_card_batch_serializer.rb +0 -24
  215. data/app/serializers/spree/events/gift_card_serializer.rb +0 -29
  216. data/app/serializers/spree/events/image_serializer.rb +0 -9
  217. data/app/serializers/spree/events/import_row_serializer.rb +0 -23
  218. data/app/serializers/spree/events/import_serializer.rb +0 -24
  219. data/app/serializers/spree/events/invitation_serializer.rb +0 -28
  220. data/app/serializers/spree/events/line_item_serializer.rb +0 -31
  221. data/app/serializers/spree/events/newsletter_subscriber_serializer.rb +0 -21
  222. data/app/serializers/spree/events/order_serializer.rb +0 -39
  223. data/app/serializers/spree/events/payment_serializer.rb +0 -24
  224. data/app/serializers/spree/events/post_category_serializer.rb +0 -20
  225. data/app/serializers/spree/events/post_serializer.rb +0 -26
  226. data/app/serializers/spree/events/price_serializer.rb +0 -22
  227. data/app/serializers/spree/events/product_serializer.rb +0 -24
  228. data/app/serializers/spree/events/promotion_serializer.rb +0 -32
  229. data/app/serializers/spree/events/refund_serializer.rb +0 -23
  230. data/app/serializers/spree/events/reimbursement_serializer.rb +0 -22
  231. data/app/serializers/spree/events/report_serializer.rb +0 -23
  232. data/app/serializers/spree/events/return_authorization_serializer.rb +0 -22
  233. data/app/serializers/spree/events/return_item_serializer.rb +0 -27
  234. data/app/serializers/spree/events/shipment_serializer.rb +0 -24
  235. data/app/serializers/spree/events/stock_item_serializer.rb +0 -22
  236. data/app/serializers/spree/events/stock_movement_serializer.rb +0 -22
  237. data/app/serializers/spree/events/stock_transfer_serializer.rb +0 -22
  238. data/app/serializers/spree/events/store_credit_serializer.rb +0 -30
  239. data/app/serializers/spree/events/user_serializer.rb +0 -18
  240. data/app/serializers/spree/events/variant_serializer.rb +0 -34
  241. data/app/serializers/spree/events/wished_item_serializer.rb +0 -20
  242. data/app/serializers/spree/events/wishlist_serializer.rb +0 -22
@@ -2,6 +2,7 @@ module Spree
2
2
  module PermittedAttributes
3
3
  ATTRIBUTES = [
4
4
  :address_attributes,
5
+ :api_key_attributes,
5
6
  :asset_attributes,
6
7
  :checkout_attributes,
7
8
  :classification_attributes,
@@ -22,6 +23,7 @@ module Spree
22
23
  :inventory_unit_attributes,
23
24
  :invitation_attributes,
24
25
  :line_item_attributes,
26
+ :market_attributes,
25
27
  :menu_attributes,
26
28
  :menu_item_attributes,
27
29
  :metafield_attributes,
@@ -34,6 +36,8 @@ module Spree
34
36
  :page_section_attributes,
35
37
  :payment_attributes,
36
38
  :payment_method_attributes,
39
+ :payment_session_attributes,
40
+ :payment_setup_session_attributes,
37
41
  :policy_attributes,
38
42
  :post_attributes,
39
43
  :post_category_attributes,
@@ -80,13 +84,15 @@ module Spree
80
84
 
81
85
  @@address_attributes = [
82
86
  :id, :firstname, :lastname, :first_name, :last_name,
83
- :address1, :address2, :city, :country_iso, :country_id, :state_id,
87
+ :address1, :address2, :city, :country_iso, :state_abbr, :country_id, :state_id,
84
88
  :zipcode, :phone, :state_name, :alternative_phone, :company,
85
89
  :user_id, :deleted_at, :label, :quick_checkout,
86
90
  { country: [:iso, :name, :iso3, :iso_name],
87
91
  state: [:name, :abbr] }
88
92
  ]
89
93
 
94
+ @@api_key_attributes = [:name, :key_type]
95
+
90
96
  @@asset_attributes = [:type, :viewable_id, :viewable_type, :attachment, :alt, :position]
91
97
 
92
98
  @@checkout_attributes = [
@@ -136,6 +142,9 @@ module Spree
136
142
 
137
143
  @@line_item_attributes = [:id, :variant_id, :quantity]
138
144
 
145
+ @@market_attributes = [:name, :currency, :default_locale, :supported_locales,
146
+ :tax_inclusive, :default, :position, country_ids: []]
147
+
139
148
  @@menu_attributes = [:name, :locale, :location]
140
149
 
141
150
  @@menu_item_attributes = [:name, :subtitle, :destination, :new_window, :item_type,
@@ -162,6 +171,10 @@ module Spree
162
171
 
163
172
  @@payment_method_attributes = [:name, :type, :description, :active, :display_on, :auto_capture, :position]
164
173
 
174
+ @@payment_session_attributes = [:amount, :payment_method_id, { external_data: {} }]
175
+
176
+ @@payment_setup_session_attributes = [:payment_method_id, { external_data: {} }]
177
+
165
178
  @@policy_attributes = [:name, :slug, :body]
166
179
 
167
180
  @@post_attributes = [:title, :meta_title, :meta_description, :slug, :author_id, :post_category_id, :published_at, :content, :excerpt, :image, tag_list: []]
@@ -262,19 +275,18 @@ module Spree
262
275
  stock_movements_attributes: [:variant_id, :quantity, :originator_id, :stock_item_id]]
263
276
 
264
277
  @@store_attributes = [:name, :url, :seo_title, :code, :meta_keywords,
265
- :meta_description, :default_currency, :mail_from_address,
278
+ :meta_description, :default_currency, :default_country_iso, :mail_from_address,
266
279
  :customer_support_email, :description, :address, :contact_phone,
267
- :supported_locales, :default_locale, :default_country_id, :supported_currencies,
268
- :new_order_notifications_email, :checkout_zone_id, :seo_robots,
269
- :preferred_timezone, :preferred_weight_unit, :preferred_unit_system,
280
+ :supported_locales, :default_locale, :supported_currencies,
281
+ :new_order_notifications_email, :seo_robots,
282
+ :preferred_admin_locale, :preferred_timezone, :preferred_weight_unit, :preferred_unit_system,
270
283
  :preferred_digital_asset_authorized_clicks, :preferred_digital_asset_authorized_days,
271
284
  :preferred_limit_digital_download_count, :preferred_limit_digital_download_days,
272
285
  :preferred_digital_asset_link_expire_time,
273
286
  :logo, :mailer_logo, :social_logo, :favicon_image,
274
- :import_products_from_store_id, :import_payment_methods_from_store_id,
275
287
  :checkout_message, :preferred_guest_checkout,
276
288
  :customer_terms_of_service, :customer_privacy_policy,
277
- :customer_returns_policy, :customer_shipping_policy, :default_country_iso]
289
+ :customer_returns_policy, :customer_shipping_policy]
278
290
 
279
291
  @@store_credit_attributes = %i[amount currency category_id memo]
280
292
 
@@ -1,7 +1,7 @@
1
1
  require 'capybara-screenshot/rspec'
2
2
 
3
3
  Capybara.configure do |config|
4
- config.save_path = ENV['CIRCLE_ARTIFACTS'] if ENV['CIRCLE_ARTIFACTS']
4
+ config.save_path = ENV['CI_ARTIFACTS'] if ENV['CI_ARTIFACTS']
5
5
  config.server = :puma
6
6
  config.default_driver = :rack_test
7
7
  config.javascript_driver = :selenium_chrome_headless
@@ -27,7 +27,7 @@ Capybara.register_driver :selenium_chrome_headless do |app|
27
27
  options.add_argument '--window-size=1920,1080'
28
28
  options.add_argument '--disable-search-engine-choice-screen'
29
29
 
30
- # Required for running in Docker containers (CircleCI)
30
+ # Required for running in CI containers
31
31
  options.add_argument '--no-sandbox'
32
32
  options.add_argument '--disable-dev-shm-usage'
33
33
 
@@ -4,14 +4,25 @@ require 'generators/spree/dummy_model/dummy_model_generator'
4
4
  desc 'Generates a dummy app for testing'
5
5
  namespace :common do
6
6
  task :test_app, [:authentication, :user_class, :admin_user_class, :css, :javascript, :install_admin, :install_storefront] do |_t, args|
7
- args.with_defaults(
7
+ # Support both Rake::TaskArguments (via invoke) and Hash (via execute)
8
+ # When using execute with a Hash, args IS the hash directly
9
+ defaults = {
8
10
  authentication: 'dummy',
9
11
  user_class: 'Spree::LegacyUser',
12
+ admin_user_class: 'Spree::LegacyAdminUser',
10
13
  install_storefront: false,
11
14
  install_admin: false,
12
15
  javascript: false,
13
16
  css: false
14
- )
17
+ }
18
+ # Rake::TaskArguments#with_defaults modifies in-place
19
+ # ActiveSupport adds Hash#with_defaults which returns a new hash, so check for Rake::TaskArguments specifically
20
+ if args.is_a?(Rake::TaskArguments)
21
+ args.with_defaults(defaults)
22
+ else
23
+ # Hash passed via execute - use reverse_merge! to merge defaults in place
24
+ args.reverse_merge!(defaults)
25
+ end
15
26
  require ENV['LIB_NAME'].to_s
16
27
 
17
28
  # Convert to booleans (supports both string and boolean values for backwards compatibility)
@@ -60,8 +71,8 @@ namespace :common do
60
71
  core_gems = %w[spree/core spree/api]
61
72
  root_gemfile = File.expand_path('../../../../Gemfile', __dir__)
62
73
  use_root_gemfile = core_gems.include?(ENV['LIB_NAME']) &&
63
- File.exist?(root_gemfile) &&
64
- File.exist?(File.expand_path('../../../../spree.gemspec', __dir__))
74
+ File.exist?(root_gemfile) &&
75
+ File.exist?(File.expand_path('../../../../spree.gemspec', __dir__))
65
76
  bundle_exec = use_root_gemfile ? "bundle exec --gemfile=#{root_gemfile}" : 'bundle exec'
66
77
  puts 'Running Spree install generator...'
67
78
  system("#{bundle_exec} rails g spree:install --force --auto-accept --migrate=false --seed=false --sample=false --user_class=#{args[:user_class]} --admin_user_class=#{args[:admin_user_class]} --authentication=#{args[:authentication]}")
@@ -0,0 +1,19 @@
1
+ FactoryBot.define do
2
+ factory :api_key, class: Spree::ApiKey do
3
+ name { FFaker::Lorem.word }
4
+ key_type { 'publishable' }
5
+ store
6
+
7
+ trait :publishable do
8
+ key_type { 'publishable' }
9
+ end
10
+
11
+ trait :secret do
12
+ key_type { 'secret' }
13
+ end
14
+
15
+ trait :revoked do
16
+ revoked_at { Time.current }
17
+ end
18
+ end
19
+ end
@@ -1,7 +1,9 @@
1
- FactoryBot.define do
2
- factory :custom_domain, class: Spree::CustomDomain do
3
- url { FFaker::Internet.domain_name }
4
- association :store, factory: :store
5
- default { true }
1
+ if defined?(Spree::CustomDomain)
2
+ FactoryBot.define do
3
+ factory :custom_domain, class: Spree::CustomDomain do
4
+ url { FFaker::Internet.domain_name }
5
+ association :store, factory: :store
6
+ default { true }
7
+ end
6
8
  end
7
9
  end
@@ -16,5 +16,17 @@ FactoryBot.define do
16
16
  )
17
17
  end
18
18
  end
19
+
20
+ factory :customer_import, class: 'Spree::Imports::Customers', parent: :import do
21
+ type { 'Spree::Imports::Customers' }
22
+
23
+ after(:create) do |import|
24
+ import.attachment.attach(
25
+ io: File.open(Spree::Core::Engine.root.join('spec', 'fixtures', 'files', 'customers_import.csv')),
26
+ filename: 'customers_import.csv',
27
+ content_type: 'text/csv'
28
+ )
29
+ end
30
+ end
19
31
  end
20
32
  end
@@ -0,0 +1,35 @@
1
+ FactoryBot.define do
2
+ factory :market, class: Spree::Market do
3
+ sequence(:name) { |n| "Market #{n}" }
4
+ currency { 'USD' }
5
+ default_locale { 'en' }
6
+ store
7
+ countries { [association(:country)] }
8
+
9
+ after(:build) do |market|
10
+ if market.countries.any?
11
+ zone = Spree::Zone.find_or_create_by!(name: 'Test Shipping Zone') do |z|
12
+ z.kind = 'country'
13
+ end
14
+ market.countries.each do |country|
15
+ zone.zone_members.find_or_create_by!(zoneable: country)
16
+ end
17
+ if zone.shipping_methods.empty?
18
+ shipping_category = Spree::ShippingCategory.first || FactoryBot.create(:shipping_category)
19
+ FactoryBot.create(:shipping_method, zones: [zone], shipping_categories: [shipping_category])
20
+ end
21
+ end
22
+ end
23
+
24
+ trait :default do
25
+ default { true }
26
+ end
27
+
28
+ trait :eu do
29
+ name { 'Europe' }
30
+ currency { 'EUR' }
31
+ default_locale { 'de' }
32
+ tax_inclusive { true }
33
+ end
34
+ end
35
+ end
@@ -75,8 +75,10 @@ FactoryBot.define do
75
75
  state { 'complete' }
76
76
 
77
77
  after(:create) do |order, evaluator|
78
- order.refresh_shipment_rates(evaluator.shipping_method_filter)
78
+ # Set completed_at before refreshing shipment rates so order.completed? returns true
79
+ # This prevents the shipping rate selection from recalculating order totals
79
80
  order.update_column(:completed_at, order.completed_at || Time.current)
81
+ order.refresh_shipment_rates(evaluator.shipping_method_filter)
80
82
  end
81
83
 
82
84
  factory :completed_order_with_pending_payment do
@@ -42,4 +42,6 @@ FactoryBot.define do
42
42
  type { 'Spree::Gateway::CustomPaymentSourceMethod' }
43
43
  name { 'Custom' }
44
44
  end
45
+
46
+ factory :bogus_payment_method, parent: :credit_card_payment_method
45
47
  end
@@ -0,0 +1,47 @@
1
+ FactoryBot.define do
2
+ factory :payment_session, class: 'Spree::PaymentSession' do
3
+ order
4
+ payment_method { create(:credit_card_payment_method, stores: [order.store]) }
5
+ amount { order.total }
6
+ currency { order.currency }
7
+ status { 'pending' }
8
+ external_id { "ps_test_#{SecureRandom.hex(12)}" }
9
+ external_data { {} }
10
+
11
+ trait :processing do
12
+ status { 'processing' }
13
+ end
14
+
15
+ trait :completed do
16
+ status { 'completed' }
17
+ end
18
+
19
+ trait :failed do
20
+ status { 'failed' }
21
+ end
22
+
23
+ trait :canceled do
24
+ status { 'canceled' }
25
+ end
26
+
27
+ trait :expired do
28
+ status { 'expired' }
29
+ expires_at { 1.hour.ago }
30
+ end
31
+
32
+ trait :with_expiration do
33
+ expires_at { 24.hours.from_now }
34
+ end
35
+
36
+ trait :with_customer do
37
+ customer { order.user || create(:user) }
38
+ end
39
+
40
+ factory :bogus_payment_session, class: 'Spree::PaymentSessions::Bogus' do
41
+ type { 'Spree::PaymentSessions::Bogus' }
42
+ payment_method { create(:bogus_payment_method, stores: [order.store]) }
43
+ external_id { "bogus_#{SecureRandom.hex(12)}" }
44
+ external_data { { 'client_secret' => "bogus_secret_#{SecureRandom.hex(8)}" } }
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,31 @@
1
+ FactoryBot.define do
2
+ factory :payment_setup_session, class: 'Spree::PaymentSetupSession' do
3
+ customer { create(:user) }
4
+ payment_method { create(:credit_card_payment_method) }
5
+ status { 'pending' }
6
+ external_id { "seti_test_#{SecureRandom.hex(12)}" }
7
+ external_client_secret { "seti_secret_#{SecureRandom.hex(12)}" }
8
+ external_data { {} }
9
+
10
+ trait :processing do
11
+ status { 'processing' }
12
+ end
13
+
14
+ trait :completed do
15
+ status { 'completed' }
16
+ payment_source { create(:credit_card, user: customer) }
17
+ end
18
+
19
+ trait :failed do
20
+ status { 'failed' }
21
+ end
22
+
23
+ trait :canceled do
24
+ status { 'canceled' }
25
+ end
26
+
27
+ trait :expired do
28
+ status { 'expired' }
29
+ end
30
+ end
31
+ end
@@ -45,5 +45,15 @@ FactoryBot.define do
45
45
  customer_group_ids { [] }
46
46
  end
47
47
  end
48
+
49
+ factory :market_price_rule, class: Spree::PriceRules::MarketRule do
50
+ after(:build) do |rule, evaluator|
51
+ rule.preferred_market_ids = evaluator.market_ids if evaluator.respond_to?(:market_ids)
52
+ end
53
+
54
+ transient do
55
+ market_ids { [] }
56
+ end
57
+ end
48
58
  end
49
59
  end
@@ -0,0 +1,15 @@
1
+ FactoryBot.define do
2
+ factory :user_identity, class: Spree::UserIdentity do
3
+ association(:user, factory: :user)
4
+ provider { 'email' }
5
+ sequence(:uid) { |n| "user_#{n}" }
6
+ info { { email: user.email } }
7
+ access_token { nil }
8
+ refresh_token { nil }
9
+ expires_at { nil }
10
+
11
+ trait :expired do
12
+ expires_at { 1.hour.ago }
13
+ end
14
+ end
15
+ end
@@ -18,7 +18,8 @@ RSpec.configure do |config|
18
18
  I18n.with_locale(:en) do
19
19
  Spree::Events.disable do
20
20
  @default_country = Spree::Country.find_by(iso: 'US') || FactoryBot.create(:country_us)
21
- @default_store = Spree::Store.find_by(default: true) || FactoryBot.create(:store, default: true, default_country: @default_country, default_currency: 'USD')
21
+ @default_store = Spree::Store.find_by(default: true) || FactoryBot.create(:store, default: true, default_currency: 'USD')
22
+ @default_store.update_column(:default_country_id, @default_country.id) unless @default_store.read_attribute(:default_country_id) == @default_country.id
22
23
  end
23
24
  end
24
25
  end
@@ -28,7 +29,7 @@ RSpec.configure do |config|
28
29
  unless self.class.metadata[:without_global_store]
29
30
  @default_store&.products = []
30
31
  @default_store&.promotions = []
31
- @default_store&.checkout_zone = nil
32
+ @default_store&.update_column(:checkout_zone_id, nil) if @default_store&.read_attribute(:checkout_zone_id).present?
32
33
  @default_store&.payment_methods = []
33
34
  end
34
35
  end
@@ -1,22 +1,22 @@
1
1
  module Spree
2
2
  module Webhooks
3
3
  def self.disable_webhooks
4
- Spree::Deprecation.warn('Spree::Webhooks.disable_webhooks is deprecated. Use Spree::LegacyWebhooks.disable_webhooks instead.')
4
+ Spree::Deprecation.warn('Spree::Webhooks.disable_webhooks is deprecated and will be removed in Spree 5.5. Use Spree::LegacyWebhooks.disable_webhooks instead.')
5
5
  prev_value = disabled?
6
- RequestStore.store[:disable_spree_legacy_webhooks] = true
6
+ Thread.current[:disable_spree_legacy_webhooks] = true
7
7
  yield
8
8
  ensure
9
- RequestStore.store[:disable_spree_legacy_webhooks] = prev_value
9
+ Thread.current[:disable_spree_legacy_webhooks] = prev_value
10
10
  end
11
11
 
12
12
  def self.disabled?
13
- Spree::Deprecation.warn('Spree::Webhooks.disabled? is deprecated. Use Spree::LegacyWebhooks.disabled? instead.')
14
- RequestStore.fetch(:disable_spree_legacy_webhooks) { false }
13
+ Spree::Deprecation.warn('Spree::Webhooks.disabled? is deprecated and will be removed in Spree 5.5. Use Spree::LegacyWebhooks.disabled? instead.')
14
+ !!Thread.current[:disable_spree_legacy_webhooks]
15
15
  end
16
16
 
17
17
  def self.disabled=(value)
18
- Spree::Deprecation.warn('Spree::Webhooks.disabled= is deprecated. Use Spree::LegacyWebhooks.disabled= instead.')
19
- RequestStore.store[:disable_spree_legacy_webhooks] = value
18
+ Spree::Deprecation.warn('Spree::Webhooks.disabled= is deprecated and will be removed in Spree 5.5. Use Spree::LegacyWebhooks.disabled= instead.')
19
+ Thread.current[:disable_spree_legacy_webhooks] = value
20
20
  end
21
21
  end
22
22
  end
@@ -0,0 +1,20 @@
1
+ namespace :spree do
2
+ namespace :images do
3
+ desc 'Backfill thumbnail_id for all variants and products'
4
+ task backfill_thumbnails: :environment do
5
+ puts 'Backfilling variant thumbnails...'
6
+ Spree::Variant.where(thumbnail_id: nil).where.not(image_count: 0).find_each do |variant|
7
+ first_image = variant.images.order(:position).first
8
+ variant.update_column(:thumbnail_id, first_image.id) if first_image
9
+ end
10
+
11
+ puts 'Backfilling product thumbnails...'
12
+ Spree::Product.where(thumbnail_id: nil).where.not(total_image_count: 0).find_each do |product|
13
+ first_image = product.variant_images.order(:position).first
14
+ product.update_column(:thumbnail_id, first_image.id) if first_image
15
+ end
16
+
17
+ puts 'Done!'
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,40 @@
1
+ namespace :spree do
2
+ namespace :markets do
3
+ desc 'Migrate checkout zones to markets and nullify checkout_zone_id'
4
+ task migrate_checkout_zones: :environment do
5
+ Spree::Store.find_each do |store|
6
+ next if store.markets.exists?
7
+
8
+ checkout_zone_id = store.read_attribute(:checkout_zone_id)
9
+ zone = Spree::Zone.find_by(id: checkout_zone_id) if checkout_zone_id
10
+
11
+ countries = if zone
12
+ zone.country_list.to_a
13
+ else
14
+ default_country = Spree::Country.find_by(id: store.read_attribute(:default_country_id))
15
+ default_country ? [default_country] : []
16
+ end
17
+
18
+ if countries.empty?
19
+ puts " Skipping store '#{store.name}' (#{store.code}) — no countries to migrate"
20
+ next
21
+ end
22
+
23
+ primary_country = countries.first
24
+ iso_country = ISO3166::Country[primary_country.iso] if primary_country
25
+
26
+ market = store.markets.create!(
27
+ name: primary_country&.name || 'Default',
28
+ currency: iso_country&.currency_code || store.read_attribute(:default_currency) || 'USD',
29
+ default_locale: iso_country&.languages_official&.first || store.read_attribute(:default_locale) || 'en',
30
+ default: true,
31
+ countries: countries
32
+ )
33
+
34
+ store.update_column(:checkout_zone_id, nil) if checkout_zone_id
35
+
36
+ puts " Created market '#{market.name}' with #{countries.size} countries for store '#{store.name}' (#{store.code})"
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,15 @@
1
+ namespace :spree do
2
+ desc 'Loads sample data (products, customers, orders, configuration)'
3
+ task load_sample_data: :environment do
4
+ Spree::SampleData::Loader.call
5
+ end
6
+ end
7
+
8
+ # Backwards compatibility
9
+ namespace :spree_sample do
10
+ desc '[DEPRECATED] Use spree:load_sample_data instead'
11
+ task load: :environment do
12
+ warn '[DEPRECATION] `rake spree_sample:load` is deprecated. Use `rake spree:load_sample_data` instead.'
13
+ Rake::Task['spree:load_sample_data'].invoke
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ email,first_name,last_name,phone,accepts_email_marketing,tags,company,address1,address2,city,province_code,country_code,zip
2
+ jane.smith@example.com,Jane,Smith,555-0101,yes,"VIP, Wholesale",Acme Corp,123 Main St,Apt 4,New York,NY,US,10001
3
+ john.doe@example.com,John,Doe,555-0202,no,VIP,,456 Oak Ave,,Los Angeles,CA,US,90001
4
+ maria.garcia@example.com,Maria,Garcia,,,Returning,,,,,,,