spree_core 4.1.5 → 4.2.0.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/spree/base_controller.rb +1 -0
  3. data/app/finders/spree/products/find.rb +46 -11
  4. data/app/helpers/spree/base_helper.rb +26 -3
  5. data/app/helpers/spree/mail_helper.rb +24 -0
  6. data/app/helpers/spree/products_helper.rb +15 -14
  7. data/app/mailers/spree/base_mailer.rb +17 -3
  8. data/app/mailers/spree/order_mailer.rb +11 -2
  9. data/app/mailers/spree/reimbursement_mailer.rb +4 -2
  10. data/app/mailers/spree/shipment_mailer.rb +4 -2
  11. data/app/models/concerns/spree/default_price.rb +2 -1
  12. data/app/models/concerns/spree/product_scopes.rb +2 -2
  13. data/app/models/concerns/spree/user_methods.rb +11 -5
  14. data/app/models/spree/app_configuration.rb +6 -0
  15. data/app/models/spree/line_item.rb +10 -1
  16. data/app/models/spree/option_type.rb +5 -1
  17. data/app/models/spree/order.rb +26 -5
  18. data/app/models/spree/price.rb +26 -2
  19. data/app/models/spree/product.rb +19 -9
  20. data/app/models/spree/promotion/actions/create_item_adjustments.rb +1 -1
  21. data/app/models/spree/promotion_handler/coupon.rb +1 -1
  22. data/app/models/spree/reimbursement.rb +2 -0
  23. data/app/models/spree/shipment.rb +2 -5
  24. data/app/models/spree/stock_location.rb +13 -2
  25. data/app/models/spree/store.rb +19 -2
  26. data/app/models/spree/taxon.rb +6 -0
  27. data/app/models/spree/variant.rb +29 -2
  28. data/app/presenters/spree/variant_presenter.rb +7 -0
  29. data/app/presenters/spree/variants/option_types_presenter.rb +1 -0
  30. data/app/services/spree/checkout/get_shipping_rates.rb +7 -10
  31. data/app/views/layouts/spree/base_mailer.html.erb +45 -40
  32. data/app/views/spree/order_mailer/cancel_email.html.erb +19 -25
  33. data/app/views/spree/order_mailer/cancel_email.text.erb +24 -2
  34. data/app/views/spree/order_mailer/confirm_email.html.erb +18 -65
  35. data/app/views/spree/order_mailer/confirm_email.text.erb +2 -1
  36. data/app/views/spree/order_mailer/store_owner_notification_email.html.erb +23 -0
  37. data/app/views/spree/order_mailer/store_owner_notification_email.text.erb +38 -0
  38. data/app/views/spree/reimbursement_mailer/reimbursement_email.html.erb +53 -58
  39. data/app/views/spree/reimbursement_mailer/reimbursement_email.text.erb +3 -1
  40. data/app/views/spree/shared/_base_mailer_footer.html.erb +6 -14
  41. data/app/views/spree/shared/_base_mailer_header.html.erb +12 -32
  42. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +293 -625
  43. data/app/views/spree/shared/_purchased_items_table.html.erb +60 -0
  44. data/app/views/spree/shared/purchased_items_table/_adjustment.html.erb +13 -0
  45. data/app/views/spree/shared/purchased_items_table/_line_item.html.erb +27 -0
  46. data/app/views/spree/shared/purchased_items_table/_subtotal.html.erb +13 -0
  47. data/app/views/spree/shared/purchased_items_table/_total.html.erb +13 -0
  48. data/app/views/spree/shipment_mailer/shipped_email.html.erb +31 -36
  49. data/app/views/spree/shipment_mailer/shipped_email.text.erb +2 -1
  50. data/config/initializers/assets.rb +1 -0
  51. data/config/locales/en.yml +113 -13
  52. data/db/default/spree/stores.rb +11 -10
  53. data/db/migrate/20140309033438_create_store_from_preferences.rb +1 -1
  54. data/db/migrate/20191017121054_add_supported_currencies_to_store.rb +10 -0
  55. data/db/migrate/20200102141311_add_social_to_spree_stores.rb +3 -0
  56. data/db/migrate/20200308210757_add_default_locale_to_spree_store.rb +7 -0
  57. data/db/migrate/20200310145140_add_customer_support_email_to_spree_store.rb +7 -0
  58. data/db/migrate/20200421095017_add_compare_at_amount_to_spree_prices.rb +7 -0
  59. data/db/migrate/20200423123001_add_default_country_id_to_spree_store.rb +9 -0
  60. data/db/migrate/20200430072209_add_footer_fields_to_spree_stores.rb +8 -0
  61. data/db/migrate/20200513154939_add_show_property_to_spree_product_properties.rb +5 -0
  62. data/db/migrate/20200607161221_add_store_owner_order_notification_delivered_to_spree_orders.rb +7 -0
  63. data/db/migrate/20200607161222_add_new_order_notifications_email_to_spree_stores.rb +7 -0
  64. data/db/migrate/20200826075557_add_unique_index_on_taxon_id_and_product_id_to_spree_products_taxons.rb +5 -0
  65. data/lib/generators/spree/install/templates/config/initializers/spree.rb +1 -0
  66. data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/backend/all.js +0 -2
  67. data/lib/generators/spree/install/templates/vendor/assets/javascripts/spree/frontend/all.js +0 -2
  68. data/lib/generators/spree/mailers_preview/mailers_preview_generator.rb +23 -0
  69. data/lib/generators/spree/mailers_preview/templates/mailers/previews/order_preview.rb +13 -0
  70. data/lib/generators/spree/mailers_preview/templates/mailers/previews/reimbursement_preview.rb +5 -0
  71. data/lib/generators/spree/mailers_preview/templates/mailers/previews/shipment_preview.rb +5 -0
  72. data/lib/generators/spree/mailers_preview/templates/mailers/previews/user_preview.rb +11 -0
  73. data/lib/spree/core.rb +1 -0
  74. data/lib/spree/core/controller_helpers/common.rb +1 -0
  75. data/lib/spree/core/controller_helpers/currency_helpers.rb +15 -0
  76. data/lib/spree/core/controller_helpers/store.rb +12 -1
  77. data/lib/spree/core/version.rb +1 -1
  78. data/lib/spree/permitted_attributes.rb +7 -4
  79. data/lib/spree/testing_support/authorization_helpers.rb +7 -4
  80. data/lib/spree/testing_support/factories/store_factory.rb +11 -8
  81. data/spree_core.gemspec +14 -8
  82. data/vendor/assets/javascripts/cleave.js +1669 -0
  83. metadata +43 -22
  84. data/app/views/spree/order_mailer/_adjustment.html.erb +0 -8
  85. data/app/views/spree/order_mailer/_subtotal.html.erb +0 -8
  86. data/app/views/spree/order_mailer/_total.html.erb +0 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1643c4f1dedde056b96b0c1e6c312c452084a0d34bc2d5ed2abc648d2185f43a
4
- data.tar.gz: cbc7c195925ef217208fa373120ebbd8cef241815dadedd24972bcd9cf904eb4
3
+ metadata.gz: dd3e3f16eb808f16f592360085f02f1382ee4ddd6ee0903c3eb8a8079e5d8bad
4
+ data.tar.gz: 8567b7555de6f0f578d6277e6943af11b68329e5e17a77d13c7e66085e7fe09f
5
5
  SHA512:
6
- metadata.gz: 337338d05ac9009476f2e66e099abc21f13461b1db2e02e85a571d722de625f6bcc38fd1009ae8a78bef10ff19aee2e687438da5415a5888125e930ee6865c21
7
- data.tar.gz: 92275d9db7cecb217bc2922898e9e1ce0359eac14606e11686ed339b5173826a2cd85329adc9c3a4bd713740e9f419f9e2909bef4024280c947bf301ce3d8a35
6
+ metadata.gz: 113900d45a999bb7aa47209797e8ab47a5ed6f40caa445242952eac3a604cc43bc658fec8fb86dc148743032f71341d97331cd7d6d7b77d84df36ffc979f122b
7
+ data.tar.gz: a175395cbe157f6ca1704ab5bdacbbf5c9abbee4bdae89f19363c06fc7a1fe06610fab87347342ecddd297d3bf22bf9354116340e8e408270a4f968a78883a0e
@@ -7,6 +7,7 @@ class Spree::BaseController < ApplicationController
7
7
  include Spree::Core::ControllerHelpers::Search
8
8
  include Spree::Core::ControllerHelpers::Store
9
9
  include Spree::Core::ControllerHelpers::StrongParameters
10
+ include Spree::Core::ControllerHelpers::CurrencyHelpers
10
11
 
11
12
  respond_to :html
12
13
  end
@@ -9,6 +9,7 @@ module Spree
9
9
  @price = String(params.dig(:filter, :price)).split(',').map(&:to_f)
10
10
  @currency = params[:currency] || current_currency
11
11
  @taxons = taxon_ids(params.dig(:filter, :taxons))
12
+ @concat_taxons = taxon_ids(params.dig(:filter, :concat_taxons))
12
13
  @name = params.dig(:filter, :name)
13
14
  @options = params.dig(:filter, :options).try(:to_unsafe_hash)
14
15
  @option_value_ids = params.dig(:filter, :option_value_ids)
@@ -22,6 +23,7 @@ module Spree
22
23
  products = by_skus(products)
23
24
  products = by_price(products)
24
25
  products = by_taxons(products)
26
+ products = by_concat_taxons(products)
25
27
  products = by_name(products)
26
28
  products = by_options(products)
27
29
  products = by_option_value_ids(products)
@@ -34,7 +36,8 @@ module Spree
34
36
 
35
37
  private
36
38
 
37
- attr_reader :ids, :skus, :price, :currency, :taxons, :name, :options, :option_value_ids, :scope, :sort_by, :deleted, :discontinued
39
+ attr_reader :ids, :skus, :price, :currency, :taxons, :concat_taxons, :name, :options,
40
+ :option_value_ids, :scope, :sort_by, :deleted, :discontinued
38
41
 
39
42
  def ids?
40
43
  ids.present?
@@ -52,6 +55,10 @@ module Spree
52
55
  taxons.present?
53
56
  end
54
57
 
58
+ def concat_taxons?
59
+ concat_taxons.present?
60
+ end
61
+
55
62
  def name?
56
63
  name.present?
57
64
  end
@@ -99,7 +106,20 @@ module Spree
99
106
  def by_taxons(products)
100
107
  return products unless taxons?
101
108
 
102
- products.joins(:taxons).where(spree_taxons: { id: taxons })
109
+ products.joins(:classifications).where(Classification.table_name => { taxon_id: taxons })
110
+ end
111
+
112
+ def by_concat_taxons(products)
113
+ return products unless concat_taxons?
114
+
115
+ product_ids = Spree::Product.
116
+ joins(:classifications).
117
+ where(Classification.table_name => { taxon_id: concat_taxons }).
118
+ group("#{Spree::Product.table_name}.id").
119
+ having("COUNT(#{Spree::Product.table_name}.id) = ?", concat_taxons.length).
120
+ ids
121
+
122
+ products.where(id: product_ids)
103
123
  end
104
124
 
105
125
  def by_name(products)
@@ -111,9 +131,11 @@ module Spree
111
131
  def by_options(products)
112
132
  return products unless options?
113
133
 
114
- options.map do |key, value|
115
- products.with_option_value(key, value)
116
- end.inject(:&)
134
+ products.where(
135
+ id: options.map do |key, value|
136
+ products.with_option_value(key, value).ids
137
+ end.flatten.compact.uniq
138
+ )
117
139
  end
118
140
 
119
141
  def by_option_value_ids(products)
@@ -142,13 +164,25 @@ module Spree
142
164
 
143
165
  case sort_by
144
166
  when 'default'
145
- products
167
+ if taxons?
168
+ products.
169
+ select("#{Product.table_name}.*, #{Classification.table_name}.position").
170
+ order("#{Classification.table_name}.position" => :asc)
171
+ else
172
+ products
173
+ end
146
174
  when 'newest-first'
147
175
  products.order(available_on: :desc)
148
176
  when 'price-high-to-low'
149
- products.select('spree_products.*, spree_prices.amount').reorder('').send(:descend_by_master_price)
177
+ products.
178
+ select("#{Product.table_name}.*, #{Spree::Price.table_name}.amount").
179
+ reorder('').
180
+ send(:descend_by_master_price)
150
181
  when 'price-low-to-high'
151
- products.select('spree_products.*, spree_prices.amount').reorder('').send(:ascend_by_master_price)
182
+ products.
183
+ select("#{Product.table_name}.*, #{Spree::Price.table_name}.amount").
184
+ reorder('').
185
+ send(:ascend_by_master_price)
152
186
  end
153
187
  end
154
188
 
@@ -160,10 +194,11 @@ module Spree
160
194
  discontinued ? products : products.available
161
195
  end
162
196
 
163
- def taxon_ids(taxon_id)
164
- return unless (taxon = Spree::Taxon.find_by(id: taxon_id))
197
+ def taxon_ids(taxons_ids)
198
+ return if taxons_ids.nil? || taxons_ids.to_s.blank?
165
199
 
166
- taxon.self_and_descendants.ids.map(&:to_s)
200
+ taxons = Spree::Taxon.where(id: taxons_ids.to_s.split(','))
201
+ taxons.map(&:cached_self_and_descendants_ids).flatten.compact.uniq.map(&:to_s)
167
202
  end
168
203
  end
169
204
  end
@@ -22,6 +22,13 @@ module Spree
22
22
  to_html
23
23
  end
24
24
 
25
+ def display_compare_at_price(product_or_variant)
26
+ product_or_variant.
27
+ price_in(current_currency).
28
+ display_compare_at_price_including_vat_for(current_price_options).
29
+ to_html
30
+ end
31
+
25
32
  def link_to_tracking(shipment, options = {})
26
33
  return unless shipment.tracking && shipment.shipping_method
27
34
 
@@ -34,7 +41,15 @@ module Spree
34
41
  end
35
42
  end
36
43
 
37
- def logo(image_path = Spree::Config[:logo], options = {})
44
+ def logo(image_path = nil, options = {})
45
+ image_path ||= if current_store.logo.attached? && current_store.logo.variable?
46
+ main_app.url_for(current_store.logo.variant(resize: '244x104>'))
47
+ elsif current_store.logo.attached? && current_store.logo.image?
48
+ main_app.url_for(current_store.logo)
49
+ else
50
+ Spree::Config[:logo]
51
+ end
52
+
38
53
  path = spree.respond_to?(:root_path) ? spree.root_path : main_app.root_path
39
54
 
40
55
  link_to path, 'aria-label': current_store.name, method: options[:method] do
@@ -97,7 +112,13 @@ module Spree
97
112
  def pretty_time(time)
98
113
  return '' if time.blank?
99
114
 
100
- [I18n.l(time.to_date, format: :long), time.strftime('%l:%M %p')].join(' ')
115
+ [I18n.l(time.to_date, format: :long), time.strftime('%l:%M %p %Z')].join(' ')
116
+ end
117
+
118
+ def pretty_date(date)
119
+ return '' if date.blank?
120
+
121
+ [I18n.l(date.to_date, format: :long)].join(' ')
101
122
  end
102
123
 
103
124
  def seo_url(taxon, options = nil)
@@ -111,7 +132,9 @@ module Spree
111
132
  # we should always try to render image of the default variant
112
133
  # same as it's done on PDP
113
134
  def default_image_for_product(product)
114
- if product.default_variant.images.any?
135
+ if product.images.any?
136
+ product.images.first
137
+ elsif product.default_variant.images.any?
115
138
  product.default_variant.images.first
116
139
  elsif product.variant_images.any?
117
140
  product.variant_images.first
@@ -0,0 +1,24 @@
1
+ module Spree
2
+ module MailHelper
3
+ include BaseHelper
4
+
5
+ def variant_image_url(variant)
6
+ image = default_image_for_product_or_variant(variant)
7
+ image ? main_app.url_for(image.url(:small)) : 'noimage/small.png'
8
+ end
9
+
10
+ def name_for(order)
11
+ order.name || Spree.t('customer')
12
+ end
13
+
14
+ def logo_path
15
+ if current_store.present? && current_store.logo.attached? && current_store.logo.variable?
16
+ main_app.url_for(current_store.logo.variant(resize: '244x104>'))
17
+ elsif current_store.present? && current_store.logo.attached? && current_store.logo.image?
18
+ main_app.url_for(current_store.logo)
19
+ else
20
+ Spree::Config.mailer_logo || Spree::Config.logo
21
+ end
22
+ end
23
+ end
24
+ end
@@ -67,7 +67,7 @@ module Spree
67
67
  cache_key_elements = common_product_cache_keys
68
68
  cache_key_elements += [
69
69
  product.cache_key_with_version,
70
- product.possible_promotions
70
+ product.possible_promotions.map(&:cache_key)
71
71
  ]
72
72
 
73
73
  cache_key_elements.compact.join('/')
@@ -79,8 +79,9 @@ module Spree
79
79
  string.slice(0..449) + '...'
80
80
  end
81
81
 
82
- def available_status(product) # will return a human readable string
83
- return Spree.t(:discontinued) if product.discontinued?
82
+ # will return a human readable string
83
+ def available_status(product)
84
+ return Spree.t(:discontinued) if product.discontinued?
84
85
  return Spree.t(:deleted) if product.deleted?
85
86
 
86
87
  if product.available?
@@ -116,16 +117,16 @@ module Spree
116
117
  def related_products
117
118
  return [] unless @product.respond_to?(:has_related_products?) && @product.has_related_products?(:related_products)
118
119
 
119
- @_related_products ||= @product.
120
- related_products.
121
- includes(
122
- :tax_category,
123
- master: [
124
- :prices,
125
- images: { attachment_attachment: :blob },
126
- ]
127
- ).
128
- limit(Spree::Config[:products_per_page])
120
+ @related_products ||= @product.
121
+ related_products.
122
+ includes(
123
+ :tax_category,
124
+ master: [
125
+ :prices,
126
+ images: { attachment_attachment: :blob },
127
+ ]
128
+ ).
129
+ limit(Spree::Config[:products_per_page])
129
130
  end
130
131
 
131
132
  def product_available_in_currency?
@@ -145,7 +146,7 @@ module Spree
145
146
  end
146
147
 
147
148
  def variants_option_types_presenter(variants, product)
148
- @_variants_option_types_presenter ||= begin
149
+ @variants_option_types_presenter ||= begin
149
150
  option_types = Spree::Variants::OptionTypesFinder.new(variant_ids: variants.map(&:id)).execute
150
151
 
151
152
  Spree::Variants::OptionTypesPresenter.new(option_types, variants, product)
@@ -1,10 +1,18 @@
1
1
  module Spree
2
2
  class BaseMailer < ActionMailer::Base
3
+ add_template_helper(MailHelper)
4
+
5
+ def current_store
6
+ @current_store ||= Spree::Store.current
7
+ end
8
+ helper_method :current_store
9
+
3
10
  def from_address
4
- Spree::Store.current.mail_from_address
11
+ current_store.mail_from_address
5
12
  end
6
13
 
7
- def money(amount, currency = Spree::Config[:currency])
14
+ def money(amount, currency = nil)
15
+ currency ||= current_store.default_currency
8
16
  Spree::Money.new(amount, currency: currency).to_s
9
17
  end
10
18
  helper_method :money
@@ -16,6 +24,7 @@ module Spree
16
24
 
17
25
  def mail(headers = {}, &block)
18
26
  ensure_default_action_mailer_url_host
27
+ set_email_locale
19
28
  super if Spree::Config[:send_core_emails]
20
29
  end
21
30
 
@@ -26,7 +35,12 @@ module Spree
26
35
  # http://guides.rubyonrails.org/action_mailer_basics.html#generating-urls-in-action-mailer-views
27
36
  def ensure_default_action_mailer_url_host
28
37
  ActionMailer::Base.default_url_options ||= {}
29
- ActionMailer::Base.default_url_options[:host] ||= Spree::Store.current.url
38
+ ActionMailer::Base.default_url_options[:host] ||= current_store.url
39
+ end
40
+
41
+ def set_email_locale
42
+ locale = @order&.store&.default_locale || current_store&.default_locale
43
+ I18n.locale = locale if locale.present?
30
44
  end
31
45
  end
32
46
  end
@@ -2,15 +2,24 @@ module Spree
2
2
  class OrderMailer < BaseMailer
3
3
  def confirm_email(order, resend = false)
4
4
  @order = order.respond_to?(:id) ? order : Spree::Order.find(order)
5
+ current_store = @order.store
5
6
  subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
6
- subject += "#{Spree::Store.current.name} #{Spree.t('order_mailer.confirm_email.subject')} ##{@order.number}"
7
+ subject += "#{current_store.name} #{Spree.t('order_mailer.confirm_email.subject')} ##{@order.number}"
7
8
  mail(to: @order.email, from: from_address, subject: subject)
8
9
  end
9
10
 
11
+ def store_owner_notification_email(order)
12
+ @order = order.respond_to?(:id) ? order : Spree::Order.find(order)
13
+ current_store = @order.store
14
+ subject = Spree.t('order_mailer.store_owner_notification_email.subject', store_name: current_store.name)
15
+ mail(to: current_store.new_order_notifications_email, from: from_address, subject: subject)
16
+ end
17
+
10
18
  def cancel_email(order, resend = false)
11
19
  @order = order.respond_to?(:id) ? order : Spree::Order.find(order)
20
+ current_store = @order.store
12
21
  subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
13
- subject += "#{Spree::Store.current.name} #{Spree.t('order_mailer.cancel_email.subject')} ##{@order.number}"
22
+ subject += "#{current_store.name} #{Spree.t('order_mailer.cancel_email.subject')} ##{@order.number}"
14
23
  mail(to: @order.email, from: from_address, subject: subject)
15
24
  end
16
25
  end
@@ -2,9 +2,11 @@ module Spree
2
2
  class ReimbursementMailer < BaseMailer
3
3
  def reimbursement_email(reimbursement, resend = false)
4
4
  @reimbursement = reimbursement.respond_to?(:id) ? reimbursement : Spree::Reimbursement.find(reimbursement)
5
+ @order = @reimbursement.order
6
+ current_store = @reimbursement.store || Spree::Store.current
5
7
  subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
6
- subject += "#{Spree::Store.current.name} #{Spree.t('reimbursement_mailer.reimbursement_email.subject')} ##{@reimbursement.order.number}"
7
- mail(to: @reimbursement.order.email, from: from_address, subject: subject)
8
+ subject += "#{current_store.name} #{Spree.t('reimbursement_mailer.reimbursement_email.subject')} ##{@order.number}"
9
+ mail(to: @order.email, from: current_store.mail_from_address, subject: subject)
8
10
  end
9
11
  end
10
12
  end
@@ -2,9 +2,11 @@ module Spree
2
2
  class ShipmentMailer < BaseMailer
3
3
  def shipped_email(shipment, resend = false)
4
4
  @shipment = shipment.respond_to?(:id) ? shipment : Spree::Shipment.find(shipment)
5
+ @order = @shipment.order
6
+ current_store = @shipment.store
5
7
  subject = (resend ? "[#{Spree.t(:resend).upcase}] " : '')
6
- subject += "#{Spree::Store.current.name} #{Spree.t('shipment_mailer.shipped_email.subject')} ##{@shipment.order.number}"
7
- mail(to: @shipment.order.email, from: from_address, subject: subject)
8
+ subject += "#{current_store.name} #{Spree.t('shipment_mailer.shipped_email.subject')} ##{@order.number}"
9
+ mail(to: @order.email, from: from_address, subject: subject)
8
10
  end
9
11
  end
10
12
  end
@@ -9,7 +9,8 @@ module Spree
9
9
  dependent: :destroy
10
10
 
11
11
  delegate :display_price, :display_amount, :price, :currency, :price=,
12
- :price_including_vat_for, :currency=, to: :find_or_build_default_price
12
+ :price_including_vat_for, :currency=, :display_compare_at_price,
13
+ :compare_at_price, :compare_at_price=, to: :find_or_build_default_price
13
14
 
14
15
  after_save :save_default_price
15
16
 
@@ -81,7 +81,7 @@ module Spree
81
81
  # SELECT COUNT(*) ...
82
82
  add_search_scope :in_taxon do |taxon|
83
83
  includes(:classifications).
84
- where('spree_products_taxons.taxon_id' => taxon.self_and_descendants.pluck(:id)).
84
+ where('spree_products_taxons.taxon_id' => taxon.cached_self_and_descendants_ids).
85
85
  order('spree_products_taxons.position ASC')
86
86
  end
87
87
 
@@ -221,7 +221,7 @@ module Spree
221
221
 
222
222
  # specifically avoid having an order for taxon search (conflicts with main order)
223
223
  def self.prepare_taxon_conditions(taxons)
224
- ids = taxons.map { |taxon| taxon.self_and_descendants.pluck(:id) }.flatten.uniq
224
+ ids = taxons.map(&:cached_self_and_descendants_ids).flatten.uniq
225
225
  joins(:classifications).where(Classification.table_name => { taxon_id: ids })
226
226
  end
227
227
  private_class_method :prepare_taxon_conditions
@@ -30,15 +30,20 @@ module Spree
30
30
  self.whitelisted_ransackable_associations = %w[bill_address ship_address]
31
31
  self.whitelisted_ransackable_attributes = %w[id email]
32
32
 
33
+ def self.with_email(query)
34
+ where('email LIKE ?', "%#{query}%")
35
+ end
36
+
33
37
  def self.with_address(query, address = :ship_address)
34
38
  left_outer_joins(address).
35
39
  where("#{Spree::Address.table_name}.firstname like ?", "%#{query}%").
36
40
  or(left_outer_joins(address).where("#{Spree::Address.table_name}.lastname like ?", "%#{query}%"))
37
41
  end
38
42
 
39
- def self.with_email_or_addresses_ids(query, addresses_ids = [])
40
- where('email LIKE ?', "%#{query}%").
41
- or(where(id: addresses_ids))
43
+ def self.with_email_or_address(email, address)
44
+ left_outer_joins(:addresses).
45
+ where("#{Spree::Address.table_name}.firstname LIKE ? or #{Spree::Address.table_name}.lastname LIKE ? or email LIKE ?",
46
+ "%#{address}%", "%#{address}%", "%#{email}%")
42
47
  end
43
48
  end
44
49
 
@@ -54,8 +59,9 @@ module Spree
54
59
  first
55
60
  end
56
61
 
57
- def total_available_store_credit
58
- store_credits.reload.to_a.sum(&:amount_remaining)
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)
59
65
  end
60
66
 
61
67
  private
@@ -44,10 +44,12 @@ module Spree
44
44
  preference :company, :boolean, default: false # Request company field for billing and shipping addr
45
45
  preference :currency, :string, default: 'USD'
46
46
  preference :default_country_id, :integer
47
+ preference :disable_sku_validation, :boolean, default: false # when turned off disables the built-in SKU uniqueness validation
47
48
  preference :expedited_exchanges, :boolean, default: false # NOTE this requires payment profiles to be supported on your gateway of choice as well as a delayed job handler to be configured with activejob. kicks off an exchange shipment upon return authorization save. charge customer if they do not return items within timely manner.
48
49
  preference :expedited_exchanges_days_window, :integer, default: 14 # the amount of days the customer has to return their item after the expedited exchange is shipped in order to avoid being charged
49
50
  preference :layout, :string, default: 'spree/layouts/spree_application'
50
51
  preference :logo, :string, default: 'logo/spree_50.png'
52
+ preference :mailer_logo, :string, default: 'logo/spree_50.png'
51
53
  preference :max_level_in_taxons_menu, :integer, default: 1 # maximum nesting level in taxons menu
52
54
  preference :products_per_page, :integer, default: 12
53
55
  preference :require_master_price, :boolean, default: true
@@ -66,6 +68,10 @@ module Spree
66
68
  preference :non_expiring_credit_types, :array, default: []
67
69
  preference :credit_to_new_allocation, :boolean, default: false
68
70
 
71
+ # Multi currency configurations
72
+ preference :allow_currency_change, :boolean, default: false
73
+ preference :show_currency_selector, :boolean, default: false
74
+
69
75
  # searcher_class allows spree extension writers to provide their own Search class
70
76
  def searcher_class
71
77
  @searcher_class ||= Spree::Core::Search::Base