spree_core 5.3.4 → 5.4.0.beta2

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 (331) hide show
  1. checksums.yaml +4 -4
  2. data/app/finders/spree/orders/find_complete.rb +33 -2
  3. data/app/finders/spree/products/find.rb +1 -28
  4. data/app/finders/spree/stores/find_default.rb +17 -0
  5. data/app/finders/spree/variants/visible_finder.rb +1 -0
  6. data/app/helpers/spree/addresses_helper.rb +1 -2
  7. data/app/helpers/spree/base_helper.rb +6 -58
  8. data/app/mailers/spree/base_mailer.rb +4 -3
  9. data/app/models/concerns/spree/adjustment_source.rb +0 -8
  10. data/app/models/concerns/spree/admin_user_methods.rb +32 -2
  11. data/app/models/concerns/spree/image_methods.rb +4 -0
  12. data/app/models/concerns/spree/metadata.rb +10 -0
  13. data/app/models/concerns/spree/number_as_param.rb +5 -3
  14. data/app/models/concerns/spree/prefixed_id.rb +82 -0
  15. data/app/models/concerns/spree/product_scopes.rb +35 -65
  16. data/app/models/concerns/spree/publishable.rb +47 -47
  17. data/app/models/concerns/spree/{multi_store_resource.rb → store_scoped_resource.rb} +1 -10
  18. data/app/models/concerns/spree/stores/markets.rb +124 -0
  19. data/app/models/concerns/spree/user_methods.rb +7 -7
  20. data/app/models/concerns/spree/user_payment_source.rb +2 -0
  21. data/app/models/concerns/spree/user_roles.rb +1 -0
  22. data/app/models/concerns/spree/vat_price_calculation.rb +2 -2
  23. data/app/models/spree/ability.rb +18 -5
  24. data/app/models/spree/address.rb +33 -2
  25. data/app/models/spree/adjustable/promotion_accumulator.rb +1 -1
  26. data/app/models/spree/adjustment.rb +3 -20
  27. data/app/models/spree/api_key.rb +102 -0
  28. data/app/models/spree/asset.rb +2 -0
  29. data/app/models/spree/authentication/strategies/base_strategy.rb +55 -0
  30. data/app/models/spree/authentication/strategies/email_password_strategy.rb +47 -0
  31. data/app/models/spree/base.rb +1 -0
  32. data/app/models/spree/calculator.rb +2 -0
  33. data/app/models/spree/country.rb +60 -0
  34. data/app/models/spree/coupon_code.rb +2 -0
  35. data/app/models/spree/credit_card.rb +2 -27
  36. data/app/models/spree/current.rb +45 -4
  37. data/app/models/spree/customer_group.rb +2 -0
  38. data/app/models/spree/customer_return.rb +2 -0
  39. data/app/models/spree/digital.rb +2 -0
  40. data/app/models/spree/digital_link.rb +2 -0
  41. data/app/models/spree/export.rb +3 -2
  42. data/app/models/spree/exports/products.rb +0 -6
  43. data/app/models/spree/fulfilment_changer.rb +8 -2
  44. data/app/models/spree/gateway/bogus.rb +69 -9
  45. data/app/models/spree/gateway.rb +0 -3
  46. data/app/models/spree/gateway_customer.rb +2 -0
  47. data/app/models/spree/gift_card.rb +2 -0
  48. data/app/models/spree/gift_card_batch.rb +6 -0
  49. data/app/models/spree/image/configuration/active_storage.rb +0 -2
  50. data/app/models/spree/image.rb +25 -31
  51. data/app/models/spree/import.rb +5 -3
  52. data/app/models/spree/import_mapping.rb +2 -0
  53. data/app/models/spree/import_row.rb +2 -0
  54. data/app/models/spree/import_schemas/customers.rb +21 -0
  55. data/app/models/spree/imports/customers.rb +9 -0
  56. data/app/models/spree/integration.rb +2 -0
  57. data/app/models/spree/inventory_unit.rb +2 -0
  58. data/app/models/spree/invitation.rb +6 -6
  59. data/app/models/spree/legacy_admin_user.rb +31 -0
  60. data/app/models/spree/legacy_user.rb +19 -1
  61. data/app/models/spree/line_item.rb +15 -4
  62. data/app/models/spree/log_entry.rb +10 -5
  63. data/app/models/spree/market.rb +83 -0
  64. data/app/models/spree/market_country.rb +25 -0
  65. data/app/models/spree/metafield.rb +2 -0
  66. data/app/models/spree/metafield_definition.rb +2 -0
  67. data/app/models/spree/newsletter_subscriber.rb +2 -0
  68. data/app/models/spree/option_type.rb +2 -0
  69. data/app/models/spree/option_value.rb +2 -0
  70. data/app/models/spree/order/address_book.rb +2 -1
  71. data/app/models/spree/order/checkout.rb +0 -18
  72. data/app/models/spree/order.rb +93 -56
  73. data/app/models/spree/payment/gateway_options.rb +2 -2
  74. data/app/models/spree/payment/processing.rb +5 -5
  75. data/app/models/spree/payment.rb +7 -2
  76. data/app/models/spree/payment_capture_event.rb +2 -0
  77. data/app/models/spree/payment_connection_error.rb +3 -0
  78. data/app/models/spree/payment_method/check.rb +1 -1
  79. data/app/models/spree/payment_method/store_credit.rb +5 -5
  80. data/app/models/spree/payment_method.rb +59 -1
  81. data/app/models/spree/payment_response.rb +70 -0
  82. data/app/models/spree/payment_session.rb +109 -0
  83. data/app/models/spree/payment_sessions/bogus.rb +4 -0
  84. data/app/models/spree/payment_setup_session.rb +79 -0
  85. data/app/models/spree/payment_source.rb +2 -0
  86. data/app/models/spree/permission_sets/default_customer.rb +19 -5
  87. data/app/models/spree/permission_sets/product_display.rb +0 -2
  88. data/app/models/spree/permission_sets/product_management.rb +0 -2
  89. data/app/models/spree/policy.rb +2 -0
  90. data/app/models/spree/price.rb +26 -2
  91. data/app/models/spree/price_list.rb +2 -0
  92. data/app/models/spree/price_rule.rb +2 -0
  93. data/app/models/spree/price_rules/market_rule.rb +19 -0
  94. data/app/models/spree/product.rb +45 -101
  95. data/app/models/spree/promotion/rules/country.rb +1 -1
  96. data/app/models/spree/promotion.rb +5 -15
  97. data/app/models/spree/promotion_action.rb +2 -0
  98. data/app/models/spree/promotion_category.rb +2 -0
  99. data/app/models/spree/promotion_handler/coupon.rb +3 -3
  100. data/app/models/spree/promotion_rule.rb +2 -0
  101. data/app/models/spree/prototype.rb +2 -3
  102. data/app/models/spree/refund.rb +8 -2
  103. data/app/models/spree/refund_reason.rb +2 -0
  104. data/app/models/spree/reimbursement/credit.rb +2 -0
  105. data/app/models/spree/reimbursement.rb +2 -0
  106. data/app/models/spree/reimbursement_type.rb +2 -0
  107. data/app/models/spree/report.rb +3 -1
  108. data/app/models/spree/return_authorization.rb +2 -0
  109. data/app/models/spree/return_authorization_reason.rb +2 -0
  110. data/app/models/spree/return_item.rb +2 -0
  111. data/app/models/spree/role.rb +2 -0
  112. data/app/models/spree/shipment/emails.rb +1 -0
  113. data/app/models/spree/shipment.rb +11 -1
  114. data/app/models/spree/shipping_category.rb +5 -3
  115. data/app/models/spree/shipping_method.rb +2 -0
  116. data/app/models/spree/shipping_method_category.rb +2 -0
  117. data/app/models/spree/shipping_rate.rb +2 -0
  118. data/app/models/spree/state_change.rb +2 -0
  119. data/app/models/spree/stock_item.rb +2 -0
  120. data/app/models/spree/stock_location.rb +2 -0
  121. data/app/models/spree/stock_movement.rb +2 -0
  122. data/app/models/spree/stock_transfer.rb +2 -1
  123. data/app/models/spree/store.rb +111 -219
  124. data/app/models/spree/store_credit.rb +6 -0
  125. data/app/models/spree/store_credit_category.rb +2 -0
  126. data/app/models/spree/store_credit_event.rb +2 -0
  127. data/app/models/spree/store_credit_type.rb +2 -0
  128. data/app/models/spree/store_product.rb +2 -0
  129. data/app/models/spree/tax_category.rb +3 -11
  130. data/app/models/spree/tax_rate.rb +2 -0
  131. data/app/models/spree/taxon.rb +2 -15
  132. data/app/models/spree/taxon_rule.rb +2 -0
  133. data/app/models/spree/taxonomy.rb +2 -0
  134. data/app/models/spree/user_identity.rb +81 -0
  135. data/app/models/spree/variant.rb +15 -43
  136. data/app/models/spree/webhook_delivery.rb +2 -0
  137. data/app/models/spree/webhook_endpoint.rb +2 -0
  138. data/app/models/spree/wished_item.rb +15 -0
  139. data/app/models/spree/wishlist.rb +2 -8
  140. data/app/models/spree/zone.rb +3 -10
  141. data/app/presenters/spree/filters/price_presenter.rb +1 -0
  142. data/app/presenters/spree/filters/price_range_presenter.rb +1 -0
  143. data/app/presenters/spree/filters/quantified_price_range_presenter.rb +1 -0
  144. data/app/presenters/spree/product_summary_presenter.rb +1 -0
  145. data/app/services/spree/addresses/helper.rb +22 -3
  146. data/app/services/spree/cart/add_item.rb +8 -4
  147. data/app/services/spree/cart/associate.rb +19 -6
  148. data/app/services/spree/cart/create.rb +13 -2
  149. data/app/services/spree/checkout/select_shipping_method.rb +13 -1
  150. data/app/services/spree/classifications/reposition.rb +5 -0
  151. data/app/services/spree/imports/row_processors/customer.rb +70 -0
  152. data/app/services/spree/orders/approve.rb +5 -3
  153. data/app/services/spree/orders/cancel.rb +9 -4
  154. data/app/services/spree/products/duplicator.rb +0 -12
  155. data/app/services/spree/products/prepare_nested_attributes.rb +1 -13
  156. data/app/services/spree/sample_data/import_runner.rb +54 -0
  157. data/app/services/spree/sample_data/loader.rb +78 -0
  158. data/app/services/spree/seeds/admin_user.rb +2 -3
  159. data/app/services/spree/seeds/all.rb +1 -0
  160. data/app/services/spree/seeds/api_keys.rb +16 -0
  161. data/app/services/spree/seeds/stores.rb +2 -4
  162. data/app/sorters/spree/orders/sort.rb +4 -0
  163. data/app/subscribers/spree/product_metrics_subscriber.rb +4 -4
  164. data/config/brakeman.ignore +120 -0
  165. data/config/locales/en.yml +23 -21
  166. data/db/migrate/20210914000000_spree_four_three.rb +0 -38
  167. data/db/migrate/20210915064329_add_metadata_to_spree_multiple_tables.rb +0 -1
  168. data/db/migrate/20250923141900_create_spree_user_identities.rb +17 -0
  169. data/db/migrate/20260123000000_create_spree_api_keys.rb +19 -0
  170. data/db/migrate/20260131000000_add_thumbnail_id_to_spree_variants_and_products.rb +9 -0
  171. data/db/migrate/20260213000000_create_spree_payment_sessions.rb +27 -0
  172. data/db/migrate/20260218000000_create_spree_payment_setup_sessions.rb +24 -0
  173. data/db/migrate/20260220000000_create_spree_markets.rb +29 -0
  174. data/db/migrate/20260226000000_add_locale_to_spree_orders.rb +5 -0
  175. data/db/migrate/20260226100000_add_token_digest_to_spree_api_keys.rb +21 -0
  176. data/db/sample_data/customers.csv +21 -0
  177. data/db/sample_data/metafield_definitions.rb +7 -0
  178. data/db/sample_data/orders.rb +131 -0
  179. data/db/sample_data/payment_methods.rb +17 -0
  180. data/db/sample_data/products.csv +1083 -0
  181. data/db/sample_data/promotions.rb +8 -0
  182. data/db/sample_data/shipping_methods.rb +39 -0
  183. data/lib/generators/spree/authentication/devise/devise_generator.rb +2 -2
  184. data/lib/generators/spree/authentication/dummy/dummy_generator.rb +54 -0
  185. data/lib/generators/spree/authentication/dummy/templates/authentication_helpers.rb.tt +52 -0
  186. data/lib/generators/spree/authentication/dummy/templates/create_spree_admin_users.rb.tt +33 -0
  187. data/lib/generators/spree/cursor_rules/templates/spree_rules.mdc +1 -3
  188. data/lib/generators/spree/dummy/dummy_generator.rb +1 -1
  189. data/lib/spree/core/configuration.rb +1 -3
  190. data/lib/spree/core/controller_helpers/common.rb +6 -0
  191. data/lib/spree/core/controller_helpers/currency.rb +5 -0
  192. data/lib/spree/core/controller_helpers/order.rb +5 -1
  193. data/lib/spree/core/controller_helpers/store.rb +1 -1
  194. data/lib/spree/core/controller_helpers/strong_parameters.rb +1 -2
  195. data/lib/spree/core/dependencies.rb +3 -11
  196. data/lib/spree/core/engine.rb +17 -17
  197. data/lib/spree/core/pricing/context.rb +6 -3
  198. data/lib/spree/core/pricing/resolver.rb +1 -9
  199. data/lib/spree/core/version.rb +1 -1
  200. data/lib/spree/core.rb +14 -29
  201. data/lib/spree/database_type_utilities.rb +7 -0
  202. data/lib/spree/events.rb +17 -10
  203. data/lib/spree/money.rb +2 -9
  204. data/lib/spree/permitted_attributes.rb +20 -20
  205. data/lib/spree/testing_support/capybara_config.rb +2 -2
  206. data/lib/spree/testing_support/common_rake.rb +15 -4
  207. data/lib/spree/testing_support/factories/api_key_factory.rb +19 -0
  208. data/lib/spree/testing_support/factories/custom_domain_factory.rb +7 -5
  209. data/lib/spree/testing_support/factories/import_factory.rb +12 -0
  210. data/lib/spree/testing_support/factories/market_factory.rb +35 -0
  211. data/lib/spree/testing_support/factories/order_factory.rb +4 -1
  212. data/lib/spree/testing_support/factories/payment_method_factory.rb +3 -6
  213. data/lib/spree/testing_support/factories/payment_session_factory.rb +47 -0
  214. data/lib/spree/testing_support/factories/payment_setup_session_factory.rb +31 -0
  215. data/lib/spree/testing_support/factories/price_rule_factory.rb +10 -0
  216. data/lib/spree/testing_support/factories/product_factory.rb +0 -7
  217. data/lib/spree/testing_support/factories/prototype_factory.rb +0 -2
  218. data/lib/spree/testing_support/factories/user_identity_factory.rb +15 -0
  219. data/lib/spree/testing_support/store.rb +3 -2
  220. data/lib/spree/webhooks.rb +7 -7
  221. data/lib/tasks/core.rake +0 -265
  222. data/lib/tasks/images.rake +20 -0
  223. data/lib/tasks/markets.rake +40 -0
  224. data/lib/tasks/sample_data.rake +15 -0
  225. data/spec/fixtures/files/customers_import.csv +4 -0
  226. metadata +101 -154
  227. data/LICENSE.md +0 -57
  228. data/app/finders/spree/posts/find.rb +0 -137
  229. data/app/finders/spree/product_properties/find_available.rb +0 -20
  230. data/app/finders/spree/stores/find_current.rb +0 -28
  231. data/app/helpers/spree/mail_helper.rb +0 -27
  232. data/app/mailers/spree/test_mailer.rb +0 -8
  233. data/app/models/action_text/video_embed.rb +0 -13
  234. data/app/models/concerns/spree/has_one_link.rb +0 -42
  235. data/app/models/concerns/spree/linkable.rb +0 -9
  236. data/app/models/concerns/spree/previewable.rb +0 -17
  237. data/app/models/spree/custom_domain.rb +0 -59
  238. data/app/models/spree/data_feed/google.rb +0 -15
  239. data/app/models/spree/data_feed.rb +0 -40
  240. data/app/models/spree/gateway/bogus_simple.rb +0 -24
  241. data/app/models/spree/post.rb +0 -106
  242. data/app/models/spree/post_category.rb +0 -44
  243. data/app/models/spree/product_property.rb +0 -51
  244. data/app/models/spree/property.rb +0 -86
  245. data/app/models/spree/property_prototype.rb +0 -9
  246. data/app/models/spree/store_favicon_image.rb +0 -20
  247. data/app/models/spree/store_logo.rb +0 -4
  248. data/app/models/spree/store_mailer_logo.rb +0 -7
  249. data/app/models/spree/taxon_image/configuration/active_storage.rb +0 -26
  250. data/app/models/spree/taxon_image.rb +0 -20
  251. data/app/presenters/spree/filters/properties_presenter.rb +0 -23
  252. data/app/presenters/spree/filters/property_presenter.rb +0 -42
  253. data/app/serializers/spree/events/asset_serializer.rb +0 -22
  254. data/app/serializers/spree/events/base_serializer.rb +0 -61
  255. data/app/serializers/spree/events/customer_return_serializer.rb +0 -20
  256. data/app/serializers/spree/events/digital_link_serializer.rb +0 -20
  257. data/app/serializers/spree/events/digital_serializer.rb +0 -18
  258. data/app/serializers/spree/events/export_serializer.rb +0 -22
  259. data/app/serializers/spree/events/gift_card_batch_serializer.rb +0 -24
  260. data/app/serializers/spree/events/gift_card_serializer.rb +0 -29
  261. data/app/serializers/spree/events/image_serializer.rb +0 -9
  262. data/app/serializers/spree/events/import_row_serializer.rb +0 -23
  263. data/app/serializers/spree/events/import_serializer.rb +0 -24
  264. data/app/serializers/spree/events/invitation_serializer.rb +0 -28
  265. data/app/serializers/spree/events/line_item_serializer.rb +0 -31
  266. data/app/serializers/spree/events/newsletter_subscriber_serializer.rb +0 -21
  267. data/app/serializers/spree/events/order_serializer.rb +0 -39
  268. data/app/serializers/spree/events/payment_serializer.rb +0 -24
  269. data/app/serializers/spree/events/post_category_serializer.rb +0 -20
  270. data/app/serializers/spree/events/post_serializer.rb +0 -26
  271. data/app/serializers/spree/events/price_serializer.rb +0 -22
  272. data/app/serializers/spree/events/product_serializer.rb +0 -24
  273. data/app/serializers/spree/events/promotion_serializer.rb +0 -32
  274. data/app/serializers/spree/events/refund_serializer.rb +0 -23
  275. data/app/serializers/spree/events/reimbursement_serializer.rb +0 -22
  276. data/app/serializers/spree/events/report_serializer.rb +0 -23
  277. data/app/serializers/spree/events/return_authorization_serializer.rb +0 -22
  278. data/app/serializers/spree/events/return_item_serializer.rb +0 -27
  279. data/app/serializers/spree/events/shipment_serializer.rb +0 -24
  280. data/app/serializers/spree/events/stock_item_serializer.rb +0 -22
  281. data/app/serializers/spree/events/stock_movement_serializer.rb +0 -22
  282. data/app/serializers/spree/events/stock_transfer_serializer.rb +0 -22
  283. data/app/serializers/spree/events/store_credit_serializer.rb +0 -30
  284. data/app/serializers/spree/events/user_serializer.rb +0 -18
  285. data/app/serializers/spree/events/variant_serializer.rb +0 -34
  286. data/app/serializers/spree/events/wished_item_serializer.rb +0 -20
  287. data/app/serializers/spree/events/wishlist_serializer.rb +0 -22
  288. data/app/services/spree/data_feeds/google/optional_attributes.rb +0 -23
  289. data/app/services/spree/data_feeds/google/optional_sub_attributes.rb +0 -21
  290. data/app/services/spree/data_feeds/google/products_list.rb +0 -14
  291. data/app/services/spree/data_feeds/google/required_attributes.rb +0 -68
  292. data/app/services/spree/data_feeds/google/rss.rb +0 -109
  293. data/app/sorters/spree/posts/sort.rb +0 -40
  294. data/app/views/action_text/video_embeds/_thumbnail.html.erb +0 -1
  295. data/app/views/action_text/video_embeds/_video_embed.html.erb +0 -3
  296. data/app/views/layouts/action_text/contents/_content.html.erb +0 -3
  297. data/app/views/spree/test_mailer/test_email.html.erb +0 -40
  298. data/app/views/spree/test_mailer/test_email.text.erb +0 -4
  299. data/config/initializers/oembed.rb +0 -1
  300. data/db/migrate/20221229132350_create_spree_data_feed_settings.rb +0 -14
  301. data/db/migrate/20230109084253_create_product_property_translations.rb +0 -24
  302. data/db/migrate/20230109105943_create_property_translations.rb +0 -24
  303. data/db/migrate/20230415155958_rename_data_feed_settings_table.rb +0 -5
  304. data/db/migrate/20230415160828_rename_data_feed_table_columns.rb +0 -7
  305. data/db/migrate/20230415161226_add_indexes_to_data_feeds_table.rb +0 -5
  306. data/db/migrate/20230512094803_rename_data_feeds_column_provider_to_type.rb +0 -5
  307. data/db/migrate/20240914153106_add_display_on_to_spree_properties.rb +0 -5
  308. data/db/migrate/20240915144935_add_position_to_spree_properties.rb +0 -6
  309. data/db/migrate/20250121160028_create_spree_posts_and_spree_post_categories.rb +0 -33
  310. data/db/migrate/20250127083740_add_kind_to_spree_properties.rb +0 -5
  311. data/db/migrate/20250217171018_create_action_text_video_embeds.rb +0 -11
  312. data/db/migrate/20250305121657_remove_spree_posts_indices.rb +0 -7
  313. data/db/migrate/20250730154601_add_unique_index_on_spree_properties_name.rb +0 -24
  314. data/lib/spree/core/controller_helpers/search.rb +0 -17
  315. data/lib/spree/core/product_filters.rb +0 -204
  316. data/lib/spree/core/query_filters/comparable.rb +0 -46
  317. data/lib/spree/core/query_filters/date.rb +0 -8
  318. data/lib/spree/core/query_filters/number.rb +0 -8
  319. data/lib/spree/core/query_filters/text.rb +0 -32
  320. data/lib/spree/core/query_filters.rb +0 -11
  321. data/lib/spree/core/search/base.rb +0 -144
  322. data/lib/spree/testing_support/factories/favicon_image_factory.rb +0 -9
  323. data/lib/spree/testing_support/factories/google_data_feed_factory.rb +0 -7
  324. data/lib/spree/testing_support/factories/post_category_factory.rb +0 -7
  325. data/lib/spree/testing_support/factories/post_factory.rb +0 -22
  326. data/lib/spree/testing_support/factories/product_property_factory.rb +0 -7
  327. data/lib/spree/testing_support/factories/property_factory.rb +0 -28
  328. data/lib/spree/testing_support/factories/taxon_image_factory.rb +0 -9
  329. data/lib/spree/testing_support/flash.rb +0 -25
  330. data/lib/spree/testing_support/flatpickr_capybara.rb +0 -124
  331. data/lib/tasks/exchanges.rake +0 -66
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2b1ea480e8607e801d3c45d8decf522c829003eb3fa6c1f8f92b9185a4bfefec
4
- data.tar.gz: 552fb0686b6da4a560dd47144d52079d1ab73c270a9e4c9093e62b9e556ef74f
3
+ metadata.gz: af6f55a25483bfb02dab0b15f67356a2732cbeb190074b9ddb75a1692594fb7a
4
+ data.tar.gz: 8f0b8f77983432ef1e1baa52def6ed2674f9e0794bc632dd91757551c4ee71c4
5
5
  SHA512:
6
- metadata.gz: 1ed2cab50fb7c122df6565b931324ea7ba307c8580a98ac8f9e2e400140df75092ed417db47311a6d3ec01985a6696cfbce1d3e3fa7917c329646b13ef51b095
7
- data.tar.gz: 34bd9929ed9e4a962696b2be41a5bb0da2c330fd12d1cbff89e34fa78cdceaa84d6b58cb7ae321d1868864c2888eccd752cd0bef7dbd9cd473aa68490619c2f6
6
+ metadata.gz: 46c6fc812dc90ba1ae3061b2e4066df5e9dd8ad530fde2db85095a7b5cb444fec2d51f4736a528c61ee4423e64d986478fdcf5478c40888e99818b849e444d60
7
+ data.tar.gz: aa2913c4e9882dd0e77d03ddcfae4f8277e4657b807080ce2d3549fd63f5c6da18448e2574b7742ad82b227a299dccfce3717a7df504be4442e3c7f0bf21629e
@@ -3,11 +3,13 @@ module Spree
3
3
  class FindComplete
4
4
  include Spree::Orders::FinderHelper
5
5
 
6
- attr_reader :user, :number, :token, :store, :email
6
+ attr_reader :user, :number, :prefix_id, :param, :token, :store, :email
7
7
 
8
- def initialize(user: nil, number: nil, token: nil, store: nil, email: nil)
8
+ def initialize(user: nil, number: nil, prefix_id: nil, param: nil, token: nil, store: nil, email: nil)
9
9
  @user = user
10
10
  @number = number
11
+ @prefix_id = prefix_id
12
+ @param = param
11
13
  @token = token
12
14
  @store = store
13
15
  @email = email
@@ -16,6 +18,8 @@ module Spree
16
18
  def execute
17
19
  orders = by_user(scope)
18
20
  orders = by_number(orders)
21
+ orders = by_prefix_id(orders)
22
+ orders = by_param(orders)
19
23
  orders = by_token(orders)
20
24
  orders = by_store(orders)
21
25
  orders = by_email(orders)
@@ -37,6 +41,14 @@ module Spree
37
41
  number.present?
38
42
  end
39
43
 
44
+ def prefix_id?
45
+ prefix_id.present?
46
+ end
47
+
48
+ def param?
49
+ param.present?
50
+ end
51
+
40
52
  def token?
41
53
  token.present?
42
54
  end
@@ -61,6 +73,25 @@ module Spree
61
73
  orders.where(number: number)
62
74
  end
63
75
 
76
+ def by_prefix_id(orders)
77
+ return orders unless prefix_id?
78
+
79
+ decoded = Spree::Order.decode_prefixed_id(prefix_id)
80
+ orders.where(id: decoded)
81
+ end
82
+
83
+ # Find by param - tries prefixed ID first, then number for backwards compatibility
84
+ def by_param(orders)
85
+ return orders unless param?
86
+
87
+ decoded = Spree::Order.decode_prefixed_id(param)
88
+ if decoded
89
+ orders.where(id: decoded)
90
+ else
91
+ orders.where(number: param)
92
+ end
93
+ end
94
+
64
95
  def by_token(orders)
65
96
  return orders unless token?
66
97
 
@@ -19,7 +19,6 @@ module Spree
19
19
  @sort_by = params.dig(:sort_by)
20
20
  @deleted = params.dig(:filter, :show_deleted)
21
21
  @discontinued = params.dig(:filter, :show_discontinued)
22
- @properties = params.dig(:filter, :properties)
23
22
  @in_stock = params.dig(:filter, :in_stock)
24
23
  @backorderable = params.dig(:filter, :backorderable)
25
24
  @purchasable = params.dig(:filter, :purchasable)
@@ -46,7 +45,6 @@ module Spree
46
45
  products = by_slug(products)
47
46
  products = by_options(products)
48
47
  products = by_option_value_ids(products)
49
- products = by_properties(products)
50
48
  products = by_tags(products)
51
49
  products = include_deleted(products)
52
50
  products = show_only_stock(products)
@@ -63,7 +61,7 @@ module Spree
63
61
  private
64
62
 
65
63
  attr_reader :ids, :skus, :price, :currency, :taxons, :concat_taxons, :name, :options, :option_value_ids, :scope,
66
- :sort_by, :deleted, :discontinued, :properties, :store, :in_stock, :backorderable, :purchasable, :tags,
64
+ :sort_by, :deleted, :discontinued, :store, :in_stock, :backorderable, :purchasable, :tags,
67
65
  :query, :vendor_ids, :out_of_stock, :slug, :taxonomies
68
66
 
69
67
  def query?
@@ -114,10 +112,6 @@ module Spree
114
112
  sort_by.present?
115
113
  end
116
114
 
117
- def properties?
118
- properties.present? && properties.values.reject(&:empty?).present?
119
- end
120
-
121
115
  def vendor_ids?
122
116
  vendor_ids.present?
123
117
  end
@@ -224,27 +218,6 @@ module Spree
224
218
  products.where(id: product_ids)
225
219
  end
226
220
 
227
- def by_properties(products)
228
- return products unless properties?
229
-
230
- product_ids = []
231
- index = 0
232
-
233
- properties.to_unsafe_hash.each do |property_filter_param, product_properties_values|
234
- next if property_filter_param.blank? || product_properties_values.empty?
235
-
236
- values = product_properties_values.split(',').reject(&:empty?).uniq.map(&:parameterize)
237
-
238
- next if values.empty?
239
-
240
- ids = scope.unscope(:order, :includes).with_property_values(property_filter_param, values).ids
241
- product_ids = index == 0 ? ids : product_ids & ids
242
- index += 1
243
- end
244
-
245
- products.where(id: product_ids)
246
- end
247
-
248
221
  def by_tags(products)
249
222
  return products if tags.empty?
250
223
 
@@ -0,0 +1,17 @@
1
+ module Spree
2
+ module Stores
3
+ class FindDefault
4
+ def initialize(scope: nil, url: nil)
5
+ @scope = scope || Spree::Store
6
+ end
7
+
8
+ def execute
9
+ store = @scope.where(default: true).first || @scope.first
10
+ return if store.nil?
11
+
12
+ Spree::Current.store = store
13
+ store
14
+ end
15
+ end
16
+ end
17
+ end
@@ -2,6 +2,7 @@ module Spree
2
2
  module Variants
3
3
  class VisibleFinder
4
4
  def initialize(scope:, current_currency:)
5
+ Spree::Deprecation.warn('Spree::Variants::VisibleFinder is deprecated and will be removed in Spree 5.5.')
5
6
  @scope = scope
6
7
  @current_currency = current_currency
7
8
  end
@@ -4,8 +4,7 @@ module Spree
4
4
  def address_form_countries_states_cache_key
5
5
  @address_form_countries_states_cache_key ||= [
6
6
  I18n.locale,
7
- current_store.cache_key_with_version,
8
- current_store.checkout_zone&.cache_key_with_version
7
+ current_store.cache_key_with_version
9
8
  ].compact
10
9
  end
11
10
 
@@ -68,30 +68,10 @@ module Spree
68
68
  end
69
69
  end
70
70
 
71
- def spree_favicon_path
72
- Spree::Deprecation.warn('BaseHelper#spree_favicon_path is deprecated and will be removed in Spree 5.5. Please use Active Storage URL helpers instead.')
73
-
74
- if current_store.favicon.present?
75
- main_app.cdn_image_url(current_store.favicon)
76
- else
77
- url_for('favicon.ico')
78
- end
79
- end
80
-
81
71
  def object
82
72
  instance_variable_get('@' + controller_name.singularize)
83
73
  end
84
74
 
85
- def method_missing(method_name, *args, &block)
86
- if image_style = image_style_from_method_name(method_name)
87
- Spree::Deprecation.warn("#{BaseHelper.name}##{method_name} is deprecated and will be removed in Spree 5.5. Please use spree_image_tag instead - https://spreecommerce.org/docs/developer/core-concepts/images-assets#preprocessed-named-variants")
88
- define_image_method(image_style)
89
- send(method_name, *args)
90
- else
91
- super
92
- end
93
- end
94
-
95
75
  def pretty_time(time)
96
76
  return '' if time.blank?
97
77
 
@@ -119,7 +99,7 @@ module Spree
119
99
  end
120
100
 
121
101
  # returns the URL of an object on the storefront
122
- # @param resource [Spree::Product, Spree::Post, Spree::Taxon, Spree::Page] the resource to get the URL for
102
+ # @param resource [Spree::Product, Spree::Taxon, Spree::Page] the resource to get the URL for
123
103
  # @param options [Hash] the options for the URL
124
104
  # @option options [String] :locale the locale of the resource, defaults to I18n.locale
125
105
  # @option options [String] :store the store of the resource, defaults to current_store
@@ -134,10 +114,10 @@ module Spree
134
114
 
135
115
  base_url = if options[:relative]
136
116
  ''
137
- elsif store.formatted_custom_domain.blank?
138
- store.formatted_url
139
- else
117
+ elsif store.respond_to?(:formatted_custom_domain) && store.formatted_custom_domain.present?
140
118
  store.formatted_custom_domain
119
+ else
120
+ store.formatted_url
141
121
  end
142
122
 
143
123
  localize = if options[:locale].present?
@@ -155,9 +135,6 @@ module Spree
155
135
  params = "?#{params}" if params.present?
156
136
 
157
137
  "#{base_url + localize}/products/#{resource.slug}#{params}"
158
- elsif defined?(Spree::Post) && resource.is_a?(Spree::Post)
159
- preview_id = options[:preview_id].present? ? "?preview_id=#{options[:preview_id]}" : ''
160
- "#{base_url + localize}/posts/#{resource.slug}#{preview_id}"
161
138
  elsif resource.is_a?(Spree::Taxon)
162
139
  "#{base_url + localize}/t/#{resource.permalink}"
163
140
  elsif defined?(Spree::Page) && (resource.is_a?(Spree::Page) || resource.is_a?(Spree::Policy))
@@ -204,7 +181,8 @@ module Spree
204
181
  end
205
182
 
206
183
  def maximum_quantity
207
- Spree::DatabaseTypeUtilities.maximum_value_for(:integer)
184
+ Spree::Deprecation.warn('BaseHelper#maximum_quantity is deprecated and will be removed in Spree 5.5')
185
+ Spree::DatabaseTypeUtilities::INTEGER_MAX
208
186
  end
209
187
 
210
188
  def payment_method_icon_tag(payment_method, opts = {})
@@ -220,36 +198,6 @@ module Spree
220
198
 
221
199
  private
222
200
 
223
- def create_product_image_tag(image, product, options, style)
224
- options[:alt] = image.alt.blank? ? product.name : image.alt
225
- image_tag main_app.cdn_image_url(image.url(style)), options
226
- end
227
-
228
- def define_image_method(style)
229
- self.class.send :define_method, "#{style}_image" do |product, *options|
230
- options = options.first || {}
231
- options[:alt] ||= product.name
232
- image_path = default_image_for_product_or_variant(product)
233
- img = if image_path.present?
234
- create_product_image_tag image_path, product, options, style
235
- else
236
- width = style.to_s.split('x').first.to_i
237
- height = style.to_s.split('x').last.to_i
238
- content_tag(:div, width: width, height: height, style: "background-color: #f0f0f0;")
239
- end
240
-
241
- content_tag(:div, img, class: "admin-product-image-container #{style}-img")
242
- end
243
- end
244
-
245
- # Returns style of image or nil
246
- def image_style_from_method_name(method_name)
247
- style = method_name.to_s.sub(/_image$/, '')
248
- if method_name.to_s.match(/_image$/) && Spree::Image.styles.keys.map(&:to_s).include?(style)
249
- style
250
- end
251
- end
252
-
253
201
  I18N_PLURAL_MANY_COUNT = 2.1
254
202
  def plural_resource_name(resource_class)
255
203
  resource_class.model_name.human(count: I18N_PLURAL_MANY_COUNT)
@@ -1,7 +1,5 @@
1
1
  module Spree
2
2
  class BaseMailer < ActionMailer::Base
3
- helper Spree::MailHelper
4
-
5
3
  def current_store
6
4
  @current_store ||= @order&.store.presence || Spree::Store.current || Spree::Store.default
7
5
  end
@@ -47,8 +45,11 @@ module Spree
47
45
  ActionMailer::Base.default_url_options[:host] = host_url
48
46
  end
49
47
 
48
+ # Sets the I18n locale for the email.
49
+ # Prefers the order's locale (the language the customer used),
50
+ # falls back to the store's default locale.
50
51
  def set_email_locale
51
- locale = @order&.store&.default_locale || current_store&.default_locale
52
+ locale = @order&.locale.presence || @order&.store&.default_locale || current_store&.default_locale
52
53
  I18n.locale = locale if locale.present?
53
54
  end
54
55
  end
@@ -5,7 +5,6 @@ module Spree
5
5
  included do
6
6
  has_many :adjustments, as: :source
7
7
  before_destroy :deals_with_adjustments_for_deleted_source
8
- after_commit :clear_adjustment_source_cache
9
8
  end
10
9
 
11
10
  protected
@@ -55,12 +54,5 @@ module Spree
55
54
  # This would mean that the order's total is not altered at all.
56
55
  adjustments.for_complete_order.update_all(source_id: nil, updated_at: Time.current)
57
56
  end
58
-
59
- def clear_adjustment_source_cache
60
- # Use base_class.name to match the polymorphic_name stored in source_type
61
- # For STI models like PromotionAction subclasses, this ensures cache key consistency
62
- cache_class_name = self.class.polymorphic_name
63
- Rails.cache.delete("spree/adjustment_source/#{cache_class_name}/#{id}")
64
- end
65
57
  end
66
58
  end
@@ -2,8 +2,19 @@ module Spree
2
2
  module AdminUserMethods
3
3
  extend ActiveSupport::Concern
4
4
 
5
+ include Spree::PrefixedId
6
+ include Spree::UserRoles
7
+ include Spree::RansackableAttributes
8
+
5
9
  included do
10
+ has_prefix_id :admin
11
+
12
+ has_person_name
13
+
14
+ normalizes :email, :first_name, :last_name, with: ->(value) { value&.to_s&.squish&.presence }
15
+
6
16
  # Associations
17
+ has_many :identities, class_name: 'Spree::UserIdentity', as: :user, dependent: :destroy
7
18
  has_many :canceled_orders, class_name: 'Spree::Order', foreign_key: :canceler_id
8
19
  has_many :created_orders, class_name: 'Spree::Order', foreign_key: :created_by_id
9
20
  has_many :approved_orders, class_name: 'Spree::Order', foreign_key: :approver_id
@@ -11,7 +22,6 @@ module Spree
11
22
  has_many :created_gift_card_batches, class_name: 'Spree::GiftCardBatch', foreign_key: :created_by_id
12
23
  has_many :refunded_refunds, class_name: 'Spree::Refund', foreign_key: :refunder_id
13
24
  has_many :performed_reimbursements, class_name: 'Spree::Reimbursement', foreign_key: :performed_by_id
14
- has_many :authored_posts, class_name: 'Spree::Post', foreign_key: :author_id
15
25
  has_many :created_store_credits, class_name: 'Spree::StoreCredit', foreign_key: :created_by_id
16
26
  has_many :reports, class_name: 'Spree::Report', foreign_key: :user_id
17
27
  has_many :exports, class_name: 'Spree::Export', foreign_key: :user_id
@@ -19,6 +29,27 @@ module Spree
19
29
  # Callbacks
20
30
  after_destroy :nullify_approver_id_in_approved_orders
21
31
  after_destroy :cleanup_admin_user_resources
32
+
33
+ # Attachments
34
+ has_one_attached :avatar, service: Spree.public_storage_service_name
35
+
36
+ #
37
+ # Attributes
38
+ #
39
+ attr_accessor :confirm_email
40
+
41
+ self.whitelisted_ransackable_associations = %w[spree_roles]
42
+ self.whitelisted_ransackable_attributes = %w[id email first_name last_name]
43
+ end
44
+
45
+ def can_be_deleted?
46
+ Spree::Store.current.users.where.not(id: id).exists?
47
+ end
48
+
49
+ # Returns the full name of the user
50
+ # @return [String]
51
+ def full_name
52
+ name&.full
22
53
  end
23
54
 
24
55
  private
@@ -41,7 +72,6 @@ module Spree
41
72
  created_gift_card_batches.update_all(created_by_id: nil, updated_at: Time.current)
42
73
  refunded_refunds.update_all(refunder_id: nil, updated_at: Time.current)
43
74
  performed_reimbursements.update_all(performed_by_id: nil, updated_at: Time.current)
44
- authored_posts.update_all(author_id: nil, updated_at: Time.current)
45
75
  created_store_credits.update_all(created_by_id: nil, updated_at: Time.current)
46
76
 
47
77
  # resources to destroy
@@ -3,6 +3,8 @@ module Spree
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  def generate_url(size:, gravity: 'centre', quality: 80, background: [0, 0, 0])
6
+ Spree::Deprecation.warn("ImageMethods#generate_url is deprecated and will be removed in Spree 6.0. Please use active storage variants with cdn_image_url")
7
+
6
8
  return if size.blank?
7
9
 
8
10
  size = size.gsub(/\s+/, '')
@@ -18,6 +20,8 @@ module Spree
18
20
  end
19
21
 
20
22
  def original_url
23
+ Spree::Deprecation.warn("ImageMethods#original_url is deprecated and will be removed in Spree 6.0. Please use active storage variants with cdn_image_url")
24
+
21
25
  cdn_image_url(attachment)
22
26
  end
23
27
 
@@ -12,6 +12,16 @@ module Spree
12
12
  serialize :private_metadata, coder: HashSerializer
13
13
  end
14
14
 
15
+ # `metadata` is the primary API-facing accessor.
16
+ # It maps to `private_metadata` under the hood (Stripe-style: write-only, never returned in Store API).
17
+ def metadata
18
+ private_metadata
19
+ end
20
+
21
+ def metadata=(value)
22
+ self.private_metadata = value
23
+ end
24
+
15
25
  # https://nandovieira.com/using-postgresql-and-jsonb-with-ruby-on-rails
16
26
  class HashSerializer
17
27
  def self.dump(hash)
@@ -3,9 +3,11 @@ module Spree
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- extend FriendlyId
7
-
8
- friendly_id :number
6
+ Spree::Deprecation.warn(
7
+ 'Spree::NumberAsParam is deprecated and will be removed in Spree 6.0. ' \
8
+ 'Models now use Spree::PrefixedId with Sqids-based prefixed_id method instead. ' \
9
+ 'This concern no longer provides any functionality and can be safely removed.'
10
+ )
9
11
  end
10
12
  end
11
13
  end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'sqids'
4
+
5
+ module Spree
6
+ # Adds Stripe-style prefixed IDs to Spree models using Sqids encoding.
7
+ # IDs are computed on the fly from integer primary keys -- no database column needed.
8
+ #
9
+ # e.g., Product with id=12345 -> "prod_86Rf07xd4z"
10
+ #
11
+ # class Product < Spree.base_class
12
+ # has_prefix_id :prod
13
+ # end
14
+ module PrefixedId
15
+ extend ActiveSupport::Concern
16
+
17
+ SQIDS = Sqids.new(min_length: 10)
18
+
19
+ included do
20
+ class_attribute :_prefix_id_prefix, instance_writer: false
21
+ end
22
+
23
+ # Returns the Stripe-style prefixed ID, or nil for unsaved records.
24
+ def prefixed_id
25
+ return nil unless id.present?
26
+
27
+ "#{self.class._prefix_id_prefix}_#{Spree::PrefixedId::SQIDS.encode([id])}"
28
+ end
29
+
30
+ # Use prefixed_id for URL params when available.
31
+ # Skip if FriendlyId is used (it has its own to_param using slug).
32
+ def to_param
33
+ return super if self.class.respond_to?(:friendly_id_config)
34
+ return super unless self.class._prefix_id_prefix.present?
35
+
36
+ prefixed_id.presence || super
37
+ end
38
+
39
+ class_methods do
40
+ def has_prefix_id(prefix)
41
+ self._prefix_id_prefix = prefix.to_s
42
+ end
43
+
44
+ def find_by_prefix_id!(prefixed_id)
45
+ decoded = decode_prefixed_id(prefixed_id)
46
+ raise ActiveRecord::RecordNotFound.new("Couldn't find #{name} with prefixed id=#{prefixed_id}", name) unless decoded
47
+
48
+ find(decoded)
49
+ end
50
+
51
+ def find_by_prefix_id(prefixed_id)
52
+ decoded = decode_prefixed_id(prefixed_id)
53
+ return nil unless decoded
54
+
55
+ find_by(id: decoded)
56
+ end
57
+
58
+ # Decode a prefixed ID string (e.g., "prod_86Rf07xd4z") to the integer primary key.
59
+ def decode_prefixed_id(prefixed_id_string)
60
+ return nil if prefixed_id_string.blank?
61
+
62
+ parts = prefixed_id_string.to_s.split('_', 2)
63
+ return nil if parts.length != 2
64
+
65
+ _prefix, encoded = parts
66
+ ids = Spree::PrefixedId::SQIDS.decode(encoded)
67
+ ids.first
68
+ end
69
+
70
+ # Find by prefixed ID first, falling back to integer id for backwards compatibility.
71
+ def find_by_param(param)
72
+ return nil if param.blank?
73
+
74
+ find_by_prefix_id(param) || (find_by(id: param) if param.to_s.match?(/\A\d+\z/))
75
+ end
76
+
77
+ def find_by_param!(param)
78
+ find_by_param(param) || raise(ActiveRecord::RecordNotFound.new("Couldn't find #{name} with param=#{param}", name))
79
+ end
80
+ end
81
+ end
82
+ end
@@ -31,21 +31,6 @@ module Spree
31
31
  end
32
32
  end
33
33
 
34
- def self.property_conditions(property)
35
- properties_table = Property.table_name
36
-
37
- case property
38
- when Property then { "#{properties_table}.id" => property.id }
39
- when Integer then { "#{properties_table}.id" => property }
40
- else
41
- if Property.column_for_attribute('id').type == :uuid
42
- ["#{properties_table}.name = ? OR #{properties_table}.id = ?", property, property]
43
- else
44
- { "#{properties_table}.name" => property }
45
- end
46
- end
47
- end
48
-
49
34
  add_simple_scopes simple_scopes
50
35
 
51
36
  add_search_scope :ascend_by_master_price do
@@ -126,9 +111,8 @@ module Spree
126
111
  #
127
112
  # SELECT COUNT(*) ...
128
113
  add_search_scope :in_taxon do |taxon|
129
- includes(:classifications).
130
- where('spree_products_taxons.taxon_id' => taxon.cached_self_and_descendants_ids).
131
- order('spree_products_taxons.position ASC')
114
+ joins(:classifications).
115
+ where("#{Classification.table_name}.taxon_id" => taxon.cached_self_and_descendants_ids).distinct
132
116
  end
133
117
 
134
118
  # This scope selects products in all taxons AND all its descendants
@@ -150,33 +134,6 @@ module Spree
150
134
  order(Arel.sql("#{min_position_sql} ASC"))
151
135
  end
152
136
 
153
- # a scope that finds all products having property specified by name, object or id
154
- add_search_scope :with_property do |property|
155
- joins(:properties).where(property_conditions(property))
156
- end
157
-
158
- # a simple test for product with a certain property-value pairing
159
- # note that it can test for properties with NULL values, but not for absent values
160
- add_search_scope :with_property_value do |property, value|
161
- if Spree.use_translations?
162
- joins(:properties).
163
- join_translation_table(Property).
164
- join_translation_table(ProductProperty).
165
- where(ProductProperty.translation_table_alias => { value: value }).
166
- where(property_conditions(property))
167
- else
168
- joins(:properties).
169
- where(ProductProperty.table_name => { value: value }).
170
- where(property_conditions(property))
171
- end
172
- end
173
-
174
- add_search_scope :with_property_values do |property_filter_param, property_values|
175
- joins(product_properties: :property).
176
- where(Property.table_name => { filter_param: property_filter_param }).
177
- where(ProductProperty.table_name => { filter_param: property_values.map(&:parameterize) })
178
- end
179
-
180
137
  add_search_scope :with_option do |option|
181
138
  if option.is_a?(OptionType)
182
139
  joins(:option_types).where(spree_option_types: { id: option.id })
@@ -205,17 +162,32 @@ module Spree
205
162
  return Product.group("#{Spree::Product.table_name}.id").none if option_type_id.blank?
206
163
 
207
164
  group("#{Spree::Product.table_name}.id").
208
- joins(variants_including_master: :option_values).
165
+ joins(variants: :option_values).
209
166
  where(Spree::OptionValue.table_name => { name: value, option_type_id: option_type_id })
210
167
  end
211
168
 
212
- # Finds all products which have either:
213
- # 1) have an option value with the name matching the one given
214
- # 2) have a product property with a value matching the one given
169
+ # Filters products by option value IDs (prefix IDs like 'optval_xxx')
170
+ # Accepts an array of option value IDs
171
+ add_search_scope :with_option_value_ids do |*ids|
172
+ ids = ids.flatten.compact
173
+ return none if ids.empty?
174
+
175
+ # Handle prefixed IDs (optval_xxx) by decoding to actual IDs
176
+ actual_ids = ids.map do |id|
177
+ id.to_s.include?('_') ? OptionValue.decode_prefixed_id(id) : id
178
+ end.compact
179
+
180
+ return none if actual_ids.empty?
181
+
182
+ group("#{Spree::Product.table_name}.id").
183
+ joins(variants: :option_values).
184
+ where(Spree::OptionValue.table_name => { id: actual_ids })
185
+ end
186
+
187
+ # Finds all products which have an option value with the name matching the one given
215
188
  add_search_scope :with do |value|
216
- includes(variants_including_master: :option_values).
217
- includes(:product_properties).
218
- where("#{OptionValue.table_name}.name = ? OR #{ProductProperty.table_name}.value = ?", value, value)
189
+ includes(variants: :option_values).
190
+ where("#{OptionValue.table_name}.name = ?", value)
219
191
  end
220
192
 
221
193
  # Finds all products that have a name containing the given words.
@@ -288,11 +260,8 @@ module Spree
288
260
 
289
261
  # Can't use add_search_scope for this as it needs a default argument
290
262
  def self.available(available_on = nil, currency = nil)
291
- scope = if available_on
292
- not_discontinued.where("#{Product.quoted_table_name}.available_on <= ?", available_on)
293
- else
294
- not_discontinued.where(status: 'active')
295
- end
263
+ scope = not_discontinued.where(status: 'active')
264
+ scope = scope.where("#{Product.quoted_table_name}.available_on <= ?", available_on) if available_on
296
265
 
297
266
  unless Spree::Config.show_products_without_price
298
267
  currency ||= Spree::Store.default.default_currency
@@ -336,16 +305,17 @@ module Spree
336
305
  # @param order_direction [Symbol] :desc (default) or :asc
337
306
  # @return [ActiveRecord::Relation]
338
307
  add_search_scope :by_best_selling do |order_direction = :desc|
339
- order_dir = order_direction == :desc ? 'DESC' : 'ASC'
340
308
  store_id = Spree::Current.store&.id
309
+ sp_table = StoreProduct.arel_table
310
+ products_table = Product.arel_table
311
+
312
+ conditions = sp_table[:product_id].eq(products_table[:id]).and(sp_table[:store_id].eq(store_id))
313
+
314
+ units_sold = Arel::Nodes::NamedFunction.new('COALESCE', [sp_table.project(sp_table[:units_sold_count]).where(conditions), 0])
315
+ revenue = Arel::Nodes::NamedFunction.new('COALESCE', [sp_table.project(sp_table[:revenue]).where(conditions), 0])
341
316
 
342
- joins(:store_products)
343
- .where(StoreProduct.table_name => { store_id: store_id })
344
- .select("#{Product.table_name}.*",
345
- "#{StoreProduct.table_name}.units_sold_count",
346
- "#{StoreProduct.table_name}.revenue")
347
- .order(Arel.sql("#{StoreProduct.table_name}.units_sold_count #{order_dir}"))
348
- .order(Arel.sql("#{StoreProduct.table_name}.revenue #{order_dir}"))
317
+ order_dir = order_direction == :desc ? :desc : :asc
318
+ order(units_sold.send(order_dir)).order(revenue.send(order_dir))
349
319
  end
350
320
 
351
321
  # .search_by_name