spree_core 6.0.0.beta1 → 6.0.0.beta3

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 (164) hide show
  1. checksums.yaml +4 -4
  2. data/app/jobs/spree/payments/handle_webhook_job.rb +1 -0
  3. data/app/jobs/spree/sample_data/load_job.rb +18 -0
  4. data/app/jobs/spree/seller_transfers/execute_pending_job.rb +1 -0
  5. data/app/mailers/spree/admin_user_mailer.rb +2 -2
  6. data/app/models/concerns/spree/acted_by.rb +210 -0
  7. data/app/models/concerns/spree/actor.rb +51 -0
  8. data/app/models/concerns/spree/admin_user_methods.rb +48 -17
  9. data/app/models/concerns/spree/customer_methods.rb +17 -1
  10. data/app/models/concerns/spree/has_number.rb +3 -2
  11. data/app/models/concerns/spree/prefixed_id.rb +4 -1
  12. data/app/models/concerns/spree/purchase/payment_processing.rb +1 -1
  13. data/app/models/concerns/spree/purchase/totals.rb +3 -1
  14. data/app/models/concerns/spree/ransackable_attributes.rb +38 -6
  15. data/app/models/concerns/spree/translatable_resource.rb +6 -7
  16. data/app/models/concerns/spree/webhook_payload_redaction.rb +132 -21
  17. data/app/models/spree/adjusters/promotion.rb +1 -1
  18. data/app/models/spree/api_key.rb +5 -3
  19. data/app/models/spree/authentication/lockout.rb +34 -0
  20. data/app/models/spree/authentication/strategies/email_password_strategy.rb +4 -12
  21. data/app/models/spree/authentication/strategies/oidc_strategy.rb +1 -1
  22. data/app/models/spree/catalog.rb +50 -13
  23. data/app/models/spree/claim.rb +3 -1
  24. data/app/models/spree/commission_line.rb +4 -2
  25. data/app/models/spree/commission_rule.rb +1 -1
  26. data/app/models/spree/coupon_code.rb +14 -2
  27. data/app/models/spree/current.rb +56 -13
  28. data/app/models/spree/exchange.rb +3 -1
  29. data/app/models/spree/export.rb +8 -5
  30. data/app/models/spree/exports/customers.rb +2 -2
  31. data/app/models/spree/fulfillment_group.rb +127 -0
  32. data/app/models/spree/gift_card.rb +9 -0
  33. data/app/models/spree/invitation.rb +18 -5
  34. data/app/models/spree/line_item.rb +1 -1
  35. data/app/models/spree/number_generators/sequential.rb +2 -2
  36. data/app/models/spree/option_value.rb +7 -0
  37. data/app/models/spree/order.rb +89 -18
  38. data/app/models/spree/order_group.rb +78 -6
  39. data/app/models/spree/payment_source.rb +1 -1
  40. data/app/models/spree/payment_split.rb +24 -0
  41. data/app/models/spree/price.rb +74 -0
  42. data/app/models/spree/pricing_provider/internal.rb +37 -15
  43. data/app/models/spree/product.rb +4 -0
  44. data/app/models/spree/product_option_type.rb +11 -0
  45. data/app/models/spree/promotion/actions/create_line_items.rb +92 -30
  46. data/app/models/spree/promotion/rules/category.rb +14 -9
  47. data/app/models/spree/promotion/rules/product.rb +17 -1
  48. data/app/models/spree/promotion.rb +1 -1
  49. data/app/models/spree/promotion_action.rb +12 -1
  50. data/app/models/spree/promotion_handler/coupon.rb +50 -5
  51. data/app/models/spree/promotion_rule.rb +14 -0
  52. data/app/models/spree/refund.rb +2 -1
  53. data/app/models/spree/return.rb +18 -7
  54. data/app/models/spree/return_line_item.rb +19 -0
  55. data/app/models/spree/search_provider/database.rb +10 -2
  56. data/app/models/spree/seller_payout.rb +3 -1
  57. data/app/models/spree/seller_transfer.rb +3 -1
  58. data/app/models/spree/stock_receipt.rb +7 -2
  59. data/app/models/spree/store.rb +4 -0
  60. data/app/models/spree/store_credit.rb +4 -0
  61. data/app/models/spree/translations/batch.rb +4 -2
  62. data/app/models/spree/user_identity.rb +10 -6
  63. data/app/models/spree/variant.rb +8 -3
  64. data/app/models/spree/webhook_delivery.rb +28 -0
  65. data/app/models/spree/webhook_endpoint.rb +14 -0
  66. data/app/presenters/spree/csv/order_line_item_presenter.rb +2 -2
  67. data/app/services/spree/carts/split_by_seller.rb +22 -12
  68. data/app/services/spree/companies/add_member.rb +8 -2
  69. data/app/services/spree/imports/row_processors/price_list_price.rb +6 -0
  70. data/app/services/spree/imports/row_processors/product_translation.rb +1 -1
  71. data/app/services/spree/imports/row_processors/product_variant.rb +17 -11
  72. data/app/services/spree/order_groups/allocate_payments.rb +3 -0
  73. data/app/services/spree/orders/approve.rb +3 -2
  74. data/app/services/spree/orders/build_fulfillments.rb +6 -0
  75. data/app/services/spree/orders/update_statuses.rb +8 -2
  76. data/app/services/spree/prices/bulk_upsert.rb +186 -47
  77. data/app/services/spree/sample_data/import_builder.rb +1 -1
  78. data/app/services/spree/sample_data/loader.rb +54 -40
  79. data/app/services/spree/seeds/all.rb +1 -26
  80. data/app/services/spree/seeds/allowed_origins.rb +5 -4
  81. data/app/services/spree/seeds/api_keys.rb +10 -9
  82. data/app/services/spree/seeds/channels.rb +9 -8
  83. data/app/services/spree/seeds/commission_rates.rb +21 -20
  84. data/app/services/spree/seeds/customer_groups.rb +5 -4
  85. data/app/services/spree/seeds/digital_delivery.rb +7 -8
  86. data/app/services/spree/seeds/payment_methods.rb +12 -11
  87. data/app/services/spree/seeds/product_types.rb +7 -8
  88. data/app/services/spree/seeds/returns_environment.rb +12 -11
  89. data/app/services/spree/seeds/roles.rb +8 -7
  90. data/app/services/spree/seeds/saved_reports.rb +19 -20
  91. data/app/services/spree/seeds/seller_requirements.rb +5 -4
  92. data/app/services/spree/seeds/store_resources.rb +41 -0
  93. data/app/services/spree/seeds/store_scoped.rb +15 -0
  94. data/app/services/spree/seeds/tax_categories.rb +10 -9
  95. data/app/services/spree/stock_locations/stock_items/create.rb +1 -1
  96. data/app/services/spree/stock_locations/stock_levels/create.rb +19 -3
  97. data/app/subscribers/spree/order_status_subscriber.rb +15 -7
  98. data/app/workflows/spree/carts/add_item.rb +5 -7
  99. data/app/workflows/spree/carts/complete.rb +20 -64
  100. data/app/workflows/spree/carts/recalculate_totals.rb +3 -1
  101. data/app/workflows/spree/claims/create.rb +31 -1
  102. data/app/workflows/spree/claims/resolve.rb +7 -11
  103. data/app/workflows/spree/exchanges/create.rb +11 -0
  104. data/app/workflows/spree/exchanges/fulfill.rb +21 -13
  105. data/app/workflows/spree/orders/cancel.rb +3 -2
  106. data/app/workflows/spree/orders/complete.rb +99 -2
  107. data/app/workflows/spree/price_lists/update.rb +17 -0
  108. data/app/workflows/spree/refunds/create.rb +1 -1
  109. data/app/workflows/spree/refunds/order_payments.rb +55 -1
  110. data/app/workflows/spree/returns/approve.rb +1 -1
  111. data/app/workflows/spree/returns/create.rb +11 -17
  112. data/app/workflows/spree/returns/refund.rb +16 -25
  113. data/app/workflows/spree/returns/returnable_quantity.rb +53 -0
  114. data/app/workflows/spree/sellers/invite.rb +1 -1
  115. data/config/locales/en.yml +8 -119
  116. data/db/migrate/20260916000001_add_email_delivery_flags_to_spree_order_groups.rb +14 -0
  117. data/db/migrate/20260916000001_order_operation_actors_polymorphic.rb +30 -0
  118. data/db/migrate/20260922000001_add_refunded_order_to_spree_store_credits.rb +5 -0
  119. data/db/migrate/20260923000001_change_spree_user_identities_tokens_to_text.rb +10 -0
  120. data/db/sample_data/channels.rb +1 -1
  121. data/db/sample_data/collections.rb +1 -1
  122. data/db/sample_data/custom_field_definitions.rb +1 -1
  123. data/db/sample_data/digital_products.rb +1 -1
  124. data/db/sample_data/fulfillment.rb +1 -1
  125. data/db/sample_data/options.rb +4 -2
  126. data/db/sample_data/orders.rb +9 -10
  127. data/db/sample_data/payment_methods.rb +18 -18
  128. data/db/sample_data/product_type_categories.rb +1 -1
  129. data/db/sample_data/product_types.rb +2 -2
  130. data/db/sample_data/promotions.rb +2 -4
  131. data/db/sample_data/wholesale.rb +1 -1
  132. data/lib/generators/spree/api_resource/api_resource_generator.rb +121 -6
  133. data/lib/generators/spree/api_resource/templates/admin_controller.rb.tt +8 -2
  134. data/lib/generators/spree/api_resource/templates/admin_controller_spec.rb.tt +3 -0
  135. data/lib/generators/spree/api_resource/templates/permissions.en.yml.tt +6 -0
  136. data/lib/generators/spree/api_resource/templates/store_controller.rb.tt +2 -2
  137. data/lib/generators/spree/api_resource/templates/store_controller_spec.rb.tt +4 -1
  138. data/lib/generators/spree/dummy/templates/rails/test.rb +7 -0
  139. data/lib/generators/spree/model/model_generator.rb +40 -1
  140. data/lib/generators/spree/model/templates/create_table_migration.rb.tt +9 -0
  141. data/lib/generators/spree/model/templates/model.rb.tt +10 -4
  142. data/lib/generators/spree/subscriber/subscriber_generator.rb +3 -3
  143. data/lib/spree/core/configuration.rb +25 -25
  144. data/lib/spree/core/engine.rb +35 -8
  145. data/lib/spree/core/preferences/runtime_configuration.rb +76 -2
  146. data/lib/spree/core/version.rb +1 -1
  147. data/lib/spree/core.rb +27 -0
  148. data/lib/spree/iso_data.rb +23 -4
  149. data/lib/spree/store_scope_guard.rb +16 -1
  150. data/lib/spree/testing_support/factories/invitation_factory.rb +1 -0
  151. data/lib/spree/testing_support/factories/order_group_factory.rb +49 -0
  152. data/lib/spree/testing_support/factories/payment_factory.rb +7 -2
  153. data/lib/spree/testing_support/factories/user_factory.rb +0 -1
  154. data/lib/spree/upgrades/5_6_to_6_0/manifest.yml +34 -0
  155. data/lib/tasks/backfill_actor_types.rake +35 -0
  156. data/lib/tasks/sample_data.rake +8 -2
  157. data/lib/tasks/store_settings.rake +1 -0
  158. data/lib/tasks/upgrade.rake +6 -21
  159. metadata +23 -9
  160. /data/{app/models → lib}/spree/checkout/default_requirements.rb +0 -0
  161. /data/{app/models → lib}/spree/checkout/registry.rb +0 -0
  162. /data/{app/models → lib}/spree/checkout/requirement.rb +0 -0
  163. /data/{app/models → lib}/spree/checkout/requirements.rb +0 -0
  164. /data/{app/models → lib}/spree/checkout/step.rb +0 -0
@@ -375,6 +375,8 @@ en:
375
375
  greater_than_max_amount: is greater than the allowed maximum amount of %{max_amount}
376
376
  spree/price:
377
377
  attributes:
378
+ amount:
379
+ leaves_a_rising_ladder: would leave the price from %{quantity} units at %{amount}, above the %{floor} a buyer pays below that quantity
378
380
  min_quantity:
379
381
  requires_price_list: quantity breaks can only be set on a price list
380
382
  too_many_breaks: a variant can carry at most %{count} quantity breaks on one price list
@@ -385,9 +387,12 @@ en:
385
387
  spree/price_list:
386
388
  attributes:
387
389
  base:
390
+ duplicate_quantity: each quantity break must have its own quantity
388
391
  invalid_quantity: each quantity break must start at a whole number of units
389
392
  negative_price: a price cannot be below zero
390
393
  nothing_to_apply_to: has no rules, no catalog and no products, so it would apply to nothing. Add one before activating.
394
+ price_rises_with_quantity: a quantity break cannot cost more than the price a buyer pays below it
395
+ quantity_on_base_price: a shop price applies at every quantity, so it cannot start at one. Remove the quantity, or pick a price list to put the break on.
391
396
  ends_at:
392
397
  must_be_after_starts_at: must be after starts at
393
398
  price_adjustment_percentage:
@@ -844,15 +849,6 @@ en:
844
849
  company_invitations:
845
850
  email_mismatch: This invitation was sent to a different email address.
846
851
  not_pending: This invitation is no longer pending and cannot be revoked.
847
- company_mailer:
848
- invitation_email:
849
- action: Accept invitation
850
- expiry_notice: This invitation link will expire in 30 days.
851
- greeting: Hi,
852
- ignore_notice: If you were not expecting this invitation, you can safely ignore this email.
853
- instructions: You have been invited to join %{company} on %{store}. Accept the invitation to start purchasing on the company's behalf.
854
- subject: invitation to join %{company}
855
- title: Join %{company}
856
852
  compare_at_amount: Compare at amount
857
853
  compare_at_price: Compare at price
858
854
  complete: complete
@@ -912,21 +908,6 @@ en:
912
908
  anonymize_failed: The erasure could not be completed and nothing was changed
913
909
  customer_group: Customer Group
914
910
  customer_groups: Customer Groups
915
- customer_mailer:
916
- data_export_email:
917
- action: Download Your Data
918
- expiry_notice: This download link expires on %{date}.
919
- greeting: Hello,
920
- ignore_notice: If you did not request a copy of your data, please contact us.
921
- instructions: Your copy of the personal data we hold about you is ready. Use the button below to download it.
922
- subject: Your Data Is Ready to Download
923
- password_reset_email:
924
- action: Reset Password
925
- expiry_notice: This password reset link will expire shortly. If you did not request this, no action is needed.
926
- greeting: Hi %{name},
927
- ignore_notice: If you did not request a password reset, you can safely ignore this email. Your password will not be changed.
928
- instructions: We received a request to reset your password. Click the button below to choose a new password.
929
- subject: Password Reset Instructions
930
911
  customer_support_email: Customer Support Email
931
912
  customers: Customers
932
913
  cut: Cut
@@ -985,14 +966,6 @@ en:
985
966
  developers: Developers
986
967
  digital:
987
968
  digital_delivery: Digital Delivery
988
- digital_asset_mailer:
989
- files_ready_email:
990
- available_until: Available until %{date}
991
- dear_customer: Dear %{name},
992
- instructions: The files from your order %{number} are ready to download.
993
- store_team: "%{store_name} Team"
994
- subject: Your files are ready
995
- thanks: Thank you for your business.
996
969
  digital_assets: Digital assets
997
970
  digital_assets_attachment_must_be_private: Upload the file to private storage before attaching it
998
971
  discontinue_on: Discontinue On
@@ -1102,6 +1075,7 @@ en:
1102
1075
  store_is_already_set: Store is already set
1103
1076
  unknown_custom_field_type: 'is not a known custom field type (expected one of: %{types})'
1104
1077
  unknown_scopes: 'contains unknown scopes: %{scopes}'
1078
+ unregistered_actor: is not a registered actor class
1105
1079
  variant_product_mismatch: must belong to the same product as the variant
1106
1080
  services:
1107
1081
  get_shipping_rates:
@@ -1144,17 +1118,6 @@ en:
1144
1118
  free_shipping: Free Shipping
1145
1119
  from: From
1146
1120
  front_end: Front End
1147
- fulfillment_mailer:
1148
- fulfilled_email:
1149
- dear_customer: Dear %{name},
1150
- delivery_method: 'Delivery method: %{delivery_method}'
1151
- fulfillment_summary: Fulfillment summary for order
1152
- instructions: Your order %{number} has been fulfilled
1153
- store_team: "%{store_name} Team"
1154
- subject: Fulfillment Notification
1155
- thanks: Thank you for your business.
1156
- track_information: 'Tracking Information: %{tracking}'
1157
- track_link: 'Tracking Link: %{url}'
1158
1121
  fulfillments:
1159
1122
  errors:
1160
1123
  backordered_units: This fulfillment holds backordered units and cannot be handed over yet
@@ -1330,16 +1293,6 @@ en:
1330
1293
  new_state: New State
1331
1294
  new_user: New User
1332
1295
  new_variant: New Variant
1333
- newsletter_mailer:
1334
- email_confirmation:
1335
- dear_customer: Hey,
1336
- ignore_disclaimer: If you didn't request this, please ignore this email.
1337
- instructions: Please click the button below to verify your email address.
1338
- message_copy_link: 'If the button doesn''t work please copy and paste the following link to your browser:'
1339
- store_team: "%{store_name} Team"
1340
- subject: Verify your email address
1341
- thanks: Thank you
1342
- verify_email_address_link: Verify email address
1343
1296
  newsletter_subscribers: Newsletter Subscribers
1344
1297
  next: Next
1345
1298
  no_cc_type: N/A
@@ -1371,34 +1324,6 @@ en:
1371
1324
  order: Order
1372
1325
  order_canceled: Order canceled
1373
1326
  order_cannot_be_deleted: Completed orders and orders with settled payments cannot be deleted
1374
- order_mailer:
1375
- cancel_email:
1376
- dear_customer: Hey %{name},
1377
- instructions: Your order has been CANCELED. Please retain this cancellation information for your records.
1378
- order_summary_canceled: Order %{number} Summary [CANCELED]
1379
- subject: Cancellation of Order
1380
- thanks: Thank you for
1381
- confirm_email:
1382
- dear_customer: Hey %{name},
1383
- instructions: Please review and retain the following order information for your records.
1384
- order_summary: Order %{number} Summary
1385
- subject: Order Confirmation
1386
- thanks: Thank you
1387
- payment_link_email:
1388
- message: Please click the button below to pay for your order.
1389
- message_copy_link: 'If the button doesn''t work please copy and paste the following link to your browser:'
1390
- pay_for_order: Pay for order
1391
- subject: 'Payment link for order #%{number}'
1392
- po_number: 'PO Number: %{number}'
1393
- store_owner_notification_email:
1394
- heading: New Order Received
1395
- instructions: You have received a new order.
1396
- order_summary: Order %{number} Summary
1397
- subject: "%{store_name} received a new order"
1398
- thanks: Thank you
1399
- store_team: "%{store_name} Team"
1400
- subtotal: 'Subtotal:'
1401
- total: 'Order Total:'
1402
1327
  order_not_found: We couldn't find your order. Please try that action again.
1403
1328
  order_number: Order %{number}
1404
1329
  order_resumed: Order resumed
@@ -1536,6 +1461,7 @@ en:
1536
1461
  price_list_import_invalid_amount: "%{column} must be a number like 16.50, got %{value}."
1537
1462
  price_list_import_invalid_quantity: min_quantity must be a whole number of units, got %{value}.
1538
1463
  price_list_import_no_price_list: This import is not attached to a price list.
1464
+ price_list_import_price_rises_with_quantity: The price from %{quantity} units must not be above %{floor}, what a buyer pays below that quantity. A file is applied a row at a time, so list the higher quantities first when lowering a whole ladder.
1539
1465
  price_list_import_sku_required: SKU is required.
1540
1466
  price_list_import_too_many_breaks: A variant can carry at most %{count} quantity breaks on one price list.
1541
1467
  price_list_import_unknown_sku: No product in this store has the SKU %{sku}.
@@ -1570,7 +1496,7 @@ en:
1570
1496
  description: Creates a promotion credit adjustment on a line item
1571
1497
  name: Create per-line-item adjustment
1572
1498
  create_line_items:
1573
- description: Populates the cart with the specified quantity of variant
1499
+ description: Adds the specified quantity of a variant to the cart free of charge
1574
1500
  name: Create line items
1575
1501
  free_shipping:
1576
1502
  description: Makes all shipments for the order free
@@ -2001,16 +1927,6 @@ en:
2001
1927
  return: return
2002
1928
  return_errors:
2003
1929
  outside_window: This order is outside the %{days}-day return window
2004
- return_mailer:
2005
- refunded_email:
2006
- dear_customer: Dear %{name},
2007
- instructions: Your return for order %{number} has been refunded.
2008
- refund_summary: Refund Summary
2009
- returned_items: Returned Items
2010
- store_team: "%{store_name} Team"
2011
- subject: Return Refunded
2012
- thanks: Thank you for your business.
2013
- total_refunded: 'Total refunded: %{total}'
2014
1930
  return_quantity: Return Quantity
2015
1931
  returned: Returned
2016
1932
  returns: Returns
@@ -2051,22 +1967,6 @@ en:
2051
1967
  selected_quantity_not_available: selected of %{item} is not available.
2052
1968
  seller: Seller
2053
1969
  seller_access_denied: You do not have access to this seller.
2054
- seller_mailer:
2055
- approved_email:
2056
- action: Go to your dashboard
2057
- heading: You're approved
2058
- message: Your application to sell on %{store_name} has been approved. You can now list products and start taking orders.
2059
- subject: You're approved to sell on %{store_name}
2060
- get_in_touch: If you think this is a mistake, reply to this email or contact us at %{store_email}.
2061
- greeting: Hi %{seller_name},
2062
- rejected_email:
2063
- heading: About your application
2064
- message: Your application to sell on %{store_name} has not been accepted.
2065
- subject: Your application to sell on %{store_name}
2066
- suspended_email:
2067
- heading: Your account has been suspended
2068
- message: Selling on %{store_name} has been paused for your account. Your products and order history are unaffected.
2069
- subject: Your %{store_name} account has been suspended
2070
1970
  seller_membership_required: This account does not belong to any seller.
2071
1971
  seller_payout_nothing_to_settle: This seller has nothing to settle right now.
2072
1972
  seller_requirement_types:
@@ -2131,17 +2031,6 @@ en:
2131
2031
  ship_total: Ship Total
2132
2032
  shipment: Shipment
2133
2033
  shipment_adjustments: Shipment adjustments
2134
- shipment_mailer:
2135
- shipped_email:
2136
- dear_customer: Dear %{name},
2137
- instructions: Your order %{number} has been shipped
2138
- shipment_summary: Shipment Summary for order
2139
- shipping_method: 'Shipping method: %{shipping_method}'
2140
- store_team: "%{store_name} Team"
2141
- subject: Shipment Notification
2142
- thanks: Thank you for your business.
2143
- track_information: 'Tracking Information: %{tracking}'
2144
- track_link: 'Tracking Link: %{url}'
2145
2034
  shipment_state: Shipment State
2146
2035
  shipments: Shipments
2147
2036
  shipped: Shipped
@@ -0,0 +1,14 @@
1
+ class AddEmailDeliveryFlagsToSpreeOrderGroups < ActiveRecord::Migration[8.1]
2
+ def change
3
+ # The same pair spree_orders carries, for the same reason: a confirmation
4
+ # is sent once, and completion is replayable — a resumed finalize
5
+ # re-publishes order_group.completed, so without a record of what was sent
6
+ # a customer gets the same email twice. These say what happened, not what
7
+ # the purchase is, so unlike the group's statuses they cannot be derived
8
+ # from the children.
9
+ add_column :spree_order_groups, :confirmation_delivered, :boolean, default: false
10
+ add_column :spree_order_groups, :store_owner_notification_delivered, :boolean, default: false
11
+
12
+ add_index :spree_order_groups, :confirmation_delivered
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ # Makes the order-operation "who did this" associations polymorphic, so a
2
+ # write made with a secret API key records the key rather than nobody.
3
+ # See docs/plans/6.0-action-actors.md.
4
+ class OrderOperationActorsPolymorphic < ActiveRecord::Migration[8.1]
5
+ ACTORS = {
6
+ spree_orders: %i[created_by approver canceler],
7
+ spree_refunds: %i[refunder],
8
+ spree_returns: %i[created_by],
9
+ spree_exchanges: %i[created_by],
10
+ spree_claims: %i[created_by],
11
+ spree_stock_receipts: %i[received_by]
12
+ }.freeze
13
+
14
+ def change
15
+ ACTORS.each do |table, names|
16
+ names.each do |name|
17
+ # Nullable with no default: the type is data, filled by
18
+ # `rake spree:upgrade:backfill_actor_types`. Until it runs, the
19
+ # transitional reader resolves these rows through the admin user
20
+ # class — the only thing they could ever have pointed at.
21
+ add_column table, :"#{name}_type", :string
22
+
23
+ # Named for the pair so it reads apart from the `_id` index that
24
+ # already exists on most of these columns.
25
+ add_index table, [:"#{name}_type", :"#{name}_id"],
26
+ name: "index_#{table}_on_#{name}_actor"
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,5 @@
1
+ class AddRefundedOrderToSpreeStoreCredits < ActiveRecord::Migration[8.1]
2
+ def change
3
+ add_reference :spree_store_credits, :refunded_order, index: true
4
+ end
5
+ end
@@ -0,0 +1,10 @@
1
+ class ChangeSpreeUserIdentitiesTokensToText < ActiveRecord::Migration[8.1]
2
+ def up
3
+ change_column :spree_user_identities, :access_token, :text
4
+ change_column :spree_user_identities, :refresh_token, :text
5
+ end
6
+
7
+ def down
8
+ raise ActiveRecord::IrreversibleMigration, 'Encrypted tokens may not fit back into string columns'
9
+ end
10
+ end
@@ -1,7 +1,7 @@
1
1
  # Adds two extra channels alongside the seeded 'Online Store' so sample data
2
2
  # exercises the channel-aware code paths (publishing, channel filters,
3
3
  # channel-scoped order attribution).
4
- store = Spree::Store.default
4
+ store = Spree::Current.store
5
5
 
6
6
  store.channels.find_or_create_by!(code: 'pos') do |channel|
7
7
  channel.name = 'Point of Sale'
@@ -1,7 +1,7 @@
1
1
  # Three collections that between them exercise both membership models: two
2
2
  # rule-based (they regenerate themselves) and one hand-curated with a dynamic
3
3
  # sort. Runs after the product import so there is a catalog to draw from.
4
- store = Spree::Store.default
4
+ store = Spree::Current.store
5
5
 
6
6
  # Each automatic collection is defined by the single rule that materializes it.
7
7
  automatic_collections = [
@@ -1,4 +1,4 @@
1
- store = Spree::Store.default
1
+ store = Spree::Current.store
2
2
 
3
3
  %w[warranty capacity voltage wattage runtime room_coverage noise_level connectivity].each do |key|
4
4
  store.custom_field_definitions.find_or_create_by!(
@@ -3,7 +3,7 @@
3
3
  # type stamps it at creation. The one thing a CSV row cannot carry is the file
4
4
  # buyers download, so that is all this step does: attach a PDF to the imported
5
5
  # product's default variant.
6
- store = Spree::Store.default
6
+ store = Spree::Current.store
7
7
 
8
8
  product = Spree::Product.find_by(store: store, slug: 'the-spree-commerce-handbook')
9
9
 
@@ -2,7 +2,7 @@
2
2
  # Shopify-style delivery methods on the Domestic and International zones.
3
3
  # The free international method showcases delivery-method rules — free
4
4
  # above a spend threshold, hidden below it.
5
- store = Spree::Store.default
5
+ store = Spree::Current.store
6
6
 
7
7
  # The zones are created from the store's country at first-run setup, so an
8
8
  # install that has not been set up yet has none. Provision them here from
@@ -1,4 +1,6 @@
1
- color = Spree::OptionType.find_or_initialize_by(name: 'color')
1
+ store = Spree::Current.store
2
+
3
+ color = Spree::OptionType.for_store(store).find_or_initialize_by(name: 'color')
2
4
  color.label = 'Color'
3
5
  color.kind = 'color_swatch'
4
6
  color.save!
@@ -15,7 +17,7 @@ color.save!
15
17
  # sells only new goods should not find this on a fresh install. A marketplace
16
18
  # that wants its sellers to describe condition the same way loads it, or
17
19
  # creates its own.
18
- condition = Spree::OptionType.find_or_initialize_by(name: 'condition')
20
+ condition = Spree::OptionType.for_store(store).find_or_initialize_by(name: 'condition')
19
21
  condition.label = 'Condition'
20
22
  condition.kind = 'buttons'
21
23
  condition.filterable = true
@@ -1,8 +1,8 @@
1
- store = Spree::Store.default
1
+ store = Spree::Current.store
2
2
 
3
3
  # Find products created by the product import
4
- product_1 = Spree::Product.find_by(name: 'Automatic Espresso Machine')
5
- product_2 = Spree::Product.find_by(name: 'Drip Coffee Maker 1.5L')
4
+ product_1 = store.products.find_by(name: 'Automatic Espresso Machine')
5
+ product_2 = store.products.find_by(name: 'Drip Coffee Maker 1.5L')
6
6
 
7
7
  unless product_1 && product_2
8
8
  puts ' Skipping orders: required products not found'
@@ -84,7 +84,7 @@ orders.each(&:rebuild_fulfillments!)
84
84
  Spree::Order.where(id: orders.map(&:id)).update_all(status: 'placed', completed_at: Time.current - 1.day)
85
85
 
86
86
  # Tax lines (zero-amount sample rows against the California rate)
87
- tax_rate = Spree::TaxRate.find_by(name: 'California')
87
+ tax_rate = store.tax_rates.find_by(name: 'California')
88
88
 
89
89
  if tax_rate
90
90
  orders.each do |order|
@@ -105,7 +105,7 @@ if tax_rate
105
105
  end
106
106
 
107
107
  # Payments
108
- method = Spree::PaymentMethod.where(name: 'Credit Card', active: true).first
108
+ method = store.payment_methods.where(name: 'Credit Card', active: true).first
109
109
 
110
110
  if method
111
111
  Spree::Gateway.class_eval do
@@ -114,8 +114,7 @@ if method
114
114
  end
115
115
  end
116
116
 
117
- credit_card = Spree::CreditCard.find_or_initialize_by(gateway_customer_profile_id: 'BGS-1234')
118
- credit_card.payment_method = method
117
+ credit_card = Spree::CreditCard.find_or_initialize_by(gateway_customer_profile_id: 'BGS-1234', payment_method: method)
119
118
  credit_card.cc_type = 'visa'
120
119
  credit_card.month = 12
121
120
  credit_card.year = 2.years.from_now.year
@@ -140,15 +139,15 @@ orders.each { |order| order.reload.update_statuses! }
140
139
 
141
140
  # A return in progress, so the admin has something to look at. Built through
142
141
  # the workflows rather than by direct writes — they own every transition.
143
- first_complete_order = Spree::Order.complete.first
142
+ first_complete_order = store.orders.complete.first
144
143
  if first_complete_order && first_complete_order.fulfillment_items.any?
145
144
  fulfillment_item = first_complete_order.fulfillment_items.first
146
145
 
147
146
  Spree::Returns::Create.call(
148
147
  order: first_complete_order,
149
148
  items: [{ fulfillment_item: fulfillment_item, quantity: 1 }],
150
- stock_location: fulfillment_item.fulfillment&.stock_location || Spree::StockLocation.first,
151
- reason: Spree::ReturnReason.first,
149
+ stock_location: fulfillment_item.fulfillment&.stock_location || store.stock_locations.first,
150
+ reason: store.return_reasons.first,
152
151
  memo: 'Sample return'
153
152
  )
154
153
  end
@@ -1,19 +1,19 @@
1
- Spree::Store.all.find_each do |store|
2
- cc_payment_method = store.payment_methods.find_or_initialize_by(
3
- type: 'Spree::Gateway::Bogus',
4
- name: 'Credit Card',
5
- description: 'Bogus payment gateway.',
6
- active: true
7
- )
8
- cc_payment_method.storefront_visible = false
9
- cc_payment_method.save!
1
+ store = Spree::Current.store
10
2
 
11
- check_payment_method = store.payment_methods.find_or_initialize_by(
12
- type: 'Spree::PaymentMethod::Check',
13
- name: 'Check',
14
- description: 'Pay by check.',
15
- active: true
16
- )
17
- check_payment_method.storefront_visible = false
18
- check_payment_method.save!
19
- end
3
+ cc_payment_method = store.payment_methods.find_or_initialize_by(
4
+ type: 'Spree::Gateway::Bogus',
5
+ name: 'Credit Card',
6
+ description: 'Bogus payment gateway.',
7
+ active: true
8
+ )
9
+ cc_payment_method.storefront_visible = false
10
+ cc_payment_method.save!
11
+
12
+ check_payment_method = store.payment_methods.find_or_initialize_by(
13
+ type: 'Spree::PaymentMethod::Check',
14
+ name: 'Check',
15
+ description: 'Pay by check.',
16
+ active: true
17
+ )
18
+ check_payment_method.storefront_visible = false
19
+ check_payment_method.save!
@@ -5,7 +5,7 @@
5
5
  # categories — before it there is nothing to link to. Seeding is additive and
6
6
  # only applies to products created from here on, so linking after the fact
7
7
  # changes nothing about the imported catalog.
8
- store = Spree::Store.default
8
+ store = Spree::Current.store
9
9
 
10
10
  categories_by_type = {
11
11
  'Kitchen Appliance' => 'Kitchen',
@@ -10,9 +10,9 @@
10
10
  #
11
11
  # Categories are attached afterwards by product_type_categories.rb — the import
12
12
  # is what creates them, so there is nothing to link to at this point.
13
- store = Spree::Store.default
13
+ store = Spree::Current.store
14
14
 
15
- color_option_type = Spree::OptionType.find_by(name: 'color')
15
+ color_option_type = Spree::OptionType.for_store(store).find_by(name: 'color')
16
16
 
17
17
  definitions = store.custom_field_definitions.where(
18
18
  namespace: 'custom',
@@ -1,8 +1,6 @@
1
- promotion = Spree::Promotion.where(
1
+ promotion = Spree::Current.store.promotions.where(
2
2
  name: 'Free Shipping',
3
3
  code: 'FREESHIP'
4
- ).first_or_create! do |promo|
5
- promo.store = Spree::Store.default
6
- end
4
+ ).first_or_create!
7
5
 
8
6
  Spree::Promotion::Actions::FreeShipping.where(promotion: promotion).first_or_create!
@@ -2,7 +2,7 @@
2
2
  # Spree::Seeds::Channels: an approved demo buyer and a customer-group price
3
3
  # list, so a fresh install can walk the whole B2B portal story — sign in as
4
4
  # the buyer, see wholesale prices, check out on the wholesale channel.
5
- store = Spree::Store.default
5
+ store = Spree::Current.store
6
6
 
7
7
  wholesale_group = store.customer_groups.find_or_create_by!(name: Spree::Seeds::CustomerGroups::WHOLESALE_NAME)
8
8