spree_core 4.10.1 → 5.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (476) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/config/spree_core_manifest.js +4 -0
  3. data/app/assets/images/google_on_white_hdpi.png +0 -0
  4. data/app/controllers/spree/base_controller.rb +1 -4
  5. data/app/finders/spree/orders/find_complete.rb +14 -2
  6. data/app/finders/spree/products/find.rb +74 -23
  7. data/app/finders/spree/stores/find_current.rb +6 -2
  8. data/app/helpers/spree/addresses_helper.rb +106 -0
  9. data/app/helpers/spree/base_helper.rb +83 -55
  10. data/app/helpers/spree/currency_helper.rb +12 -0
  11. data/app/helpers/spree/images_helper.rb +18 -0
  12. data/app/helpers/spree/mail_helper.rb +24 -0
  13. data/app/helpers/spree/products_helper.rb +1 -20
  14. data/app/javascript/spree/core/controllers/address_autocomplete_controller.js +233 -0
  15. data/app/javascript/spree/core/controllers/address_form_controller.js +98 -0
  16. data/app/javascript/spree/core/controllers/enable_button_controller.js +29 -0
  17. data/app/javascript/spree/core/helpers/address_autocomplete/google_places_suggestions_provider.js +179 -0
  18. data/app/javascript/spree/core/helpers/debounce.js +9 -0
  19. data/app/javascript/spree/core/helpers/scroll_lock.js +25 -0
  20. data/app/jobs/spree/addresses/geocode_address_job.rb +31 -0
  21. data/app/jobs/spree/base_job.rb +1 -0
  22. data/app/jobs/spree/coupon_codes/bulk_generate_job.rb +17 -0
  23. data/app/jobs/spree/exports/generate_job.rb +12 -0
  24. data/app/jobs/spree/products/auto_match_taxons_job.rb +14 -0
  25. data/app/jobs/spree/products/touch_taxons_job.rb +12 -0
  26. data/app/jobs/spree/reports/generate_job.rb +12 -0
  27. data/app/jobs/spree/stock_locations/stock_items/create_job.rb +1 -1
  28. data/app/jobs/spree/themes/duplicate_components_job.rb +59 -0
  29. data/app/jobs/spree/themes/screenshot_job.rb +81 -0
  30. data/app/jobs/spree/variants/remove_from_incomplete_orders_job.rb +2 -0
  31. data/app/jobs/spree/variants/remove_line_item_job.rb +2 -0
  32. data/app/mailers/spree/base_mailer.rb +51 -0
  33. data/app/mailers/spree/export_mailer.rb +19 -0
  34. data/app/mailers/spree/report_mailer.rb +20 -0
  35. data/app/mailers/spree/test_mailer.rb +8 -0
  36. data/app/models/action_text/rich_text_decorator.rb +11 -0
  37. data/app/models/action_text/video_embed.rb +13 -0
  38. data/app/models/acts_as_taggable_on/tag_decorator.rb +10 -0
  39. data/app/models/concerns/spree/calculated_adjustments.rb +2 -0
  40. data/app/models/concerns/spree/display_on.rb +13 -0
  41. data/app/models/concerns/spree/has_one_link.rb +42 -0
  42. data/app/models/concerns/spree/has_page_links.rb +53 -0
  43. data/app/models/concerns/spree/metadata.rb +3 -7
  44. data/app/models/concerns/spree/multi_searchable.rb +21 -0
  45. data/app/models/concerns/spree/multi_store_resource.rb +9 -0
  46. data/app/models/concerns/spree/number_as_param.rb +4 -2
  47. data/app/models/concerns/spree/parameterizable_name.rb +21 -0
  48. data/app/models/concerns/spree/previewable.rb +17 -0
  49. data/app/models/concerns/spree/product_scopes.rb +7 -7
  50. data/app/models/concerns/spree/stores/setup.rb +52 -0
  51. data/app/models/concerns/spree/stores/socials.rb +68 -0
  52. data/app/models/concerns/spree/user_address.rb +4 -0
  53. data/app/models/concerns/spree/user_methods.rb +61 -11
  54. data/app/models/concerns/spree/user_reporting.rb +14 -6
  55. data/app/models/concerns/spree/user_roles.rb +1 -1
  56. data/app/models/spree/ability.rb +4 -2
  57. data/app/models/spree/address.rb +122 -28
  58. data/app/models/spree/adjustment.rb +4 -1
  59. data/app/models/spree/asset/support/active_storage.rb +1 -1
  60. data/app/models/spree/asset.rb +18 -6
  61. data/app/models/spree/base.rb +38 -7
  62. data/app/models/spree/base_analytics_event_handler.rb +49 -0
  63. data/app/models/spree/calculator.rb +1 -1
  64. data/app/models/spree/classification.rb +10 -1
  65. data/app/models/spree/country.rb +1 -1
  66. data/app/models/spree/coupon_code.rb +38 -0
  67. data/app/models/spree/credit_card.rb +4 -3
  68. data/app/models/spree/current.rb +9 -0
  69. data/app/models/spree/custom_domain.rb +53 -0
  70. data/app/models/spree/customer_return.rb +13 -1
  71. data/app/models/spree/data_feed.rb +1 -1
  72. data/app/models/spree/digital.rb +5 -6
  73. data/app/models/spree/digital_link.rb +11 -6
  74. data/app/models/spree/export.rb +172 -0
  75. data/app/models/spree/exports/orders.rb +23 -0
  76. data/app/models/spree/exports/products.rb +35 -0
  77. data/app/models/spree/gateway/bogus.rb +5 -0
  78. data/app/models/spree/gateway.rb +14 -4
  79. data/app/models/spree/gateway_customer.rb +13 -0
  80. data/app/models/spree/image/configuration/active_storage.rb +1 -1
  81. data/app/models/spree/inventory_unit.rb +1 -1
  82. data/app/models/spree/legacy_user.rb +3 -1
  83. data/app/models/spree/line_item.rb +37 -2
  84. data/app/models/spree/log_entry.rb +1 -1
  85. data/app/models/spree/option_type.rb +40 -6
  86. data/app/models/spree/option_type_prototype.rb +1 -1
  87. data/app/models/spree/option_value.rb +35 -5
  88. data/app/models/spree/option_value_variant.rb +2 -2
  89. data/app/models/spree/order/address_book.rb +34 -15
  90. data/app/models/spree/order/checkout.rb +12 -2
  91. data/app/models/spree/order/currency_updater.rb +1 -1
  92. data/app/models/spree/order/digital.rb +14 -3
  93. data/app/models/spree/order/emails.rb +1 -1
  94. data/app/models/spree/order/payments.rb +1 -13
  95. data/app/models/spree/order/store_credit.rb +17 -5
  96. data/app/models/spree/order/webhooks.rb +1 -1
  97. data/app/models/spree/order.rb +179 -49
  98. data/app/models/spree/order_promotion.rb +1 -1
  99. data/app/models/spree/order_updater.rb +9 -3
  100. data/app/models/spree/page.rb +184 -0
  101. data/app/models/spree/page_block.rb +69 -0
  102. data/app/models/spree/page_blocks/buttons.rb +29 -0
  103. data/app/models/spree/page_blocks/heading.rb +18 -0
  104. data/app/models/spree/page_blocks/image.rb +17 -0
  105. data/app/models/spree/page_blocks/link.rb +21 -0
  106. data/app/models/spree/page_blocks/mega_nav.rb +33 -0
  107. data/app/models/spree/page_blocks/mega_nav_with_subcategories.rb +32 -0
  108. data/app/models/spree/page_blocks/nav.rb +15 -0
  109. data/app/models/spree/page_blocks/newsletter_form.rb +18 -0
  110. data/app/models/spree/page_blocks/products/buy_buttons.rb +12 -0
  111. data/app/models/spree/page_blocks/products/price.rb +18 -0
  112. data/app/models/spree/page_blocks/products/quantity_selector.rb +12 -0
  113. data/app/models/spree/page_blocks/products/share.rb +8 -0
  114. data/app/models/spree/page_blocks/products/title.rb +15 -0
  115. data/app/models/spree/page_blocks/products/variant_picker.rb +9 -0
  116. data/app/models/spree/page_blocks/subheading.rb +17 -0
  117. data/app/models/spree/page_blocks/text.rb +16 -0
  118. data/app/models/spree/page_link.rb +59 -0
  119. data/app/models/spree/page_section.rb +215 -0
  120. data/app/models/spree/page_sections/announcement_bar.rb +30 -0
  121. data/app/models/spree/page_sections/collection_banner.rb +18 -0
  122. data/app/models/spree/page_sections/custom_code.rb +11 -0
  123. data/app/models/spree/page_sections/featured_posts.rb +43 -0
  124. data/app/models/spree/page_sections/featured_product.rb +46 -0
  125. data/app/models/spree/page_sections/featured_taxon.rb +88 -0
  126. data/app/models/spree/page_sections/featured_taxons.rb +45 -0
  127. data/app/models/spree/page_sections/footer.rb +94 -0
  128. data/app/models/spree/page_sections/header.rb +62 -0
  129. data/app/models/spree/page_sections/image_banner.rb +38 -0
  130. data/app/models/spree/page_sections/image_with_text.rb +48 -0
  131. data/app/models/spree/page_sections/main_password_footer.rb +18 -0
  132. data/app/models/spree/page_sections/main_password_header.rb +20 -0
  133. data/app/models/spree/page_sections/newsletter.rb +47 -0
  134. data/app/models/spree/page_sections/page_title.rb +19 -0
  135. data/app/models/spree/page_sections/post_details.rb +19 -0
  136. data/app/models/spree/page_sections/post_grid.rb +19 -0
  137. data/app/models/spree/page_sections/product_details.rb +16 -0
  138. data/app/models/spree/page_sections/product_grid.rb +13 -0
  139. data/app/models/spree/page_sections/related_products.rb +60 -0
  140. data/app/models/spree/page_sections/rich_text.rb +20 -0
  141. data/app/models/spree/page_sections/taxon_banner.rb +18 -0
  142. data/app/models/spree/page_sections/taxon_grid.rb +17 -0
  143. data/app/models/spree/page_sections/video.rb +99 -0
  144. data/app/models/spree/pages/account.rb +15 -0
  145. data/app/models/spree/pages/cart.rb +9 -0
  146. data/app/models/spree/pages/checkout.rb +9 -0
  147. data/app/models/spree/pages/custom.rb +34 -0
  148. data/app/models/spree/pages/homepage.rb +68 -0
  149. data/app/models/spree/pages/login.rb +15 -0
  150. data/app/models/spree/pages/password.rb +57 -0
  151. data/app/models/spree/pages/post.rb +27 -0
  152. data/app/models/spree/pages/post_list.rb +32 -0
  153. data/app/models/spree/pages/product_details.rb +29 -0
  154. data/app/models/spree/pages/search_results.rb +43 -0
  155. data/app/models/spree/pages/shop_all.rb +36 -0
  156. data/app/models/spree/pages/taxon.rb +29 -0
  157. data/app/models/spree/pages/taxon_list.rb +41 -0
  158. data/app/models/spree/pages/wishlist.rb +11 -0
  159. data/app/models/spree/payment/gateway_options.rb +13 -15
  160. data/app/models/spree/payment/processing.rb +1 -1
  161. data/app/models/spree/payment/webhooks.rb +1 -1
  162. data/app/models/spree/payment.rb +61 -12
  163. data/app/models/spree/payment_capture_event.rb +1 -1
  164. data/app/models/spree/payment_method/store_credit.rb +9 -1
  165. data/app/models/spree/payment_method.rb +26 -8
  166. data/app/models/spree/payment_source.rb +2 -2
  167. data/app/models/spree/post.rb +108 -0
  168. data/app/models/spree/post_category.rb +33 -0
  169. data/app/models/spree/preference.rb +1 -1
  170. data/app/models/spree/price.rb +10 -3
  171. data/app/models/spree/product/webhooks.rb +1 -1
  172. data/app/models/spree/product.rb +325 -54
  173. data/app/models/spree/product_option_type.rb +1 -1
  174. data/app/models/spree/product_promotion_rule.rb +1 -1
  175. data/app/models/spree/product_property.rb +4 -1
  176. data/app/models/spree/promotion/actions/create_line_items.rb +37 -2
  177. data/app/models/spree/promotion/rules/country.rb +22 -4
  178. data/app/models/spree/promotion/rules/currency.rb +21 -0
  179. data/app/models/spree/promotion/rules/item_total.rb +12 -3
  180. data/app/models/spree/promotion/rules/option_value.rb +5 -20
  181. data/app/models/spree/promotion/rules/product.rb +33 -1
  182. data/app/models/spree/promotion/rules/taxon.rb +31 -0
  183. data/app/models/spree/promotion/rules/user.rb +33 -4
  184. data/app/models/spree/promotion.rb +136 -15
  185. data/app/models/spree/promotion_action.rb +31 -1
  186. data/app/models/spree/promotion_action_line_item.rb +1 -1
  187. data/app/models/spree/promotion_category.rb +1 -1
  188. data/app/models/spree/promotion_handler/cart.rb +1 -1
  189. data/app/models/spree/promotion_handler/coupon.rb +46 -8
  190. data/app/models/spree/promotion_handler/free_shipping.rb +1 -1
  191. data/app/models/spree/promotion_handler/promotion_duplicator.rb +6 -5
  192. data/app/models/spree/promotion_rule.rb +23 -1
  193. data/app/models/spree/promotion_rule_taxon.rb +1 -1
  194. data/app/models/spree/promotion_rule_user.rb +1 -1
  195. data/app/models/spree/property.rb +11 -3
  196. data/app/models/spree/property_prototype.rb +1 -1
  197. data/app/models/spree/prototype.rb +1 -1
  198. data/app/models/spree/prototype_taxon.rb +1 -1
  199. data/app/models/spree/refund.rb +24 -4
  200. data/app/models/spree/refund_reason.rb +12 -2
  201. data/app/models/spree/reimbursement/credit.rb +1 -1
  202. data/app/models/spree/reimbursement/emails.rb +1 -1
  203. data/app/models/spree/reimbursement.rb +5 -3
  204. data/app/models/spree/reimbursement_type.rb +1 -1
  205. data/app/models/spree/report.rb +110 -0
  206. data/app/models/spree/report_line_item.rb +27 -0
  207. data/app/models/spree/report_line_items/products_performance.rb +76 -0
  208. data/app/models/spree/report_line_items/sales_total.rb +49 -0
  209. data/app/models/spree/reports/products_performance.rb +44 -0
  210. data/app/models/spree/reports/sales_total.rb +14 -0
  211. data/app/models/spree/return_authorization.rb +4 -1
  212. data/app/models/spree/return_authorization_reason.rb +1 -1
  213. data/app/models/spree/return_item.rb +2 -1
  214. data/app/models/spree/role.rb +5 -2
  215. data/app/models/spree/role_user.rb +2 -2
  216. data/app/models/spree/shipment/emails.rb +1 -1
  217. data/app/models/spree/shipment/webhooks.rb +1 -1
  218. data/app/models/spree/shipment.rb +14 -4
  219. data/app/models/spree/shipping_category.rb +1 -1
  220. data/app/models/spree/shipping_method.rb +48 -8
  221. data/app/models/spree/shipping_method_category.rb +1 -1
  222. data/app/models/spree/shipping_method_zone.rb +1 -1
  223. data/app/models/spree/shipping_rate.rb +21 -3
  224. data/app/models/spree/state.rb +1 -1
  225. data/app/models/spree/state_change.rb +1 -1
  226. data/app/models/spree/stock_item/webhooks.rb +1 -1
  227. data/app/models/spree/stock_item.rb +9 -6
  228. data/app/models/spree/stock_location.rb +35 -8
  229. data/app/models/spree/stock_movement/webhooks.rb +1 -1
  230. data/app/models/spree/stock_movement.rb +9 -3
  231. data/app/models/spree/stock_transfer.rb +41 -3
  232. data/app/models/spree/store.rb +345 -72
  233. data/app/models/spree/store_credit.rb +12 -4
  234. data/app/models/spree/store_credit_category.rb +1 -1
  235. data/app/models/spree/store_credit_event.rb +21 -1
  236. data/app/models/spree/store_credit_type.rb +1 -1
  237. data/app/models/spree/store_payment_method.rb +1 -1
  238. data/app/models/spree/store_product.rb +1 -1
  239. data/app/models/spree/store_promotion.rb +1 -1
  240. data/app/models/spree/tax_category.rb +15 -1
  241. data/app/models/spree/tax_rate.rb +1 -1
  242. data/app/models/spree/taxon.rb +210 -27
  243. data/app/models/spree/taxon_image/configuration/active_storage.rb +1 -1
  244. data/app/models/spree/taxon_rule.rb +25 -0
  245. data/app/models/spree/taxon_rules/available_on.rb +20 -0
  246. data/app/models/spree/taxon_rules/sale.rb +16 -0
  247. data/app/models/spree/taxon_rules/tag.rb +19 -0
  248. data/app/models/spree/taxonomy.rb +3 -2
  249. data/app/models/spree/theme.rb +200 -0
  250. data/app/models/spree/themes/default.rb +94 -0
  251. data/app/models/spree/variant/webhooks.rb +1 -1
  252. data/app/models/spree/variant.rb +211 -62
  253. data/app/models/spree/wished_item.rb +1 -1
  254. data/app/models/spree/wishlist.rb +1 -1
  255. data/app/models/spree/zone.rb +1 -1
  256. data/app/models/spree/zone_member.rb +1 -1
  257. data/app/presenters/spree/csv/order_line_item_presenter.rb +145 -0
  258. data/app/presenters/spree/csv/product_presenter.rb +63 -0
  259. data/app/presenters/spree/csv/product_variant_presenter.rb +130 -0
  260. data/app/services/spree/addresses/create.rb +31 -6
  261. data/app/services/spree/addresses/helper.rb +7 -4
  262. data/app/services/spree/addresses/update.rb +79 -12
  263. data/app/services/spree/cart/remove_out_of_stock_items.rb +56 -0
  264. data/app/services/spree/checkout/add_store_credit.rb +6 -1
  265. data/app/services/spree/checkout/advance.rb +44 -4
  266. data/app/services/spree/checkout/select_shipping_method.rb +2 -0
  267. data/app/services/spree/coupon_codes/bulk_generate.rb +37 -0
  268. data/app/services/spree/coupon_codes/coupon_codes_handler.rb +34 -0
  269. data/app/services/spree/orders/create_user_account.rb +70 -0
  270. data/app/services/spree/orders/update_contact_information.rb +19 -0
  271. data/app/services/spree/products/auto_match_taxons.rb +64 -0
  272. data/app/services/spree/products/duplicator.rb +121 -0
  273. data/app/services/spree/products/prepare_nested_attributes.rb +169 -0
  274. data/app/services/spree/seeds/admin_user.rb +22 -0
  275. data/app/services/spree/seeds/all.rb +1 -0
  276. data/app/services/spree/seeds/stores.rb +5 -10
  277. data/app/services/spree/seeds/zones.rb +2 -0
  278. data/app/services/spree/tags/bulk_add.rb +38 -0
  279. data/app/services/spree/tags/bulk_remove.rb +24 -0
  280. data/app/services/spree/taxons/add_products.rb +39 -0
  281. data/app/services/spree/taxons/regenerate_products.rb +53 -0
  282. data/app/services/spree/taxons/remove_products.rb +53 -0
  283. data/app/services/spree/taxons/touch_featured_sections.rb +21 -0
  284. data/app/services/spree/themes/duplicator.rb +40 -0
  285. data/app/services/spree/variants/remove_line_items.rb +1 -1
  286. data/app/sorters/spree/classifications/sort.rb +68 -0
  287. data/app/sorters/spree/products/sort.rb +2 -3
  288. data/app/views/action_text/video_embeds/_thumbnail.html.erb +1 -0
  289. data/app/views/action_text/video_embeds/_video_embed.html.erb +3 -0
  290. data/app/views/active_storage/blobs/_blob.html.erb +20 -0
  291. data/app/views/layouts/action_text/contents/_content.html.erb +3 -0
  292. data/app/views/layouts/spree/base_mailer.html.erb +46 -0
  293. data/app/views/spree/addresses/_form.html.erb +58 -0
  294. data/app/views/spree/addresses/_suggestions_box.erb +14 -0
  295. data/app/views/spree/export_mailer/export_done.html.erb +15 -0
  296. data/app/views/spree/report_mailer/report_done.html.erb +15 -0
  297. data/app/views/spree/shared/_base_mailer_footer.html.erb +12 -0
  298. data/app/views/spree/shared/_base_mailer_header.html.erb +6 -0
  299. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +456 -0
  300. data/app/views/spree/shared/_google_places_api_loader.html.erb +7 -0
  301. data/app/views/spree/shared/_mailer_line_item.html.erb +12 -0
  302. data/app/views/spree/shared/_mailer_logo.html.erb +41 -0
  303. data/app/views/spree/shared/_payment.html.erb +41 -0
  304. data/app/views/spree/test_mailer/test_email.html.erb +40 -0
  305. data/app/views/spree/test_mailer/test_email.text.erb +4 -0
  306. data/config/i18n-tasks.yml +178 -0
  307. data/config/importmap.rb +14 -0
  308. data/config/initializers/acts_as_taggable_on.rb +2 -0
  309. data/config/initializers/inflections.rb +2 -0
  310. data/config/initializers/mobility.rb +4 -0
  311. data/config/initializers/oembed.rb +1 -0
  312. data/config/locales/en.yml +823 -413
  313. data/config/routes.rb +6 -5
  314. data/db/migrate/20210914000000_spree_four_three.rb +0 -79
  315. data/db/migrate/20240913143518_change_default_value_of_spree_option_types_filterable.rb +5 -0
  316. data/db/migrate/20240914153106_add_display_on_to_spree_properties.rb +5 -0
  317. data/db/migrate/20240915144935_add_position_to_spree_properties.rb +6 -0
  318. data/db/migrate/20241004181911_create_spree_coupon_codes.rb +15 -0
  319. data/db/migrate/20241005093437_add_multi_code_to_spree_promotions.rb +14 -0
  320. data/db/migrate/20241014140140_translate_rich_texts.rb +17 -0
  321. data/db/migrate/20241030134309_create_spree_exports.rb +23 -0
  322. data/db/migrate/20241104083457_migrate_spree_promotion_rules_option_value_eligible_values.rb +16 -0
  323. data/db/migrate/20241123110646_add_estimated_transit_fields_to_spree_shipping_methods.rb +6 -0
  324. data/db/migrate/20241127193411_create_spree_taxon_rules.rb +13 -0
  325. data/db/migrate/20241127223627_add_rules_match_policy_and_sort_order_to_spree_taxons.rb +6 -0
  326. data/db/migrate/20241128103947_add_automatic_to_spree_taxons.rb +5 -0
  327. data/db/migrate/20241218183905_add_gateway_customer_profile_id_to_spree_payment_sources.rb +5 -0
  328. data/db/migrate/20250107220432_add_accept_marketing_and_signup_for_an_account_to_spree_orders.rb +6 -0
  329. data/db/migrate/20250110171203_add_quick_checkout_to_spree_addresses.rb +6 -0
  330. data/db/migrate/20250113180019_add_preferences_to_spree_stores.rb +5 -0
  331. data/db/migrate/20250114193857_add_metadata_to_spree_stores.rb +13 -0
  332. data/db/migrate/20250119165904_create_spree_custom_domains.rb +22 -0
  333. data/db/migrate/20250120094216_create_page_builder_models.rb +78 -0
  334. data/db/migrate/20250120152208_add_default_locale_to_action_text_rich_texts.rb +7 -0
  335. data/db/migrate/20250121160028_create_spree_posts_and_spree_post_categories.rb +33 -0
  336. data/db/migrate/20250122113708_add_first_and_last_name_to_spree_admin_class.rb +9 -0
  337. data/db/migrate/20250123135358_add_custom_code_fields_to_spree_store.rb +7 -0
  338. data/db/migrate/20250127083740_add_kind_to_spree_properties.rb +5 -0
  339. data/db/migrate/20250127112758_add_latitude_and_longitude_to_spree_addresses.rb +6 -0
  340. data/db/migrate/20250127151258_add_phone_to_spree_users.rb +5 -0
  341. data/db/migrate/20250204162453_create_spree_reports.rb +13 -0
  342. data/db/migrate/20250207084000_add_accepts_email_marketing_field_to_spree_users_table.rb +6 -0
  343. data/db/migrate/20250217171018_create_action_text_video_embeds.rb +11 -0
  344. data/db/migrate/20250304115943_add_performed_by_to_spree_reimbursements.rb +5 -0
  345. data/db/migrate/20250305121352_remove_page_builder_indices.rb +11 -0
  346. data/db/migrate/20250305121657_remove_spree_posts_indices.rb +7 -0
  347. data/db/migrate/20250311105934_create_spree_gateway_customers.rb +18 -0
  348. data/db/migrate/20250312202705_add_unique_index_on_promotion_rules_associations.rb +75 -0
  349. data/db/migrate/20250313104226_add_user_type_to_spree_role_users.rb +18 -0
  350. data/db/migrate/20250313175830_add_unique_index_on_promotion_action_line_items.rb +29 -0
  351. data/db/migrate/20250314144210_create_spree_taggings_and_spree_tags.rb +38 -0
  352. data/lib/generators/spree/authentication/custom/custom_generator.rb +49 -0
  353. data/lib/generators/spree/authentication/custom/templates/authentication_helpers.rb.tt +50 -0
  354. data/lib/generators/spree/authentication/devise/devise_generator.rb +57 -0
  355. data/lib/generators/spree/authentication/devise/templates/authentication_helpers.rb.tt +50 -0
  356. data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
  357. data/lib/generators/spree/dummy/templates/rails/database.yml +1 -0
  358. data/lib/generators/spree/dummy/templates/rails/test.rb +1 -1
  359. data/lib/generators/spree/install/install_generator.rb +21 -36
  360. data/lib/generators/spree/install/templates/config/initializers/spree.rb +40 -6
  361. data/lib/normalize_string.rb +18 -0
  362. data/lib/spree/analytics.rb +11 -0
  363. data/lib/spree/core/components.rb +1 -1
  364. data/lib/spree/core/configuration.rb +14 -11
  365. data/lib/spree/core/controller_helpers/auth.rb +0 -26
  366. data/lib/spree/core/controller_helpers/order.rb +77 -12
  367. data/lib/spree/core/controller_helpers/search.rb +2 -0
  368. data/lib/spree/core/controller_helpers/store.rb +0 -5
  369. data/lib/spree/core/controller_helpers/strong_parameters.rb +4 -0
  370. data/lib/spree/core/controller_helpers/turbo.rb +19 -0
  371. data/lib/spree/core/dependencies.rb +3 -5
  372. data/lib/spree/core/engine.rb +158 -7
  373. data/lib/spree/core/preferences/configuration.rb +2 -44
  374. data/lib/spree/core/preferences/preferable.rb +9 -0
  375. data/lib/spree/core/preferences/preferable_class_methods.rb +11 -1
  376. data/lib/spree/core/preferences/runtime_configuration.rb +13 -2
  377. data/lib/spree/core/search/base.rb +2 -0
  378. data/lib/spree/core/version.rb +1 -1
  379. data/lib/spree/core.rb +61 -11
  380. data/lib/spree/i18n.rb +5 -8
  381. data/lib/spree/migrations.rb +1 -1
  382. data/lib/spree/permitted_attributes.rb +24 -15
  383. data/lib/spree/testing_support/authorization_helpers.rb +9 -6
  384. data/lib/spree/testing_support/capybara_config.rb +11 -0
  385. data/lib/spree/testing_support/common_rake.rb +20 -12
  386. data/lib/spree/testing_support/factories/calculator_factory.rb +16 -0
  387. data/lib/spree/testing_support/factories/country_factory.rb +8 -0
  388. data/lib/spree/testing_support/factories/coupon_code_factory.rb +7 -0
  389. data/lib/spree/testing_support/factories/custom_domain_factory.rb +7 -0
  390. data/lib/spree/testing_support/factories/export_factory.rb +32 -0
  391. data/lib/spree/testing_support/factories/gateway_customer_factory.rb +7 -0
  392. data/lib/spree/testing_support/factories/order_factory.rb +14 -3
  393. data/lib/spree/testing_support/factories/page_block_factory.rb +21 -0
  394. data/lib/spree/testing_support/factories/page_factory.rb +33 -0
  395. data/lib/spree/testing_support/factories/page_link_factory.rb +7 -0
  396. data/lib/spree/testing_support/factories/page_section_factory.rb +24 -0
  397. data/lib/spree/testing_support/factories/payment_factory.rb +2 -2
  398. data/lib/spree/testing_support/factories/post_category_factory.rb +7 -0
  399. data/lib/spree/testing_support/factories/post_factory.rb +10 -0
  400. data/lib/spree/testing_support/factories/product_factory.rb +3 -8
  401. data/lib/spree/testing_support/factories/product_property_factory.rb +1 -1
  402. data/lib/spree/testing_support/factories/promotion_action_factory.rb +5 -0
  403. data/lib/spree/testing_support/factories/promotion_factory.rb +7 -9
  404. data/lib/spree/testing_support/factories/promotion_rule_factory.rb +12 -0
  405. data/lib/spree/testing_support/factories/property_factory.rb +1 -1
  406. data/lib/spree/testing_support/factories/report_factory.rb +33 -0
  407. data/lib/spree/testing_support/factories/role_user_factory.rb +7 -0
  408. data/lib/spree/testing_support/factories/shipping_method_factory.rb +9 -0
  409. data/lib/spree/testing_support/factories/stock_transfer_factory.rb +5 -2
  410. data/lib/spree/testing_support/factories/store_factory.rb +6 -9
  411. data/lib/spree/testing_support/factories/taxon_factory.rb +13 -0
  412. data/lib/spree/testing_support/factories/taxon_rule_factory.rb +38 -0
  413. data/lib/spree/testing_support/factories/theme_factory.rb +14 -0
  414. data/lib/spree/testing_support/factories/user_factory.rb +13 -11
  415. data/lib/spree/testing_support/factories/variant_factory.rb +23 -5
  416. data/lib/spree/testing_support/jobs.rb +1 -7
  417. data/lib/spree/testing_support/metadata.rb +13 -1
  418. data/lib/spree/testing_support/order_walkthrough.rb +1 -7
  419. data/lib/spree/testing_support/preferences.rb +1 -4
  420. data/lib/spree/testing_support/store.rb +26 -0
  421. data/lib/spree_core.rb +1 -0
  422. data/vendor/javascript/@rails--request.js.js +4 -0
  423. data/vendor/javascript/@stimulus-components--auto-submit.js +4 -0
  424. data/vendor/javascript/stimulus-reveal-controller.js +4 -0
  425. data/vendor/javascript/tailwindcss-stimulus-components.js +4 -0
  426. metadata +340 -197
  427. data/Gemfile +0 -3
  428. data/app/finders/spree/cms_pages/find.rb +0 -41
  429. data/app/finders/spree/menus/find.rb +0 -11
  430. data/app/models/concerns/spree/display_link.rb +0 -30
  431. data/app/models/spree/cms/pages/feature_page.rb +0 -7
  432. data/app/models/spree/cms/pages/homepage.rb +0 -20
  433. data/app/models/spree/cms/pages/standard_page.rb +0 -4
  434. data/app/models/spree/cms/sections/featured_article.rb +0 -22
  435. data/app/models/spree/cms/sections/hero_image.rb +0 -38
  436. data/app/models/spree/cms/sections/image_gallery.rb +0 -97
  437. data/app/models/spree/cms/sections/product_carousel.rb +0 -14
  438. data/app/models/spree/cms/sections/rich_text_content.rb +0 -13
  439. data/app/models/spree/cms/sections/side_by_side_images.rb +0 -68
  440. data/app/models/spree/cms_page.rb +0 -70
  441. data/app/models/spree/cms_section.rb +0 -69
  442. data/app/models/spree/cms_section_image.rb +0 -9
  443. data/app/models/spree/cms_section_image_one.rb +0 -4
  444. data/app/models/spree/cms_section_image_three.rb +0 -4
  445. data/app/models/spree/cms_section_image_two.rb +0 -4
  446. data/app/models/spree/icon.rb +0 -7
  447. data/app/models/spree/linkable/homepage.rb +0 -3
  448. data/app/models/spree/linkable/uri.rb +0 -3
  449. data/app/models/spree/menu.rb +0 -66
  450. data/app/models/spree/menu_item.rb +0 -72
  451. data/brakeman.ignore +0 -328
  452. data/db/migrate/20211201202851_update_linkable_resource_types.rb +0 -10
  453. data/db/migrate/20220329113557_fix_cms_pages_unique_indexes.rb +0 -8
  454. data/lib/generators/spree/custom_authentication/custom_authentication_generator.rb +0 -23
  455. data/lib/generators/spree/custom_authentication/templates/authentication_helpers.rb.tt +0 -23
  456. data/lib/generators/spree/custom_user/custom_user_generator.rb +0 -46
  457. data/lib/generators/spree/custom_user/templates/current_user_helpers.rb.tt +0 -15
  458. data/lib/generators/spree/custom_user/templates/initializer.rb.tt +0 -1
  459. data/lib/generators/spree/custom_user/templates/migration.rb.tt +0 -7
  460. data/lib/generators/spree/dummy/templates/package.json +0 -12
  461. data/lib/spree/core/product_duplicator.rb +0 -85
  462. data/lib/spree/core/runtime_configuration.rb +0 -10
  463. data/lib/spree/testing_support/factories/cms_page_factory.rb +0 -20
  464. data/lib/spree/testing_support/factories/cms_section_factory.rb +0 -31
  465. data/lib/spree/testing_support/factories/icon_factory.rb +0 -9
  466. data/lib/spree/testing_support/factories/menu_factory.rb +0 -16
  467. data/lib/spree/testing_support/factories/menu_item_factory.rb +0 -10
  468. data/script/rails +0 -9
  469. data/spec/fixtures/favicon.ico +0 -0
  470. data/spec/fixtures/files/icon_256x256.gif +0 -0
  471. data/spec/fixtures/files/icon_256x256.png +0 -0
  472. data/spec/fixtures/files/icon_512x512.png +0 -0
  473. data/spec/fixtures/files/img_256x128.png +0 -0
  474. data/spec/fixtures/text-file.txt +0 -1
  475. data/spec/fixtures/thinking-cat.jpg +0 -0
  476. data/spree_core.gemspec +0 -62
@@ -1,18 +1,19 @@
1
1
  module Spree
2
- class Payment < Spree::Base
2
+ class Payment < Spree.base_class
3
3
  class GatewayOptions
4
4
  def initialize(payment)
5
5
  @payment = payment
6
+ @order = payment.order
6
7
  end
7
8
 
9
+ attr_reader :payment, :order
10
+ delegate :currency, to: :payment
11
+ delegate :email, to: :order
12
+
8
13
  def statement_descriptor_suffix
9
14
  order.number
10
15
  end
11
16
 
12
- def email
13
- order.email
14
- end
15
-
16
17
  def customer
17
18
  order.email
18
19
  end
@@ -26,7 +27,11 @@ module Spree
26
27
  end
27
28
 
28
29
  def order_id
29
- "#{order.number}-#{@payment.number}"
30
+ "#{order.number}-#{payment.number}"
31
+ end
32
+
33
+ def payment_id
34
+ payment.number
30
35
  end
31
36
 
32
37
  def shipping
@@ -45,10 +50,6 @@ module Spree
45
50
  order.promo_total * exchange_multiplier
46
51
  end
47
52
 
48
- def currency
49
- @payment.currency
50
- end
51
-
52
53
  def billing_address
53
54
  order.bill_address.try(:active_merchant_hash)
54
55
  end
@@ -64,6 +65,7 @@ module Spree
64
65
  :customer_id,
65
66
  :ip,
66
67
  :order_id,
68
+ :payment_id,
67
69
  :shipping,
68
70
  :tax,
69
71
  :subtotal,
@@ -82,12 +84,8 @@ module Spree
82
84
 
83
85
  private
84
86
 
85
- def order
86
- @payment.order
87
- end
88
-
89
87
  def exchange_multiplier
90
- @payment.payment_method.try(:exchange_multiplier) || 1.0
88
+ payment.payment_method.try(:exchange_multiplier) || 1.0
91
89
  end
92
90
  end
93
91
  end
@@ -1,7 +1,7 @@
1
1
  require_dependency 'spree/payment/gateway_options'
2
2
 
3
3
  module Spree
4
- class Payment < Spree::Base
4
+ class Payment < Spree.base_class
5
5
  module Processing
6
6
  extend ActiveSupport::Concern
7
7
  included do
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Payment < Spree::Base
2
+ class Payment < Spree.base_class
3
3
  module Webhooks
4
4
  extend ActiveSupport::Concern
5
5
 
@@ -1,7 +1,7 @@
1
1
  require_dependency 'spree/payment/processing'
2
2
 
3
3
  module Spree
4
- class Payment < Spree::Base
4
+ class Payment < Spree.base_class
5
5
  include Spree::Core::NumberGenerator.new(prefix: 'P', letters: true, length: 7)
6
6
  include Spree::NumberIdentifier
7
7
  include Spree::NumberAsParam
@@ -10,6 +10,8 @@ module Spree
10
10
  include Spree::Security::Payments
11
11
  end
12
12
 
13
+ extend Spree::DisplayMoney
14
+
13
15
  include Spree::Payment::Processing
14
16
  include Spree::Payment::Webhooks
15
17
 
@@ -35,20 +37,24 @@ module Spree
35
37
 
36
38
  before_validation :validate_source
37
39
 
38
- after_save :create_payment_profile, if: :profiles_supported?
40
+ after_initialize :set_amount, if: -> { new_record? && order.present? && !amount_changed? }
39
41
 
42
+ #
43
+ # Callbacks
44
+ after_save :create_payment_profile, if: :profiles_supported?
40
45
  # update the order totals, etc.
41
- set_callback :save, :after, :update_order, unless: -> { capture_on_dispatch }
42
-
46
+ after_save :update_order, unless: -> { capture_on_dispatch }
43
47
  # invalidate previously entered payments
44
48
  after_create :invalidate_old_payments
45
49
  after_create :create_eligible_credit_event
50
+ after_destroy :update_order
46
51
 
47
52
  attr_accessor :source_attributes, :request_env, :capture_on_dispatch
48
53
 
49
54
  after_initialize :build_source
50
55
 
51
56
  validates :amount, numericality: true
57
+ validate :amount_must_be_less_than_or_equal_to_max_amount, if: -> { new_record? || amount_changed? }
52
58
 
53
59
  delegate :store_credit?, to: :payment_method, allow_nil: true
54
60
  delegate :name, to: :payment_method, allow_nil: true, prefix: true
@@ -77,12 +83,13 @@ module Spree
77
83
  self.whitelisted_ransackable_attributes = %w[number amount state response_code avs_response cvv_response_code cvv_response_message]
78
84
 
79
85
  # transaction_id is much easier to understand
80
- def transaction_id
81
- response_code
82
- end
86
+ alias_attribute :transaction_id, :response_code
83
87
 
84
88
  delegate :currency, to: :order
85
89
 
90
+ money_methods :amount, :credit_allowed
91
+ alias money display_amount # for compatibility with older versions of Spree
92
+
86
93
  # order state machine (see http://github.com/pluginaweek/state_machine/tree/master for details)
87
94
  state_machine initial: :checkout do
88
95
  # With card payments, happens before purchase or authorization happens
@@ -131,10 +138,18 @@ module Spree
131
138
  payment_method.payment_source_class.unscoped { super }
132
139
  end
133
140
 
134
- def money
135
- Spree::Money.new(amount, currency: currency)
141
+ def max_amount
142
+ return amount if order.nil?
143
+
144
+ amount_from_order = order.total - order.payment_total
145
+
146
+ if payment_method&.store_credit?
147
+ store_credits = order.available_store_credits
148
+ store_credits.any? ? [store_credits.first.amount_remaining, amount_from_order].min : amount_from_order
149
+ else
150
+ amount_from_order
151
+ end
136
152
  end
137
- alias display_amount money
138
153
 
139
154
  def amount=(amount)
140
155
  self[:amount] =
@@ -158,13 +173,28 @@ module Spree
158
173
  credit_allowed > 0
159
174
  end
160
175
 
176
+ # we shouldn't allow deleting payments via admin interface
177
+ def can_be_deleted?
178
+ false
179
+ end
180
+
161
181
  # see https://github.com/spree/spree/issues/981
162
182
  def build_source
163
183
  return unless new_record?
164
184
 
165
185
  if source_attributes.present? && source.blank? && payment_method.try(:payment_source_class)
166
- self.source = payment_method.payment_source_class.new(source_attributes)
167
- source.payment_method_id = payment_method.id
186
+ self.source = if source_attributes[:id].present? && source_attributes[:id] != :new
187
+ payment_method.payment_source_class.find(source_attributes[:id])
188
+ else
189
+ payment_method.payment_source_class.new(source_attributes)
190
+ end
191
+
192
+ if source.user_id.present? && source.user_id != order.user_id
193
+ self.source = nil
194
+ return
195
+ end
196
+
197
+ source.payment_method_id = payment_method.id if source.respond_to?(:payment_method_id)
168
198
  source.user_id = order.user_id if order
169
199
  end
170
200
  end
@@ -194,6 +224,10 @@ module Spree
194
224
  true
195
225
  end
196
226
 
227
+ def gateway_dashboard_payment_url
228
+ payment_method.try(:gateway_dashboard_payment_url, self)
229
+ end
230
+
197
231
  def captured_amount
198
232
  capture_events.sum(:amount)
199
233
  end
@@ -206,8 +240,23 @@ module Spree
206
240
  checkout? || pending?
207
241
  end
208
242
 
243
+ def display_source_name
244
+ return if source.blank?
245
+
246
+ source_class = source.class
247
+ source_class.respond_to?(:display_name) ? source_class.display_name : source_class.name.demodulize.split(/(?=[A-Z])/).join(' ')
248
+ end
249
+
209
250
  private
210
251
 
252
+ def set_amount
253
+ self.amount = order.total - order.payment_total
254
+ end
255
+
256
+ def amount_must_be_less_than_or_equal_to_max_amount
257
+ errors.add(:amount, :greater_than_max_amount, max_amount: max_amount) if amount > max_amount
258
+ end
259
+
211
260
  def after_void
212
261
  # Implement your logic here
213
262
  end
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class PaymentCaptureEvent < Spree::Base
2
+ class PaymentCaptureEvent < Spree.base_class
3
3
  if defined?(Spree::Webhooks::HasWebhooks)
4
4
  include Spree::Webhooks::HasWebhooks
5
5
  end
@@ -4,6 +4,14 @@ module Spree
4
4
  ::Spree::StoreCredit
5
5
  end
6
6
 
7
+ def method_type
8
+ 'store_credit'
9
+ end
10
+
11
+ def description_partial_name
12
+ 'store_credit'
13
+ end
14
+
7
15
  def can_capture?(payment)
8
16
  ['checkout', 'pending'].include?(payment.state)
9
17
  end
@@ -110,7 +118,7 @@ module Spree
110
118
  authorization: auth_code || response
111
119
  )
112
120
  else
113
- ActiveMerchant::Billing::Response.new(false, store_credit.errors.full_messages.join, {}, {})
121
+ ActiveMerchant::Billing::Response.new(false, store_credit.errors.full_messages.to_sentence, {}, {})
114
122
  end
115
123
  end
116
124
  end
@@ -1,22 +1,22 @@
1
1
  module Spree
2
- class PaymentMethod < Spree::Base
2
+ class PaymentMethod < Spree.base_class
3
3
  acts_as_paranoid
4
4
  acts_as_list
5
5
 
6
6
  include Spree::MultiStoreResource
7
7
  include Spree::Metadata
8
+ include Spree::DisplayOn
8
9
  if defined?(Spree::Security::PaymentMethods)
9
10
  include Spree::Security::PaymentMethods
10
11
  end
11
12
 
12
- DISPLAY = [:both, :front_end, :back_end].freeze
13
+ scope :active, -> { where(active: true).order(position: :asc) }
14
+ scope :available, -> { active.where(display_on: [:front_end, :back_end, :both]) }
13
15
 
14
- scope :active, -> { where(active: true).order(position: :asc) }
15
- scope :available, -> { active.where(display_on: [:front_end, :back_end, :both]) }
16
- scope :available_on_front_end, -> { active.where(display_on: [:front_end, :both]) }
17
- scope :available_on_back_end, -> { active.where(display_on: [:back_end, :both]) }
16
+ after_initialize :set_name, if: :new_record?
18
17
 
19
18
  validates :name, presence: true
19
+ auto_strip_attributes :name
20
20
 
21
21
  has_many :store_payment_methods, class_name: 'Spree::StorePaymentMethod'
22
22
  has_many :stores, class_name: 'Spree::Store', through: :store_payment_methods
@@ -26,6 +26,8 @@ module Spree
26
26
  has_many :credit_cards, class_name: 'Spree::CreditCard'
27
27
  end
28
28
 
29
+ has_many :gateway_customers, class_name: 'Spree::GatewayCustomer'
30
+
29
31
  def self.providers
30
32
  Rails.application.config.spree.payment_methods
31
33
  end
@@ -47,6 +49,14 @@ module Spree
47
49
  type.demodulize.downcase
48
50
  end
49
51
 
52
+ def default_name
53
+ self.class.name.demodulize.titleize.gsub(/Gateway/, '').strip
54
+ end
55
+
56
+ def payment_icon_name
57
+ type.demodulize.gsub(/(^Spree::Gateway::|Gateway$)/, '').downcase.gsub(/\s+/, '').strip
58
+ end
59
+
50
60
  def self.find_with_destroyed(*args)
51
61
  unscoped { find(*args) }
52
62
  end
@@ -59,6 +69,10 @@ module Spree
59
69
  true
60
70
  end
61
71
 
72
+ def show_in_admin?
73
+ true
74
+ end
75
+
62
76
  # Custom gateways should redefine this method. See Gateway implementation
63
77
  # as an example
64
78
  def reusable_sources(_order)
@@ -83,8 +97,8 @@ module Spree
83
97
 
84
98
  # Custom PaymentMethod/Gateway can redefine this method to check method
85
99
  # availability for concrete order.
86
- def available_for_order?(_order)
87
- true
100
+ def available_for_order?(order)
101
+ !order.covered_by_store_credit?
88
102
  end
89
103
 
90
104
  def available_for_store?(store)
@@ -104,5 +118,9 @@ module Spree
104
118
  def public_preference_keys
105
119
  []
106
120
  end
121
+
122
+ def set_name
123
+ self.name ||= default_name
124
+ end
107
125
  end
108
126
  end
@@ -1,9 +1,9 @@
1
1
  module Spree
2
- class PaymentSource < Spree::Base
2
+ class PaymentSource < Spree.base_class
3
3
  include Spree::Metadata
4
4
 
5
5
  belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
6
- belongs_to :user, class_name: 'Spree::User', optional: true
6
+ belongs_to :user, class_name: Spree.user_class.to_s, optional: true
7
7
 
8
8
  validates_uniqueness_of :gateway_payment_profile_id, scope: :type
9
9
  end
@@ -0,0 +1,108 @@
1
+ module Spree
2
+ class Post < Spree.base_class
3
+ include Spree::SingleStoreResource
4
+ extend FriendlyId
5
+
6
+ friendly_id :slug_candidates, use: %i[slugged scoped history], scope: %i[store_id deleted?]
7
+ acts_as_paranoid
8
+ acts_as_taggable_on :tags
9
+ acts_as_taggable_tenant :store_id
10
+
11
+ if defined?(PgSearch)
12
+ include PgSearch::Model
13
+ pg_search_scope :search_by_title, against: :title
14
+ else
15
+ scope :search_by_title, ->(query) { where('title LIKE ?', "%#{query}%") }
16
+ end
17
+
18
+ #
19
+ # Ransack filtering
20
+ #
21
+ self.whitelisted_ransackable_attributes = %w[author_id post_category_id published_at]
22
+ self.whitelisted_ransackable_associations = %w[author post_category]
23
+ self.whitelisted_ransackable_scopes = %w[search_by_title]
24
+
25
+ #
26
+ # Attachments
27
+ #
28
+ has_one_attached :image, service: Spree.public_storage_service_name
29
+
30
+ #
31
+ # Rich Text
32
+ #
33
+ has_rich_text :content
34
+ has_rich_text :excerpt
35
+
36
+ #
37
+ # Associations
38
+ #
39
+ belongs_to :author, class_name: Spree.admin_user_class.to_s
40
+ belongs_to :store, class_name: 'Spree::Store'
41
+ belongs_to :post_category, class_name: 'Spree::PostCategory', optional: true
42
+ alias category post_category
43
+
44
+ #
45
+ # Validations
46
+ #
47
+ validates :title, :store, :author, presence: true
48
+ validates :slug, presence: true, uniqueness: { scope: :store_id, conditions: -> { where(deleted_at: nil) } }
49
+ validates :meta_title, length: { maximum: 160 }, allow_blank: true
50
+ validates :meta_description, length: { maximum: 320 }, allow_blank: true
51
+ validates :image, content_type: Rails.application.config.active_storage.web_image_content_types
52
+
53
+ #
54
+ # Scopes
55
+ #
56
+ scope :published, -> { where(published_at: [..Time.current]) }
57
+
58
+ delegate :name, to: :author, prefix: true, allow_nil: true
59
+ delegate :title, to: :post_category, prefix: true, allow_nil: true
60
+
61
+ def should_generate_new_friendly_id?
62
+ slug.blank? || (persisted? && title_changed?)
63
+ end
64
+
65
+ def slug_candidates
66
+ [
67
+ :title,
68
+ [:title, :id]
69
+ ]
70
+ end
71
+
72
+ def published?
73
+ published_at.present?
74
+ end
75
+
76
+ def page_builder_url
77
+ return unless Spree::Core::Engine.routes.url_helpers.respond_to?(:post_path)
78
+
79
+ Spree::Core::Engine.routes.url_helpers.post_path(self)
80
+ end
81
+
82
+ def publish(date = nil)
83
+ update(published_at: date || Time.current)
84
+ end
85
+
86
+ def unpublish
87
+ update(published_at: nil)
88
+ end
89
+
90
+ def description
91
+ excerpt.to_plain_text.presence || content.to_plain_text
92
+ end
93
+
94
+ def shortened_description
95
+ desc = excerpt.to_plain_text.presence || content.to_plain_text
96
+ desc.length > 320 ? "#{desc[0...320]}..." : desc
97
+ end
98
+
99
+ def self.to_tom_select_json
100
+ pluck(:id, :title).map do |id, title|
101
+ {
102
+ id: id,
103
+ name: title
104
+ }
105
+ end.as_json
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,33 @@
1
+ module Spree
2
+ class PostCategory < Spree.base_class
3
+ include Spree::SingleStoreResource
4
+ extend FriendlyId
5
+
6
+ friendly_id :slug_candidates, use: %i[slugged scoped history], scope: %i[store_id]
7
+
8
+ #
9
+ # Associations
10
+ #
11
+ belongs_to :store, class_name: 'Spree::Store'
12
+ has_many :posts, class_name: 'Spree::Post'
13
+
14
+ #
15
+ # Validations
16
+ #
17
+ validates :title, :store, presence: true
18
+ validates :slug, presence: true, uniqueness: { scope: :store_id }
19
+
20
+ has_rich_text :description
21
+
22
+ def should_generate_new_friendly_id?
23
+ slug.blank? || title_changed?
24
+ end
25
+
26
+ def slug_candidates
27
+ [
28
+ :title,
29
+ [:title, :id]
30
+ ]
31
+ end
32
+ end
33
+ end
@@ -1,4 +1,4 @@
1
- class Spree::Preference < Spree::Base
1
+ class Spree::Preference < Spree.base_class
2
2
  if Rails::VERSION::STRING >= '7.1.0'
3
3
  serialize :value, coder: YAML
4
4
  else
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Price < Spree::Base
2
+ class Price < Spree.base_class
3
3
  include Spree::VatPriceCalculation
4
4
  if defined?(Spree::Webhooks::HasWebhooks)
5
5
  include Spree::Webhooks::HasWebhooks
@@ -18,22 +18,25 @@ module Spree
18
18
  validates :amount, allow_nil: true, numericality: {
19
19
  greater_than_or_equal_to: 0,
20
20
  less_than_or_equal_to: MAXIMUM_AMOUNT
21
- }, if: -> { Spree::RuntimeConfig.allow_empty_price_amount }
21
+ }, if: -> { Spree::Config.allow_empty_price_amount }
22
22
 
23
23
  # new behavior
24
24
  validates :amount, allow_nil: false, numericality: {
25
25
  greater_than_or_equal_to: 0,
26
26
  less_than_or_equal_to: MAXIMUM_AMOUNT
27
- }, unless: -> { Spree::RuntimeConfig.allow_empty_price_amount }
27
+ }, unless: -> { Spree::Config.allow_empty_price_amount }
28
28
 
29
29
  validates :compare_at_amount, allow_nil: true, numericality: {
30
30
  greater_than_or_equal_to: 0,
31
31
  less_than_or_equal_to: MAXIMUM_AMOUNT
32
32
  }
33
33
 
34
+ validates :currency, presence: true
35
+
34
36
  scope :with_currency, ->(currency) { where(currency: currency) }
35
37
  scope :non_zero, -> { where.not(amount: [nil, 0]) }
36
38
  scope :discounted, -> { where('compare_at_amount > amount') }
39
+ scope :for_products, ->(products) { joins(variant: :product).where("#{Spree::Product.table_name}.id" => products) }
37
40
 
38
41
  extend DisplayMoney
39
42
  money_methods :amount, :price, :compare_at_amount
@@ -41,6 +44,10 @@ module Spree
41
44
 
42
45
  self.whitelisted_ransackable_attributes = ['amount', 'compare_at_amount']
43
46
 
47
+ attribute :eligible_for_taxon_matching, :boolean, default: false
48
+ before_validation -> { self.eligible_for_taxon_matching = new_record? ? discounted? : discounted? != was_discounted? }
49
+ after_commit -> { variant&.product&.auto_match_taxons }, if: -> { eligible_for_taxon_matching? }
50
+
44
51
  def money
45
52
  Spree::Money.new(amount || 0, currency: currency.upcase)
46
53
  end
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Product < Spree::Base
2
+ class Product < Spree.base_class
3
3
  module Webhooks
4
4
  def send_product_activated_webhook
5
5
  # Implement your logic here