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.
Files changed (213) 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 -4
  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 +15 -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 -127
  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 +7 -7
  149. metadata +60 -93
  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/line_item_action.rb +0 -8
  159. data/app/models/spree/order_promotion.rb +0 -27
  160. data/app/models/spree/promotion/actions/create_adjustment.rb +0 -81
  161. data/app/models/spree/promotion/actions/create_item_adjustments.rb +0 -98
  162. data/app/models/spree/promotion/actions/create_quantity_adjustments.rb +0 -139
  163. data/app/models/spree/promotion/actions/free_shipping.rb +0 -59
  164. data/app/models/spree/promotion/order_adjustments_recalculator.rb +0 -92
  165. data/app/models/spree/promotion/rules/first_order.rb +0 -38
  166. data/app/models/spree/promotion/rules/first_repeat_purchase_since.rb +0 -36
  167. data/app/models/spree/promotion/rules/item_total.rb +0 -86
  168. data/app/models/spree/promotion/rules/minimum_quantity.rb +0 -59
  169. data/app/models/spree/promotion/rules/nth_order.rb +0 -45
  170. data/app/models/spree/promotion/rules/one_use_per_user.rb +0 -25
  171. data/app/models/spree/promotion/rules/option_value.rb +0 -50
  172. data/app/models/spree/promotion/rules/product.rb +0 -86
  173. data/app/models/spree/promotion/rules/store.rb +0 -26
  174. data/app/models/spree/promotion/rules/taxon.rb +0 -91
  175. data/app/models/spree/promotion/rules/user.rb +0 -34
  176. data/app/models/spree/promotion/rules/user_logged_in.rb +0 -20
  177. data/app/models/spree/promotion/rules/user_role.rb +0 -45
  178. data/app/models/spree/promotion.rb +0 -271
  179. data/app/models/spree/promotion_action.rb +0 -47
  180. data/app/models/spree/promotion_category.rb +0 -8
  181. data/app/models/spree/promotion_chooser.rb +0 -34
  182. data/app/models/spree/promotion_code/batch_builder.rb +0 -64
  183. data/app/models/spree/promotion_code.rb +0 -54
  184. data/app/models/spree/promotion_code_batch.rb +0 -27
  185. data/app/models/spree/promotion_handler/cart.rb +0 -75
  186. data/app/models/spree/promotion_handler/coupon.rb +0 -123
  187. data/app/models/spree/promotion_handler/page.rb +0 -26
  188. data/app/models/spree/promotion_handler/shipping.rb +0 -61
  189. data/app/models/spree/promotion_rule.rb +0 -55
  190. data/app/models/spree/promotion_rule_store.rb +0 -10
  191. data/app/models/spree/promotion_rule_taxon.rb +0 -8
  192. data/app/models/spree/promotion_rule_user.rb +0 -10
  193. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_errored.text.erb +0 -2
  194. data/app/views/spree/promotion_code_batch_mailer/promotion_code_batch_finished.text.erb +0 -2
  195. data/bin/rails +0 -13
  196. data/db/migrate/20161017102621_create_spree_promotion_code_batch.rb +0 -38
  197. data/db/migrate/20180202190713_create_promotion_rule_stores.rb +0 -12
  198. data/db/migrate/20180328172631_add_join_characters_to_promotion_code_batch.rb +0 -11
  199. data/db/migrate/20190106184413_remove_code_from_spree_promotions.rb +0 -42
  200. data/db/migrate/20220317165036_set_promotions_with_any_policy_to_all_if_possible.rb +0 -20
  201. data/db/migrate/20230322085416_remove_match_policy_from_spree_promotion.rb +0 -5
  202. data/db/migrate/20230325132905_remove_unused_columns_from_promotion_rules.rb +0 -6
  203. data/db/migrate/20230325161633_drop_unused_promo_action_line_items.rb +0 -13
  204. data/db/migrate/20231027084517_add_order_promotions_foreign_key.rb +0 -10
  205. data/db/migrate/20231031175215_add_promotion_order_promotion_foreign_key.rb +0 -10
  206. data/lib/solidus/migrations/promotions_with_code_handlers.rb +0 -66
  207. data/lib/spree/permission_sets/promotion_display.rb +0 -25
  208. data/lib/spree/permission_sets/promotion_management.rb +0 -25
  209. data/lib/spree/ransack_4_1_patch.rb +0 -16
  210. data/lib/spree/testing_support/factories/order_promotion_factory.rb +0 -8
  211. data/lib/spree/testing_support/factories/promotion_category_factory.rb +0 -7
  212. data/lib/spree/testing_support/factories/promotion_code_factory.rb +0 -8
  213. 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