solidus_core 3.1.7 → 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 (92) 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/user_address_book.rb +11 -1
  6. data/app/models/concerns/spree/user_methods.rb +20 -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/product/scopes.rb +21 -3
  18. data/app/models/spree/product.rb +1 -1
  19. data/app/models/spree/promotion/actions/create_adjustment.rb +4 -0
  20. data/app/models/spree/promotion/actions/create_item_adjustments.rb +5 -6
  21. data/app/models/spree/promotion/rules/product.rb +20 -8
  22. data/app/models/spree/promotion/rules/store.rb +4 -0
  23. data/app/models/spree/promotion/rules/taxon.rb +4 -0
  24. data/app/models/spree/promotion/rules/user.rb +4 -0
  25. data/app/models/spree/promotion.rb +34 -23
  26. data/app/models/spree/promotion_action.rb +4 -0
  27. data/app/models/spree/promotion_code.rb +8 -4
  28. data/app/models/spree/promotion_handler/cart.rb +26 -6
  29. data/app/models/spree/promotion_rule.rb +5 -0
  30. data/app/models/spree/reimbursement.rb +2 -2
  31. data/app/models/spree/return_item.rb +1 -2
  32. data/app/models/spree/stock/allocator/on_hand_first.rb +2 -2
  33. data/app/models/spree/stock/quantifier.rb +12 -8
  34. data/app/models/spree/stock/simple_coordinator.rb +2 -1
  35. data/app/models/spree/tax/item_tax.rb +3 -2
  36. data/app/models/spree/tax/order_tax.rb +3 -1
  37. data/app/models/spree/tax/tax_location.rb +4 -7
  38. data/app/models/spree/tax_rate.rb +2 -0
  39. data/app/models/spree/variant.rb +1 -1
  40. data/app/subscribers/spree/mailer_subscriber.rb +4 -0
  41. data/app/subscribers/spree/order_mailer_subscriber.rb +35 -0
  42. data/config/locales/en.yml +9 -2
  43. data/db/migrate/20201127212108_add_type_before_removal_to_spree_payment_methods.rb +7 -0
  44. data/db/migrate/20220317165036_set_promotions_with_any_policy_to_all_if_possible.rb +20 -0
  45. data/lib/generators/solidus/install/install_generator/bundler_context.rb +97 -0
  46. data/lib/generators/solidus/install/install_generator/install_frontend.rb +50 -0
  47. data/lib/generators/solidus/install/install_generator/support_solidus_frontend_extraction.rb +48 -0
  48. data/lib/generators/solidus/install/install_generator.rb +56 -49
  49. data/lib/generators/solidus/install/templates/config/initializers/spree.rb.tt +6 -16
  50. data/lib/generators/solidus/install/templates/vendor/assets/javascripts/spree/backend/all.js +2 -2
  51. data/lib/spree/app_configuration.rb +27 -0
  52. data/lib/spree/bus.rb +20 -0
  53. data/lib/spree/core/controller_helpers/auth.rb +9 -1
  54. data/lib/spree/core/controller_helpers/current_host.rb +1 -3
  55. data/lib/spree/core/controller_helpers/order.rb +10 -10
  56. data/lib/spree/core/controller_helpers/search.rb +1 -1
  57. data/lib/spree/core/engine.rb +33 -8
  58. data/lib/spree/core/state_machines/order.rb +1 -1
  59. data/lib/spree/core/stock_configuration.rb +18 -0
  60. data/lib/spree/core/validators/email.rb +3 -1
  61. data/lib/spree/core/version.rb +1 -1
  62. data/lib/spree/core.rb +20 -0
  63. data/lib/spree/event/subscriber_registry.rb +4 -6
  64. data/lib/spree/event.rb +1 -1
  65. data/lib/spree/migrations.rb +1 -1
  66. data/lib/spree/permission_sets/default_customer.rb +8 -1
  67. data/lib/spree/permitted_attributes.rb +4 -4
  68. data/lib/spree/preferences/configuration.rb +34 -12
  69. data/lib/spree/preferences/preferable_class_methods.rb +1 -1
  70. data/lib/spree/preferences/preference_differentiator.rb +2 -1
  71. data/lib/spree/preferences/static_model_preferences.rb +0 -2
  72. data/lib/spree/rails_compatibility.rb +99 -0
  73. data/lib/spree/testing_support/bus_helpers.rb +101 -0
  74. data/lib/spree/testing_support/common_rake.rb +47 -19
  75. data/lib/spree/testing_support/dummy_app/assets/javascripts/spree/backend/all.js +1 -1
  76. data/lib/spree/testing_support/dummy_app/assets/javascripts/spree/frontend/all.js +1 -1
  77. data/lib/spree/testing_support/dummy_app.rb +6 -2
  78. data/lib/spree/testing_support/factories/address_factory.rb +7 -2
  79. data/lib/spree/testing_support/factories/inventory_unit_factory.rb +1 -1
  80. data/lib/spree/testing_support/factories/order_factory.rb +8 -4
  81. data/lib/spree/testing_support/factories/product_factory.rb +4 -1
  82. data/lib/spree/testing_support/factories/store_credit_factory.rb +4 -4
  83. data/lib/spree/testing_support/factory_bot.rb +1 -1
  84. data/lib/spree/testing_support/order_walkthrough.rb +5 -4
  85. data/lib/spree/testing_support/silence_deprecations.rb +9 -0
  86. data/lib/tasks/payment_method.rake +29 -0
  87. data/lib/tasks/solidus/delete_prices_with_nil_amount.rake +2 -2
  88. data/lib/tasks/solidus/split_promotions_with_any_match_policy.rake +33 -0
  89. data/solidus_core.gemspec +6 -2
  90. metadata +68 -23
  91. data/lib/generators/solidus/install/templates/vendor/assets/javascripts/spree/frontend/all.js +0 -10
  92. data/lib/generators/solidus/install/templates/vendor/assets/stylesheets/spree/frontend/all.css +0 -9
@@ -9,6 +9,10 @@ module Spree
9
9
  dependent: :destroy
10
10
  has_many :users, through: :promotion_rule_users, class_name: Spree::UserClassHandle.new
11
11
 
12
+ def preload_relations
13
+ [:users]
14
+ end
15
+
12
16
  def applicable?(promotable)
13
17
  promotable.is_a?(Spree::Order)
14
18
  end
@@ -3,6 +3,7 @@
3
3
  module Spree
4
4
  class Promotion < Spree::Base
5
5
  MATCH_POLICIES = %w(all any)
6
+
6
7
  UNACTIVATABLE_ORDER_STATES = ["complete", "awaiting_return", "returned"]
7
8
 
8
9
  attr_reader :eligibility_errors
@@ -67,6 +68,19 @@ module Spree
67
68
  ).first
68
69
  end
69
70
 
71
+ # All orders that have been discounted using this promotion
72
+ def discounted_orders
73
+ Spree::Order.
74
+ joins(:all_adjustments).
75
+ where(
76
+ spree_adjustments: {
77
+ source_type: "Spree::PromotionAction",
78
+ source_id: actions.map(&:id),
79
+ eligible: true
80
+ }
81
+ ).distinct
82
+ end
83
+
70
84
  def as_json(options = {})
71
85
  options[:except] ||= :code
72
86
  super
@@ -151,7 +165,7 @@ module Spree
151
165
  return [] if rules.none?
152
166
 
153
167
  eligible = lambda { |rule| rule.eligible?(promotable, options) }
154
- specific_rules = rules.for(promotable)
168
+ specific_rules = rules.select { |rule| rule.applicable?(promotable) }
155
169
  return [] if specific_rules.none?
156
170
 
157
171
  if match_all?
@@ -163,6 +177,12 @@ module Spree
163
177
  end
164
178
  specific_rules
165
179
  else
180
+ Spree::Deprecation.warn(
181
+ <<~WARN
182
+ Your promotion "#{name}" with ID #{id} has a match_policy of 'any'.
183
+ This is deprecated, please split the promotion into separate promotions for each rule.
184
+ WARN
185
+ )
166
186
  unless specific_rules.any?(&eligible)
167
187
  @eligibility_errors = specific_rules.map(&:eligibility_errors).detect(&:present?)
168
188
  return nil
@@ -190,11 +210,11 @@ module Spree
190
210
  # @param excluded_orders [Array<Spree::Order>] Orders to exclude from usage count
191
211
  # @return [Integer] usage count
192
212
  def usage_count(excluded_orders: [])
193
- Spree::Adjustment.promotion.
194
- eligible.
195
- in_completed_orders(excluded_orders: excluded_orders, exclude_canceled: true).
196
- where(source_id: actions).
197
- count(:order_id)
213
+ discounted_orders.
214
+ complete.
215
+ where.not(id: [excluded_orders.map(&:id)]).
216
+ where.not(spree_orders: { state: :canceled }).
217
+ count
198
218
  end
199
219
 
200
220
  def line_item_actionable?(order, line_item, promotion_code: nil)
@@ -215,21 +235,12 @@ module Spree
215
235
  end
216
236
 
217
237
  def used_by?(user, excluded_orders = [])
218
- [
219
- :adjustments,
220
- :line_item_adjustments,
221
- :shipment_adjustments
222
- ].any? do |adjustment_type|
223
- user.orders.complete.joins(adjustment_type).where(
224
- spree_adjustments: {
225
- source_type: "Spree::PromotionAction",
226
- source_id: actions.map(&:id),
227
- eligible: true
228
- }
229
- ).where.not(
230
- id: excluded_orders.map(&:id)
231
- ).any?
232
- end
238
+ discounted_orders.
239
+ complete.
240
+ where.not(id: excluded_orders.map(&:id)).
241
+ where(user: user).
242
+ where.not(spree_orders: { state: :canceled }).
243
+ exists?
233
244
  end
234
245
 
235
246
  # Removes a promotion and any adjustments or other side effects from an
@@ -251,9 +262,9 @@ module Spree
251
262
  def blacklisted?(promotable)
252
263
  case promotable
253
264
  when Spree::LineItem
254
- !promotable.product.promotionable?
265
+ !promotable.variant.product.promotionable?
255
266
  when Spree::Order
256
- promotable.line_items.joins(:product).where(spree_products: { promotionable: false }).exists?
267
+ promotable.line_items.any? { |line_item| !line_item.variant.product.promotionable? }
257
268
  end
258
269
  end
259
270
 
@@ -16,6 +16,10 @@ module Spree
16
16
  scope :of_type, ->(type) { where(type: Array.wrap(type).map(&:to_s)) }
17
17
  scope :shipping, -> { of_type(Spree::Config.environment.promotions.shipping_actions.to_a) }
18
18
 
19
+ def preload_relations
20
+ []
21
+ end
22
+
19
23
  # Updates the state of the order or performs some other action depending on
20
24
  # the subclass options will contain the payload from the event that
21
25
  # activated the promotion. This will include the key :user which allows
@@ -28,10 +28,14 @@ class Spree::PromotionCode < Spree::Base
28
28
  # @param excluded_orders [Array<Spree::Order>] Orders to exclude from usage count
29
29
  # @return [Integer] usage count
30
30
  def usage_count(excluded_orders: [])
31
- adjustments.
32
- eligible.
33
- in_completed_orders(excluded_orders: excluded_orders, exclude_canceled: true).
34
- count(:order_id)
31
+ promotion.
32
+ discounted_orders.
33
+ complete.
34
+ where.not(spree_orders: { state: :canceled }).
35
+ joins(:order_promotions).
36
+ where(spree_orders_promotions: { promotion_code_id: self.id }).
37
+ where.not(id: excluded_orders.map(&:id)).
38
+ count
35
39
  end
36
40
 
37
41
  def usage_limit
@@ -33,23 +33,43 @@ module Spree
33
33
  private
34
34
 
35
35
  def promotions
36
- connected_order_promotions | sale_promotions
36
+ promos = connected_order_promotions | sale_promotions
37
+ promos.flat_map(&:promotion_actions).group_by(&:preload_relations).each do |preload_relations, actions|
38
+ preload(records: actions, associations: preload_relations)
39
+ end
40
+ promos.flat_map(&:promotion_rules).group_by(&:preload_relations).each do |preload_relations, rules|
41
+ preload(records: rules, associations: preload_relations)
42
+ end
43
+ promos
44
+ end
45
+
46
+ def preload(records:, associations:)
47
+ if Rails::VERSION::MAJOR >= 7
48
+ ActiveRecord::Associations::Preloader.new(records: records, associations: associations).call
49
+ else
50
+ ActiveRecord::Associations::Preloader.new.preload(records, associations)
51
+ end
37
52
  end
38
53
 
39
54
  def connected_order_promotions
40
- Spree::Promotion.active.includes(:promotion_rules).
41
- joins(:order_promotions).
42
- where(spree_orders_promotions: { order_id: order.id }).readonly(false).to_a
55
+ order.promotions.active.includes(promotion_includes)
43
56
  end
44
57
 
45
58
  def sale_promotions
46
- Spree::Promotion.where(apply_automatically: true).active.includes(:promotion_rules)
59
+ Spree::Promotion.where(apply_automatically: true).active.includes(promotion_includes)
47
60
  end
48
61
 
49
62
  def promotion_code(promotion)
50
- order_promotion = Spree::OrderPromotion.where(order: order, promotion: promotion).first
63
+ order_promotion = order.order_promotions.detect { |op| op.promotion_id == promotion.id }
51
64
  order_promotion.present? ? order_promotion.promotion_code : nil
52
65
  end
66
+
67
+ def promotion_includes
68
+ [
69
+ :promotion_rules,
70
+ :promotion_actions,
71
+ ]
72
+ end
53
73
  end
54
74
  end
55
75
  end
@@ -14,9 +14,14 @@ module Spree
14
14
  validates :promotion, presence: true
15
15
  validate :unique_per_promotion, on: :create
16
16
 
17
+ def preload_relations
18
+ []
19
+ end
20
+
17
21
  def self.for(promotable)
18
22
  all.select { |rule| rule.applicable?(promotable) }
19
23
  end
24
+ deprecate :for, "Please select promotion rules by their applicable status on the promotable instead."
20
25
 
21
26
  def applicable?(_promotable)
22
27
  raise NotImplementedError, "applicable? should be implemented in a sub-class of Spree::PromotionRule"
@@ -92,10 +92,10 @@ module Spree
92
92
 
93
93
  if unpaid_amount_within_tolerance?
94
94
  reimbursed!
95
- Spree::Event.fire 'reimbursement_reimbursed', reimbursement: self
95
+ Spree::Bus.publish :reimbursement_reimbursed, reimbursement: self
96
96
  else
97
97
  errored!
98
- Spree::Event.fire 'reimbursement_errored', reimbursement: self
98
+ Spree::Bus.publish :reimbursement_errored, reimbursement: self
99
99
  end
100
100
 
101
101
  if errored?
@@ -30,7 +30,7 @@ module Spree
30
30
  self.refund_amount_calculator = Calculator::Returns::DefaultRefundAmount
31
31
 
32
32
  belongs_to :return_authorization, inverse_of: :return_items, optional: true
33
- belongs_to :inventory_unit, inverse_of: :return_items, optional: true
33
+ belongs_to :inventory_unit, inverse_of: :return_items
34
34
  belongs_to :exchange_variant, class_name: 'Spree::Variant', optional: true
35
35
  belongs_to :exchange_inventory_unit, class_name: 'Spree::InventoryUnit', inverse_of: :original_return_item, optional: true
36
36
  belongs_to :customer_return, inverse_of: :return_items, optional: true
@@ -42,7 +42,6 @@ module Spree
42
42
  validate :eligible_exchange_variant
43
43
  validate :belongs_to_same_customer_order
44
44
  validate :validate_acceptance_status_for_reimbursement
45
- validates :inventory_unit, presence: true
46
45
  validate :validate_no_other_completed_return_items
47
46
 
48
47
  after_create :cancel_others, unless: :cancelled?
@@ -7,11 +7,11 @@ module Spree
7
7
  def allocate_inventory(desired)
8
8
  # Allocate any available on hand inventory
9
9
  on_hand = allocate_on_hand(desired)
10
- desired -= on_hand.values.sum if on_hand.present?
10
+ desired -= on_hand.values.reduce(&:+) if on_hand.present?
11
11
 
12
12
  # Allocate remaining desired inventory from backorders
13
13
  backordered = allocate_backordered(desired)
14
- desired -= backordered.values.sum if backordered.present?
14
+ desired -= backordered.values.reduce(&:+) if backordered.present?
15
15
 
16
16
  # If all works at this point desired must be empty
17
17
  [on_hand, backordered, desired]
@@ -6,14 +6,18 @@ module Spree
6
6
  attr_reader :stock_items
7
7
 
8
8
  # @param [Variant] variant The variant to check inventory for.
9
- # @param [StockLocation, Integer] stock_location The stock_location to check inventory in. If unspecified it will check inventory in all available StockLocations
10
- def initialize(variant, stock_location = nil)
9
+ # @param [StockLocation, Integer] stock_location_or_id
10
+ # The stock_location or stock location ID to check inventory in.
11
+ # If unspecified it will check inventory in all available StockLocations
12
+ def initialize(variant, stock_location_or_id = nil)
11
13
  @variant = variant
12
- @stock_items = Spree::StockItem.where(variant_id: variant)
13
- if stock_location
14
- @stock_items.where!(stock_location: stock_location)
15
- else
16
- @stock_items.joins!(:stock_location).merge!(Spree::StockLocation.active)
14
+ @stock_items = variant.stock_items.select do |stock_item|
15
+ if stock_location_or_id
16
+ stock_item.stock_location == stock_location_or_id ||
17
+ stock_item.stock_location_id == stock_location_or_id
18
+ else
19
+ stock_item.stock_location.active?
20
+ end
17
21
  end
18
22
  end
19
23
 
@@ -23,7 +27,7 @@ module Spree
23
27
  # inventory is not tracked on the variant.
24
28
  def total_on_hand
25
29
  if @variant.should_track_inventory?
26
- stock_items.sum(:count_on_hand)
30
+ stock_items.sum(&:count_on_hand)
27
31
  else
28
32
  Float::INFINITY
29
33
  end
@@ -24,7 +24,8 @@ module Spree
24
24
 
25
25
  def initialize(order, inventory_units = nil)
26
26
  @order = order
27
- @inventory_units = inventory_units || InventoryUnitBuilder.new(order).units
27
+ @inventory_units =
28
+ inventory_units || Spree::Config.stock.inventory_unit_builder_class.new(order).units
28
29
  @splitters = Spree::Config.environment.stock_splitters
29
30
 
30
31
  filtered_stock_locations = Spree::Config.stock.location_filter_class.new(Spree::StockLocation.all, @order).filter
@@ -5,9 +5,10 @@ module Spree
5
5
  # Simple object used to hold tax data for an item.
6
6
  #
7
7
  # This generic object will hold the amount of tax that should be applied to
8
- # an item. (Either a {Spree::LineItem} or a {Spree::Shipment}.)
8
+ # an item. (Either a {Spree::Order}, a {Spree::LineItem} or a {Spree::Shipment}.)
9
9
  #
10
- # @attr_reader [Integer] item_id the {Spree::LineItem} or {Spree::Shipment} ID
10
+ # @attr_reader [Integer] item_id the {Spree::LineItem} or {Spree::Shipment} ID.
11
+ # Or blank if an order-level tax.
11
12
  # @attr_reader [String] label information about the taxes
12
13
  # @attr_reader [Spree::TaxRate] tax_rate will be used as the source for tax
13
14
  # adjustments
@@ -8,13 +8,15 @@ module Spree
8
8
  # adjustments on an order.
9
9
  #
10
10
  # @attr_reader [Integer] order_id the {Spree::Order} these taxes apply to
11
+ # @attr_reader [Array<Spree::Tax::ItemTax>] order_taxes an array of tax
12
+ # data for the order
11
13
  # @attr_reader [Array<Spree::Tax::ItemTax>] line_item_taxes an array of
12
14
  # tax data for order's line items
13
15
  # @attr_reader [Array<Spree::Tax::ItemTax>] shipment_taxes an array of
14
16
  # tax data for the order's shipments
15
17
  class OrderTax
16
18
  include ActiveModel::Model
17
- attr_accessor :order_id, :line_item_taxes, :shipment_taxes
19
+ attr_accessor :order_id, :order_taxes, :line_item_taxes, :shipment_taxes
18
20
  end
19
21
  end
20
22
  end
@@ -8,7 +8,7 @@ module Spree
8
8
  # @attr_reader [Integer] country_id the ID of a Spree::Country object
9
9
  # @attr_reader [Integer] state_id the ID of a Spree::State object
10
10
  class TaxLocation
11
- attr_reader :country_id, :state_id
11
+ attr_reader :country, :state
12
12
 
13
13
  # Create a new TaxLocation object
14
14
  #
@@ -19,18 +19,15 @@ module Spree
19
19
  #
20
20
  # @return [Spree::Tax::TaxLocation] a Spree::Tax::TaxLocation object
21
21
  def initialize(country: nil, state: nil)
22
- @country_id = country && country.id
23
- @state_id = state && state.id
22
+ @country, @state = country, state
24
23
  end
24
+ delegate :id, to: :state, prefix: true, allow_nil: true
25
+ delegate :id, to: :country, prefix: true, allow_nil: true
25
26
 
26
27
  def ==(other)
27
28
  state_id == other.state_id && country_id == other.country_id
28
29
  end
29
30
 
30
- def country
31
- Spree::Country.find_by(id: country_id)
32
- end
33
-
34
31
  def empty?
35
32
  country_id.nil? && state_id.nil?
36
33
  end
@@ -27,6 +27,8 @@ module Spree
27
27
 
28
28
  validates :amount, presence: true, numericality: true
29
29
 
30
+ self.whitelisted_ransackable_associations = %w[tax_categories zone]
31
+
30
32
  # Finds all tax rates whose zones match a given address
31
33
  scope :for_address, ->(address) { joins(:zone).merge(Spree::Zone.for_address(address)) }
32
34
  scope :for_country,
@@ -66,7 +66,7 @@ module Spree
66
66
 
67
67
  validates :cost_price, numericality: { greater_than_or_equal_to: 0, allow_nil: true }
68
68
  validates :price, numericality: { greater_than_or_equal_to: 0, allow_nil: true }
69
- validates_uniqueness_of :sku, allow_blank: true, case_sensitive: true, if: :enforce_unique_sku?
69
+ validates_uniqueness_of :sku, allow_blank: true, case_sensitive: true, conditions: -> { where(deleted_at: nil) }, if: :enforce_unique_sku?
70
70
 
71
71
  after_create :create_stock_items
72
72
  after_create :set_position
@@ -3,6 +3,10 @@
3
3
  require 'spree/event/subscriber'
4
4
 
5
5
  module Spree
6
+ # Legacy subscriber
7
+ #
8
+ # This subscriber module is used by the legacy pub/sub system (see
9
+ # {Spree::Event}).
6
10
  module MailerSubscriber
7
11
  include Spree::Event::Subscriber
8
12
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spree
4
+ # Mailing after events on a {Spree::Order}
5
+ class OrderMailerSubscriber
6
+ include Omnes::Subscriber
7
+
8
+ handle :order_finalized,
9
+ with: :send_confirmation_email,
10
+ id: :spree_order_mailer_send_confirmation_email
11
+
12
+ handle :reimbursement_reimbursed,
13
+ with: :send_reimbursement_email,
14
+ id: :spree_order_mailer_send_reimbursement_email
15
+
16
+ # Sends confirmation email to the user
17
+ #
18
+ # @param event [Omnes::UnstructuredEvent]
19
+ def send_confirmation_email(event)
20
+ order = event[:order]
21
+ unless order.confirmation_delivered?
22
+ Spree::Config.order_mailer_class.confirm_email(order).deliver_later
23
+ order.update_column(:confirmation_delivered, true)
24
+ end
25
+ end
26
+
27
+ # Sends reimbursement email to the user
28
+ #
29
+ # @param event [Omnes::UnstructuredEvent]
30
+ def send_reimbursement_email(event)
31
+ reimbursement = event[:reimbursement]
32
+ Spree::Config.reimbursement_mailer_class.reimbursement_email(reimbursement.id).deliver_later
33
+ end
34
+ end
35
+ end
@@ -365,7 +365,7 @@ en:
365
365
  amount_authorized: Amount Authorized
366
366
  amount_credited: Amount Credited
367
367
  amount_used: Amount Used
368
- category_id: Credit Type
368
+ category_id: Category
369
369
  created_at: Issued On
370
370
  created_by_id: Created By
371
371
  invalidated_at: Invalidated
@@ -866,6 +866,10 @@ en:
866
866
  new_price: New Price
867
867
  new:
868
868
  new_price: New Price
869
+ master_variant_table:
870
+ master_variant: Master Variant Prices
871
+ table:
872
+ variant_pricing: Variant Prices
869
873
  promotions:
870
874
  actions:
871
875
  calculator_label: Calculated by
@@ -998,12 +1002,16 @@ en:
998
1002
  edit_variant: Edit Variant
999
1003
  form:
1000
1004
  dimensions: Dimensions
1005
+ options: Options
1001
1006
  pricing: Pricing
1002
1007
  pricing_hint: These values are populated from the product details page and
1003
1008
  can be overridden below
1009
+ properties: Properties
1004
1010
  use_product_tax_category: Use Product Tax Category
1005
1011
  new:
1006
1012
  new_variant: New Variant
1013
+ table:
1014
+ no_variants_found: No variants found for '%{term}'
1007
1015
  table_filter:
1008
1016
  show_deleted: Show Deleted Variants
1009
1017
  administration: Administration
@@ -2248,7 +2256,6 @@ en:
2248
2256
  value: Value
2249
2257
  variant: Variant
2250
2258
  variant_placeholder: Choose a Variant
2251
- variant_pricing: Variant Pricing
2252
2259
  variant_properties: Variant Properties
2253
2260
  variant_search: Variant Search
2254
2261
  variant_search_placeholder: SKU or Option Value
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AddTypeBeforeRemovalToSpreePaymentMethods < ActiveRecord::Migration[5.2]
4
+ def change
5
+ add_column :spree_payment_methods, :type_before_removal, :string
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SetPromotionsWithAnyPolicyToAllIfPossible < ActiveRecord::Migration[5.2]
4
+ def up
5
+ Spree::Promotion.where(match_policy: :any).includes(:promotion_rules).all.each do |promotion|
6
+ if promotion.promotion_rules.length <= 1
7
+ promotion.update!(match_policy: :all)
8
+ else
9
+ raise StandardError, <<~MSG
10
+ You have promotions with a match policy of any and more than one rule. Please
11
+ run `bundle exec rake solidus:split_promotions_with_any_match_policy`.
12
+ MSG
13
+ end
14
+ end
15
+ end
16
+
17
+ def down
18
+ # No-Op
19
+ end
20
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solidus
4
+ class InstallGenerator < Rails::Generators::Base
5
+ # Bundler context during the install process.
6
+ #
7
+ # This class gives access to information about the bundler context in which
8
+ # the install generator is run. I.e., which solidus components are present
9
+ # in the user's Gemfile. It also allows modifying the Gemfile to add or
10
+ # remove gems.
11
+ #
12
+ # @api private
13
+ class BundlerContext
14
+ # Write and remove into and from a Gemfile
15
+ #
16
+ # This custom injector fixes support for path, git and custom sources,
17
+ # which is missing in bundler's upstream injector for a dependency fetched
18
+ # with `Bundled.locked_gems.dependencies`.
19
+ #
20
+ # @api private
21
+ class InjectorWithPathSupport < Bundler::Injector
22
+ private def build_gem_lines(conservative_versioning)
23
+ @deps.map do |d|
24
+ name = d.name.dump
25
+ is_local = d.source.instance_of?(Bundler::Source::Path)
26
+ is_git = d.source.instance_of?(Bundler::Source::Git)
27
+
28
+ requirement = if is_local
29
+ ", path: \"#{d.source.path}\""
30
+ elsif is_git
31
+ ", git: \"#{d.git}\"".yield_self { |g| d.ref ? g + ", ref: \"#{d.ref}\"" : g }
32
+ elsif conservative_versioning
33
+ ", \"#{conservative_version(@definition.specs[d.name][0])}\""
34
+ else
35
+ ", #{d.requirement.as_list.map(&:dump).join(", ")}"
36
+ end
37
+
38
+ source = ", :source => \"#{d.source.remotes.join(",")}\"" unless is_local || is_git || d.source.nil?
39
+
40
+ %(gem #{name}#{requirement}#{source})
41
+ end.join("\n")
42
+ end
43
+ end
44
+
45
+ attr_reader :dependencies, :injector
46
+
47
+ def self.bundle_cleanly(&block)
48
+ Bundler.respond_to?(:with_unbundled_env) ? Bundler.with_unbundled_env(&block) : Bundler.with_clean_env(&block)
49
+ end
50
+
51
+ def initialize
52
+ @dependencies = Bundler.locked_gems.dependencies
53
+ @injector = InjectorWithPathSupport
54
+ end
55
+
56
+ def solidus_in_gemfile?
57
+ !solidus_dependency.nil?
58
+ end
59
+
60
+ def component_in_gemfile?(name)
61
+ !@dependencies["solidus_#{name}"].nil?
62
+ end
63
+
64
+ def break_down_components(components)
65
+ raise <<~MSG unless solidus_in_gemfile?
66
+ solidus meta gem needs to be present in the Gemfile to build the component dependency
67
+ MSG
68
+
69
+ @injector.inject(
70
+ components.map { |component| dependency_for_component(component) }
71
+ )
72
+ end
73
+
74
+ def remove(*args, **kwargs, &block)
75
+ @injector.remove(*args, **kwargs, &block)
76
+ end
77
+
78
+ private
79
+
80
+ def dependency_for_component(component)
81
+ Bundler::Dependency.new(
82
+ "solidus_#{component}",
83
+ solidus_dependency.requirement,
84
+ {
85
+ "source" => solidus_dependency.source,
86
+ "git" => solidus_dependency.source.try(:uri),
87
+ "ref" => solidus_dependency.source.try(:ref)
88
+ }
89
+ )
90
+ end
91
+
92
+ def solidus_dependency
93
+ @dependencies['solidus']
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Solidus
4
+ class InstallGenerator < Rails::Generators::Base
5
+ class InstallFrontend
6
+ attr_reader :bundler_context,
7
+ :generator_context
8
+
9
+ def initialize(bundler_context:, generator_context:)
10
+ @bundler_context = bundler_context
11
+ @generator_context = generator_context
12
+ end
13
+
14
+ def call(frontend, installer_adds_auth:)
15
+ case frontend
16
+ when 'solidus_frontend'
17
+ install_solidus_frontend
18
+ when 'solidus_starter_frontend'
19
+ install_solidus_starter_frontend(installer_adds_auth)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def install_solidus_frontend
26
+ unless @bundler_context.component_in_gemfile?(:frontend)
27
+ BundlerContext.bundle_cleanly do
28
+ `bundle add solidus_frontend`
29
+ `bundle install`
30
+ end
31
+ end
32
+
33
+ @generator_context.generate('solidus_frontend:install')
34
+ end
35
+
36
+ def install_solidus_starter_frontend(installer_adds_auth)
37
+ @bundler_context.remove(['solidus_frontend']) if @bundler_context.component_in_gemfile?(:frontend)
38
+
39
+ # TODO: Move installation of solidus_auth_devise to the
40
+ # solidus_starter_frontend template
41
+ BundlerContext.bundle_cleanly { `bundle add solidus_auth_devise` } unless auth_present?(installer_adds_auth)
42
+ `LOCATION="https://raw.githubusercontent.com/solidusio/solidus_starter_frontend/main/template.rb" bin/rails app:template`
43
+ end
44
+
45
+ def auth_present?(installer_adds_auth)
46
+ installer_adds_auth || @bundler_context.component_in_gemfile?(:auth_devise)
47
+ end
48
+ end
49
+ end
50
+ end