solidus_core 4.3.5 → 4.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/helpers/spree/base_helper.rb +2 -2
- data/app/mailers/spree/base_mailer.rb +1 -1
- data/app/mailers/spree/carton_mailer.rb +1 -1
- data/app/mailers/spree/order_mailer.rb +3 -3
- data/app/mailers/spree/reimbursement_mailer.rb +1 -1
- data/app/models/concerns/spree/active_storage_adapter/normalization.rb +1 -1
- data/app/models/concerns/spree/active_storage_adapter.rb +1 -1
- data/app/models/concerns/spree/display_money.rb +1 -1
- data/app/models/concerns/spree/ordered_property_value_list.rb +2 -2
- data/app/models/concerns/spree/user_address_book.rb +4 -4
- data/app/models/concerns/spree/user_methods.rb +3 -3
- data/app/models/spree/address.rb +6 -6
- data/app/models/spree/adjustment.rb +13 -66
- data/app/models/spree/calculator/returns/default_refund_amount.rb +1 -1
- data/app/models/spree/carton.rb +2 -2
- data/app/models/spree/credit_card.rb +6 -6
- data/app/models/spree/deprecated_configurable_class.rb +40 -0
- data/app/models/spree/fulfilment_changer.rb +4 -4
- data/app/models/spree/inventory_unit.rb +2 -2
- data/app/models/spree/line_item.rb +1 -4
- data/app/models/spree/null_promotion_adjuster.rb +13 -0
- data/app/models/spree/null_promotion_advertiser.rb +9 -0
- data/app/models/spree/null_promotion_finder.rb +9 -0
- data/app/models/spree/null_promotion_handler.rb +44 -0
- data/app/models/spree/order.rb +15 -22
- data/app/models/spree/order_cancellations.rb +8 -8
- data/app/models/spree/order_mutex.rb +2 -2
- data/app/models/spree/order_shipping.rb +9 -9
- data/app/models/spree/order_updater.rb +6 -10
- data/app/models/spree/payment/processing.rb +2 -2
- data/app/models/spree/payment.rb +2 -2
- data/app/models/spree/payment_create.rb +1 -1
- data/app/models/spree/payment_method/store_credit.rb +1 -1
- data/app/models/spree/payment_source.rb +5 -1
- data/app/models/spree/permission_set.rb +11 -0
- data/app/models/spree/product.rb +7 -28
- data/app/models/spree/refund.rb +1 -1
- data/app/models/spree/reimbursement.rb +4 -4
- data/app/models/spree/reimbursement_performer.rb +3 -3
- data/app/models/spree/reimbursement_tax_calculator.rb +2 -2
- data/app/models/spree/reimbursement_type/credit.rb +1 -1
- data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +6 -6
- data/app/models/spree/reimbursement_type/store_credit.rb +1 -1
- data/app/models/spree/return_item.rb +9 -9
- data/app/models/spree/role.rb +3 -1
- data/app/models/spree/role_permission.rb +8 -0
- data/app/models/spree/shipment.rb +7 -7
- data/app/models/spree/shipping_category.rb +2 -0
- data/app/models/spree/shipping_rate.rb +1 -1
- data/app/models/spree/{order_contents.rb → simple_order_contents.rb} +4 -11
- data/app/models/spree/stock/estimator.rb +1 -1
- data/app/models/spree/stock/inventory_unit_builder.rb +1 -1
- data/app/models/spree/stock/package.rb +2 -2
- data/app/models/spree/stock/simple_coordinator.rb +1 -1
- data/app/models/spree/stock_location.rb +5 -5
- data/app/models/spree/store.rb +1 -1
- data/app/models/spree/store_credit.rb +15 -15
- data/app/models/spree/store_credit_event.rb +3 -3
- data/app/models/spree/tax_calculator/default.rb +2 -2
- data/app/models/spree/tax_calculator/shipping_rate.rb +1 -1
- data/app/models/spree/tax_category.rb +3 -1
- data/app/models/spree/tax_rate.rb +3 -3
- data/app/models/spree/taxonomy.rb +2 -2
- data/app/models/spree/unit_cancel.rb +1 -2
- data/app/models/spree/variant/vat_price_generator.rb +1 -1
- data/app/models/spree/variant.rb +7 -2
- data/app/models/spree/wallet.rb +2 -2
- data/app/views/spree/order_mailer/cancel_email.html.erb +1 -1
- data/app/views/spree/order_mailer/cancel_email.text.erb +1 -1
- data/app/views/spree/order_mailer/confirm_email.html.erb +5 -5
- data/app/views/spree/order_mailer/confirm_email.text.erb +5 -5
- data/config/locales/en.yml +4 -90
- data/db/default/spree/permission_sets.rb +10 -0
- data/db/default/spree/return_reasons.rb +3 -1
- data/db/default/spree/states.rb +1 -1
- data/db/migrate/20160101010000_solidus_one_four.rb +0 -127
- data/db/migrate/20240821173254_create_spree_permission_sets_in_core.rb +9 -0
- data/db/migrate/20240821173341_create_spree_roles_permissions_in_core.rb +9 -0
- data/db/migrate/20240821173641_add_description_to_spree_roles.rb +5 -0
- data/db/migrate/20240904152041_add_privilege_and_category_to_spree_permission_sets.rb +6 -0
- data/db/seeds.rb +1 -0
- data/lib/generators/solidus/install/app_templates/frontend/starter.rb +1 -1
- data/lib/generators/solidus/update/update_generator.rb +1 -1
- data/lib/generators/spree/dummy/templates/rails/test.rb +6 -1
- data/lib/spree/app_configuration.rb +53 -84
- data/lib/spree/core/class_constantizer.rb +2 -2
- data/lib/spree/core/controller_helpers/payment_parameters.rb +1 -1
- data/lib/spree/core/engine.rb +1 -0
- data/lib/spree/core/environment/calculators.rb +35 -3
- data/lib/spree/core/environment/promotions.rb +25 -4
- data/lib/spree/core/environment_extension.rb +16 -2
- data/lib/spree/core/importer/order.rb +5 -5
- data/lib/spree/core/importer/product.rb +3 -3
- data/lib/spree/core/nested_class_set.rb +28 -0
- data/lib/spree/core/null_promotion_configuration.rb +84 -0
- data/lib/spree/core/product_filters.rb +1 -1
- data/lib/spree/core/search/variant.rb +2 -2
- data/lib/spree/core/state_machines/order.rb +0 -1
- data/lib/spree/core/validators/email.rb +1 -1
- data/lib/spree/core/version.rb +2 -2
- data/lib/spree/core.rb +2 -6
- data/lib/spree/deprecator.rb +9 -0
- data/lib/spree/i18n.rb +1 -1
- data/lib/spree/mailer_previews/carton_preview.rb +1 -1
- data/lib/spree/permission_sets/base.rb +13 -1
- data/lib/spree/permission_sets/configuration_display.rb +10 -0
- data/lib/spree/permission_sets/configuration_management.rb +10 -0
- data/lib/spree/permission_sets/dashboard_display.rb +12 -0
- data/lib/spree/permission_sets/default_customer.rb +11 -1
- data/lib/spree/permission_sets/order_display.rb +10 -0
- data/lib/spree/permission_sets/order_management.rb +10 -0
- data/lib/spree/permission_sets/product_display.rb +10 -0
- data/lib/spree/permission_sets/product_management.rb +10 -0
- data/lib/spree/permission_sets/restricted_stock_display.rb +10 -0
- data/lib/spree/permission_sets/restricted_stock_management.rb +10 -0
- data/lib/spree/permission_sets/stock_display.rb +10 -0
- data/lib/spree/permission_sets/stock_management.rb +10 -0
- data/lib/spree/permission_sets/super_user.rb +10 -0
- data/lib/spree/permission_sets/user_display.rb +10 -0
- data/lib/spree/permission_sets/user_management.rb +10 -0
- data/lib/spree/permission_sets.rb +0 -2
- data/lib/spree/permitted_attributes.rb +2 -2
- data/lib/spree/preferences/store.rb +2 -2
- data/lib/spree/testing_support/capybara_ext.rb +1 -1
- data/lib/spree/testing_support/dummy_ability.rb +7 -0
- data/lib/spree/testing_support/dummy_app/database.yml +2 -2
- data/lib/spree/testing_support/dummy_app/migrations.rb +8 -15
- data/lib/spree/testing_support/dummy_app/rake_tasks.rb +2 -2
- data/lib/spree/testing_support/dummy_app.rb +17 -12
- data/lib/spree/testing_support/factories/adjustment_factory.rb +1 -2
- data/lib/spree/testing_support/factories/calculator_factory.rb +1 -5
- data/lib/spree/testing_support/factories/carton_factory.rb +2 -2
- data/lib/spree/testing_support/factories/customer_return_factory.rb +2 -2
- data/lib/spree/testing_support/factories/inventory_unit_factory.rb +3 -3
- data/lib/spree/testing_support/factories/order_factory.rb +5 -24
- data/lib/spree/testing_support/factories/product_factory.rb +1 -1
- data/lib/spree/testing_support/factories/shipment_factory.rb +1 -1
- data/lib/spree/testing_support/factories/stock_item_factory.rb +5 -1
- data/lib/spree/testing_support/factories/stock_package_factory.rb +1 -1
- data/lib/spree/testing_support/factories/user_factory.rb +1 -1
- data/lib/spree/testing_support/factories/zone_factory.rb +1 -1
- data/lib/spree/testing_support/order_walkthrough.rb +3 -3
- data/lib/spree/testing_support/shared_examples/calculator.rb +10 -0
- data/lib/spree/testing_support/shared_examples/order_factory.rb +141 -0
- data/lib/spree/testing_support/shared_examples/working_factory.rb +15 -0
- data/lib/tasks/colorado_delivery_fee.rake +2 -2
- data/solidus_core.gemspec +7 -7
- metadata +60 -93
- data/app/jobs/spree/promotion_code_batch_job.rb +0 -26
- data/app/mailers/spree/promotion_code_batch_mailer.rb +0 -15
- data/app/models/spree/calculator/distributed_amount.rb +0 -33
- data/app/models/spree/calculator/flat_percent_item_total.rb +0 -23
- data/app/models/spree/calculator/flexi_rate.rb +0 -22
- data/app/models/spree/calculator/percent_on_line_item.rb +0 -13
- data/app/models/spree/calculator/tiered_flat_rate.rb +0 -52
- data/app/models/spree/calculator/tiered_percent.rb +0 -62
- data/app/models/spree/line_item_action.rb +0 -8
- data/app/models/spree/order_promotion.rb +0 -27
- data/app/models/spree/promotion/actions/create_adjustment.rb +0 -81
- data/app/models/spree/promotion/actions/create_item_adjustments.rb +0 -98
- data/app/models/spree/promotion/actions/create_quantity_adjustments.rb +0 -139
- data/app/models/spree/promotion/actions/free_shipping.rb +0 -59
- data/app/models/spree/promotion/order_adjustments_recalculator.rb +0 -92
- data/app/models/spree/promotion/rules/first_order.rb +0 -38
- data/app/models/spree/promotion/rules/first_repeat_purchase_since.rb +0 -36
- data/app/models/spree/promotion/rules/item_total.rb +0 -86
- data/app/models/spree/promotion/rules/minimum_quantity.rb +0 -59
- data/app/models/spree/promotion/rules/nth_order.rb +0 -45
- data/app/models/spree/promotion/rules/one_use_per_user.rb +0 -25
- data/app/models/spree/promotion/rules/option_value.rb +0 -50
- data/app/models/spree/promotion/rules/product.rb +0 -86
- data/app/models/spree/promotion/rules/store.rb +0 -26
- data/app/models/spree/promotion/rules/taxon.rb +0 -91
- data/app/models/spree/promotion/rules/user.rb +0 -34
- data/app/models/spree/promotion/rules/user_logged_in.rb +0 -20
- data/app/models/spree/promotion/rules/user_role.rb +0 -45
- data/app/models/spree/promotion.rb +0 -271
- data/app/models/spree/promotion_action.rb +0 -47
- data/app/models/spree/promotion_category.rb +0 -8
- data/app/models/spree/promotion_chooser.rb +0 -34
- data/app/models/spree/promotion_code/batch_builder.rb +0 -64
- data/app/models/spree/promotion_code.rb +0 -54
- data/app/models/spree/promotion_code_batch.rb +0 -27
- data/app/models/spree/promotion_handler/cart.rb +0 -75
- data/app/models/spree/promotion_handler/coupon.rb +0 -123
- data/app/models/spree/promotion_handler/page.rb +0 -26
- data/app/models/spree/promotion_handler/shipping.rb +0 -61
- data/app/models/spree/promotion_rule.rb +0 -55
- data/app/models/spree/promotion_rule_store.rb +0 -10
- data/app/models/spree/promotion_rule_taxon.rb +0 -8
- data/app/models/spree/promotion_rule_user.rb +0 -10
- data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_errored.text.erb +0 -2
- data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_finished.text.erb +0 -2
- data/bin/rails +0 -13
- data/db/migrate/20161017102621_create_spree_promotion_code_batch.rb +0 -38
- data/db/migrate/20180202190713_create_promotion_rule_stores.rb +0 -12
- data/db/migrate/20180328172631_add_join_characters_to_promotion_code_batch.rb +0 -11
- data/db/migrate/20190106184413_remove_code_from_spree_promotions.rb +0 -42
- data/db/migrate/20220317165036_set_promotions_with_any_policy_to_all_if_possible.rb +0 -20
- data/db/migrate/20230322085416_remove_match_policy_from_spree_promotion.rb +0 -5
- data/db/migrate/20230325132905_remove_unused_columns_from_promotion_rules.rb +0 -6
- data/db/migrate/20230325161633_drop_unused_promo_action_line_items.rb +0 -13
- data/db/migrate/20231027084517_add_order_promotions_foreign_key.rb +0 -10
- data/db/migrate/20231031175215_add_promotion_order_promotion_foreign_key.rb +0 -10
- data/lib/solidus/migrations/promotions_with_code_handlers.rb +0 -66
- data/lib/spree/permission_sets/promotion_display.rb +0 -25
- data/lib/spree/permission_sets/promotion_management.rb +0 -25
- data/lib/spree/ransack_4_1_patch.rb +0 -16
- data/lib/spree/testing_support/factories/order_promotion_factory.rb +0 -8
- data/lib/spree/testing_support/factories/promotion_category_factory.rb +0 -7
- data/lib/spree/testing_support/factories/promotion_code_factory.rb +0 -8
- data/lib/spree/testing_support/factories/promotion_factory.rb +0 -98
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion < Spree::Base
|
5
|
-
module Rules
|
6
|
-
class FirstRepeatPurchaseSince < PromotionRule
|
7
|
-
preference :days_ago, :integer, default: 365
|
8
|
-
validates :preferred_days_ago, numericality: { only_integer: true, greater_than: 0 }
|
9
|
-
|
10
|
-
# This promotion is applicable to orders only.
|
11
|
-
def applicable?(promotable)
|
12
|
-
promotable.is_a?(Spree::Order)
|
13
|
-
end
|
14
|
-
|
15
|
-
# This is never eligible if the order does not have a user, and that user does not have any previous completed orders.
|
16
|
-
#
|
17
|
-
# This is eligible if the user's most recently completed order is more than the preferred days ago
|
18
|
-
# @param order [Spree::Order]
|
19
|
-
def eligible?(order, _options = {})
|
20
|
-
return false unless order.user
|
21
|
-
|
22
|
-
last_order = last_completed_order(order.user)
|
23
|
-
return false unless last_order
|
24
|
-
|
25
|
-
last_order.completed_at < preferred_days_ago.days.ago
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def last_completed_order(user)
|
31
|
-
user.orders.complete.order(:completed_at).last
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion < Spree::Base
|
5
|
-
module Rules
|
6
|
-
# A rule to apply to an order greater than (or greater than or equal to)
|
7
|
-
# a specific amount
|
8
|
-
#
|
9
|
-
# To add extra operators please override `self.operators_map` or any other helper method.
|
10
|
-
# To customize the error message you can also override `ineligible_message`.
|
11
|
-
class ItemTotal < PromotionRule
|
12
|
-
preference :amount, :decimal, default: 100.00
|
13
|
-
preference :currency, :string, default: ->{ Spree::Config[:currency] }
|
14
|
-
preference :operator, :string, default: 'gt'
|
15
|
-
|
16
|
-
# The list of allowed operators names mapped to their symbols.
|
17
|
-
def self.operators_map
|
18
|
-
{
|
19
|
-
gte: :>=,
|
20
|
-
gt: :>,
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.operator_options
|
25
|
-
operators_map.map do |name, _method|
|
26
|
-
[I18n.t(name, scope: 'spree.item_total_rule.operators'), name]
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def applicable?(promotable)
|
31
|
-
promotable.is_a?(Spree::Order)
|
32
|
-
end
|
33
|
-
|
34
|
-
def eligible?(order, _options = {})
|
35
|
-
return false unless order.currency == preferred_currency
|
36
|
-
|
37
|
-
unless total_for_order(order).send(operator, threshold)
|
38
|
-
eligibility_errors.add(:base, ineligible_message, error_code: ineligible_error_code)
|
39
|
-
end
|
40
|
-
|
41
|
-
eligibility_errors.empty?
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
|
46
|
-
def operator
|
47
|
-
self.class.operators_map.fetch(
|
48
|
-
preferred_operator.to_sym,
|
49
|
-
preferred_operator_default,
|
50
|
-
)
|
51
|
-
end
|
52
|
-
|
53
|
-
def total_for_order(order)
|
54
|
-
order.item_total
|
55
|
-
end
|
56
|
-
|
57
|
-
def threshold
|
58
|
-
BigDecimal(preferred_amount.to_s)
|
59
|
-
end
|
60
|
-
|
61
|
-
def formatted_amount
|
62
|
-
Spree::Money.new(preferred_amount, currency: preferred_currency).to_s
|
63
|
-
end
|
64
|
-
|
65
|
-
def ineligible_message
|
66
|
-
case preferred_operator.to_s
|
67
|
-
when 'gte'
|
68
|
-
eligibility_error_message(:item_total_less_than, amount: formatted_amount)
|
69
|
-
when 'gt'
|
70
|
-
eligibility_error_message(:item_total_less_than_or_equal, amount: formatted_amount)
|
71
|
-
else
|
72
|
-
eligibility_error_message(:item_total_doesnt_match_with_operator, amount: formatted_amount, operator: preferred_operator)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
def ineligible_error_code
|
77
|
-
if preferred_operator == 'gte'
|
78
|
-
:item_total_less_than
|
79
|
-
else
|
80
|
-
:item_total_less_than_or_equal
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion
|
5
|
-
module Rules
|
6
|
-
# Promotion rule for ensuring an order contains a minimum quantity of
|
7
|
-
# actionable items.
|
8
|
-
#
|
9
|
-
# This promotion rule is only compatible with the "all" match policy. It
|
10
|
-
# doesn't make a lot of sense to use it without that policy as it reduces
|
11
|
-
# it to a simple quantity check across the entire order which would be
|
12
|
-
# better served by an item total rule.
|
13
|
-
class MinimumQuantity < PromotionRule
|
14
|
-
validates :preferred_minimum_quantity, numericality: { only_integer: true, greater_than: 0 }
|
15
|
-
|
16
|
-
preference :minimum_quantity, :integer, default: 1
|
17
|
-
|
18
|
-
# What type of objects we should run our eligiblity checks against. In
|
19
|
-
# this case, our rule only applies to an entire order.
|
20
|
-
#
|
21
|
-
# @param promotable [Spree::Order,Spree::LineItem]
|
22
|
-
# @return [Boolean] true if promotable is a Spree::Order, false
|
23
|
-
# otherwise
|
24
|
-
def applicable?(promotable)
|
25
|
-
promotable.is_a?(Spree::Order)
|
26
|
-
end
|
27
|
-
|
28
|
-
# Will look at all of the "actionable" line items in the order and
|
29
|
-
# determine if the sum of their quantity is greater than the minimum.
|
30
|
-
#
|
31
|
-
# "Actionable" items are ones where they pass the "actionable?" check of
|
32
|
-
# all rules on the promotion. (e.g.: Match product/taxon when one of
|
33
|
-
# those rules is present.)
|
34
|
-
#
|
35
|
-
# When false is returned, the reason will be included in the
|
36
|
-
# `eligibility_errors` object.
|
37
|
-
#
|
38
|
-
# @param order [Spree::Order] the order we want to check eligibility on
|
39
|
-
# @param _options [Hash] ignored
|
40
|
-
# @return [Boolean] true if promotion is eligible, false otherwise
|
41
|
-
def eligible?(order, _options = {})
|
42
|
-
actionable_line_items = order.line_items.select do |line_item|
|
43
|
-
promotion.rules.all? { _1.actionable?(line_item) }
|
44
|
-
end
|
45
|
-
|
46
|
-
if actionable_line_items.sum(&:quantity) < preferred_minimum_quantity
|
47
|
-
eligibility_errors.add(
|
48
|
-
:base,
|
49
|
-
eligibility_error_message(:quantity_less_than_minimum, count: preferred_minimum_quantity),
|
50
|
-
error_code: :quantity_less_than_minimum
|
51
|
-
)
|
52
|
-
end
|
53
|
-
|
54
|
-
eligibility_errors.empty?
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion
|
5
|
-
module Rules
|
6
|
-
class NthOrder < PromotionRule
|
7
|
-
preference :nth_order, :integer, default: 2
|
8
|
-
# It does not make sense to have this apply to the first order using preferred_nth_order == 1
|
9
|
-
# Instead we could use the first_order rule
|
10
|
-
validates :preferred_nth_order, numericality: { only_integer: true, greater_than: 1 }
|
11
|
-
|
12
|
-
# This promotion is applicable to orders only.
|
13
|
-
def applicable?(promotable)
|
14
|
-
promotable.is_a?(Spree::Order)
|
15
|
-
end
|
16
|
-
|
17
|
-
# This is never eligible if the order does not have a user, and that user does not have any previous completed orders.
|
18
|
-
#
|
19
|
-
# Use the first order rule if you want a promotion to be applied to the first order for a user.
|
20
|
-
# @param order [Spree::Order]
|
21
|
-
def eligible?(order, _options = {})
|
22
|
-
return false unless order.user
|
23
|
-
|
24
|
-
nth_order?(order)
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
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
|
36
|
-
end
|
37
|
-
|
38
|
-
def nth_order?(order)
|
39
|
-
count = completed_order_count(order) + 1
|
40
|
-
count == preferred_nth_order
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion < Spree::Base
|
5
|
-
module Rules
|
6
|
-
class OneUsePerUser < PromotionRule
|
7
|
-
def applicable?(promotable)
|
8
|
-
promotable.is_a?(Spree::Order)
|
9
|
-
end
|
10
|
-
|
11
|
-
def eligible?(order, _options = {})
|
12
|
-
if order.user.present?
|
13
|
-
if promotion.used_by?(order.user, [order])
|
14
|
-
eligibility_errors.add(:base, eligibility_error_message(:limit_once_per_user), error_code: :limit_once_per_user)
|
15
|
-
end
|
16
|
-
else
|
17
|
-
eligibility_errors.add(:base, eligibility_error_message(:no_user_specified), error_code: :no_user_specified)
|
18
|
-
end
|
19
|
-
|
20
|
-
eligibility_errors.empty?
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,50 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion < Spree::Base
|
5
|
-
module Rules
|
6
|
-
class OptionValue < PromotionRule
|
7
|
-
MATCH_POLICIES = %w(any)
|
8
|
-
preference :match_policy, :string, default: MATCH_POLICIES.first
|
9
|
-
preference :eligible_values, :hash
|
10
|
-
|
11
|
-
def applicable?(promotable)
|
12
|
-
promotable.is_a?(Spree::Order)
|
13
|
-
end
|
14
|
-
|
15
|
-
def eligible?(promotable, _options = {})
|
16
|
-
case preferred_match_policy
|
17
|
-
when 'any'
|
18
|
-
promotable.line_items.any? { |item| actionable?(item) }
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def actionable?(line_item)
|
23
|
-
pid = line_item.product.id
|
24
|
-
ovids = line_item.variant.option_values.pluck(:id)
|
25
|
-
|
26
|
-
product_ids.include?(pid) && (value_ids(pid) & ovids).present?
|
27
|
-
end
|
28
|
-
|
29
|
-
def preferred_eligible_values
|
30
|
-
values = preferences[:eligible_values] || {}
|
31
|
-
Hash[values.keys.map(&:to_i).zip(
|
32
|
-
values.values.map do |value|
|
33
|
-
(value.is_a?(Array) ? value : value.split(",")).map(&:to_i)
|
34
|
-
end
|
35
|
-
)]
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def product_ids
|
41
|
-
preferred_eligible_values.keys
|
42
|
-
end
|
43
|
-
|
44
|
-
def value_ids(product_id)
|
45
|
-
preferred_eligible_values[product_id]
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion < Spree::Base
|
5
|
-
module Rules
|
6
|
-
# A rule to limit a promotion based on products in the order. Can
|
7
|
-
# require all or any of the products to be present. Valid products
|
8
|
-
# either come from assigned product group or are assingned directly to
|
9
|
-
# the rule.
|
10
|
-
class Product < PromotionRule
|
11
|
-
has_many :product_promotion_rules, dependent: :destroy, foreign_key: :promotion_rule_id,
|
12
|
-
class_name: 'Spree::ProductPromotionRule'
|
13
|
-
has_many :products, class_name: 'Spree::Product', through: :product_promotion_rules
|
14
|
-
|
15
|
-
def preload_relations
|
16
|
-
[:products]
|
17
|
-
end
|
18
|
-
|
19
|
-
MATCH_POLICIES = %w(any all none)
|
20
|
-
|
21
|
-
validates_inclusion_of :preferred_match_policy, in: MATCH_POLICIES
|
22
|
-
|
23
|
-
preference :match_policy, :string, default: MATCH_POLICIES.first
|
24
|
-
|
25
|
-
# scope/association that is used to test eligibility
|
26
|
-
def eligible_products
|
27
|
-
products
|
28
|
-
end
|
29
|
-
|
30
|
-
def applicable?(promotable)
|
31
|
-
promotable.is_a?(Spree::Order)
|
32
|
-
end
|
33
|
-
|
34
|
-
def eligible?(order, _options = {})
|
35
|
-
return true if eligible_products.empty?
|
36
|
-
|
37
|
-
case preferred_match_policy
|
38
|
-
when "all"
|
39
|
-
unless eligible_products.all? { |product| order_products(order).include?(product) }
|
40
|
-
eligibility_errors.add(:base, eligibility_error_message(:missing_product), error_code: :missing_product)
|
41
|
-
end
|
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)
|
46
|
-
end
|
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)
|
51
|
-
end
|
52
|
-
else
|
53
|
-
raise "unexpected match policy: #{preferred_match_policy.inspect}"
|
54
|
-
end
|
55
|
-
|
56
|
-
eligibility_errors.empty?
|
57
|
-
end
|
58
|
-
|
59
|
-
def actionable?(line_item)
|
60
|
-
case preferred_match_policy
|
61
|
-
when 'any', 'all'
|
62
|
-
product_ids.include? line_item.variant.product_id
|
63
|
-
when 'none'
|
64
|
-
product_ids.exclude? line_item.variant.product_id
|
65
|
-
else
|
66
|
-
raise "unexpected match policy: #{preferred_match_policy.inspect}"
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def product_ids_string
|
71
|
-
product_ids.join(',')
|
72
|
-
end
|
73
|
-
|
74
|
-
def product_ids_string=(product_ids)
|
75
|
-
self.product_ids = product_ids.to_s.split(',').map(&:strip)
|
76
|
-
end
|
77
|
-
|
78
|
-
private
|
79
|
-
|
80
|
-
def order_products(order)
|
81
|
-
order.line_items.map(&:variant).map(&:product)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion
|
5
|
-
module Rules
|
6
|
-
class Store < PromotionRule
|
7
|
-
has_many :promotion_rule_stores, class_name: "Spree::PromotionRuleStore",
|
8
|
-
foreign_key: :promotion_rule_id,
|
9
|
-
dependent: :destroy
|
10
|
-
has_many :stores, through: :promotion_rule_stores, class_name: "Spree::Store"
|
11
|
-
|
12
|
-
def preload_relations
|
13
|
-
[:stores]
|
14
|
-
end
|
15
|
-
|
16
|
-
def applicable?(promotable)
|
17
|
-
promotable.is_a?(Spree::Order)
|
18
|
-
end
|
19
|
-
|
20
|
-
def eligible?(order, _options = {})
|
21
|
-
stores.none? || stores.include?(order.store)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion < Spree::Base
|
5
|
-
module Rules
|
6
|
-
class Taxon < PromotionRule
|
7
|
-
has_many :promotion_rule_taxons, class_name: 'Spree::PromotionRuleTaxon', foreign_key: :promotion_rule_id,
|
8
|
-
dependent: :destroy
|
9
|
-
has_many :taxons, through: :promotion_rule_taxons, class_name: 'Spree::Taxon'
|
10
|
-
|
11
|
-
def preload_relations
|
12
|
-
[:taxons]
|
13
|
-
end
|
14
|
-
|
15
|
-
MATCH_POLICIES = %w(any all none)
|
16
|
-
|
17
|
-
validates_inclusion_of :preferred_match_policy, in: MATCH_POLICIES
|
18
|
-
|
19
|
-
preference :match_policy, :string, default: MATCH_POLICIES.first
|
20
|
-
def applicable?(promotable)
|
21
|
-
promotable.is_a?(Spree::Order)
|
22
|
-
end
|
23
|
-
|
24
|
-
def eligible?(order, _options = {})
|
25
|
-
order_taxons = taxons_in_order(order)
|
26
|
-
|
27
|
-
case preferred_match_policy
|
28
|
-
when 'all'
|
29
|
-
matches_all = taxons.all? do |rule_taxon|
|
30
|
-
order_taxons.where(id: rule_taxon.self_and_descendants.ids).exists?
|
31
|
-
end
|
32
|
-
|
33
|
-
unless matches_all
|
34
|
-
eligibility_errors.add(:base, eligibility_error_message(:missing_taxon), error_code: :missing_taxon)
|
35
|
-
end
|
36
|
-
when 'any'
|
37
|
-
unless order_taxons.where(id: rule_taxon_ids_with_children).exists?
|
38
|
-
eligibility_errors.add(:base, eligibility_error_message(:no_matching_taxons), error_code: :no_matching_taxons)
|
39
|
-
end
|
40
|
-
when 'none'
|
41
|
-
if order_taxons.where(id: rule_taxon_ids_with_children).exists?
|
42
|
-
eligibility_errors.add(:base, eligibility_error_message(:has_excluded_taxon), error_code: :has_excluded_taxon)
|
43
|
-
end
|
44
|
-
else
|
45
|
-
raise "unexpected match policy: #{preferred_match_policy.inspect}"
|
46
|
-
end
|
47
|
-
|
48
|
-
eligibility_errors.empty?
|
49
|
-
end
|
50
|
-
|
51
|
-
def actionable?(line_item)
|
52
|
-
found = Spree::Classification.where(
|
53
|
-
product_id: line_item.variant.product_id,
|
54
|
-
taxon_id: rule_taxon_ids_with_children
|
55
|
-
).exists?
|
56
|
-
|
57
|
-
case preferred_match_policy
|
58
|
-
when 'any', 'all'
|
59
|
-
found
|
60
|
-
when 'none'
|
61
|
-
!found
|
62
|
-
else
|
63
|
-
raise "unexpected match policy: #{preferred_match_policy.inspect}"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def taxon_ids_string
|
68
|
-
taxons.pluck(:id).join(',')
|
69
|
-
end
|
70
|
-
|
71
|
-
def taxon_ids_string=(taxon_ids)
|
72
|
-
taxon_ids = taxon_ids.to_s.split(',').map(&:strip)
|
73
|
-
self.taxons = Spree::Taxon.find(taxon_ids)
|
74
|
-
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
# All taxons in an order
|
79
|
-
def taxons_in_order(order)
|
80
|
-
Spree::Taxon.joins(products: { variants_including_master: :line_items })
|
81
|
-
.where(spree_line_items: { order_id: order.id }).distinct
|
82
|
-
end
|
83
|
-
|
84
|
-
# ids of taxons rules and taxons rules children
|
85
|
-
def rule_taxon_ids_with_children
|
86
|
-
taxons.flat_map { |taxon| taxon.self_and_descendants.ids }.uniq
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion < Spree::Base
|
5
|
-
module Rules
|
6
|
-
class User < PromotionRule
|
7
|
-
has_many :promotion_rule_users, class_name: 'Spree::PromotionRuleUser',
|
8
|
-
foreign_key: :promotion_rule_id,
|
9
|
-
dependent: :destroy
|
10
|
-
has_many :users, through: :promotion_rule_users, class_name: Spree::UserClassHandle.new
|
11
|
-
|
12
|
-
def preload_relations
|
13
|
-
[:users]
|
14
|
-
end
|
15
|
-
|
16
|
-
def applicable?(promotable)
|
17
|
-
promotable.is_a?(Spree::Order)
|
18
|
-
end
|
19
|
-
|
20
|
-
def eligible?(order, _options = {})
|
21
|
-
users.include?(order.user)
|
22
|
-
end
|
23
|
-
|
24
|
-
def user_ids_string
|
25
|
-
user_ids.join(',')
|
26
|
-
end
|
27
|
-
|
28
|
-
def user_ids_string=(user_ids)
|
29
|
-
self.user_ids = user_ids.to_s.split(',').map(&:strip)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion < Spree::Base
|
5
|
-
module Rules
|
6
|
-
class UserLoggedIn < PromotionRule
|
7
|
-
def applicable?(promotable)
|
8
|
-
promotable.is_a?(Spree::Order)
|
9
|
-
end
|
10
|
-
|
11
|
-
def eligible?(order, _options = {})
|
12
|
-
unless order.user.present?
|
13
|
-
eligibility_errors.add(:base, eligibility_error_message(:no_user_specified), error_code: :no_user_specified)
|
14
|
-
end
|
15
|
-
eligibility_errors.empty?
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spree
|
4
|
-
class Promotion < Spree::Base
|
5
|
-
module Rules
|
6
|
-
class UserRole < PromotionRule
|
7
|
-
preference :role_ids, :array, default: []
|
8
|
-
|
9
|
-
MATCH_POLICIES = %w(any all)
|
10
|
-
preference :match_policy, default: MATCH_POLICIES.first
|
11
|
-
|
12
|
-
def applicable?(promotable)
|
13
|
-
promotable.is_a?(Spree::Order)
|
14
|
-
end
|
15
|
-
|
16
|
-
def eligible?(order, _options = {})
|
17
|
-
return false unless order.user
|
18
|
-
if all_match_policy?
|
19
|
-
match_all_roles?(order)
|
20
|
-
else
|
21
|
-
match_any_roles?(order)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def all_match_policy?
|
28
|
-
preferred_match_policy == 'all' && preferred_role_ids.present?
|
29
|
-
end
|
30
|
-
|
31
|
-
def user_roles(order)
|
32
|
-
order.user.spree_roles.where(id: preferred_role_ids)
|
33
|
-
end
|
34
|
-
|
35
|
-
def match_all_roles?(order)
|
36
|
-
user_roles(order).count == preferred_role_ids.count
|
37
|
-
end
|
38
|
-
|
39
|
-
def match_any_roles?(order)
|
40
|
-
user_roles(order).exists?
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|