solidus_friendly_promotions 1.0.1 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (195) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile +1 -1
  4. data/MIGRATING.md +1 -1
  5. data/README.md +22 -16
  6. data/app/assets/config/solidus_friendly_promotions/manifest.js +7 -1
  7. data/app/controllers/solidus_friendly_promotions/admin/benefits_controller.rb +85 -0
  8. data/app/controllers/solidus_friendly_promotions/admin/conditions_controller.rb +69 -0
  9. data/app/controllers/solidus_friendly_promotions/admin/promotions_controller.rb +3 -3
  10. data/app/decorators/models/solidus_friendly_promotions/adjustment_decorator.rb +4 -4
  11. data/app/decorators/models/solidus_friendly_promotions/line_item_decorator.rb +2 -2
  12. data/app/decorators/models/solidus_friendly_promotions/order_decorator.rb +6 -6
  13. data/app/helpers/solidus_friendly_promotions/admin/benefits_helper.rb +19 -0
  14. data/app/helpers/solidus_friendly_promotions/admin/conditions_helper.rb +12 -0
  15. data/app/javascript/solidus_friendly_promotions/controllers/product_option_values_controller.js +1 -1
  16. data/app/javascript/solidus_friendly_promotions/web_components/number_with_currency.js +35 -0
  17. data/app/javascript/solidus_friendly_promotions/{jquery → web_components}/option_value_picker.js +8 -0
  18. data/app/javascript/solidus_friendly_promotions/web_components/product_picker.js +7 -0
  19. data/app/javascript/solidus_friendly_promotions/web_components/select_two.js +11 -0
  20. data/app/javascript/solidus_friendly_promotions/web_components/taxon_picker.js +7 -0
  21. data/app/javascript/solidus_friendly_promotions/web_components/user_picker.js +7 -0
  22. data/app/javascript/solidus_friendly_promotions/web_components/variant_picker.js +7 -0
  23. data/app/javascript/solidus_friendly_promotions.js +7 -11
  24. data/app/models/concerns/solidus_friendly_promotions/{actions/order_level_action.rb → benefits/order_benefit.rb} +2 -2
  25. data/app/models/concerns/solidus_friendly_promotions/{rules/line_item_applicable_order_rule.rb → conditions/line_item_applicable_order_condition.rb} +2 -2
  26. data/app/models/concerns/solidus_friendly_promotions/{rules/line_item_level_rule.rb → conditions/line_item_level_condition.rb} +2 -2
  27. data/app/models/concerns/solidus_friendly_promotions/{rules/order_level_rule.rb → conditions/order_level_condition.rb} +2 -2
  28. data/app/models/concerns/solidus_friendly_promotions/{rules/shipment_level_rule.rb → conditions/shipment_level_condition.rb} +2 -2
  29. data/app/models/solidus_friendly_promotions/{promotion_action.rb → benefit.rb} +48 -11
  30. data/app/models/solidus_friendly_promotions/{actions → benefits}/adjust_line_item.rb +6 -2
  31. data/app/models/solidus_friendly_promotions/{actions → benefits}/adjust_line_item_quantity_groups.rb +3 -3
  32. data/app/models/solidus_friendly_promotions/{actions → benefits}/adjust_shipment.rb +6 -2
  33. data/app/models/solidus_friendly_promotions/{actions → benefits}/create_discounted_item.rb +6 -7
  34. data/app/models/solidus_friendly_promotions/calculators/distributed_amount.rb +1 -1
  35. data/app/models/solidus_friendly_promotions/calculators/tiered_flat_rate.rb +1 -1
  36. data/app/models/solidus_friendly_promotions/calculators/tiered_percent.rb +1 -1
  37. data/app/models/solidus_friendly_promotions/calculators/tiered_percent_on_eligible_item_quantity.rb +4 -2
  38. data/app/models/solidus_friendly_promotions/{promotion_rule.rb → condition.rb} +13 -7
  39. data/app/models/solidus_friendly_promotions/condition_product.rb +8 -0
  40. data/app/models/solidus_friendly_promotions/condition_store.rb +8 -0
  41. data/app/models/solidus_friendly_promotions/condition_taxon.rb +8 -0
  42. data/app/models/solidus_friendly_promotions/{promotion_rules_user.rb → condition_user.rb} +2 -2
  43. data/app/models/solidus_friendly_promotions/{rules → conditions}/discounted_item_total.rb +3 -3
  44. data/app/models/solidus_friendly_promotions/{rules → conditions}/first_order.rb +3 -3
  45. data/app/models/solidus_friendly_promotions/{rules → conditions}/first_repeat_purchase_since.rb +3 -3
  46. data/app/models/solidus_friendly_promotions/{rules → conditions}/item_total.rb +5 -5
  47. data/app/models/solidus_friendly_promotions/{rules → conditions}/line_item_option_value.rb +3 -3
  48. data/app/models/solidus_friendly_promotions/{rules → conditions}/line_item_product.rb +8 -8
  49. data/app/models/solidus_friendly_promotions/{rules → conditions}/line_item_taxon.rb +8 -8
  50. data/app/models/solidus_friendly_promotions/{rules → conditions}/minimum_quantity.rb +8 -8
  51. data/app/models/solidus_friendly_promotions/{rules → conditions}/nth_order.rb +5 -5
  52. data/app/models/solidus_friendly_promotions/{rules → conditions}/one_use_per_user.rb +3 -3
  53. data/app/models/solidus_friendly_promotions/{rules → conditions}/option_value.rb +3 -3
  54. data/app/models/solidus_friendly_promotions/{rules → conditions}/product.rb +9 -9
  55. data/app/models/solidus_friendly_promotions/{rules → conditions}/shipping_method.rb +3 -3
  56. data/app/models/solidus_friendly_promotions/{rules → conditions}/store.rb +6 -6
  57. data/app/models/solidus_friendly_promotions/{rules → conditions}/taxon.rb +12 -12
  58. data/app/models/solidus_friendly_promotions/{rules → conditions}/user.rb +7 -7
  59. data/app/models/solidus_friendly_promotions/{rules → conditions}/user_logged_in.rb +3 -3
  60. data/app/models/solidus_friendly_promotions/{rules → conditions}/user_role.rb +3 -3
  61. data/app/models/solidus_friendly_promotions/eligibility_result.rb +1 -1
  62. data/app/models/solidus_friendly_promotions/eligibility_results.rb +7 -7
  63. data/app/models/solidus_friendly_promotions/friendly_promotion_adjuster/discount_order.rb +28 -29
  64. data/app/models/solidus_friendly_promotions/friendly_promotion_adjuster/load_promotions.rb +10 -11
  65. data/app/models/solidus_friendly_promotions/friendly_promotion_adjuster/persist_discounted_order.rb +2 -2
  66. data/app/models/solidus_friendly_promotions/order_promotion.rb +1 -1
  67. data/app/models/solidus_friendly_promotions/permission_sets/friendly_promotion_management.rb +1 -1
  68. data/app/models/solidus_friendly_promotions/promotion.rb +14 -43
  69. data/app/models/solidus_friendly_promotions/promotion_advertiser.rb +10 -0
  70. data/app/models/solidus_friendly_promotions/promotion_code.rb +1 -1
  71. data/app/models/solidus_friendly_promotions/shipping_rate_discount.rb +1 -1
  72. data/app/views/solidus_friendly_promotions/admin/benefit_fields/_adjust_line_item.html.erb +6 -0
  73. data/app/views/solidus_friendly_promotions/admin/{promotion_actions/actions → benefit_fields}/_adjust_line_item_quantity_groups.html.erb +4 -4
  74. data/app/views/solidus_friendly_promotions/admin/benefit_fields/_adjust_shipment.html.erb +6 -0
  75. data/app/views/solidus_friendly_promotions/admin/benefit_fields/_calculator_fields.erb +11 -0
  76. data/app/views/solidus_friendly_promotions/admin/{promotion_actions/actions → benefit_fields}/_create_discounted_item.html.erb +8 -6
  77. data/app/views/solidus_friendly_promotions/admin/benefits/_benefit.html.erb +50 -0
  78. data/app/views/solidus_friendly_promotions/admin/benefits/_calculator_select.html.erb +16 -0
  79. data/app/views/solidus_friendly_promotions/admin/benefits/_form.html.erb +3 -0
  80. data/app/views/solidus_friendly_promotions/admin/benefits/_new_benefit.html.erb +33 -0
  81. data/app/views/solidus_friendly_promotions/admin/benefits/_type_select.html.erb +16 -0
  82. data/app/views/solidus_friendly_promotions/admin/benefits/edit.html.erb +19 -0
  83. data/app/views/solidus_friendly_promotions/admin/benefits/new.html.erb +1 -0
  84. data/app/views/solidus_friendly_promotions/admin/{promotion_actions/calculators → calculator_fields}/_default_fields.html.erb +1 -1
  85. data/app/views/solidus_friendly_promotions/admin/{promotion_actions/calculators → calculator_fields}/distributed_amount/_fields.html.erb +3 -3
  86. data/app/views/solidus_friendly_promotions/admin/calculator_fields/flat_rate/_fields.html.erb +6 -0
  87. data/app/views/solidus_friendly_promotions/admin/calculator_fields/flexi_rate/_fields.html.erb +24 -0
  88. data/app/views/solidus_friendly_promotions/admin/calculator_fields/percent/_fields.html.erb +6 -0
  89. data/app/views/solidus_friendly_promotions/admin/calculator_fields/tiered_flat_rate/_fields.html.erb +32 -0
  90. data/app/views/solidus_friendly_promotions/admin/{promotion_actions/calculators → calculator_fields}/tiered_flat_rate/_tier_fields.html.erb +7 -8
  91. data/app/views/solidus_friendly_promotions/admin/calculator_fields/tiered_percent/_fields.html.erb +47 -0
  92. data/app/views/solidus_friendly_promotions/admin/{promotion_actions/calculators → calculator_fields}/tiered_percent/_tier_fields.html.erb +8 -7
  93. data/app/views/solidus_friendly_promotions/admin/{promotion_actions/calculators → calculator_fields}/tiered_percent_on_eligible_item_quantity/_fields.html.erb +11 -9
  94. data/app/views/solidus_friendly_promotions/admin/calculator_fields/tiered_percent_on_eligible_item_quantity/_tier_fields.html.erb +35 -0
  95. data/app/views/solidus_friendly_promotions/admin/condition_fields/_first_order.html.erb +3 -0
  96. data/app/views/solidus_friendly_promotions/admin/condition_fields/_first_repeat_purchase_since.html.erb +7 -0
  97. data/app/views/solidus_friendly_promotions/admin/condition_fields/_item_total.html.erb +15 -0
  98. data/app/views/solidus_friendly_promotions/admin/condition_fields/_line_item_option_value.html.erb +25 -0
  99. data/app/views/solidus_friendly_promotions/admin/{promotion_rules/rules → condition_fields}/_line_item_product.html.erb +7 -7
  100. data/app/views/solidus_friendly_promotions/admin/condition_fields/_line_item_taxon.html.erb +17 -0
  101. data/app/views/solidus_friendly_promotions/admin/condition_fields/_minimum_quantity.html.erb +5 -0
  102. data/app/views/solidus_friendly_promotions/admin/condition_fields/_nth_order.html.erb +15 -0
  103. data/app/views/solidus_friendly_promotions/admin/condition_fields/_one_use_per_user.html.erb +3 -0
  104. data/app/views/solidus_friendly_promotions/admin/{promotion_rules/rules → condition_fields}/_option_value.html.erb +10 -10
  105. data/app/views/solidus_friendly_promotions/admin/condition_fields/_product.html.erb +28 -0
  106. data/app/views/solidus_friendly_promotions/admin/{promotion_rules/rules → condition_fields}/_shipping_method.html.erb +3 -3
  107. data/app/views/solidus_friendly_promotions/admin/condition_fields/_store.html.erb +9 -0
  108. data/app/views/solidus_friendly_promotions/admin/condition_fields/_taxon.html.erb +28 -0
  109. data/app/views/solidus_friendly_promotions/admin/condition_fields/_user.html.erb +7 -0
  110. data/app/views/solidus_friendly_promotions/admin/condition_fields/_user_logged_in.html.erb +3 -0
  111. data/app/views/solidus_friendly_promotions/admin/condition_fields/_user_role.html.erb +15 -0
  112. data/app/views/solidus_friendly_promotions/admin/condition_fields/line_item_option_value/_option_value_fields.html.erb +21 -0
  113. data/app/views/solidus_friendly_promotions/admin/conditions/_condition.html.erb +26 -0
  114. data/app/views/solidus_friendly_promotions/admin/conditions/_new_condition.html.erb +26 -0
  115. data/app/views/solidus_friendly_promotions/admin/conditions/_type_select.html.erb +20 -0
  116. data/app/views/solidus_friendly_promotions/admin/conditions/new.html.erb +1 -0
  117. data/app/views/solidus_friendly_promotions/admin/promotion_code_batches/_form_fields.html.erb +5 -5
  118. data/app/views/solidus_friendly_promotions/admin/promotions/_form.html.erb +4 -4
  119. data/app/views/solidus_friendly_promotions/admin/promotions/_table_filter.html.erb +6 -6
  120. data/app/views/solidus_friendly_promotions/admin/promotions/edit.html.erb +7 -41
  121. data/app/views/solidus_friendly_promotions/admin/shared/_number_with_currency.html.erb +20 -0
  122. data/app/views/solidus_friendly_promotions/admin/shared/preference_fields/_boolean.html.erb +14 -0
  123. data/app/views/solidus_friendly_promotions/admin/shared/preference_fields/_decimal.html.erb +12 -0
  124. data/app/views/solidus_friendly_promotions/admin/shared/preference_fields/_encrypted_string.html.erb +12 -0
  125. data/app/views/solidus_friendly_promotions/admin/shared/preference_fields/_integer.html.erb +12 -0
  126. data/app/views/solidus_friendly_promotions/admin/shared/preference_fields/_password.html.erb +12 -0
  127. data/app/views/solidus_friendly_promotions/admin/shared/preference_fields/_string.html.erb +12 -0
  128. data/app/views/solidus_friendly_promotions/admin/shared/preference_fields/_text.html.erb +12 -0
  129. data/bin/sandbox +3 -3
  130. data/config/importmap.rb +2 -0
  131. data/config/locales/en.yml +128 -94
  132. data/config/routes.rb +3 -2
  133. data/db/migrate/20231011120928_add_db_comments_to_friendly_promotion_rules_taxons.rb +2 -2
  134. data/db/migrate/20231011142040_add_db_comments_to_friendly_promotion_rules_users.rb +1 -1
  135. data/db/migrate/20231011190222_add_db_comments_to_friendly_promotion_actions.rb +1 -1
  136. data/db/migrate/20240409093831_add_action_reference_to_rules.rb +34 -0
  137. data/db/migrate/20240506142650_remove_promotion_rules_promotion_id.rb +5 -0
  138. data/db/migrate/20240508080834_rename_promotion_rules_to_conditions.rb +19 -0
  139. data/db/migrate/20240508131514_rename_friendly_promotion_actions_to_friendly_benefits.rb +19 -0
  140. data/db/migrate/20240612113608_update_column_comments_for_benefits.rb +31 -0
  141. data/db/migrate/20240612114132_update_column_comments_for_conditions.rb +30 -0
  142. data/db/migrate/20240612115209_update_column_comments_for_condition_stores.rb +23 -0
  143. data/db/migrate/20240612115749_update_column_comments_for_condition_products.rb +22 -0
  144. data/db/migrate/20240612120411_update_column_comments_for_condition_taxons.rb +24 -0
  145. data/db/migrate/20240612121049_update_column_comments_for_condition_users.rb +23 -0
  146. data/lib/generators/solidus_friendly_promotions/install/templates/initializer.rb +30 -30
  147. data/lib/solidus_friendly_promotions/configuration.rb +11 -3
  148. data/lib/solidus_friendly_promotions/migrate_adjustments.rb +11 -11
  149. data/lib/solidus_friendly_promotions/promotion_map.rb +17 -17
  150. data/lib/solidus_friendly_promotions/promotion_migrator.rb +16 -16
  151. data/lib/solidus_friendly_promotions/testing_support/factories/friendly_promotion_factory.rb +8 -34
  152. data/lib/solidus_friendly_promotions/testing_support/factories/friendly_shipping_rate_discount_factory.rb +2 -2
  153. data/lib/solidus_friendly_promotions/version.rb +1 -1
  154. data/lib/tasks/solidus_friendly_promotions/migrate_adjustments.rake +2 -2
  155. data/solidus_friendly_promotions.gemspec +2 -2
  156. metadata +114 -86
  157. data/.rubocop_todo.yml +0 -157
  158. data/app/controllers/solidus_friendly_promotions/admin/promotion_actions_controller.rb +0 -103
  159. data/app/controllers/solidus_friendly_promotions/admin/promotion_rules_controller.rb +0 -105
  160. data/app/helpers/solidus_friendly_promotions/admin/promotion_actions_helper.rb +0 -23
  161. data/app/helpers/solidus_friendly_promotions/admin/promotion_rules_helper.rb +0 -25
  162. data/app/models/solidus_friendly_promotions/products_promotion_rule.rb +0 -8
  163. data/app/models/solidus_friendly_promotions/promotion_rules_store.rb +0 -8
  164. data/app/models/solidus_friendly_promotions/promotion_rules_taxon.rb +0 -8
  165. data/app/views/solidus_friendly_promotions/admin/promotion_actions/_calculator_select.html.erb +0 -16
  166. data/app/views/solidus_friendly_promotions/admin/promotion_actions/_form.html.erb +0 -3
  167. data/app/views/solidus_friendly_promotions/admin/promotion_actions/_promotion_action.html.erb +0 -29
  168. data/app/views/solidus_friendly_promotions/admin/promotion_actions/_type_select.html.erb +0 -14
  169. data/app/views/solidus_friendly_promotions/admin/promotion_actions/actions/_adjust_line_item.html.erb +0 -6
  170. data/app/views/solidus_friendly_promotions/admin/promotion_actions/actions/_adjust_shipment.html.erb +0 -6
  171. data/app/views/solidus_friendly_promotions/admin/promotion_actions/actions/_calculator_fields.erb +0 -9
  172. data/app/views/solidus_friendly_promotions/admin/promotion_actions/calculators/flat_rate/_fields.html.erb +0 -6
  173. data/app/views/solidus_friendly_promotions/admin/promotion_actions/calculators/tiered_flat_rate/_fields.html.erb +0 -34
  174. data/app/views/solidus_friendly_promotions/admin/promotion_actions/calculators/tiered_percent/_fields.html.erb +0 -34
  175. data/app/views/solidus_friendly_promotions/admin/promotion_actions/calculators/tiered_percent_on_eligible_item_quantity/_tier_fields.html.erb +0 -27
  176. data/app/views/solidus_friendly_promotions/admin/promotion_actions/edit.html.erb +0 -23
  177. data/app/views/solidus_friendly_promotions/admin/promotion_actions/new.html.erb +0 -26
  178. data/app/views/solidus_friendly_promotions/admin/promotion_rules/_promotion_rule.html.erb +0 -22
  179. data/app/views/solidus_friendly_promotions/admin/promotion_rules/_type_select.html.erb +0 -20
  180. data/app/views/solidus_friendly_promotions/admin/promotion_rules/new.html.erb +0 -24
  181. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_first_order.html.erb +0 -3
  182. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_first_repeat_purchase_since.html.erb +0 -6
  183. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_item_total.html.erb +0 -17
  184. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_line_item_option_value.html.erb +0 -25
  185. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_line_item_taxon.html.erb +0 -17
  186. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_minimum_quantity.html.erb +0 -5
  187. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_nth_order.html.erb +0 -15
  188. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_one_use_per_user.html.erb +0 -3
  189. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_product.html.erb +0 -44
  190. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_store.html.erb +0 -9
  191. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_taxon.html.erb +0 -44
  192. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_user.html.erb +0 -7
  193. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_user_logged_in.html.erb +0 -3
  194. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/_user_role.html.erb +0 -15
  195. data/app/views/solidus_friendly_promotions/admin/promotion_rules/rules/line_item_option_value/_option_value_fields.html.erb +0 -17
@@ -3,21 +3,22 @@
3
3
  require "spree/preferences/persistable"
4
4
 
5
5
  module SolidusFriendlyPromotions
6
- # Base class for all types of promotion action.
6
+ # Base class for all types of benefit.
7
7
  #
8
- # PromotionActions perform the necessary tasks when a promotion is activated
8
+ # Benefits perform the necessary tasks when a promotion is activated
9
9
  # by an event and determined to be eligible.
10
- class PromotionAction < Spree::Base
10
+ class Benefit < Spree::Base
11
11
  include Spree::Preferences::Persistable
12
12
  include Spree::CalculatedAdjustments
13
13
  include Spree::AdjustmentSource
14
14
  before_destroy :remove_adjustments_from_incomplete_orders
15
15
  before_destroy :raise_for_adjustments_for_completed_orders
16
16
 
17
- belongs_to :promotion, inverse_of: :actions
17
+ belongs_to :promotion, inverse_of: :benefits
18
18
  belongs_to :original_promotion_action, class_name: "Spree::PromotionAction", optional: true
19
19
  has_many :adjustments, class_name: "Spree::Adjustment", as: :source
20
- has_many :shipping_rate_discounts, class_name: "SolidusFriendlyPromotions::ShippingRateDiscount", inverse_of: :promotion_action
20
+ has_many :shipping_rate_discounts, class_name: "SolidusFriendlyPromotions::ShippingRateDiscount", inverse_of: :benefit
21
+ has_many :conditions, class_name: "SolidusFriendlyPromotions::Condition", inverse_of: :benefit, foreign_key: :benefit_id, dependent: :destroy
21
22
 
22
23
  scope :of_type, ->(type) { where(type: Array.wrap(type).map(&:to_s)) }
23
24
 
@@ -55,21 +56,57 @@ module SolidusFriendlyPromotions
55
56
  end
56
57
 
57
58
  def to_partial_path
58
- "solidus_friendly_promotions/admin/promotion_actions/actions/#{model_name.element}"
59
+ "solidus_friendly_promotions/admin/benefit_fields/#{model_name.element}"
59
60
  end
60
61
 
61
62
  def level
62
63
  raise NotImplementedError
63
64
  end
64
65
 
65
- def relevant_rules
66
- promotion.rules.select do |rule|
67
- rule.level.in?([:order, level].uniq)
68
- end
66
+ def available_conditions
67
+ possible_conditions - conditions.select(&:persisted?)
69
68
  end
70
69
 
71
70
  def available_calculators
72
- SolidusFriendlyPromotions.config.promotion_calculators[self.class] || (raise NotImplementedError)
71
+ SolidusFriendlyPromotions.config.promotion_calculators[self.class] || []
72
+ end
73
+
74
+ def eligible_by_applicable_conditions?(promotable, dry_run: false)
75
+ applicable_conditions = conditions.select do |condition|
76
+ condition.applicable?(promotable)
77
+ end
78
+
79
+ applicable_conditions.map do |applicable_condition|
80
+ eligible = applicable_condition.eligible?(promotable)
81
+
82
+ break [false] if !eligible && !dry_run
83
+
84
+ if dry_run
85
+ if applicable_condition.eligibility_errors.details[:base].first
86
+ code = applicable_condition.eligibility_errors.details[:base].first[:error_code]
87
+ message = applicable_condition.eligibility_errors.full_messages.first
88
+ end
89
+ promotion.eligibility_results.add(
90
+ item: promotable,
91
+ condition: applicable_condition,
92
+ success: eligible,
93
+ code: eligible ? nil : (code || :coupon_code_unknown_error),
94
+ message: eligible ? nil : (message || I18n.t(:coupon_code_unknown_error, scope: [:solidus_friendly_promotions, :eligibility_errors]))
95
+ )
96
+ end
97
+
98
+ eligible
99
+ end.all?
100
+ end
101
+
102
+ def applicable_line_items(order)
103
+ order.discountable_line_items.select do |line_item|
104
+ eligible_by_applicable_conditions?(line_item)
105
+ end
106
+ end
107
+
108
+ def possible_conditions
109
+ Set.new(SolidusFriendlyPromotions.config.order_conditions)
73
110
  end
74
111
 
75
112
  private
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Actions
5
- class AdjustLineItem < PromotionAction
4
+ module Benefits
5
+ class AdjustLineItem < Benefit
6
6
  def can_discount?(object)
7
7
  object.is_a? Spree::LineItem
8
8
  end
@@ -10,6 +10,10 @@ module SolidusFriendlyPromotions
10
10
  def level
11
11
  :line_item
12
12
  end
13
+
14
+ def possible_conditions
15
+ super + SolidusFriendlyPromotions.config.line_item_conditions
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Actions
4
+ module Benefits
5
5
  class AdjustLineItemQuantityGroups < AdjustLineItem
6
6
  preference :group_size, :integer, default: 1
7
7
 
8
8
  ##
9
9
  # Computes the amount for the adjustment based on the line item and any
10
- # other applicable items in the order. The rules for this specific
10
+ # other applicable items in the order. The conditions for this specific
11
11
  # adjustment are as follows:
12
12
  #
13
13
  # = Setup
@@ -58,7 +58,7 @@ module SolidusFriendlyPromotions
58
58
  adjustment_amount = adjustment_amount.abs
59
59
 
60
60
  order = line_item.order
61
- line_items = promotion.applicable_line_items(order)
61
+ line_items = applicable_line_items(order)
62
62
 
63
63
  item_units = line_items.sort_by do |line_item|
64
64
  [-line_item.quantity, line_item.id]
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Actions
5
- class AdjustShipment < PromotionAction
4
+ module Benefits
5
+ class AdjustShipment < Benefit
6
6
  def can_discount?(object)
7
7
  object.is_a?(Spree::Shipment) || object.is_a?(Spree::ShippingRate)
8
8
  end
@@ -10,6 +10,10 @@ module SolidusFriendlyPromotions
10
10
  def level
11
11
  :shipment
12
12
  end
13
+
14
+ def possible_conditions
15
+ super + SolidusFriendlyPromotions.config.shipment_conditions
16
+ end
13
17
  end
14
18
  end
15
19
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Actions
5
- class CreateDiscountedItem < PromotionAction
6
- include OrderLevelAction
4
+ module Benefits
5
+ class CreateDiscountedItem < Benefit
6
+ include OrderBenefit
7
7
  preference :variant_id, :integer
8
8
  preference :quantity, :integer, default: 1
9
9
  preference :necessary_quantity, :integer, default: 1
@@ -22,19 +22,18 @@ module SolidusFriendlyPromotions
22
22
  private
23
23
 
24
24
  def find_item(order)
25
- order.line_items.detect { |line_item| line_item.managed_by_order_action == self }
25
+ order.line_items.detect { |line_item| line_item.managed_by_order_benefit == self }
26
26
  end
27
27
 
28
28
  def create_item(order)
29
- order.line_items.create!(quantity: determine_item_quantity(order), variant: variant, managed_by_order_action: self)
29
+ order.line_items.create!(quantity: determine_item_quantity(order), variant: variant, managed_by_order_benefit: self)
30
30
  end
31
31
 
32
32
  def determine_item_quantity(order)
33
- applicable_line_items = promotion.applicable_line_items(order)
34
33
  # Integer division will floor automatically, which is what we want here:
35
34
  # 1 Item, 2 needed: 1 * 1 / 2 => 0
36
35
  # 5 items, 2 preferred, 2 needed: 5 / 2 * 2 => 4
37
- applicable_line_items.sum(&:quantity) / preferred_necessary_quantity * preferred_quantity
36
+ applicable_line_items(order).sum(&:quantity) / preferred_necessary_quantity * preferred_quantity
38
37
  end
39
38
 
40
39
  def set_quantity(line_item, quantity)
@@ -18,7 +18,7 @@ module SolidusFriendlyPromotions
18
18
  return 0 unless line_item
19
19
  return 0 unless preferred_currency.casecmp(line_item.currency).zero?
20
20
 
21
- distributable_line_items = calculable.promotion.applicable_line_items(line_item.order)
21
+ distributable_line_items = calculable.applicable_line_items(line_item.order)
22
22
  return 0 unless line_item.in?(distributable_line_items)
23
23
 
24
24
  DistributedAmountsHandler.new(
@@ -8,7 +8,7 @@ module SolidusFriendlyPromotions
8
8
  include PromotionCalculator
9
9
 
10
10
  preference :base_amount, :decimal, default: 0
11
- preference :tiers, :hash, default: {}
11
+ preference :tiers, :hash, default: {10 => 10}
12
12
  preference :currency, :string, default: -> { Spree::Config[:currency] }
13
13
 
14
14
  before_validation do
@@ -8,7 +8,7 @@ module SolidusFriendlyPromotions
8
8
  include PromotionCalculator
9
9
 
10
10
  preference :base_percent, :decimal, default: 0
11
- preference :tiers, :hash, default: {}
11
+ preference :tiers, :hash, default: {50 => 5}
12
12
  preference :currency, :string, default: -> { Spree::Config[:currency] }
13
13
 
14
14
  before_validation do
@@ -3,11 +3,13 @@ require_dependency "spree/calculator"
3
3
  module SolidusFriendlyPromotions
4
4
  module Calculators
5
5
  class TieredPercentOnEligibleItemQuantity < SolidusFriendlyPromotions::Calculators::TieredPercent
6
+ preference :tiers, :hash, default: {10 => 5}
7
+
6
8
  before_validation do
7
9
  # Convert tier values to decimals. Strings don't do us much good.
8
10
  if preferred_tiers.is_a?(Hash)
9
11
  self.preferred_tiers = preferred_tiers.map do |key, value|
10
- [cast_to_d(key.to_i), cast_to_d(value.to_s)]
12
+ [key.to_i, cast_to_d(value.to_s)]
11
13
  end.to_h
12
14
  end
13
15
  end
@@ -29,7 +31,7 @@ module SolidusFriendlyPromotions
29
31
  private
30
32
 
31
33
  def eligible_line_items_quantity_total(order)
32
- calculable.promotion.applicable_line_items(order).sum(&:quantity)
34
+ calculable.applicable_line_items(order).sum(&:quantity)
33
35
  end
34
36
  end
35
37
  end
@@ -3,14 +3,16 @@
3
3
  require "spree/preferences/persistable"
4
4
 
5
5
  module SolidusFriendlyPromotions
6
- class PromotionRule < Spree::Base
6
+ class Condition < Spree::Base
7
7
  include Spree::Preferences::Persistable
8
8
 
9
- belongs_to :promotion
9
+ belongs_to :benefit, class_name: "SolidusFriendlyPromotions::Benefit", inverse_of: :conditions, optional: true
10
+ has_one :promotion, through: :benefit
10
11
 
11
12
  scope :of_type, ->(type) { where(type: type) }
12
13
 
13
- validate :unique_per_promotion, on: :create
14
+ validate :unique_per_benefit, on: :create
15
+ validate :possible_condition_for_benefit, if: -> { benefit.present? }
14
16
 
15
17
  def preload_relations
16
18
  []
@@ -33,7 +35,7 @@ module SolidusFriendlyPromotions
33
35
  end
34
36
 
35
37
  def to_partial_path
36
- "solidus_friendly_promotions/admin/promotion_rules/rules/#{model_name.element}"
38
+ "solidus_friendly_promotions/admin/condition_fields/#{model_name.element}"
37
39
  end
38
40
 
39
41
  def updateable?
@@ -42,10 +44,14 @@ module SolidusFriendlyPromotions
42
44
 
43
45
  private
44
46
 
45
- def unique_per_promotion
46
- return unless self.class.exists?(promotion_id: promotion_id, type: self.class.name)
47
+ def unique_per_benefit
48
+ return unless self.class.exists?(benefit_id: benefit_id, type: self.class.name)
47
49
 
48
- errors.add(:promotion, :already_contains_rule_type)
50
+ errors.add(:benefit, :already_contains_condition_type)
51
+ end
52
+
53
+ def possible_condition_for_benefit
54
+ benefit.possible_conditions.include?(self.class) || errors.add(:type, :invalid_condition_type)
49
55
  end
50
56
 
51
57
  def eligibility_error_message(key, options = {})
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusFriendlyPromotions
4
+ class ConditionProduct < Spree::Base
5
+ belongs_to :condition, class_name: "SolidusFriendlyPromotions::Condition", optional: true
6
+ belongs_to :product, class_name: "Spree::Product", optional: true
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusFriendlyPromotions
4
+ class ConditionStore < Spree::Base
5
+ belongs_to :condition, class_name: "SolidusFriendlyPromotions::Condition", optional: true
6
+ belongs_to :store, class_name: "Spree::Store", optional: true
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusFriendlyPromotions
4
+ class ConditionTaxon < Spree::Base
5
+ belongs_to :condition, class_name: "SolidusFriendlyPromotions::Condition", optional: true
6
+ belongs_to :taxon, class_name: "Spree::Taxon", optional: true
7
+ end
8
+ end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- class PromotionRulesUser < Spree::Base
5
- belongs_to :promotion_rule, class_name: "SolidusFriendlyPromotions::PromotionRule", optional: true
4
+ class ConditionUser < Spree::Base
5
+ belongs_to :condition, class_name: "SolidusFriendlyPromotions::Condition", optional: true
6
6
  belongs_to :user, class_name: Spree::UserClassHandle.new, optional: true
7
7
  end
8
8
  end
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- # A rule to apply to an order greater than (or greater than or equal to)
4
+ module Conditions
5
+ # A condition to apply to an order greater than (or greater than or equal to)
6
6
  # a specific amount after previous promotions have applied
7
7
  #
8
8
  # To add extra operators please override `self.operators_map` or any other helper method.
9
9
  # To customize the error message you can also override `ineligible_message`.
10
10
  class DiscountedItemTotal < ItemTotal
11
11
  def to_partial_path
12
- "solidus_friendly_promotions/admin/promotion_rules/rules/item_total"
12
+ "solidus_friendly_promotions/admin/condition_fields/item_total"
13
13
  end
14
14
 
15
15
  private
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- class FirstOrder < PromotionRule
6
- include OrderLevelRule
4
+ module Conditions
5
+ class FirstOrder < Condition
6
+ include OrderLevelCondition
7
7
  attr_reader :user, :email
8
8
 
9
9
  def eligible?(order, options = {})
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- class FirstRepeatPurchaseSince < PromotionRule
6
- include OrderLevelRule
4
+ module Conditions
5
+ class FirstRepeatPurchaseSince < Condition
6
+ include OrderLevelCondition
7
7
 
8
8
  preference :days_ago, :integer, default: 365
9
9
  validates :preferred_days_ago, numericality: {only_integer: true, greater_than: 0}
@@ -1,14 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- # A rule to apply to an order greater than (or greater than or equal to)
4
+ module Conditions
5
+ # A condition to apply to an order greater than (or greater than or equal to)
6
6
  # a specific amount
7
7
  #
8
8
  # To add extra operators please override `self.operators_map` or any other helper method.
9
9
  # To customize the error message you can also override `ineligible_message`.
10
- class ItemTotal < PromotionRule
11
- include OrderLevelRule
10
+ class ItemTotal < Condition
11
+ include OrderLevelCondition
12
12
 
13
13
  preference :amount, :decimal, default: 100.00
14
14
  preference :currency, :string, default: -> { Spree::Config[:currency] }
@@ -24,7 +24,7 @@ module SolidusFriendlyPromotions
24
24
 
25
25
  def self.operator_options
26
26
  operators_map.map do |name, _method|
27
- [I18n.t(name, scope: "spree.item_total_rule.operators"), name]
27
+ [I18n.t(name, scope: "solidus_friendly_promotions.item_total_condition.operators"), name]
28
28
  end
29
29
  end
30
30
 
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- class LineItemOptionValue < PromotionRule
6
- include LineItemLevelRule
4
+ module Conditions
5
+ class LineItemOptionValue < Condition
6
+ include LineItemLevelCondition
7
7
 
8
8
  preference :eligible_values, :hash
9
9
 
@@ -1,20 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- # A rule to apply a promotion only to line items with or without a chosen product
6
- class LineItemProduct < PromotionRule
7
- include LineItemLevelRule
4
+ module Conditions
5
+ # A condition to apply a promotion only to line items with or without a chosen product
6
+ class LineItemProduct < Condition
7
+ include LineItemLevelCondition
8
8
 
9
9
  MATCH_POLICIES = %w[include exclude].freeze
10
10
 
11
- has_many :product_promotion_rules,
11
+ has_many :condition_products,
12
12
  dependent: :destroy,
13
- foreign_key: :promotion_rule_id,
14
- class_name: "SolidusFriendlyPromotions::ProductsPromotionRule"
13
+ foreign_key: :condition_id,
14
+ class_name: "SolidusFriendlyPromotions::ConditionProduct"
15
15
  has_many :products,
16
16
  class_name: "Spree::Product",
17
- through: :product_promotion_rules
17
+ through: :condition_products
18
18
 
19
19
  preference :match_policy, :string, default: MATCH_POLICIES.first
20
20
 
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- class LineItemTaxon < PromotionRule
6
- include LineItemLevelRule
4
+ module Conditions
5
+ class LineItemTaxon < Condition
6
+ include LineItemLevelCondition
7
7
 
8
- has_many :promotion_rule_taxons, class_name: "SolidusFriendlyPromotions::PromotionRulesTaxon", foreign_key: :promotion_rule_id,
8
+ has_many :condition_taxons, class_name: "SolidusFriendlyPromotions::ConditionTaxon", foreign_key: :condition_id,
9
9
  dependent: :destroy
10
- has_many :taxons, through: :promotion_rule_taxons, class_name: "Spree::Taxon"
10
+ has_many :taxons, through: :condition_taxons, class_name: "Spree::Taxon"
11
11
 
12
12
  MATCH_POLICIES = %w[include exclude].freeze
13
13
 
@@ -18,7 +18,7 @@ module SolidusFriendlyPromotions
18
18
  def eligible?(line_item, _options = {})
19
19
  found = Spree::Classification.where(
20
20
  product_id: line_item.variant.product_id,
21
- taxon_id: rule_taxon_ids_with_children
21
+ taxon_id: condition_taxon_ids_with_children
22
22
  ).exists?
23
23
 
24
24
  case preferred_match_policy
@@ -46,8 +46,8 @@ module SolidusFriendlyPromotions
46
46
 
47
47
  private
48
48
 
49
- # ids of taxons rules and taxons rules children
50
- def rule_taxon_ids_with_children
49
+ # ids of taxons conditions and taxons conditions children
50
+ def condition_taxon_ids_with_children
51
51
  taxons.flat_map { |taxon| taxon.self_and_descendants.ids }.uniq
52
52
  end
53
53
  end
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- # Promotion rule for ensuring an order contains a minimum quantity of
4
+ module Conditions
5
+ # Promotion condition for ensuring an order contains a minimum quantity of
6
6
  # applicable items.
7
7
  #
8
- # This promotion rule is only compatible with the "all" match policy. It
8
+ # This promotion condition is only compatible with the "all" match policy. It
9
9
  # doesn't make a lot of sense to use it without that policy as it reduces
10
10
  # it to a simple quantity check across the entire order which would be
11
- # better served by an item total rule.
12
- class MinimumQuantity < PromotionRule
13
- include OrderLevelRule
11
+ # better served by an item total condition.
12
+ class MinimumQuantity < Condition
13
+ include OrderLevelCondition
14
14
 
15
15
  validates :preferred_minimum_quantity, numericality: {only_integer: true, greater_than: 0}
16
16
 
@@ -19,7 +19,7 @@ module SolidusFriendlyPromotions
19
19
  # Will look at all of the "applicable" line items in the order and
20
20
  # determine if the sum of their quantity is greater than the minimum.
21
21
  #
22
- # "Applicable" items are ones that pass all eligibility checks of applicable rules.
22
+ # "Applicable" items are ones that pass all eligibility checks of applicable conditions.
23
23
  #
24
24
  # When false is returned, the reason will be included in the
25
25
  # `eligibility_errors` object.
@@ -27,7 +27,7 @@ module SolidusFriendlyPromotions
27
27
  # @param order [Spree::Order] the order we want to check eligibility on
28
28
  # @return [Boolean] true if promotion is eligible, false otherwise
29
29
  def eligible?(order)
30
- if promotion.applicable_line_items(order).sum(&:quantity) < preferred_minimum_quantity
30
+ if benefit.applicable_line_items(order).sum(&:quantity) < preferred_minimum_quantity
31
31
  eligibility_errors.add(
32
32
  :base,
33
33
  eligibility_error_message(:quantity_less_than_minimum, count: preferred_minimum_quantity),
@@ -1,18 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- class NthOrder < PromotionRule
6
- include OrderLevelRule
4
+ module Conditions
5
+ class NthOrder < Condition
6
+ include OrderLevelCondition
7
7
 
8
8
  preference :nth_order, :integer, default: 2
9
9
  # It does not make sense to have this apply to the first order using preferred_nth_order == 1
10
- # Instead we could use the first_order rule
10
+ # Instead we could use the first_order condition
11
11
  validates :preferred_nth_order, numericality: {only_integer: true, greater_than: 1}
12
12
 
13
13
  # This is never eligible if the order does not have a user, and that user does not have any previous completed orders.
14
14
  #
15
- # Use the first order rule if you want a promotion to be applied to the first order for a user.
15
+ # Use the first order condition if you want a promotion to be applied to the first order for a user.
16
16
  # @param order [Spree::Order]
17
17
  def eligible?(order, _options = {})
18
18
  return false unless order.user
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- class OneUsePerUser < PromotionRule
6
- include OrderLevelRule
4
+ module Conditions
5
+ class OneUsePerUser < Condition
6
+ include OrderLevelCondition
7
7
 
8
8
  def eligible?(order, _options = {})
9
9
  if order.user.present?
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- class OptionValue < PromotionRule
6
- include LineItemApplicableOrderRule
4
+ module Conditions
5
+ class OptionValue < Condition
6
+ include LineItemApplicableOrderCondition
7
7
 
8
8
  preference :eligible_values, :hash
9
9
 
@@ -1,19 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- # A rule to limit a promotion based on products in the order. Can
4
+ module Conditions
5
+ # A condition to limit a promotion based on products in the order. Can
6
6
  # require all or any of the products to be present. Valid products
7
7
  # either come from assigned product group or are assingned directly to
8
- # the rule.
9
- class Product < PromotionRule
10
- include LineItemApplicableOrderRule
8
+ # the condition.
9
+ class Product < Condition
10
+ include LineItemApplicableOrderCondition
11
11
 
12
- has_many :products_promotion_rules,
12
+ has_many :condition_products,
13
13
  dependent: :destroy,
14
- foreign_key: :promotion_rule_id,
15
- class_name: "SolidusFriendlyPromotions::ProductsPromotionRule"
16
- has_many :products, class_name: "Spree::Product", through: :products_promotion_rules
14
+ foreign_key: :condition_id,
15
+ class_name: "SolidusFriendlyPromotions::ConditionProduct"
16
+ has_many :products, class_name: "Spree::Product", through: :condition_products
17
17
 
18
18
  def preload_relations
19
19
  [:products]
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- module Rules
5
- class ShippingMethod < PromotionRule
6
- include ShipmentLevelRule
4
+ module Conditions
5
+ class ShippingMethod < Condition
6
+ include ShipmentLevelCondition
7
7
 
8
8
  preference :shipping_method_ids, type: :array, default: []
9
9