spree_core 5.2.6 → 5.3.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 (294) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/spree/addresses_helper.rb +1 -23
  3. data/app/helpers/spree/base_helper.rb +25 -77
  4. data/app/helpers/spree/currency_helper.rb +2 -2
  5. data/app/helpers/spree/images_helper.rb +5 -0
  6. data/app/helpers/spree/mail_helper.rb +1 -1
  7. data/app/helpers/spree/products_helper.rb +1 -1
  8. data/app/jobs/spree/events/subscriber_job.rb +58 -0
  9. data/app/jobs/spree/products/refresh_metrics_job.rb +14 -0
  10. data/app/jobs/spree/products/touch_taxons_job.rb +0 -1
  11. data/app/jobs/spree/variants/touch_job.rb +9 -0
  12. data/app/models/concerns/spree/adjustment_source.rb +8 -0
  13. data/app/models/concerns/spree/parameterizable_name.rb +1 -1
  14. data/app/models/concerns/spree/product_scopes.rb +54 -8
  15. data/app/models/concerns/spree/publishable.rb +253 -0
  16. data/app/models/concerns/spree/unique_name.rb +1 -1
  17. data/app/models/concerns/spree/user_methods.rb +21 -1
  18. data/app/models/spree/ability.rb +3 -3
  19. data/app/models/spree/address.rb +0 -3
  20. data/app/models/spree/adjustable/promotion_accumulator.rb +1 -1
  21. data/app/models/spree/adjustment.rb +32 -6
  22. data/app/models/spree/asset.rb +6 -3
  23. data/app/models/spree/base.rb +3 -1
  24. data/app/models/spree/classification.rb +2 -2
  25. data/app/models/spree/credit_card.rb +0 -3
  26. data/app/models/spree/current.rb +24 -3
  27. data/app/models/spree/custom_domain.rb +1 -1
  28. data/app/models/spree/customer_group.rb +94 -0
  29. data/app/models/spree/customer_group_user.rb +16 -0
  30. data/app/models/spree/customer_return.rb +2 -3
  31. data/app/models/spree/digital.rb +2 -4
  32. data/app/models/spree/digital_link.rb +2 -3
  33. data/app/models/spree/event.rb +104 -0
  34. data/app/models/spree/export.rb +7 -1
  35. data/app/models/spree/gift_card.rb +13 -1
  36. data/app/models/spree/gift_card_batch.rb +3 -1
  37. data/app/models/spree/image.rb +20 -5
  38. data/app/models/spree/import.rb +17 -12
  39. data/app/models/spree/import_row.rb +13 -26
  40. data/app/models/spree/inventory_unit.rb +0 -3
  41. data/app/models/spree/invitation.rb +12 -6
  42. data/app/models/spree/line_item.rb +57 -4
  43. data/app/models/spree/newsletter_subscriber.rb +2 -0
  44. data/app/models/spree/option_type.rb +2 -5
  45. data/app/models/spree/option_value.rb +1 -4
  46. data/app/models/spree/order/checkout.rb +7 -2
  47. data/app/models/spree/order/emails.rb +3 -11
  48. data/app/models/spree/order/store_credit.rb +5 -1
  49. data/app/models/spree/order.rb +80 -31
  50. data/app/models/spree/order_updater.rb +28 -9
  51. data/app/models/spree/payment/custom_events.rb +37 -0
  52. data/app/models/spree/payment.rb +13 -4
  53. data/app/models/spree/payment_capture_event.rb +0 -4
  54. data/app/models/spree/payment_method.rb +1 -1
  55. data/app/models/spree/permission_sets/default_customer.rb +3 -3
  56. data/app/models/spree/policy.rb +1 -8
  57. data/app/models/spree/post.rb +2 -7
  58. data/app/models/spree/post_category.rb +2 -0
  59. data/app/models/spree/price.rb +8 -6
  60. data/app/models/spree/price_list.rb +263 -0
  61. data/app/models/spree/price_rule.rb +26 -0
  62. data/app/models/spree/price_rules/customer_group_rule.rb +21 -0
  63. data/app/models/spree/price_rules/user_rule.rb +19 -0
  64. data/app/models/spree/price_rules/volume_rule.rb +21 -0
  65. data/app/models/spree/price_rules/zone_rule.rb +19 -0
  66. data/app/models/spree/product.rb +117 -76
  67. data/app/models/spree/product_property.rb +2 -2
  68. data/app/models/spree/promotion/rules/customer_group.rb +22 -0
  69. data/app/models/spree/promotion/rules/user.rb +2 -2
  70. data/app/models/spree/promotion.rb +3 -4
  71. data/app/models/spree/promotion_handler/coupon.rb +3 -3
  72. data/app/models/spree/property.rb +3 -6
  73. data/app/models/spree/prototype.rb +0 -3
  74. data/app/models/spree/refund.rb +2 -3
  75. data/app/models/spree/reimbursement.rb +5 -3
  76. data/app/models/spree/report.rb +7 -1
  77. data/app/models/spree/reports/products_performance.rb +1 -1
  78. data/app/models/spree/reports/sales_total.rb +1 -1
  79. data/app/models/spree/return_authorization.rb +7 -3
  80. data/app/models/spree/return_item.rb +15 -4
  81. data/app/models/spree/shipment/custom_events.rb +47 -0
  82. data/app/models/spree/shipment.rb +12 -5
  83. data/app/models/spree/shipping_category.rb +0 -3
  84. data/app/models/spree/shipping_method.rb +0 -3
  85. data/app/models/spree/stock/quantifier.rb +1 -1
  86. data/app/models/spree/stock_item.rb +2 -0
  87. data/app/models/spree/stock_location.rb +0 -3
  88. data/app/models/spree/stock_movement/custom_events.rb +44 -0
  89. data/app/models/spree/stock_movement.rb +3 -0
  90. data/app/models/spree/stock_transfer.rb +2 -3
  91. data/app/models/spree/store.rb +64 -92
  92. data/app/models/spree/store_credit.rb +3 -4
  93. data/app/models/spree/store_product.rb +14 -0
  94. data/app/models/spree/subscriber.rb +186 -0
  95. data/app/models/spree/tax_category.rb +0 -4
  96. data/app/models/spree/tax_rate.rb +0 -3
  97. data/app/models/spree/taxon.rb +3 -36
  98. data/app/models/spree/taxonomy.rb +0 -3
  99. data/app/models/spree/variant.rb +114 -21
  100. data/app/models/spree/webhook_delivery.rb +60 -0
  101. data/app/models/spree/webhook_endpoint.rb +53 -0
  102. data/app/models/spree/wished_item.rb +2 -4
  103. data/app/models/spree/wishlist.rb +2 -3
  104. data/app/models/spree/zone.rb +0 -9
  105. data/app/paginators/spree/shared/paginate.rb +4 -0
  106. data/app/serializers/spree/events/asset_serializer.rb +22 -0
  107. data/app/serializers/spree/events/base_serializer.rb +61 -0
  108. data/app/serializers/spree/events/customer_return_serializer.rb +20 -0
  109. data/app/serializers/spree/events/digital_link_serializer.rb +20 -0
  110. data/app/serializers/spree/events/digital_serializer.rb +18 -0
  111. data/app/serializers/spree/events/export_serializer.rb +22 -0
  112. data/app/serializers/spree/events/gift_card_batch_serializer.rb +24 -0
  113. data/app/serializers/spree/events/gift_card_serializer.rb +29 -0
  114. data/app/serializers/spree/events/image_serializer.rb +9 -0
  115. data/app/serializers/spree/events/import_row_serializer.rb +23 -0
  116. data/app/serializers/spree/events/import_serializer.rb +24 -0
  117. data/app/serializers/spree/events/invitation_serializer.rb +28 -0
  118. data/app/serializers/spree/events/line_item_serializer.rb +31 -0
  119. data/app/serializers/spree/events/newsletter_subscriber_serializer.rb +21 -0
  120. data/app/serializers/spree/events/order_serializer.rb +39 -0
  121. data/app/serializers/spree/events/payment_serializer.rb +24 -0
  122. data/app/serializers/spree/events/post_category_serializer.rb +20 -0
  123. data/app/serializers/spree/events/post_serializer.rb +26 -0
  124. data/app/serializers/spree/events/price_serializer.rb +22 -0
  125. data/app/serializers/spree/events/product_serializer.rb +24 -0
  126. data/app/serializers/spree/events/promotion_serializer.rb +32 -0
  127. data/app/serializers/spree/events/refund_serializer.rb +23 -0
  128. data/app/serializers/spree/events/reimbursement_serializer.rb +22 -0
  129. data/app/serializers/spree/events/report_serializer.rb +23 -0
  130. data/app/serializers/spree/events/return_authorization_serializer.rb +22 -0
  131. data/app/serializers/spree/events/return_item_serializer.rb +27 -0
  132. data/app/serializers/spree/events/shipment_serializer.rb +24 -0
  133. data/app/serializers/spree/events/stock_item_serializer.rb +22 -0
  134. data/app/serializers/spree/events/stock_movement_serializer.rb +22 -0
  135. data/app/serializers/spree/events/stock_transfer_serializer.rb +22 -0
  136. data/app/serializers/spree/events/store_credit_serializer.rb +30 -0
  137. data/app/serializers/spree/events/user_serializer.rb +18 -0
  138. data/app/serializers/spree/events/variant_serializer.rb +34 -0
  139. data/app/serializers/spree/events/wished_item_serializer.rb +20 -0
  140. data/app/serializers/spree/events/wishlist_serializer.rb +22 -0
  141. data/app/services/spree/addresses/update.rb +1 -1
  142. data/app/services/spree/cart/add_item.rb +1 -1
  143. data/app/services/spree/coupon_codes/coupon_codes_handler.rb +2 -1
  144. data/app/services/spree/data_feeds/google/required_attributes.rb +4 -4
  145. data/app/services/spree/newsletter/verify.rb +5 -0
  146. data/app/services/spree/products/auto_match_taxons.rb +1 -1
  147. data/app/services/spree/seeds/all.rb +1 -1
  148. data/app/services/spree/taxons/add_products.rb +8 -4
  149. data/app/services/spree/taxons/regenerate_products.rb +8 -0
  150. data/app/services/spree/taxons/remove_products.rb +12 -7
  151. data/app/subscribers/spree/event_log_subscriber.rb +64 -0
  152. data/app/subscribers/spree/export_subscriber.rb +26 -0
  153. data/app/subscribers/spree/invitation_email_subscriber.rb +40 -0
  154. data/app/subscribers/spree/product_metrics_subscriber.rb +29 -0
  155. data/app/subscribers/spree/report_subscriber.rb +26 -0
  156. data/config/locales/en.yml +126 -0
  157. data/db/migrate/20251110120000_create_spree_price_lists.rb +22 -0
  158. data/db/migrate/20251110120001_create_spree_price_rules.rb +13 -0
  159. data/db/migrate/20251110120002_add_price_list_id_to_spree_prices.rb +6 -0
  160. data/db/migrate/20251110120003_add_price_list_id_to_spree_line_items.rb +5 -0
  161. data/db/migrate/20251201172118_fix_indexes_on_friendly_id_slugs.rb +8 -0
  162. data/db/migrate/20251214000001_create_spree_webhook_endpoints.rb +19 -0
  163. data/db/migrate/20251214000002_create_spree_webhook_deliveries.rb +23 -0
  164. data/db/migrate/20251222000000_add_performance_indexes_to_spree_adjustments.rb +25 -0
  165. data/db/migrate/20260112000000_fix_spree_prices_unique_indexes.rb +33 -0
  166. data/db/migrate/20260115120000_create_spree_customer_groups.rb +14 -0
  167. data/db/migrate/20260115120001_create_spree_customer_group_users.rb +14 -0
  168. data/db/migrate/20260117140831_remove_not_null_constraint_from_policy_name.rb +5 -0
  169. data/db/migrate/20260118120000_add_statistics_to_store_products.rb +11 -0
  170. data/db/migrate/20260119120000_add_counter_caches_to_spree_products.rb +9 -0
  171. data/db/migrate/20260119170000_add_counter_caches_to_spree_taxons.rb +9 -0
  172. data/db/migrate/20260120120000_add_image_count_to_spree_variants.rb +9 -0
  173. data/lib/generators/spree/dummy/dummy_generator.rb +14 -2
  174. data/lib/spree/core/configuration.rb +1 -0
  175. data/lib/spree/core/controller_helpers/auth.rb +0 -15
  176. data/lib/spree/core/controller_helpers/currency.rb +13 -9
  177. data/lib/spree/core/controller_helpers/search.rb +1 -1
  178. data/lib/spree/core/controller_helpers/store.rb +5 -1
  179. data/lib/spree/core/engine.rb +61 -78
  180. data/lib/spree/core/importer/order.rb +1 -1
  181. data/lib/spree/core/importer/product.rb +1 -1
  182. data/lib/spree/core/preferences/preferable.rb +14 -1
  183. data/lib/spree/core/pricing/context.rb +63 -0
  184. data/lib/spree/core/pricing/resolver.rb +129 -0
  185. data/lib/spree/core/search/base.rb +1 -1
  186. data/lib/spree/core/token_generator.rb +1 -1
  187. data/lib/spree/core/version.rb +1 -1
  188. data/lib/spree/core.rb +42 -47
  189. data/lib/spree/events/adapters/active_support_notifications.rb +112 -0
  190. data/lib/spree/events/adapters/base.rb +193 -0
  191. data/lib/spree/events/registry.rb +99 -0
  192. data/lib/spree/events.rb +240 -0
  193. data/lib/spree/permitted_attributes.rb +13 -2
  194. data/lib/spree/testing_support/common_rake.rb +68 -35
  195. data/lib/spree/testing_support/factories/customer_group_factory.rb +6 -0
  196. data/lib/spree/testing_support/factories/customer_group_user_factory.rb +6 -0
  197. data/lib/spree/testing_support/factories/price_factory.rb +4 -0
  198. data/lib/spree/testing_support/factories/price_list_factory.rb +34 -0
  199. data/lib/spree/testing_support/factories/price_rule_factory.rb +49 -0
  200. data/lib/spree/testing_support/factories/promotion_rule_factory.rb +12 -0
  201. data/lib/spree/testing_support/factories/stock_item_factory.rb +6 -4
  202. data/lib/spree/testing_support/factories/store_product_factory.rb +6 -0
  203. data/lib/spree/testing_support/factories/taxon_factory.rb +0 -1
  204. data/lib/spree/testing_support/factories/webhook_delivery_factory.rb +48 -0
  205. data/lib/spree/testing_support/factories/webhook_endpoint_factory.rb +22 -0
  206. data/lib/spree/testing_support/lifecycle_events.rb +38 -0
  207. data/lib/spree/testing_support/store.rb +4 -2
  208. data/lib/spree/webhooks.rb +22 -0
  209. data/lib/tasks/products.rake +40 -0
  210. data/lib/tasks/taxons.rake +19 -0
  211. data/lib/tasks/variants.rake +18 -0
  212. metadata +112 -114
  213. data/app/jobs/spree/themes/duplicate_components_job.rb +0 -59
  214. data/app/jobs/spree/themes/screenshot_job.rb +0 -81
  215. data/app/models/concerns/spree/has_page_links.rb +0 -53
  216. data/app/models/spree/page.rb +0 -188
  217. data/app/models/spree/page_block.rb +0 -73
  218. data/app/models/spree/page_blocks/buttons.rb +0 -29
  219. data/app/models/spree/page_blocks/heading.rb +0 -18
  220. data/app/models/spree/page_blocks/image.rb +0 -20
  221. data/app/models/spree/page_blocks/link.rb +0 -21
  222. data/app/models/spree/page_blocks/mega_nav.rb +0 -33
  223. data/app/models/spree/page_blocks/mega_nav_with_subcategories.rb +0 -32
  224. data/app/models/spree/page_blocks/metafields.rb +0 -18
  225. data/app/models/spree/page_blocks/nav.rb +0 -15
  226. data/app/models/spree/page_blocks/newsletter_form.rb +0 -18
  227. data/app/models/spree/page_blocks/products/brand.rb +0 -15
  228. data/app/models/spree/page_blocks/products/buy_buttons.rb +0 -24
  229. data/app/models/spree/page_blocks/products/description.rb +0 -18
  230. data/app/models/spree/page_blocks/products/price.rb +0 -18
  231. data/app/models/spree/page_blocks/products/quantity_selector.rb +0 -20
  232. data/app/models/spree/page_blocks/products/share.rb +0 -8
  233. data/app/models/spree/page_blocks/products/title.rb +0 -19
  234. data/app/models/spree/page_blocks/products/variant_picker.rb +0 -13
  235. data/app/models/spree/page_blocks/subheading.rb +0 -17
  236. data/app/models/spree/page_blocks/text.rb +0 -16
  237. data/app/models/spree/page_link.rb +0 -60
  238. data/app/models/spree/page_section.rb +0 -222
  239. data/app/models/spree/page_sections/announcement_bar.rb +0 -28
  240. data/app/models/spree/page_sections/breadcrumbs.rb +0 -12
  241. data/app/models/spree/page_sections/collection_banner.rb +0 -18
  242. data/app/models/spree/page_sections/custom_code.rb +0 -11
  243. data/app/models/spree/page_sections/featured_posts.rb +0 -45
  244. data/app/models/spree/page_sections/featured_product.rb +0 -50
  245. data/app/models/spree/page_sections/featured_taxon.rb +0 -90
  246. data/app/models/spree/page_sections/featured_taxons.rb +0 -45
  247. data/app/models/spree/page_sections/footer.rb +0 -101
  248. data/app/models/spree/page_sections/header.rb +0 -62
  249. data/app/models/spree/page_sections/image_banner.rb +0 -55
  250. data/app/models/spree/page_sections/image_with_text.rb +0 -65
  251. data/app/models/spree/page_sections/main_password_footer.rb +0 -18
  252. data/app/models/spree/page_sections/main_password_header.rb +0 -20
  253. data/app/models/spree/page_sections/newsletter.rb +0 -54
  254. data/app/models/spree/page_sections/page_title.rb +0 -19
  255. data/app/models/spree/page_sections/post_details.rb +0 -19
  256. data/app/models/spree/page_sections/post_grid.rb +0 -19
  257. data/app/models/spree/page_sections/product_details.rb +0 -53
  258. data/app/models/spree/page_sections/product_grid.rb +0 -13
  259. data/app/models/spree/page_sections/related_products.rb +0 -58
  260. data/app/models/spree/page_sections/rich_text.rb +0 -31
  261. data/app/models/spree/page_sections/taxon_banner.rb +0 -18
  262. data/app/models/spree/page_sections/taxon_grid.rb +0 -17
  263. data/app/models/spree/page_sections/video.rb +0 -107
  264. data/app/models/spree/pages/account.rb +0 -19
  265. data/app/models/spree/pages/cart.rb +0 -19
  266. data/app/models/spree/pages/checkout.rb +0 -15
  267. data/app/models/spree/pages/custom.rb +0 -38
  268. data/app/models/spree/pages/homepage.rb +0 -72
  269. data/app/models/spree/pages/login.rb +0 -19
  270. data/app/models/spree/pages/password.rb +0 -59
  271. data/app/models/spree/pages/post.rb +0 -27
  272. data/app/models/spree/pages/post_list.rb +0 -36
  273. data/app/models/spree/pages/product_details.rb +0 -30
  274. data/app/models/spree/pages/search_results.rb +0 -43
  275. data/app/models/spree/pages/shop_all.rb +0 -40
  276. data/app/models/spree/pages/taxon.rb +0 -29
  277. data/app/models/spree/pages/taxon_list.rb +0 -41
  278. data/app/models/spree/pages/wishlist.rb +0 -15
  279. data/app/models/spree/theme.rb +0 -233
  280. data/app/models/spree/themes/default.rb +0 -97
  281. data/app/services/spree/taxons/touch_featured_sections.rb +0 -21
  282. data/db/migrate/20250120094216_create_page_builder_models.rb +0 -78
  283. data/db/migrate/20250305121352_remove_page_builder_indices.rb +0 -11
  284. data/db/migrate/20250825175217_add_missing_page_builder_indexes.rb +0 -7
  285. data/db/migrate/20250913130044_add_page_links_counter_cache_to_spree_stores.rb +0 -10
  286. data/lib/generators/spree/dummy/templates/initializers/devise.rb +0 -3
  287. data/lib/generators/spree/install/install_generator.rb +0 -219
  288. data/lib/generators/spree/install/templates/config/initializers/spree.rb +0 -126
  289. data/lib/spree/core/webhooks.rb +0 -21
  290. data/lib/spree/testing_support/factories/page_block_factory.rb +0 -22
  291. data/lib/spree/testing_support/factories/page_factory.rb +0 -33
  292. data/lib/spree/testing_support/factories/page_link_factory.rb +0 -7
  293. data/lib/spree/testing_support/factories/page_section_factory.rb +0 -27
  294. data/lib/spree/testing_support/factories/theme_factory.rb +0 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4e0552e5475aa54e072158a70ea648d02d5514550eca293f1c0e0c79554c4216
4
- data.tar.gz: afe49cf6d48fa819396d1518e3531435ffc22d038ce1a75aef430082bbc429fb
3
+ metadata.gz: e9a0e0a87e86ccf2c9213c4511c96c63b672ee82dba7c47f029b60e94226b975
4
+ data.tar.gz: 191192ca65bb1d919da4dd77cc93b50cfcfb51618a36dc954788ff4b259d5185
5
5
  SHA512:
6
- metadata.gz: 46b12717f12408f073b31a2a4f70d8850204bcfd59d32b20a6d891bc0326b7ea0c563c9b876e81156c6ba40f6ba88705553f87bc349598f52e8d761a7ea887a7
7
- data.tar.gz: 37e34cbc4020055babe24354344aae7306dde8343267b2bac666fe691881936e5ebf6daeaa982ad4ce1ea4df88eecc77cb168c5321c57c2329b920dba37d05d7
6
+ metadata.gz: d6eeed104b0d5ffa31c70d98792da3944ae19b81fd63afd62368fdeb6a8a5efa93775660c07e7990e05c9b3e8934d2ae064bc389d91f1c3c4face95dc10f477d
7
+ data.tar.gz: 54698f48b85f66aca3c03c3efaaf836ee216996b98c3564739d0cad3e816e1b158f0e79b4b3df9034c2e0f6a54ad1621d55484cb0803a87e6edf045fb806f39b
@@ -31,7 +31,7 @@ module Spree
31
31
  method_name = Spree.t(:zipcode)
32
32
  form.label(:zipcode, method_name, id: address_id + '_zipcode_label', class: 'block text-xs text-neutral-600 mb-1') +
33
33
  form.text_field(:zipcode,
34
- class: 'text-input h-full',
34
+ class: 'text-input',
35
35
  placeholder: method_name,
36
36
  required: country&.zipcode_required?,
37
37
  data: { 'address-form-target': 'zipcode', address_autocomplete_target: 'zipcode' },
@@ -74,28 +74,6 @@ module Spree
74
74
  end
75
75
  end
76
76
 
77
- def current_store_countries_with_states_ids
78
- Spree::Deprecation.warn('current_store_countries_with_states_ids is deprecated and will be removed in Spree 5.3')
79
-
80
- @current_store_countries_with_states_ids ||= current_store.countries_available_for_checkout.find_all { |country| country.states_required? }.each_with_object([]) do |country, memo|
81
- memo << current_store.states_available_for_checkout(country)
82
- end.flatten.pluck(:country_id)
83
- end
84
-
85
- def current_store_countries_without_states_ids
86
- Spree::Deprecation.warn('current_store_countries_without_states_ids is deprecated and will be removed in Spree 5.3')
87
-
88
- @current_store_countries_without_states_ids ||= current_store.countries_available_for_checkout.find_all { |country| !country.states_required? }.pluck(:id)
89
- end
90
-
91
- def current_store_supported_countries_ids
92
- Spree::Deprecation.warn('current_store_supported_countries_ids is deprecated and will be removed in Spree 5.3')
93
-
94
- @current_store_supported_countries_ids ||= Rails.cache.fetch(['current_store_supported_countries_ids', current_store]) do
95
- (current_store_countries_with_states_ids + current_store_countries_without_states_ids).uniq
96
- end
97
- end
98
-
99
77
  def user_available_addresses
100
78
  return [] unless try_spree_current_user
101
79
 
@@ -23,16 +23,22 @@ module Spree
23
23
  end
24
24
 
25
25
  def spree_resource_path(resource)
26
+ Spree::Deprecation.warn('BaseHelper#spree_resource_path is deprecated and will be removed in Spree 5.5')
27
+
26
28
  last_word = resource.class.name.split('::', 10).last
27
29
 
28
30
  spree_class_name_as_path(last_word)
29
31
  end
30
32
 
31
33
  def spree_class_name_as_path(class_name)
34
+ Spree::Deprecation.warn('BaseHelper#spree_class_name_as_path is deprecated and will be removed in Spree 5.5')
35
+
32
36
  class_name.underscore.humanize.parameterize(separator: '_')
33
37
  end
34
38
 
35
39
  def display_price(product_or_variant)
40
+ Spree::Deprecation.warn('display_price is deprecated and will be removed in Spree 5.5. Use variant.price_for(context).display_amount instead.')
41
+
36
42
  product_or_variant.
37
43
  price_in(current_currency).
38
44
  display_price_including_vat_for(current_price_options).
@@ -40,6 +46,8 @@ module Spree
40
46
  end
41
47
 
42
48
  def display_compare_at_price(product_or_variant)
49
+ Spree::Deprecation.warn('display_compare_at_price is deprecated and will be removed in Spree 5.5. Use variant.price_for(context).display_compare_at_amount instead.')
50
+
43
51
  product_or_variant.
44
52
  price_in(current_currency).
45
53
  display_compare_at_price_including_vat_for(current_price_options).
@@ -47,6 +55,8 @@ module Spree
47
55
  end
48
56
 
49
57
  def link_to_tracking(shipment, options = {})
58
+ Spree::Deprecation.warn('BaseHelper#link_to_tracking is deprecated and will be removed in Spree 5.5. Please use shipment.tracking_url instead.')
59
+
50
60
  return unless shipment.tracking && shipment.shipping_method
51
61
 
52
62
  options[:target] ||= :blank
@@ -59,6 +69,8 @@ module Spree
59
69
  end
60
70
 
61
71
  def spree_favicon_path
72
+ Spree::Deprecation.warn('BaseHelper#spree_favicon_path is deprecated and will be removed in Spree 5.5. Please use Active Storage URL helpers instead.')
73
+
62
74
  if current_store.favicon.present?
63
75
  main_app.cdn_image_url(current_store.favicon)
64
76
  else
@@ -70,66 +82,9 @@ module Spree
70
82
  instance_variable_get('@' + controller_name.singularize)
71
83
  end
72
84
 
73
- def og_meta_data
74
- og_meta = {}
75
-
76
- if object.is_a? Spree::Product
77
- image = default_image_for_product_or_variant(object)
78
- og_meta['og:image'] = main_app.cdn_image_url(image.attachment) if image&.attachment
79
-
80
- og_meta['og:url'] = spree.url_for(object) if frontend_available? # url_for product needed
81
- og_meta['og:type'] = object.class.name.demodulize.downcase
82
- og_meta['og:title'] = object.name
83
- og_meta['og:description'] = object.description
84
-
85
- price = object.price_in(current_currency)
86
- if price
87
- og_meta['product:price:amount'] = price.amount
88
- og_meta['product:price:currency'] = current_currency
89
- end
90
- end
91
-
92
- og_meta
93
- end
94
-
95
- def meta_data
96
- meta = {}
97
-
98
- if object.is_a? ApplicationRecord
99
- meta[:keywords] = object.meta_keywords if object.try(:meta_keywords).present?
100
- meta[:description] = object.meta_description if object.try(:meta_description).present?
101
- end
102
-
103
- if meta[:description].blank? && object.is_a?(Spree::Product)
104
- meta[:description] = truncate(strip_tags(object.description), length: 160, separator: ' ')
105
- end
106
-
107
- if meta[:keywords].blank? || meta[:description].blank?
108
- if object && object[:name].present?
109
- meta.reverse_merge!(keywords: [object.name, current_store.meta_keywords].reject(&:blank?).join(', '),
110
- description: [object.name, current_store.meta_description].reject(&:blank?).join(', '))
111
- else
112
- meta.reverse_merge!(keywords: (current_store.meta_keywords || current_store.seo_title),
113
- description: current_store.seo_meta_description)
114
- end
115
- end
116
- meta
117
- end
118
-
119
- def og_meta_data_tags
120
- og_meta_data.map do |property, content|
121
- tag('meta', property: property, content: content) unless property.nil? || content.nil?
122
- end.join("\n")
123
- end
124
-
125
- def meta_data_tags
126
- meta_data.map do |name, content|
127
- tag('meta', name: name, content: content) unless name.nil? || content.nil?
128
- end.join("\n")
129
- end
130
-
131
85
  def method_missing(method_name, *args, &block)
132
86
  if image_style = image_style_from_method_name(method_name)
87
+ Spree::Deprecation.warn("#{BaseHelper.name}##{method_name} is deprecated and will be removed in Spree 5.5. Please use spree_image_tag instead - https://spreecommerce.org/docs/developer/core-concepts/images-assets#preprocessed-named-variants")
133
88
  define_image_method(image_style)
134
89
  send(method_name, *args)
135
90
  else
@@ -140,7 +95,7 @@ module Spree
140
95
  def pretty_time(time)
141
96
  return '' if time.blank?
142
97
 
143
- Spree::Deprecation.warn('BaseHelper#pretty_time is deprecated and will be removed in Spree 6.0. Please add `local_time` gem to your Gemfile and use `local_time(time)` instead')
98
+ Spree::Deprecation.warn('BaseHelper#pretty_time is deprecated and will be removed in Spree 5.5. Please add `local_time` gem to your Gemfile and use `local_time(time)` instead')
144
99
 
145
100
  [I18n.l(time.to_date, format: :long), time.strftime('%l:%M %p %Z')].join(' ')
146
101
  end
@@ -148,16 +103,18 @@ module Spree
148
103
  def pretty_date(date)
149
104
  return '' if date.blank?
150
105
 
151
- Spree::Deprecation.warn('BaseHelper#pretty_date is deprecated and will be removed in Spree 6.0. Please add `local_time` gem to your Gemfile and use `local_date(date)` instead')
106
+ Spree::Deprecation.warn('BaseHelper#pretty_date is deprecated and will be removed in Spree 5.5. Please add `local_time` gem to your Gemfile and use `local_date(date)` instead')
152
107
 
153
108
  [I18n.l(date.to_date, format: :long)].join(' ')
154
109
  end
155
110
 
156
111
  def seo_url(taxon, options = {})
112
+ Spree::Deprecation.warn('BaseHelper#seo_url is deprecated and will be removed in Spree 5.5. Please use spree_storefront_resource_url')
157
113
  spree.nested_taxons_path(taxon.permalink, options.merge(locale: locale_param))
158
114
  end
159
115
 
160
116
  def frontend_available?
117
+ Spree::Deprecation.warn('BaseHelper#frontend_available? is deprecated and will be removed in Spree 5.5')
161
118
  Spree::Core::Engine.frontend_available?
162
119
  end
163
120
 
@@ -198,14 +155,14 @@ module Spree
198
155
  params = "?#{params}" if params.present?
199
156
 
200
157
  "#{base_url + localize}/products/#{resource.slug}#{params}"
201
- elsif resource.is_a?(Post)
158
+ elsif defined?(Spree::Post) && resource.is_a?(Spree::Post)
202
159
  preview_id = options[:preview_id].present? ? "?preview_id=#{options[:preview_id]}" : ''
203
160
  "#{base_url + localize}/posts/#{resource.slug}#{preview_id}"
204
161
  elsif resource.is_a?(Spree::Taxon)
205
162
  "#{base_url + localize}/t/#{resource.permalink}"
206
- elsif resource.is_a?(Spree::Page) || resource.is_a?(Spree::Policy)
163
+ elsif defined?(Spree::Page) && (resource.is_a?(Spree::Page) || resource.is_a?(Spree::Policy))
207
164
  "#{base_url + localize}#{resource.page_builder_url}"
208
- elsif resource.is_a?(Spree::PageLink)
165
+ elsif defined?(Spree::PageLink) && resource.is_a?(Spree::PageLink)
209
166
  resource.linkable_url
210
167
  elsif localize.blank?
211
168
  base_url
@@ -217,19 +174,19 @@ module Spree
217
174
  # we should always try to render image of the default variant
218
175
  # same as it's done on PDP
219
176
  def default_image_for_product(product)
220
- Spree::Deprecation.warn('BaseHelper#default_image_for_product is deprecated and will be removed in Spree 6.0. Please use product.default_image instead')
177
+ Spree::Deprecation.warn('BaseHelper#default_image_for_product is deprecated and will be removed in Spree 5.5. Please use product.default_image instead')
221
178
 
222
179
  product.default_image
223
180
  end
224
181
 
225
182
  def default_image_for_product_or_variant(product_or_variant)
226
- Spree::Deprecation.warn('BaseHelper#default_image_for_product_or_variant is deprecated and will be removed in Spree 6.0. Please use product_or_variant.default_image instead')
183
+ Spree::Deprecation.warn('BaseHelper#default_image_for_product_or_variant is deprecated and will be removed in Spree 5.5. Please use product_or_variant.default_image instead')
227
184
 
228
185
  product_or_variant.default_image
229
186
  end
230
187
 
231
188
  def base_cache_key
232
- Spree::Deprecation.warn('`base_cache_key` is deprecated and will be removed in Spree 6. Please use `spree_base_cache_key` instead')
189
+ Spree::Deprecation.warn('`base_cache_key` is deprecated and will be removed in Spree 5.5. Please use `spree_base_cache_key` instead')
233
190
  spree_base_cache_key
234
191
  end
235
192
 
@@ -256,6 +213,8 @@ module Spree
256
213
  opts[:width] ||= opts[:height] * 1.5 if opts[:height]
257
214
  opts[:size] = "#{opts[:width]}x#{opts[:height]}" if opts[:width] && opts[:height]
258
215
 
216
+ opts[:fallback] = 'payment_icons/storecredit.svg'
217
+
259
218
  inline_svg "payment_icons/#{payment_method}.svg", opts
260
219
  end
261
220
 
@@ -291,17 +250,6 @@ module Spree
291
250
  end
292
251
  end
293
252
 
294
- def meta_robots
295
- return unless current_store.respond_to?(:seo_robots)
296
- return if current_store.seo_robots.blank?
297
-
298
- tag('meta', name: 'robots', content: current_store.seo_robots)
299
- end
300
-
301
- def legal_policy(policy)
302
- current_store.send("customer_#{policy}")&.body&.html_safe
303
- end
304
-
305
253
  I18N_PLURAL_MANY_COUNT = 2.1
306
254
  def plural_resource_name(resource_class)
307
255
  resource_class.model_name.human(count: I18N_PLURAL_MANY_COUNT)
@@ -45,12 +45,12 @@ module Spree
45
45
  # Returns the list of supported currencies for the current store.
46
46
  # @return [Array<Money::Currency>] the list of supported currencies
47
47
  def preferred_currencies
48
- Spree::Deprecation.warn('preferred_currencies is deprecated and will be removed in Spree 6.0. Use current_store.supported_currencies_list instead.')
48
+ Spree::Deprecation.warn('preferred_currencies is deprecated and will be removed in Spree 5.5. Use current_store.supported_currencies_list instead.')
49
49
  @preferred_currencies ||= current_store.supported_currencies_list
50
50
  end
51
51
 
52
52
  def preferred_currencies_select_options
53
- Spree::Deprecation.warn('preferred_currencies_select_options is deprecated and will be removed in Spree 6.0. Use supported_currency_options instead.')
53
+ Spree::Deprecation.warn('preferred_currencies_select_options is deprecated and will be removed in Spree 5.5. Use supported_currency_options instead.')
54
54
  preferred_currencies.map { |currency| currency_presentation(currency) }
55
55
  end
56
56
 
@@ -9,6 +9,10 @@ module Spree
9
9
  # @option options [Integer] :height the height of the image
10
10
  # @option options [Symbol] :variant use a preprocessed named variant (e.g., :mini, :small, :medium, :large, :xlarge)
11
11
  def spree_image_tag(image, options = {})
12
+ return unless image
13
+ return unless image.variable?
14
+ return if image.respond_to?(:attached?) && !image.attached?
15
+
12
16
  url_options = if options[:variant].present?
13
17
  { variant: options[:variant] }
14
18
  else
@@ -25,6 +29,7 @@ module Spree
25
29
  return unless image
26
30
  return unless image.variable?
27
31
  return if image.respond_to?(:attached?) && !image.attached?
32
+
28
33
  url_helpers = respond_to?(:main_app) ? main_app : Rails.application.routes.url_helpers
29
34
 
30
35
  # Use preprocessed named variant if specified (e.g., :mini, :small, :medium, :large, :xlarge)
@@ -17,7 +17,7 @@ module Spree
17
17
  end
18
18
 
19
19
  def logo_path
20
- Spree::Deprecation.warn('logo_path is deprecated and will be removed in Spree 6.0. Please use Active Storage URL helpers instead.')
20
+ Spree::Deprecation.warn('logo_path is deprecated and will be removed in Spree 5.5. Please use Active Storage URL helpers instead.')
21
21
 
22
22
  return main_app.cdn_image_url(store_logo.variant(resize_to_limit: [244, 104])) if store_logo&.variable?
23
23
 
@@ -121,7 +121,7 @@ module Spree
121
121
  end
122
122
 
123
123
  def related_products
124
- Spree::Deprecation.warn('ProductsHelper#related_products is deprecated and will be removed in Spree 6.0. Please use ProductsHelper#relations from now on.')
124
+ Spree::Deprecation.warn('ProductsHelper#related_products is deprecated and will be removed in Spree 5.5. Please use ProductsHelper#relations from now on.')
125
125
 
126
126
  return [] unless @product.respond_to?(:has_related_products?)
127
127
 
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ # Job for executing subscribers asynchronously.
6
+ #
7
+ # When subscribers are configured to run async (the default),
8
+ # this job is enqueued to handle the event processing in the background.
9
+ #
10
+ # @example Direct usage (typically called by the adapter)
11
+ # Spree::Events::SubscriberJob.perform_later(
12
+ # 'MySubscriber',
13
+ # { name: 'order.complete', payload: {...}, ... }
14
+ # )
15
+ #
16
+ class SubscriberJob < Spree::BaseJob
17
+ queue_as Spree.queues.events
18
+
19
+ # Retry configuration
20
+ retry_on StandardError, wait: :polynomially_longer, attempts: 3
21
+
22
+ discard_on ActiveJob::DeserializationError do |job, error|
23
+ Rails.error.report(error, context: {
24
+ subscriber: job.arguments.first,
25
+ event: job.arguments.second
26
+ })
27
+ end
28
+
29
+ # @param subscriber_class_name [String] The subscriber class name
30
+ # @param event_hash [Hash] The event data as a hash
31
+ def perform(subscriber_class_name, event_hash)
32
+ subscriber_class = subscriber_class_name.constantize
33
+ event = reconstruct_event(event_hash)
34
+
35
+ if subscriber_class < Spree::Subscriber
36
+ subscriber_class.new.call(event)
37
+ elsif subscriber_class.respond_to?(:call)
38
+ subscriber_class.call(event)
39
+ else
40
+ raise ArgumentError, "#{subscriber_class_name} is not a valid subscriber"
41
+ end
42
+ rescue NameError => e
43
+ Rails.error.report(e, context: {
44
+ subscriber: subscriber_class_name,
45
+ event_name: event_hash[:name] || event_hash['name']
46
+ })
47
+ raise
48
+ end
49
+
50
+ private
51
+
52
+ def reconstruct_event(event_hash)
53
+ event_hash = event_hash.deep_symbolize_keys
54
+ Spree::Event.new(**event_hash.slice(:id, :name, :store_id, :payload, :metadata, :created_at))
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,14 @@
1
+ module Spree
2
+ module Products
3
+ class RefreshMetricsJob < Spree::BaseJob
4
+ queue_as Spree.queues.products
5
+
6
+ def perform(product_id, store_id)
7
+ store_product = Spree::StoreProduct.find_by(product_id: product_id, store_id: store_id)
8
+ return unless store_product
9
+
10
+ store_product.refresh_metrics!
11
+ end
12
+ end
13
+ end
14
+ end
@@ -6,7 +6,6 @@ module Spree
6
6
  def perform(taxon_ids, taxonomy_ids)
7
7
  Spree::Taxon.where(id: taxon_ids).update_all(updated_at: Time.current)
8
8
  Spree::Taxonomy.where(id: taxonomy_ids).update_all(updated_at: Time.current)
9
- Spree::Taxons::TouchFeaturedSections.call(taxon_ids: taxon_ids)
10
9
  end
11
10
  end
12
11
  end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module Variants
3
+ class TouchJob < Spree::BaseJob
4
+ def perform(variant_ids)
5
+ Spree::Variant.where(id: variant_ids).find_each(&:touch)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -5,6 +5,7 @@ module Spree
5
5
  included do
6
6
  has_many :adjustments, as: :source
7
7
  before_destroy :deals_with_adjustments_for_deleted_source
8
+ after_commit :clear_adjustment_source_cache
8
9
  end
9
10
 
10
11
  protected
@@ -54,5 +55,12 @@ module Spree
54
55
  # This would mean that the order's total is not altered at all.
55
56
  adjustments.for_complete_order.update_all(source_id: nil, updated_at: Time.current)
56
57
  end
58
+
59
+ def clear_adjustment_source_cache
60
+ # Use base_class.name to match the polymorphic_name stored in source_type
61
+ # For STI models like PromotionAction subclasses, this ensures cache key consistency
62
+ cache_class_name = self.class.polymorphic_name
63
+ Rails.cache.delete("spree/adjustment_source/#{cache_class_name}/#{id}")
64
+ end
57
65
  end
58
66
  end
@@ -3,7 +3,7 @@ module Spree
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- auto_strip_attributes :name, :presentation
6
+ normalizes :name, :presentation, with: ->(value) { value&.to_s&.squish&.presence }
7
7
 
8
8
  #
9
9
  # Callbacks
@@ -56,6 +56,34 @@ module Spree
56
56
  order(price_table_name => { amount: :desc })
57
57
  end
58
58
 
59
+ # Price sorting scopes that use subqueries to get prices across all variants
60
+ # These ensure products with only variant prices (no master price) are included in results
61
+ add_search_scope :ascend_by_price do
62
+ price_subquery = Price
63
+ .non_zero
64
+ .joins(:variant)
65
+ .where("#{Variant.table_name}.product_id = #{Product.table_name}.id")
66
+ .select('MIN(amount)')
67
+
68
+ price_sort_sql = "COALESCE((#{price_subquery.to_sql}), 999999999)"
69
+
70
+ select("#{Product.table_name}.*", "#{price_sort_sql} AS min_price").
71
+ order(Arel.sql("#{price_sort_sql} ASC"))
72
+ end
73
+
74
+ add_search_scope :descend_by_price do
75
+ price_subquery = Price
76
+ .non_zero
77
+ .joins(:variant)
78
+ .where("#{Variant.table_name}.product_id = #{Product.table_name}.id")
79
+ .select('MAX(amount)')
80
+
81
+ price_sort_sql = "COALESCE((#{price_subquery.to_sql}), 0)"
82
+
83
+ select("#{Product.table_name}.*", "#{price_sort_sql} AS max_price").
84
+ order(Arel.sql("#{price_sort_sql} DESC"))
85
+ end
86
+
59
87
  add_search_scope :price_between do |low, high|
60
88
  where(Price.table_name => { amount: low..high })
61
89
  end
@@ -113,16 +141,13 @@ module Spree
113
141
  end
114
142
 
115
143
  add_search_scope :ascend_by_taxons_min_position do |taxon_ids|
144
+ min_position_sql = "MIN(#{Classification.table_name}.position)"
145
+
116
146
  joins(:classifications).
117
147
  where(Classification.table_name => { taxon_id: taxon_ids }).
118
- select(
119
- [
120
- "#{Product.table_name}.*",
121
- "MIN(#{Classification.table_name}.position) AS min_position"
122
- ].join(', ')
123
- ).
124
- group(:id).
125
- order(min_position: :asc)
148
+ select("#{Product.table_name}.*", "#{min_position_sql} AS min_taxon_position").
149
+ group("#{Product.table_name}.id").
150
+ order(Arel.sql("#{min_position_sql} ASC"))
126
151
  end
127
152
 
128
153
  # a scope that finds all products having property specified by name, object or id
@@ -302,6 +327,27 @@ module Spree
302
327
  group('spree_products.id').joins(:taxons).where(Taxon.arel_table[:name].eq(name))
303
328
  end
304
329
 
330
+ # Orders products by best selling based on units_sold_count and revenue
331
+ # stored in spree_products_stores table.
332
+ #
333
+ # These metrics are updated asynchronously when orders are completed
334
+ # via the ProductMetricsSubscriber.
335
+ #
336
+ # @param order_direction [Symbol] :desc (default) or :asc
337
+ # @return [ActiveRecord::Relation]
338
+ add_search_scope :by_best_selling do |order_direction = :desc|
339
+ order_dir = order_direction == :desc ? 'DESC' : 'ASC'
340
+ store_id = Spree::Current.store&.id
341
+
342
+ joins(:store_products)
343
+ .where(StoreProduct.table_name => { store_id: store_id })
344
+ .select("#{Product.table_name}.*",
345
+ "#{StoreProduct.table_name}.units_sold_count",
346
+ "#{StoreProduct.table_name}.revenue")
347
+ .order(Arel.sql("#{StoreProduct.table_name}.units_sold_count #{order_dir}"))
348
+ .order(Arel.sql("#{StoreProduct.table_name}.revenue #{order_dir}"))
349
+ end
350
+
305
351
  # .search_by_name
306
352
  if defined?(PgSearch)
307
353
  include PgSearch::Model