solidus_core 3.1.6 → 3.2.0
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.
- checksums.yaml +4 -4
- data/app/helpers/spree/products_helper.rb +1 -1
- data/app/models/concerns/spree/active_storage_adapter/attachment.rb +23 -10
- data/app/models/concerns/spree/active_storage_adapter.rb +1 -1
- data/app/models/concerns/spree/user_address_book.rb +11 -1
- data/app/models/concerns/spree/user_methods.rb +20 -1
- data/app/models/spree/adjustment.rb +1 -0
- data/app/models/spree/carton.rb +1 -1
- data/app/models/spree/log_entry.rb +74 -1
- data/app/models/spree/option_value.rb +9 -0
- data/app/models/spree/order.rb +68 -29
- data/app/models/spree/order_contents.rb +2 -1
- data/app/models/spree/order_inventory.rb +1 -1
- data/app/models/spree/order_merger.rb +2 -2
- data/app/models/spree/order_taxation.rb +6 -4
- data/app/models/spree/order_updater.rb +4 -3
- data/app/models/spree/payment_method.rb +11 -0
- data/app/models/spree/price.rb +1 -1
- data/app/models/spree/product/scopes.rb +21 -3
- data/app/models/spree/product.rb +1 -1
- data/app/models/spree/promotion/actions/create_adjustment.rb +4 -0
- data/app/models/spree/promotion/actions/create_item_adjustments.rb +5 -6
- data/app/models/spree/promotion/rules/product.rb +20 -8
- data/app/models/spree/promotion/rules/store.rb +4 -0
- data/app/models/spree/promotion/rules/taxon.rb +4 -0
- data/app/models/spree/promotion/rules/user.rb +4 -0
- data/app/models/spree/promotion.rb +34 -23
- data/app/models/spree/promotion_action.rb +4 -0
- data/app/models/spree/promotion_code.rb +8 -4
- data/app/models/spree/promotion_handler/cart.rb +26 -6
- data/app/models/spree/promotion_rule.rb +5 -0
- data/app/models/spree/reimbursement.rb +2 -2
- data/app/models/spree/return_item.rb +1 -2
- data/app/models/spree/stock/allocator/on_hand_first.rb +2 -2
- data/app/models/spree/stock/quantifier.rb +12 -8
- data/app/models/spree/stock/simple_coordinator.rb +2 -1
- data/app/models/spree/tax/item_tax.rb +3 -2
- data/app/models/spree/tax/order_tax.rb +3 -1
- data/app/models/spree/tax/tax_location.rb +4 -7
- data/app/models/spree/tax_rate.rb +2 -0
- data/app/models/spree/variant.rb +1 -1
- data/app/subscribers/spree/mailer_subscriber.rb +4 -0
- data/app/subscribers/spree/order_mailer_subscriber.rb +35 -0
- data/config/i18n-tasks.yml +134 -0
- data/config/locales/en.yml +391 -257
- data/db/migrate/20201127212108_add_type_before_removal_to_spree_payment_methods.rb +7 -0
- data/db/migrate/20220317165036_set_promotions_with_any_policy_to_all_if_possible.rb +20 -0
- data/lib/generators/solidus/install/install_generator/bundler_context.rb +97 -0
- data/lib/generators/solidus/install/install_generator/install_frontend.rb +53 -0
- data/lib/generators/solidus/install/install_generator/support_solidus_frontend_extraction.rb +48 -0
- data/lib/generators/solidus/install/install_generator.rb +58 -50
- data/lib/generators/solidus/install/templates/config/initializers/spree.rb.tt +6 -16
- data/lib/generators/solidus/install/templates/vendor/assets/javascripts/spree/backend/all.js +2 -2
- data/lib/spree/app_configuration.rb +43 -0
- data/lib/spree/bus.rb +20 -0
- data/lib/spree/core/controller_helpers/auth.rb +9 -1
- data/lib/spree/core/controller_helpers/current_host.rb +1 -3
- data/lib/spree/core/controller_helpers/order.rb +10 -10
- data/lib/spree/core/controller_helpers/search.rb +1 -1
- data/lib/spree/core/engine.rb +39 -8
- data/lib/spree/core/state_machines/order.rb +1 -1
- data/lib/spree/core/stock_configuration.rb +18 -0
- data/lib/spree/core/validators/email.rb +3 -1
- data/lib/spree/core/version.rb +2 -2
- data/lib/spree/core.rb +20 -0
- data/lib/spree/event/subscriber_registry.rb +4 -6
- data/lib/spree/event.rb +1 -1
- data/lib/spree/migrations.rb +1 -1
- data/lib/spree/permission_sets/default_customer.rb +8 -1
- data/lib/spree/permitted_attributes.rb +4 -4
- data/lib/spree/preferences/configuration.rb +34 -12
- data/lib/spree/preferences/preferable_class_methods.rb +1 -1
- data/lib/spree/preferences/preference_differentiator.rb +2 -1
- data/lib/spree/preferences/static_model_preferences.rb +0 -2
- data/lib/spree/rails_compatibility.rb +99 -0
- data/lib/spree/testing_support/bus_helpers.rb +101 -0
- data/lib/spree/testing_support/common_rake.rb +47 -19
- data/lib/spree/testing_support/dummy_app/assets/javascripts/spree/backend/all.js +1 -1
- data/lib/spree/testing_support/dummy_app/assets/javascripts/spree/frontend/all.js +1 -1
- data/lib/spree/testing_support/dummy_app.rb +6 -2
- data/lib/spree/testing_support/factories/address_factory.rb +7 -2
- data/lib/spree/testing_support/factories/inventory_unit_factory.rb +1 -1
- data/lib/spree/testing_support/factories/order_factory.rb +8 -4
- data/lib/spree/testing_support/factories/product_factory.rb +4 -1
- data/lib/spree/testing_support/factories/store_credit_factory.rb +4 -4
- data/lib/spree/testing_support/factories/user_factory.rb +6 -0
- data/lib/spree/testing_support/factory_bot.rb +1 -1
- data/lib/spree/testing_support/order_walkthrough.rb +5 -4
- data/lib/spree/testing_support/silence_deprecations.rb +9 -0
- data/lib/tasks/payment_method.rake +29 -0
- data/lib/tasks/solidus/delete_prices_with_nil_amount.rake +2 -2
- data/lib/tasks/solidus/split_promotions_with_any_match_policy.rake +33 -0
- data/solidus_core.gemspec +7 -2
- metadata +90 -24
- data/lib/generators/solidus/install/templates/vendor/assets/javascripts/spree/frontend/all.js +0 -10
- data/lib/generators/solidus/install/templates/vendor/assets/stylesheets/spree/frontend/all.css +0 -9
|
@@ -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
|
-
|
|
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
|
|
35
|
-
unless eligible_products.all? { |product| order.
|
|
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
|
|
39
|
-
unless order.
|
|
40
|
-
eligibility_errors.add(:base, eligibility_error_message(: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
|
|
43
|
-
unless order.
|
|
44
|
-
eligibility_errors.add(:base, eligibility_error_message(: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
|
|
@@ -8,6 +8,10 @@ module Spree
|
|
|
8
8
|
dependent: :destroy
|
|
9
9
|
has_many :taxons, through: :promotion_rule_taxons, class_name: 'Spree::Taxon'
|
|
10
10
|
|
|
11
|
+
def preload_relations
|
|
12
|
+
[:taxons]
|
|
13
|
+
end
|
|
14
|
+
|
|
11
15
|
MATCH_POLICIES = %w(any all none)
|
|
12
16
|
|
|
13
17
|
validates_inclusion_of :preferred_match_policy, in: MATCH_POLICIES
|
|
@@ -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.
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
where(
|
|
197
|
-
count
|
|
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
|
-
|
|
220
|
-
:
|
|
221
|
-
:
|
|
222
|
-
|
|
223
|
-
|
|
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.
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
|
|
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(
|
|
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 =
|
|
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::
|
|
95
|
+
Spree::Bus.publish :reimbursement_reimbursed, reimbursement: self
|
|
96
96
|
else
|
|
97
97
|
errored!
|
|
98
|
-
Spree::
|
|
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
|
|
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.
|
|
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.
|
|
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]
|
|
10
|
-
|
|
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 =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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(
|
|
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 =
|
|
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 :
|
|
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
|
-
@
|
|
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,
|
data/app/models/spree/variant.rb
CHANGED
|
@@ -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
|
|
@@ -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
|