spree_core 4.2.5 → 4.3.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (248) hide show
  1. checksums.yaml +4 -4
  2. data/app/finders/concerns/spree/product_filterable.rb +9 -0
  3. data/app/finders/spree/cms_pages/find.rb +41 -0
  4. data/app/finders/spree/menus/find.rb +11 -0
  5. data/app/finders/spree/option_values/find_available.rb +20 -0
  6. data/app/finders/spree/orders/find_complete.rb +14 -2
  7. data/app/finders/spree/orders/find_current.rb +1 -13
  8. data/app/finders/spree/product_properties/find_available.rb +20 -0
  9. data/app/finders/spree/products/find.rb +55 -20
  10. data/app/finders/spree/stores/find_current.rb +24 -0
  11. data/app/helpers/spree/base_helper.rb +62 -2
  12. data/app/helpers/spree/locale_helper.rb +5 -1
  13. data/app/helpers/spree/products_helper.rb +7 -3
  14. data/app/models/concerns/spree/display_link.rb +42 -0
  15. data/app/models/concerns/spree/filter_param.rb +21 -0
  16. data/app/models/concerns/spree/memoized_data.rb +24 -0
  17. data/app/models/concerns/spree/multi_store_resource.rb +24 -0
  18. data/app/models/concerns/spree/product_scopes.rb +59 -8
  19. data/app/models/concerns/spree/single_store_resource.rb +9 -0
  20. data/app/models/concerns/spree/user_address.rb +19 -0
  21. data/app/models/concerns/spree/user_methods.rb +5 -4
  22. data/app/models/concerns/spree/user_payment_source.rb +1 -1
  23. data/app/models/spree/ability.rb +3 -1
  24. data/app/models/spree/address.rb +27 -6
  25. data/app/models/spree/app_configuration.rb +8 -0
  26. data/app/models/spree/app_dependencies.rb +18 -6
  27. data/app/models/spree/base.rb +18 -0
  28. data/app/models/spree/classification.rb +3 -0
  29. data/app/models/spree/cms/pages/feature_page.rb +7 -0
  30. data/app/models/spree/cms/pages/homepage.rb +20 -0
  31. data/app/models/spree/cms/pages/standard_page.rb +4 -0
  32. data/app/models/spree/cms/sections/featured_article.rb +29 -0
  33. data/app/models/spree/cms/sections/hero_image.rb +47 -0
  34. data/app/models/spree/cms/sections/image_gallery.rb +103 -0
  35. data/app/models/spree/cms/sections/product_carousel.rb +14 -0
  36. data/app/models/spree/cms/sections/rich_text_content.rb +13 -0
  37. data/app/models/spree/cms/sections/side_by_side_images.rb +74 -0
  38. data/app/models/spree/cms_page.rb +66 -0
  39. data/app/models/spree/cms_section.rb +57 -0
  40. data/app/models/spree/country.rb +14 -6
  41. data/app/models/spree/credit_card.rb +2 -8
  42. data/app/models/spree/customer_return.rb +8 -2
  43. data/app/models/spree/icon.rb +9 -0
  44. data/app/models/spree/image/configuration/active_storage.rb +2 -0
  45. data/app/models/spree/inventory_unit.rb +1 -1
  46. data/app/models/spree/line_item.rb +1 -1
  47. data/app/models/spree/menu.rb +63 -0
  48. data/app/models/spree/menu_item.rb +76 -0
  49. data/app/models/spree/option_type.rb +1 -1
  50. data/app/models/spree/option_value.rb +11 -0
  51. data/app/models/spree/option_value_variant.rb +1 -1
  52. data/app/models/spree/order.rb +46 -45
  53. data/app/models/spree/order/address_book.rb +3 -5
  54. data/app/models/spree/order/currency_updater.rb +1 -1
  55. data/app/models/spree/order/emails.rb +32 -0
  56. data/app/models/spree/order/payments.rb +1 -1
  57. data/app/models/spree/order/store_credit.rb +1 -1
  58. data/app/models/spree/payment.rb +7 -0
  59. data/app/models/spree/payment_method.rb +4 -0
  60. data/app/models/spree/preferences/preferable.rb +12 -0
  61. data/app/models/spree/preferences/preferable_class_methods.rb +10 -1
  62. data/app/models/spree/product.rb +27 -22
  63. data/app/models/spree/product_property.rb +19 -4
  64. data/app/models/spree/promotion.rb +6 -15
  65. data/app/models/spree/promotion/rules/country.rb +1 -1
  66. data/app/models/spree/promotion/rules/first_order.rb +4 -3
  67. data/app/models/spree/promotion/rules/taxon.rb +10 -7
  68. data/app/models/spree/promotion_handler/cart.rb +7 -2
  69. data/app/models/spree/promotion_handler/coupon.rb +5 -4
  70. data/app/models/spree/promotion_handler/free_shipping.rb +5 -6
  71. data/app/models/spree/promotion_handler/page.rb +3 -2
  72. data/app/models/spree/promotion_handler/promotion_duplicator.rb +1 -0
  73. data/app/models/spree/promotion_rule.rb +2 -0
  74. data/app/models/spree/property.rb +27 -0
  75. data/app/models/spree/reimbursement.rb +3 -1
  76. data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +2 -1
  77. data/app/models/spree/shipment_handler.rb +4 -2
  78. data/app/models/spree/stock/quantifier.rb +6 -6
  79. data/app/models/spree/store.rb +90 -7
  80. data/app/models/spree/store_credit.rb +7 -3
  81. data/app/models/spree/store_credit_event.rb +2 -2
  82. data/app/models/spree/store_payment_method.rb +11 -0
  83. data/app/models/spree/store_product.rb +11 -0
  84. data/app/models/spree/store_promotion.rb +11 -0
  85. data/app/models/spree/taxon.rb +21 -1
  86. data/app/models/spree/taxon_image/configuration/active_storage.rb +2 -0
  87. data/app/models/spree/taxonomy.rb +3 -1
  88. data/app/models/spree/variant.rb +13 -4
  89. data/app/presenters/spree/filters/options_presenter.rb +27 -0
  90. data/app/presenters/spree/filters/price_presenter.rb +22 -0
  91. data/app/presenters/spree/filters/price_range_presenter.rb +29 -0
  92. data/app/presenters/spree/filters/properties_presenter.rb +23 -0
  93. data/app/presenters/spree/filters/property_presenter.rb +22 -0
  94. data/app/presenters/spree/filters/quantified_price_range_presenter.rb +44 -0
  95. data/app/services/spree/account/addresses/create.rb +1 -0
  96. data/app/services/spree/account/addresses/helper.rb +6 -0
  97. data/app/services/spree/account/addresses/update.rb +9 -3
  98. data/app/services/spree/account/create.rb +17 -0
  99. data/app/services/spree/account/update.rb +15 -0
  100. data/app/services/spree/build_localized_redirect_url.rb +1 -1
  101. data/app/services/spree/cart/create.rb +5 -3
  102. data/app/services/spree/cart/destroy.rb +40 -0
  103. data/app/services/spree/cart/empty.rb +36 -0
  104. data/app/services/spree/cart/estimate_shipping_rates.rb +3 -3
  105. data/app/services/spree/checkout/add_store_credit.rb +1 -1
  106. data/app/services/spree/classifications/reposition.rb +18 -0
  107. data/app/services/spree/credit_cards/destroy.rb +41 -0
  108. data/app/validators/db_maximum_length_validator.rb +5 -0
  109. data/app/validators/email_validator.rb +3 -1
  110. data/app/views/spree/shared/_purchased_items_table.text.erb +25 -0
  111. data/config/initializers/active_storage.rb +2 -0
  112. data/config/locales/en.yml +166 -2
  113. data/config/routes.rb +0 -5
  114. data/db/migrate/20201023152810_add_filterable_to_spree_properties.rb +8 -0
  115. data/db/migrate/20210407200948_create_spree_menus.rb +16 -0
  116. data/db/migrate/20210408092939_create_spree_menu_items.rb +31 -0
  117. data/db/migrate/20210504163720_add_filter_param_to_spree_product_properties.rb +8 -0
  118. data/db/migrate/20210505114659_add_filter_param_to_spree_properties.rb +8 -0
  119. data/db/migrate/20210512191732_create_spree_cms_pages.rb +24 -0
  120. data/db/migrate/20210514204251_create_spree_cms_sections.rb +22 -0
  121. data/db/migrate/20210527094055_create_spree_products_stores.rb +29 -0
  122. data/db/migrate/20210608045519_ensure_store_default_country_is_set.rb +5 -0
  123. data/db/migrate/20210702112334_add_missing_timestamp_columns.rb +46 -0
  124. data/db/migrate/20210713131614_add_unique_index_on_property_id_and_product_id_to_product_properties.rb +29 -0
  125. data/db/migrate/20210715091956_add_store_id_to_spree_store_credits.rb +10 -0
  126. data/db/migrate/20210716093151_add_store_id_to_spree_taxonomies.rb +11 -0
  127. data/db/migrate/20210716104141_add_index_on_name_parent_id_and_taxonomy_id_on_spree_taxons.rb +31 -0
  128. data/db/migrate/20210721120857_add_index_on_permalink_parent_id_and_taxonomy_id_on_spree_taxons.rb +31 -0
  129. data/db/migrate/20210721125657_create_spree_promotions_stores.rb +29 -0
  130. data/db/migrate/20210722090705_add_store_id_to_spree_customer_returns.rb +11 -0
  131. data/db/migrate/20210726065456_change_integer_id_columns_into_bigint.rb +305 -0
  132. data/db/migrate/20210730154425_fix_promotion_code_and_path_unique_indexes.rb +9 -0
  133. data/lib/generators/spree/dummy/dummy_generator.rb +11 -6
  134. data/lib/generators/spree/dummy_model/templates/model.rb.tt +1 -1
  135. data/lib/generators/spree/install/install_generator.rb +12 -24
  136. data/lib/spree/core.rb +8 -4
  137. data/lib/spree/core/components.rb +8 -0
  138. data/lib/spree/core/controller_helpers/auth.rb +7 -1
  139. data/lib/spree/core/controller_helpers/common.rb +1 -1
  140. data/lib/spree/core/controller_helpers/order.rb +4 -4
  141. data/lib/spree/core/controller_helpers/search.rb +1 -0
  142. data/lib/spree/core/controller_helpers/store.rb +10 -1
  143. data/lib/spree/core/engine.rb +6 -0
  144. data/lib/spree/core/importer/product.rb +3 -1
  145. data/lib/spree/core/product_duplicator.rb +1 -0
  146. data/lib/spree/core/search/base.rb +17 -22
  147. data/lib/spree/core/version.rb +1 -1
  148. data/lib/spree/i18n.rb +1 -1
  149. data/lib/spree/money.rb +2 -1
  150. data/lib/spree/permitted_attributes.rb +14 -3
  151. data/lib/spree/testing_support/authorization_helpers.rb +6 -3
  152. data/lib/spree/testing_support/capybara_config.rb +3 -1
  153. data/lib/spree/testing_support/common_rake.rb +17 -4
  154. data/lib/spree/testing_support/extension_rake.rb +2 -2
  155. data/lib/spree/testing_support/factories/address_factory.rb +1 -1
  156. data/lib/spree/testing_support/factories/classification_factory.rb +8 -0
  157. data/lib/spree/testing_support/factories/cms_page_factory.rb +20 -0
  158. data/lib/spree/testing_support/factories/cms_section_factory.rb +31 -0
  159. data/lib/spree/testing_support/factories/customer_return_factory.rb +24 -17
  160. data/lib/spree/testing_support/factories/icon_factory.rb +7 -0
  161. data/lib/spree/testing_support/factories/line_item_factory.rb +6 -2
  162. data/lib/spree/testing_support/factories/menu_factory.rb +16 -0
  163. data/lib/spree/testing_support/factories/menu_item_factory.rb +10 -0
  164. data/lib/spree/testing_support/factories/options_factory.rb +5 -0
  165. data/lib/spree/testing_support/factories/order_factory.rb +11 -2
  166. data/lib/spree/testing_support/factories/payment_method_factory.rb +6 -2
  167. data/lib/spree/testing_support/factories/product_factory.rb +11 -1
  168. data/lib/spree/testing_support/factories/product_property_factory.rb +1 -1
  169. data/lib/spree/testing_support/factories/promotion_factory.rb +18 -9
  170. data/lib/spree/testing_support/factories/property_factory.rb +22 -0
  171. data/lib/spree/testing_support/factories/stock_location_factory.rb +5 -4
  172. data/lib/spree/testing_support/factories/store_credit_factory.rb +1 -0
  173. data/lib/spree/testing_support/factories/store_factory.rb +11 -0
  174. data/lib/spree/testing_support/factories/taxon_factory.rb +3 -1
  175. data/lib/spree/testing_support/factories/taxon_image_factory.rb +7 -0
  176. data/lib/spree/testing_support/factories/taxonomy_factory.rb +1 -0
  177. data/lib/spree/testing_support/factories/user_factory.rb +7 -2
  178. data/lib/spree/testing_support/factories/variant_factory.rb +2 -2
  179. data/lib/spree/testing_support/flatpickr_capybara.rb +58 -35
  180. data/lib/spree/testing_support/order_walkthrough.rb +9 -9
  181. data/lib/tasks/core.rake +1 -1
  182. data/spec/fixtures/favicon.ico +0 -0
  183. data/spec/fixtures/files/icon_256x256.gif +0 -0
  184. data/spec/fixtures/files/icon_256x256.png +0 -0
  185. data/spec/fixtures/files/icon_512x512.png +0 -0
  186. data/spec/fixtures/files/img_256x128.png +0 -0
  187. data/spree_core.gemspec +11 -10
  188. metadata +206 -157
  189. data/app/assets/images/logo/spree_50.png +0 -0
  190. data/app/assets/images/noimage/large.png +0 -0
  191. data/app/assets/images/noimage/mini.png +0 -0
  192. data/app/assets/images/noimage/product.png +0 -0
  193. data/app/assets/images/noimage/small.png +0 -0
  194. data/app/assets/javascripts/spree.js +0 -78
  195. data/app/controllers/spree/errors_controller.rb +0 -11
  196. data/app/helpers/spree/mail_helper.rb +0 -29
  197. data/app/mailers/spree/base_mailer.rb +0 -46
  198. data/app/mailers/spree/order_mailer.rb +0 -26
  199. data/app/mailers/spree/reimbursement_mailer.rb +0 -12
  200. data/app/mailers/spree/shipment_mailer.rb +0 -12
  201. data/app/mailers/spree/test_mailer.rb +0 -8
  202. data/app/models/spree/validations/db_maximum_length_validator.rb +0 -22
  203. data/app/views/layouts/spree/base_mailer.html.erb +0 -46
  204. data/app/views/spree/errors/forbidden.html.erb +0 -0
  205. data/app/views/spree/errors/unauthorized.html.erb +0 -0
  206. data/app/views/spree/order_mailer/cancel_email.html.erb +0 -24
  207. data/app/views/spree/order_mailer/cancel_email.text.erb +0 -38
  208. data/app/views/spree/order_mailer/confirm_email.html.erb +0 -23
  209. data/app/views/spree/order_mailer/confirm_email.text.erb +0 -39
  210. data/app/views/spree/order_mailer/store_owner_notification_email.html.erb +0 -23
  211. data/app/views/spree/order_mailer/store_owner_notification_email.text.erb +0 -38
  212. data/app/views/spree/reimbursement_mailer/reimbursement_email.html.erb +0 -56
  213. data/app/views/spree/reimbursement_mailer/reimbursement_email.text.erb +0 -24
  214. data/app/views/spree/shared/_base_mailer_footer.html.erb +0 -12
  215. data/app/views/spree/shared/_base_mailer_header.html.erb +0 -13
  216. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +0 -456
  217. data/app/views/spree/shared/_error_messages.html.erb +0 -11
  218. data/app/views/spree/shared/_mailer_line_item.html.erb +0 -16
  219. data/app/views/spree/shared/_paths.html.erb +0 -8
  220. data/app/views/spree/shared/_purchased_items_table.html.erb +0 -69
  221. data/app/views/spree/shared/purchased_items_table/_adjustment.html.erb +0 -13
  222. data/app/views/spree/shared/purchased_items_table/_line_item.html.erb +0 -27
  223. data/app/views/spree/shared/purchased_items_table/_subtotal.html.erb +0 -13
  224. data/app/views/spree/shared/purchased_items_table/_total.html.erb +0 -13
  225. data/app/views/spree/shipment_mailer/shipped_email.html.erb +0 -36
  226. data/app/views/spree/shipment_mailer/shipped_email.text.erb +0 -17
  227. data/app/views/spree/test_mailer/test_email.html.erb +0 -40
  228. data/app/views/spree/test_mailer/test_email.text.erb +0 -4
  229. data/config/initializers/assets.rb +0 -2
  230. data/config/initializers/premailer_assets.rb +0 -1
  231. data/config/initializers/premailer_rails.rb +0 -3
  232. data/db/migrate/20140805171219_make_existing_credit_cards_default.rb +0 -10
  233. data/lib/generators/spree/dummy/templates/initializers/bullet.rb +0 -5
  234. data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/backend/all.js +0 -15
  235. data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/frontend/all.js +0 -16
  236. data/lib/generators/spree/install/templates/vendor/assets/stylesheets/spree/backend/all.css +0 -16
  237. data/lib/generators/spree/install/templates/vendor/assets/stylesheets/spree/frontend/all.css +0 -16
  238. data/lib/generators/spree/mailers_preview/mailers_preview_generator.rb +0 -23
  239. data/lib/generators/spree/mailers_preview/templates/mailers/previews/order_preview.rb +0 -13
  240. data/lib/generators/spree/mailers_preview/templates/mailers/previews/reimbursement_preview.rb +0 -5
  241. data/lib/generators/spree/mailers_preview/templates/mailers/previews/shipment_preview.rb +0 -5
  242. data/lib/generators/spree/mailers_preview/templates/mailers/previews/user_preview.rb +0 -11
  243. data/lib/tasks/email.rake +0 -10
  244. data/vendor/assets/javascripts/cleave.js +0 -1669
  245. data/vendor/assets/javascripts/fetch.umd.js +0 -531
  246. data/vendor/assets/javascripts/jquery.payment.js +0 -652
  247. data/vendor/assets/javascripts/jsuri.js +0 -458
  248. data/vendor/assets/javascripts/polyfill.min.js +0 -1
@@ -16,12 +16,16 @@ module Spree
16
16
 
17
17
  def locale_presentation(locale)
18
18
  if I18n.exists?('spree.i18n.this_file_language', locale: locale)
19
- [Spree.t('i18n.this_file_language', locale: locale), locale.to_s]
19
+ [locale_full_name(locale), locale.to_s]
20
20
  else
21
21
  locale.to_s == 'en' ? ['English (US)', 'en'] : [locale, locale.to_s]
22
22
  end
23
23
  end
24
24
 
25
+ def locale_full_name(locale)
26
+ Spree.t('i18n.this_file_language', locale: locale)
27
+ end
28
+
25
29
  def should_render_locale_dropdown?
26
30
  return false if current_store.nil?
27
31
 
@@ -44,9 +44,13 @@ module Spree
44
44
  variants_option_types_presenter(variants, product).options
45
45
  end
46
46
 
47
+ def product_wysiwyg_editor_enabled?
48
+ Spree::Config[:product_wysiwyg_editor_enabled]
49
+ end
50
+
47
51
  # converts line breaks in product description into <p> tags (for html display purposes)
48
52
  def product_description(product)
49
- description = if Spree::Config[:show_raw_product_description]
53
+ description = if Spree::Config[:show_raw_product_description] || product_wysiwyg_editor_enabled?
50
54
  product.description
51
55
  else
52
56
  product.description.to_s.gsub(/(.*?)\r?\n\r?\n/m, '<p>\1</p>')
@@ -63,7 +67,7 @@ module Spree
63
67
  end
64
68
 
65
69
  def cache_key_for_products(products = @products, additional_cache_key = nil)
66
- max_updated_at = (products.maximum(:updated_at) || Date.today).to_s(:number)
70
+ max_updated_at = (products.except(:group, :order).maximum(:updated_at) || Date.today).to_s(:number)
67
71
  products_cache_keys = "spree/products/#{products.map(&:id).join('-')}-#{params[:page]}-#{params[:sort_by]}-#{max_updated_at}-#{@taxon&.id}"
68
72
  (common_product_cache_keys + [products_cache_keys] + [additional_cache_key]).compact.join('/')
69
73
  end
@@ -131,7 +135,7 @@ module Spree
131
135
 
132
136
  return [] if product_ids.empty?
133
137
 
134
- Spree::Product.
138
+ current_store.products.
135
139
  available.not_discontinued.distinct.
136
140
  where(id: product_ids).
137
141
  includes(
@@ -0,0 +1,42 @@
1
+ module Spree
2
+ module DisplayLink
3
+ def link
4
+ case linked_resource_type
5
+ when 'Spree::Taxon'
6
+ return if linked_resource&.permalink.blank?
7
+
8
+ if spree_routes.method_defined?(:nested_taxons_path)
9
+ spree_routes.nested_taxons_path(linked_resource.permalink)
10
+ else
11
+ "/#{Spree::Config[:storefront_taxons_path]}/#{linked_resource.permalink}"
12
+ end
13
+ when 'Spree::Product'
14
+ return if linked_resource&.slug.blank?
15
+
16
+ if spree_routes.method_defined?(:products_path)
17
+ spree_routes.product_path(linked_resource)
18
+ else
19
+ "/#{Spree::Config[:storefront_products_path]}/#{linked_resource.slug}"
20
+ end
21
+ when 'Spree::CmsPage'
22
+ return if linked_resource&.slug.blank?
23
+
24
+ if spree_routes.method_defined?(:page_path)
25
+ spree_routes.page_path(linked_resource.slug)
26
+ else
27
+ "/#{Spree::Config[:storefront_pages_path]}/#{linked_resource.slug}"
28
+ end
29
+ when 'Home Page'
30
+ '/'
31
+ when 'URL'
32
+ destination
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def spree_routes
39
+ Spree::Core::Engine.routes.url_helpers
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ module Spree
2
+ module FilterParam
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_save :set_filter_param
7
+ end
8
+
9
+ protected
10
+
11
+ def set_filter_param
12
+ return if param_candidate.blank?
13
+
14
+ self.filter_param = param_candidate.parameterize
15
+ end
16
+
17
+ def param_candidate
18
+ name
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ module Spree
2
+ module MemoizedData
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ # reset cache on save inside trasaction and transaction commit
7
+ after_save :reset_memoized_data
8
+ after_commit :reset_memoized_data
9
+
10
+ def reload(options = {})
11
+ reset_memoized_data
12
+ super(options)
13
+ end
14
+
15
+ private
16
+
17
+ def reset_memoized_data
18
+ self.class.const_get('MEMOIZED_METHODS').each do |v|
19
+ instance_variable_set(:"@#{v.gsub(/\?/, '')}", nil)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ module Spree
2
+ module MultiStoreResource
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ scope :for_store, ->(store) { joins(:stores).where(Store.table_name => { id: store.id }) }
7
+
8
+ validate :must_have_one_store, unless: :disable_store_presence_validation?
9
+ end
10
+
11
+ protected
12
+
13
+ def must_have_one_store
14
+ return if stores.any?
15
+
16
+ errors.add(:stores, Spree.t(:must_have_one_store))
17
+ end
18
+
19
+ # this can be overriden on model basis
20
+ def disable_store_presence_validation?
21
+ Spree::Config[:disable_store_presence_validation]
22
+ end
23
+ end
24
+ end
@@ -43,23 +43,23 @@ module Spree
43
43
  add_simple_scopes simple_scopes
44
44
 
45
45
  add_search_scope :ascend_by_master_price do
46
- joins(master: :default_price).order("#{price_table_name}.amount ASC")
46
+ order("#{price_table_name}.amount ASC")
47
47
  end
48
48
 
49
49
  add_search_scope :descend_by_master_price do
50
- joins(master: :default_price).order("#{price_table_name}.amount DESC")
50
+ order("#{price_table_name}.amount DESC")
51
51
  end
52
52
 
53
53
  add_search_scope :price_between do |low, high|
54
- joins(master: :default_price).where(Price.table_name => { amount: low..high })
54
+ where(Price.table_name => { amount: low..high })
55
55
  end
56
56
 
57
57
  add_search_scope :master_price_lte do |price|
58
- joins(master: :default_price).where("#{price_table_name}.amount <= ?", price)
58
+ where("#{price_table_name}.amount <= ?", price)
59
59
  end
60
60
 
61
61
  add_search_scope :master_price_gte do |price|
62
- joins(master: :default_price).where("#{price_table_name}.amount >= ?", price)
62
+ where("#{price_table_name}.amount >= ?", price)
63
63
  end
64
64
 
65
65
  # This scope selects products in taxon AND all its descendants
@@ -94,6 +94,19 @@ module Spree
94
94
  taxons.first ? prepare_taxon_conditions(taxons) : where(nil)
95
95
  end
96
96
 
97
+ add_search_scope :ascend_by_taxons_min_position do |taxon_ids|
98
+ joins(:classifications).
99
+ where(Classification.table_name => { taxon_id: taxon_ids }).
100
+ select(
101
+ [
102
+ "#{Product.table_name}.*",
103
+ "MIN(#{Classification.table_name}.position) AS min_position"
104
+ ].join(', ')
105
+ ).
106
+ group(:id).
107
+ order(min_position: :asc)
108
+ end
109
+
97
110
  # a scope that finds all products having property specified by name, object or id
98
111
  add_search_scope :with_property do |property|
99
112
  joins(:properties).where(property_conditions(property))
@@ -107,6 +120,12 @@ module Spree
107
120
  where(property_conditions(property))
108
121
  end
109
122
 
123
+ add_search_scope :with_property_values do |property_filter_param, property_values|
124
+ joins(product_properties: :property).
125
+ where(Property.table_name => { filter_param: property_filter_param }).
126
+ where(ProductProperty.table_name => { filter_param: property_values.map(&:parameterize) })
127
+ end
128
+
110
129
  add_search_scope :with_option do |option|
111
130
  option_types = OptionType.table_name
112
131
  conditions = case option
@@ -198,18 +217,50 @@ module Spree
198
217
  end
199
218
  end
200
219
  search_scopes << :not_discontinued
220
+
221
+ def self.with_currency(currency)
222
+ joins(variants_including_master: :prices).
223
+ where(Price.table_name => { currency: currency.upcase }).
224
+ where.not(Price.table_name => { amount: nil }).
225
+ distinct
226
+ end
227
+ search_scopes << :with_currency
228
+
201
229
  # Can't use add_search_scope for this as it needs a default argument
202
- def self.available(available_on = nil, _currency = nil)
230
+ def self.available(available_on = nil, currency = nil)
203
231
  available_on ||= Time.current
204
- not_discontinued.joins(master: :prices).where("#{Product.quoted_table_name}.available_on <= ?", available_on)
232
+
233
+ scope = not_discontinued.where("#{Product.quoted_table_name}.available_on <= ?", available_on)
234
+
235
+ unless Spree::Config.show_products_without_price
236
+ currency ||= Spree::Config[:currency]
237
+ scope = scope.with_currency(currency)
238
+ end
239
+
240
+ scope
205
241
  end
206
242
  search_scopes << :available
207
243
 
208
244
  def self.active(currency = nil)
209
- available(nil, currency&.upcase)
245
+ available(nil, currency)
210
246
  end
211
247
  search_scopes << :active
212
248
 
249
+ def self.for_filters(currency, taxon: nil)
250
+ scope = active(currency)
251
+ scope = scope.in_taxon(taxon) if taxon.present?
252
+ scope
253
+ end
254
+ search_scopes << :for_filters
255
+
256
+ def self.for_user(user = nil)
257
+ if user.try(:has_spree_role?, 'admin')
258
+ with_deleted
259
+ else
260
+ not_deleted.not_discontinued.where("#{Product.quoted_table_name}.available_on <= ?", Time.current)
261
+ end
262
+ end
263
+
213
264
  add_search_scope :taxons_name_eq do |name|
214
265
  group('spree_products.id').joins(:taxons).where(Taxon.arel_table[:name].eq(name))
215
266
  end
@@ -0,0 +1,9 @@
1
+ module Spree
2
+ module SingleStoreResource
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ scope :for_store, ->(store) { where(store_id: store.id) }
7
+ end
8
+ end
9
+ end
@@ -16,7 +16,12 @@ module Spree
16
16
  has_many :addresses, -> { where(deleted_at: nil).order('updated_at DESC') },
17
17
  class_name: 'Spree::Address', foreign_key: :user_id
18
18
 
19
+ validate :address_not_associated_with_other_user, :address_not_deprecated_in_completed_order
20
+
19
21
  def persist_order_address(order)
22
+ # FIXME: we should check if the User's address is associated with country accepted by Store
23
+ # if not we should try to find an address with valid country in User's address book
24
+ # or we should call `build_bill_address`
20
25
  b_address = bill_address || build_bill_address
21
26
  b_address.attributes = order.bill_address.value_attributes
22
27
  b_address.save
@@ -30,6 +35,20 @@ module Spree
30
35
  update(ship_address_id: s_address.id)
31
36
  end
32
37
  end
38
+
39
+ private
40
+
41
+ def address_not_associated_with_other_user
42
+ errors.add(:bill_address_id, :belongs_to_other_user) if bill_address&.user_id && self != bill_address&.user
43
+ errors.add(:ship_address_id, :belongs_to_other_user) if ship_address&.user_id && self != ship_address&.user
44
+ end
45
+
46
+ def address_not_deprecated_in_completed_order
47
+ errors.add(:bill_address_id, :deprecated_in_completed_order) if
48
+ orders.complete.with_deleted_bill_address.where(bill_address: bill_address_id).any?
49
+ errors.add(:ship_address_id, :deprecated_in_completed_order) if
50
+ orders.complete.with_deleted_ship_address.where(ship_address: ship_address_id).any?
51
+ end
33
52
  end
34
53
  end
35
54
  end
@@ -27,7 +27,7 @@ module Spree
27
27
  belongs_to :ship_address, class_name: 'Spree::Address', optional: true
28
28
  belongs_to :bill_address, class_name: 'Spree::Address', optional: true
29
29
 
30
- self.whitelisted_ransackable_associations = %w[bill_address ship_address]
30
+ self.whitelisted_ransackable_associations = %w[bill_address ship_address addresses]
31
31
  self.whitelisted_ransackable_attributes = %w[id email]
32
32
 
33
33
  def self.with_email(query)
@@ -59,9 +59,10 @@ module Spree
59
59
  first
60
60
  end
61
61
 
62
- def total_available_store_credit(currency = nil)
63
- currency ||= Spree::Config[:currency]
64
- store_credits.where(currency: currency).reload.to_a.sum(&:amount_remaining)
62
+ def total_available_store_credit(currency = nil, store = nil)
63
+ store ||= Store.default
64
+ currency ||= store.default_currency
65
+ store_credits.for_store(store).where(currency: currency).reload.to_a.sum(&:amount_remaining)
65
66
  end
66
67
 
67
68
  private
@@ -9,7 +9,7 @@ module Spree
9
9
  end
10
10
 
11
11
  def payment_sources
12
- credit_cards.with_payment_profile.not_expired.where(payment_method: Spree::PaymentMethod.active)
12
+ credit_cards.with_payment_profile.not_expired.where(payment_method: Spree::PaymentMethod.active).not_removed
13
13
  end
14
14
 
15
15
  def drop_payment_source(source)
@@ -61,6 +61,8 @@ module Spree
61
61
 
62
62
  def apply_user_permissions(user)
63
63
  can :read, ::Spree::Country
64
+ can :read, ::Spree::Menu
65
+ can :read, ::Spree::CmsPage
64
66
  can :read, ::Spree::OptionType
65
67
  can :read, ::Spree::OptionValue
66
68
  can :create, ::Spree::Order
@@ -71,7 +73,7 @@ module Spree
71
73
  !order.completed? && (order.user == user || order.token && token == order.token)
72
74
  end
73
75
  can :manage, ::Spree::Address, user_id: user.id
74
- can :read, ::Spree::CreditCard, user_id: user.id
76
+ can [:read, :destroy], ::Spree::CreditCard, user_id: user.id
75
77
  can :read, ::Spree::Product
76
78
  can :read, ::Spree::ProductProperty
77
79
  can :read, ::Spree::Property
@@ -1,6 +1,6 @@
1
1
  module Spree
2
2
  class Address < Spree::Base
3
- require 'twitter_cldr'
3
+ require 'validates_zipcode'
4
4
 
5
5
  if Rails::VERSION::STRING >= '6.1'
6
6
  serialize :preferences, Hash, default: {}
@@ -55,13 +55,21 @@ module Spree
55
55
  alias_attribute :first_name, :firstname
56
56
  alias_attribute :last_name, :lastname
57
57
 
58
- self.whitelisted_ransackable_attributes = %w[firstname lastname company]
58
+ self.whitelisted_ransackable_attributes = ADDRESS_FIELDS
59
+ self.whitelisted_ransackable_associations = %w[country state user]
59
60
 
60
61
  def self.build_default
62
+ ActiveSupport::Deprecation.warn(<<-DEPRECATION, caller)
63
+ `Address#build_default` is deprecated and will be removed in Spree 5.0.
64
+ Please use standard rails `Address.new(country: current_store.default_country)`
65
+ DEPRECATION
61
66
  new(country: Spree::Country.default)
62
67
  end
63
68
 
64
69
  def self.default(user = nil, kind = 'bill')
70
+ ActiveSupport::Deprecation.warn(<<-DEPRECATION, caller)
71
+ `Address#default` is deprecated and will be removed in Spree 5.0.
72
+ DEPRECATION
65
73
  if user && user_address = user.public_send(:"#{kind}_address")
66
74
  user_address.clone
67
75
  else
@@ -157,6 +165,7 @@ module Spree
157
165
  super
158
166
  else
159
167
  update_column :deleted_at, Time.current
168
+ assign_new_default_address_to_user
160
169
  end
161
170
  end
162
171
 
@@ -214,11 +223,23 @@ module Spree
214
223
  end
215
224
 
216
225
  def postal_code_validate
217
- return if country.blank? || country.iso.blank? || !require_zipcode?
218
- return unless TwitterCldr::Shared::PostalCodes.territories.include?(country.iso.downcase.to_sym)
226
+ return if country.blank? || country_iso.blank? || !require_zipcode? || zipcode.blank?
227
+ return unless ::ValidatesZipcode::CldrRegexpCollection::ZIPCODES_REGEX.keys.include?(country_iso.upcase.to_sym)
219
228
 
220
- postal_code = TwitterCldr::Shared::PostalCodes.for_territory(country.iso)
221
- errors.add(:zipcode, :invalid) unless postal_code.valid?(zipcode.to_s.strip)
229
+ formatted_zip = ::ValidatesZipcode::Formatter.new(
230
+ zipcode: zipcode.to_s.strip,
231
+ country_alpha2: country_iso.upcase
232
+ ).format
233
+
234
+ errors.add(:zipcode, :invalid) unless ::ValidatesZipcode.valid?(formatted_zip, country_iso.upcase)
235
+ end
236
+
237
+ def assign_new_default_address_to_user
238
+ return unless user
239
+
240
+ user.bill_address = user.addresses.last if user.bill_address == self
241
+ user.ship_address = user.addresses.last if user.ship_address == self
242
+ user.save!
222
243
  end
223
244
  end
224
245
  end