spree_core 6.0.0.beta4 → 6.0.0.rc1

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 (495) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/app/helpers/spree/images_helper.rb +0 -57
  4. data/app/jobs/spree/base_job.rb +21 -0
  5. data/app/jobs/spree/carts/reap_expired_job.rb +2 -2
  6. data/app/jobs/spree/collections/regenerate_time_based_job.rb +6 -3
  7. data/app/jobs/spree/orders/finalize_stale_drafts_job.rb +8 -5
  8. data/app/jobs/spree/payments/cancel_unused_sessions_job.rb +61 -0
  9. data/app/jobs/spree/seller_payouts/sweep_seller_job.rb +2 -0
  10. data/app/mailers/spree/admin_user_mailer.rb +4 -19
  11. data/app/mailers/spree/base_mailer.rb +96 -13
  12. data/app/mailers/spree/email_template_mailer.rb +27 -0
  13. data/app/mailers/spree/export_mailer.rb +3 -4
  14. data/app/mailers/spree/import_mailer.rb +3 -4
  15. data/app/mailers/spree/invitation_mailer.rb +24 -7
  16. data/app/mailers/spree/seller_user_mailer.rb +4 -16
  17. data/app/mailers/spree/webhook_mailer.rb +2 -2
  18. data/app/models/concerns/spree/acted_by.rb +1 -1
  19. data/app/models/concerns/spree/admin_user_methods.rb +13 -1
  20. data/app/models/concerns/spree/api_typed.rb +91 -0
  21. data/app/models/concerns/spree/calculator/tiers.rb +76 -0
  22. data/app/models/concerns/spree/customer_methods.rb +15 -14
  23. data/app/models/concerns/spree/email_template_identity.rb +52 -0
  24. data/app/models/concerns/spree/parameterizable_name.rb +2 -0
  25. data/app/models/concerns/spree/payment_session_transitions.rb +8 -2
  26. data/app/models/concerns/spree/post_sale/taxation.rb +54 -0
  27. data/app/models/concerns/spree/post_sale/taxed_line.rb +51 -0
  28. data/app/models/concerns/spree/preference_schema.rb +4 -12
  29. data/app/models/concerns/spree/product_scopes.rb +11 -1
  30. data/app/models/concerns/spree/provider_listing.rb +41 -0
  31. data/app/models/concerns/spree/publishable.rb +82 -14
  32. data/app/models/concerns/spree/purchase/addresses.rb +23 -10
  33. data/app/models/concerns/spree/purchase/currency.rb +1 -1
  34. data/app/models/concerns/spree/purchase/deprecated_aliases.rb +87 -0
  35. data/app/models/concerns/spree/purchase/gift_cards.rb +10 -4
  36. data/app/models/concerns/spree/purchase/locale.rb +1 -1
  37. data/app/models/concerns/spree/purchase/payment_processing.rb +7 -3
  38. data/app/models/concerns/spree/purchase/purchase_order.rb +2 -2
  39. data/app/models/concerns/spree/purchase/totals.rb +49 -1
  40. data/app/models/concerns/spree/receivable.rb +1 -1
  41. data/app/models/concerns/spree/searchable.rb +0 -4
  42. data/app/models/concerns/spree/secret_preferences.rb +59 -0
  43. data/app/models/concerns/spree/single_store_resource.rb +1 -1
  44. data/app/models/concerns/spree/stores/email_branding.rb +31 -0
  45. data/app/models/concerns/spree/type_labels.rb +38 -0
  46. data/app/models/concerns/spree/typed_adjustment_line.rb +1 -1
  47. data/app/models/concerns/spree/typed_associations.rb +6 -0
  48. data/app/models/spree/address.rb +11 -1
  49. data/app/models/spree/adjusters/promotion.rb +1 -15
  50. data/app/models/spree/allowed_origin.rb +0 -1
  51. data/app/models/spree/api_key.rb +5 -6
  52. data/app/models/spree/authentication/strategies/oidc_strategy.rb +5 -5
  53. data/app/models/spree/base.rb +70 -22
  54. data/app/models/spree/calculator/flat_percent_item_total.rb +1 -3
  55. data/app/models/spree/calculator/flat_rate.rb +1 -3
  56. data/app/models/spree/calculator/flexi_rate.rb +1 -3
  57. data/app/models/spree/calculator/percent_on_line_item.rb +1 -1
  58. data/app/models/spree/calculator/price_sack.rb +1 -3
  59. data/app/models/spree/calculator/shipping/digital_delivery.rb +1 -3
  60. data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +1 -3
  61. data/app/models/spree/calculator/shipping/flat_rate.rb +1 -3
  62. data/app/models/spree/calculator/shipping/flexi_rate.rb +1 -3
  63. data/app/models/spree/calculator/shipping/per_item.rb +1 -3
  64. data/app/models/spree/calculator/shipping/price_sack.rb +1 -3
  65. data/app/models/spree/calculator/tiered_flat_rate.rb +6 -23
  66. data/app/models/spree/calculator/tiered_percent.rb +7 -25
  67. data/app/models/spree/cart.rb +78 -18
  68. data/app/models/spree/channel/gating.rb +1 -1
  69. data/app/models/spree/channel.rb +4 -4
  70. data/app/models/spree/claim.rb +21 -1
  71. data/app/models/spree/claim_line_item.rb +41 -6
  72. data/app/models/spree/collection.rb +0 -1
  73. data/app/models/spree/collection_rule.rb +5 -21
  74. data/app/models/spree/commission_line.rb +1 -1
  75. data/app/models/spree/commission_rate.rb +2 -3
  76. data/app/models/spree/commission_rate_value.rb +1 -1
  77. data/app/models/spree/commission_rule.rb +4 -11
  78. data/app/models/spree/commission_rules/product_rule.rb +1 -1
  79. data/app/models/spree/company_invitation.rb +1 -0
  80. data/app/models/spree/consent_record.rb +0 -1
  81. data/app/models/spree/credit_card.rb +1 -1
  82. data/app/models/spree/current.rb +23 -0
  83. data/app/models/spree/custom_field.rb +2 -2
  84. data/app/models/spree/custom_field_definition.rb +9 -23
  85. data/app/models/spree/custom_fields/boolean.rb +1 -1
  86. data/app/models/spree/custom_fields/json.rb +1 -1
  87. data/app/models/spree/data_feed/google.rb +0 -2
  88. data/app/models/spree/data_request.rb +1 -1
  89. data/app/models/spree/delivery_method.rb +30 -13
  90. data/app/models/spree/delivery_method_rule.rb +4 -11
  91. data/app/models/spree/delivery_rate.rb +4 -5
  92. data/app/models/spree/delivery_rate_provider/base.rb +1 -0
  93. data/app/models/spree/delivery_zone.rb +0 -1
  94. data/app/models/spree/delivery_zone_member.rb +4 -4
  95. data/app/models/spree/digital_asset.rb +7 -0
  96. data/app/models/spree/digital_asset_provider/base.rb +2 -0
  97. data/app/models/spree/digital_link.rb +2 -5
  98. data/app/models/spree/discount.rb +1 -1
  99. data/app/models/spree/email_template.rb +25 -0
  100. data/app/models/spree/email_template_draft.rb +13 -0
  101. data/app/models/spree/email_template_revision.rb +17 -0
  102. data/app/models/spree/email_templates/entry.rb +118 -0
  103. data/app/models/spree/email_templates/sample_record.rb +16 -0
  104. data/app/models/spree/emails/branding.rb +80 -0
  105. data/app/models/spree/exchange.rb +15 -1
  106. data/app/models/spree/exchange_line_item.rb +121 -5
  107. data/app/models/spree/export.rb +0 -1
  108. data/app/models/spree/exports/products.rb +10 -1
  109. data/app/models/spree/exports/report.rb +1 -1
  110. data/app/models/spree/fee.rb +4 -2
  111. data/app/models/spree/fulfillment.rb +53 -27
  112. data/app/models/spree/fulfillment_changer.rb +2 -2
  113. data/app/models/spree/fulfillment_item.rb +0 -4
  114. data/app/models/spree/fulfillment_provider/base.rb +1 -0
  115. data/app/models/spree/gateway/bogus.rb +4 -0
  116. data/app/models/spree/gateway/custom_payment_source_method.rb +5 -0
  117. data/app/models/spree/gateway.rb +5 -1
  118. data/app/models/spree/gift_card.rb +12 -1
  119. data/app/models/spree/gift_card_batch.rb +0 -1
  120. data/app/models/spree/import.rb +2 -7
  121. data/app/models/spree/import_mapping.rb +1 -2
  122. data/app/models/spree/import_row.rb +2 -2
  123. data/app/models/spree/import_schemas/products.rb +1 -0
  124. data/app/models/spree/integration.rb +8 -18
  125. data/app/models/spree/invitation.rb +5 -5
  126. data/app/models/spree/line_item.rb +13 -2
  127. data/app/models/spree/locale.rb +11 -8
  128. data/app/models/spree/market.rb +1 -0
  129. data/app/models/spree/newsletter_subscriber.rb +3 -0
  130. data/app/models/spree/order.rb +56 -138
  131. data/app/models/spree/order_group.rb +11 -2
  132. data/app/models/spree/order_inventory.rb +10 -5
  133. data/app/models/spree/order_promotion.rb +1 -1
  134. data/app/models/spree/order_routing/has_strategy_preference.rb +1 -1
  135. data/app/models/spree/order_routing/strategy/base.rb +4 -2
  136. data/app/models/spree/order_routing/strategy/rules.rb +1 -1
  137. data/app/models/spree/order_routing_rule.rb +6 -22
  138. data/app/models/spree/package_type.rb +1 -2
  139. data/app/models/spree/payment/gateway_options.rb +14 -52
  140. data/app/models/spree/payment/processing.rb +2 -4
  141. data/app/models/spree/payment.rb +20 -5
  142. data/app/models/spree/payment_method/session_instrumentation.rb +1 -0
  143. data/app/models/spree/payment_method/store_credit.rb +4 -4
  144. data/app/models/spree/payment_method.rb +36 -4
  145. data/app/models/spree/payment_session.rb +5 -1
  146. data/app/models/spree/payment_setup_session.rb +1 -0
  147. data/app/models/spree/payout_provider/base.rb +3 -1
  148. data/app/models/spree/pickup_point_provider/base.rb +2 -0
  149. data/app/models/spree/price_list.rb +1 -2
  150. data/app/models/spree/price_rules/channel_rule.rb +1 -1
  151. data/app/models/spree/price_rules/customer_group_rule.rb +1 -1
  152. data/app/models/spree/product.rb +31 -7
  153. data/app/models/spree/product_submission.rb +0 -12
  154. data/app/models/spree/product_type.rb +0 -1
  155. data/app/models/spree/promotion/actions/create_line_items.rb +27 -17
  156. data/app/models/spree/promotion/rules/category.rb +0 -4
  157. data/app/models/spree/promotion/rules/channel.rb +0 -4
  158. data/app/models/spree/promotion/rules/country.rb +0 -4
  159. data/app/models/spree/promotion/rules/currency.rb +0 -4
  160. data/app/models/spree/promotion/rules/customer_group.rb +0 -4
  161. data/app/models/spree/promotion/rules/first_order.rb +0 -4
  162. data/app/models/spree/promotion/rules/item_total.rb +4 -8
  163. data/app/models/spree/promotion/rules/market.rb +0 -4
  164. data/app/models/spree/promotion/rules/one_use_per_user.rb +0 -4
  165. data/app/models/spree/promotion/rules/option_value.rb +0 -3
  166. data/app/models/spree/promotion/rules/product.rb +0 -4
  167. data/app/models/spree/promotion/rules/user.rb +0 -4
  168. data/app/models/spree/promotion/rules/user_logged_in.rb +0 -4
  169. data/app/models/spree/promotion.rb +35 -6
  170. data/app/models/spree/promotion_action.rb +7 -14
  171. data/app/models/spree/promotion_action_line_item.rb +1 -1
  172. data/app/models/spree/promotion_handler/coupon.rb +59 -27
  173. data/app/models/spree/promotion_rule.rb +7 -14
  174. data/app/models/spree/purchase_order.rb +1 -0
  175. data/app/models/spree/quantity_rule.rb +1 -1
  176. data/app/models/spree/refund.rb +28 -3
  177. data/app/models/spree/return.rb +30 -2
  178. data/app/models/spree/return_line_item.rb +65 -14
  179. data/app/models/spree/role.rb +7 -7
  180. data/app/models/spree/saved_report.rb +1 -1
  181. data/app/models/spree/seller.rb +2 -1
  182. data/app/models/spree/seller_payout.rb +7 -0
  183. data/app/models/spree/seller_requirement.rb +4 -12
  184. data/app/models/spree/seller_requirement_custom_field.rb +1 -2
  185. data/app/models/spree/seller_requirement_submission.rb +2 -2
  186. data/app/models/spree/seller_requirements/accept_terms.rb +2 -3
  187. data/app/models/spree/seller_transfer.rb +5 -0
  188. data/app/models/spree/shipping_label.rb +1 -0
  189. data/app/models/spree/stock/availability_validator.rb +2 -2
  190. data/app/models/spree/stock/inventory_unit_builder.rb +1 -1
  191. data/app/models/spree/stock/packer.rb +2 -2
  192. data/app/models/spree/stock/splitter/weight.rb +1 -1
  193. data/app/models/spree/stock_level/custom_events.rb +6 -0
  194. data/app/models/spree/stock_level.rb +1 -1
  195. data/app/models/spree/stock_movement.rb +1 -1
  196. data/app/models/spree/stock_receipt_item.rb +1 -1
  197. data/app/models/spree/stock_reservation.rb +2 -2
  198. data/app/models/spree/stock_transfer.rb +4 -2
  199. data/app/models/spree/store.rb +33 -7
  200. data/app/models/spree/store_credit.rb +8 -9
  201. data/app/models/spree/store_credit_event.rb +5 -5
  202. data/app/models/spree/tax_exemption_certificate.rb +2 -0
  203. data/app/models/spree/tax_identifier.rb +3 -1
  204. data/app/models/spree/tax_line.rb +53 -3
  205. data/app/models/spree/tax_provider/base.rb +71 -14
  206. data/app/models/spree/tax_provider/internal.rb +59 -33
  207. data/app/models/spree/tax_provider/recorded_share.rb +114 -0
  208. data/app/models/spree/tax_rate.rb +1 -2
  209. data/app/models/spree/taxonomy.rb +0 -1
  210. data/app/models/spree/variant.rb +4 -3
  211. data/app/models/spree/variant_media.rb +1 -1
  212. data/app/models/spree/webhook_endpoint.rb +10 -13
  213. data/app/models/spree/wishlist.rb +1 -6
  214. data/app/models/spree/wishlist_item/custom_events.rb +6 -0
  215. data/app/presenters/spree/csv/customer_presenter.rb +1 -1
  216. data/app/presenters/spree/csv/newsletter_subscriber_presenter.rb +1 -1
  217. data/app/presenters/spree/csv/order_line_item_presenter.rb +1 -1
  218. data/app/presenters/spree/csv/product_variant_presenter.rb +42 -12
  219. data/app/serializers/spree/emails/base_serializer.rb +14 -0
  220. data/app/serializers/spree/emails/export_serializer.rb +13 -0
  221. data/app/serializers/spree/emails/import_serializer.rb +19 -0
  222. data/app/serializers/spree/emails/invitation_serializer.rb +28 -0
  223. data/app/serializers/spree/emails/store_serializer.rb +31 -0
  224. data/app/serializers/spree/emails/user_serializer.rb +12 -0
  225. data/app/serializers/spree/emails/webhook_endpoint_serializer.rb +16 -0
  226. data/app/services/spree/carts/create.rb +8 -2
  227. data/app/services/spree/carts/destroy.rb +2 -2
  228. data/app/services/spree/carts/remove_out_of_stock_items.rb +2 -2
  229. data/app/services/spree/carts/split_by_seller.rb +1 -1
  230. data/app/services/spree/carts/update.rb +19 -5
  231. data/app/services/spree/catalogs/set_product_terms.rb +1 -1
  232. data/app/services/spree/categories/add_products.rb +13 -31
  233. data/app/services/spree/categories/remove_products.rb +12 -51
  234. data/app/services/spree/checkout/advance.rb +1 -4
  235. data/app/services/spree/collections/add_products.rb +10 -23
  236. data/app/services/spree/collections/remove_products.rb +7 -43
  237. data/app/services/spree/coupon_codes/bulk_generate.rb +8 -14
  238. data/app/services/spree/data_requests/create.rb +1 -1
  239. data/app/services/spree/deliveries/destroy.rb +2 -2
  240. data/app/services/spree/email_templates/check.rb +58 -0
  241. data/app/services/spree/email_templates/no_sample_record.rb +7 -0
  242. data/app/services/spree/email_templates/preview.rb +99 -0
  243. data/app/services/spree/emails/file_system.rb +23 -0
  244. data/app/services/spree/emails/filters.rb +84 -0
  245. data/app/services/spree/emails/liquid_context.rb +48 -0
  246. data/app/services/spree/emails/rendered_email.rb +14 -0
  247. data/app/services/spree/emails/renderer.rb +125 -0
  248. data/app/services/spree/emails/template.rb +51 -0
  249. data/app/services/spree/emails/template_data.rb +23 -0
  250. data/app/services/spree/emails/template_resolver.rb +109 -0
  251. data/app/services/spree/emails/text_converter.rb +72 -0
  252. data/app/services/spree/emails/translation_inliner.rb +134 -0
  253. data/app/services/spree/imports/row_processors/price_list_price.rb +10 -10
  254. data/app/services/spree/imports/row_processors/product_variant.rb +65 -34
  255. data/app/services/spree/imports/row_processors/purchase_order.rb +13 -13
  256. data/app/services/spree/locales.rb +4 -5
  257. data/app/services/spree/newsletter/subscribe.rb +8 -12
  258. data/app/services/spree/orders/build_fulfillments.rb +3 -2
  259. data/app/services/spree/orders/create.rb +2 -1
  260. data/app/services/spree/orders/discounts/create.rb +7 -4
  261. data/app/services/spree/orders/discounts/destroy.rb +1 -0
  262. data/app/services/spree/orders/discounts/update.rb +1 -0
  263. data/app/services/spree/orders/fees/create.rb +1 -0
  264. data/app/services/spree/orders/fees/destroy.rb +1 -0
  265. data/app/services/spree/orders/fees/update.rb +1 -0
  266. data/app/services/spree/orders/remove_line_item.rb +13 -3
  267. data/app/services/spree/orders/update.rb +10 -6
  268. data/app/services/spree/orders/update_item.rb +6 -3
  269. data/app/services/spree/orders/update_statuses.rb +3 -1
  270. data/app/services/spree/product_memberships.rb +61 -0
  271. data/app/services/spree/returns/eligibility_validator.rb +1 -1
  272. data/app/services/spree/search_provider/custom_field_schema.rb +2 -2
  273. data/app/services/spree/seeds/commission_rates.rb +1 -1
  274. data/app/services/spree/seeds/digital_delivery.rb +1 -1
  275. data/app/services/spree/seeds/payment_methods.rb +2 -2
  276. data/app/services/spree/seeds/saved_reports.rb +3 -3
  277. data/app/services/spree/sellers/requirements.rb +1 -2
  278. data/app/services/spree/shipping_labels/confirm_refund.rb +1 -1
  279. data/app/services/spree/shipping_labels/store_file.rb +3 -3
  280. data/app/services/spree/stock_levels/correct.rb +3 -3
  281. data/app/services/spree/stock_reservations/reserve.rb +2 -3
  282. data/app/services/spree/store_credits/apply.rb +15 -13
  283. data/app/services/spree/stores/provision_defaults.rb +15 -14
  284. data/app/subscribers/spree/seller_onboarding_subscriber.rb +1 -1
  285. data/app/views/layouts/spree/base_mailer.html.erb +2 -43
  286. data/app/views/layouts/spree/base_mailer.liquid +79 -0
  287. data/app/views/spree/admin_user_mailer/password_reset_email.liquid +14 -0
  288. data/app/views/spree/export_mailer/export_done.liquid +12 -0
  289. data/app/views/spree/import_mailer/import_done.liquid +15 -0
  290. data/app/views/spree/invitation_mailer/invitation_accepted.liquid +9 -0
  291. data/app/views/spree/invitation_mailer/invitation_email.liquid +13 -0
  292. data/app/views/spree/seller_user_mailer/password_reset_email.liquid +14 -0
  293. data/app/views/spree/shared/_mailer_button.html.erb +4 -5
  294. data/app/views/spree/shared/_mailer_hero.html.erb +6 -5
  295. data/app/views/spree/shared/_summary_row.liquid +8 -0
  296. data/app/views/spree/webhook_mailer/endpoint_disabled.liquid +21 -0
  297. data/app/workflows/spree/carts/add_item.rb +4 -4
  298. data/app/workflows/spree/carts/complete.rb +13 -3
  299. data/app/workflows/spree/carts/merge.rb +1 -1
  300. data/app/workflows/spree/carts/recalculate_totals.rb +5 -0
  301. data/app/workflows/spree/carts/upsert_items.rb +18 -9
  302. data/app/workflows/spree/claims/approve.rb +5 -22
  303. data/app/workflows/spree/claims/cancel.rb +5 -21
  304. data/app/workflows/spree/claims/create.rb +15 -0
  305. data/app/workflows/spree/claims/deny.rb +7 -0
  306. data/app/workflows/spree/claims/resolve.rb +34 -31
  307. data/app/workflows/spree/customers/anonymize.rb +3 -4
  308. data/app/workflows/spree/customers/create.rb +1 -1
  309. data/app/workflows/spree/data_requests/fulfill.rb +2 -2
  310. data/app/workflows/spree/deliveries/update_tracking.rb +1 -1
  311. data/app/workflows/spree/email_templates/discard_draft.rb +20 -0
  312. data/app/workflows/spree/email_templates/publish.rb +70 -0
  313. data/app/workflows/spree/email_templates/restore_revision.rb +33 -0
  314. data/app/workflows/spree/email_templates/revert.rb +29 -0
  315. data/app/workflows/spree/email_templates/save_draft.rb +85 -0
  316. data/app/workflows/spree/exchanges/approve.rb +5 -22
  317. data/app/workflows/spree/exchanges/cancel.rb +5 -21
  318. data/app/workflows/spree/exchanges/create.rb +6 -0
  319. data/app/workflows/spree/exchanges/fulfill.rb +75 -51
  320. data/app/workflows/spree/exchanges/receive.rb +6 -65
  321. data/app/workflows/spree/fulfillments/cancel.rb +1 -1
  322. data/app/workflows/spree/fulfillments/create.rb +51 -47
  323. data/app/workflows/spree/fulfillments/fulfill.rb +23 -27
  324. data/app/workflows/spree/fulfillments/mark_delivered.rb +1 -1
  325. data/app/workflows/spree/fulfillments/replacements.rb +59 -0
  326. data/app/workflows/spree/gift_cards/apply.rb +2 -2
  327. data/app/workflows/spree/orders/add_item.rb +5 -1
  328. data/app/workflows/spree/orders/cancel.rb +3 -3
  329. data/app/workflows/spree/orders/complete.rb +16 -8
  330. data/app/workflows/spree/payments/process.rb +2 -2
  331. data/app/workflows/spree/post_sale/approval.rb +35 -0
  332. data/app/workflows/spree/post_sale/cancellation.rb +44 -0
  333. data/app/workflows/spree/post_sale/receipt.rb +92 -0
  334. data/app/workflows/spree/products/nested_attributes.rb +1 -1
  335. data/app/workflows/spree/purchase_orders/cancel.rb +1 -1
  336. data/app/workflows/spree/purchase_orders/close.rb +3 -31
  337. data/app/workflows/spree/purchase_orders/mark_draft.rb +2 -2
  338. data/app/workflows/spree/purchase_orders/mark_ordered.rb +2 -2
  339. data/app/workflows/spree/purchase_orders/receive.rb +1 -1
  340. data/app/workflows/spree/purchase_orders/update.rb +5 -34
  341. data/app/workflows/spree/receivables/closing_short.rb +46 -0
  342. data/app/workflows/spree/receivables/draft_editing.rb +48 -0
  343. data/app/workflows/spree/refunds/create.rb +5 -2
  344. data/app/workflows/spree/refunds/order_payments.rb +14 -2
  345. data/app/workflows/spree/refunds/tax_credit.rb +67 -0
  346. data/app/workflows/spree/returns/approve.rb +5 -22
  347. data/app/workflows/spree/returns/cancel.rb +5 -22
  348. data/app/workflows/spree/returns/create.rb +8 -0
  349. data/app/workflows/spree/returns/receive.rb +5 -76
  350. data/app/workflows/spree/returns/refund.rb +31 -8
  351. data/app/workflows/spree/seller_requirement_submissions/create.rb +1 -2
  352. data/app/workflows/spree/seller_transfers/reverse.rb +28 -1
  353. data/app/workflows/spree/shipping_labels/purchase.rb +8 -8
  354. data/app/workflows/spree/shipping_labels/record.rb +5 -5
  355. data/app/workflows/spree/shipping_labels/refund.rb +2 -2
  356. data/app/workflows/spree/stock_receipts/recording.rb +4 -4
  357. data/app/workflows/spree/stock_transfers/cancel.rb +2 -2
  358. data/app/workflows/spree/stock_transfers/close.rb +3 -30
  359. data/app/workflows/spree/stock_transfers/mark_draft.rb +1 -1
  360. data/app/workflows/spree/stock_transfers/mark_in_transit.rb +3 -3
  361. data/app/workflows/spree/stock_transfers/mark_ready.rb +2 -2
  362. data/app/workflows/spree/stock_transfers/receive.rb +1 -1
  363. data/app/workflows/spree/stock_transfers/update.rb +5 -33
  364. data/config/i18n-tasks.yml +32 -18
  365. data/config/initializers/alba.rb +7 -0
  366. data/config/language_names.csv +264 -0
  367. data/config/locales/ar.yml +811 -0
  368. data/config/locales/be.yml +855 -0
  369. data/config/locales/bg.yml +723 -0
  370. data/config/locales/ca.yml +689 -0
  371. data/config/locales/cs.yml +855 -0
  372. data/config/locales/da.yml +771 -0
  373. data/config/locales/de-CH.yml +248 -0
  374. data/config/locales/de.yml +835 -0
  375. data/config/locales/el.yml +769 -0
  376. data/config/locales/en.yml +37 -503
  377. data/config/locales/es-CL.yml +301 -0
  378. data/config/locales/es-EC.yml +186 -0
  379. data/config/locales/es-MX.yml +334 -0
  380. data/config/locales/es.yml +831 -0
  381. data/config/locales/et.yml +644 -0
  382. data/config/locales/fa.yml +709 -0
  383. data/config/locales/fi.yml +771 -0
  384. data/config/locales/fr.yml +830 -0
  385. data/config/locales/hu.yml +751 -0
  386. data/config/locales/id.yml +756 -0
  387. data/config/locales/it.yml +833 -0
  388. data/config/locales/ja.yml +726 -0
  389. data/config/locales/km.yml +759 -0
  390. data/config/locales/ko.yml +575 -0
  391. data/config/locales/ku.yml +753 -0
  392. data/config/locales/lt.yml +821 -0
  393. data/config/locales/lv.yml +685 -0
  394. data/config/locales/nb.yml +824 -0
  395. data/config/locales/ne.yml +823 -0
  396. data/config/locales/nl.yml +826 -0
  397. data/config/locales/pl.yml +835 -0
  398. data/config/locales/pt-BR.yml +547 -0
  399. data/config/locales/pt.yml +636 -0
  400. data/config/locales/ro.yml +750 -0
  401. data/config/locales/ru.yml +834 -0
  402. data/config/locales/sk.yml +680 -0
  403. data/config/locales/sl-SI.yml +600 -0
  404. data/config/locales/sv.yml +827 -0
  405. data/config/locales/th.yml +745 -0
  406. data/config/locales/tr.yml +777 -0
  407. data/config/locales/uk.yml +836 -0
  408. data/config/locales/vi.yml +768 -0
  409. data/config/locales/zh-CN.yml +786 -0
  410. data/config/locales/zh-TW.yml +834 -0
  411. data/db/migrate/20260925000001_add_replacement_to_spree_fulfillment_items.rb +5 -0
  412. data/db/migrate/20261001000001_add_post_sale_tax.rb +30 -0
  413. data/db/migrate/20261001000001_convert_preferences_to_json.rb +166 -0
  414. data/db/migrate/20261001000001_create_spree_email_templates.rb +52 -0
  415. data/lib/generators/spree/dummy/dummy_generator.rb +0 -9
  416. data/lib/generators/spree/dummy/templates/rails/test.rb +7 -0
  417. data/lib/spree/checkout/default_requirements.rb +37 -13
  418. data/lib/spree/core/configuration.rb +1 -1
  419. data/lib/spree/core/controller_helpers/store.rb +1 -1
  420. data/lib/spree/core/dependencies.rb +5 -4
  421. data/lib/spree/core/emails/escaped_output.rb +60 -0
  422. data/lib/spree/core/engine.rb +48 -167
  423. data/lib/spree/core/permissions/default_catalog.rb +5 -0
  424. data/lib/spree/core/preferences/json_conversion.rb +182 -0
  425. data/lib/spree/core/preferences/masking.rb +4 -1
  426. data/lib/spree/core/preferences/preferable.rb +137 -83
  427. data/lib/spree/core/preferences/preferable_class_methods.rb +81 -146
  428. data/lib/spree/core/previews/import_preview.rb +10 -0
  429. data/lib/spree/core/tax/provider_error.rb +37 -0
  430. data/lib/spree/core/version.rb +1 -1
  431. data/lib/spree/core.rb +85 -370
  432. data/lib/spree/emails/editable_templates.rb +82 -0
  433. data/lib/spree/events/catalog.rb +189 -0
  434. data/lib/spree/events.rb +21 -1
  435. data/lib/spree/hooks.rb +0 -17
  436. data/lib/spree/i18n.rb +32 -15
  437. data/lib/spree/reporting/adapters/live.rb +6 -6
  438. data/lib/spree/reporting/default_vocabulary.rb +22 -10
  439. data/lib/spree/reporting/hydration.rb +1 -1
  440. data/lib/spree/reporting/query.rb +8 -0
  441. data/lib/spree/reporting/schema.rb +10 -10
  442. data/lib/spree/testing_support/editable_email_templates.rb +61 -0
  443. data/lib/spree/testing_support/emails.rb +22 -0
  444. data/lib/spree/testing_support/factories/cart_factory.rb +1 -1
  445. data/lib/spree/testing_support/factories/email_template_factory.rb +28 -0
  446. data/lib/spree/testing_support/factories/order_factory.rb +2 -2
  447. data/lib/spree/testing_support/factories/refund_factory.rb +1 -1
  448. data/lib/spree/testing_support/factories/stock_factory.rb +1 -1
  449. data/lib/spree/testing_support/factories/variant_factory.rb +1 -1
  450. data/lib/spree/testing_support/i18n.rb +3 -94
  451. data/lib/spree/testing_support/lifecycle_events.rb +1 -1
  452. data/lib/spree/testing_support/order_walkthrough.rb +1 -1
  453. data/lib/spree/testing_support/preferences.rb +0 -5
  454. data/lib/spree/testing_support/store.rb +9 -1
  455. data/lib/spree/upgrades/5_6_to_6_0/manifest.yml +45 -0
  456. data/lib/tasks/categories_and_collections.rake +3 -3
  457. data/lib/tasks/core.rake +6 -4
  458. data/lib/tasks/media.rake +3 -3
  459. data/lib/tasks/package_types.rake +1 -1
  460. data/lib/tasks/preferences_json.rake +101 -0
  461. data/spec/fixtures/mailer_views/custom_views_probe_mailer/welcome_email.html.erb +4 -0
  462. metadata +188 -44
  463. data/app/models/acts_as_taggable_on/tag_decorator.rb +0 -10
  464. data/app/models/concerns/spree/has_image_alt_text.rb +0 -18
  465. data/app/models/spree/base_analytics_event_handler.rb +0 -54
  466. data/app/models/spree/invitations/store.rb +0 -6
  467. data/app/models/spree/preference.rb +0 -14
  468. data/app/models/spree/promotion_handler/page.rb +0 -25
  469. data/app/models/spree/promotion_handler/promotion_duplicator.rb +0 -60
  470. data/app/models/spree/stock/differentiator.rb +0 -45
  471. data/app/presenters/spree/filters/options_presenter.rb +0 -47
  472. data/app/services/spree/carts/empty.rb +0 -42
  473. data/app/services/spree/country_to_timezone.rb +0 -273
  474. data/app/services/spree/payments/create.rb +0 -92
  475. data/app/validators/spree/url_validator.rb +0 -23
  476. data/app/views/active_storage/blobs/_blob.html.erb +0 -14
  477. data/app/views/spree/admin_user_mailer/password_reset_email.html.erb +0 -8
  478. data/app/views/spree/export_mailer/export_done.html.erb +0 -7
  479. data/app/views/spree/import_mailer/import_done.html.erb +0 -12
  480. data/app/views/spree/invitation_mailer/invitation_accepted.html.erb +0 -4
  481. data/app/views/spree/invitation_mailer/invitation_email.html.erb +0 -12
  482. data/app/views/spree/seller_user_mailer/password_reset_email.html.erb +0 -8
  483. data/app/views/spree/shared/_base_mailer_footer.html.erb +0 -19
  484. data/app/views/spree/shared/_base_mailer_header.html.erb +0 -8
  485. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +0 -399
  486. data/app/views/spree/shared/_mailer_logo.html.erb +0 -41
  487. data/app/views/spree/shared/_purchased_items_styles.html.erb +0 -119
  488. data/app/views/spree/webhook_mailer/endpoint_disabled.html.erb +0 -51
  489. data/app/views/spree/webhook_mailer/endpoint_disabled.text.erb +0 -10
  490. data/app/workflows/spree/fulfillments/purchase_label.rb +0 -40
  491. data/app/workflows/spree/returns/purchase_label.rb +0 -32
  492. data/lib/spree/analytics.rb +0 -11
  493. data/lib/spree/core/preferences/scoped_store.rb +0 -34
  494. data/lib/spree/core/preferences/store.rb +0 -105
  495. data/lib/spree/translation_migrations.rb +0 -52
@@ -31,7 +31,7 @@ FactoryBot.define do
31
31
  country = Spree::Country.by_iso('US')
32
32
 
33
33
  if Spree::DeliveryMethod.none?
34
- create(:shipping_method).tap do |delivery_method|
34
+ create(:delivery_method).tap do |delivery_method|
35
35
  delivery_method.calculator.preferred_amount = evaluator.shipping_cost
36
36
  delivery_method.calculator.preferred_currency = cart.store.default_currency
37
37
  delivery_method.calculator.save!
@@ -0,0 +1,28 @@
1
+ FactoryBot.define do
2
+ factory :email_template, class: Spree::EmailTemplate do
3
+ store { Spree::Store.default || create(:store) }
4
+ key { 'spree/admin_user_mailer/password_reset_email' }
5
+ locale { 'any' }
6
+ subject { 'Reset {{ store.name }}' }
7
+ body { '<mj-section><mj-column><mj-text>Hello</mj-text></mj-column></mj-section>' }
8
+ base_subject { 'Reset {{ store.name }}' }
9
+ base_body { '<mj-section><mj-column><mj-text>Default</mj-text></mj-column></mj-section>' }
10
+ published_at { Time.current }
11
+ end
12
+
13
+ factory :email_template_draft, class: Spree::EmailTemplateDraft do
14
+ store { Spree::Store.default || create(:store) }
15
+ key { 'spree/admin_user_mailer/password_reset_email' }
16
+ locale { 'any' }
17
+ subject { 'Reset {{ store.name }}' }
18
+ body { '<mj-section><mj-column><mj-text>Draft</mj-text></mj-column></mj-section>' }
19
+ base_subject { 'Reset {{ store.name }}' }
20
+ base_body { '<mj-section><mj-column><mj-text>Default</mj-text></mj-column></mj-section>' }
21
+ end
22
+
23
+ factory :email_template_revision, class: Spree::EmailTemplateRevision do
24
+ email_template
25
+ subject { 'Reset {{ store.name }}' }
26
+ body { '<mj-section><mj-column><mj-text>Hello</mj-text></mj-column></mj-section>' }
27
+ end
28
+ end
@@ -39,7 +39,7 @@ FactoryBot.define do
39
39
  create(:line_item, order: order, price: evaluator.line_items_price)
40
40
  order.line_items.reload # to ensure order.line_items is accessible after
41
41
 
42
- order.update_column(:item_count, order.line_items.count)
42
+ order.update_column(:total_quantity, order.line_items.count)
43
43
  order.reload
44
44
  end
45
45
  end
@@ -78,7 +78,7 @@ FactoryBot.define do
78
78
  end
79
79
 
80
80
  stock_location = order.line_items&.first&.variant&.stock_levels&.first&.stock_location || create(:stock_location)
81
- create(:shipment, order: order, cost: evaluator.shipment_cost, stock_location: stock_location)
81
+ create(:fulfillment, order: order, cost: evaluator.shipment_cost, stock_location: stock_location)
82
82
  order.fulfillments.reload
83
83
 
84
84
  order.recalculate_totals!
@@ -4,7 +4,7 @@ FactoryBot.define do
4
4
  factory :refund, class: Spree::Refund do
5
5
  amount { 100.00 }
6
6
  transaction_id { generate(:refund_transaction_id) }
7
- association(:payment, state: 'completed')
7
+ association(:payment, status: 'completed')
8
8
  association(:reason, factory: :refund_reason)
9
9
  end
10
10
 
@@ -20,7 +20,7 @@ FactoryBot.define do
20
20
 
21
21
  after(:build) do |package, evaluator|
22
22
  evaluator.variants_contents.each do |variant, count|
23
- package.add_multiple build_list(:inventory_unit, count, variant: variant)
23
+ package.add_multiple build_list(:fulfillment_item, count, variant: variant)
24
24
  end
25
25
  end
26
26
 
@@ -45,7 +45,7 @@ FactoryBot.define do
45
45
  product { |p| p.association(:product) }
46
46
 
47
47
  factory :with_image_variant do
48
- images { create_list(:image, 1) }
48
+ images { create_list(:media, 1) }
49
49
  end
50
50
 
51
51
  trait :with_no_price do
@@ -1,94 +1,3 @@
1
- # This file exists solely to test whether or not there are missing translations
2
- # within the code that Spree's test suite covers.
3
- #
4
- # If there is a translation referenced which has no corresponding key within the
5
- # .yml file, then there will be a message output at the end of the suite showing
6
- # that.
7
- #
8
- # If there is a translation within the locale file which *isn't* used in the
9
- # test, this will also be shown at the end of the suite run.
10
- module Spree
11
- class << self
12
- attr_accessor :used_translations, :missing_translation_messages,
13
- :unused_translations, :unused_translation_messages
14
- alias normal_t t
15
- end
16
-
17
- def self.t(*args)
18
- original_args = args.dup
19
- options = args.extract_options!
20
- self.used_translations ||= []
21
- [*args.first].each do |translation_key|
22
- key = ([*options[:scope]] << translation_key).join('.')
23
- self.used_translations << key
24
- end
25
- normal_t(*original_args)
26
- end
27
-
28
- def self.check_missing_translations
29
- self.missing_translation_messages = []
30
- self.used_translations ||= []
31
- used_translations.map { |a| a.split('.') }.each do |translation_keys|
32
- root = translations
33
- processed_keys = []
34
- translation_keys.each do |key|
35
- root = root.fetch(key.to_sym)
36
- processed_keys << key.to_sym
37
- rescue KeyError
38
- error = "#{(processed_keys << key).join('.')} (#{I18n.locale})"
39
- unless Spree.missing_translation_messages.include?(error)
40
- Spree.missing_translation_messages << error
41
- end
42
- end
43
- end
44
- end
45
-
46
- def self.check_unused_translations
47
- self.used_translations ||= []
48
- self.unused_translation_messages = []
49
- self.unused_translations = []
50
- load_translations(translations)
51
- translation_diff = unused_translations - used_translations
52
- translation_diff.each do |translation|
53
- Spree.unused_translation_messages << "#{translation} (#{I18n.locale})"
54
- end
55
- end
56
-
57
- private
58
-
59
- def self.load_translations(hash, root = [])
60
- hash.each do |k, v|
61
- if v.is_a?(Hash)
62
- load_translations(v, root.dup << k)
63
- else
64
- key = (root + [k]).join('.')
65
- unused_translations << key
66
- end
67
- end
68
- end
69
-
70
- def self.translations
71
- @translations ||= I18n.backend.send(:translations)[I18n.locale][:spree]
72
- end
73
- end
74
-
75
- RSpec.configure do |config|
76
- # Need to check here again because this is used in i18n_spec too.
77
- if ENV['CHECK_TRANSLATIONS']
78
- config.after :suite do
79
- Spree.check_missing_translations
80
- if Spree.missing_translation_messages.any?
81
- puts "\nThere are missing translations within Spree:"
82
- puts Spree.missing_translation_messages.sort
83
- exit(1)
84
- end
85
-
86
- Spree.check_unused_translations
87
- if Spree.unused_translation_messages.any?
88
- puts "\nThere are unused translations within Spree:"
89
- puts Spree.unused_translation_messages.sort
90
- exit(1)
91
- end
92
- end
93
- end
94
- end
1
+ # Deprecated: Spree's specs now catch missing keys through Rails'
2
+ # config.i18n.raise_on_missing_translations. Removed in Spree 6.1.
3
+ Spree::Deprecation.warn("spree/testing_support/i18n is deprecated and does nothing; set config.i18n.raise_on_missing_translations = true in your test environment instead. It will be removed in Spree 6.1.") if defined?(Spree::Deprecation)
@@ -21,7 +21,7 @@ shared_examples_for 'lifecycle events' do |factory: nil, event_prefix: nil|
21
21
  expect(record).to receive(:publish_event).with("#{lifecycle_event_prefix}.updated")
22
22
  allow(record).to receive(:publish_event).with(anything)
23
23
 
24
- # update_attribute, not update!: Spree::Shipment#update! shadows the
24
+ # update_attribute, not update!: Spree::Fulfillment#update! shadows the
25
25
  # Active Record method with the legacy state-recalculation API.
26
26
  Timecop.travel(1.minute.from_now) do
27
27
  record.update_attribute(:updated_at, Time.current)
@@ -21,7 +21,7 @@ class OrderWalkthrough
21
21
 
22
22
  # A delivery method must exist for rates to be displayed on checkout page
23
23
  unless Spree::DeliveryMethod.exists?
24
- FactoryBot.create(:shipping_method).tap do |delivery_method|
24
+ FactoryBot.create(:delivery_method).tap do |delivery_method|
25
25
  delivery_method.calculator.preferred_amount = 10
26
26
  delivery_method.calculator.preferred_currency = store.default_currency
27
27
  delivery_method.calculator.save
@@ -18,11 +18,6 @@ module Spree
18
18
  yield(config) if block_given?
19
19
  end
20
20
 
21
- def assert_preference_unset(preference)
22
- find("#preferences_#{preference}")['checked'].should be false
23
- Spree::Config[preference].should be false
24
- end
25
-
26
21
  # Stubs store-scoped commerce settings for the duration of one example.
27
22
  #
28
23
  # stub_store_preferences(track_inventory_levels: false)
@@ -29,6 +29,15 @@ RSpec.configure do |config|
29
29
  end
30
30
  end
31
31
 
32
+ # Reloaded before each example rather than after: the after hooks run
33
+ # inside the example's transaction, so a reload there still sees the
34
+ # example's writes, and the next example would start from values the
35
+ # database no longer holds. Setting a preference to such a stale value is
36
+ # no change to Rails, so it would never be saved.
37
+ config.before(:each) do
38
+ @default_store&.reload unless self.class.metadata[:without_global_store]
39
+ end
40
+
32
41
  config.after(:each) do
33
42
  unless self.class.metadata[:without_global_store]
34
43
  @default_store&.products = []
@@ -43,7 +52,6 @@ RSpec.configure do |config|
43
52
  @default_store.association(:default_market).reset if @default_store.association_cached?(:default_market)
44
53
  @default_store.association(:markets).reset if @default_store.association_cached?(:markets)
45
54
  @default_store.remove_instance_variable(:@has_markets) if @default_store.instance_variable_defined?(:@has_markets)
46
- @default_store.reload
47
55
  end
48
56
  end
49
57
  end
@@ -35,6 +35,22 @@ steps:
35
35
 
36
36
  Idempotent, and a no-op on an already-consolidated schema.
37
37
 
38
+ - id: preferences_json
39
+ name: "Check for preferences still stored as YAML"
40
+ task: "spree:upgrade:preferences_json"
41
+ notes: |
42
+ Spree 6.0 stores preferences as JSON instead of YAML, and keeps secrets
43
+ (preferences declared as passwords, such as gateway API keys) in a
44
+ separate secret_preferences column. The migration converts every row and
45
+ moves every secret itself, so a normal db:migrate needs nothing from this
46
+ step.
47
+
48
+ This is a safety net: it converts any row still holding YAML, and moves
49
+ the secrets of a class that was not loaded when the migration ran, such
50
+ as one from an extension gem installed afterwards.
51
+
52
+ Idempotent, and a no-op once everything is converted.
53
+
38
54
  - id: migrate_media_class_names
39
55
  name: "Rewrite stored Spree::Asset and Spree::Image class names"
40
56
  task: "spree:migrate_media_class_names"
@@ -288,6 +304,20 @@ steps:
288
304
  with one statement scoped to the rows still missing a code, so an
289
305
  interrupted run picks up where it stopped.
290
306
 
307
+ - id: migrate_checkout_zones
308
+ name: "Convert checkout zones to markets"
309
+ task: "spree:markets:migrate_checkout_zones"
310
+ notes: |
311
+ Markets replace the store's checkout zone in Spree 6. Stores that have
312
+ no market yet get a default one covering their checkout zone's
313
+ countries, or their default country when no zone was set, and the
314
+ checkout zone is cleared.
315
+
316
+ Run before migrate_tax_zones, which matches zone price rules against a
317
+ store's markets, and before backfill_order_markets, which assigns each
318
+ store's default market to its orders. Idempotent: stores that already
319
+ have a market are skipped.
320
+
291
321
  - id: migrate_promotion_option_value_rules
292
322
  name: "Rewrite Option Value promotion rules to stable option value ids"
293
323
  task: "spree:upgrade:migrate_promotion_option_value_rules"
@@ -715,3 +745,18 @@ steps:
715
745
  predates the upgrade.
716
746
 
717
747
  Idempotent, and safe to re-run at any time to repair drift.
748
+
749
+ - id: encrypt_secret_preferences
750
+ name: "Encrypt gateway and integration secrets"
751
+ task: "spree:upgrade:encrypt_secret_preferences"
752
+ notes: |
753
+ The 6.0 migration moves existing secrets into the secret_preferences
754
+ column in plain text, so it never needs encryption keys. They stay
755
+ readable and are encrypted the next time their record is saved. This step
756
+ encrypts them all now.
757
+
758
+ Skips with a note when Active Record encryption keys are not configured;
759
+ see the encryption section of the upgrade guide to add them, then run
760
+ this step again.
761
+
762
+ Idempotent.
@@ -80,7 +80,7 @@ namespace :spree do
80
80
  # otherwise purge/destroy: ActionText description, images, custom fields, slugs.
81
81
  move_polymorphic.call(ActionText::RichText, :record_type, :record_id, category, collection)
82
82
  move_polymorphic.call(ActiveStorage::Attachment, :record_type, :record_id, category, collection, name: %w[image square_image])
83
- move_polymorphic.call(Spree::Metafield, :resource_type, :resource_id, category, collection)
83
+ move_polymorphic.call(Spree::CustomField, :resource_type, :resource_id, category, collection)
84
84
  move_polymorphic.call(FriendlyId::Slug, :sluggable_type, :sluggable_id, category, collection)
85
85
 
86
86
  # Rules -> collection_rules (remap the STI type; insert_all bypasses the
@@ -169,8 +169,8 @@ namespace :spree do
169
169
  # category rows that still hold the pre-6.0 names.
170
170
  puts 'Backfilling renamed class-name strings...'
171
171
  [
172
- [Spree::Metafield, :resource_type, 'Spree::Taxon', 'Spree::Category'],
173
- [Spree::MetafieldDefinition, :resource_type, 'Spree::Taxon', 'Spree::Category'],
172
+ [Spree::CustomField, :resource_type, 'Spree::Taxon', 'Spree::Category'],
173
+ [Spree::CustomFieldDefinition, :resource_type, 'Spree::Taxon', 'Spree::Category'],
174
174
  [ActiveStorage::Attachment, :record_type, 'Spree::Taxon', 'Spree::Category'],
175
175
  # description is an ActionText field (translates :description, backend: :action_text);
176
176
  # surviving categories keep their rich-text description without this.
data/lib/tasks/core.rake CHANGED
@@ -26,14 +26,16 @@ namespace :core do
26
26
 
27
27
  desc 'Migrate newsletter subscribers'
28
28
  task migrate_newsletter_subscribers: :environment do |_t, _args|
29
- Spree.customer_class.where(accepts_email_marketing: true).in_batches(of: 500) do |user_batch|
30
- subscriber_attributes = user_batch.pluck(:id, :email, :updated_at).map do |id, email, updated_at|
29
+ store_id = Spree::Store.default&.id
30
+
31
+ Spree.customer_class.where(accepts_email_marketing: true).in_batches(of: 500) do |customer_batch|
32
+ subscriber_attributes = customer_batch.pluck(:id, :email, :updated_at).map do |id, email, updated_at|
31
33
  {
32
34
  email: Spree::NewsletterSubscriber.new(email: email).email, # normalized email
33
- user_id: id,
35
+ customer_id: id,
34
36
  verified_at: updated_at,
35
37
  verification_token: nil,
36
- store_id: Spree::Store.default&.id,
38
+ store_id: store_id,
37
39
  updated_at: DateTime.current,
38
40
  created_at: DateTime.current
39
41
  }
data/lib/tasks/media.rake CHANGED
@@ -31,9 +31,9 @@ namespace :spree do
31
31
  # Subquery (not pluck) so the product set doesn't materialize in Ruby —
32
32
  # important for catalogs with millions of products.
33
33
  variant_product_ids = Spree::Variant
34
- .joins("INNER JOIN #{Spree::Asset.table_name} ON " \
35
- "#{Spree::Asset.table_name}.viewable_id = #{Spree::Variant.table_name}.id " \
36
- "AND #{Spree::Asset.table_name}.viewable_type = 'Spree::Variant'")
34
+ .joins("INNER JOIN #{Spree::Media.table_name} ON " \
35
+ "#{Spree::Media.table_name}.viewable_id = #{Spree::Variant.table_name}.id " \
36
+ "AND #{Spree::Media.table_name}.viewable_type = 'Spree::Variant'")
37
37
  .select(:product_id)
38
38
 
39
39
  relation = Spree::Product.where(id: variant_product_ids)
@@ -43,7 +43,7 @@ namespace :spree do
43
43
  end
44
44
 
45
45
  store.package_types.create!(
46
- name: Spree.t('package_types.default_name'),
46
+ name: I18n.t('spree.package_types.default_name'),
47
47
  kind: 'box',
48
48
  default: true,
49
49
  weight: weight.positive? ? weight : nil,
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ # 5.6 → 6.0 follow-ups to the ConvertPreferencesToJson migration
4
+ # (docs/plans/6.0-json-preferences.md). Both are idempotent.
5
+ module Spree
6
+ module SecretPreferencesUpgrade
7
+ # The models keeping secrets in `secret_preferences`, one per table.
8
+ def self.models
9
+ Rails.application.eager_load!
10
+ Spree::Base.descendants.select do |model|
11
+ model.include?(Spree::SecretPreferences) && model.base_class == model && model.table_exists?
12
+ end
13
+ end
14
+
15
+ # Every row of the model, deleted ones included, except rows whose class
16
+ # is no longer installed — loading one of those raises, which would stop
17
+ # the task before it reached the rest. They are reported and left as
18
+ # they are; their secrets stay readable.
19
+ #
20
+ # @return [ActiveRecord::Relation]
21
+ def self.loadable_rows(model)
22
+ rows = model.unscoped
23
+ return rows unless model.column_names.include?(model.inheritance_column)
24
+
25
+ types = rows.distinct.pluck(model.inheritance_column)
26
+ missing = types.compact.reject(&:safe_constantize)
27
+ return rows if missing.empty?
28
+
29
+ missing.each { |type| puts " #{model.table_name}: skipped rows of #{type}, which is not installed" }
30
+ rows.where.not(model.inheritance_column => missing).or(rows.where(model.inheritance_column => nil))
31
+ end
32
+ end
33
+ end
34
+
35
+ namespace :spree do
36
+ namespace :upgrade do
37
+ desc <<~DESC
38
+ Converts any preferences row still holding YAML to JSON, and moves secrets
39
+ left in `preferences` to the encrypted `secret_preferences` column.
40
+
41
+ The 6.0 migration does both itself, so a normal `db:migrate` leaves nothing
42
+ for this task. It exists for schemas changed out of band, and for secrets of
43
+ a class that was not loaded when the migration ran (an extension gem added
44
+ afterwards).
45
+ DESC
46
+ task preferences_json: :environment do
47
+ conversion = Spree::Preferences::JsonConversion.new(ActiveRecord::Base.connection, log: ->(message) { puts " #{message}" })
48
+
49
+ conversion.preference_tables.each do |table|
50
+ converted = conversion.text_column?(table) ? conversion.convert_text_table(table) : conversion.convert_table(table)
51
+ puts " #{table}: #{converted} rows converted from YAML" if converted.positive?
52
+ end
53
+
54
+ Spree::SecretPreferencesUpgrade.models.each do |model|
55
+ moved = 0
56
+
57
+ Spree::SecretPreferencesUpgrade.loadable_rows(model).find_each do |record|
58
+ separated = record.separated_secret_preferences
59
+ next unless separated
60
+
61
+ # Written without callbacks: moving a secret is not a change to it, and
62
+ # must not look like one to a gateway that re-registers on key changes.
63
+ record.update_columns(separated)
64
+ moved += 1
65
+ end
66
+
67
+ puts " #{model.table_name}: moved secrets out of preferences for #{moved} rows" if moved.positive?
68
+ end
69
+
70
+ puts 'preferences_json done.'
71
+ end
72
+
73
+ desc <<~DESC
74
+ Encrypts every `secret_preferences` value still stored in plain text.
75
+
76
+ The 6.0 migration moves existing secrets into `secret_preferences` without
77
+ encrypting them, so it never depends on encryption keys. They stay readable
78
+ as they are and are encrypted on their next save; this task encrypts them
79
+ all at once. Skips with a note when Active Record encryption keys are not
80
+ configured.
81
+ DESC
82
+ task encrypt_secret_preferences: :environment do
83
+ unless ActiveRecord::Encryption.config.has_primary_key?
84
+ puts ' Active Record encryption keys are not configured, so secrets stay in plain text. ' \
85
+ 'See https://spreecommerce.org/docs/developer/deployment/environment_variables'
86
+ next
87
+ end
88
+
89
+ Spree::SecretPreferencesUpgrade.models.each do |model|
90
+ count = 0
91
+ Spree::SecretPreferencesUpgrade.loadable_rows(model).where.not(secret_preferences: nil).find_each do |record|
92
+ record.encrypt
93
+ count += 1
94
+ end
95
+ puts " #{model.table_name}: encrypted secrets for #{count} rows"
96
+ end
97
+
98
+ puts 'encrypt_secret_preferences done.'
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,4 @@
1
+ <%= render layout: 'spree/shared/mailer_hero' do %>
2
+ <h1>Welcome</h1>
3
+ <%= render 'spree/shared/mailer_button', url: 'https://example.com/start', label: 'Get started' %>
4
+ <% end %>