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.
Files changed (211) hide show
  1. checksums.yaml +4 -4
  2. data/app/helpers/spree/base_helper.rb +2 -2
  3. data/app/mailers/spree/base_mailer.rb +1 -1
  4. data/app/mailers/spree/carton_mailer.rb +1 -1
  5. data/app/mailers/spree/order_mailer.rb +3 -3
  6. data/app/mailers/spree/reimbursement_mailer.rb +1 -1
  7. data/app/models/concerns/spree/active_storage_adapter/normalization.rb +1 -1
  8. data/app/models/concerns/spree/active_storage_adapter.rb +1 -1
  9. data/app/models/concerns/spree/display_money.rb +1 -1
  10. data/app/models/concerns/spree/ordered_property_value_list.rb +2 -2
  11. data/app/models/concerns/spree/user_address_book.rb +4 -4
  12. data/app/models/concerns/spree/user_methods.rb +3 -3
  13. data/app/models/spree/address.rb +6 -6
  14. data/app/models/spree/adjustment.rb +13 -66
  15. data/app/models/spree/calculator/returns/default_refund_amount.rb +1 -1
  16. data/app/models/spree/carton.rb +2 -2
  17. data/app/models/spree/credit_card.rb +6 -6
  18. data/app/models/spree/deprecated_configurable_class.rb +40 -0
  19. data/app/models/spree/fulfilment_changer.rb +4 -4
  20. data/app/models/spree/inventory_unit.rb +2 -2
  21. data/app/models/spree/line_item.rb +1 -1
  22. data/app/models/spree/null_promotion_adjuster.rb +13 -0
  23. data/app/models/spree/null_promotion_advertiser.rb +9 -0
  24. data/app/models/spree/null_promotion_finder.rb +9 -0
  25. data/app/models/spree/null_promotion_handler.rb +44 -0
  26. data/app/models/spree/order.rb +15 -22
  27. data/app/models/spree/order_cancellations.rb +8 -8
  28. data/app/models/spree/order_mutex.rb +2 -2
  29. data/app/models/spree/order_shipping.rb +9 -9
  30. data/app/models/spree/order_updater.rb +6 -10
  31. data/app/models/spree/payment/processing.rb +2 -2
  32. data/app/models/spree/payment.rb +2 -2
  33. data/app/models/spree/payment_create.rb +1 -1
  34. data/app/models/spree/payment_method/store_credit.rb +1 -1
  35. data/app/models/spree/payment_source.rb +5 -1
  36. data/app/models/spree/permission_set.rb +11 -0
  37. data/app/models/spree/product.rb +7 -28
  38. data/app/models/spree/refund.rb +1 -1
  39. data/app/models/spree/reimbursement.rb +4 -4
  40. data/app/models/spree/reimbursement_performer.rb +3 -3
  41. data/app/models/spree/reimbursement_tax_calculator.rb +2 -2
  42. data/app/models/spree/reimbursement_type/credit.rb +1 -1
  43. data/app/models/spree/reimbursement_type/reimbursement_helpers.rb +6 -6
  44. data/app/models/spree/reimbursement_type/store_credit.rb +1 -1
  45. data/app/models/spree/return_item.rb +9 -9
  46. data/app/models/spree/role.rb +3 -1
  47. data/app/models/spree/role_permission.rb +8 -0
  48. data/app/models/spree/shipment.rb +7 -7
  49. data/app/models/spree/shipping_category.rb +2 -0
  50. data/app/models/spree/shipping_rate.rb +1 -1
  51. data/app/models/spree/{order_contents.rb → simple_order_contents.rb} +4 -11
  52. data/app/models/spree/stock/estimator.rb +1 -1
  53. data/app/models/spree/stock/inventory_unit_builder.rb +1 -1
  54. data/app/models/spree/stock/package.rb +2 -2
  55. data/app/models/spree/stock/simple_coordinator.rb +1 -1
  56. data/app/models/spree/stock_location.rb +5 -5
  57. data/app/models/spree/store.rb +1 -1
  58. data/app/models/spree/store_credit.rb +17 -15
  59. data/app/models/spree/store_credit_event.rb +3 -3
  60. data/app/models/spree/tax_calculator/default.rb +2 -2
  61. data/app/models/spree/tax_calculator/shipping_rate.rb +1 -1
  62. data/app/models/spree/tax_category.rb +3 -1
  63. data/app/models/spree/tax_rate.rb +3 -3
  64. data/app/models/spree/taxonomy.rb +2 -2
  65. data/app/models/spree/unit_cancel.rb +1 -2
  66. data/app/models/spree/variant/vat_price_generator.rb +1 -1
  67. data/app/models/spree/variant.rb +7 -2
  68. data/app/models/spree/wallet.rb +2 -2
  69. data/app/views/spree/order_mailer/cancel_email.html.erb +1 -1
  70. data/app/views/spree/order_mailer/cancel_email.text.erb +1 -1
  71. data/app/views/spree/order_mailer/confirm_email.html.erb +5 -5
  72. data/app/views/spree/order_mailer/confirm_email.text.erb +5 -5
  73. data/config/locales/en.yml +4 -90
  74. data/db/default/spree/permission_sets.rb +10 -0
  75. data/db/default/spree/return_reasons.rb +3 -1
  76. data/db/default/spree/states.rb +1 -1
  77. data/db/migrate/20160101010000_solidus_one_four.rb +0 -117
  78. data/db/migrate/20240821173254_create_spree_permission_sets_in_core.rb +9 -0
  79. data/db/migrate/20240821173341_create_spree_roles_permissions_in_core.rb +9 -0
  80. data/db/migrate/20240821173641_add_description_to_spree_roles.rb +5 -0
  81. data/db/migrate/20240904152041_add_privilege_and_category_to_spree_permission_sets.rb +6 -0
  82. data/db/seeds.rb +1 -0
  83. data/lib/generators/solidus/install/app_templates/frontend/starter.rb +1 -1
  84. data/lib/generators/solidus/update/update_generator.rb +1 -1
  85. data/lib/generators/spree/dummy/templates/rails/test.rb +6 -1
  86. data/lib/spree/app_configuration.rb +53 -84
  87. data/lib/spree/core/class_constantizer.rb +2 -2
  88. data/lib/spree/core/controller_helpers/payment_parameters.rb +1 -1
  89. data/lib/spree/core/engine.rb +1 -0
  90. data/lib/spree/core/environment/calculators.rb +35 -3
  91. data/lib/spree/core/environment/promotions.rb +25 -4
  92. data/lib/spree/core/environment_extension.rb +16 -2
  93. data/lib/spree/core/importer/order.rb +5 -5
  94. data/lib/spree/core/importer/product.rb +3 -3
  95. data/lib/spree/core/nested_class_set.rb +28 -0
  96. data/lib/spree/core/null_promotion_configuration.rb +84 -0
  97. data/lib/spree/core/product_filters.rb +1 -1
  98. data/lib/spree/core/search/variant.rb +2 -2
  99. data/lib/spree/core/state_machines/order.rb +0 -1
  100. data/lib/spree/core/validators/email.rb +1 -1
  101. data/lib/spree/core/version.rb +2 -2
  102. data/lib/spree/core.rb +2 -6
  103. data/lib/spree/deprecator.rb +9 -0
  104. data/lib/spree/i18n.rb +1 -1
  105. data/lib/spree/mailer_previews/carton_preview.rb +1 -1
  106. data/lib/spree/permission_sets/base.rb +13 -1
  107. data/lib/spree/permission_sets/configuration_display.rb +10 -0
  108. data/lib/spree/permission_sets/configuration_management.rb +10 -0
  109. data/lib/spree/permission_sets/dashboard_display.rb +12 -0
  110. data/lib/spree/permission_sets/default_customer.rb +11 -1
  111. data/lib/spree/permission_sets/order_display.rb +10 -0
  112. data/lib/spree/permission_sets/order_management.rb +10 -0
  113. data/lib/spree/permission_sets/product_display.rb +10 -0
  114. data/lib/spree/permission_sets/product_management.rb +10 -0
  115. data/lib/spree/permission_sets/restricted_stock_display.rb +10 -0
  116. data/lib/spree/permission_sets/restricted_stock_management.rb +10 -0
  117. data/lib/spree/permission_sets/stock_display.rb +10 -0
  118. data/lib/spree/permission_sets/stock_management.rb +10 -0
  119. data/lib/spree/permission_sets/super_user.rb +10 -0
  120. data/lib/spree/permission_sets/user_display.rb +10 -0
  121. data/lib/spree/permission_sets/user_management.rb +10 -0
  122. data/lib/spree/permission_sets.rb +0 -2
  123. data/lib/spree/permitted_attributes.rb +2 -2
  124. data/lib/spree/preferences/store.rb +2 -2
  125. data/lib/spree/testing_support/capybara_ext.rb +1 -1
  126. data/lib/spree/testing_support/dummy_ability.rb +7 -0
  127. data/lib/spree/testing_support/dummy_app/database.yml +2 -2
  128. data/lib/spree/testing_support/dummy_app/migrations.rb +8 -15
  129. data/lib/spree/testing_support/dummy_app/rake_tasks.rb +2 -2
  130. data/lib/spree/testing_support/dummy_app.rb +17 -12
  131. data/lib/spree/testing_support/factories/adjustment_factory.rb +1 -2
  132. data/lib/spree/testing_support/factories/calculator_factory.rb +1 -5
  133. data/lib/spree/testing_support/factories/carton_factory.rb +2 -2
  134. data/lib/spree/testing_support/factories/customer_return_factory.rb +2 -2
  135. data/lib/spree/testing_support/factories/inventory_unit_factory.rb +3 -3
  136. data/lib/spree/testing_support/factories/order_factory.rb +5 -24
  137. data/lib/spree/testing_support/factories/product_factory.rb +1 -1
  138. data/lib/spree/testing_support/factories/shipment_factory.rb +1 -1
  139. data/lib/spree/testing_support/factories/stock_item_factory.rb +5 -1
  140. data/lib/spree/testing_support/factories/stock_package_factory.rb +1 -1
  141. data/lib/spree/testing_support/factories/user_factory.rb +1 -1
  142. data/lib/spree/testing_support/factories/zone_factory.rb +1 -1
  143. data/lib/spree/testing_support/order_walkthrough.rb +3 -3
  144. data/lib/spree/testing_support/shared_examples/calculator.rb +10 -0
  145. data/lib/spree/testing_support/shared_examples/order_factory.rb +141 -0
  146. data/lib/spree/testing_support/shared_examples/working_factory.rb +15 -0
  147. data/lib/tasks/colorado_delivery_fee.rake +2 -2
  148. data/solidus_core.gemspec +6 -6
  149. metadata +60 -91
  150. data/app/jobs/spree/promotion_code_batch_job.rb +0 -26
  151. data/app/mailers/spree/promotion_code_batch_mailer.rb +0 -15
  152. data/app/models/spree/calculator/distributed_amount.rb +0 -33
  153. data/app/models/spree/calculator/flat_percent_item_total.rb +0 -23
  154. data/app/models/spree/calculator/flexi_rate.rb +0 -22
  155. data/app/models/spree/calculator/percent_on_line_item.rb +0 -13
  156. data/app/models/spree/calculator/tiered_flat_rate.rb +0 -52
  157. data/app/models/spree/calculator/tiered_percent.rb +0 -62
  158. data/app/models/spree/order_promotion.rb +0 -27
  159. data/app/models/spree/promotion/actions/create_adjustment.rb +0 -81
  160. data/app/models/spree/promotion/actions/create_item_adjustments.rb +0 -98
  161. data/app/models/spree/promotion/actions/create_quantity_adjustments.rb +0 -139
  162. data/app/models/spree/promotion/actions/free_shipping.rb +0 -59
  163. data/app/models/spree/promotion/order_adjustments_recalculator.rb +0 -92
  164. data/app/models/spree/promotion/rules/first_order.rb +0 -38
  165. data/app/models/spree/promotion/rules/first_repeat_purchase_since.rb +0 -36
  166. data/app/models/spree/promotion/rules/item_total.rb +0 -86
  167. data/app/models/spree/promotion/rules/minimum_quantity.rb +0 -59
  168. data/app/models/spree/promotion/rules/nth_order.rb +0 -45
  169. data/app/models/spree/promotion/rules/one_use_per_user.rb +0 -25
  170. data/app/models/spree/promotion/rules/option_value.rb +0 -50
  171. data/app/models/spree/promotion/rules/product.rb +0 -86
  172. data/app/models/spree/promotion/rules/store.rb +0 -26
  173. data/app/models/spree/promotion/rules/taxon.rb +0 -91
  174. data/app/models/spree/promotion/rules/user.rb +0 -34
  175. data/app/models/spree/promotion/rules/user_logged_in.rb +0 -20
  176. data/app/models/spree/promotion/rules/user_role.rb +0 -45
  177. data/app/models/spree/promotion.rb +0 -271
  178. data/app/models/spree/promotion_action.rb +0 -47
  179. data/app/models/spree/promotion_category.rb +0 -8
  180. data/app/models/spree/promotion_chooser.rb +0 -34
  181. data/app/models/spree/promotion_code/batch_builder.rb +0 -64
  182. data/app/models/spree/promotion_code.rb +0 -54
  183. data/app/models/spree/promotion_code_batch.rb +0 -27
  184. data/app/models/spree/promotion_handler/cart.rb +0 -75
  185. data/app/models/spree/promotion_handler/coupon.rb +0 -123
  186. data/app/models/spree/promotion_handler/page.rb +0 -26
  187. data/app/models/spree/promotion_handler/shipping.rb +0 -61
  188. data/app/models/spree/promotion_rule.rb +0 -55
  189. data/app/models/spree/promotion_rule_store.rb +0 -10
  190. data/app/models/spree/promotion_rule_taxon.rb +0 -8
  191. data/app/models/spree/promotion_rule_user.rb +0 -10
  192. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_errored.text.erb +0 -2
  193. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_finished.text.erb +0 -2
  194. data/db/migrate/20161017102621_create_spree_promotion_code_batch.rb +0 -38
  195. data/db/migrate/20180202190713_create_promotion_rule_stores.rb +0 -12
  196. data/db/migrate/20180328172631_add_join_characters_to_promotion_code_batch.rb +0 -11
  197. data/db/migrate/20190106184413_remove_code_from_spree_promotions.rb +0 -42
  198. data/db/migrate/20220317165036_set_promotions_with_any_policy_to_all_if_possible.rb +0 -20
  199. data/db/migrate/20230322085416_remove_match_policy_from_spree_promotion.rb +0 -5
  200. data/db/migrate/20230325132905_remove_unused_columns_from_promotion_rules.rb +0 -6
  201. data/db/migrate/20230325161633_drop_unused_promo_action_line_items.rb +0 -13
  202. data/db/migrate/20231027084517_add_order_promotions_foreign_key.rb +0 -10
  203. data/db/migrate/20231031175215_add_promotion_order_promotion_foreign_key.rb +0 -10
  204. data/lib/solidus/migrations/promotions_with_code_handlers.rb +0 -66
  205. data/lib/spree/permission_sets/promotion_display.rb +0 -25
  206. data/lib/spree/permission_sets/promotion_management.rb +0 -25
  207. data/lib/spree/ransack_4_1_patch.rb +0 -16
  208. data/lib/spree/testing_support/factories/order_promotion_factory.rb +0 -8
  209. data/lib/spree/testing_support/factories/promotion_category_factory.rb +0 -7
  210. data/lib/spree/testing_support/factories/promotion_code_factory.rb +0 -8
  211. 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