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,68 @@
1
+ module Spree
2
+ module Stores
3
+ module Socials
4
+ extend ActiveSupport::Concern
5
+
6
+ SUPPORTED_SOCIAL_NETWORKS = %w[instagram facebook twitter pinterest tiktok youtube spotify].freeze
7
+
8
+ SOCIAL_NETWORKS_CONFIG = {
9
+ twitter: {
10
+ input_placeholder: 'https://twitter.com/your_handle',
11
+ profile_link: 'https://twitter.com/your_handle'
12
+ },
13
+ instagram: {
14
+ input_placeholder: 'https://www.instagram.com/your_handle',
15
+ profile_link: 'https://www.instagram.com/your_handle'
16
+ },
17
+ facebook: {
18
+ input_placeholder: 'https://www.facebook.com/your_page',
19
+ profile_link: 'https://www.facebook.com/your_page'
20
+ },
21
+ youtube: {
22
+ input_placeholder: 'https://www.youtube.com/@your_channel',
23
+ profile_link: 'https://www.youtube.com/@your_channel'
24
+ },
25
+ pinterest: {
26
+ input_placeholder: 'https://pinterest.com/your_handle',
27
+ profile_link: 'https://pinterest.com/your_handle'
28
+ },
29
+ tiktok: {
30
+ input_placeholder: 'your_handle',
31
+ profile_link: 'https://www.tiktok.com/@your_handle'
32
+ },
33
+ spotify: {
34
+ input_placeholder: 'https://open.spotify.com/user/your_handle',
35
+ profile_link: 'https://open.spotify.com/user/your_handle'
36
+ }
37
+ }.freeze
38
+
39
+ included do
40
+ # generate methods for social links
41
+ SUPPORTED_SOCIAL_NETWORKS.each do |social|
42
+ # store the social handle in the public metadata
43
+ store_accessor :public_metadata, social
44
+
45
+ define_method "#{social}_link" do
46
+ return if send(social).blank?
47
+
48
+ send(social).match(/http/) ? send(social) : SOCIAL_NETWORKS_CONFIG[social.to_sym][:profile_link].gsub(/your_handle|your_page|your_channel/, send(social).sub(/^\//, '').sub(/^@/, ''))
49
+ end
50
+
51
+ define_method "#{social}_handle" do
52
+ return if send(social).blank?
53
+
54
+ (send(social).match(/http/) ? send(social).split('/').last : send(social)).sub(/^\//, '').gsub('@', '').split('?').first
55
+ end
56
+ end
57
+ end
58
+
59
+ def social_handle
60
+ @social_handle ||= instagram_handle || youtube_handle || tiktok_handle
61
+ end
62
+
63
+ def social_links
64
+ @social_links ||= [instagram_link, facebook_link, twitter_link, pinterest_link, youtube_link, tiktok_link, spotify_link].compact_blank
65
+ end
66
+ end
67
+ end
68
+ end
@@ -20,6 +20,10 @@ module Spree
20
20
 
21
21
  validate :address_not_associated_with_other_user, :address_not_deprecated_in_completed_order
22
22
 
23
+ def address
24
+ @address ||= bill_address || ship_address || addresses.first
25
+ end
26
+
23
27
  def persist_order_address(order)
24
28
  # FIXME: we should check if the User's address is associated with country accepted by Store
25
29
  # if not we should try to find an address with valid country in User's address book
@@ -6,7 +6,7 @@ module Spree
6
6
  include Spree::UserReporting
7
7
  include Spree::UserRoles
8
8
  include Spree::RansackableAttributes
9
-
9
+ include Spree::MultiSearchable
10
10
  included do
11
11
  # we need to have this callback before any dependent: :destroy associations
12
12
  # https://github.com/rails/rails/issues/3458
@@ -16,19 +16,56 @@ module Spree
16
16
 
17
17
  attr_accessor :use_billing
18
18
 
19
+ has_person_name
20
+ auto_strip_attributes :email, :first_name, :last_name
21
+ acts_as_taggable_on :tags
22
+
23
+ #
24
+ # Associations
25
+ #
19
26
  has_many :promotion_rule_users, class_name: 'Spree::PromotionRuleUser', foreign_key: :user_id, dependent: :destroy
20
27
  has_many :promotion_rules, through: :promotion_rule_users, class_name: 'Spree::PromotionRule'
21
-
22
28
  has_many :orders, foreign_key: :user_id, class_name: 'Spree::Order'
23
- has_many :store_credits, foreign_key: :user_id, class_name: 'Spree::StoreCredit'
24
-
29
+ has_many :completed_orders, -> { complete }, foreign_key: :user_id, class_name: 'Spree::Order'
30
+ has_many :store_credits, class_name: 'Spree::StoreCredit', foreign_key: :user_id, dependent: :destroy
31
+ has_many :wishlists, class_name: 'Spree::Wishlist', foreign_key: :user_id, dependent: :destroy
32
+ has_many :wished_items, through: :wishlists, source: :wished_items
33
+ has_many :gateway_customers, class_name: 'Spree::GatewayCustomer'
25
34
  belongs_to :ship_address, class_name: 'Spree::Address', optional: true
26
35
  belongs_to :bill_address, class_name: 'Spree::Address', optional: true
27
36
 
28
- has_many :wishlists, class_name: 'Spree::Wishlist', foreign_key: :user_id
37
+ #
38
+ # Attachments
39
+ #
40
+ has_one_attached :avatar, service: Spree.public_storage_service_name
41
+
42
+ #
43
+ # Attributes
44
+ #
45
+ attr_accessor :confirm_email, :terms_of_service
46
+
47
+ def self.multi_search(query)
48
+ sanitized_query = sanitize_query_for_multi_search(query)
49
+ return none if query.blank?
50
+
51
+ name_conditions = []
52
+
53
+ name_conditions << multi_search_condition(self, :first_name, sanitized_query)
54
+ name_conditions << multi_search_condition(self, :last_name, sanitized_query)
55
+
56
+ full_name = NameOfPerson::PersonName.full(sanitized_query)
29
57
 
30
- self.whitelisted_ransackable_associations = %w[bill_address ship_address addresses]
31
- self.whitelisted_ransackable_attributes = %w[id email]
58
+ if full_name.first.present? && full_name.last.present?
59
+ name_conditions << multi_search_condition(self, :first_name, full_name.first)
60
+ name_conditions << multi_search_condition(self, :last_name, full_name.last)
61
+ end
62
+
63
+ where(email: sanitized_query).or(where(name_conditions.reduce(:or)))
64
+ end
65
+
66
+ self.whitelisted_ransackable_associations = %w[bill_address ship_address addresses tags spree_roles]
67
+ self.whitelisted_ransackable_attributes = %w[id email first_name last_name accepts_email_marketing]
68
+ self.whitelisted_ransackable_scopes = %w[multi_search]
32
69
 
33
70
  def self.with_email(query)
34
71
  where("#{table_name}.email LIKE ?", "%#{query}%")
@@ -48,7 +85,7 @@ module Spree
48
85
  end
49
86
 
50
87
  def last_incomplete_spree_order(store, options = {})
51
- orders.where(store: store).incomplete.
88
+ orders.where(store: store).incomplete.not_canceled.
52
89
  includes(options[:includes]).
53
90
  order('created_at DESC').
54
91
  first
@@ -69,12 +106,15 @@ module Spree
69
106
  end
70
107
 
71
108
  def default_wishlist_for_store(current_store)
72
- wishlists.find_or_create_by(is_default: true, store_id: current_store.id) do |wishlist|
73
- wishlist.name = Spree.t(:default_wishlist_name)
74
- wishlist.save
109
+ wishlists.find_by(is_default: true, store_id: current_store.id) || ActiveRecord::Base.connected_to(role: :writing) do
110
+ wishlists.create!(store: current_store, is_default: true, name: Spree.t(:default_wishlist_name))
75
111
  end
76
112
  end
77
113
 
114
+ def can_be_deleted?
115
+ orders.complete.none?
116
+ end
117
+
78
118
  private
79
119
 
80
120
  def check_completed_orders
@@ -82,6 +122,8 @@ module Spree
82
122
  end
83
123
 
84
124
  def nullify_approver_id_in_approved_orders
125
+ return unless Spree.admin_user_class != Spree.user_class
126
+
85
127
  Spree::Order.where(approver_id: id).update_all(approver_id: nil)
86
128
  end
87
129
 
@@ -97,5 +139,13 @@ module Spree
97
139
  def use_billing?
98
140
  use_billing.in?([true, 'true', '1'])
99
141
  end
142
+
143
+ def scramble_email_and_names
144
+ self.email = "#{SecureRandom.uuid}@example.net"
145
+ self.first_name = 'Deleted'
146
+ self.last_name = 'User'
147
+ self.login = email
148
+ save
149
+ end
100
150
  end
101
151
  end
@@ -6,7 +6,7 @@ module Spree
6
6
  def report_values_for(report_name, store)
7
7
  store ||= Store.default
8
8
 
9
- completed_orders(store).pluck(:currency).uniq.each_with_object([]) do |currency, arr|
9
+ completed_orders_for_store(store).pluck(:currency).uniq.each_with_object([]) do |currency, arr|
10
10
  arr << send("display_#{report_name}", store: store, currency: currency)
11
11
  end
12
12
  end
@@ -31,17 +31,25 @@ module Spree
31
31
  column: :all)
32
32
  end
33
33
 
34
+ def amount_spent_in(currency)
35
+ completed_orders.where(currency: currency).sum(:total)
36
+ end
37
+
38
+ def display_amount_spent_in(currency)
39
+ Money.new(amount_spent_in(currency), currency: currency).to_html
40
+ end
41
+
42
+ def completed_orders_for_store(store)
43
+ orders.for_store(store).complete.order(currency: :desc)
44
+ end
45
+
34
46
  private
35
47
 
36
48
  def order_calculate(operation:, column:, store: nil, currency: nil)
37
49
  store ||= Store.default
38
50
  currency ||= store.default_currency
39
51
 
40
- completed_orders(store).where(currency: currency).calculate(operation, column) || BigDecimal('0.00')
41
- end
42
-
43
- def completed_orders(store)
44
- orders.for_store(store).complete.order(currency: :desc)
52
+ completed_orders_for_store(store).where(currency: currency).calculate(operation, column) || BigDecimal('0.00')
45
53
  end
46
54
  end
47
55
  end
@@ -3,7 +3,7 @@ module Spree
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- has_many :role_users, class_name: 'Spree::RoleUser', foreign_key: :user_id, dependent: :destroy
6
+ has_many :role_users, class_name: 'Spree::RoleUser', foreign_key: :user_id, as: :user, dependent: :destroy
7
7
  has_many :spree_roles, through: :role_users, class_name: 'Spree::Role', source: :role
8
8
 
9
9
  scope :spree_admin, -> { joins(:spree_roles).where(Spree::Role.table_name => { name: 'admin' }) }
@@ -58,12 +58,14 @@ module Spree
58
58
 
59
59
  def apply_admin_permissions(user)
60
60
  can :manage, :all
61
+ cannot :cancel, Spree::Order
62
+ can :cancel, Spree::Order, &:allow_cancel?
63
+ cannot [:edit, :update], Spree::RefundReason, mutable: false
64
+ cannot [:edit, :update], Spree::ReimbursementType, mutable: false
61
65
  end
62
66
 
63
67
  def apply_user_permissions(user)
64
68
  can :read, ::Spree::Country
65
- can :read, ::Spree::Menu
66
- can :read, ::Spree::CmsPage
67
69
  can :read, ::Spree::OptionType
68
70
  can :read, ::Spree::OptionValue
69
71
  can :create, ::Spree::Order
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Address < Spree::Base
2
+ class Address < Spree.base_class
3
3
  require 'validates_zipcode'
4
4
 
5
5
  include Spree::Metadata
@@ -10,11 +10,7 @@ module Spree
10
10
  include Spree::Security::Addresses
11
11
  end
12
12
 
13
- if Rails::VERSION::STRING >= '7.1.0'
14
- serialize :preferences, type: Hash, coder: YAML, default: {}
15
- else
16
- serialize :preferences, Hash, default: {}
17
- end
13
+ serialize :preferences, type: Hash, coder: YAML, default: {}
18
14
 
19
15
  NO_ZIPCODE_ISO_CODES ||= [
20
16
  'AO', 'AG', 'AW', 'BS', 'BZ', 'BJ', 'BM', 'BO', 'BW', 'BF', 'BI', 'CM', 'CF', 'KM', 'CG',
@@ -33,17 +29,31 @@ module Spree
33
29
  # we're not freezing this on purpose so developers can extend and manage
34
30
  # those attributes depending of the logic of their applications
35
31
  ADDRESS_FIELDS = %w(firstname lastname company address1 address2 city state zipcode country phone)
36
- EXCLUDED_KEYS_FOR_COMPARISON = %w(id updated_at created_at deleted_at label user_id)
32
+ EXCLUDED_KEYS_FOR_COMPARISON = %w(id updated_at created_at deleted_at label user_id public_metadata private_metadata)
33
+ FIELDS_TO_NORMALIZE = %w(firstname lastname phone alternative_phone company address1 address2 city zipcode)
37
34
 
38
35
  scope :not_deleted, -> { where(deleted_at: nil) }
39
36
 
37
+ scope :by_state_name_or_abbr, lambda { |state_name|
38
+ joins(:state).merge(Spree::State.where(name: state_name).or(Spree::State.where(abbr: state_name)))
39
+ }
40
+
41
+ scope :not_quick_checkout, -> { where(quick_checkout: false) }
42
+
40
43
  belongs_to :country, class_name: 'Spree::Country'
41
44
  belongs_to :state, class_name: 'Spree::State', optional: true
42
- belongs_to :user, class_name: "::#{Spree.user_class}", optional: true
45
+ belongs_to :user, class_name: Spree.user_class.name, optional: true, touch: true
43
46
 
44
47
  has_many :shipments, inverse_of: :address
45
48
 
49
+ after_initialize :set_default_values, if: -> { new_record? && user.present? }
50
+
46
51
  before_validation :clear_invalid_state_entities, if: -> { country.present? }, on: :update
52
+ before_validation :remove_emoji_and_normalize
53
+
54
+ after_create :set_user_attributes, if: -> { user.present? }
55
+
56
+ after_commit :async_geocode
47
57
 
48
58
  with_options presence: true do
49
59
  validates :firstname, :lastname, if: :require_name?
@@ -64,8 +74,7 @@ module Spree
64
74
  delegate :name, :iso3, :iso, :iso_name, to: :country, prefix: true
65
75
  delegate :abbr, to: :state, prefix: true, allow_nil: true
66
76
 
67
- alias_attribute :first_name, :firstname
68
- alias_attribute :last_name, :lastname
77
+ alias_attribute :postal_code, :zipcode
69
78
 
70
79
  self.whitelisted_ransackable_attributes = ADDRESS_FIELDS
71
80
  self.whitelisted_ransackable_associations = %w[country state user]
@@ -76,6 +85,30 @@ module Spree
76
85
  end.flatten
77
86
  end
78
87
 
88
+ def user_default_billing?
89
+ user.present? && id == user.bill_address_id
90
+ end
91
+
92
+ def user_default_shipping?
93
+ user.present? && id == user.ship_address_id
94
+ end
95
+
96
+ def first_name
97
+ firstname
98
+ end
99
+
100
+ def first_name=(value)
101
+ self.firstname = value
102
+ end
103
+
104
+ def last_name
105
+ lastname
106
+ end
107
+
108
+ def last_name=(value)
109
+ self.lastname = value
110
+ end
111
+
79
112
  def full_name
80
113
  "#{firstname} #{lastname}".strip
81
114
  end
@@ -88,6 +121,10 @@ module Spree
88
121
  state_name.present? ? state_name : state&.name
89
122
  end
90
123
 
124
+ def street
125
+ [address1, address2].join(' ')
126
+ end
127
+
91
128
  def to_s
92
129
  [
93
130
  full_name,
@@ -136,23 +173,31 @@ module Spree
136
173
  end
137
174
 
138
175
  def require_zipcode?
139
- country ? country.zipcode_required? : true
176
+ !quick_checkout && (country ? country.zipcode_required? : true)
140
177
  end
141
178
 
142
179
  def require_name?
143
- true
180
+ !quick_checkout
181
+ end
182
+
183
+ def require_company?
184
+ false
144
185
  end
145
186
 
146
187
  def require_street?
147
- true
188
+ !quick_checkout
189
+ end
190
+
191
+ def show_company_address_field?
192
+ false
148
193
  end
149
194
 
150
195
  def editable?
151
- new_record? || (shipments.empty? && !Order.complete.where('bill_address_id = ? OR ship_address_id = ?', id, id).exists?)
196
+ new_record? || Order.complete.where('bill_address_id = ? OR ship_address_id = ?', id, id).none?
152
197
  end
153
198
 
154
199
  def can_be_deleted?
155
- shipments.empty? && !Order.complete.where('bill_address_id = ? OR ship_address_id = ?', id, id).exists?
200
+ shipments.empty? && Order.complete.where('bill_address_id = ? OR ship_address_id = ?', id, id).none?
156
201
  end
157
202
 
158
203
  def check
@@ -162,16 +207,37 @@ module Spree
162
207
  end
163
208
 
164
209
  def destroy
210
+ assign_new_default_address_to_user
211
+
165
212
  if can_be_deleted?
166
213
  super
167
214
  else
168
215
  update_column :deleted_at, Time.current
169
- assign_new_default_address_to_user
170
216
  end
171
217
  end
172
218
 
219
+ def async_geocode
220
+ Spree::Addresses::GeocodeAddressJob.perform_later(id) if should_geocode?
221
+ end
222
+
223
+ def geocoder_address
224
+ @geocoder_address ||= [street, city, state_text, country.to_s].compact.map(&:strip).join(', ')
225
+ end
226
+
173
227
  private
174
228
 
229
+ def should_geocode?
230
+ Spree::Config[:geocode_addresses] && (
231
+ saved_changes.key?(:address1) || saved_changes.key?(:city) || saved_changes.key?(:state_id) || saved_changes.key?(:country_id)
232
+ )
233
+ end
234
+
235
+ def set_default_values
236
+ self.firstname ||= user.first_name
237
+ self.lastname ||= user.last_name
238
+ self.phone ||= user.phone
239
+ end
240
+
175
241
  def clear_state
176
242
  self.state = nil
177
243
  end
@@ -188,6 +254,27 @@ module Spree
188
254
  end
189
255
  end
190
256
 
257
+ def remove_emoji_and_normalize
258
+ attributes_to_normalize = attributes.slice(*FIELDS_TO_NORMALIZE)
259
+ normalized_attributes = attributes_to_normalize.compact_blank.deep_transform_values do |value|
260
+ NormalizeString.remove_emoji_and_normalize(value.to_s).strip
261
+ end
262
+
263
+ normalized_attributes.transform_keys! { |key| key.gsub('original_', '') } if defined?(Spree::Security::Addresses)
264
+
265
+ assign_attributes(normalized_attributes)
266
+ end
267
+
268
+ def set_user_attributes
269
+ if user.name.blank?
270
+ user.first_name = firstname
271
+ user.last_name = lastname
272
+ end
273
+ user.phone = user.phone.presence || phone.presence
274
+
275
+ user.save! if user.changed?
276
+ end
277
+
191
278
  def state_validate
192
279
  # Skip state validation without country (also required)
193
280
  # or when disabled by preference
@@ -206,16 +293,14 @@ module Spree
206
293
  end
207
294
 
208
295
  # ensure state_name belongs to country without states, or that it matches a predefined state name/abbr
209
- if state_name.present?
210
- if country.states.present?
211
- states = country.states.find_all_by_name_or_abbr(state_name)
212
-
213
- if states.size == 1
214
- self.state = states.first
215
- clear_state_name
216
- else
217
- errors.add(:state, :invalid)
218
- end
296
+ if state_name.present? && country.states.present?
297
+ states = country.states.find_all_by_name_or_abbr(state_name)
298
+
299
+ if states.size == 1
300
+ self.state = states.first
301
+ clear_state_name
302
+ else
303
+ errors.add(:state, :invalid)
219
304
  end
220
305
  end
221
306
 
@@ -238,9 +323,18 @@ module Spree
238
323
  def assign_new_default_address_to_user
239
324
  return unless user
240
325
 
241
- user.bill_address = user.addresses.last if user.bill_address == self
242
- user.ship_address = user.addresses.last if user.ship_address == self
326
+ user.reload
327
+ return if user.bill_address != self && user.ship_address != self
328
+
329
+ last_address = assign_new_default_address_to_user_scope.find { |address| address.id != id && address.valid? }
330
+
331
+ user.bill_address = last_address if user.bill_address == self
332
+ user.ship_address = last_address if user.ship_address == self
243
333
  user.save!
244
334
  end
335
+
336
+ def assign_new_default_address_to_user_scope
337
+ user.addresses.not_quick_checkout.reorder(created_at: :desc)
338
+ end
245
339
  end
246
340
  end
@@ -21,7 +21,7 @@
21
21
  # total. This allows an adjustment to be preserved if it becomes ineligible so
22
22
  # it might be reinstated.
23
23
  module Spree
24
- class Adjustment < Spree::Base
24
+ class Adjustment < Spree.base_class
25
25
  with_options polymorphic: true do
26
26
  belongs_to :adjustable, touch: true
27
27
  belongs_to :source
@@ -101,7 +101,10 @@ module Spree
101
101
  amount = source.compute_amount(target)
102
102
  attributes = { amount: amount, updated_at: Time.current }
103
103
  attributes[:eligible] = source.promotion.eligible?(target) if promotion?
104
+
104
105
  update_columns(attributes)
106
+ source.promotion.touch if promotion?
107
+
105
108
  amount
106
109
  end
107
110
 
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Asset < Spree::Base
2
+ class Asset < Spree.base_class
3
3
  module Support
4
4
  module ActiveStorage
5
5
  extend ActiveSupport::Concern
@@ -1,5 +1,5 @@
1
1
  module Spree
2
- class Asset < Spree::Base
2
+ class Asset < Spree.base_class
3
3
  include Support::ActiveStorage
4
4
  include Spree::Metadata
5
5
  if defined?(Spree::Webhooks::HasWebhooks)
@@ -9,12 +9,24 @@ module Spree
9
9
  belongs_to :viewable, polymorphic: true, touch: true
10
10
  acts_as_list scope: [:viewable_id, :viewable_type]
11
11
 
12
- if Spree.public_storage_service_name
13
- has_one_attached :attachment, service: Spree.public_storage_service_name
14
- else
15
- has_one_attached :attachment
16
- end
12
+ delegate :key, :attached?, :variant, :variable?, :blob, :filename, to: :attachment
13
+
14
+ has_one_attached :attachment, service: Spree.public_storage_service_name
17
15
 
18
16
  default_scope { includes(attachment_attachment: :blob) }
17
+
18
+ store_accessor :private_metadata, :session_uploaded_assets_uuid
19
+ scope :with_session_uploaded_assets_uuid, lambda { |uuid|
20
+ case ActiveRecord::Base.connection.adapter_name
21
+ when 'PostgreSQL'
22
+ where("#{table_name}.private_metadata @> ?", { session_uploaded_assets_uuid: uuid }.to_json)
23
+ when 'Mysql2', 'SQLite'
24
+ where("JSON_EXTRACT(private_metadata, '$.session_uploaded_assets_uuid') = '#{uuid}'")
25
+ end
26
+ }
27
+
28
+ def product
29
+ @product ||= viewable_type == 'Spree::Variant' ? viewable&.product : nil
30
+ end
19
31
  end
20
32
  end
@@ -1,11 +1,5 @@
1
1
  class Spree::Base < ApplicationRecord
2
2
  include Spree::Preferences::Preferable
3
- if Rails::VERSION::STRING >= '7.1.0'
4
- serialize :preferences, type: Hash, coder: YAML
5
- else
6
- serialize :preferences, Hash
7
- end
8
-
9
3
  include Spree::RansackableAttributes
10
4
  include Spree::TranslatableResourceScopes
11
5
 
@@ -23,6 +17,10 @@ class Spree::Base < ApplicationRecord
23
17
 
24
18
  self.abstract_class = true
25
19
 
20
+ scope :for_ordering_with_translations, lambda { |klass, fields = nil|
21
+ select("#{klass.table_name}.*").select(*(fields || klass::TRANSLATABLE_FIELDS))
22
+ }
23
+
26
24
  def self.belongs_to_required_by_default
27
25
  false
28
26
  end
@@ -50,8 +48,13 @@ class Spree::Base < ApplicationRecord
50
48
  false
51
49
  end
52
50
 
51
+ # this can overridden in subclasses to disallow deletion
52
+ def can_be_deleted?
53
+ true
54
+ end
55
+
53
56
  def self.json_api_columns
54
- column_names.reject { |c| c.match(/_id$|id|preferences|(.*)password|(.*)token|(.*)api_key/) }
57
+ column_names.reject { |c| c.match(/_id$|id|preferences|(.*)password|(.*)token|(.*)api_key|^original_(.*)/) }
55
58
  end
56
59
 
57
60
  def self.json_api_permitted_attributes
@@ -67,4 +70,32 @@ class Spree::Base < ApplicationRecord
67
70
  def self.json_api_type
68
71
  to_s.demodulize.underscore
69
72
  end
73
+
74
+ def self.to_tom_select_json
75
+ pluck(:name, :id).map do |name, id|
76
+ {
77
+ id: id,
78
+ name: name
79
+ }
80
+ end.as_json
81
+ end
82
+
83
+ def uuid_for_friendly_id
84
+ SecureRandom.uuid
85
+ end
86
+
87
+ # Try building a slug based on the following fields in increasing order of specificity.
88
+ def slug_candidates
89
+ if defined?(:deleted_at) && deleted_at.present?
90
+ [
91
+ ['deleted', :name],
92
+ ['deleted', :name, :uuid_for_friendly_id]
93
+ ]
94
+ else
95
+ [
96
+ [:name],
97
+ [:name, :uuid_for_friendly_id]
98
+ ]
99
+ end
100
+ end
70
101
  end