solidus_legacy_promotions 4.6.2 → 4.7.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/Rakefile +14 -14
- data/app/jobs/spree/promotion_code_batch_job.rb +1 -1
- data/app/models/spree/calculator/distributed_amount.rb +1 -1
- data/app/models/spree/calculator/flat_percent_item_total.rb +1 -1
- data/app/models/spree/calculator/flexi_rate.rb +4 -4
- data/app/models/spree/calculator/percent_on_line_item.rb +1 -1
- data/app/models/spree/calculator/tiered_flat_rate.rb +2 -2
- data/app/models/spree/calculator/tiered_percent.rb +3 -3
- data/app/models/spree/order_promotion.rb +4 -4
- data/app/models/spree/promotion/actions/create_adjustment.rb +1 -1
- data/app/models/spree/promotion/actions/create_item_adjustments.rb +1 -1
- data/app/models/spree/promotion/actions/create_quantity_adjustments.rb +13 -9
- data/app/models/spree/promotion/actions/free_shipping.rb +1 -1
- data/app/models/spree/promotion/order_adjustments_recalculator.rb +11 -12
- data/app/models/spree/promotion/rules/first_repeat_purchase_since.rb +1 -1
- data/app/models/spree/promotion/rules/item_total.rb +8 -8
- data/app/models/spree/promotion/rules/minimum_quantity.rb +1 -1
- data/app/models/spree/promotion/rules/nth_order.rb +7 -7
- data/app/models/spree/promotion/rules/option_value.rb +4 -4
- data/app/models/spree/promotion/rules/product.rb +10 -10
- data/app/models/spree/promotion/rules/taxon.rb +13 -13
- data/app/models/spree/promotion/rules/user.rb +3 -3
- data/app/models/spree/promotion/rules/user_role.rb +2 -2
- data/app/models/spree/promotion.rb +22 -22
- data/app/models/spree/promotion_action.rb +3 -3
- data/app/models/spree/promotion_chooser.rb +1 -1
- data/app/models/spree/promotion_code/batch_builder.rb +2 -2
- data/app/models/spree/promotion_code.rb +10 -10
- data/app/models/spree/promotion_code_batch.rb +1 -1
- data/app/models/spree/promotion_handler/cart.rb +1 -1
- data/app/models/spree/promotion_handler/coupon.rb +4 -4
- data/app/models/spree/promotion_handler/page.rb +2 -2
- data/app/models/spree/promotion_handler/shipping.rb +15 -15
- data/app/models/spree/promotion_rule.rb +2 -2
- data/app/models/spree/promotion_rule_user.rb +2 -2
- data/app/patches/models/solidus_legacy_promotions/spree_adjustment_patch.rb +1 -1
- data/app/patches/models/solidus_legacy_promotions/spree_in_memory_order_updater_patch.rb +39 -0
- data/app/patches/models/solidus_legacy_promotions/spree_order_patch.rb +1 -1
- data/app/patches/models/solidus_legacy_promotions/spree_order_updater_patch.rb +18 -18
- data/app/subscribers/spree/order_promotion_subscriber.rb +2 -2
- data/config/routes.rb +1 -1
- data/db/migrate/20161017102621_create_spree_promotion_code_batch.rb +3 -3
- data/db/migrate/20190106184413_remove_code_from_spree_promotions.rb +3 -3
- data/db/migrate/20231027084517_add_order_promotions_foreign_key.rb +1 -1
- data/lib/components/admin/solidus_admin/promotion_categories/index/component.rb +12 -12
- data/lib/components/admin/solidus_admin/promotions/index/component.rb +17 -17
- data/lib/components/admin/solidus_legacy_promotions/orders/index/component.rb +3 -3
- data/lib/controllers/admin/solidus_admin/promotions_controller.rb +3 -3
- data/lib/controllers/backend/spree/admin/promotion_actions_controller.rb +6 -6
- data/lib/controllers/backend/spree/admin/promotion_code_batches_controller.rb +1 -1
- data/lib/controllers/backend/spree/admin/promotion_codes_controller.rb +2 -2
- data/lib/controllers/backend/spree/admin/promotion_rules_controller.rb +7 -7
- data/lib/controllers/backend/spree/admin/promotions_controller.rb +9 -9
- data/lib/solidus_legacy_promotions/configuration.rb +7 -7
- data/lib/solidus_legacy_promotions/engine.rb +4 -4
- data/lib/solidus_legacy_promotions/migrations/promotions_with_code_handlers.rb +6 -6
- data/lib/solidus_legacy_promotions/testing_support/factories/calculator_factory.rb +1 -1
- data/lib/solidus_legacy_promotions/testing_support/factories/order_promotion_factory.rb +1 -1
- data/lib/solidus_legacy_promotions/testing_support/factories/promotion_category_factory.rb +2 -2
- data/lib/solidus_legacy_promotions/testing_support/factories/promotion_code_factory.rb +1 -1
- data/lib/solidus_legacy_promotions/testing_support/factories/promotion_factory.rb +4 -4
- data/lib/solidus_legacy_promotions/testing_support/factory_bot.rb +1 -1
- data/lib/solidus_legacy_promotions.rb +1 -1
- data/lib/views/backend/spree/admin/promotion_code_batches/download.csv.ruby +1 -1
- data/lib/views/backend/spree/admin/promotion_codes/index.csv.ruby +1 -1
- data/solidus_legacy_promotions.gemspec +16 -16
- metadata +12 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1f4488328d1d0991ae51ae2ce26d9220df5dceca5662d6212158f0fba93803a6
|
|
4
|
+
data.tar.gz: c20347dd2b0b060f86b6b919ebb3ee4ce59b84a7e2f4a0140d71cb78bb5c35e8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fc6187c4f3f4eaee61588995c50efd9560a99cf03550b3840e3ebcc048c3990c61a92de5687981953bba626569623fc0f2ae7344f2d63ea8fbfe0e4aaa966d3d
|
|
7
|
+
data.tar.gz: 6ac7409390d658619c9131d70ded81c6f56d82cd12dbc420ec1d164476407206fefe0e0891b262204f651765bfe1e57326e974234a66570a6a05d83fb3c2b9d4
|
data/Rakefile
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
9
|
-
require
|
|
3
|
+
require "rubygems"
|
|
4
|
+
require "rake"
|
|
5
|
+
require "rake/testtask"
|
|
6
|
+
require "rspec/core/rake_task"
|
|
7
|
+
require "spree/testing_support/dummy_app/rake_tasks"
|
|
8
|
+
require "solidus_admin/testing_support/dummy_app/rake_tasks"
|
|
9
|
+
require "bundler/gem_tasks"
|
|
10
10
|
|
|
11
11
|
RSpec::Core::RakeTask.new
|
|
12
12
|
task default: :spec
|
|
13
13
|
|
|
14
14
|
DummyApp::RakeTasks.new(
|
|
15
15
|
gem_root: File.dirname(__FILE__),
|
|
16
|
-
lib_name:
|
|
16
|
+
lib_name: "solidus_legacy_promotions"
|
|
17
17
|
)
|
|
18
18
|
|
|
19
|
-
require
|
|
19
|
+
require "yard/rake/yardoc_task"
|
|
20
20
|
YARD::Rake::YardocTask.new(:yard)
|
|
21
21
|
# The following workaround can be removed
|
|
22
22
|
# once https://github.com/lsegal/yard/pull/1457 is merged.
|
|
23
|
-
task(
|
|
24
|
-
task yard:
|
|
23
|
+
task("yard:require") { require "yard" }
|
|
24
|
+
task yard: "yard:require"
|
|
25
25
|
|
|
26
26
|
namespace :spec do
|
|
27
27
|
task :isolated do
|
|
28
|
-
spec_files = Dir[
|
|
28
|
+
spec_files = Dir["spec/**/*_spec.rb"]
|
|
29
29
|
failed_specs =
|
|
30
30
|
spec_files.reject do |file|
|
|
31
31
|
puts "rspec #{file}"
|
|
32
|
-
system(
|
|
32
|
+
system("rspec", file)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
if !failed_specs.empty?
|
|
@@ -40,4 +40,4 @@ namespace :spec do
|
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
43
|
-
task test_app:
|
|
43
|
+
task test_app: "db:reset"
|
|
@@ -14,7 +14,7 @@ module Spree
|
|
|
14
14
|
.promotion_code_batch_finished(promotion_code_batch)
|
|
15
15
|
.deliver_now
|
|
16
16
|
end
|
|
17
|
-
rescue
|
|
17
|
+
rescue => error
|
|
18
18
|
if promotion_code_batch.email?
|
|
19
19
|
Spree::Config.promotions.promotion_code_batch_mailer_class
|
|
20
20
|
.promotion_code_batch_errored(promotion_code_batch)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_dependency
|
|
3
|
+
require_dependency "spree/calculator"
|
|
4
4
|
|
|
5
5
|
# This is a calculator for line item adjustment actions. It accepts a line item
|
|
6
6
|
# and calculates its weighted adjustment amount based on the value of the
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_dependency
|
|
3
|
+
require_dependency "spree/calculator"
|
|
4
4
|
|
|
5
5
|
module Spree
|
|
6
6
|
class Calculator::FlexiRate < Calculator
|
|
7
|
-
preference :first_item,
|
|
7
|
+
preference :first_item, :decimal, default: 0
|
|
8
8
|
preference :additional_item, :decimal, default: 0
|
|
9
|
-
preference :max_items,
|
|
10
|
-
preference :currency,
|
|
9
|
+
preference :max_items, :integer, default: 0
|
|
10
|
+
preference :currency, :string, default: -> { Spree::Config[:currency] }
|
|
11
11
|
|
|
12
12
|
def compute(object)
|
|
13
13
|
items_count = object.quantity
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_dependency
|
|
3
|
+
require_dependency "spree/calculator"
|
|
4
4
|
|
|
5
5
|
module Spree
|
|
6
6
|
class Calculator::TieredFlatRate < Calculator
|
|
@@ -39,7 +39,7 @@ module Spree
|
|
|
39
39
|
|
|
40
40
|
def preferred_tiers_content
|
|
41
41
|
if preferred_tiers.is_a? Hash
|
|
42
|
-
unless preferred_tiers.keys.all?{ |key| key.is_a?(Numeric) && key > 0 }
|
|
42
|
+
unless preferred_tiers.keys.all? { |key| key.is_a?(Numeric) && key > 0 }
|
|
43
43
|
errors.add(:base, :keys_should_be_positive_number)
|
|
44
44
|
end
|
|
45
45
|
else
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_dependency
|
|
3
|
+
require_dependency "spree/calculator"
|
|
4
4
|
|
|
5
5
|
module Spree
|
|
6
6
|
class Calculator::TieredPercent < Calculator
|
|
@@ -46,10 +46,10 @@ module Spree
|
|
|
46
46
|
|
|
47
47
|
def preferred_tiers_content
|
|
48
48
|
if preferred_tiers.is_a? Hash
|
|
49
|
-
unless preferred_tiers.keys.all?{ |key| key.is_a?(Numeric) && key > 0 }
|
|
49
|
+
unless preferred_tiers.keys.all? { |key| key.is_a?(Numeric) && key > 0 }
|
|
50
50
|
errors.add(:base, :keys_should_be_positive_number)
|
|
51
51
|
end
|
|
52
|
-
unless preferred_tiers.values.all?{ |key| key.is_a?(Numeric) && key >= 0 && key <= 100 }
|
|
52
|
+
unless preferred_tiers.values.all? { |key| key.is_a?(Numeric) && key >= 0 && key <= 100 }
|
|
53
53
|
errors.add(:base, :values_should_be_percent)
|
|
54
54
|
end
|
|
55
55
|
else
|
|
@@ -6,11 +6,11 @@ module Spree
|
|
|
6
6
|
# 1. A promotion that a user attempted to apply to their order
|
|
7
7
|
# 2. The specific code that they used
|
|
8
8
|
class OrderPromotion < Spree::Base
|
|
9
|
-
self.table_name =
|
|
9
|
+
self.table_name = "spree_orders_promotions"
|
|
10
10
|
|
|
11
|
-
belongs_to :order, class_name:
|
|
12
|
-
belongs_to :promotion, class_name:
|
|
13
|
-
belongs_to :promotion_code, class_name:
|
|
11
|
+
belongs_to :order, class_name: "Spree::Order", optional: true
|
|
12
|
+
belongs_to :promotion, class_name: "Spree::Promotion", optional: true
|
|
13
|
+
belongs_to :promotion_code, class_name: "Spree::PromotionCode", optional: true
|
|
14
14
|
|
|
15
15
|
validates :order, presence: true
|
|
16
16
|
validates :promotion, presence: true
|
|
@@ -34,7 +34,7 @@ module Spree
|
|
|
34
34
|
order:,
|
|
35
35
|
source: self,
|
|
36
36
|
promotion_code: options[:promotion_code],
|
|
37
|
-
label: I18n.t(
|
|
37
|
+
label: I18n.t("spree.adjustment_labels.order", promotion: Spree::Promotion.model_name.human, promotion_name: promotion.name)
|
|
38
38
|
)
|
|
39
39
|
true
|
|
40
40
|
end
|
|
@@ -66,7 +66,7 @@ module Spree
|
|
|
66
66
|
amount:,
|
|
67
67
|
order:,
|
|
68
68
|
promotion_code:,
|
|
69
|
-
label: I18n.t(
|
|
69
|
+
label: I18n.t("spree.adjustment_labels.line_item", promotion: Spree::Promotion.model_name.human, promotion_name: promotion.name)
|
|
70
70
|
)
|
|
71
71
|
true
|
|
72
72
|
end
|
|
@@ -63,9 +63,9 @@ module Spree
|
|
|
63
63
|
order = line_item.order
|
|
64
64
|
line_items = actionable_line_items(order)
|
|
65
65
|
|
|
66
|
-
actioned_line_items = order.line_item_adjustments.reload
|
|
67
|
-
select { |adjustment| adjustment.source == self && adjustment.amount < 0 }
|
|
68
|
-
map(&:adjustable)
|
|
66
|
+
actioned_line_items = order.line_item_adjustments.reload
|
|
67
|
+
.select { |adjustment| adjustment.source == self && adjustment.amount < 0 }
|
|
68
|
+
.map(&:adjustable)
|
|
69
69
|
other_line_items = actioned_line_items - [line_item]
|
|
70
70
|
|
|
71
71
|
applicable_quantity = total_applicable_quantity(line_items)
|
|
@@ -75,7 +75,7 @@ module Spree
|
|
|
75
75
|
line_item.quantity
|
|
76
76
|
].min
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
set_line_item_action_quantity(usable_quantity, line_item)
|
|
79
79
|
|
|
80
80
|
amount = adjustment_amount * usable_quantity
|
|
81
81
|
[line_item.amount, amount].min * -1
|
|
@@ -83,6 +83,11 @@ module Spree
|
|
|
83
83
|
|
|
84
84
|
private
|
|
85
85
|
|
|
86
|
+
def create_adjustment(adjustable, order, promotion_code)
|
|
87
|
+
return unless super
|
|
88
|
+
save!
|
|
89
|
+
end
|
|
90
|
+
|
|
86
91
|
def actionable_line_items(order)
|
|
87
92
|
order.line_items.select do |item|
|
|
88
93
|
promotion.line_item_actionable? order, item
|
|
@@ -97,17 +102,16 @@ module Spree
|
|
|
97
102
|
end
|
|
98
103
|
|
|
99
104
|
def total_used_quantity(line_items)
|
|
100
|
-
line_item_actions.
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
line_item_actions.select { |line_item_action|
|
|
106
|
+
line_items.map(&:id).include? line_item_action.line_item_id
|
|
107
|
+
}.sum(&:quantity)
|
|
103
108
|
end
|
|
104
109
|
|
|
105
|
-
def
|
|
110
|
+
def set_line_item_action_quantity(quantity, line_item)
|
|
106
111
|
line_item_action = line_item_actions.where(
|
|
107
112
|
line_item_id: line_item.id
|
|
108
113
|
).first_or_initialize
|
|
109
114
|
line_item_action.quantity = quantity
|
|
110
|
-
line_item_action.save!
|
|
111
115
|
end
|
|
112
116
|
|
|
113
117
|
##
|
|
@@ -13,12 +13,12 @@ module Spree
|
|
|
13
13
|
@order = order
|
|
14
14
|
end
|
|
15
15
|
|
|
16
|
-
def call
|
|
16
|
+
def call(persist: true)
|
|
17
17
|
all_items = line_items + shipments
|
|
18
18
|
all_items.each do |item|
|
|
19
19
|
promotion_adjustments = item.adjustments.select(&:promotion?)
|
|
20
20
|
|
|
21
|
-
promotion_adjustments.each { |adjustment| recalculate(adjustment) }
|
|
21
|
+
promotion_adjustments.each { |adjustment| recalculate(adjustment, persist:) }
|
|
22
22
|
Spree::Config.promotions.promotion_chooser_class.new(promotion_adjustments).update
|
|
23
23
|
|
|
24
24
|
item.promo_total = promotion_adjustments.select(&:eligible?).sum(&:amount)
|
|
@@ -28,14 +28,16 @@ module Spree
|
|
|
28
28
|
# in #update_adjustment_total since they include the totals from the order's
|
|
29
29
|
# line items and/or shipments.
|
|
30
30
|
order_promotion_adjustments = order.adjustments.select(&:promotion?)
|
|
31
|
-
order_promotion_adjustments.each { |adjustment| recalculate(adjustment) }
|
|
31
|
+
order_promotion_adjustments.each { |adjustment| recalculate(adjustment, persist:) }
|
|
32
32
|
Spree::Config.promotions.promotion_chooser_class.new(order_promotion_adjustments).update
|
|
33
33
|
|
|
34
34
|
order.promo_total = all_items.sum(&:promo_total) +
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
order_promotion_adjustments
|
|
36
|
+
.select(&:eligible?)
|
|
37
|
+
.select(&:promotion?)
|
|
38
|
+
.sum(&:amount)
|
|
39
|
+
|
|
40
|
+
order.save! if persist
|
|
39
41
|
order
|
|
40
42
|
end
|
|
41
43
|
|
|
@@ -52,7 +54,7 @@ module Spree
|
|
|
52
54
|
# admin) or is closed, this is a noop.
|
|
53
55
|
#
|
|
54
56
|
# @return [BigDecimal] New amount of this adjustment
|
|
55
|
-
def recalculate(adjustment)
|
|
57
|
+
def recalculate(adjustment, persist:)
|
|
56
58
|
if adjustment.finalized?
|
|
57
59
|
return adjustment.amount
|
|
58
60
|
end
|
|
@@ -68,10 +70,7 @@ module Spree
|
|
|
68
70
|
|
|
69
71
|
adjustment.eligible = calculate_eligibility(adjustment)
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
# This is only not a save! to avoid the extra queries to load the order
|
|
73
|
-
# (for validations) and to touch the adjustment.
|
|
74
|
-
adjustment.update_columns(eligible: adjustment.eligible, amount: adjustment.amount, updated_at: Time.current) if adjustment.changed?
|
|
73
|
+
adjustment.save!(validate: false) if persist
|
|
75
74
|
end
|
|
76
75
|
adjustment.amount
|
|
77
76
|
end
|
|
@@ -5,7 +5,7 @@ module Spree
|
|
|
5
5
|
module Rules
|
|
6
6
|
class FirstRepeatPurchaseSince < PromotionRule
|
|
7
7
|
preference :days_ago, :integer, default: 365
|
|
8
|
-
validates :preferred_days_ago, numericality: {
|
|
8
|
+
validates :preferred_days_ago, numericality: {only_integer: true, greater_than: 0}
|
|
9
9
|
|
|
10
10
|
# This promotion is applicable to orders only.
|
|
11
11
|
def applicable?(promotable)
|
|
@@ -10,20 +10,20 @@ module Spree
|
|
|
10
10
|
# To customize the error message you can also override `ineligible_message`.
|
|
11
11
|
class ItemTotal < PromotionRule
|
|
12
12
|
preference :amount, :decimal, default: 100.00
|
|
13
|
-
preference :currency, :string, default: ->{ Spree::Config[:currency] }
|
|
14
|
-
preference :operator, :string, default:
|
|
13
|
+
preference :currency, :string, default: -> { Spree::Config[:currency] }
|
|
14
|
+
preference :operator, :string, default: "gt"
|
|
15
15
|
|
|
16
16
|
# The list of allowed operators names mapped to their symbols.
|
|
17
17
|
def self.operators_map
|
|
18
18
|
{
|
|
19
19
|
gte: :>=,
|
|
20
|
-
gt:
|
|
20
|
+
gt: :>
|
|
21
21
|
}
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def self.operator_options
|
|
25
25
|
operators_map.map do |name, _method|
|
|
26
|
-
[I18n.t(name, scope:
|
|
26
|
+
[I18n.t(name, scope: "spree.item_total_rule.operators"), name]
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -46,7 +46,7 @@ module Spree
|
|
|
46
46
|
def operator
|
|
47
47
|
self.class.operators_map.fetch(
|
|
48
48
|
preferred_operator.to_sym,
|
|
49
|
-
preferred_operator_default
|
|
49
|
+
preferred_operator_default
|
|
50
50
|
)
|
|
51
51
|
end
|
|
52
52
|
|
|
@@ -64,9 +64,9 @@ module Spree
|
|
|
64
64
|
|
|
65
65
|
def ineligible_message
|
|
66
66
|
case preferred_operator.to_s
|
|
67
|
-
when
|
|
67
|
+
when "gte"
|
|
68
68
|
eligibility_error_message(:item_total_less_than, amount: formatted_amount)
|
|
69
|
-
when
|
|
69
|
+
when "gt"
|
|
70
70
|
eligibility_error_message(:item_total_less_than_or_equal, amount: formatted_amount)
|
|
71
71
|
else
|
|
72
72
|
eligibility_error_message(:item_total_doesnt_match_with_operator, amount: formatted_amount, operator: preferred_operator)
|
|
@@ -74,7 +74,7 @@ module Spree
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def ineligible_error_code
|
|
77
|
-
if preferred_operator ==
|
|
77
|
+
if preferred_operator == "gte"
|
|
78
78
|
:item_total_less_than
|
|
79
79
|
else
|
|
80
80
|
:item_total_less_than_or_equal
|
|
@@ -11,7 +11,7 @@ module Spree
|
|
|
11
11
|
# it to a simple quantity check across the entire order which would be
|
|
12
12
|
# better served by an item total rule.
|
|
13
13
|
class MinimumQuantity < PromotionRule
|
|
14
|
-
validates :preferred_minimum_quantity, numericality: {
|
|
14
|
+
validates :preferred_minimum_quantity, numericality: {only_integer: true, greater_than: 0}
|
|
15
15
|
|
|
16
16
|
preference :minimum_quantity, :integer, default: 1
|
|
17
17
|
|
|
@@ -7,7 +7,7 @@ module Spree
|
|
|
7
7
|
preference :nth_order, :integer, default: 2
|
|
8
8
|
# It does not make sense to have this apply to the first order using preferred_nth_order == 1
|
|
9
9
|
# Instead we could use the first_order rule
|
|
10
|
-
validates :preferred_nth_order, numericality: {
|
|
10
|
+
validates :preferred_nth_order, numericality: {only_integer: true, greater_than: 1}
|
|
11
11
|
|
|
12
12
|
# This promotion is applicable to orders only.
|
|
13
13
|
def applicable?(promotable)
|
|
@@ -27,12 +27,12 @@ module Spree
|
|
|
27
27
|
private
|
|
28
28
|
|
|
29
29
|
def completed_order_count(order)
|
|
30
|
-
order
|
|
31
|
-
user
|
|
32
|
-
orders
|
|
33
|
-
complete
|
|
34
|
-
where(Spree::Order.arel_table[:completed_at].lt(order.completed_at || Time.current))
|
|
35
|
-
count
|
|
30
|
+
order
|
|
31
|
+
.user
|
|
32
|
+
.orders
|
|
33
|
+
.complete
|
|
34
|
+
.where(Spree::Order.arel_table[:completed_at].lt(order.completed_at || Time.current))
|
|
35
|
+
.count
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def nth_order?(order)
|
|
@@ -4,7 +4,7 @@ module Spree
|
|
|
4
4
|
class Promotion < Spree::Base
|
|
5
5
|
module Rules
|
|
6
6
|
class OptionValue < PromotionRule
|
|
7
|
-
MATCH_POLICIES = %w
|
|
7
|
+
MATCH_POLICIES = %w[any]
|
|
8
8
|
preference :match_policy, :string, default: MATCH_POLICIES.first
|
|
9
9
|
preference :eligible_values, :hash
|
|
10
10
|
|
|
@@ -14,7 +14,7 @@ module Spree
|
|
|
14
14
|
|
|
15
15
|
def eligible?(promotable, _options = {})
|
|
16
16
|
case preferred_match_policy
|
|
17
|
-
when
|
|
17
|
+
when "any"
|
|
18
18
|
promotable.line_items.any? { |item| actionable?(item) }
|
|
19
19
|
end
|
|
20
20
|
end
|
|
@@ -28,11 +28,11 @@ module Spree
|
|
|
28
28
|
|
|
29
29
|
def preferred_eligible_values
|
|
30
30
|
values = preferences[:eligible_values] || {}
|
|
31
|
-
|
|
31
|
+
values.keys.map(&:to_i).zip(
|
|
32
32
|
values.values.map do |value|
|
|
33
33
|
(value.is_a?(Array) ? value : value.split(",")).map(&:to_i)
|
|
34
34
|
end
|
|
35
|
-
)
|
|
35
|
+
).to_h
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
private
|
|
@@ -11,17 +11,17 @@ module Spree
|
|
|
11
11
|
has_many :product_promotion_rules,
|
|
12
12
|
dependent: :destroy,
|
|
13
13
|
foreign_key: :promotion_rule_id,
|
|
14
|
-
class_name:
|
|
14
|
+
class_name: "Spree::ProductPromotionRule",
|
|
15
15
|
inverse_of: :promotion_rule
|
|
16
|
-
has_many :products, class_name:
|
|
16
|
+
has_many :products, class_name: "Spree::Product", through: :product_promotion_rules
|
|
17
17
|
|
|
18
18
|
def preload_relations
|
|
19
19
|
[:products]
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
MATCH_POLICIES = %w
|
|
22
|
+
MATCH_POLICIES = %w[any all none]
|
|
23
23
|
|
|
24
|
-
validates :preferred_match_policy, inclusion: {
|
|
24
|
+
validates :preferred_match_policy, inclusion: {in: MATCH_POLICIES}
|
|
25
25
|
|
|
26
26
|
preference :match_policy, :string, default: MATCH_POLICIES.first
|
|
27
27
|
|
|
@@ -45,12 +45,12 @@ module Spree
|
|
|
45
45
|
when "any"
|
|
46
46
|
unless order_products(order).any? { |product| eligible_products.include?(product) }
|
|
47
47
|
eligibility_errors.add(:base, eligibility_error_message(:no_applicable_products),
|
|
48
|
-
|
|
48
|
+
error_code: :no_applicable_products)
|
|
49
49
|
end
|
|
50
50
|
when "none"
|
|
51
51
|
unless order_products(order).none? { |product| eligible_products.include?(product) }
|
|
52
52
|
eligibility_errors.add(:base, eligibility_error_message(:has_excluded_product),
|
|
53
|
-
|
|
53
|
+
error_code: :has_excluded_product)
|
|
54
54
|
end
|
|
55
55
|
else
|
|
56
56
|
raise "unexpected match policy: #{preferred_match_policy.inspect}"
|
|
@@ -61,9 +61,9 @@ module Spree
|
|
|
61
61
|
|
|
62
62
|
def actionable?(line_item)
|
|
63
63
|
case preferred_match_policy
|
|
64
|
-
when
|
|
64
|
+
when "any", "all"
|
|
65
65
|
product_ids.include? line_item.variant.product_id
|
|
66
|
-
when
|
|
66
|
+
when "none"
|
|
67
67
|
product_ids.exclude? line_item.variant.product_id
|
|
68
68
|
else
|
|
69
69
|
raise "unexpected match policy: #{preferred_match_policy.inspect}"
|
|
@@ -71,11 +71,11 @@ module Spree
|
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
def product_ids_string
|
|
74
|
-
product_ids.join(
|
|
74
|
+
product_ids.join(",")
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def product_ids_string=(product_ids)
|
|
78
|
-
self.product_ids = product_ids.to_s.split(
|
|
78
|
+
self.product_ids = product_ids.to_s.split(",").map(&:strip)
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
private
|
|
@@ -5,19 +5,19 @@ module Spree
|
|
|
5
5
|
module Rules
|
|
6
6
|
class Taxon < PromotionRule
|
|
7
7
|
has_many :promotion_rule_taxons,
|
|
8
|
-
class_name:
|
|
8
|
+
class_name: "Spree::PromotionRuleTaxon",
|
|
9
9
|
foreign_key: :promotion_rule_id,
|
|
10
10
|
dependent: :destroy,
|
|
11
11
|
inverse_of: :promotion_rule
|
|
12
|
-
has_many :taxons, through: :promotion_rule_taxons, class_name:
|
|
12
|
+
has_many :taxons, through: :promotion_rule_taxons, class_name: "Spree::Taxon"
|
|
13
13
|
|
|
14
14
|
def preload_relations
|
|
15
15
|
[:taxons]
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
MATCH_POLICIES = %w
|
|
18
|
+
MATCH_POLICIES = %w[any all none]
|
|
19
19
|
|
|
20
|
-
validates :preferred_match_policy, inclusion: {
|
|
20
|
+
validates :preferred_match_policy, inclusion: {in: MATCH_POLICIES}
|
|
21
21
|
|
|
22
22
|
preference :match_policy, :string, default: MATCH_POLICIES.first
|
|
23
23
|
def applicable?(promotable)
|
|
@@ -28,7 +28,7 @@ module Spree
|
|
|
28
28
|
order_taxons = taxons_in_order(order)
|
|
29
29
|
|
|
30
30
|
case preferred_match_policy
|
|
31
|
-
when
|
|
31
|
+
when "all"
|
|
32
32
|
matches_all = taxons.all? do |rule_taxon|
|
|
33
33
|
order_taxons.where(id: rule_taxon.self_and_descendants.ids).exists?
|
|
34
34
|
end
|
|
@@ -36,11 +36,11 @@ module Spree
|
|
|
36
36
|
unless matches_all
|
|
37
37
|
eligibility_errors.add(:base, eligibility_error_message(:missing_taxon), error_code: :missing_taxon)
|
|
38
38
|
end
|
|
39
|
-
when
|
|
39
|
+
when "any"
|
|
40
40
|
unless order_taxons.where(id: rule_taxon_ids_with_children).exists?
|
|
41
41
|
eligibility_errors.add(:base, eligibility_error_message(:no_matching_taxons), error_code: :no_matching_taxons)
|
|
42
42
|
end
|
|
43
|
-
when
|
|
43
|
+
when "none"
|
|
44
44
|
if order_taxons.where(id: rule_taxon_ids_with_children).exists?
|
|
45
45
|
eligibility_errors.add(:base, eligibility_error_message(:has_excluded_taxon), error_code: :has_excluded_taxon)
|
|
46
46
|
end
|
|
@@ -58,9 +58,9 @@ module Spree
|
|
|
58
58
|
).exists?
|
|
59
59
|
|
|
60
60
|
case preferred_match_policy
|
|
61
|
-
when
|
|
61
|
+
when "any", "all"
|
|
62
62
|
found
|
|
63
|
-
when
|
|
63
|
+
when "none"
|
|
64
64
|
!found
|
|
65
65
|
else
|
|
66
66
|
raise "unexpected match policy: #{preferred_match_policy.inspect}"
|
|
@@ -68,11 +68,11 @@ module Spree
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def taxon_ids_string
|
|
71
|
-
taxons.pluck(:id).join(
|
|
71
|
+
taxons.pluck(:id).join(",")
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
def taxon_ids_string=(taxon_ids)
|
|
75
|
-
taxon_ids = taxon_ids.to_s.split(
|
|
75
|
+
taxon_ids = taxon_ids.to_s.split(",").map(&:strip)
|
|
76
76
|
self.taxons = Spree::Taxon.find(taxon_ids)
|
|
77
77
|
end
|
|
78
78
|
|
|
@@ -80,8 +80,8 @@ module Spree
|
|
|
80
80
|
|
|
81
81
|
# All taxons in an order
|
|
82
82
|
def taxons_in_order(order)
|
|
83
|
-
Spree::Taxon.joins(products: {
|
|
84
|
-
.where(spree_line_items: {
|
|
83
|
+
Spree::Taxon.joins(products: {variants_including_master: :line_items})
|
|
84
|
+
.where(spree_line_items: {order_id: order.id}).distinct
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
# ids of taxons rules and taxons rules children
|
|
@@ -5,7 +5,7 @@ module Spree
|
|
|
5
5
|
module Rules
|
|
6
6
|
class User < PromotionRule
|
|
7
7
|
has_many :promotion_rule_users,
|
|
8
|
-
class_name:
|
|
8
|
+
class_name: "Spree::PromotionRuleUser",
|
|
9
9
|
foreign_key: :promotion_rule_id,
|
|
10
10
|
dependent: :destroy,
|
|
11
11
|
inverse_of: :promotion_rule
|
|
@@ -24,11 +24,11 @@ module Spree
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def user_ids_string
|
|
27
|
-
user_ids.join(
|
|
27
|
+
user_ids.join(",")
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def user_ids_string=(user_ids)
|
|
31
|
-
self.user_ids = user_ids.to_s.split(
|
|
31
|
+
self.user_ids = user_ids.to_s.split(",").map(&:strip)
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
end
|
|
@@ -6,7 +6,7 @@ module Spree
|
|
|
6
6
|
class UserRole < PromotionRule
|
|
7
7
|
preference :role_ids, :array, default: []
|
|
8
8
|
|
|
9
|
-
MATCH_POLICIES = %w
|
|
9
|
+
MATCH_POLICIES = %w[any all]
|
|
10
10
|
preference :match_policy, default: MATCH_POLICIES.first
|
|
11
11
|
|
|
12
12
|
def applicable?(promotable)
|
|
@@ -25,7 +25,7 @@ module Spree
|
|
|
25
25
|
private
|
|
26
26
|
|
|
27
27
|
def all_match_policy?
|
|
28
|
-
preferred_match_policy ==
|
|
28
|
+
preferred_match_policy == "all" && preferred_role_ids.present?
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def user_roles(order)
|