spree_core 6.0.0.beta4 → 6.0.0.rc2

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 (575) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -5
  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/search_provider/index_job.rb +4 -0
  10. data/app/jobs/spree/seller_payouts/sweep_seller_job.rb +2 -0
  11. data/app/jobs/spree/uploads/purge_unattached_job.rb +49 -0
  12. data/app/mailers/spree/admin_user_mailer.rb +4 -19
  13. data/app/mailers/spree/base_mailer.rb +97 -13
  14. data/app/mailers/spree/email_template_mailer.rb +27 -0
  15. data/app/mailers/spree/export_mailer.rb +3 -4
  16. data/app/mailers/spree/import_mailer.rb +3 -4
  17. data/app/mailers/spree/invitation_mailer.rb +24 -7
  18. data/app/mailers/spree/seller_user_mailer.rb +4 -16
  19. data/app/mailers/spree/webhook_mailer.rb +2 -2
  20. data/app/models/concerns/spree/acted_by.rb +1 -1
  21. data/app/models/concerns/spree/admin_user_methods.rb +15 -1
  22. data/app/models/concerns/spree/api_typed.rb +91 -0
  23. data/app/models/concerns/spree/calculated_adjustments.rb +41 -13
  24. data/app/models/concerns/spree/calculator/currency_amounts.rb +1 -1
  25. data/app/models/concerns/spree/calculator/tiers.rb +63 -0
  26. data/app/models/concerns/spree/canonical_decimals.rb +61 -0
  27. data/app/models/concerns/spree/customer_methods.rb +23 -18
  28. data/app/models/concerns/spree/derived_number.rb +11 -13
  29. data/app/models/concerns/spree/email_template_identity.rb +52 -0
  30. data/app/models/concerns/spree/parameterizable_name.rb +2 -0
  31. data/app/models/concerns/spree/payment_session_transitions.rb +8 -2
  32. data/app/models/concerns/spree/post_sale/taxation.rb +54 -0
  33. data/app/models/concerns/spree/post_sale/taxed_line.rb +51 -0
  34. data/app/models/concerns/spree/preference_schema/json_schema.rb +139 -0
  35. data/app/models/concerns/spree/preference_schema.rb +62 -32
  36. data/app/models/concerns/spree/product_scopes.rb +16 -2
  37. data/app/models/concerns/spree/provider_listing.rb +41 -0
  38. data/app/models/concerns/spree/publishable.rb +82 -14
  39. data/app/models/concerns/spree/purchase/addresses.rb +23 -10
  40. data/app/models/concerns/spree/purchase/currency.rb +1 -1
  41. data/app/models/concerns/spree/purchase/deprecated_aliases.rb +87 -0
  42. data/app/models/concerns/spree/purchase/gift_cards.rb +10 -4
  43. data/app/models/concerns/spree/purchase/locale.rb +1 -1
  44. data/app/models/concerns/spree/purchase/payment_processing.rb +8 -4
  45. data/app/models/concerns/spree/purchase/purchase_order.rb +9 -4
  46. data/app/models/concerns/spree/purchase/store_credits.rb +36 -1
  47. data/app/models/concerns/spree/purchase/totals.rb +49 -8
  48. data/app/models/concerns/spree/ransackable_attributes.rb +46 -0
  49. data/app/models/concerns/spree/receivable.rb +1 -1
  50. data/app/models/concerns/spree/searchable.rb +0 -4
  51. data/app/models/concerns/spree/secret_preferences.rb +59 -0
  52. data/app/models/concerns/spree/signed_id_attachments.rb +54 -0
  53. data/app/models/concerns/spree/single_store_resource.rb +1 -1
  54. data/app/models/concerns/spree/stores/email_branding.rb +32 -0
  55. data/app/models/concerns/spree/stores/markets.rb +5 -2
  56. data/app/models/concerns/spree/type_labels.rb +38 -0
  57. data/app/models/concerns/spree/typed_adjustment_line.rb +5 -6
  58. data/app/models/concerns/spree/typed_associations.rb +12 -18
  59. data/app/models/concerns/spree/vat_price_calculation.rb +5 -6
  60. data/app/models/spree/address.rb +12 -2
  61. data/app/models/spree/adjusters/largest_remainder.rb +14 -1
  62. data/app/models/spree/adjusters/promotion.rb +4 -19
  63. data/app/models/spree/allowed_origin.rb +3 -1
  64. data/app/models/spree/api_key.rb +5 -6
  65. data/app/models/spree/authentication/strategies/oidc_strategy.rb +5 -5
  66. data/app/models/spree/base.rb +99 -22
  67. data/app/models/spree/calculator/flat_percent_item_total.rb +2 -4
  68. data/app/models/spree/calculator/flat_rate.rb +3 -5
  69. data/app/models/spree/calculator/flexi_rate.rb +4 -6
  70. data/app/models/spree/calculator/percent_on_line_item.rb +2 -2
  71. data/app/models/spree/calculator/price_sack.rb +5 -7
  72. data/app/models/spree/calculator/shipping/digital_delivery.rb +3 -5
  73. data/app/models/spree/calculator/shipping/flat_percent_item_total.rb +7 -7
  74. data/app/models/spree/calculator/shipping/flat_rate.rb +5 -7
  75. data/app/models/spree/calculator/shipping/flexi_rate.rb +4 -6
  76. data/app/models/spree/calculator/shipping/per_item.rb +3 -5
  77. data/app/models/spree/calculator/shipping/price_sack.rb +5 -7
  78. data/app/models/spree/calculator/tiered_flat_rate.rb +7 -24
  79. data/app/models/spree/calculator/tiered_percent.rb +7 -25
  80. data/app/models/spree/cart.rb +78 -18
  81. data/app/models/spree/catalog.rb +1 -0
  82. data/app/models/spree/catalog_price.rb +0 -7
  83. data/app/models/spree/catalog_price_tier.rb +0 -8
  84. data/app/models/spree/category.rb +3 -1
  85. data/app/models/spree/channel/gating.rb +3 -2
  86. data/app/models/spree/channel.rb +6 -4
  87. data/app/models/spree/claim.rb +22 -1
  88. data/app/models/spree/claim_line_item.rb +41 -6
  89. data/app/models/spree/collection.rb +2 -1
  90. data/app/models/spree/collection_rule.rb +5 -21
  91. data/app/models/spree/commission_line.rb +1 -1
  92. data/app/models/spree/commission_rate.rb +7 -4
  93. data/app/models/spree/commission_rate_value.rb +1 -1
  94. data/app/models/spree/commission_rule.rb +4 -11
  95. data/app/models/spree/commission_rules/category_rule.rb +2 -5
  96. data/app/models/spree/commission_rules/item_total_rule.rb +2 -2
  97. data/app/models/spree/commission_rules/product_rule.rb +1 -1
  98. data/app/models/spree/commission_rules/seller_rule.rb +2 -5
  99. data/app/models/spree/company.rb +1 -0
  100. data/app/models/spree/company_invitation.rb +1 -0
  101. data/app/models/spree/consent_record.rb +0 -1
  102. data/app/models/spree/credit_card.rb +1 -1
  103. data/app/models/spree/current.rb +23 -0
  104. data/app/models/spree/custom_field.rb +2 -2
  105. data/app/models/spree/custom_field_definition.rb +20 -35
  106. data/app/models/spree/custom_fields/boolean.rb +1 -1
  107. data/app/models/spree/custom_fields/json.rb +1 -1
  108. data/app/models/spree/customer_group.rb +1 -0
  109. data/app/models/spree/data_feed/google.rb +0 -2
  110. data/app/models/spree/data_request.rb +2 -1
  111. data/app/models/spree/delivery_method.rb +36 -14
  112. data/app/models/spree/delivery_method_rule.rb +4 -11
  113. data/app/models/spree/delivery_method_rules/channel_rule.rb +2 -5
  114. data/app/models/spree/delivery_method_rules/item_total_rule.rb +2 -2
  115. data/app/models/spree/delivery_profile.rb +1 -0
  116. data/app/models/spree/delivery_rate.rb +7 -8
  117. data/app/models/spree/delivery_rate_provider/base.rb +1 -0
  118. data/app/models/spree/delivery_zone.rb +1 -2
  119. data/app/models/spree/delivery_zone_member.rb +4 -4
  120. data/app/models/spree/digital_asset.rb +7 -0
  121. data/app/models/spree/digital_asset_provider/base.rb +2 -0
  122. data/app/models/spree/digital_link.rb +2 -5
  123. data/app/models/spree/discount.rb +1 -1
  124. data/app/models/spree/email_template.rb +25 -0
  125. data/app/models/spree/email_template_draft.rb +13 -0
  126. data/app/models/spree/email_template_revision.rb +17 -0
  127. data/app/models/spree/email_templates/entry.rb +118 -0
  128. data/app/models/spree/email_templates/sample_record.rb +16 -0
  129. data/app/models/spree/emails/branding.rb +80 -0
  130. data/app/models/spree/exchange.rb +16 -1
  131. data/app/models/spree/exchange_line_item.rb +121 -5
  132. data/app/models/spree/export.rb +0 -1
  133. data/app/models/spree/exports/products.rb +10 -1
  134. data/app/models/spree/exports/report.rb +3 -3
  135. data/app/models/spree/fee.rb +4 -2
  136. data/app/models/spree/file_upload.rb +155 -0
  137. data/app/models/spree/fulfillment.rb +66 -30
  138. data/app/models/spree/fulfillment_changer.rb +2 -2
  139. data/app/models/spree/fulfillment_group.rb +6 -1
  140. data/app/models/spree/fulfillment_item.rb +0 -4
  141. data/app/models/spree/fulfillment_provider/base.rb +1 -0
  142. data/app/models/spree/gateway/bogus.rb +6 -0
  143. data/app/models/spree/gateway/custom_payment_source_method.rb +5 -0
  144. data/app/models/spree/gateway.rb +6 -2
  145. data/app/models/spree/gift_card.rb +18 -8
  146. data/app/models/spree/gift_card_batch.rb +3 -5
  147. data/app/models/spree/import.rb +5 -7
  148. data/app/models/spree/import_mapping.rb +1 -2
  149. data/app/models/spree/import_row.rb +2 -2
  150. data/app/models/spree/import_schemas/products.rb +1 -0
  151. data/app/models/spree/integration.rb +9 -19
  152. data/app/models/spree/invitation.rb +5 -5
  153. data/app/models/spree/line_item.rb +15 -4
  154. data/app/models/spree/locale.rb +11 -8
  155. data/app/models/spree/market.rb +8 -2
  156. data/app/models/spree/media.rb +1 -9
  157. data/app/models/spree/newsletter_subscriber.rb +4 -0
  158. data/app/models/spree/option_type.rb +2 -1
  159. data/app/models/spree/option_value.rb +2 -1
  160. data/app/models/spree/order.rb +60 -142
  161. data/app/models/spree/order_group.rb +18 -4
  162. data/app/models/spree/order_inventory.rb +10 -5
  163. data/app/models/spree/order_promotion.rb +1 -1
  164. data/app/models/spree/order_routing/has_strategy_preference.rb +1 -1
  165. data/app/models/spree/order_routing/strategy/base.rb +4 -2
  166. data/app/models/spree/order_routing/strategy/rules.rb +1 -1
  167. data/app/models/spree/order_routing_rule.rb +6 -22
  168. data/app/models/spree/package_type.rb +2 -2
  169. data/app/models/spree/payment/gateway_options.rb +15 -53
  170. data/app/models/spree/payment/processing.rb +2 -4
  171. data/app/models/spree/payment.rb +21 -13
  172. data/app/models/spree/payment_method/check.rb +2 -0
  173. data/app/models/spree/payment_method/session_instrumentation.rb +1 -0
  174. data/app/models/spree/payment_method/store_credit.rb +15 -13
  175. data/app/models/spree/payment_method.rb +78 -6
  176. data/app/models/spree/payment_session.rb +5 -1
  177. data/app/models/spree/payment_setup_session.rb +1 -0
  178. data/app/models/spree/payout_provider/base.rb +3 -1
  179. data/app/models/spree/pickup_point_provider/base.rb +2 -0
  180. data/app/models/spree/policy.rb +1 -0
  181. data/app/models/spree/price.rb +17 -14
  182. data/app/models/spree/price_adjustment_tier.rb +4 -0
  183. data/app/models/spree/price_list.rb +14 -9
  184. data/app/models/spree/price_rules/channel_rule.rb +3 -6
  185. data/app/models/spree/price_rules/customer_group_rule.rb +3 -6
  186. data/app/models/spree/price_rules/market_rule.rb +2 -5
  187. data/app/models/spree/price_rules/user_rule.rb +1 -3
  188. data/app/models/spree/product/channels.rb +9 -2
  189. data/app/models/spree/product.rb +54 -30
  190. data/app/models/spree/product_submission.rb +0 -12
  191. data/app/models/spree/product_type.rb +1 -1
  192. data/app/models/spree/promotion/actions/create_line_items.rb +28 -18
  193. data/app/models/spree/promotion/rules/category.rb +1 -5
  194. data/app/models/spree/promotion/rules/channel.rb +2 -9
  195. data/app/models/spree/promotion/rules/country.rb +3 -8
  196. data/app/models/spree/promotion/rules/currency.rb +1 -5
  197. data/app/models/spree/promotion/rules/customer_group.rb +2 -9
  198. data/app/models/spree/promotion/rules/first_order.rb +0 -4
  199. data/app/models/spree/promotion/rules/item_total.rb +6 -10
  200. data/app/models/spree/promotion/rules/market.rb +2 -9
  201. data/app/models/spree/promotion/rules/one_use_per_user.rb +0 -4
  202. data/app/models/spree/promotion/rules/option_value.rb +2 -6
  203. data/app/models/spree/promotion/rules/product.rb +1 -5
  204. data/app/models/spree/promotion/rules/user.rb +0 -4
  205. data/app/models/spree/promotion/rules/user_logged_in.rb +0 -4
  206. data/app/models/spree/promotion.rb +36 -6
  207. data/app/models/spree/promotion_action.rb +7 -14
  208. data/app/models/spree/promotion_action_line_item.rb +1 -1
  209. data/app/models/spree/promotion_handler/coupon.rb +59 -27
  210. data/app/models/spree/promotion_rule.rb +7 -14
  211. data/app/models/spree/purchase_order.rb +3 -0
  212. data/app/models/spree/quantity_rule.rb +1 -1
  213. data/app/models/spree/refund.rb +41 -18
  214. data/app/models/spree/return.rb +31 -2
  215. data/app/models/spree/return_line_item.rb +65 -14
  216. data/app/models/spree/role.rb +7 -7
  217. data/app/models/spree/saved_report.rb +2 -1
  218. data/app/models/spree/search_provider/base.rb +4 -0
  219. data/app/models/spree/seller.rb +10 -2
  220. data/app/models/spree/seller_payout.rb +8 -0
  221. data/app/models/spree/seller_requirement.rb +5 -12
  222. data/app/models/spree/seller_requirement_custom_field.rb +1 -2
  223. data/app/models/spree/seller_requirement_submission.rb +3 -2
  224. data/app/models/spree/seller_requirements/accept_terms.rb +2 -3
  225. data/app/models/spree/seller_transfer.rb +6 -0
  226. data/app/models/spree/shipping_label.rb +2 -0
  227. data/app/models/spree/stock/availability_validator.rb +2 -2
  228. data/app/models/spree/stock/estimator.rb +1 -1
  229. data/app/models/spree/stock/inventory_unit_builder.rb +1 -1
  230. data/app/models/spree/stock/packer.rb +2 -2
  231. data/app/models/spree/stock/splitter/weight.rb +1 -1
  232. data/app/models/spree/stock_level/custom_events.rb +6 -0
  233. data/app/models/spree/stock_level.rb +3 -1
  234. data/app/models/spree/stock_location.rb +1 -0
  235. data/app/models/spree/stock_movement.rb +1 -1
  236. data/app/models/spree/stock_receipt_item.rb +1 -1
  237. data/app/models/spree/stock_reservation.rb +2 -2
  238. data/app/models/spree/stock_transfer.rb +6 -2
  239. data/app/models/spree/store.rb +70 -19
  240. data/app/models/spree/store_credit.rb +13 -13
  241. data/app/models/spree/store_credit_event.rb +5 -5
  242. data/app/models/spree/supplier.rb +1 -0
  243. data/app/models/spree/tax_category.rb +1 -0
  244. data/app/models/spree/tax_exemption_certificate.rb +3 -0
  245. data/app/models/spree/tax_identifier.rb +3 -1
  246. data/app/models/spree/tax_line.rb +53 -3
  247. data/app/models/spree/tax_provider/base.rb +71 -14
  248. data/app/models/spree/tax_provider/internal.rb +70 -41
  249. data/app/models/spree/tax_provider/recorded_share.rb +114 -0
  250. data/app/models/spree/tax_rate.rb +30 -8
  251. data/app/models/spree/taxon.rb +1 -1
  252. data/app/models/spree/taxonomy.rb +0 -1
  253. data/app/models/spree/update_status.rb +25 -0
  254. data/app/models/spree/variant.rb +10 -12
  255. data/app/models/spree/variant_media.rb +1 -1
  256. data/app/models/spree/webhook_delivery.rb +1 -0
  257. data/app/models/spree/webhook_endpoint.rb +46 -13
  258. data/app/models/spree/wishlist.rb +1 -6
  259. data/app/models/spree/wishlist_item/custom_events.rb +6 -0
  260. data/app/presenters/spree/csv/customer_presenter.rb +1 -1
  261. data/app/presenters/spree/csv/newsletter_subscriber_presenter.rb +1 -1
  262. data/app/presenters/spree/csv/order_line_item_presenter.rb +10 -6
  263. data/app/presenters/spree/csv/price_list_price_presenter.rb +3 -8
  264. data/app/presenters/spree/csv/product_variant_presenter.rb +59 -20
  265. data/app/presenters/spree/csv/purchase_order_item_presenter.rb +1 -3
  266. data/app/serializers/spree/emails/base_serializer.rb +14 -0
  267. data/app/serializers/spree/emails/export_serializer.rb +13 -0
  268. data/app/serializers/spree/emails/import_serializer.rb +19 -0
  269. data/app/serializers/spree/emails/invitation_serializer.rb +28 -0
  270. data/app/serializers/spree/emails/store_serializer.rb +31 -0
  271. data/app/serializers/spree/emails/user_serializer.rb +12 -0
  272. data/app/serializers/spree/emails/webhook_endpoint_serializer.rb +16 -0
  273. data/app/services/spree/carts/create.rb +8 -2
  274. data/app/services/spree/carts/destroy.rb +2 -2
  275. data/app/services/spree/carts/remove_out_of_stock_items.rb +2 -2
  276. data/app/services/spree/carts/split_by_seller.rb +1 -1
  277. data/app/services/spree/carts/update.rb +22 -8
  278. data/app/services/spree/catalogs/set_product_terms.rb +1 -1
  279. data/app/services/spree/categories/add_products.rb +13 -31
  280. data/app/services/spree/categories/remove_products.rb +12 -51
  281. data/app/services/spree/checkout/advance.rb +1 -4
  282. data/app/services/spree/collections/add_products.rb +10 -23
  283. data/app/services/spree/collections/remove_products.rb +7 -43
  284. data/app/services/spree/coupon_codes/bulk_generate.rb +8 -14
  285. data/app/services/spree/data_requests/create.rb +1 -1
  286. data/app/services/spree/deliveries/destroy.rb +2 -2
  287. data/app/services/spree/email_templates/check.rb +58 -0
  288. data/app/services/spree/email_templates/no_sample_record.rb +7 -0
  289. data/app/services/spree/email_templates/preview.rb +99 -0
  290. data/app/services/spree/emails/file_system.rb +23 -0
  291. data/app/services/spree/emails/filters.rb +84 -0
  292. data/app/services/spree/emails/liquid_context.rb +48 -0
  293. data/app/services/spree/emails/rendered_email.rb +14 -0
  294. data/app/services/spree/emails/renderer.rb +125 -0
  295. data/app/services/spree/emails/template.rb +51 -0
  296. data/app/services/spree/emails/template_data.rb +23 -0
  297. data/app/services/spree/emails/template_resolver.rb +109 -0
  298. data/app/services/spree/emails/text_converter.rb +72 -0
  299. data/app/services/spree/emails/translation_inliner.rb +134 -0
  300. data/app/services/spree/imports/row_processors/price_list_price.rb +10 -10
  301. data/app/services/spree/imports/row_processors/product_variant.rb +77 -34
  302. data/app/services/spree/imports/row_processors/purchase_order.rb +13 -13
  303. data/app/services/spree/locales.rb +43 -10
  304. data/app/services/spree/newsletter/subscribe.rb +8 -12
  305. data/app/services/spree/orders/build_fulfillments.rb +3 -2
  306. data/app/services/spree/orders/create.rb +5 -4
  307. data/app/services/spree/orders/discounts/create.rb +14 -11
  308. data/app/services/spree/orders/discounts/destroy.rb +1 -0
  309. data/app/services/spree/orders/discounts/update.rb +1 -0
  310. data/app/services/spree/orders/fees/create.rb +1 -0
  311. data/app/services/spree/orders/fees/destroy.rb +1 -0
  312. data/app/services/spree/orders/fees/update.rb +1 -0
  313. data/app/services/spree/orders/remove_line_item.rb +13 -3
  314. data/app/services/spree/orders/update.rb +10 -6
  315. data/app/services/spree/orders/update_item.rb +6 -3
  316. data/app/services/spree/orders/update_statuses.rb +3 -1
  317. data/app/services/spree/prices/bulk_upsert.rb +32 -25
  318. data/app/services/spree/product_memberships.rb +61 -0
  319. data/app/services/spree/returns/eligibility_validator.rb +1 -1
  320. data/app/services/spree/search_provider/custom_field_schema.rb +2 -2
  321. data/app/services/spree/seeds/commission_rates.rb +1 -1
  322. data/app/services/spree/seeds/digital_delivery.rb +1 -1
  323. data/app/services/spree/seeds/payment_methods.rb +2 -2
  324. data/app/services/spree/seeds/saved_reports.rb +3 -3
  325. data/app/services/spree/seeds/stores.rb +1 -1
  326. data/app/services/spree/sellers/requirements.rb +1 -2
  327. data/app/services/spree/shipping_labels/confirm_refund.rb +1 -1
  328. data/app/services/spree/shipping_labels/store_file.rb +3 -3
  329. data/app/services/spree/stock_levels/correct.rb +3 -3
  330. data/app/services/spree/stock_reservations/reserve.rb +2 -3
  331. data/app/services/spree/store_credits/apply.rb +15 -13
  332. data/app/services/spree/stores/provision_defaults.rb +23 -25
  333. data/app/services/spree/update_check.rb +160 -0
  334. data/app/services/spree/uploads/assign_stores.rb +92 -0
  335. data/app/subscribers/spree/seller_onboarding_subscriber.rb +1 -1
  336. data/app/validators/spree/attachment_content_type_validator.rb +19 -2
  337. data/app/validators/spree/locale_codes_validator.rb +22 -0
  338. data/app/views/layouts/spree/base_mailer.html.erb +2 -43
  339. data/app/views/layouts/spree/base_mailer.liquid +79 -0
  340. data/app/views/spree/admin_user_mailer/password_reset_email.liquid +14 -0
  341. data/app/views/spree/export_mailer/export_done.liquid +12 -0
  342. data/app/views/spree/import_mailer/import_done.liquid +15 -0
  343. data/app/views/spree/invitation_mailer/invitation_accepted.liquid +9 -0
  344. data/app/views/spree/invitation_mailer/invitation_email.liquid +13 -0
  345. data/app/views/spree/seller_user_mailer/password_reset_email.liquid +14 -0
  346. data/app/views/spree/shared/_mailer_button.html.erb +4 -5
  347. data/app/views/spree/shared/_mailer_hero.html.erb +6 -5
  348. data/app/views/spree/shared/_summary_row.liquid +8 -0
  349. data/app/views/spree/webhook_mailer/endpoint_disabled.liquid +21 -0
  350. data/app/workflows/spree/carts/add_item.rb +4 -4
  351. data/app/workflows/spree/carts/complete.rb +13 -3
  352. data/app/workflows/spree/carts/merge.rb +1 -1
  353. data/app/workflows/spree/carts/recalculate_totals.rb +5 -0
  354. data/app/workflows/spree/carts/upsert_items.rb +18 -9
  355. data/app/workflows/spree/claims/approve.rb +5 -22
  356. data/app/workflows/spree/claims/cancel.rb +5 -21
  357. data/app/workflows/spree/claims/create.rb +15 -0
  358. data/app/workflows/spree/claims/deny.rb +7 -0
  359. data/app/workflows/spree/claims/resolve.rb +34 -31
  360. data/app/workflows/spree/customers/anonymize.rb +3 -4
  361. data/app/workflows/spree/customers/create.rb +1 -1
  362. data/app/workflows/spree/data_requests/fulfill.rb +2 -2
  363. data/app/workflows/spree/deliveries/update_tracking.rb +1 -1
  364. data/app/workflows/spree/email_templates/discard_draft.rb +20 -0
  365. data/app/workflows/spree/email_templates/publish.rb +70 -0
  366. data/app/workflows/spree/email_templates/restore_revision.rb +33 -0
  367. data/app/workflows/spree/email_templates/revert.rb +29 -0
  368. data/app/workflows/spree/email_templates/save_draft.rb +85 -0
  369. data/app/workflows/spree/exchanges/approve.rb +5 -22
  370. data/app/workflows/spree/exchanges/cancel.rb +5 -21
  371. data/app/workflows/spree/exchanges/create.rb +6 -0
  372. data/app/workflows/spree/exchanges/fulfill.rb +75 -51
  373. data/app/workflows/spree/exchanges/receive.rb +6 -65
  374. data/app/workflows/spree/fulfillments/cancel.rb +1 -1
  375. data/app/workflows/spree/fulfillments/create.rb +53 -49
  376. data/app/workflows/spree/fulfillments/fulfill.rb +23 -27
  377. data/app/workflows/spree/fulfillments/mark_delivered.rb +1 -1
  378. data/app/workflows/spree/fulfillments/replacements.rb +59 -0
  379. data/app/workflows/spree/gift_cards/apply.rb +2 -2
  380. data/app/workflows/spree/orders/add_item.rb +5 -1
  381. data/app/workflows/spree/orders/cancel.rb +3 -3
  382. data/app/workflows/spree/orders/complete.rb +16 -8
  383. data/app/workflows/spree/payments/capture.rb +20 -5
  384. data/app/workflows/spree/payments/process.rb +5 -3
  385. data/app/workflows/spree/post_sale/approval.rb +35 -0
  386. data/app/workflows/spree/post_sale/cancellation.rb +44 -0
  387. data/app/workflows/spree/post_sale/receipt.rb +92 -0
  388. data/app/workflows/spree/price_lists/update.rb +4 -4
  389. data/app/workflows/spree/products/nested_attributes.rb +1 -1
  390. data/app/workflows/spree/purchase_orders/cancel.rb +1 -1
  391. data/app/workflows/spree/purchase_orders/close.rb +3 -31
  392. data/app/workflows/spree/purchase_orders/create.rb +3 -1
  393. data/app/workflows/spree/purchase_orders/mark_draft.rb +2 -2
  394. data/app/workflows/spree/purchase_orders/mark_ordered.rb +2 -2
  395. data/app/workflows/spree/purchase_orders/receive.rb +1 -1
  396. data/app/workflows/spree/purchase_orders/update.rb +5 -34
  397. data/app/workflows/spree/receivables/closing_short.rb +46 -0
  398. data/app/workflows/spree/receivables/draft_editing.rb +48 -0
  399. data/app/workflows/spree/refunds/create.rb +5 -2
  400. data/app/workflows/spree/refunds/order_payments.rb +14 -2
  401. data/app/workflows/spree/refunds/tax_credit.rb +67 -0
  402. data/app/workflows/spree/returns/approve.rb +5 -22
  403. data/app/workflows/spree/returns/cancel.rb +5 -22
  404. data/app/workflows/spree/returns/create.rb +8 -0
  405. data/app/workflows/spree/returns/receive.rb +5 -76
  406. data/app/workflows/spree/returns/refund.rb +31 -8
  407. data/app/workflows/spree/seller_requirement_submissions/create.rb +1 -2
  408. data/app/workflows/spree/seller_transfers/reverse.rb +28 -1
  409. data/app/workflows/spree/shipping_labels/purchase.rb +8 -8
  410. data/app/workflows/spree/shipping_labels/record.rb +7 -7
  411. data/app/workflows/spree/shipping_labels/refund.rb +2 -2
  412. data/app/workflows/spree/stock_receipts/recording.rb +4 -4
  413. data/app/workflows/spree/stock_transfers/cancel.rb +2 -2
  414. data/app/workflows/spree/stock_transfers/close.rb +3 -30
  415. data/app/workflows/spree/stock_transfers/create.rb +3 -1
  416. data/app/workflows/spree/stock_transfers/mark_draft.rb +1 -1
  417. data/app/workflows/spree/stock_transfers/mark_in_transit.rb +3 -3
  418. data/app/workflows/spree/stock_transfers/mark_ready.rb +2 -2
  419. data/app/workflows/spree/stock_transfers/receive.rb +1 -1
  420. data/app/workflows/spree/stock_transfers/update.rb +5 -33
  421. data/config/currency_exponents.json +180 -0
  422. data/config/i18n-tasks.yml +32 -18
  423. data/config/initializers/alba.rb +7 -0
  424. data/config/language_names.csv +264 -0
  425. data/config/locales/ar.yml +811 -0
  426. data/config/locales/be.yml +855 -0
  427. data/config/locales/bg.yml +723 -0
  428. data/config/locales/ca.yml +689 -0
  429. data/config/locales/content_locales.rb +9 -0
  430. data/config/locales/cs.yml +855 -0
  431. data/config/locales/da.yml +771 -0
  432. data/config/locales/de-CH.yml +248 -0
  433. data/config/locales/de.yml +835 -0
  434. data/config/locales/el.yml +769 -0
  435. data/config/locales/en.yml +47 -505
  436. data/config/locales/es-CL.yml +301 -0
  437. data/config/locales/es-EC.yml +186 -0
  438. data/config/locales/es-MX.yml +334 -0
  439. data/config/locales/es.yml +831 -0
  440. data/config/locales/et.yml +644 -0
  441. data/config/locales/fa.yml +709 -0
  442. data/config/locales/fi.yml +771 -0
  443. data/config/locales/fr.yml +830 -0
  444. data/config/locales/hu.yml +751 -0
  445. data/config/locales/id.yml +756 -0
  446. data/config/locales/it.yml +833 -0
  447. data/config/locales/ja.yml +726 -0
  448. data/config/locales/km.yml +759 -0
  449. data/config/locales/ko.yml +575 -0
  450. data/config/locales/ku.yml +753 -0
  451. data/config/locales/lt.yml +821 -0
  452. data/config/locales/lv.yml +685 -0
  453. data/config/locales/nb.yml +824 -0
  454. data/config/locales/ne.yml +823 -0
  455. data/config/locales/nl.yml +826 -0
  456. data/config/locales/pl.yml +835 -0
  457. data/config/locales/pt-BR.yml +547 -0
  458. data/config/locales/pt.yml +636 -0
  459. data/config/locales/ro.yml +750 -0
  460. data/config/locales/ru.yml +834 -0
  461. data/config/locales/sk.yml +680 -0
  462. data/config/locales/sl-SI.yml +600 -0
  463. data/config/locales/sv.yml +827 -0
  464. data/config/locales/th.yml +745 -0
  465. data/config/locales/tr.yml +777 -0
  466. data/config/locales/uk.yml +836 -0
  467. data/config/locales/vi.yml +768 -0
  468. data/config/locales/zh-CN.yml +786 -0
  469. data/config/locales/zh-TW.yml +834 -0
  470. data/db/migrate/20260925000001_add_replacement_to_spree_fulfillment_items.rb +5 -0
  471. data/db/migrate/20261001000001_add_post_sale_tax.rb +30 -0
  472. data/db/migrate/20261001000001_convert_preferences_to_json.rb +166 -0
  473. data/db/migrate/20261001000001_create_spree_email_templates.rb +52 -0
  474. data/db/migrate/20261009000001_change_money_columns_to_decimal_19_4.rb +116 -0
  475. data/db/migrate/20261010000001_add_store_id_to_active_storage_blobs.rb +12 -0
  476. data/lib/generators/spree/dummy/dummy_generator.rb +0 -9
  477. data/lib/generators/spree/dummy/templates/rails/test.rb +26 -0
  478. data/lib/spree/checkout/default_requirements.rb +37 -13
  479. data/lib/spree/core/configuration.rb +19 -1
  480. data/lib/spree/core/controller_helpers/store.rb +1 -1
  481. data/lib/spree/core/dependencies.rb +5 -4
  482. data/lib/spree/core/emails/escaped_output.rb +60 -0
  483. data/lib/spree/core/engine.rb +72 -165
  484. data/lib/spree/core/permissions/default_catalog.rb +5 -0
  485. data/lib/spree/core/preferences/invalid_preferences.rb +18 -0
  486. data/lib/spree/core/preferences/json_conversion.rb +186 -0
  487. data/lib/spree/core/preferences/masking.rb +55 -2
  488. data/lib/spree/core/preferences/preferable.rb +343 -103
  489. data/lib/spree/core/preferences/preferable_class_methods.rb +188 -136
  490. data/lib/spree/core/previews/import_preview.rb +10 -0
  491. data/lib/spree/core/ransack_configuration.rb +13 -2
  492. data/lib/spree/core/tax/provider_error.rb +37 -0
  493. data/lib/spree/core/version.rb +1 -1
  494. data/lib/spree/core.rb +91 -373
  495. data/lib/spree/emails/editable_templates.rb +82 -0
  496. data/lib/spree/events/catalog.rb +189 -0
  497. data/lib/spree/events.rb +21 -1
  498. data/lib/spree/hooks.rb +0 -17
  499. data/lib/spree/i18n.rb +32 -15
  500. data/lib/spree/iso_data.rb +7 -0
  501. data/lib/spree/localized_number.rb +6 -0
  502. data/lib/spree/migrations.rb +4 -1
  503. data/lib/spree/money.rb +196 -15
  504. data/lib/spree/reporting/adapters/base.rb +7 -6
  505. data/lib/spree/reporting/adapters/live.rb +6 -6
  506. data/lib/spree/reporting/default_vocabulary.rb +22 -10
  507. data/lib/spree/reporting/hydration.rb +1 -1
  508. data/lib/spree/reporting/query.rb +8 -0
  509. data/lib/spree/reporting/registry.rb +13 -0
  510. data/lib/spree/reporting/schema.rb +10 -10
  511. data/lib/spree/testing_support/editable_email_templates.rb +61 -0
  512. data/lib/spree/testing_support/emails.rb +22 -0
  513. data/lib/spree/testing_support/factories/cart_factory.rb +1 -1
  514. data/lib/spree/testing_support/factories/email_template_factory.rb +28 -0
  515. data/lib/spree/testing_support/factories/order_factory.rb +2 -2
  516. data/lib/spree/testing_support/factories/product_factory.rb +9 -0
  517. data/lib/spree/testing_support/factories/refund_factory.rb +1 -1
  518. data/lib/spree/testing_support/factories/stock_factory.rb +1 -1
  519. data/lib/spree/testing_support/factories/variant_factory.rb +1 -1
  520. data/lib/spree/testing_support/i18n.rb +3 -94
  521. data/lib/spree/testing_support/lifecycle_events.rb +1 -1
  522. data/lib/spree/testing_support/order_walkthrough.rb +1 -1
  523. data/lib/spree/testing_support/preferences.rb +0 -5
  524. data/lib/spree/testing_support/store.rb +9 -1
  525. data/lib/spree/upgrades/5_6_to_6_0/manifest.yml +67 -1
  526. data/lib/spree/uploads.rb +101 -0
  527. data/lib/tasks/categories_and_collections.rake +3 -3
  528. data/lib/tasks/core.rake +6 -4
  529. data/lib/tasks/markets.rake +2 -1
  530. data/lib/tasks/media.rake +3 -3
  531. data/lib/tasks/migrate_users_to_customers.rake +23 -18
  532. data/lib/tasks/money.rake +46 -0
  533. data/lib/tasks/package_types.rake +1 -1
  534. data/lib/tasks/preferences_json.rake +101 -0
  535. data/lib/tasks/seller_sample_data.rake +2 -2
  536. data/lib/tasks/store_settings.rake +13 -6
  537. data/lib/tasks/typed_adjustments_migration.rake +1 -1
  538. data/lib/tasks/uploads.rake +19 -0
  539. data/spec/fixtures/mailer_views/custom_views_probe_mailer/welcome_email.html.erb +4 -0
  540. metadata +219 -46
  541. data/app/jobs/spree/products/touch_categories_job.rb +0 -15
  542. data/app/jobs/spree/products/touch_taxons_job.rb +0 -13
  543. data/app/models/acts_as_taggable_on/tag_decorator.rb +0 -10
  544. data/app/models/concerns/spree/has_image_alt_text.rb +0 -18
  545. data/app/models/spree/base_analytics_event_handler.rb +0 -54
  546. data/app/models/spree/invitations/store.rb +0 -6
  547. data/app/models/spree/preference.rb +0 -14
  548. data/app/models/spree/promotion_handler/page.rb +0 -25
  549. data/app/models/spree/promotion_handler/promotion_duplicator.rb +0 -60
  550. data/app/models/spree/stock/differentiator.rb +0 -45
  551. data/app/presenters/spree/filters/options_presenter.rb +0 -47
  552. data/app/services/spree/carts/empty.rb +0 -42
  553. data/app/services/spree/country_to_timezone.rb +0 -273
  554. data/app/services/spree/payments/create.rb +0 -92
  555. data/app/validators/spree/url_validator.rb +0 -23
  556. data/app/views/active_storage/blobs/_blob.html.erb +0 -14
  557. data/app/views/spree/admin_user_mailer/password_reset_email.html.erb +0 -8
  558. data/app/views/spree/export_mailer/export_done.html.erb +0 -7
  559. data/app/views/spree/import_mailer/import_done.html.erb +0 -12
  560. data/app/views/spree/invitation_mailer/invitation_accepted.html.erb +0 -4
  561. data/app/views/spree/invitation_mailer/invitation_email.html.erb +0 -12
  562. data/app/views/spree/seller_user_mailer/password_reset_email.html.erb +0 -8
  563. data/app/views/spree/shared/_base_mailer_footer.html.erb +0 -19
  564. data/app/views/spree/shared/_base_mailer_header.html.erb +0 -8
  565. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +0 -399
  566. data/app/views/spree/shared/_mailer_logo.html.erb +0 -41
  567. data/app/views/spree/shared/_purchased_items_styles.html.erb +0 -119
  568. data/app/views/spree/webhook_mailer/endpoint_disabled.html.erb +0 -51
  569. data/app/views/spree/webhook_mailer/endpoint_disabled.text.erb +0 -10
  570. data/app/workflows/spree/fulfillments/purchase_label.rb +0 -40
  571. data/app/workflows/spree/returns/purchase_label.rb +0 -32
  572. data/lib/spree/analytics.rb +0 -11
  573. data/lib/spree/core/preferences/scoped_store.rb +0 -34
  574. data/lib/spree/core/preferences/store.rb +0 -105
  575. data/lib/spree/translation_migrations.rb +0 -52
@@ -2,6 +2,10 @@
2
2
 
3
3
  module Spree
4
4
  class CollectionRule < Spree.base_class
5
+ include Spree::TypeLabels
6
+
7
+ self.type_labels_scope = 'spree.collection_rule_types'
8
+
5
9
  has_prefix_id :crule
6
10
 
7
11
  MATCH_POLICIES = %w[is_equal_to is_not_equal_to contains does_not_contain].freeze
@@ -18,25 +22,6 @@ module Spree
18
22
 
19
23
  validate :type_must_be_registered
20
24
 
21
- # @return [String] localized display name for the rule kind, used by admin pickers
22
- def self.human_name
23
- Spree.t("collection_rule_types.#{api_type}.name", default: api_type.titleize)
24
- end
25
-
26
- # @return [String] localized description for the rule kind
27
- def self.human_description
28
- Spree.t("collection_rule_types.#{api_type}.description", default: '')
29
- end
30
-
31
- # Feeds the `description` field of `subclasses_with_preference_schema`
32
- # (the `/types` discovery payload), which only reads `.description`.
33
- def self.description
34
- human_description
35
- end
36
-
37
- def human_name = self.class.human_name
38
- def human_description = self.class.human_description
39
-
40
25
  registers_subclasses_via { Rails.application.config.spree.collection_rules }
41
26
 
42
27
  private
@@ -47,8 +32,7 @@ module Spree
47
32
  return if type.blank?
48
33
  return if Rails.application.config.spree.collection_rules.any? { |rule| rule.to_s == type }
49
34
 
50
- errors.add(:type, :invalid_collection_rule, message: Spree.t(:invalid_collection_rule, scope: [:errors, :messages],
51
- default: 'is not a registered collection rule'))
35
+ errors.add(:type, :invalid_collection_rule, message: I18n.t('spree.errors.messages.invalid_collection_rule'))
52
36
  end
53
37
 
54
38
  def regenerate_collection_products
@@ -81,7 +81,7 @@ module Spree
81
81
  def exactly_one_subject
82
82
  return if [line_item_id, fulfillment_id].compact.one?
83
83
 
84
- errors.add(:base, :exactly_one_of_line_item_or_fulfillment, message: Spree.t('errors.messages.exactly_one_of_line_item_or_fulfillment'))
84
+ errors.add(:base, :exactly_one_of_line_item_or_fulfillment, message: I18n.t('spree.errors.messages.exactly_one_of_line_item_or_fulfillment'))
85
85
  end
86
86
  end
87
87
  end
@@ -36,6 +36,9 @@ module Spree
36
36
  include Spree::SingleStoreResource
37
37
  include Spree::HasListPosition
38
38
  include Spree::Metadata
39
+ include Spree::CanonicalDecimals
40
+
41
+ canonical_decimals :value, places: 5
39
42
  include Spree::TypedAssociations
40
43
 
41
44
  KINDS = %w[percentage fixed].freeze
@@ -43,7 +46,6 @@ module Spree
43
46
  #
44
47
  # Associations
45
48
  #
46
- belongs_to :store, class_name: 'Spree::Store'
47
49
  # Every amount this rate states, one row per currency: what a flat fee
48
50
  # charges, and the floor and cap a percentage charges within. A flat rate
49
51
  # with no amount for the sale's currency does not apply to it (see
@@ -104,6 +106,7 @@ module Spree
104
106
 
105
107
  self.whitelisted_ransackable_attributes = %w[name code kind enabled position value
106
108
  tax_inclusive include_shipping]
109
+ search_by :name
107
110
  self.whitelisted_ransackable_associations = %w[commission_rules]
108
111
 
109
112
  # @return [Boolean]
@@ -245,7 +248,7 @@ module Spree
245
248
  # shape a price list's rules use.
246
249
  #
247
250
  # Ids inside a rule's preferences are scope-checked against this rate's own
248
- # store as they are written (see normalize_id_preference), so a rule can
251
+ # store as they are written (see `of: :id, scope:`), so a rule can
249
252
  # never be pointed at another marketplace's records.
250
253
  #
251
254
  # @param rows [Array<Hash>, nil]
@@ -357,14 +360,14 @@ module Spree
357
360
  def flat_fee_does_not_charge_delivery
358
361
  return unless fixed? && include_shipping?
359
362
 
360
- errors.add(:include_shipping, :flat_fee_cannot_charge_delivery, message: Spree.t('errors.messages.flat_fee_cannot_charge_delivery'))
363
+ errors.add(:include_shipping, :flat_fee_cannot_charge_delivery, message: I18n.t('spree.errors.messages.flat_fee_cannot_charge_delivery'))
361
364
  end
362
365
 
363
366
  def fixed_rate_states_an_amount
364
367
  return unless fixed?
365
368
  return if @pending_amounts.present? || commission_rate_values.any?
366
369
 
367
- errors.add(:base, :commission_rate_needs_an_amount, message: Spree.t('errors.messages.commission_rate_needs_an_amount'))
370
+ errors.add(:base, :commission_rate_needs_an_amount, message: I18n.t('spree.errors.messages.commission_rate_needs_an_amount'))
368
371
  end
369
372
  end
370
373
  end
@@ -41,7 +41,7 @@ module Spree
41
41
  return if max_amount.nil? || min_amount.nil?
42
42
  return if max_amount >= min_amount
43
43
 
44
- errors.add(:max_amount, :must_be_greater_than_min_amount, message: Spree.t('errors.messages.must_be_greater_than_min_amount'))
44
+ errors.add(:max_amount, :must_be_greater_than_min_amount, message: I18n.t('spree.errors.messages.must_be_greater_than_min_amount'))
45
45
  end
46
46
  end
47
47
  end
@@ -15,6 +15,9 @@ module Spree
15
15
  # setting. A rate with no rules charges every sale.
16
16
  class CommissionRule < Spree.base_class
17
17
  include Spree::PreferenceSchema
18
+ include Spree::TypeLabels
19
+
20
+ self.type_labels_scope = 'spree.commission_rule_types'
18
21
 
19
22
  has_prefix_id :comrule
20
23
 
@@ -47,16 +50,6 @@ module Spree
47
50
 
48
51
  registers_subclasses_via { Spree.commission_rules }
49
52
 
50
- # @return [String] the name an operator picks this rule kind by
51
- def self.human_name
52
- Spree.t("commission_rule_types.#{api_type}.name", default: name.demodulize.titleize)
53
- end
54
-
55
- # @return [String] what the rule does, shown beside the name in the picker
56
- def self.description
57
- Spree.t("commission_rule_types.#{api_type}.description", default: '')
58
- end
59
-
60
53
  # Whether this rule admits the sale.
61
54
  #
62
55
  # @param context [Spree::Commissions::Context]
@@ -71,7 +64,7 @@ module Spree
71
64
  return if type.blank?
72
65
  return if Spree.commission_rules.any? { |rule| rule.to_s == type }
73
66
 
74
- errors.add(:type, :invalid_commission_rule, message: Spree.t('errors.messages.invalid_commission_rule'))
67
+ errors.add(:type, :invalid_commission_rule, message: I18n.t('spree.errors.messages.invalid_commission_rule'))
75
68
  end
76
69
  end
77
70
  end
@@ -9,11 +9,8 @@ module Spree
9
9
  # restate the rule on every new leaf. The walk is done once per order by
10
10
  # Spree::Commissions::Context, not per rule.
11
11
  class CategoryRule < Spree::CommissionRule
12
- preference :category_ids, :array, default: [],
13
- parse_on_set: normalize_id_preference(
14
- klass: Spree::Category,
15
- scope: ->(rule) { rule.store.categories }
16
- )
12
+ preference :category_ids, :array, of: :id, model: 'Spree::Category', default: [],
13
+ scope: ->(rule) { rule.store.categories }
17
14
 
18
15
  # @return [Array<Spree::Category>]
19
16
  def categories
@@ -14,8 +14,8 @@ module Spree
14
14
  # This rule is the reason commission rules became classes. It could not
15
15
  # exist while a rule was only able to name a record.
16
16
  class ItemTotalRule < Spree::CommissionRule
17
- preference :min_amount, :decimal, nullable: true
18
- preference :max_amount, :decimal, nullable: true
17
+ preference :min_amount, :money, nullable: true
18
+ preference :max_amount, :money, nullable: true
19
19
 
20
20
  def applicable?(context)
21
21
  # Weighed exactly as the fee will weigh it, per this rate's own base.
@@ -48,7 +48,7 @@ module Spree
48
48
 
49
49
  return if store.products.where(id: chosen_ids).count == chosen_ids.uniq.size
50
50
 
51
- errors.add(:products, :product_not_in_store, message: Spree.t('errors.messages.product_not_in_store'))
51
+ errors.add(:products, :product_not_in_store, message: I18n.t('spree.errors.messages.product_not_in_store'))
52
52
  end
53
53
  end
54
54
  end
@@ -7,11 +7,8 @@ module Spree
7
7
  # Ids are checked against the rate's own store on write, so a rule can
8
8
  # never be pointed at another marketplace's seller — and the client is
9
9
  # told, rather than having the id quietly dropped.
10
- preference :seller_ids, :array, default: [],
11
- parse_on_set: normalize_id_preference(
12
- klass: Spree::Seller,
13
- scope: ->(rule) { rule.store.sellers }
14
- )
10
+ preference :seller_ids, :array, of: :id, model: 'Spree::Seller', default: [],
11
+ scope: ->(rule) { rule.store.sellers }
15
12
 
16
13
  # @return [Array<Spree::Seller>]
17
14
  def sellers
@@ -101,6 +101,7 @@ module Spree
101
101
  }
102
102
 
103
103
  self.whitelisted_ransackable_attributes = %w[name kind parent_id po_number_required]
104
+ search_by :name
104
105
  self.whitelisted_ransackable_associations = %w[parent children memberships external_references]
105
106
 
106
107
  # The node a buyer browses and buys as when they name none: the single
@@ -15,6 +15,7 @@ module Spree
15
15
  include Spree::Metadata
16
16
 
17
17
  publishes_lifecycle_events
18
+ publishes_events :accepted, :revoked
18
19
 
19
20
  EXPIRY = 30.days
20
21
 
@@ -42,7 +42,6 @@ module Spree
42
42
  SOURCES = [CHECKOUT, REGISTRATION, ACCOUNT, ADMIN, NEWSLETTER, ANONYMIZATION,
43
43
  UNKNOWN, 'import', 'storefront'].freeze
44
44
 
45
- belongs_to :store, class_name: 'Spree::Store'
46
45
  belongs_to :owner, polymorphic: true
47
46
 
48
47
  validates :purpose, presence: true
@@ -158,7 +158,7 @@ module Spree
158
158
  # Show the card brand, eg. "VISA", "MASTERCARD", etc.
159
159
  # @return [String]
160
160
  def display_brand
161
- brand.present? ? brand.upcase : Spree.t(:no_cc_type)
161
+ brand.present? ? brand.upcase : I18n.t('spree.no_cc_type')
162
162
  end
163
163
 
164
164
  # Returns the first name of the cardholder.
@@ -38,6 +38,29 @@ module Spree
38
38
  super || Spree::Store.default
39
39
  end
40
40
 
41
+ # Runs the block in +store+ from a clean context: nothing a previous store
42
+ # resolved (channel, market, currency, integrations, pricing) carries in,
43
+ # and nothing resolved inside leaks out. For work that walks several
44
+ # stores in one unit of work, such as an installation-wide sweep job; a
45
+ # request or a single-store job assigns #store once instead.
46
+ #
47
+ # The store scope guard stays armed afterwards, like any other store
48
+ # declaration in this unit of work.
49
+ #
50
+ # @param store [Spree::Store]
51
+ # @return [Object] the block's result
52
+ def with_store(store)
53
+ previous = attributes
54
+
55
+ begin
56
+ self.attributes = {}
57
+ self.store = store
58
+ yield
59
+ ensure
60
+ self.attributes = previous.merge(store_scope_guard_armed: store_scope_guard_armed)
61
+ end
62
+ end
63
+
41
64
  def channel
42
65
  super || (self.channel = store&.default_channel)
43
66
  end
@@ -128,7 +128,7 @@ module Spree
128
128
 
129
129
  unless type == custom_field_definition.field_type_class_name
130
130
  errors.add(:type, :custom_field_definition_mismatch,
131
- message: Spree.t('errors.messages.custom_field_definition_mismatch'))
131
+ message: I18n.t('spree.errors.messages.custom_field_definition_mismatch'))
132
132
  end
133
133
  end
134
134
 
@@ -144,7 +144,7 @@ module Spree
144
144
  return if definition_type.safe_constantize&.base_class&.name == resource_type
145
145
 
146
146
  errors.add(:resource_type, :custom_field_definition_mismatch,
147
- message: Spree.t('errors.messages.custom_field_definition_mismatch'))
147
+ message: I18n.t('spree.errors.messages.custom_field_definition_mismatch'))
148
148
  end
149
149
 
150
150
  # Definitions are store-owned, so a record may only carry its own store's.
@@ -25,20 +25,14 @@ module Spree
25
25
  scope :for_resource_type, ->(resource_type) { where(resource_type: resource_type) }
26
26
  scope :storefront_visible, -> { where(storefront_visible: true) }
27
27
  scope :admin_only, -> { where(storefront_visible: false) }
28
- scope :search, ->(query) do
29
- return all if query.blank?
30
-
31
- search_term = "%#{query.downcase}%"
32
- namespace_condition = arel_table[:namespace].lower.matches(search_term)
33
- key_condition = arel_table[:key].lower.matches(search_term)
34
- label_condition = arel_table[:label].lower.matches(search_term)
35
-
36
- where(namespace_condition.or(key_condition).or(label_condition))
37
- end
38
28
 
39
29
  #
40
30
  # Callbacks
41
31
  #
32
+ # The API names resources by shorthand (`product`); the column keeps the
33
+ # class name the custom fields themselves are stored under. Also applies to
34
+ # `where(resource_type:)`, so finders accept either.
35
+ normalizes :resource_type, with: ->(value) { Spree::Base.polymorphic_type_for(value, available_resources) || value }
42
36
  normalizes :key, with: ->(value) { value.to_s.parameterize.underscore.strip }
43
37
  normalizes :namespace, with: ->(value) { value.to_s.parameterize.underscore.strip }
44
38
  before_validation :set_default_type, if: -> { self[:field_type].blank? }, on: :create
@@ -48,8 +42,17 @@ module Spree
48
42
  #
49
43
  # Ransack
50
44
  #
51
- self.whitelisted_ransackable_attributes = %w[key namespace label resource_type storefront_visible searchable sortable]
52
- self.whitelisted_ransackable_scopes = %w[search]
45
+ self.whitelisted_ransackable_attributes = %w[key namespace label resource_type field_type storefront_visible searchable sortable]
46
+
47
+ # Both columns store class names; filters take the short names clients see.
48
+ def self.api_type_resolver(attribute)
49
+ case attribute
50
+ when 'resource_type' then ->(api_type) { normalize_value_for(:resource_type, api_type) }
51
+ when 'field_type' then ->(api_type) { Spree::CustomField::TYPE_TOKENS[api_type] }
52
+ else super
53
+ end
54
+ end
55
+ search_by :namespace, :key, :label
53
56
 
54
57
  # API-facing token for the STI subclass name stored in the `field_type`
55
58
  # column. Reader returns the registered token (`short_text`); writer
@@ -117,25 +120,13 @@ module Spree
117
120
  # as the API names it, so a client renders a picker rather than carrying
118
121
  # its own list that drifts from the registry.
119
122
  #
120
- # `Spree::Category` reports itself as `Spree::Taxon`: existing category
121
- # definitions are stored under the old class name, and offering the new
122
- # one would file a merchant's next definition somewhere the category card
123
- # does not read. Drops with the alias in 6.1.
124
- #
125
- # @return [Array<Hash{Symbol => String}>] `resource_type` + `name`
123
+ # @return [Array<Hash{Symbol => String}>] `resource_type` shorthand + `name`
126
124
  def self.enabled_resource_types
127
125
  # Through `available_resources`, not the registry directly: that is the
128
126
  # accessor the rest of the class reads, so discovery and validation
129
127
  # cannot disagree about what a host app has made available.
130
- Array(available_resources).filter_map do |resource|
131
- next if resource.nil?
132
-
133
- # The label follows the class a merchant knows; the wire value follows
134
- # where the rows are actually stored.
135
- name = resource.to_s.demodulize.titleize.pluralize
136
- resource_type = resource.to_s == 'Spree::Category' ? 'Spree::Taxon' : resource.to_s
137
-
138
- { resource_type: resource_type, name: name }
128
+ Array(available_resources).compact.map do |resource|
129
+ { resource_type: Spree::Base.polymorphic_api_type(resource), name: resource.to_s.demodulize.titleize.pluralize }
139
130
  end.uniq { |entry| entry[:resource_type] }.sort_by { |entry| entry[:name] }
140
131
  end
141
132
 
@@ -174,7 +165,7 @@ module Spree
174
165
 
175
166
  tokens = Spree::CustomField::TYPE_TOKENS.keys.join(', ')
176
167
  errors.add(:field_type, :unknown_custom_field_type, types: tokens,
177
- message: Spree.t('errors.messages.unknown_custom_field_type', types: tokens))
168
+ message: I18n.t('spree.errors.messages.unknown_custom_field_type', types: tokens))
178
169
  end
179
170
 
180
171
  # Validates the stored class name, not the token the reader returns.
@@ -186,14 +177,8 @@ module Spree
186
177
  errors.add(:field_type, :inclusion)
187
178
  end
188
179
 
189
- # Both the registry's own names and the ones discovery offers: a value a
190
- # client was offered has to be accepted, and the two differ where a class
191
- # has been renamed (categories are stored under Spree::Taxon while the
192
- # registry holds Spree::Category). Existing callers name either, so
193
- # narrowing to one would reject definitions that already work.
194
180
  def valid_available_resources
195
- self.class.available_resources.map(&:to_s) |
196
- self.class.enabled_resource_types.map { |resource| resource[:resource_type] }
181
+ self.class.available_resources.map(&:to_s)
197
182
  end
198
183
 
199
184
  def set_default_type
@@ -4,7 +4,7 @@ module Spree
4
4
  normalizes :value, with: ->(value) { value.to_b.to_s }
5
5
 
6
6
  def csv_value
7
- value.to_b ? Spree.t(:say_yes) : Spree.t(:say_no)
7
+ value.to_b ? I18n.t('spree.say_yes') : I18n.t('spree.say_no')
8
8
  end
9
9
 
10
10
  def serialize_value
@@ -31,7 +31,7 @@ module Spree
31
31
  JSON.parse(value)
32
32
  rescue JSON::ParserError => e
33
33
  errors.add(:value, :invalid_json, detail: e.message,
34
- message: Spree.t('errors.messages.invalid_json', detail: e.message))
34
+ message: I18n.t('spree.errors.messages.invalid_json', detail: e.message))
35
35
  end
36
36
  end
37
37
  end
@@ -5,6 +5,7 @@ module Spree
5
5
  acts_as_paranoid
6
6
 
7
7
  include Spree::SingleStoreResource
8
+ search_by :name
8
9
 
9
10
  #
10
11
  # Associations
@@ -1,5 +1,3 @@
1
- require_dependency 'spree/data_feed'
2
-
3
1
  module Spree
4
2
  class DataFeed::Google < DataFeed
5
3
  class << self
@@ -19,6 +19,7 @@ module Spree
19
19
  has_spree_number prefix: 'DSR'
20
20
 
21
21
  publishes_lifecycle_events
22
+ publishes_event :completed
22
23
 
23
24
  include Spree::HasStatus
24
25
  has_status :pending, :processing, :completed, :failed, default: :pending
@@ -37,7 +38,6 @@ module Spree
37
38
  # asked, and it stops working when the request expires.
38
39
  has_secure_token :download_token
39
40
 
40
- belongs_to :store, class_name: 'Spree::Store'
41
41
  belongs_to :customer, class_name: Spree.customer_class.to_s
42
42
  # Null when the subject asked for it themselves; set when staff acted on a
43
43
  # request that arrived by email.
@@ -56,6 +56,7 @@ module Spree
56
56
 
57
57
  self.whitelisted_ransackable_attributes = %w[number kind status email requested_at completed_at]
58
58
  self.whitelisted_ransackable_scopes = %w[access erasure in_progress]
59
+ self.ransackable_scope_types = %w[access erasure in_progress].index_with('boolean')
59
60
 
60
61
  before_validation :set_defaults, on: :create
61
62
 
@@ -80,6 +80,12 @@ module Spree
80
80
  after_save :apply_pending_services, if: :pending_services?
81
81
  attribute :fulfillment_provider, :string, default: 'Spree::FulfillmentProvider::Manual'
82
82
 
83
+ # The API names providers by their shorthand (`manual`, `easy_post`); the
84
+ # columns keep the class name.
85
+ normalizes :fulfillment_provider, with: ->(value) { Spree::ApiTyped.class_name_for(Spree.fulfillment_providers, value) }
86
+ normalizes :rate_provider, with: ->(value) { Spree::ApiTyped.class_name_for(Spree.delivery_rate_providers, value) }
87
+ normalizes :pickup_point_provider, with: ->(value) { Spree::ApiTyped.class_name_for(Spree.pickup_point_providers, value) }
88
+
83
89
  # Methods whose fulfillment provider satisfies the predicate — behavior
84
90
  # queries route through provider classes, never string vocabularies.
85
91
  scope :with_provider, ->(predicate) {
@@ -116,6 +122,7 @@ module Spree
116
122
  # needed. `seller_id` is what the operator's list filters by to see one
117
123
  # seller's methods, or (blank) the marketplace's own.
118
124
  self.whitelisted_ransackable_attributes = %w[storefront_visible available_to_sellers seller_id]
125
+ search_by :name
119
126
  self.whitelisted_ransackable_associations = %w[seller]
120
127
 
121
128
  validates :name, presence: true
@@ -138,6 +145,16 @@ module Spree
138
145
  # not save a provider whose integration isn't connected — that breaks
139
146
  # quoting at checkout, not at save time where the admin can see it.
140
147
  validate :rate_provider_must_be_available, if: :rate_provider_changed?
148
+ # Every provider column is constantized and instantiated at checkout or
149
+ # ship time, so only a registered class may be stored.
150
+ validates :fulfillment_provider,
151
+ inclusion: { in: -> (_record) { Spree.fulfillment_providers.map(&:to_s) } },
152
+ allow_blank: true,
153
+ if: :fulfillment_provider_changed?
154
+ validates :pickup_point_provider,
155
+ inclusion: { in: -> (_record) { Spree.pickup_point_providers.map(&:to_s) } },
156
+ allow_blank: true,
157
+ if: :pickup_point_provider_changed?
141
158
  # Providers declare the fulfillment types they handle; a mismatch would
142
159
  # only surface at checkout (no rates) or at ship time (no dispatch),
143
160
  # so reject it where the admin can still see why.
@@ -211,7 +228,11 @@ module Spree
211
228
  end
212
229
 
213
230
  def ensure_calculator
214
- self.calculator ||= Spree::Calculator::Shipping::FlatRate.new(preferred_amount: 0)
231
+ self.calculator ||= default_calculator
232
+ end
233
+
234
+ def default_calculator
235
+ Spree::Calculator::Shipping::FlatRate.new(preferred_amount: 0)
215
236
  end
216
237
 
217
238
  def assign_default_delivery_profile
@@ -234,7 +255,7 @@ module Spree
234
255
  return if delivery_zone.delivery_origin_group_id == delivery_origin_group_id
235
256
 
236
257
  errors.add(:delivery_zone, :does_not_belong_to_origin_group,
237
- message: Spree.t('errors.messages.delivery_zone_not_in_origin_group'))
258
+ message: I18n.t('spree.errors.messages.delivery_zone_not_in_origin_group'))
238
259
  end
239
260
 
240
261
  def pickup_point?
@@ -263,7 +284,7 @@ module Spree
263
284
  #
264
285
  # @return [Class]
265
286
  def provider_class
266
- (fulfillment_provider.presence || DEFAULT_FULFILLMENT_PROVIDER).safe_constantize ||
287
+ Spree::ApiTyped.registered_class(Spree.fulfillment_providers, fulfillment_provider.presence || DEFAULT_FULFILLMENT_PROVIDER) ||
267
288
  DEFAULT_FULFILLMENT_PROVIDER.constantize
268
289
  end
269
290
 
@@ -286,7 +307,8 @@ module Spree
286
307
  #
287
308
  # @return [Class]
288
309
  def rate_provider_class
289
- (rate_provider.presence || DEFAULT_RATE_PROVIDER).safe_constantize || DEFAULT_RATE_PROVIDER.constantize
310
+ Spree::ApiTyped.registered_class(Spree.delivery_rate_providers, rate_provider.presence || DEFAULT_RATE_PROVIDER) ||
311
+ DEFAULT_RATE_PROVIDER.constantize
290
312
  end
291
313
 
292
314
 
@@ -363,7 +385,7 @@ module Spree
363
385
  #
364
386
  # @return [Spree::PickupPointProvider::Base, nil]
365
387
  def pickup_point_provider_instance
366
- @pickup_point_provider_instance ||= pickup_point_provider.presence&.constantize&.new
388
+ @pickup_point_provider_instance ||= Spree::ApiTyped.registered_class(Spree.pickup_point_providers, pickup_point_provider)&.new
367
389
  end
368
390
 
369
391
  def self.calculators
@@ -430,14 +452,14 @@ module Spree
430
452
 
431
453
  if calculator.is_a?(Spree::Calculator::Shipping::FlatRate)
432
454
  if calculator.preferred_amount == 0
433
- Spree.t(:free)
455
+ I18n.t('spree.free')
434
456
  else
435
457
  Spree::Money.new(calculator.preferred_amount, { currency: calculator.preferred_currency }).to_s
436
458
  end
437
459
  elsif calculator.is_a?(Spree::Calculator::Shipping::FlexiRate)
438
460
  Spree::Money.new(calculator.preferred_first_item, { currency: calculator.preferred_currency }).to_s
439
461
  elsif calculator.is_a?(Spree::Calculator::Shipping::FlatPercentItemTotal)
440
- ActionController::Base.helpers.number_to_percentage(calculator.preferred_flat_percent, precision: 2)
462
+ ActiveSupport::NumberHelper.number_to_percentage(calculator.preferred_flat_percent, precision: 2)
441
463
  else
442
464
  ''
443
465
  end
@@ -500,7 +522,7 @@ module Spree
500
522
  return if delivery_zone.delivery_profile_id == delivery_profile_id
501
523
 
502
524
  errors.add(:delivery_zone, :does_not_belong_to_profile,
503
- message: Spree.t('errors.messages.delivery_zone_not_in_profile'))
525
+ message: I18n.t('spree.errors.messages.delivery_zone_not_in_profile'))
504
526
  end
505
527
 
506
528
  def profile_must_accept_provider
@@ -513,7 +535,7 @@ module Spree
513
535
  errors.add(
514
536
  :fulfillment_provider, :profile_does_not_accept_provider,
515
537
  provider: provider_class.provider_name, profile: delivery_profile.name,
516
- message: Spree.t('errors.messages.profile_does_not_accept_provider',
538
+ message: I18n.t('spree.errors.messages.profile_does_not_accept_provider',
517
539
  provider: provider_class.provider_name, profile: delivery_profile.name)
518
540
  )
519
541
  end
@@ -527,7 +549,7 @@ module Spree
527
549
  errors.add(
528
550
  :rate_provider, :rate_provider_requires_shipping,
529
551
  provider: rate_provider_class.provider_name,
530
- message: Spree.t('errors.messages.rate_provider_requires_shipping',
552
+ message: I18n.t('spree.errors.messages.rate_provider_requires_shipping',
531
553
  provider: rate_provider_class.provider_name)
532
554
  )
533
555
  end
@@ -537,7 +559,7 @@ module Spree
537
559
  return unless Spree.delivery_rate_providers.map(&:to_s).include?(rate_provider)
538
560
  return if rate_provider_class.available_for_store?(store)
539
561
 
540
- errors.add(:rate_provider, :rate_provider_unavailable, message: Spree.t('errors.messages.rate_provider_unavailable'))
562
+ errors.add(:rate_provider, :rate_provider_unavailable, message: I18n.t('spree.errors.messages.rate_provider_unavailable'))
541
563
  end
542
564
 
543
565
  def seller_must_belong_to_store
@@ -549,18 +571,18 @@ module Spree
549
571
 
550
572
  def seller_methods_use_own_providers
551
573
  unless rate_provider.blank? || rate_provider == DEFAULT_RATE_PROVIDER
552
- errors.add(:rate_provider, :seller_delivery_method_provider, message: Spree.t('errors.messages.seller_delivery_method_provider'))
574
+ errors.add(:rate_provider, :seller_delivery_method_provider, message: I18n.t('spree.errors.messages.seller_delivery_method_provider'))
553
575
  end
554
576
 
555
577
  return if fulfillment_provider.blank? || fulfillment_provider == DEFAULT_FULFILLMENT_PROVIDER
556
578
 
557
- errors.add(:fulfillment_provider, :seller_delivery_method_provider, message: Spree.t('errors.messages.seller_delivery_method_provider'))
579
+ errors.add(:fulfillment_provider, :seller_delivery_method_provider, message: I18n.t('spree.errors.messages.seller_delivery_method_provider'))
558
580
  end
559
581
 
560
582
  def only_marketplace_methods_are_shared
561
583
  return unless available_to_sellers? && seller_owned?
562
584
 
563
- errors.add(:available_to_sellers, :seller_delivery_method_not_shareable, message: Spree.t('errors.messages.seller_delivery_method_not_shareable'))
585
+ errors.add(:available_to_sellers, :seller_delivery_method_not_shareable, message: I18n.t('spree.errors.messages.seller_delivery_method_not_shareable'))
564
586
  end
565
587
  end
566
588
  end
@@ -7,6 +7,9 @@ module Spree
7
7
  # See docs/plans/6.0-delivery-method-rules.md.
8
8
  class DeliveryMethodRule < Spree.base_class
9
9
  include Spree::PreferenceSchema
10
+ include Spree::TypeLabels
11
+
12
+ self.type_labels_scope = 'spree.delivery_method_rule_types'
10
13
 
11
14
  has_prefix_id :dmrule
12
15
 
@@ -27,16 +30,6 @@ module Spree
27
30
 
28
31
  registers_subclasses_via { Spree.delivery_method_rules }
29
32
 
30
- # @return [String] localized display name for the rule kind, used by admin pickers
31
- def self.human_name
32
- Spree.t("delivery_method_rule_types.#{api_type}.name", default: api_type.titleize)
33
- end
34
-
35
- # @return [String] localized description for the rule kind
36
- def self.human_description
37
- Spree.t("delivery_method_rule_types.#{api_type}.description", default: '')
38
- end
39
-
40
33
  # @param package [Spree::Stock::Package]
41
34
  # @return [Boolean]
42
35
  def eligible?(_package)
@@ -49,7 +42,7 @@ module Spree
49
42
  return if type.blank?
50
43
  return if Spree.delivery_method_rules.any? { |rule| rule.to_s == type }
51
44
 
52
- errors.add(:type, :invalid_delivery_method_rule, message: Spree.t(:invalid_delivery_method_rule, scope: [:errors, :messages], default: 'is not a registered delivery method rule'))
45
+ errors.add(:type, :invalid_delivery_method_rule, message: I18n.t('spree.errors.messages.invalid_delivery_method_rule'))
53
46
  end
54
47
  end
55
48
  end