solidus_friendly_promotions 1.0.0.pre → 1.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '042911d4cf39c2bddcce9c5826f8c8f790e2ca8396cc32d339c7f5c2dea0a834'
4
- data.tar.gz: cf2a4ee16b1d40a6d89771de93b37b145bfce413aab7114a0660cdf0c5798d27
3
+ metadata.gz: ac98e07030bf9f63775dafdffc94d3a6be02b8050664037469f57a32dc71da43
4
+ data.tar.gz: fdd1d7e3fbbfc92cb347af92c28c5f518d91724a330408a576d47449c6e8f201
5
5
  SHA512:
6
- metadata.gz: 5ffa465ffa65e01a30adae44873edabe2fa25594b7c3c09beda6e0e2946ed4e8fdbec547dafc4d22974bbeddb0a978a96c65c5c83f3b300d4e9b0473dc809f23
7
- data.tar.gz: 601306df6e5de918612d12ed6084d2a6ea2b690d15ef13ff36d826a541dc19dabaf84b62ea74c0065f106baf256089df544e9814fe3ddcc4da5635ffc8e74c60
6
+ metadata.gz: c9eb24c1fabf89ee0b61731b8541e1459dfe9d508ffc2721f8f1384df382c1653b94f407c04438a2047ebf0fc868e4849fc5f88b821ab141eac44b21bde910b9
7
+ data.tar.gz: 1e89490f9daf5ad6480b37bc47581bb7ba4a948bb1af7aa7b9539b3c094c6549db4055132b53155e3fc419f881b71d64c81577ba447d188e704eda176bd5b808
@@ -2,6 +2,20 @@
2
2
 
3
3
  module SolidusFriendlyPromotions
4
4
  module LineItemDecorator
5
+ def self.prepended(base)
6
+ base.belongs_to :managed_by_order_action, class_name: "SolidusFriendlyPromotions::PromotionAction", optional: true
7
+ base.validate :validate_managed_quantity_same, on: :update
8
+ end
9
+
10
+ private
11
+
12
+ def validate_managed_quantity_same
13
+ if managed_by_order_action && quantity_changed?
14
+ errors.add(:quantity, :cannot_be_changed_for_automated_items)
15
+ end
16
+ end
17
+
18
+ Spree::LineItem.prepend self
5
19
  Spree::LineItem.prepend SolidusFriendlyPromotions::DiscountableAmount
6
20
  end
7
21
  end
@@ -29,6 +29,13 @@ module SolidusFriendlyPromotions
29
29
  shipments.each(&:reset_current_discounts)
30
30
  end
31
31
 
32
+ # This helper method excludes line items that are managed by an order action for the benefit
33
+ # of calculators and actions that discount normal line items. Line items that are managed by an
34
+ # order actions handle their discounts themselves.
35
+ def discountable_line_items
36
+ line_items.reject(&:managed_by_order_action)
37
+ end
38
+
32
39
  def apply_shipping_promotions
33
40
  if Spree::Config.promotion_adjuster_class <= SolidusFriendlyPromotions::FriendlyPromotionAdjuster
34
41
  recalculate
@@ -37,6 +44,10 @@ module SolidusFriendlyPromotions
37
44
  end
38
45
  end
39
46
 
47
+ def free_from_order_action?(line_item, _options)
48
+ !line_item.managed_by_order_action
49
+ end
50
+
40
51
  Spree::Order.prepend self
41
52
  end
42
53
  end
@@ -4,9 +4,12 @@ import "solidus_friendly_promotions/jquery/option_value_picker"
4
4
 
5
5
  Turbo.session.drive = false;
6
6
 
7
- document.addEventListener("turbo:frame-load", ({ _target }) => {
7
+ const initPickers = ({ _target }) => {
8
8
  Spree.initNumberWithCurrency();
9
9
  $(".product_picker").productAutocomplete();
10
10
  $(".user_picker").userAutocomplete();
11
11
  $(".taxon_picker").taxonAutocomplete();
12
- });
12
+ $(".variant_autocomplete").variantAutocomplete();
13
+ };
14
+ document.addEventListener("turbo:frame-load", initPickers);
15
+ document.addEventListener("DOMContentLoaded", initPickers);
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusFriendlyPromotions
4
+ module Actions
5
+ module OrderLevelAction
6
+ def can_discount?(_)
7
+ false
8
+ end
9
+
10
+ def level
11
+ :order
12
+ end
13
+ end
14
+ end
15
+ end
@@ -79,7 +79,7 @@ module SolidusFriendlyPromotions
79
79
  private
80
80
 
81
81
  def actionable_line_items(order)
82
- order.line_items.select do |item|
82
+ order.discountable_line_items.select do |item|
83
83
  promotion.rules.select do |rule|
84
84
  rule.applicable?(item)
85
85
  end.all? { |rule| rule.eligible?(item) }
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusFriendlyPromotions
4
+ module Actions
5
+ class CreateDiscountedItem < PromotionAction
6
+ include OrderLevelAction
7
+ preference :variant_id, :integer
8
+ preference :quantity, :integer, default: 1
9
+
10
+ def perform(order)
11
+ line_item = find_item(order) || create_item(order)
12
+ line_item.current_discounts << discount(line_item)
13
+ end
14
+
15
+ def remove_from(order)
16
+ line_item = find_item(order)
17
+ order.line_items.destroy(line_item)
18
+ end
19
+
20
+ private
21
+
22
+ def find_item(order)
23
+ order.line_items.detect { |line_item| line_item.managed_by_order_action == self }
24
+ end
25
+
26
+ def create_item(order)
27
+ order.line_items.create!(quantity: preferred_quantity, variant: variant, managed_by_order_action: self)
28
+ end
29
+
30
+ def variant
31
+ Spree::Variant.find(preferred_variant_id)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -28,7 +28,7 @@ module SolidusFriendlyPromotions
28
28
  private
29
29
 
30
30
  def eligible_line_items(order)
31
- order.line_items.select do |line_item|
31
+ order.discountable_line_items.select do |line_item|
32
32
  calculable.promotion.eligible_by_applicable_rules?(line_item)
33
33
  end
34
34
  end
@@ -16,6 +16,7 @@ module SolidusFriendlyPromotions
16
16
 
17
17
  SolidusFriendlyPromotions::Promotion.ordered_lanes.each do |lane, _index|
18
18
  lane_promotions = eligible_promotions_for_promotable(promotions.select { |promotion| promotion.lane == lane }, order)
19
+ perform_order_actions(lane_promotions, lane) unless dry_run
19
20
  line_item_discounts = adjust_line_items(lane_promotions)
20
21
  shipment_discounts = adjust_shipments(lane_promotions)
21
22
  shipping_rate_discounts = adjust_shipping_rates(lane_promotions)
@@ -29,8 +30,25 @@ module SolidusFriendlyPromotions
29
30
 
30
31
  private
31
32
 
33
+ def perform_order_actions(lane_promotions, lane)
34
+ lane_promotions.each do |promotion|
35
+ promotion.actions.select { |action| action.level == :order }.each { |action| action.perform(order) }
36
+ end
37
+
38
+ automated_line_items = order.line_items.select(&:managed_by_order_action)
39
+ return if automated_line_items.empty?
40
+
41
+ ineligible_line_items = automated_line_items.select do |line_item|
42
+ line_item.managed_by_order_action.promotion.lane == lane && !line_item.managed_by_order_action.in?(lane_promotions.flat_map(&:actions))
43
+ end
44
+
45
+ ineligible_line_items.each do |line_item|
46
+ line_item.managed_by_order_action.remove_from(order)
47
+ end
48
+ end
49
+
32
50
  def adjust_line_items(promotions)
33
- order.line_items.select do |line_item|
51
+ order.discountable_line_items.select do |line_item|
34
52
  line_item.variant.product.promotionable?
35
53
  end.map do |line_item|
36
54
  discounts = generate_discounts(promotions, line_item)
@@ -27,7 +27,6 @@ module SolidusFriendlyPromotions
27
27
  end
28
28
  end
29
29
  order.reset_current_discounts
30
- order.promo_total = (order.line_items + order.shipments).sum(&:promo_total)
31
30
  order
32
31
  end
33
32
 
@@ -19,6 +19,13 @@ module SolidusFriendlyPromotions
19
19
  PersistDiscountedOrder.new(discounted_order).call unless dry_run
20
20
 
21
21
  order.reset_current_discounts
22
+
23
+ unless dry_run
24
+ # Since automations might have added a line item, we need to recalculate item total and item count here.
25
+ order.item_total = order.line_items.sum(&:amount)
26
+ order.item_count = order.line_items.sum(&:quantity)
27
+ order.promo_total = (order.line_items + order.shipments).sum(&:promo_total)
28
+ end
22
29
  order
23
30
  end
24
31
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SolidusFriendlyPromotions
4
+ module PromotionHandler
5
+ # We handle shipping promotions just like other promotions, so we don't need a
6
+ # special promotion handler for shipping. However, Solidus wants us to implement one.
7
+ # This is what this class is for.
8
+ class Null
9
+ attr_reader :order
10
+ attr_accessor :error, :success
11
+
12
+ def initialize(order)
13
+ @order = order
14
+ end
15
+
16
+ def activate
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ <%= fields_for param_prefix, promotion_action do |form| %>
2
+ <div class="field">
3
+ <%= form.label :preferred_variant_id %>
4
+ <%= form.text_field :preferred_variant_id, class: "variant_autocomplete fullwidth" %>
5
+ <%= form.label :preferred_quantity %>
6
+ <%= form.number_field :preferred_quantity, class: "fullwidth" %>
7
+ </div>
8
+ <% end %>
9
+
10
+ <%= render(
11
+ "solidus_friendly_promotions/admin/promotion_actions/actions/calculator_fields",
12
+ promotion_action: promotion_action,
13
+ param_prefix: param_prefix,
14
+ form: form
15
+ ) %>
@@ -48,26 +48,28 @@
48
48
  </div>
49
49
 
50
50
  <div class="row">
51
- <% [:line_item, :shipment].each do |level| %>
51
+ <% [:order, :line_item, :shipment].each do |level| %>
52
52
  <% if promotion_actions_by_level(@promotion, level).any? %>
53
- <div class="col-6">
53
+ <div class="col-<%= level == :order ? 12 : 6 %>">
54
54
  <fieldset>
55
55
  <legend align="center"><%= t("#{level}_actions", scope: :solidus_friendly_promotions) %></legend>
56
56
 
57
57
  <%= render partial: 'solidus_friendly_promotions/admin/promotion_actions/promotion_action', collection: promotion_actions_by_level(@promotion, level), locals: {} %>
58
58
  </fieldset>
59
59
  </div>
60
- <div class="col-6">
61
- <fieldset>
62
- <legend align="center"><%= t("#{level}_rules", scope: :solidus_friendly_promotions) %></legend>
60
+ <% if level != :order %>
61
+ <div class="col-6">
62
+ <fieldset>
63
+ <legend align="center"><%= t("#{level}_rules", scope: :solidus_friendly_promotions) %></legend>
63
64
 
64
- <%= render partial: 'solidus_friendly_promotions/admin/promotion_rules/promotion_rule', collection: promotion_rules_by_level(@promotion, level), locals: { level: level } %>
65
+ <%= render partial: 'solidus_friendly_promotions/admin/promotion_rules/promotion_rule', collection: promotion_rules_by_level(@promotion, level), locals: { level: level } %>
65
66
 
66
- <%= turbo_frame_tag @promotion, "new_#{level}_promotion_rule" do %>
67
- <%= link_to t(:add_rule, scope: :solidus_friendly_promotions), solidus_friendly_promotions.new_admin_promotion_promotion_rule_path(@promotion, level: level), class: 'btn btn-secondary' %>
68
- <% end %>
69
- </fieldset>
70
- </div>
67
+ <%= turbo_frame_tag @promotion, "new_#{level}_promotion_rule" do %>
68
+ <%= link_to t(:add_rule, scope: :solidus_friendly_promotions), solidus_friendly_promotions.new_admin_promotion_promotion_rule_path(@promotion, level: level), class: 'btn btn-secondary' %>
69
+ <% end %>
70
+ </fieldset>
71
+ </div>
72
+ <% end %>
71
73
  <% end %>
72
74
  <% end %>
73
75
  </div>
@@ -23,6 +23,7 @@ en:
23
23
  shipment_rules: Shipment Rules
24
24
  line_item_actions: Line Item Actions
25
25
  shipment_actions: Shipment Actions
26
+ order_actions: Order Actions
26
27
  invalid_promotion_rule_level: Invalid Promotion Rule Level. Must be one of "order", "shipment", or "line_item"
27
28
  invalid_promotion_action: Invalid promotion action.
28
29
  invalid_promotion_rule: Invalid promotion rule.
@@ -161,6 +162,7 @@ en:
161
162
  models:
162
163
  solidus_friendly_promotions/actions/adjust_shipment: Discount matching shipments
163
164
  solidus_friendly_promotions/actions/adjust_line_item: Discount matching line items
165
+ solidus_friendly_promotions/actions/create_discounted_item: Create discounted line item
164
166
  solidus_friendly_promotions/actions/adjust_line_item_quantity_groups: Discount matching line items based on quantity groups
165
167
  solidus_friendly_promotions/calculators/distributed_amount: Distributed Amount
166
168
  solidus_friendly_promotions/calculators/percent: Flat Percent
@@ -199,6 +201,8 @@ en:
199
201
  description: Creates a promotion credit on matching line items
200
202
  solidus_friendly_promotions/actions/adjust_shipment:
201
203
  description: Creates a promotion credit on matching shipments
204
+ solidus_friendly_promotions/actions/create_discounted_item:
205
+ description: Creates a discounted item
202
206
  solidus_friendly_promotions/rules/first_order:
203
207
  description: Must be the customer's first order
204
208
  solidus_friendly_promotions/rules/first_repeat_purchase_since:
@@ -253,3 +257,7 @@ en:
253
257
  attributes:
254
258
  base:
255
259
  disallowed_with_apply_automatically: Could not create promotion code on promotion that apply automatically
260
+ spree/line_item:
261
+ attributes:
262
+ quantity:
263
+ cannot_be_changed_for_automated_items: cannot be changed on a line item managed by a promotion action
@@ -0,0 +1,5 @@
1
+ class AddManagedByOrderActionToLineItems < ActiveRecord::Migration[7.0]
2
+ def change
3
+ add_reference :spree_line_items, :managed_by_order_action, foreign_key: {to_table: :friendly_promotion_actions, null: true}
4
+ end
5
+ end
@@ -4,6 +4,10 @@
4
4
  Spree::Config.order_contents_class = "SolidusFriendlyPromotions::SimpleOrderContents"
5
5
  Spree::Config.promotion_adjuster_class = "SolidusFriendlyPromotions::FriendlyPromotionAdjuster"
6
6
 
7
+ Rails.application.config.to_prepare do |config|
8
+ Spree::Order.line_item_comparison_hooks << :free_from_order_action?
9
+ end
10
+
7
11
  # Replace the promotions menu from core with ours
8
12
  Spree::Backend::Config.configure do |config|
9
13
  config.menu_items = config.menu_items.map do |item|
@@ -82,6 +86,10 @@ SolidusFriendlyPromotions.configure do |config|
82
86
  "SolidusFriendlyPromotions::Actions::AdjustLineItemQuantityGroups" => [
83
87
  "SolidusFriendlyPromotions::Calculators::FlatRate",
84
88
  "SolidusFriendlyPromotions::Calculators::Percent"
89
+ ],
90
+ "SolidusFriendlyPromotions::Actions::CreateDiscountedItem" => [
91
+ "SolidusFriendlyPromotions::Calculators::FlatRate",
92
+ "SolidusFriendlyPromotions::Calculators::Percent"
85
93
  ]
86
94
  )
87
95
 
@@ -113,6 +121,7 @@ SolidusFriendlyPromotions.configure do |config|
113
121
  config.actions = [
114
122
  "SolidusFriendlyPromotions::Actions::AdjustLineItem",
115
123
  "SolidusFriendlyPromotions::Actions::AdjustLineItemQuantityGroups",
116
- "SolidusFriendlyPromotions::Actions::AdjustShipment"
124
+ "SolidusFriendlyPromotions::Actions::AdjustShipment",
125
+ "SolidusFriendlyPromotions::Actions::CreateDiscountedItem"
117
126
  ]
118
127
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SolidusFriendlyPromotions
4
- VERSION = "1.0.0.pre"
4
+ VERSION = "1.0.0.rc.1"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidus_friendly_promotions
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre
4
+ version: 1.0.0.rc.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Meyerhoff
@@ -188,6 +188,7 @@ files:
188
188
  - app/javascript/solidus_friendly_promotions/jquery/option_value_picker.js
189
189
  - app/jobs/solidus_friendly_promotions/promotion_code_batch_job.rb
190
190
  - app/mailers/solidus_friendly_promotions/promotion_code_batch_mailer.rb
191
+ - app/models/concerns/solidus_friendly_promotions/actions/order_level_action.rb
191
192
  - app/models/concerns/solidus_friendly_promotions/discountable_amount.rb
192
193
  - app/models/concerns/solidus_friendly_promotions/rules/line_item_applicable_order_rule.rb
193
194
  - app/models/concerns/solidus_friendly_promotions/rules/line_item_level_rule.rb
@@ -197,6 +198,7 @@ files:
197
198
  - app/models/solidus_friendly_promotions/actions/adjust_line_item.rb
198
199
  - app/models/solidus_friendly_promotions/actions/adjust_line_item_quantity_groups.rb
199
200
  - app/models/solidus_friendly_promotions/actions/adjust_shipment.rb
201
+ - app/models/solidus_friendly_promotions/actions/create_discounted_item.rb
200
202
  - app/models/solidus_friendly_promotions/calculators/distributed_amount.rb
201
203
  - app/models/solidus_friendly_promotions/calculators/flat_rate.rb
202
204
  - app/models/solidus_friendly_promotions/calculators/flexi_rate.rb
@@ -223,6 +225,7 @@ files:
223
225
  - app/models/solidus_friendly_promotions/promotion_code/batch_builder.rb
224
226
  - app/models/solidus_friendly_promotions/promotion_code_batch.rb
225
227
  - app/models/solidus_friendly_promotions/promotion_handler/coupon.rb
228
+ - app/models/solidus_friendly_promotions/promotion_handler/null.rb
226
229
  - app/models/solidus_friendly_promotions/promotion_handler/page.rb
227
230
  - app/models/solidus_friendly_promotions/promotion_rule.rb
228
231
  - app/models/solidus_friendly_promotions/promotion_rules_store.rb
@@ -256,6 +259,7 @@ files:
256
259
  - app/views/solidus_friendly_promotions/admin/promotion_actions/actions/_adjust_line_item_quantity_groups.html.erb
257
260
  - app/views/solidus_friendly_promotions/admin/promotion_actions/actions/_adjust_shipment.html.erb
258
261
  - app/views/solidus_friendly_promotions/admin/promotion_actions/actions/_calculator_fields.erb
262
+ - app/views/solidus_friendly_promotions/admin/promotion_actions/actions/_create_discounted_item.html.erb
259
263
  - app/views/solidus_friendly_promotions/admin/promotion_actions/calculators/_default_fields.html.erb
260
264
  - app/views/solidus_friendly_promotions/admin/promotion_actions/calculators/distributed_amount/_fields.html.erb
261
265
  - app/views/solidus_friendly_promotions/admin/promotion_actions/calculators/flat_rate/_fields.html.erb
@@ -338,6 +342,7 @@ files:
338
342
  - db/migrate/20231012020928_add_db_comments_to_friendly_products_promotion_rules.rb
339
343
  - db/migrate/20231012120928_add_db_comments_to_friendly_promotion_categories.rb
340
344
  - db/migrate/20231013181921_add_original_promotion_ids.rb
345
+ - db/migrate/20231104135812_add_managed_by_order_action_to_line_items.rb
341
346
  - lib/generators/solidus_friendly_promotions/install/install_generator.rb
342
347
  - lib/generators/solidus_friendly_promotions/install/templates/initializer.rb
343
348
  - lib/solidus_friendly_promotions.rb