solidus_core 4.3.4 → 4.4.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/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 -1
- 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 +17 -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 -117
- 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 +6 -6
- metadata +60 -91
- 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/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/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,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
|