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
@@ -0,0 +1,49 @@
1
+ module Spree
2
+ class BaseAnalyticsEventHandler
3
+ # Initializes the event handler
4
+ # @param client [Object] The client object
5
+ # @param opts [Hash] The options
6
+ # @option opts [User] :user
7
+ # @option opts [String] :session_id
8
+ def initialize(opts = {})
9
+ @user = opts[:user]
10
+ @session = opts[:session]
11
+ @request = opts[:request]
12
+ end
13
+
14
+ attr_reader :user, :session, :request
15
+
16
+ # Returns the client
17
+ # @return [Object] The client object
18
+ def client
19
+ raise NotImplementedError, 'Subclasses must implement the client method'
20
+ end
21
+
22
+ # Handles the event
23
+ # @param event_name [String] eg. 'order_completed'
24
+ # @param properties [Hash] eg. { product: Spree::Product, taxon: Spree::Taxon, query: String }
25
+ # rubocop:disable Lint/UnusedMethodArgument
26
+ def handle_event(event_name, properties = {})
27
+ raise NotImplementedError, 'Subclasses must implement the handle method'
28
+ end
29
+ # rubocop:enable Lint/UnusedMethodArgument
30
+
31
+ # Returns the human name for the event
32
+ # @param event_name [String] eg. 'order_completed'
33
+ # @return [String] eg. 'Order Completed'
34
+ def event_human_name(event_name)
35
+ Analytics.events[event_name.to_sym]
36
+ end
37
+
38
+ protected
39
+
40
+ # Returns the identity hash for the event
41
+ # @return [Hash] eg. { user_id: 1, session_id: '123' }
42
+ def identity_hash
43
+ {
44
+ user_id: user&.id,
45
+ session_id: session&.id
46
+ }
47
+ end
48
+ end
49
+ end
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Calculator < Spree::Base
2
+ class Calculator < Spree.base_class
3
3
  acts_as_paranoid
4
4
 
5
5
  belongs_to :calculable, polymorphic: true, optional: true, inverse_of: :calculator
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Classification < Spree::Base
2
+ class Classification < Spree.base_class
3
3
  self.table_name = 'spree_products_taxons'
4
4
  acts_as_list scope: :taxon
5
5
 
@@ -14,5 +14,14 @@ module Spree
14
14
  validates :taxon_id, uniqueness: { scope: :product_id, message: :already_linked, allow_blank: true }
15
15
 
16
16
  self.whitelisted_ransackable_attributes = ['taxon_id', 'product_id']
17
+
18
+ scope :by_best_selling, lambda { |order_direction = :desc|
19
+ left_joins(product: :orders).
20
+ select("#{Spree::Classification.table_name}.*, COUNT(#{Spree::Order.table_name}.id) AS completed_orders_count, SUM(#{Spree::Order.table_name}.total) AS completed_orders_total").
21
+ where(Spree::Order.table_name => { id: nil }).
22
+ or(where.not(Spree::Order.table_name => { completed_at: nil })).
23
+ group("#{Spree::Classification.table_name}.id").
24
+ reorder(completed_orders_count: order_direction, completed_orders_total: order_direction)
25
+ }
17
26
  end
18
27
  end
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Country < Spree::Base
2
+ class Country < Spree.base_class
3
3
  has_many :addresses, dependent: :restrict_with_error
4
4
  has_many :states,
5
5
  -> { order name: :asc },
@@ -0,0 +1,38 @@
1
+ module Spree
2
+ class CouponCode < Spree.base_class
3
+ include Spree::Security::CouponCodes if defined?(Spree::Security::CouponCodes)
4
+
5
+ enum :state, %i(unused used)
6
+
7
+ acts_as_paranoid
8
+
9
+ scope :used_with_code, ->(code) { used.where(code: code.downcase) }
10
+ scope :with_order, ->(order_id) { where(order_id: order_id) }
11
+ scope :in_promotions, ->(promotion_ids) { where(promotion_id: promotion_ids) }
12
+ scope :not_in_promotions, ->(promotion_ids) { where.not(promotion_id: promotion_ids) }
13
+
14
+ belongs_to :promotion, class_name: 'Spree::Promotion', touch: true
15
+ belongs_to :order, class_name: 'Spree::Order'
16
+
17
+ validates :code, presence: true, uniqueness: { scope: spree_base_uniqueness_scope, conditions: -> { where(deleted_at: nil) } }
18
+ validates :state, :promotion, presence: true
19
+
20
+ self.whitelisted_ransackable_attributes = %w[state code]
21
+
22
+ def self.used?(code)
23
+ used_with_code(code).any?
24
+ end
25
+
26
+ def apply_order!(order)
27
+ update(order: order, state: 'used')
28
+ end
29
+
30
+ def remove_from_order
31
+ update(order: nil, state: 'unused')
32
+ end
33
+
34
+ def display_code
35
+ code.upcase
36
+ end
37
+ end
38
+ end
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class CreditCard < Spree::Base
2
+ class CreditCard < Spree.base_class
3
3
  include ActiveMerchant::Billing::CreditCardMethods
4
4
  include Spree::Metadata
5
5
  if defined?(Spree::Webhooks::HasWebhooks)
@@ -12,8 +12,9 @@ module Spree
12
12
  acts_as_paranoid
13
13
 
14
14
  belongs_to :payment_method
15
- belongs_to :user, class_name: "::#{Spree.user_class}", foreign_key: 'user_id',
16
- optional: true
15
+ belongs_to :user, class_name: "::#{Spree.user_class}", foreign_key: 'user_id', optional: true
16
+ belongs_to :gateway_customer, class_name: 'Spree::GatewayCustomer', optional: true
17
+
17
18
  has_many :payments, as: :source
18
19
 
19
20
  before_save :set_last_digits
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ class Current < ::ActiveSupport::CurrentAttributes
3
+ attribute :store
4
+
5
+ def store
6
+ super || Spree::Store.default
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,53 @@
1
+ module Spree
2
+ class CustomDomain < Spree::Base
3
+ include Spree::SingleStoreResource
4
+ include Spree::Metadata
5
+
6
+ auto_strip_attributes :url
7
+
8
+ #
9
+ # Associations
10
+ #
11
+ belongs_to :store, class_name: 'Spree::Store', inverse_of: :custom_domains, touch: true
12
+
13
+ #
14
+ # Validations
15
+ #
16
+ validates :url, presence: true, uniqueness: true, format: {
17
+ with: %r{[a-z][a-z0-9-]*[a-z0-9]}i
18
+ }, length: { in: 1..63 }
19
+ validate :url_is_valid
20
+
21
+ #
22
+ # Callbacks
23
+ #
24
+ before_validation :sanitize_url
25
+ after_save :ensure_has_one_default
26
+ after_validation :ensure_default, on: :create
27
+
28
+ def url_is_valid
29
+ parts = url.split('.')
30
+
31
+ errors.add(:url, 'use domain or subdomain') if (parts[0] != 'www' && parts.size > 3) || (parts[0] == 'www' && parts.size > 4) || parts.size < 2
32
+ end
33
+
34
+ def ensure_default
35
+ self.default = store.custom_domains.count.zero?
36
+ end
37
+
38
+ def ensure_has_one_default
39
+ store.custom_domains.where.not(id: id).update_all(default: false) if default?
40
+ end
41
+
42
+ def active?
43
+ true
44
+ end
45
+
46
+ private
47
+
48
+ # remove https:// and http:// from the url
49
+ def sanitize_url
50
+ self.url = url&.gsub(%r{https?://}, '')
51
+ end
52
+ end
53
+ end
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class CustomerReturn < Spree::Base
2
+ class CustomerReturn < Spree.base_class
3
3
  include Spree::Core::NumberGenerator.new(prefix: 'CR', length: 9)
4
4
  include Spree::NumberIdentifier
5
5
  include Spree::Metadata
@@ -54,6 +54,18 @@ module Spree
54
54
  return_items.sum(:pre_tax_amount)
55
55
  end
56
56
 
57
+ def can_create_reimbursement?
58
+ !fully_reimbursed? && completely_decided? && no_pending_reimbursements?
59
+ end
60
+
61
+ def no_pending_reimbursements?
62
+ if association(:reimbursements).loaded?
63
+ reimbursements.select(&:pending?).empty?
64
+ else
65
+ reimbursements.where(reimbursement_status: :pending).none?
66
+ end
67
+ end
68
+
57
69
  private
58
70
 
59
71
  def inventory_units
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class DataFeed < Base
2
+ class DataFeed < Spree.base_class
3
3
  belongs_to :store, class_name: 'Spree::Store', foreign_key: 'store_id'
4
4
 
5
5
  scope :for_store, ->(store) { where(store: store) }
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Digital < Spree::Base
2
+ class Digital < Spree.base_class
3
3
  belongs_to :variant
4
4
  has_many :digital_links, dependent: :destroy
5
5
 
@@ -7,13 +7,12 @@ module Spree
7
7
  include Spree::Webhooks::HasWebhooks
8
8
  end
9
9
 
10
- if Spree.private_storage_service_name
11
- has_one_attached :attachment, service: Spree.private_storage_service_name
12
- else
13
- has_one_attached :attachment
14
- end
10
+ has_one_attached :attachment, service: Spree.private_storage_service_name
15
11
 
16
12
  validates :attachment, attached: true
17
13
  validates :variant, presence: true
14
+
15
+ delegate :product, to: :variant
16
+ delegate :filename, :content_type, to: :attachment
18
17
  end
19
18
  end
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class DigitalLink < Spree::Base
2
+ class DigitalLink < Spree.base_class
3
3
  if Rails::VERSION::STRING >= '7.1.0'
4
4
  has_secure_token on: :save
5
5
  else
@@ -20,21 +20,24 @@ module Spree
20
20
  validates :digital, :line_item, presence: true
21
21
  validates :access_counter, numericality: { greater_than_or_equal_to: 0 }
22
22
 
23
+ delegate :filename, :content_type, to: :digital
24
+ delegate :order, to: :line_item
25
+
23
26
  def authorizable?
24
27
  !(expired? || access_limit_exceeded?)
25
28
  end
26
29
 
27
30
  def expired?
28
- if line_item.order.store.limit_digital_download_days
29
- created_at <= line_item.order.store.digital_asset_authorized_days.day.ago
31
+ if line_item.order.store.preferred_limit_digital_download_days
32
+ created_at <= line_item.order.store.preferred_digital_asset_authorized_days.day.ago
30
33
  else
31
34
  false
32
35
  end
33
36
  end
34
37
 
35
38
  def access_limit_exceeded?
36
- if line_item.order.store.limit_digital_download_count
37
- access_counter >= line_item.order.store.digital_asset_authorized_clicks
39
+ if line_item.order.store.preferred_limit_digital_download_count
40
+ access_counter >= line_item.order.store.preferred_digital_asset_authorized_clicks
38
41
  else
39
42
  false
40
43
  end
@@ -43,7 +46,9 @@ module Spree
43
46
  # This method should be called when a download is initiated.
44
47
  # It returns +true+ or +false+ depending on whether the authorization is granted.
45
48
  def authorize!
46
- authorizable? && increment!(:access_counter, touch: true) ? true : false
49
+ ActiveRecord::Base.connected_to(role: :writing) do
50
+ authorizable? && increment!(:access_counter, touch: true)
51
+ end
47
52
  end
48
53
 
49
54
  def reset!
@@ -0,0 +1,172 @@
1
+ require 'csv'
2
+
3
+ module Spree
4
+ class Export < Spree.base_class
5
+ SUPPORTED_FILE_FORMATS = %i[csv].freeze
6
+
7
+ include Spree::SingleStoreResource
8
+ include Spree::NumberIdentifier
9
+ include Spree::NumberAsParam
10
+ include Spree::VendorConcern if defined?(Spree::VendorConcern)
11
+
12
+ include Spree::Core::NumberGenerator.new(prefix: 'EF')
13
+
14
+ #
15
+ # Associations
16
+ #
17
+ belongs_to :store, class_name: 'Spree::Store'
18
+ belongs_to :user, class_name: Spree.admin_user_class.to_s
19
+ belongs_to :vendor, -> { with_deleted }, class_name: 'Spree::Vendor', optional: true
20
+
21
+ #
22
+ # Validations
23
+ #
24
+ validates :format, :store, :user, :type, presence: true
25
+
26
+ #
27
+ # Enums
28
+ #
29
+ enum :format, SUPPORTED_FILE_FORMATS.each_with_index.to_h
30
+
31
+ #
32
+ # Ransack configuration
33
+ #
34
+ self.whitelisted_ransackable_attributes = %w[number type format vendor_id]
35
+
36
+ #
37
+ # Attachments
38
+ #
39
+ has_one_attached :attachment, service: Spree.private_storage_service_name
40
+
41
+ #
42
+ # Callbacks
43
+ #
44
+ before_validation :set_default_format, on: :create
45
+ before_create :clear_search_params, if: -> { record_selection == 'all' }
46
+ after_commit :generate_async, on: :create
47
+
48
+ #
49
+ # Virtual attributes
50
+ #
51
+ attribute :record_selection, :string, default: 'filtered'
52
+
53
+ def done?
54
+ attachment.present? && attachment.attached?
55
+ end
56
+
57
+ def generate_async
58
+ Spree::Exports::GenerateJob.perform_later(id)
59
+ end
60
+
61
+ def generate
62
+ send(:"generate_#{format}")
63
+ handle_attachment
64
+ send_export_done_email
65
+ end
66
+
67
+ def generate_csv
68
+ ::CSV.open(export_tmp_file_path, 'wb', encoding: 'UTF-8', col_sep: ',', row_sep: "\r\n") do |csv|
69
+ csv << csv_headers
70
+ records_to_export.includes(scope_includes).find_in_batches do |batch|
71
+ batch.each do |record|
72
+ if multi_line_csv?
73
+ record.to_csv(store).each do |line|
74
+ csv << line
75
+ end
76
+ else
77
+ csv << record.to_csv(store)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
83
+
84
+ def multi_line_csv?
85
+ false
86
+ end
87
+
88
+ def csv_headers
89
+ raise NotImplementedError, 'csv_headers must be implemented'
90
+ end
91
+
92
+ def build_csv_line(_record)
93
+ raise NotImplementedError, 'build_csv_line must be implemented'
94
+ end
95
+
96
+ def handle_attachment
97
+ file = ::File.open(export_tmp_file_path)
98
+ attachment.attach(io: file, filename: export_file_name)
99
+ ::File.delete(export_tmp_file_path) if ::File.exist?(export_tmp_file_path)
100
+ end
101
+
102
+ def scope
103
+ scope = model_class
104
+ scope = scope.for_store(store) if model_class.respond_to?(:for_store)
105
+ scope = scope.for_vendor(vendor) if model_class.respond_to?(:for_vendor) && vendor.present?
106
+ scope.accessible_by(current_ability)
107
+ end
108
+
109
+ def records_to_export
110
+ if search_params.present?
111
+ scope.ransack(search_params.is_a?(String) ? JSON.parse(search_params.to_s).to_h : search_params)
112
+ else
113
+ scope.ransack
114
+ end.result
115
+ end
116
+
117
+ def scope_includes
118
+ []
119
+ end
120
+
121
+ # eg. Spree::Exports::Products => Spree::Product
122
+ def model_class
123
+ "Spree::#{type.demodulize.singularize}".constantize
124
+ end
125
+
126
+ def current_ability
127
+ @current_ability ||= Spree::Dependencies.ability_class.constantize.new(user)
128
+ end
129
+
130
+ # eg. Spree::Exports::Products => products-store-my-store-code-20241030133348.csv
131
+ def export_file_name
132
+ "#{type.demodulize.underscore}-#{store.code}-#{created_at.strftime('%Y%m%d%H%M%S')}.#{format}"
133
+ end
134
+
135
+ def export_tmp_file_path
136
+ Rails.root.join('tmp', export_file_name)
137
+ end
138
+
139
+ def send_export_done_email
140
+ Spree::ExportMailer.export_done(self).deliver_later
141
+ end
142
+
143
+ class << self
144
+ def available_types
145
+ Rails.application.config.spree.export_types
146
+ end
147
+
148
+ def available_models
149
+ available_types.map(&:model_class)
150
+ end
151
+
152
+ def type_for_model(model)
153
+ available_types.find { |type| type.model_class.to_s == model.to_s }
154
+ end
155
+
156
+ # eg. Spree::Exports::Products => Spree::Product
157
+ def model_class
158
+ "Spree::#{to_s.demodulize.singularize}".constantize
159
+ end
160
+ end
161
+
162
+ private
163
+
164
+ def set_default_format
165
+ self.format = SUPPORTED_FILE_FORMATS.first if format.blank?
166
+ end
167
+
168
+ def clear_search_params
169
+ self.search_params = nil
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,23 @@
1
+ module Spree
2
+ module Exports
3
+ class Orders < Spree::Export
4
+ def scope_includes
5
+ [
6
+ :payments,
7
+ :shipments,
8
+ { bill_address: :state },
9
+ { ship_address: :state },
10
+ { line_items: { variant: { product: [:taxons] } } }
11
+ ]
12
+ end
13
+
14
+ def multi_line_csv?
15
+ true
16
+ end
17
+
18
+ def csv_headers
19
+ Spree::CSV::OrderLineItemPresenter::HEADERS
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ module Spree
2
+ module Exports
3
+ class Products < Spree::Export
4
+ # to avoid N+1 queries
5
+ def scope_includes
6
+ [:tax_category, :master, { taxons: :taxonomy }, { product_properties: [:property] }, { variants_including_master: variant_includes }]
7
+ end
8
+
9
+ def variant_includes
10
+ [:images, :prices, :stock_items, { option_values: [:option_type] }]
11
+ end
12
+
13
+ def multi_line_csv?
14
+ true
15
+ end
16
+
17
+ # when doing full product export, we want to exclude archived products
18
+ def scope
19
+ if search_params.nil?
20
+ super.where.not(status: 'archived')
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ def csv_headers
27
+ @csv_headers ||= Spree::CSV::ProductVariantPresenter::CSV_HEADERS + properties_headers
28
+ end
29
+
30
+ def properties_headers
31
+ @properties_headers ||= Spree::Property.order(:position).count.times.flat_map { |n| ["property#{n + 1}_name", "property#{n + 1}_value"] }
32
+ end
33
+ end
34
+ end
35
+ end
@@ -10,11 +10,16 @@ module Spree
10
10
  attr_accessor :test
11
11
 
12
12
  preference :dummy_key, :string, default: 'PUBLICKEY123'
13
+ preference :dummy_secret_key, :password, default: 'SECRETKEY123'
13
14
 
14
15
  def provider_class
15
16
  self.class
16
17
  end
17
18
 
19
+ def show_in_admin?
20
+ false
21
+ end
22
+
18
23
  def create_profile(payment)
19
24
  return if payment.source.has_payment_profile?
20
25
 
@@ -4,15 +4,19 @@ module Spree
4
4
 
5
5
  delegate :authorize, :purchase, :capture, :void, :credit, to: :provider
6
6
 
7
- validates :type, presence: true
8
-
9
- preference :server, :string, default: 'test'
10
- preference :test_mode, :boolean, default: true
7
+ validates :type, presence: true, inclusion: { in: :valid_providers_list }
11
8
 
12
9
  def payment_source_class
13
10
  CreditCard
14
11
  end
15
12
 
13
+ # Override in the gateway to provide a payment url
14
+ # eg. for Stripe, this would be the payment intent url
15
+ # https://dashboard.stripe.com/payments/#{payment.transaction_id}
16
+ def gateway_dashboard_payment_url(_payment)
17
+ nil
18
+ end
19
+
16
20
  def provider
17
21
  gateway_options = options
18
22
  gateway_options.delete :login if gateway_options.key?(:login) && gateway_options[:login].nil?
@@ -77,5 +81,11 @@ module Spree
77
81
  end
78
82
  end
79
83
  end
84
+
85
+ private
86
+
87
+ def valid_providers_list
88
+ Spree::PaymentMethod.providers.map(&:to_s)
89
+ end
80
90
  end
81
91
  end
@@ -0,0 +1,13 @@
1
+ module Spree
2
+ class GatewayCustomer < Spree.base_class
3
+ belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
4
+ belongs_to :user, class_name: Spree.user_class.to_s
5
+
6
+ validates :payment_method, presence: true
7
+ validates :user, presence: true
8
+ validates :profile_id, presence: true
9
+ validates :payment_method_id, uniqueness: { scope: :user_id }
10
+
11
+ encrypts :profile_id, deterministic: true if Rails.configuration.active_record.encryption.include?(:primary_key)
12
+ end
13
+ end
@@ -5,7 +5,7 @@ module Spree
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- validates :attachment, attached: true, content_type: /\Aimage\/.*\z/
8
+ validates :attachment, attached: true, content_type: Rails.application.config.active_storage.web_image_content_types
9
9
 
10
10
  def self.styles
11
11
  @styles ||= {
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class InventoryUnit < Spree::Base
2
+ class InventoryUnit < Spree.base_class
3
3
  if defined?(Spree::Webhooks::HasWebhooks)
4
4
  include Spree::Webhooks::HasWebhooks
5
5
  end
@@ -1,6 +1,6 @@
1
1
  # Default implementation of User. This class is intended to be modified by extensions (ex. spree_auth_devise)
2
2
  module Spree
3
- class LegacyUser < Spree::Base
3
+ class LegacyUser < Spree.base_class
4
4
  include Spree::UserAddress
5
5
  include Spree::UserPaymentSource
6
6
  include Spree::UserMethods
@@ -9,5 +9,7 @@ module Spree
9
9
  self.table_name = 'spree_users'
10
10
 
11
11
  attr_accessor :password, :password_confirmation
12
+
13
+ validates :email, presence: true, uniqueness: { case_sensitive: false }
12
14
  end
13
15
  end