spree_core 4.2.0.beta → 4.2.0.rc5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/spree/base_controller.rb +2 -3
  3. data/app/controllers/spree/errors_controller.rb +11 -0
  4. data/app/finders/spree/addresses/find.rb +6 -0
  5. data/app/finders/spree/base_finder.rb +14 -0
  6. data/app/finders/spree/countries/find.rb +11 -3
  7. data/app/finders/spree/credit_cards/find.rb +2 -2
  8. data/app/finders/spree/orders/find_current.rb +2 -2
  9. data/app/finders/spree/products/find.rb +12 -1
  10. data/app/helpers/spree/base_helper.rb +38 -18
  11. data/app/helpers/spree/locale_helper.rb +19 -0
  12. data/app/helpers/spree/mail_helper.rb +12 -7
  13. data/app/helpers/spree/products_helper.rb +39 -13
  14. data/app/mailers/spree/base_mailer.rb +5 -5
  15. data/app/mailers/spree/order_mailer.rb +3 -3
  16. data/app/mailers/spree/reimbursement_mailer.rb +1 -1
  17. data/app/mailers/spree/shipment_mailer.rb +1 -1
  18. data/app/models/concerns/spree/default_price.rb +1 -5
  19. data/app/models/concerns/spree/user_methods.rb +2 -2
  20. data/app/models/concerns/spree/user_payment_source.rb +1 -1
  21. data/app/models/spree/ability.rb +45 -34
  22. data/app/models/spree/address.rb +17 -1
  23. data/app/models/spree/adjustment.rb +1 -0
  24. data/app/models/spree/app_configuration.rb +2 -3
  25. data/app/models/spree/app_dependencies.rb +10 -2
  26. data/app/models/spree/base.rb +5 -0
  27. data/app/models/spree/credit_card.rb +5 -0
  28. data/app/models/spree/fulfilment_changer.rb +58 -16
  29. data/app/models/spree/image.rb +14 -14
  30. data/app/models/spree/inventory_unit.rb +2 -7
  31. data/app/models/spree/line_item.rb +9 -16
  32. data/app/models/spree/log_entry.rb +1 -1
  33. data/app/models/spree/option_type.rb +2 -0
  34. data/app/models/spree/order.rb +12 -6
  35. data/app/models/spree/order/address_book.rb +7 -20
  36. data/app/models/spree/order/payments.rb +10 -2
  37. data/app/models/spree/payment.rb +18 -4
  38. data/app/models/spree/payment/processing.rb +2 -2
  39. data/app/models/spree/payment_method.rb +3 -3
  40. data/app/models/spree/preferences/store.rb +1 -1
  41. data/app/models/spree/price.rb +1 -6
  42. data/app/models/spree/product.rb +24 -17
  43. data/app/models/spree/promotion.rb +10 -15
  44. data/app/models/spree/promotion/rules/option_value.rb +1 -1
  45. data/app/models/spree/promotion/rules/product.rb +2 -1
  46. data/app/models/spree/promotion/rules/user.rb +2 -1
  47. data/app/models/spree/promotion_handler/coupon.rb +1 -2
  48. data/app/models/spree/promotion_handler/promotion_duplicator.rb +9 -3
  49. data/app/models/spree/refund.rb +2 -2
  50. data/app/models/spree/return_item/eligibility_validator/default.rb +0 -2
  51. data/app/models/spree/return_item/eligibility_validator/{r_m_a_required.rb → rma_required.rb} +0 -0
  52. data/app/models/spree/shipment.rb +1 -1
  53. data/app/models/spree/shipping_method.rb +1 -5
  54. data/app/models/spree/shipping_rate.rb +2 -11
  55. data/app/models/spree/stock/availability_validator.rb +3 -4
  56. data/app/models/spree/stock_item.rb +1 -5
  57. data/app/models/spree/store.rb +45 -1
  58. data/app/models/spree/store_credit.rb +1 -1
  59. data/app/models/spree/variant.rb +8 -15
  60. data/app/models/spree/zone.rb +17 -4
  61. data/app/presenters/spree/variant_presenter.rb +4 -6
  62. data/app/services/spree/account/addresses/create.rb +23 -0
  63. data/app/services/spree/account/addresses/helper.rb +37 -0
  64. data/app/services/spree/account/addresses/update.rb +23 -0
  65. data/app/services/spree/cart/estimate_shipping_rates.rb +1 -1
  66. data/app/services/spree/checkout/update.rb +13 -2
  67. data/app/services/spree/compare_line_items.rb +4 -2
  68. data/app/sorters/spree/base_sorter.rb +35 -0
  69. data/app/sorters/spree/orders/sort.rb +1 -37
  70. data/app/sorters/spree/products/sort.rb +9 -32
  71. data/app/validators/email_validator.rb +1 -1
  72. data/app/views/spree/errors/forbidden.html.erb +0 -0
  73. data/app/views/spree/errors/unauthorized.html.erb +0 -0
  74. data/app/views/spree/shared/_base_mailer_stylesheets.html.erb +0 -2
  75. data/app/views/spree/shared/purchased_items_table/_line_item.html.erb +1 -1
  76. data/config/initializers/inflections.rb +3 -0
  77. data/config/initializers/rails61_fixes.rb +3 -0
  78. data/config/locales/en.yml +42 -63
  79. data/config/routes.rb +2 -1
  80. data/db/default/spree/countries.rb +10 -4
  81. data/db/default/spree/states.rb +42 -5
  82. data/db/default/spree/stores.rb +18 -13
  83. data/db/default/spree/zones.rb +5 -2
  84. data/db/migrate/20130326175857_add_stock_location_to_rma.rb +1 -1
  85. data/db/migrate/20200610113542_add_label_to_spree_addresses.rb +5 -0
  86. data/db/migrate/20201006110150_add_checkout_zone_field_to_store.rb +12 -0
  87. data/db/migrate/20201012091259_add_filterable_column_to_spree_option_types.rb +6 -0
  88. data/db/migrate/20201013084504_add_seo_robots_to_spree_stores.rb +5 -0
  89. data/db/migrate/20201127084048_add_default_country_kind_to_spree_zones.rb +5 -0
  90. data/db/migrate/20210112193440_remove_contact_email_from_spree_stores.rb +5 -0
  91. data/db/migrate/20210114182625_create_spree_payment_methods_stores.rb +10 -0
  92. data/db/migrate/20210114220232_migrate_data_payment_methods_stores.rb +15 -0
  93. data/db/migrate/20210117112551_remove_store_id_from_spree_payment_methods.rb +5 -0
  94. data/db/migrate/20210120142527_ensure_default_locale_in_spree_stores.rb +5 -0
  95. data/lib/generators/spree/install/templates/config/spree_storefront.yml +9 -9
  96. data/lib/spree/core.rb +3 -1
  97. data/lib/spree/core/controller_helpers/auth.rb +3 -1
  98. data/lib/spree/core/controller_helpers/common.rb +6 -8
  99. data/lib/spree/core/controller_helpers/currency.rb +45 -0
  100. data/lib/spree/core/controller_helpers/locale.rb +57 -0
  101. data/lib/spree/core/controller_helpers/order.rb +9 -4
  102. data/lib/spree/core/controller_helpers/store.rb +4 -16
  103. data/lib/spree/core/importer/order.rb +9 -9
  104. data/lib/spree/core/product_filters.rb +3 -3
  105. data/lib/spree/core/version.rb +1 -1
  106. data/lib/spree/i18n.rb +7 -21
  107. data/lib/spree/permitted_attributes.rb +3 -3
  108. data/lib/spree/service_module.rb +6 -2
  109. data/lib/spree/testing_support/capybara_config.rb +1 -1
  110. data/lib/spree/testing_support/factories/promotion_factory.rb +29 -17
  111. data/lib/spree/testing_support/factories/shipment_factory.rb +7 -9
  112. data/lib/spree/testing_support/factories/stock_location_factory.rb +2 -2
  113. data/lib/spree/testing_support/factories/zone_factory.rb +16 -13
  114. data/lib/spree/testing_support/i18n.rb +1 -1
  115. data/lib/spree/testing_support/order_walkthrough.rb +8 -3
  116. data/lib/spree/testing_support/rspec_retry_config.rb +10 -0
  117. data/spree_core.gemspec +7 -5
  118. metadata +90 -28
  119. data/lib/spree/core/controller_helpers/currency_helpers.rb +0 -15
  120. data/lib/spree/i18n/base.rb +0 -17
  121. data/lib/spree/i18n/initializer.rb +0 -1
@@ -4,7 +4,7 @@ module Spree
4
4
 
5
5
  with_options inverse_of: :line_items do
6
6
  belongs_to :order, class_name: 'Spree::Order', touch: true
7
- belongs_to :variant, class_name: 'Spree::Variant'
7
+ belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant'
8
8
  end
9
9
  belongs_to :tax_category, class_name: 'Spree::TaxCategory'
10
10
 
@@ -57,16 +57,13 @@ module Spree
57
57
  end
58
58
 
59
59
  def update_price
60
- if Spree::Config.allow_currency_change == true
61
- currency_price = Spree::Price.where(
62
- currency: order.currency,
63
- variant_id: variant_id
64
- ).first
60
+ currency_price = variant.price_in(order.currency)
65
61
 
66
- self.price = currency_price.price_including_vat_for(tax_zone: tax_zone)
67
- else
68
- self.price = variant.price_including_vat_for(tax_zone: tax_zone)
69
- end
62
+ self.price = if currency_price.amount.present?
63
+ currency_price.price_including_vat_for(tax_zone: tax_zone)
64
+ else
65
+ 0
66
+ end
70
67
  end
71
68
 
72
69
  def copy_tax_category
@@ -75,7 +72,8 @@ module Spree
75
72
 
76
73
  extend DisplayMoney
77
74
  money_methods :amount, :subtotal, :discounted_amount, :final_amount, :total, :price,
78
- :adjustment_total, :additional_tax_total, :promo_total, :included_tax_total
75
+ :adjustment_total, :additional_tax_total, :promo_total, :included_tax_total,
76
+ :pre_tax_amount
79
77
 
80
78
  alias single_money display_price
81
79
  alias single_display_amount display_price
@@ -119,11 +117,6 @@ module Spree
119
117
  assign_attributes opts
120
118
  end
121
119
 
122
- # Remove variant default_scope `deleted_at: nil`
123
- def variant
124
- Spree::Variant.unscoped { super }
125
- end
126
-
127
120
  private
128
121
 
129
122
  def ensure_valid_quantity
@@ -11,7 +11,7 @@ module Spree
11
11
  end
12
12
 
13
13
  def parsed_details
14
- @details ||= YAML.load(details)
14
+ @details ||= YAML.safe_load(details, [ActiveMerchant::Billing::Response])
15
15
  end
16
16
  end
17
17
  end
@@ -19,6 +19,8 @@ module Spree
19
19
 
20
20
  default_scope { order(:position) }
21
21
 
22
+ scope :filterable, -> { where(filterable: true) }
23
+
22
24
  accepts_nested_attributes_for :option_values, reject_if: ->(ov) { ov[:name].blank? || ov[:presentation].blank? }, allow_destroy: true
23
25
 
24
26
  after_touch :touch_all_products
@@ -22,7 +22,7 @@ module Spree
22
22
  money_methods :outstanding_balance, :item_total, :adjustment_total,
23
23
  :included_tax_total, :additional_tax_total, :tax_total,
24
24
  :shipment_total, :promo_total, :total,
25
- :cart_promo_total
25
+ :cart_promo_total, :pre_tax_item_amount, :pre_tax_total
26
26
 
27
27
  alias display_ship_total display_shipment_total
28
28
  alias_attribute :ship_total, :shipment_total
@@ -157,6 +157,7 @@ module Spree
157
157
  scope :completed_between, ->(start_date, end_date) { where(completed_at: start_date..end_date) }
158
158
  scope :complete, -> { where.not(completed_at: nil) }
159
159
  scope :incomplete, -> { where(completed_at: nil) }
160
+ scope :not_canceled, -> { where.not(state: 'canceled') }
160
161
 
161
162
  # shows completed orders first, by their completed_at date, then uncompleted orders by their created_at
162
163
  scope :reverse_chronological, -> { order(Arel.sql('spree_orders.completed_at IS NULL'), completed_at: :desc, created_at: :desc) }
@@ -174,7 +175,12 @@ module Spree
174
175
 
175
176
  # Sum of all line item amounts pre-tax
176
177
  def pre_tax_item_amount
177
- line_items.to_a.sum(&:pre_tax_amount)
178
+ line_items.sum(:pre_tax_amount)
179
+ end
180
+
181
+ # Sum of all line item and shipment pre-tax
182
+ def pre_tax_total
183
+ pre_tax_item_amount + shipments.sum(:pre_tax_amount)
178
184
  end
179
185
 
180
186
  def shipping_discount
@@ -644,10 +650,10 @@ module Spree
644
650
  end
645
651
 
646
652
  def has_free_shipping?
647
- promotions.
648
- joins(:promotion_actions).
649
- where(spree_promotion_actions: { type: 'Spree::Promotion::Actions::FreeShipping' }).
650
- exists?
653
+ shipment_adjustments.
654
+ joins(:promotion_action).
655
+ where(spree_adjustments: { eligible: true, source_type: 'Spree::PromotionAction' },
656
+ spree_promotion_actions: { type: 'Spree::Promotion::Actions::FreeShipping' }).exists?
651
657
  end
652
658
 
653
659
  private
@@ -55,31 +55,18 @@ module Spree
55
55
  def update_or_create_address(attributes = {})
56
56
  return if attributes.blank?
57
57
 
58
- attributes = attributes.select { |_k, v| v.present? }
58
+ attributes.transform_values! { |v| v == '' ? nil : v }
59
59
 
60
- if user
61
- address = user.addresses.build(attributes.except(:id)).check
62
- return address if address.id
63
- end
64
-
65
- if attributes[:id]
66
- address = Spree::Address.find(attributes[:id])
67
- attributes.delete(:id)
60
+ default_address_scope = user ? user.addresses : ::Spree::Address
61
+ default_address = default_address_scope.find_by(id: attributes[:id])
68
62
 
69
- if address&.editable?
70
- address.update(attributes)
71
- return address
72
- else
73
- attributes.delete(:id)
74
- end
75
- end
63
+ if default_address&.editable?
64
+ default_address.update(attributes)
76
65
 
77
- unless attributes[:id]
78
- address = Spree::Address.new(attributes)
79
- address.save
66
+ return default_address
80
67
  end
81
68
 
82
- address
69
+ ::Spree::Address.find_or_create_by(attributes.except(:id, :updated_at, :created_at))
83
70
  end
84
71
  end
85
72
  end
@@ -32,7 +32,7 @@ module Spree
32
32
  end
33
33
 
34
34
  def pending_payments
35
- payments.select(&:pending?)
35
+ payments.pending
36
36
  end
37
37
 
38
38
  def unprocessed_payments
@@ -52,7 +52,7 @@ module Spree
52
52
 
53
53
  payment.public_send(method)
54
54
 
55
- if payment.completed? && payment_total != total
55
+ if payment.completed? && payment_total != total_without_pending_store_credits
56
56
  self.payment_total += payment.amount
57
57
  end
58
58
  end
@@ -60,6 +60,14 @@ module Spree
60
60
  result = !!Spree::Config[:allow_checkout_on_gateway_error]
61
61
  errors.add(:base, e.message) && (return result)
62
62
  end
63
+
64
+ # Pending store credits are not added to `self.payment_total`.
65
+ # It can cause a situation where the amount of the credit card payment reduced with store credits
66
+ # may be added twice to `self.payment_total` causing wrong `order.outstanding_balance`
67
+ # calculations and thus an incorrect payment state.
68
+ def total_without_pending_store_credits
69
+ total - payments.map { |p| p.amount if p.source.is_a?(Spree::StoreCredit) && p.pending? }.sum(&:to_f)
70
+ end
63
71
  end
64
72
  end
65
73
  end
@@ -14,7 +14,7 @@ module Spree
14
14
 
15
15
  with_options inverse_of: :payments do
16
16
  belongs_to :order, class_name: 'Spree::Order', touch: true
17
- belongs_to :payment_method, class_name: 'Spree::PaymentMethod'
17
+ belongs_to :payment_method, -> { with_deleted }, class_name: 'Spree::PaymentMethod'
18
18
  end
19
19
  belongs_to :source, polymorphic: true
20
20
 
@@ -195,14 +195,28 @@ module Spree
195
195
 
196
196
  def validate_source
197
197
  if source && !source.valid?
198
- source.errors.each do |field, error|
199
- field_name = I18n.t("activerecord.attributes.#{source.class.to_s.underscore}.#{field}")
200
- errors.add(Spree.t(source.class.to_s.demodulize.underscore), "#{field_name} #{error}")
198
+ if Rails::VERSION::STRING >= '6.1'
199
+ source.errors.map { |error| { field: error.attribute, message: error&.message } }.each do |err|
200
+ next if err[:field].blank? || err[:message].blank?
201
+
202
+ add_source_error(err[:field], err[:message])
203
+ end
204
+ else
205
+ source.errors.messages.each do |field, error|
206
+ next if field.blank? || error.empty?
207
+
208
+ add_source_error(field, error.first)
209
+ end
201
210
  end
202
211
  end
203
212
  !errors.present?
204
213
  end
205
214
 
215
+ def add_source_error(field, message)
216
+ field_name = I18n.t("activerecord.attributes.#{source.class.to_s.underscore}.#{field}")
217
+ errors.add(Spree.t(source.class.to_s.demodulize.underscore), "#{field_name} #{message}")
218
+ end
219
+
206
220
  def profiles_supported?
207
221
  payment_method.respond_to?(:payment_profiles_supported?) && payment_method.payment_profiles_supported?
208
222
  end
@@ -163,8 +163,8 @@ module Spree
163
163
  else
164
164
  error.to_s
165
165
  end
166
- logger.error(Spree.t(:gateway_error))
167
- logger.error(" #{error.to_yaml}")
166
+ Rails.logger.error(Spree.t(:gateway_error))
167
+ Rails.logger.error(" #{error.to_yaml}")
168
168
  raise Core::GatewayError, text
169
169
  end
170
170
 
@@ -12,7 +12,7 @@ module Spree
12
12
 
13
13
  validates :name, presence: true
14
14
 
15
- belongs_to :store
15
+ has_and_belongs_to_many :stores
16
16
 
17
17
  with_options dependent: :restrict_with_error do
18
18
  has_many :payments, class_name: 'Spree::Payment', inverse_of: :payment_method
@@ -79,9 +79,9 @@ module Spree
79
79
  end
80
80
 
81
81
  def available_for_store?(store)
82
- return true if store.blank? || store_id.blank?
82
+ return true if store.blank?
83
83
 
84
- store_id == store.id
84
+ store_ids.include?(store.id)
85
85
  end
86
86
  end
87
87
  end
@@ -6,7 +6,7 @@
6
6
 
7
7
  require 'singleton'
8
8
 
9
- DB_EXCEPTIONS = if defined? PG
9
+ DB_EXCEPTIONS ||= if defined? PG
10
10
  [PG::ConnectionBad, ActiveRecord::NoDatabaseError]
11
11
  elsif defined? Mysql2
12
12
  [Mysql2::Error::ConnectionError, ActiveRecord::NoDatabaseError]
@@ -6,7 +6,7 @@ module Spree
6
6
 
7
7
  MAXIMUM_AMOUNT = BigDecimal('99_999_999.99')
8
8
 
9
- belongs_to :variant, class_name: 'Spree::Variant', inverse_of: :prices, touch: true
9
+ belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant', inverse_of: :prices, touch: true
10
10
 
11
11
  before_validation :ensure_currency
12
12
 
@@ -63,11 +63,6 @@ module Spree
63
63
  Spree::Money.new(compare_at_price_including_vat_for(price_options), currency: currency)
64
64
  end
65
65
 
66
- # Remove variant default_scope `deleted_at: nil`
67
- def variant
68
- Spree::Variant.unscoped { super }
69
- end
70
-
71
66
  private
72
67
 
73
68
  def ensure_currency
@@ -160,7 +160,7 @@ module Spree
160
160
  #
161
161
  # @return [Spree::Variant]
162
162
  def default_variant
163
- Rails.cache.fetch(default_variant_cache_key) do
163
+ @default_variant ||= Rails.cache.fetch(default_variant_cache_key) do
164
164
  if Spree::Config[:track_inventory_levels] && variants.in_stock_or_backorderable.any?
165
165
  variants.in_stock_or_backorderable.first
166
166
  else
@@ -172,11 +172,11 @@ module Spree
172
172
  # Returns default Variant ID for Product
173
173
  # @return [Integer]
174
174
  def default_variant_id
175
- default_variant.id
175
+ @default_variant_id ||= default_variant.id
176
176
  end
177
177
 
178
178
  def tax_category
179
- super || TaxCategory.find_by(is_default: true)
179
+ @tax_category ||= super || TaxCategory.find_by(is_default: true)
180
180
  end
181
181
 
182
182
  # Adding properties and option types on creation based on a chosen prototype
@@ -288,11 +288,11 @@ module Spree
288
288
  end
289
289
 
290
290
  def total_on_hand
291
- if any_variants_not_track_inventory?
292
- Float::INFINITY
293
- else
294
- stock_items.sum(:count_on_hand)
295
- end
291
+ @total_on_hand ||= if any_variants_not_track_inventory?
292
+ Float::INFINITY
293
+ else
294
+ stock_items.sum(:count_on_hand)
295
+ end
296
296
  end
297
297
 
298
298
  # Master variant may be deleted (i.e. when the product is deleted)
@@ -303,14 +303,11 @@ module Spree
303
303
  end
304
304
 
305
305
  def brand
306
- taxons.joins(:taxonomy).find_by(spree_taxonomies: { name: Spree.t(:taxonomy_brands_name) })
306
+ @brand ||= taxons.joins(:taxonomy).find_by(spree_taxonomies: { name: Spree.t(:taxonomy_brands_name) })
307
307
  end
308
308
 
309
309
  def category
310
- taxons.joins(:taxonomy).
311
- where(spree_taxonomies: { name: Spree.t(:taxonomy_categories_name) }).
312
- order(depth: :desc).
313
- first
310
+ @category ||= taxons.joins(:taxonomy).order(depth: :desc).find_by(spree_taxonomies: { name: Spree.t(:taxonomy_categories_name) })
314
311
  end
315
312
 
316
313
  private
@@ -411,8 +408,18 @@ module Spree
411
408
  # We call master.default_price here to ensure price is initialized.
412
409
  # Required to avoid Variant#check_price validation failing on create.
413
410
  unless master.default_price && master.valid?
414
- master.errors.each do |att, error|
415
- errors.add(att, error)
411
+ if Rails::VERSION::STRING >= '6.1'
412
+ master.errors.map { |error| { field: error.attribute, message: error&.message } }.each do |err|
413
+ next if err[:field].blank? || err[:message].blank?
414
+
415
+ errors.add(err[:field], err[:message])
416
+ end
417
+ else
418
+ master.errors.messages.each do |field, error|
419
+ next if field.blank? || error.empty?
420
+
421
+ errors.add(field, error.first)
422
+ end
416
423
  end
417
424
  end
418
425
  end
@@ -430,12 +437,12 @@ module Spree
430
437
  end
431
438
 
432
439
  def taxon_and_ancestors
433
- taxons.map(&:self_and_ancestors).flatten.uniq
440
+ @taxon_and_ancestors ||= taxons.map(&:self_and_ancestors).flatten.uniq
434
441
  end
435
442
 
436
443
  # Get the taxonomy ids of all taxons assigned to this product and their ancestors.
437
444
  def taxonomy_ids
438
- taxon_and_ancestors.map(&:taxonomy_id).flatten.uniq
445
+ @taxonomy_ids ||= taxon_and_ancestors.map(&:taxonomy_id).flatten.uniq
439
446
  end
440
447
 
441
448
  # Iterate through this products taxons and taxonomies and touch their timestamps in a batch
@@ -28,6 +28,8 @@ module Spree
28
28
 
29
29
  before_save :normalize_blank_values
30
30
 
31
+ before_validation :normalize_code
32
+
31
33
  scope :coupons, -> { where.not(code: nil) }
32
34
  scope :advertised, -> { where(advertise: true) }
33
35
  scope :applied, lambda {
@@ -192,21 +194,10 @@ module Spree
192
194
  end
193
195
 
194
196
  def used_by?(user, excluded_orders = [])
195
- [
196
- :adjustments,
197
- :line_item_adjustments,
198
- :shipment_adjustments
199
- ].any? do |adjustment_type|
200
- user.orders.complete.joins(adjustment_type).where(
201
- spree_adjustments: {
202
- source_type: 'Spree::PromotionAction',
203
- source_id: actions.map(&:id),
204
- eligible: true
205
- }
206
- ).where.not(
207
- id: excluded_orders.map(&:id)
208
- ).any?
209
- end
197
+ user.orders.complete.joins(:promotions).joins(:all_adjustments).
198
+ where.not(spree_orders: { id: excluded_orders.map(&:id) }).
199
+ where(spree_promotions: { id: id }).
200
+ where(spree_adjustments: { source_type: 'Spree::PromotionAction', eligible: true }).any?
210
201
  end
211
202
 
212
203
  private
@@ -227,6 +218,10 @@ module Spree
227
218
  end
228
219
  end
229
220
 
221
+ def normalize_code
222
+ self.code = code.strip if code.present?
223
+ end
224
+
230
225
  def match_all?
231
226
  match_policy == 'all'
232
227
  end
@@ -31,7 +31,7 @@ module Spree
31
31
  end
32
32
 
33
33
  def actionable?(line_item)
34
- product_id = line_item.product.id
34
+ product_id = line_item.product_id
35
35
  option_values_ids = line_item.variant.option_value_ids
36
36
  eligible_product_ids = preferred_eligible_values.keys
37
37
  eligible_value_ids = preferred_eligible_values[product_id]
@@ -58,7 +58,8 @@ module Spree
58
58
  end
59
59
 
60
60
  def product_ids_string=(s)
61
- self.product_ids = s.to_s.split(',').map(&:strip)
61
+ # check this
62
+ self.product_ids = s
62
63
  end
63
64
  end
64
65
  end