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
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class RefundSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ amount: money(resource.amount),
12
+ transaction_id: resource.transaction_id,
13
+ payment_id: resource.payment_id,
14
+ refund_reason_id: resource.refund_reason_id,
15
+ reimbursement_id: resource.reimbursement_id,
16
+ refunder_id: resource.refunder_id,
17
+ created_at: timestamp(resource.created_at),
18
+ updated_at: timestamp(resource.updated_at)
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class ReimbursementSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ number: resource.number,
12
+ reimbursement_status: resource.reimbursement_status,
13
+ total: money(resource.total),
14
+ order_id: resource.order_id,
15
+ customer_return_id: resource.customer_return_id,
16
+ created_at: timestamp(resource.created_at),
17
+ updated_at: timestamp(resource.updated_at)
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class ReportSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ type: resource.type,
12
+ store_id: resource.store_id,
13
+ user_id: resource.user_id,
14
+ currency: resource.currency,
15
+ date_from: timestamp(resource.date_from),
16
+ date_to: timestamp(resource.date_to),
17
+ created_at: timestamp(resource.created_at),
18
+ updated_at: timestamp(resource.updated_at)
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class ReturnAuthorizationSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ number: resource.number,
12
+ state: resource.state.to_s,
13
+ order_id: resource.order_id,
14
+ stock_location_id: resource.stock_location_id,
15
+ return_authorization_reason_id: resource.return_authorization_reason_id,
16
+ created_at: timestamp(resource.created_at),
17
+ updated_at: timestamp(resource.updated_at)
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class ReturnItemSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ reception_status: resource.reception_status,
12
+ acceptance_status: resource.acceptance_status,
13
+ pre_tax_amount: money(resource.pre_tax_amount),
14
+ included_tax_total: money(resource.included_tax_total),
15
+ additional_tax_total: money(resource.additional_tax_total),
16
+ inventory_unit_id: resource.inventory_unit_id,
17
+ return_authorization_id: resource.return_authorization_id,
18
+ customer_return_id: resource.customer_return_id,
19
+ reimbursement_id: resource.reimbursement_id,
20
+ exchange_variant_id: resource.exchange_variant_id,
21
+ created_at: timestamp(resource.created_at),
22
+ updated_at: timestamp(resource.updated_at)
23
+ }
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class ShipmentSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ number: resource.number,
12
+ state: resource.state.to_s,
13
+ tracking: resource.tracking,
14
+ cost: money(resource.cost),
15
+ order_id: resource.order_id,
16
+ stock_location_id: resource.stock_location_id,
17
+ shipped_at: timestamp(resource.shipped_at),
18
+ created_at: timestamp(resource.created_at),
19
+ updated_at: timestamp(resource.updated_at)
20
+ }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class StockItemSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ count_on_hand: resource.count_on_hand,
12
+ backorderable: resource.backorderable,
13
+ stock_location_id: resource.stock_location_id,
14
+ variant_id: resource.variant_id,
15
+ deleted_at: timestamp(resource.deleted_at),
16
+ created_at: timestamp(resource.created_at),
17
+ updated_at: timestamp(resource.updated_at)
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class StockMovementSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ quantity: resource.quantity,
12
+ action: resource.action,
13
+ originator_type: resource.originator_type,
14
+ originator_id: resource.originator_id,
15
+ stock_item_id: resource.stock_item_id,
16
+ created_at: timestamp(resource.created_at),
17
+ updated_at: timestamp(resource.updated_at)
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class StockTransferSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ number: resource.number,
12
+ type: resource.type,
13
+ reference: resource.reference,
14
+ source_location_id: resource.source_location_id,
15
+ destination_location_id: resource.destination_location_id,
16
+ created_at: timestamp(resource.created_at),
17
+ updated_at: timestamp(resource.updated_at)
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class StoreCreditSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ amount: money(resource.amount),
12
+ amount_used: money(resource.amount_used),
13
+ amount_authorized: money(resource.amount_authorized),
14
+ currency: resource.currency,
15
+ memo: resource.memo,
16
+ user_id: resource.user_id,
17
+ category_id: resource.category_id,
18
+ type_id: resource.type_id,
19
+ store_id: resource.store_id,
20
+ created_by_id: resource.created_by_id,
21
+ originator_type: resource.originator_type,
22
+ originator_id: resource.originator_id,
23
+ deleted_at: timestamp(resource.deleted_at),
24
+ created_at: timestamp(resource.created_at),
25
+ updated_at: timestamp(resource.updated_at)
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class UserSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ email: resource.email,
12
+ created_at: timestamp(resource.created_at),
13
+ updated_at: timestamp(resource.updated_at)
14
+ }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class VariantSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ sku: resource.sku,
12
+ barcode: resource.barcode,
13
+ is_master: resource.is_master,
14
+ position: resource.position,
15
+ weight: money(resource.weight),
16
+ height: money(resource.height),
17
+ width: money(resource.width),
18
+ depth: money(resource.depth),
19
+ weight_unit: resource.weight_unit,
20
+ dimensions_unit: resource.dimensions_unit,
21
+ cost_price: money(resource.cost_price),
22
+ cost_currency: resource.cost_currency,
23
+ track_inventory: resource.track_inventory,
24
+ product_id: resource.product_id,
25
+ tax_category_id: resource.tax_category_id,
26
+ discontinue_on: timestamp(resource.discontinue_on),
27
+ deleted_at: timestamp(resource.deleted_at),
28
+ created_at: timestamp(resource.created_at),
29
+ updated_at: timestamp(resource.updated_at)
30
+ }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class WishedItemSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ quantity: resource.quantity,
12
+ variant_id: resource.variant_id,
13
+ wishlist_id: resource.wishlist_id,
14
+ created_at: timestamp(resource.created_at),
15
+ updated_at: timestamp(resource.updated_at)
16
+ }
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ module Events
5
+ class WishlistSerializer < BaseSerializer
6
+ protected
7
+
8
+ def attributes
9
+ {
10
+ id: resource.id,
11
+ name: resource.name,
12
+ is_private: resource.is_private,
13
+ is_default: resource.is_default,
14
+ user_id: resource.user_id,
15
+ store_id: resource.store_id,
16
+ created_at: timestamp(resource.created_at),
17
+ updated_at: timestamp(resource.updated_at)
18
+ }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -12,7 +12,7 @@ module Spree
12
12
  default_shipping = opts.fetch(:default_shipping, false)
13
13
  address_changes_except = opts.fetch(:address_changes_except, [])
14
14
  create_new_address_on_update = opts.fetch(:create_new_address_on_update, false)
15
- Spree::Deprecation.warn('Spree::Addresses::Update create_new_address_on_update parameter is deprecated and will be removed in Spree 6.') if create_new_address_on_update
15
+ Spree::Deprecation.warn('Spree::Addresses::Update create_new_address_on_update parameter is deprecated and will be removed in Spree 5.5.') if create_new_address_on_update
16
16
 
17
17
  prepare_address_params!(address, address_params)
18
18
  address.assign_attributes(address_params)
@@ -39,7 +39,7 @@ module Spree
39
39
 
40
40
  return failure(line_item) unless line_item.save
41
41
 
42
- line_item.reload.update_price
42
+ line_item.reload.recalculate_price
43
43
 
44
44
  ::Spree::TaxRate.adjust(order, [line_item]) if line_item_created
45
45
  success(order: order, line_item: line_item, line_item_created: line_item_created, options: options)
@@ -19,7 +19,8 @@ module Spree
19
19
  private
20
20
 
21
21
  def find_current_promotions_ids
22
- order.all_adjustments.promotion.eligible.map { |a| a.source.try(:promotion_id) }.compact
22
+ order.all_adjustments.promotion.eligible.joins("INNER JOIN #{Spree::PromotionAction.table_name} ON #{Spree::PromotionAction.table_name}.id = #{Spree::Adjustment.table_name}.source_id").
23
+ pluck("#{Spree::PromotionAction.table_name}.promotion_id").compact.uniq
23
24
  end
24
25
 
25
26
  def use_all_current(promotion_ids)
@@ -12,7 +12,7 @@ module Spree
12
12
  information['id'] = input[:variant].id
13
13
  information['title'] = format_title(input[:product], input[:variant])
14
14
  information['description'] = get_description(input[:product], input[:variant])
15
- information['link'] = "#{input[:store].url}/#{input[:product].slug}"
15
+ information['link'] = "#{input[:store].url}/products/#{input[:product].slug}"
16
16
  information['image_link'] = get_image_link(input[:variant], input[:product])
17
17
  information['price'] = format_price(input[:variant])
18
18
  information['availability'] = get_availability(input[:product])
@@ -26,11 +26,11 @@ module Spree
26
26
  def format_title(product, variant)
27
27
  # Title of a variant is created by joining title of a product and variant's option_values, as they are
28
28
  # what differentiates it from other variants.
29
- title = product.name
29
+ parts = [product.name]
30
30
  variant.option_values.find_each do |option_value|
31
- title << " - #{option_value.name}"
31
+ parts << option_value.name
32
32
  end
33
- title
33
+ parts.join(' - ')
34
34
  end
35
35
 
36
36
  def get_description(product, variant)
@@ -8,6 +8,7 @@ module Spree
8
8
  def call
9
9
  verify_subscriber
10
10
  set_user_email_marketing_to_true
11
+ publish_event
11
12
 
12
13
  subscriber
13
14
  end
@@ -25,6 +26,10 @@ module Spree
25
26
 
26
27
  subscriber.user.update!(accepts_email_marketing: true)
27
28
  end
29
+
30
+ def publish_event
31
+ subscriber.publish_event('newsletter_subscriber.verified')
32
+ end
28
33
  end
29
34
  end
30
35
  end
@@ -40,7 +40,7 @@ module Spree
40
40
 
41
41
  all_affected_taxons = (taxons_to_remove + taxons_to_add).uniq
42
42
 
43
- if all_affected_taxons.any?
43
+ if all_affected_taxons.any? && defined?(Spree::Taxons::TouchFeaturedSections)
44
44
  Spree::Taxons::TouchFeaturedSections.call(taxon_ids: all_affected_taxons.pluck(:id))
45
45
  product.touch
46
46
  end
@@ -4,7 +4,7 @@ module Spree
4
4
  prepend Spree::ServiceModule::Base
5
5
 
6
6
  def call
7
- Spree::Webhooks.disable_webhooks do
7
+ Spree::Events.disable do
8
8
  # GEO
9
9
  Countries.call
10
10
  States.call
@@ -28,12 +28,16 @@ module Spree
28
28
  # doing a quick insert_all here to avoid the overhead of instantiating
29
29
  Spree::Classification.insert_all(classifications_params)
30
30
 
31
- # clearing cache
32
- Spree::Product.where(id: products.pluck(:id)).touch_all
33
-
31
+ # update counter caches
34
32
  taxon_ids = taxons.pluck(:id)
33
+ product_ids = products.pluck(:id)
34
+ taxon_ids.each { |id| Spree::Taxon.reset_counters(id, :classifications) }
35
+ product_ids.each { |id| Spree::Product.reset_counters(id, :classifications) }
36
+
37
+ # clearing cache
38
+ Spree::Product.where(id: product_ids).touch_all
35
39
  Spree::Taxon.where(id: taxon_ids).touch_all
36
- Spree::Taxons::TouchFeaturedSections.call(taxon_ids: taxon_ids)
40
+ Spree::Taxons::TouchFeaturedSections.call(taxon_ids: taxon_ids) if defined?(Spree::Taxons::TouchFeaturedSections)
37
41
 
38
42
  success(true)
39
43
  end
@@ -5,6 +5,7 @@ module Spree
5
5
 
6
6
  def call(taxon:)
7
7
  return if taxon.nil?
8
+ return if taxon.destroyed?
8
9
  return if taxon.manual?
9
10
 
10
11
  previous_products_ids = taxon.classifications.order(position: :asc).pluck(:product_id)
@@ -34,6 +35,13 @@ module Spree
34
35
  Spree::Product.where(id: (previous_products_ids + product_ids_to_insert).uniq).touch_all
35
36
  end
36
37
 
38
+ # update counter caches
39
+ # Check if taxon still exists (may have been destroyed)
40
+ Spree::Taxon.reset_counters(taxon.id, :classifications)
41
+ all_product_ids = (previous_products_ids + product_ids_to_insert).uniq
42
+ existing_product_ids = Spree::Product.where(id: all_product_ids).pluck(:id)
43
+ existing_product_ids.each { |id| Spree::Product.reset_counters(id, :classifications) }
44
+
37
45
  success(taxon)
38
46
  end
39
47
 
@@ -11,12 +11,15 @@ module Spree
11
11
  def call(taxons:, products:)
12
12
  return if taxons.blank? || products.blank?
13
13
 
14
+ taxon_ids = taxons.pluck(:id)
15
+ product_ids = products.pluck(:id)
16
+
14
17
  ApplicationRecord.transaction do
15
- taxons.pluck(:id).each do |taxon_id|
16
- Spree::Classification.where(taxon_id: taxon_id, product_id: products.pluck(:id)).delete_all
18
+ taxon_ids.each do |taxon_id|
19
+ Spree::Classification.where(taxon_id: taxon_id, product_id: product_ids).delete_all
17
20
  end
18
21
 
19
- classifications_params = taxons.pluck(:id).flat_map do |taxon_id|
22
+ classifications_params = taxon_ids.flat_map do |taxon_id|
20
23
  position = 0
21
24
  existing_product_ids = Spree::Classification.where(taxon_id: taxon_id).pluck(:product_id)
22
25
 
@@ -42,12 +45,14 @@ module Spree
42
45
  end
43
46
  end
44
47
 
45
- # clear cache
46
- Spree::Product.where(id: products.pluck(:id)).touch_all
48
+ # update counter caches
49
+ taxon_ids.each { |id| Spree::Taxon.reset_counters(id, :classifications) }
50
+ product_ids.each { |id| Spree::Product.reset_counters(id, :classifications) }
47
51
 
48
- taxon_ids = taxons.pluck(:id)
52
+ # clear cache
53
+ Spree::Product.where(id: product_ids).touch_all
49
54
  Spree::Taxon.where(id: taxon_ids).touch_all
50
- Spree::Taxons::TouchFeaturedSections.call(taxon_ids: taxon_ids)
55
+ Spree::Taxons::TouchFeaturedSections.call(taxon_ids: taxon_ids) if defined?(Spree::Taxons::TouchFeaturedSections)
51
56
 
52
57
  success(true)
53
58
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ # Logs all Spree events to Rails logger.
5
+ #
6
+ # Enabled by default. To disable, set Spree::Config.events_log_enabled = false
7
+ #
8
+ # Events are logged at info level. Sensitive parameters are filtered using
9
+ # Rails.application.config.filter_parameters.
10
+ #
11
+ # @example Output
12
+ # [Spree Event] order.complete | payload: {"id"=>1} | 0.5ms
13
+ #
14
+ class EventLogSubscriber
15
+ NAMESPACE = 'spree'
16
+
17
+ class << self
18
+ def attach_to_notifications
19
+ # Always detach first to ensure clean state after code reload
20
+ detach_from_notifications
21
+
22
+ @subscription = ActiveSupport::Notifications.subscribe(/\.#{NAMESPACE}$/) do |name, start, finish, _id, payload|
23
+ log_event(name, start, finish, payload)
24
+ end
25
+
26
+ @attached = true
27
+ Rails.logger.info "[Spree Events] Event logging enabled"
28
+ end
29
+
30
+ def detach_from_notifications
31
+ ActiveSupport::Notifications.unsubscribe(@subscription) if @subscription
32
+ @subscription = nil
33
+ @attached = false
34
+ end
35
+
36
+ def attached?
37
+ @attached || false
38
+ end
39
+
40
+ private
41
+
42
+ def log_event(name, start, finish, payload)
43
+ spree_event = payload[:event]
44
+ return unless spree_event
45
+
46
+ event_name = spree_event.name
47
+ event_payload = filter_sensitive_params(spree_event.payload)
48
+ duration = ((finish - start) * 1000).round(2)
49
+
50
+ Rails.logger.info " \e[36m[Spree Event]\e[0m \e[1m#{event_name}\e[0m | payload: #{event_payload.inspect} | #{duration}ms"
51
+ end
52
+
53
+ def filter_sensitive_params(payload)
54
+ parameter_filter.filter(payload)
55
+ end
56
+
57
+ def parameter_filter
58
+ @parameter_filter ||= ActiveSupport::ParameterFilter.new(
59
+ Rails.application.config.filter_parameters
60
+ )
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ # Handles Export lifecycle events.
5
+ #
6
+ # This subscriber replaces the following callbacks in Spree::Export:
7
+ # - after_commit :generate_async, on: :create
8
+ #
9
+ # When an export is created, this subscriber triggers the async generation job.
10
+ #
11
+ # We use async: false because this subscriber just queues a background job,
12
+ # so there's no benefit to running the subscriber itself asynchronously.
13
+ #
14
+ class ExportSubscriber < Spree::Subscriber
15
+ subscribes_to 'export.created', async: false
16
+
17
+ on 'export.created', :generate_export_async
18
+
19
+ def generate_export_async(event)
20
+ export_id = event.payload['id']
21
+ return unless export_id
22
+
23
+ Spree::Exports::GenerateJob.perform_later(export_id)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ class InvitationEmailSubscriber < Spree::Subscriber
5
+ subscribes_to 'invitation.created', 'invitation.accepted', 'invitation.resent'
6
+
7
+ on 'invitation.created', :send_invitation_email
8
+ on 'invitation.accepted', :send_acceptance_notification
9
+ on 'invitation.resent', :resend_invitation_email
10
+
11
+ private
12
+
13
+ def send_invitation_email(event)
14
+ invitation = find_invitation(event)
15
+ return unless invitation
16
+
17
+ InvitationMailer.invitation_email(invitation).deliver_later
18
+ end
19
+
20
+ def send_acceptance_notification(event)
21
+ invitation = find_invitation(event)
22
+ return unless invitation
23
+
24
+ InvitationMailer.invitation_accepted(invitation).deliver_later
25
+ end
26
+
27
+ def resend_invitation_email(event)
28
+ invitation = find_invitation(event)
29
+ return unless invitation
30
+ return if invitation.expired? || invitation.deleted? || invitation.accepted?
31
+
32
+ InvitationMailer.invitation_email(invitation).deliver_later
33
+ end
34
+
35
+ def find_invitation(event)
36
+ invitation_id = event.payload['id']
37
+ Spree::Invitation.find_by(id: invitation_id)
38
+ end
39
+ end
40
+ end