spree_core 4.2.0.rc2 → 4.2.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/spree/base_controller.rb +0 -2
  3. data/app/finders/spree/addresses/find.rb +1 -12
  4. data/app/finders/spree/base_finder.rb +14 -0
  5. data/app/finders/spree/countries/find.rb +11 -3
  6. data/app/finders/spree/credit_cards/find.rb +2 -2
  7. data/app/finders/spree/orders/find_current.rb +1 -1
  8. data/app/helpers/spree/base_helper.rb +1 -7
  9. data/app/mailers/spree/base_mailer.rb +4 -4
  10. data/app/mailers/spree/order_mailer.rb +3 -3
  11. data/app/mailers/spree/reimbursement_mailer.rb +1 -1
  12. data/app/mailers/spree/shipment_mailer.rb +1 -1
  13. data/app/models/concerns/spree/default_price.rb +1 -5
  14. data/app/models/concerns/spree/user_methods.rb +2 -2
  15. data/app/models/spree/ability.rb +2 -6
  16. data/app/models/spree/address.rb +4 -0
  17. data/app/models/spree/app_dependencies.rb +4 -2
  18. data/app/models/spree/base.rb +5 -0
  19. data/app/models/spree/fulfilment_changer.rb +58 -16
  20. data/app/models/spree/inventory_unit.rb +2 -7
  21. data/app/models/spree/line_item.rb +1 -6
  22. data/app/models/spree/order.rb +1 -0
  23. data/app/models/spree/payment.rb +18 -4
  24. data/app/models/spree/payment/processing.rb +2 -2
  25. data/app/models/spree/payment_method.rb +3 -3
  26. data/app/models/spree/price.rb +1 -6
  27. data/app/models/spree/product.rb +12 -2
  28. data/app/models/spree/promotion/rules/product.rb +2 -1
  29. data/app/models/spree/promotion/rules/user.rb +2 -1
  30. data/app/models/spree/refund.rb +2 -2
  31. data/app/models/spree/return_item/eligibility_validator/default.rb +0 -2
  32. data/app/models/spree/return_item/eligibility_validator/{r_m_a_required.rb → rma_required.rb} +0 -0
  33. data/app/models/spree/shipment.rb +1 -1
  34. data/app/models/spree/shipping_method.rb +1 -5
  35. data/app/models/spree/shipping_rate.rb +2 -11
  36. data/app/models/spree/stock/availability_validator.rb +3 -4
  37. data/app/models/spree/stock_item.rb +1 -5
  38. data/app/models/spree/store.rb +24 -0
  39. data/app/models/spree/store_credit.rb +1 -1
  40. data/app/models/spree/variant.rb +1 -8
  41. data/app/models/spree/zone.rb +13 -4
  42. data/app/services/spree/account/addresses/create.rb +6 -1
  43. data/app/services/spree/account/addresses/{base.rb → helper.rb} +1 -3
  44. data/app/services/spree/account/addresses/update.rb +6 -1
  45. data/app/services/spree/compare_line_items.rb +4 -2
  46. data/app/sorters/spree/base_sorter.rb +35 -0
  47. data/app/sorters/spree/orders/sort.rb +1 -37
  48. data/app/sorters/spree/products/sort.rb +9 -32
  49. data/app/validators/email_validator.rb +1 -1
  50. data/config/initializers/inflections.rb +3 -0
  51. data/config/initializers/rails61_fixes.rb +3 -0
  52. data/config/locales/en.yml +25 -8
  53. data/db/migrate/20130326175857_add_stock_location_to_rma.rb +1 -1
  54. data/db/migrate/20201127084048_add_default_country_kind_to_spree_zones.rb +5 -0
  55. data/db/migrate/20210112193440_remove_contact_email_from_spree_stores.rb +5 -0
  56. data/db/migrate/20210114182625_create_spree_payment_methods_stores.rb +10 -0
  57. data/db/migrate/20210114220232_migrate_data_payment_methods_stores.rb +15 -0
  58. data/db/migrate/20210117112551_remove_store_id_from_spree_payment_methods.rb +5 -0
  59. data/lib/spree/core/product_filters.rb +3 -3
  60. data/lib/spree/core/version.rb +1 -1
  61. data/lib/spree/i18n.rb +7 -21
  62. data/lib/spree/permitted_attributes.rb +2 -2
  63. data/lib/spree/service_module.rb +6 -2
  64. data/lib/spree/testing_support/capybara_config.rb +1 -1
  65. data/lib/spree/testing_support/factories/shipment_factory.rb +7 -9
  66. data/lib/spree/testing_support/factories/zone_factory.rb +16 -13
  67. data/lib/spree/testing_support/order_walkthrough.rb +8 -3
  68. data/lib/spree/testing_support/rspec_retry_config.rb +10 -0
  69. data/spree_core.gemspec +4 -3
  70. metadata +55 -21
  71. data/lib/spree/i18n/base.rb +0 -17
  72. data/lib/spree/i18n/initializer.rb +0 -1
@@ -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) }
@@ -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 @@ 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
@@ -411,8 +411,18 @@ module Spree
411
411
  # We call master.default_price here to ensure price is initialized.
412
412
  # Required to avoid Variant#check_price validation failing on create.
413
413
  unless master.default_price && master.valid?
414
- master.errors.each do |att, error|
415
- errors.add(att, error)
414
+ if Rails::VERSION::STRING >= '6.1'
415
+ master.errors.map { |error| { field: error.attribute, message: error&.message } }.each do |err|
416
+ next if err[:field].blank? || err[:message].blank?
417
+
418
+ errors.add(err[:field], err[:message])
419
+ end
420
+ else
421
+ master.errors.messages.each do |field, error|
422
+ next if field.blank? || error.empty?
423
+
424
+ errors.add(field, error.first)
425
+ end
416
426
  end
417
427
  end
418
428
  end
@@ -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
@@ -22,7 +22,8 @@ module Spree
22
22
  end
23
23
 
24
24
  def user_ids_string=(s)
25
- self.user_ids = s.to_s.split(',').map(&:strip)
25
+ # check this
26
+ self.user_ids = s
26
27
  end
27
28
  end
28
29
  end
@@ -61,14 +61,14 @@ module Spree
61
61
  end
62
62
 
63
63
  unless response.success?
64
- logger.error(Spree.t(:gateway_error) + " #{response.to_yaml}")
64
+ Rails.logger.error(Spree.t(:gateway_error) + " #{response.to_yaml}")
65
65
  text = response.params['message'] || response.params['response_reason_text'] || response.message
66
66
  raise Core::GatewayError, text
67
67
  end
68
68
 
69
69
  response
70
70
  rescue ActiveMerchant::ConnectionError => e
71
- logger.error(Spree.t(:gateway_error) + " #{e.inspect}")
71
+ Rails.logger.error(Spree.t(:gateway_error) + " #{e.inspect}")
72
72
  raise Core::GatewayError, Spree.t(:unable_to_connect_to_gateway)
73
73
  end
74
74
 
@@ -1,5 +1,3 @@
1
- require_relative 'r_m_a_required'
2
-
3
1
  module Spree
4
2
  class ReturnItem::EligibilityValidator::Default < Spree::ReturnItem::EligibilityValidator::BaseValidator
5
3
  class_attribute :permitted_eligibility_validators
@@ -362,7 +362,7 @@ module Spree
362
362
  desired_shipment: shipment_to_transfer_to,
363
363
  variant: variant,
364
364
  quantity: quantity
365
- ).run!
365
+ )
366
366
  end
367
367
 
368
368
  private
@@ -19,7 +19,7 @@ module Spree
19
19
  foreign_key: 'shipping_method_id'
20
20
  has_many :zones, through: :shipping_method_zones, class_name: 'Spree::Zone'
21
21
 
22
- belongs_to :tax_category, class_name: 'Spree::TaxCategory', optional: true
22
+ belongs_to :tax_category, -> { with_deleted }, class_name: 'Spree::TaxCategory', optional: true
23
23
 
24
24
  validates :name, :display_on, presence: true
25
25
 
@@ -44,10 +44,6 @@ module Spree
44
44
  select { |c| c.to_s.constantize < Spree::ShippingCalculator }
45
45
  end
46
46
 
47
- def tax_category
48
- Spree::TaxCategory.unscoped { super }
49
- end
50
-
51
47
  def available_to_display?(display_filter)
52
48
  (frontend? && display_filter == DISPLAY_ON_FRONT_END) ||
53
49
  (backend? && display_filter == DISPLAY_ON_BACK_END)
@@ -1,9 +1,8 @@
1
1
  module Spree
2
2
  class ShippingRate < Spree::Base
3
3
  belongs_to :shipment, class_name: 'Spree::Shipment'
4
- belongs_to :tax_rate, class_name: 'Spree::TaxRate'
5
- belongs_to :shipping_method, class_name: 'Spree::ShippingMethod', inverse_of: :shipping_rates
6
-
4
+ belongs_to :tax_rate, -> { with_deleted }, class_name: 'Spree::TaxRate'
5
+ belongs_to :shipping_method, -> { with_deleted }, class_name: 'Spree::ShippingMethod', inverse_of: :shipping_rates
7
6
  extend Spree::DisplayMoney
8
7
 
9
8
  money_methods :base_price, :final_price, :tax_amount
@@ -32,14 +31,6 @@ module Spree
32
31
  @tax_amount ||= tax_rate&.calculator&.compute_shipping_rate(self) || BigDecimal(0)
33
32
  end
34
33
 
35
- def shipping_method
36
- Spree::ShippingMethod.unscoped { super }
37
- end
38
-
39
- def tax_rate
40
- Spree::TaxRate.unscoped { super }
41
- end
42
-
43
34
  # returns base price - any available discounts for this Shipment
44
35
  # useful when you want to present a list of available shipping rates
45
36
  def final_price
@@ -14,10 +14,9 @@ module Spree
14
14
  display_name = variant.name.to_s
15
15
  display_name += " (#{variant.options_text})" unless variant.options_text.blank?
16
16
 
17
- line_item.errors[:quantity] << Spree.t(
18
- :selected_quantity_not_available,
19
- item: display_name.inspect
20
- )
17
+ line_item.errors.add(:quantity,
18
+ :selected_quantity_not_available,
19
+ message: Spree.t(:selected_quantity_not_available, item: display_name.inspect))
21
20
  end
22
21
 
23
22
  private
@@ -4,7 +4,7 @@ module Spree
4
4
 
5
5
  with_options inverse_of: :stock_items do
6
6
  belongs_to :stock_location, class_name: 'Spree::StockLocation'
7
- belongs_to :variant, class_name: 'Spree::Variant'
7
+ belongs_to :variant, -> { with_deleted }, class_name: 'Spree::Variant'
8
8
  end
9
9
  has_many :stock_movements, inverse_of: :stock_item
10
10
 
@@ -56,10 +56,6 @@ module Spree
56
56
  in_stock? || backorderable?
57
57
  end
58
58
 
59
- def variant
60
- Spree::Variant.unscoped { super }
61
- end
62
-
63
59
  def reduce_count_on_hand_to_zero
64
60
  set_count_on_hand(0) if count_on_hand > 0
65
61
  end
@@ -30,6 +30,8 @@ module Spree
30
30
 
31
31
  after_commit :clear_cache
32
32
 
33
+ alias_attribute :contact_email, :customer_support_email
34
+
33
35
  def self.current(domain = nil)
34
36
  current_store = domain ? Store.by_url(domain).first : nil
35
37
  current_store || Store.default
@@ -51,6 +53,28 @@ module Spree
51
53
  "#{name} (#{code})"
52
54
  end
53
55
 
56
+ def formatted_url
57
+ return if url.blank?
58
+
59
+ if url.match(/http:\/\/|https:\/\//)
60
+ url
61
+ else
62
+ "https://#{url}"
63
+ end
64
+ end
65
+
66
+ def countries_available_for_checkout
67
+ checkout_zone_or_default.try(:country_list) || Spree::Country.all
68
+ end
69
+
70
+ def states_available_for_checkout(country)
71
+ checkout_zone_or_default.try(:state_list_for, country) || country.states
72
+ end
73
+
74
+ def checkout_zone_or_default
75
+ checkout_zone || Spree::Zone.default_checkout_zone
76
+ end
77
+
54
78
  private
55
79
 
56
80
  def ensure_default_exists_and_is_unique
@@ -68,7 +68,7 @@ module Spree
68
68
  end
69
69
 
70
70
  def validate_authorization(amount, order_currency)
71
- if amount_remaining.to_d < amount.to_d
71
+ if BigDecimal(amount_remaining, 3) < BigDecimal(amount, 3)
72
72
  errors.add(:base, Spree.t('store_credit_payment_method.insufficient_funds'))
73
73
  elsif currency != order_currency
74
74
  errors.add(:base, Spree.t('store_credit_payment_method.currency_mismatch'))
@@ -3,7 +3,7 @@ module Spree
3
3
  acts_as_paranoid
4
4
  acts_as_list scope: :product
5
5
 
6
- belongs_to :product, touch: true, class_name: 'Spree::Product', inverse_of: :variants
6
+ belongs_to :product, -> { with_deleted }, touch: true, class_name: 'Spree::Product', inverse_of: :variants
7
7
  belongs_to :tax_category, class_name: 'Spree::TaxCategory', optional: true
8
8
 
9
9
  delegate :name, :name=, :description, :slug, :available_on, :shipping_category_id,
@@ -150,13 +150,6 @@ module Spree
150
150
  !!deleted_at
151
151
  end
152
152
 
153
- # Product may be created with deleted_at already set,
154
- # which would make AR's default finder return nil.
155
- # This is a stopgap for that little problem.
156
- def product
157
- Spree::Product.unscoped { super }
158
- end
159
-
160
153
  def options=(options = {})
161
154
  options.each do |option|
162
155
  set_option_value(option[:name], option[:value])
@@ -101,8 +101,6 @@ module Spree
101
101
  zone_member.zoneable_id == address.country_id
102
102
  when 'Spree::State'
103
103
  zone_member.zoneable_id == address.state_id
104
- else
105
- false
106
104
  end
107
105
  end
108
106
  end
@@ -114,8 +112,6 @@ module Spree
114
112
  zoneables
115
113
  when 'state' then
116
114
  zoneables.collect(&:country)
117
- else
118
- []
119
115
  end.flatten.compact.uniq
120
116
  end
121
117
 
@@ -171,6 +167,19 @@ module Spree
171
167
  true
172
168
  end
173
169
 
170
+ def state_list
171
+ case kind
172
+ when 'country'
173
+ zoneables.map(&:states)
174
+ when 'state'
175
+ zoneables
176
+ end.flatten.compact.uniq
177
+ end
178
+
179
+ def state_list_for(country)
180
+ state_list.select { |state| state.country == country }
181
+ end
182
+
174
183
  private
175
184
 
176
185
  def remove_defunct_members
@@ -1,7 +1,12 @@
1
1
  module Spree
2
2
  module Account
3
3
  module Addresses
4
- class Create < ::Spree::Account::Addresses::Base
4
+ class Create
5
+ prepend Spree::ServiceModule::Base
6
+ include Spree::Account::Addresses::Helper
7
+
8
+ attr_accessor :country
9
+
5
10
  def call(user:, address_params:)
6
11
  fill_country_and_state_ids(address_params)
7
12
 
@@ -1,9 +1,7 @@
1
1
  module Spree
2
2
  module Account
3
3
  module Addresses
4
- class Base
5
- prepend Spree::ServiceModule::Base
6
-
4
+ module Helper
7
5
  private
8
6
 
9
7
  attr_accessor :country
@@ -1,7 +1,12 @@
1
1
  module Spree
2
2
  module Account
3
3
  module Addresses
4
- class Update < ::Spree::Account::Addresses::Base
4
+ class Update
5
+ prepend Spree::ServiceModule::Base
6
+ include Spree::Account::Addresses::Helper
7
+
8
+ attr_accessor :country
9
+
5
10
  def call(address:, address_params:)
6
11
  address_params[:country_id] ||= address.country_id
7
12
  fill_country_and_state_ids(address_params)
@@ -1,9 +1,11 @@
1
1
  # This class should be refactored
2
2
  module Spree
3
3
  class CompareLineItems
4
- prepend Spree::ServiceModule:: Base
4
+ prepend Spree::ServiceModule::Base
5
+
6
+ def call(order:, line_item:, options: {}, comparison_hooks: nil)
7
+ comparison_hooks ||= Rails.application.config.spree.line_item_comparison_hooks
5
8
 
6
- def call(order:, line_item:, options: {}, comparison_hooks: Rails.application.config.spree.line_item_comparison_hooks)
7
9
  legacy_part = comparison_hooks.all? do |hook|
8
10
  order.send(hook, line_item, options)
9
11
  end
@@ -0,0 +1,35 @@
1
+ module Spree
2
+ class BaseSorter
3
+ def initialize(scope, params = {}, allowed_sort_attributes = [])
4
+ @scope = scope
5
+ @sort = params[:sort]
6
+ @allowed_sort_attributes = allowed_sort_attributes
7
+ end
8
+
9
+ def call
10
+ by_param_attribute(scope)
11
+ end
12
+
13
+ protected
14
+
15
+ attr_reader :scope, :collection, :sort, :allowed_sort_attributes
16
+
17
+ def by_param_attribute(scope)
18
+ return scope if sort_field.blank? || !allowed_sort_attributes.include?(sort_field.to_sym)
19
+
20
+ scope.order("#{sort_field}": order_direction)
21
+ end
22
+
23
+ def desc_order
24
+ @desc_order ||= String(sort)[0] == '-'
25
+ end
26
+
27
+ def sort_field
28
+ @sort_field ||= desc_order ? sort[1..-1] : sort
29
+ end
30
+
31
+ def order_direction
32
+ desc_order ? :desc : :asc
33
+ end
34
+ end
35
+ end