solidus_core 3.1.9 → 3.2.0.alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/spree/products_helper.rb +1 -1
  3. data/app/models/concerns/spree/active_storage_adapter/attachment.rb +23 -10
  4. data/app/models/concerns/spree/active_storage_adapter.rb +1 -1
  5. data/app/models/concerns/spree/default_price.rb +28 -4
  6. data/app/models/concerns/spree/user_address_book.rb +11 -1
  7. data/app/models/spree/adjustment.rb +1 -0
  8. data/app/models/spree/carton.rb +1 -1
  9. data/app/models/spree/option_value.rb +9 -0
  10. data/app/models/spree/order.rb +68 -29
  11. data/app/models/spree/order_contents.rb +2 -1
  12. data/app/models/spree/order_inventory.rb +1 -1
  13. data/app/models/spree/order_merger.rb +2 -2
  14. data/app/models/spree/order_taxation.rb +6 -4
  15. data/app/models/spree/order_updater.rb +4 -3
  16. data/app/models/spree/payment_method.rb +11 -0
  17. data/app/models/spree/price.rb +1 -1
  18. data/app/models/spree/product/scopes.rb +21 -3
  19. data/app/models/spree/product.rb +1 -1
  20. data/app/models/spree/promotion/actions/create_adjustment.rb +4 -0
  21. data/app/models/spree/promotion/actions/create_item_adjustments.rb +5 -6
  22. data/app/models/spree/promotion/rules/product.rb +20 -8
  23. data/app/models/spree/promotion/rules/store.rb +4 -0
  24. data/app/models/spree/promotion/rules/taxon.rb +4 -0
  25. data/app/models/spree/promotion/rules/user.rb +4 -0
  26. data/app/models/spree/promotion.rb +34 -23
  27. data/app/models/spree/promotion_action.rb +4 -0
  28. data/app/models/spree/promotion_code.rb +8 -4
  29. data/app/models/spree/promotion_handler/cart.rb +26 -6
  30. data/app/models/spree/promotion_rule.rb +5 -0
  31. data/app/models/spree/reimbursement.rb +2 -2
  32. data/app/models/spree/return_item.rb +1 -2
  33. data/app/models/spree/stock/allocator/on_hand_first.rb +2 -2
  34. data/app/models/spree/stock/quantifier.rb +12 -8
  35. data/app/models/spree/stock/simple_coordinator.rb +2 -1
  36. data/app/models/spree/tax/item_tax.rb +3 -2
  37. data/app/models/spree/tax/order_tax.rb +3 -1
  38. data/app/models/spree/tax/tax_location.rb +4 -7
  39. data/app/models/spree/tax_rate.rb +2 -0
  40. data/app/models/spree/variant/price_selector.rb +1 -18
  41. data/app/models/spree/variant.rb +2 -2
  42. data/app/subscribers/spree/mailer_subscriber.rb +4 -0
  43. data/app/subscribers/spree/order_mailer_subscriber.rb +35 -0
  44. data/config/locales/en.yml +7 -253
  45. data/db/migrate/20201127212108_add_type_before_removal_to_spree_payment_methods.rb +7 -0
  46. data/db/migrate/20220317165036_set_promotions_with_any_policy_to_all_if_possible.rb +20 -0
  47. data/lib/generators/solidus/install/install_generator/bundler_context.rb +97 -0
  48. data/lib/generators/solidus/install/install_generator/install_frontend.rb +50 -0
  49. data/lib/generators/solidus/install/install_generator/support_solidus_frontend_extraction.rb +48 -0
  50. data/lib/generators/solidus/install/install_generator.rb +56 -49
  51. data/lib/generators/solidus/install/templates/config/initializers/spree.rb.tt +6 -16
  52. data/lib/generators/solidus/install/templates/vendor/assets/javascripts/spree/backend/all.js +2 -2
  53. data/lib/spree/app_configuration.rb +29 -3
  54. data/lib/spree/bus.rb +20 -0
  55. data/lib/spree/core/controller_helpers/auth.rb +9 -1
  56. data/lib/spree/core/controller_helpers/current_host.rb +1 -3
  57. data/lib/spree/core/controller_helpers/order.rb +10 -10
  58. data/lib/spree/core/controller_helpers/search.rb +1 -1
  59. data/lib/spree/core/engine.rb +33 -8
  60. data/lib/spree/core/state_machines/order.rb +1 -1
  61. data/lib/spree/core/stock_configuration.rb +18 -0
  62. data/lib/spree/core/validators/email.rb +3 -1
  63. data/lib/spree/core/version.rb +1 -1
  64. data/lib/spree/core.rb +20 -0
  65. data/lib/spree/event/subscriber_registry.rb +4 -6
  66. data/lib/spree/event.rb +1 -1
  67. data/lib/spree/migrations.rb +1 -1
  68. data/lib/spree/permission_sets/default_customer.rb +8 -1
  69. data/lib/spree/permitted_attributes.rb +4 -4
  70. data/lib/spree/preferences/configuration.rb +34 -12
  71. data/lib/spree/preferences/preferable.rb +0 -5
  72. data/lib/spree/preferences/preferable_class_methods.rb +3 -3
  73. data/lib/spree/preferences/preference_differentiator.rb +2 -1
  74. data/lib/spree/preferences/static_model_preferences.rb +0 -2
  75. data/lib/spree/rails_compatibility.rb +99 -0
  76. data/lib/spree/testing_support/bus_helpers.rb +101 -0
  77. data/lib/spree/testing_support/common_rake.rb +47 -19
  78. data/lib/spree/testing_support/dummy_app/assets/javascripts/spree/backend/all.js +1 -1
  79. data/lib/spree/testing_support/dummy_app/assets/javascripts/spree/frontend/all.js +1 -1
  80. data/lib/spree/testing_support/dummy_app.rb +6 -2
  81. data/lib/spree/testing_support/factories/address_factory.rb +7 -2
  82. data/lib/spree/testing_support/factories/inventory_unit_factory.rb +1 -1
  83. data/lib/spree/testing_support/factories/order_factory.rb +8 -4
  84. data/lib/spree/testing_support/factories/product_factory.rb +4 -1
  85. data/lib/spree/testing_support/factories/store_credit_factory.rb +4 -4
  86. data/lib/spree/testing_support/factory_bot.rb +1 -1
  87. data/lib/spree/testing_support/order_walkthrough.rb +5 -4
  88. data/lib/spree/testing_support/silence_deprecations.rb +9 -0
  89. data/lib/tasks/payment_method.rake +29 -0
  90. data/lib/tasks/solidus/delete_prices_with_nil_amount.rake +2 -2
  91. data/lib/tasks/solidus/split_promotions_with_any_match_policy.rake +33 -0
  92. data/solidus_core.gemspec +6 -2
  93. metadata +71 -26
  94. data/lib/generators/solidus/install/templates/vendor/assets/javascripts/spree/frontend/all.js +0 -10
  95. data/lib/generators/solidus/install/templates/vendor/assets/stylesheets/spree/frontend/all.css +0 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd88c98f5da37d9a89e981aad39979998349f0e2405a4a7095a8f75f4d3839f8
4
- data.tar.gz: 656beea8141300d09b62b4970dccd7691556112597a891a4f0d1821a67914ea3
3
+ metadata.gz: b1b866f15d9df0394383e7f634858ee99f21ed214e8fae6928af514a6421ddbc
4
+ data.tar.gz: d2f5c689bf6debe86f5b9be575eea7640e496606f8933b85a1d2e7a2cb90123c
5
5
  SHA512:
6
- metadata.gz: 44d04ac1151fd4f7f2ac20b7f117e500b76be1d39fd2ad5ef72654dca8749bd9dd42eb9acd402adf519d2769d7099b8d44977ccf0a906089c10315675b22cad1
7
- data.tar.gz: 93ff18fdf9856b60aec7f484bd468db70c67bd9e446e7fbedf383ff88f21f59fb261d0c53b7db1f46c0a8848f133fb032258ae7d57c968d485503abc248fb606
6
+ metadata.gz: df2acde7ab4aa4b01e3d5b187b6c47a911714c868237a1ba494095a43bdd07bac5082e2080d4aabc563576d502fecda0d28a94b9cef53db8e6c1e1c89a0cbc97
7
+ data.tar.gz: c183f6200f52b585a4ae391bd8b412c6a4f58e987fcc6ceb3cd1cf6835b92b1019f6077e4a13c75dbe6a4c0dd64c81fe7c4d8d3deeed2b8fbadc67ed74148cb5
@@ -68,7 +68,7 @@ module Spree
68
68
  # @return [String] a cache invalidation key for products
69
69
  def cache_key_for_products
70
70
  count = @products.count
71
- max_updated_at = (@products.maximum(:updated_at) || Date.today).to_s(:number)
71
+ max_updated_at = Spree::RailsCompatibility.to_fs((@products.maximum(:updated_at) || Date.today), :number)
72
72
  "#{I18n.locale}/#{current_pricing_options.cache_key}/spree/products/all-#{params[:page]}-#{max_updated_at}-#{count}"
73
73
  end
74
74
  end
@@ -4,14 +4,16 @@ require 'mini_magick'
4
4
 
5
5
  module Spree
6
6
  module ActiveStorageAdapter
7
- # Decorares AtiveStorage attachment to add methods exptected by Solidus'
7
+ # Decorates ActiveStorage attachment to add methods expected by Solidus'
8
8
  # Paperclip-oriented attachment support.
9
9
  class Attachment
10
10
  delegate_missing_to :@attachment
11
11
 
12
+ attr_reader :attachment
13
+
12
14
  def initialize(attachment, styles: {})
13
15
  @attachment = attachment
14
- @styles = normalize_styles(styles)
16
+ @transformations = styles_to_transformations(styles)
15
17
  end
16
18
 
17
19
  def exists?
@@ -27,13 +29,13 @@ module Spree
27
29
  end
28
30
 
29
31
  def variant(style = nil)
30
- size = style_to_size(style)
31
- @attachment.variant(
32
- resize_to_limit: size,
32
+ transformation = @transformations[style] || default_transformation(width, height)
33
+
34
+ @attachment.variant({
33
35
  saver: {
34
36
  strip: true
35
37
  }
36
- ).processed
38
+ }.merge(transformation)).processed
37
39
  end
38
40
 
39
41
  def height
@@ -59,12 +61,23 @@ module Spree
59
61
  @attachment.metadata
60
62
  end
61
63
 
62
- def normalize_styles(styles)
63
- styles.transform_values { |v| v.split('x').map(&:to_i) }
64
+ def styles_to_transformations(styles)
65
+ styles.transform_values(&method(:imagemagick_to_image_processing_definition))
66
+ end
67
+
68
+ def imagemagick_to_image_processing_definition(definition)
69
+ width_height = definition.split('x').map(&:to_i)
70
+
71
+ case definition[-1].to_sym
72
+ when :^
73
+ { resize_to_fill: width_height }
74
+ else
75
+ default_transformation(*width_height)
76
+ end
64
77
  end
65
78
 
66
- def style_to_size(style)
67
- @styles.fetch(style&.to_sym) { [width, height] }
79
+ def default_transformation(width, height)
80
+ { resize_to_limit: [width, height] }
68
81
  end
69
82
  end
70
83
  end
@@ -10,7 +10,7 @@ module Spree
10
10
  included do
11
11
  next if Rails.gem_version >= Gem::Version.new('6.1.0.alpha')
12
12
 
13
- abort <<~MESSAGE
13
+ raise <<~MESSAGE
14
14
  Configuration Error: Solidus ActiveStorage attachment adpater requires Rails >= 6.1.0.
15
15
 
16
16
  Spree::Config.image_attachment_module preference is set to #{Spree::Config.image_attachment_module}
@@ -16,12 +16,10 @@ module Spree
16
16
 
17
17
  # Returns `#prices` prioritized for being considered as default price
18
18
  #
19
- # @deprecated
20
19
  # @return [ActiveRecord::Relation<Spree::Price>]
21
20
  def currently_valid_prices
22
21
  prices.currently_valid
23
22
  end
24
- deprecate :currently_valid_prices, deprecator: Spree::Deprecation
25
23
 
26
24
  # Returns {#default_price} or builds it from {Spree::Variant.default_price_attributes}
27
25
  #
@@ -35,7 +33,7 @@ module Spree
35
33
  # Select from {#prices} the one to be considered as the default
36
34
  #
37
35
  # This method works with the in-memory association, so non-persisted prices
38
- # are taken into account.
36
+ # are taken into account. Discarded prices are also considered.
39
37
  #
40
38
  # A price is a candidate to be considered as the default when it meets
41
39
  # {Spree::Variant.default_price_attributes} criteria. When more than one candidate is
@@ -46,11 +44,37 @@ module Spree
46
44
  # @return [Spree::Price, nil]
47
45
  # @see Spree::Variant.default_price_attributes
48
46
  def default_price
49
- price_selector.price_for_options(Spree::Config.default_pricing_options)
47
+ prioritized_default(
48
+ prices_meeting_criteria_to_be_default(
49
+ (prices + prices.with_discarded).uniq
50
+ )
51
+ )
50
52
  end
51
53
 
52
54
  def has_default_price?
53
55
  default_price.present? && !default_price.discarded?
54
56
  end
57
+
58
+ private
59
+
60
+ def prices_meeting_criteria_to_be_default(prices)
61
+ criteria = self.class.default_price_attributes.transform_keys(&:to_s)
62
+ prices.select do |price|
63
+ contender = price.attributes.slice(*criteria.keys)
64
+ criteria == contender
65
+ end
66
+ end
67
+
68
+ def prioritized_default(prices)
69
+ prices.min do |prev, succ|
70
+ contender_one, contender_two = [succ, prev].map do |item|
71
+ [
72
+ item.updated_at || Time.zone.now,
73
+ item.id || Float::INFINITY
74
+ ]
75
+ end
76
+ contender_one <=> contender_two
77
+ end
78
+ end
55
79
  end
56
80
  end
@@ -37,6 +37,9 @@ module Spree
37
37
 
38
38
  has_one :default_user_ship_address, ->{ default_shipping }, class_name: 'Spree::UserAddress', foreign_key: 'user_id'
39
39
  has_one :ship_address, through: :default_user_ship_address, source: :address
40
+
41
+ accepts_nested_attributes_for :ship_address
42
+ accepts_nested_attributes_for :bill_address
40
43
  end
41
44
 
42
45
  # saves address in address book
@@ -104,12 +107,19 @@ module Spree
104
107
  return new_address unless new_address.valid?
105
108
 
106
109
  first_one = user_addresses.empty?
110
+ user_address = prepare_user_address(new_address)
107
111
 
108
112
  if address_attributes[:id].present? && new_address.id != address_attributes[:id]
113
+ if ship_address&.id == address_attributes[:id].to_i
114
+ user_addresses.mark_default(user_address, address_type: :shipping)
115
+ end
116
+
117
+ if bill_address&.id == address_attributes[:id].to_i
118
+ user_addresses.mark_default(user_address, address_type: :billing)
119
+ end
109
120
  remove_from_address_book(address_attributes[:id])
110
121
  end
111
122
 
112
- user_address = prepare_user_address(new_address)
113
123
  user_addresses.mark_default(user_address, address_type: address_type) if default || first_one
114
124
 
115
125
  if persisted?
@@ -62,6 +62,7 @@ module Spree
62
62
  .distinct
63
63
  exclude_canceled ? result.merge(Spree::Order.not_canceled) : result
64
64
  end
65
+ deprecate :in_completed_orders, "Please don't use this and rather go through Spree::Promotion#discounted_orders"
65
66
 
66
67
  def finalize!
67
68
  update!(finalized: true)
@@ -42,7 +42,7 @@ class Spree::Carton < Spree::Base
42
42
  end
43
43
 
44
44
  def display_shipped_at
45
- shipped_at.to_s(:rfc822)
45
+ Spree::RailsCompatibility.to_fs(shipped_at, :rfc822)
46
46
  end
47
47
 
48
48
  def manifest
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Spree
4
4
  class OptionValue < Spree::Base
5
+ # TODO: Remove optional on Solidus v4.0. Don't forget adding a migration to
6
+ # enforce at the database layer
5
7
  belongs_to :option_type, class_name: 'Spree::OptionType', inverse_of: :option_values, optional: true
6
8
  acts_as_list scope: :option_type
7
9
 
@@ -13,7 +15,14 @@ module Spree
13
15
 
14
16
  after_save :touch, if: :saved_changes?
15
17
  after_touch :touch_all_variants
18
+ after_save do
19
+ Spree::Deprecation.warn <<~MSG if option_type.nil?
20
+ Having an option_value with no associated option_type will be deprecated
21
+ on Solidus v4.0
22
+ MSG
23
+ end
16
24
 
25
+ # TODO: Remove allow_nil once option_type is required on Solidus v4.0
17
26
  delegate :name, :presentation, to: :option_type, prefix: :option_type, allow_nil: true
18
27
 
19
28
  self.whitelisted_ransackable_attributes = %w[name presentation]
@@ -38,9 +38,21 @@ module Spree
38
38
  class CannotRebuildShipments < StandardError; end
39
39
 
40
40
  extend Spree::DisplayMoney
41
- money_methods :outstanding_balance, :item_total, :adjustment_total,
42
- :included_tax_total, :additional_tax_total, :tax_total,
43
- :shipment_total, :total, :order_total_after_store_credit, :total_available_store_credit
41
+ money_methods(
42
+ :outstanding_balance,
43
+ :item_total,
44
+ :adjustment_total,
45
+ :included_tax_total,
46
+ :additional_tax_total,
47
+ :tax_total,
48
+ :shipment_total,
49
+ :total,
50
+ :order_total_after_store_credit,
51
+ :total_available_store_credit,
52
+ :item_total_before_tax,
53
+ :shipment_total_before_tax,
54
+ :item_total_excluding_vat
55
+ )
44
56
  alias :display_ship_total :display_shipment_total
45
57
 
46
58
  checkout_flow do
@@ -102,7 +114,7 @@ module Spree
102
114
  # Returns
103
115
  has_many :return_authorizations, dependent: :destroy, inverse_of: :order
104
116
  has_many :return_items, through: :inventory_units
105
- has_many :customer_returns, through: :return_items
117
+ has_many :customer_returns, -> { distinct }, through: :return_items
106
118
  has_many :reimbursements, inverse_of: :order
107
119
  has_many :refunds, through: :payments
108
120
 
@@ -195,6 +207,10 @@ module Spree
195
207
  line_items.to_a.sum(&:total_before_tax)
196
208
  end
197
209
 
210
+ def shipment_total_before_tax
211
+ shipments.to_a.sum(&:total_before_tax)
212
+ end
213
+
198
214
  # Sum of all line item amounts pre-tax
199
215
  def item_total_excluding_vat
200
216
  line_items.to_a.sum(&:total_excluding_vat)
@@ -239,7 +255,7 @@ module Spree
239
255
  ship_address
240
256
  else
241
257
  bill_address
242
- end || store.default_cart_tax_location
258
+ end || store&.default_cart_tax_location
243
259
  end
244
260
 
245
261
  def updater
@@ -379,25 +395,16 @@ module Spree
379
395
  Spree::CreditCard.where(id: credit_card_ids)
380
396
  end
381
397
 
382
- # Finalizes an in progress order after checkout is complete.
383
- # Called after transition to complete state when payments will have been processed
398
+ # TODO: Remove on Solidus 4.0
399
+ # @api private
384
400
  def finalize!
385
- # lock all adjustments (coupon promotions, etc.)
386
- all_adjustments.each(&:finalize!)
387
-
388
- # update payment and shipment(s) states, and save
389
- updater.update_payment_state
390
- shipments.each do |shipment|
391
- shipment.update_state
392
- shipment.finalize!
393
- end
394
-
395
- updater.update_shipment_state
396
- save!
397
-
398
- touch :completed_at
399
-
400
- Spree::Event.fire 'order_finalized', order: self
401
+ Spree::Deprecation.warn <<~MSG
402
+ Calling `Spree::Order#finalize!` is discouraged. Instead, use
403
+ `Spree::Order#complete!`, which goes through all the needed safety
404
+ checks before finalizing an order. This method will be removed
405
+ altogether on Solidus 4.0.
406
+ MSG
407
+ finalize
401
408
  end
402
409
 
403
410
  def fulfill!
@@ -495,7 +502,8 @@ module Spree
495
502
  end
496
503
 
497
504
  def create_shipments_for_line_item(line_item)
498
- units = Spree::Stock::InventoryUnitBuilder.new(self).missing_units_for_line_item(line_item)
505
+ units = Spree::Config.stock.inventory_unit_builder_class.new(self).missing_units_for_line_item(line_item)
506
+
499
507
  Spree::Config.stock.coordinator_class.new(self, units).shipments.each do |shipment|
500
508
  shipments << shipment
501
509
  end
@@ -526,7 +534,7 @@ module Spree
526
534
  state: 'cart',
527
535
  updated_at: Time.current
528
536
  )
529
- next! if !line_items.empty?
537
+ self.next
530
538
  end
531
539
 
532
540
  def refresh_shipment_rates
@@ -741,6 +749,27 @@ module Spree
741
749
  end
742
750
  end
743
751
 
752
+ # Finalizes an in progress order after checkout is complete.
753
+ # Called after transition to complete state when payments will have been processed
754
+ def finalize
755
+ # lock all adjustments (coupon promotions, etc.)
756
+ all_adjustments.each(&:finalize!)
757
+
758
+ # update payment and shipment(s) states, and save
759
+ updater.update_payment_state
760
+ shipments.each do |shipment|
761
+ shipment.update_state
762
+ shipment.finalize!
763
+ end
764
+
765
+ updater.update_shipment_state
766
+ save!
767
+
768
+ touch :completed_at
769
+
770
+ Spree::Bus.publish :order_finalized, order: self
771
+ end
772
+
744
773
  def associate_store
745
774
  self.store ||= Spree::Store.default
746
775
  end
@@ -761,9 +790,12 @@ module Spree
761
790
 
762
791
  def ensure_inventory_units
763
792
  if has_checkout_step?("delivery")
764
- inventory_validator = Spree::Stock::InventoryValidator.new
793
+ inventory_validator = Spree::Config.stock.inventory_validator_class.new
794
+
795
+ errors = line_items.map { |line_item|
796
+ inventory_validator.validate(line_item)
797
+ }.compact
765
798
 
766
- errors = line_items.map { |line_item| inventory_validator.validate(line_item) }.compact
767
799
  raise InsufficientStock if errors.any?
768
800
  end
769
801
  end
@@ -781,8 +813,15 @@ module Spree
781
813
  end
782
814
 
783
815
  def validate_line_item_availability
784
- availability_validator = Spree::Stock::AvailabilityValidator.new
785
- raise InsufficientStock unless line_items.all? { |line_item| availability_validator.validate(line_item) }
816
+ availability_validator = Spree::Config.stock.availability_validator_class.new
817
+
818
+ # NOTE: This code assumes that the availability validator will return
819
+ # true for success and false for failure. This is not normally the
820
+ # behaviour of validators, as the framework only cares about the
821
+ # population of the errors, not the return value of the validate method.
822
+ raise InsufficientStock unless line_items.all? { |line_item|
823
+ availability_validator.validate(line_item)
824
+ }
786
825
  end
787
826
 
788
827
  def ensure_line_items_present
@@ -42,8 +42,8 @@ module Spree
42
42
  # If we do not update first, then the item total will be wrong and ItemTotal
43
43
  # promotion rules would not be triggered.
44
44
  reload_totals
45
- PromotionHandler::Cart.new(order).activate
46
45
  order.ensure_updated_shipments
46
+ PromotionHandler::Cart.new(order).activate
47
47
  end
48
48
  reload_totals
49
49
  true
@@ -89,6 +89,7 @@ module Spree
89
89
  line_item ||= order.line_items.new(
90
90
  quantity: 0,
91
91
  variant: variant,
92
+ adjustments: [],
92
93
  )
93
94
 
94
95
  line_item.quantity += quantity.to_i
@@ -62,7 +62,7 @@ module Spree
62
62
  potential_shipments.detect do |shipment|
63
63
  shipment.include?(variant)
64
64
  end || potential_shipments.detect do |shipment|
65
- stock_item = shipment.stock_location.stock_item(variant.id)
65
+ stock_item = variant.stock_items.detect { |stock_item| stock_item.stock_location == shipment.stock_location }
66
66
  if stock_item
67
67
  stock_item.backorderable? || stock_item.count_on_hand >= quantity
68
68
  end
@@ -115,8 +115,8 @@ module Spree
115
115
  current_line_item.quantity += other_order_line_item.quantity
116
116
  handle_error(current_line_item) unless current_line_item.save
117
117
  else
118
- order.line_items << other_order_line_item
119
- handle_error(other_order_line_item) unless other_order_line_item.save
118
+ new_line_item = order.line_items.build(other_order_line_item.attributes.except("id"))
119
+ handle_error(new_line_item) unless new_line_item.save
120
120
  end
121
121
  end
122
122
 
@@ -17,13 +17,15 @@ module Spree
17
17
 
18
18
  # Apply taxes to the order.
19
19
  #
20
- # This method will create or update adjustments on all line items and
21
- # shipments in the order to reflect the appropriate taxes passed in. It
22
- # will also remove any now inapplicable tax adjustments.
20
+ # This method will create or update adjustments on the order and all line
21
+ # items and shipments in the order to reflect the appropriate taxes passed
22
+ # in. It will also remove any now inapplicable tax adjustments.
23
23
  #
24
24
  # @param [Spree::Tax::OrderTax] taxes the taxes to apply to the order
25
25
  # @return [void]
26
26
  def apply(taxes)
27
+ update_adjustments(@order, taxes.order_taxes) if taxes.order_taxes
28
+
27
29
  @order.line_items.each do |item|
28
30
  taxed_items = taxes.line_item_taxes.select { |element| element.item_id == item.id }
29
31
  update_adjustments(item, taxed_items)
@@ -70,7 +72,7 @@ module Spree
70
72
 
71
73
  tax_adjustment ||= item.adjustments.new(
72
74
  source: tax_item.tax_rate,
73
- order_id: item.order_id,
75
+ order_id: item.is_a?(Spree::Order) ? item.id : item.order_id,
74
76
  label: tax_item.label,
75
77
  included: tax_item.included_in_price
76
78
  )
@@ -26,7 +26,7 @@ module Spree
26
26
  update_shipments
27
27
  update_shipment_state
28
28
  end
29
- Spree::Event.fire 'order_recalculated', order: order
29
+ Spree::Bus.publish :order_recalculated, order: order
30
30
  persist_totals
31
31
  end
32
32
  end
@@ -157,10 +157,11 @@ module Spree
157
157
  recalculate_adjustments
158
158
 
159
159
  all_items = line_items + shipments
160
+ order_tax_adjustments = adjustments.select(&:eligible?).select(&:tax?)
160
161
 
161
162
  order.adjustment_total = all_items.sum(&:adjustment_total) + adjustments.select(&:eligible?).sum(&:amount)
162
- order.included_tax_total = all_items.sum(&:included_tax_total)
163
- order.additional_tax_total = all_items.sum(&:additional_tax_total)
163
+ order.included_tax_total = all_items.sum(&:included_tax_total) + order_tax_adjustments.select(&:included?).sum(&:amount)
164
+ order.additional_tax_total = all_items.sum(&:additional_tax_total) + order_tax_adjustments.reject(&:included?).sum(&:amount)
164
165
 
165
166
  order.promo_total = all_items.sum(&:promo_total) + adjustments.select(&:eligible?).select(&:promotion?).sum(&:amount)
166
167
 
@@ -13,6 +13,7 @@ module Spree
13
13
  #
14
14
  class PaymentMethod < Spree::Base
15
15
  include Spree::Preferences::Persistable
16
+ class UnsupportedPaymentMethod < StandardError; end
16
17
 
17
18
  preference :server, :string, default: 'test'
18
19
  preference :test_mode, :boolean, default: true
@@ -60,6 +61,16 @@ module Spree
60
61
  def model_name
61
62
  ModelName.new(self, Spree)
62
63
  end
64
+
65
+ def find_sti_class(type_name)
66
+ super(type_name)
67
+ rescue ActiveRecord::SubclassNotFound
68
+ raise UnsupportedPaymentMethod, "Found invalid payment type '#{type_name}'.\n"\
69
+ "This may happen after switching payment service provider, when payment methods "\
70
+ "reference old types that are not supported any more.\n"\
71
+ "If that is the case, consider running 'rake payment_method:deprecate_unsupported_payment_methods' "\
72
+ "to fix the issue."
73
+ end
63
74
  end
64
75
 
65
76
  # Represents the gateway of this payment method
@@ -55,7 +55,7 @@ module Spree
55
55
 
56
56
  def display_country
57
57
  if country_iso
58
- "#{country_iso} (#{I18n.t(country_iso, scope: [:spree, :country_names])})"
58
+ "#{country_iso} (#{country.name})"
59
59
  else
60
60
  I18n.t(:any_country, scope: [:spree, :admin, :prices])
61
61
  end
@@ -194,13 +194,31 @@ module Spree
194
194
  group("spree_products.id").joins(:taxons).where(Spree::Taxon.arel_table[:name].eq(name))
195
195
  end
196
196
 
197
- def self.with_variant_sku_cont(sku)
198
- sku_match = "%#{sku}%"
197
+ def self.with_all_variant_sku_cont(sku)
198
+ variant_table = Spree::Variant.arel_table
199
+ subquery = Spree::Variant.with_discarded.where(
200
+ variant_table[:sku].matches("%#{sku}%").and(
201
+ variant_table[:product_id].eq(arel_table[:id])
202
+ )
203
+ )
204
+ where(subquery.arel.exists)
205
+ end
206
+
207
+ def self.with_kept_variant_sku_cont(sku)
199
208
  variant_table = Spree::Variant.arel_table
200
- subquery = Spree::Variant.where(variant_table[:sku].matches(sku_match).and(variant_table[:product_id].eq(arel_table[:id])))
209
+ subquery = Spree::Variant.where(
210
+ variant_table[:sku].matches("%#{sku}%").and(
211
+ variant_table[:product_id].eq(arel_table[:id])
212
+ )
213
+ )
201
214
  where(subquery.arel.exists)
202
215
  end
203
216
 
217
+ def self.with_variant_sku_cont(sku)
218
+ Spree::Deprecation.warn("use .with_kept_variant_sku_cont instead")
219
+ with_kept_variant_sku_cont(sku)
220
+ end
221
+
204
222
  class << self
205
223
  private
206
224
 
@@ -135,7 +135,7 @@ module Spree
135
135
  self.whitelisted_ransackable_attributes = %w[name slug]
136
136
 
137
137
  def self.ransackable_scopes(_auth_object = nil)
138
- %i(with_discarded with_variant_sku_cont)
138
+ %i(with_discarded with_variant_sku_cont with_all_variant_sku_cont with_kept_variant_sku_cont)
139
139
  end
140
140
 
141
141
  # @return [Boolean] true if there are any variants
@@ -15,6 +15,10 @@ module Spree
15
15
  before_destroy :remove_adjustments_from_incomplete_orders
16
16
  before_discard :remove_adjustments_from_incomplete_orders
17
17
 
18
+ def preload_relations
19
+ [:calculator]
20
+ end
21
+
18
22
  # Creates the adjustment related to a promotion for the order passed
19
23
  # through options hash
20
24
  #
@@ -15,6 +15,10 @@ module Spree
15
15
  before_destroy :remove_adjustments_from_incomplete_orders
16
16
  before_discard :remove_adjustments_from_incomplete_orders
17
17
 
18
+ def preload_relations
19
+ [:calculator]
20
+ end
21
+
18
22
  def perform(payload = {})
19
23
  order = payload[:order]
20
24
  promotion = payload[:promotion]
@@ -83,13 +87,8 @@ module Spree
83
87
  end
84
88
 
85
89
  def line_items_to_adjust(promotion, order)
86
- excluded_ids = adjustments.
87
- where(adjustable_id: order.line_items.pluck(:id), adjustable_type: 'Spree::LineItem').
88
- pluck(:adjustable_id).
89
- to_set
90
-
91
90
  order.line_items.select do |line_item|
92
- !excluded_ids.include?(line_item.id) &&
91
+ line_item.adjustments.none? { |adjustment| adjustment.source == self } &&
93
92
  promotion.line_item_actionable?(order, line_item)
94
93
  end
95
94
  end
@@ -12,6 +12,10 @@ module Spree
12
12
  class_name: 'Spree::ProductPromotionRule'
13
13
  has_many :products, class_name: 'Spree::Product', through: :product_promotion_rules
14
14
 
15
+ def preload_relations
16
+ [:products]
17
+ end
18
+
15
19
  MATCH_POLICIES = %w(any all none)
16
20
 
17
21
  validates_inclusion_of :preferred_match_policy, in: MATCH_POLICIES
@@ -31,17 +35,19 @@ module Spree
31
35
  return true if eligible_products.empty?
32
36
 
33
37
  case preferred_match_policy
34
- when 'all'
35
- unless eligible_products.all? { |product| order.products.include?(product) }
38
+ when "all"
39
+ unless eligible_products.all? { |product| order_products(order).include?(product) }
36
40
  eligibility_errors.add(:base, eligibility_error_message(:missing_product), error_code: :missing_product)
37
41
  end
38
- when 'any'
39
- unless order.products.any? { |product| eligible_products.include?(product) }
40
- eligibility_errors.add(:base, eligibility_error_message(:no_applicable_products), error_code: :no_applicable_products)
42
+ when "any"
43
+ unless order_products(order).any? { |product| eligible_products.include?(product) }
44
+ eligibility_errors.add(:base, eligibility_error_message(:no_applicable_products),
45
+ error_code: :no_applicable_products)
41
46
  end
42
- when 'none'
43
- unless order.products.none? { |product| eligible_products.include?(product) }
44
- eligibility_errors.add(:base, eligibility_error_message(:has_excluded_product), error_code: :has_excluded_product)
47
+ when "none"
48
+ unless order_products(order).none? { |product| eligible_products.include?(product) }
49
+ eligibility_errors.add(:base, eligibility_error_message(:has_excluded_product),
50
+ error_code: :has_excluded_product)
45
51
  end
46
52
  else
47
53
  raise "unexpected match policy: #{preferred_match_policy.inspect}"
@@ -68,6 +74,12 @@ module Spree
68
74
  def product_ids_string=(product_ids)
69
75
  self.product_ids = product_ids.to_s.split(',').map(&:strip)
70
76
  end
77
+
78
+ private
79
+
80
+ def order_products(order)
81
+ order.line_items.map(&:variant).map(&:product)
82
+ end
71
83
  end
72
84
  end
73
85
  end