solidus_promotions 4.6.2 → 4.7.1

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 (124) hide show
  1. checksums.yaml +4 -4
  2. data/MIGRATING.md +10 -4
  3. data/README.md +7 -0
  4. data/app/javascript/backend/solidus_promotions/controllers/product_option_values_controller.js +3 -26
  5. data/app/javascript/backend/solidus_promotions/web_components/option_value_picker.js +36 -19
  6. data/app/javascript/backend/solidus_promotions/web_components/product_picker.js +6 -1
  7. data/app/jobs/solidus_promotions/promotion_code_batch_job.rb +1 -1
  8. data/app/models/concerns/solidus_promotions/adjustment_discounts.rb +20 -0
  9. data/app/models/concerns/solidus_promotions/benefits/line_item_benefit.rb +5 -0
  10. data/app/models/concerns/solidus_promotions/benefits/order_benefit.rb +5 -0
  11. data/app/models/concerns/solidus_promotions/benefits/shipment_benefit.rb +5 -0
  12. data/app/models/concerns/solidus_promotions/calculators/promotion_calculator.rb +7 -0
  13. data/app/models/concerns/solidus_promotions/conditions/line_item_applicable_order_level_condition.rb +17 -5
  14. data/app/models/concerns/solidus_promotions/conditions/line_item_level_condition.rb +15 -2
  15. data/app/models/concerns/solidus_promotions/conditions/option_value_condition.rb +21 -0
  16. data/app/models/concerns/solidus_promotions/conditions/order_level_condition.rb +15 -2
  17. data/app/models/concerns/solidus_promotions/conditions/product_condition.rb +28 -0
  18. data/app/models/concerns/solidus_promotions/conditions/shipment_level_condition.rb +15 -2
  19. data/app/models/concerns/solidus_promotions/conditions/taxon_condition.rb +77 -0
  20. data/app/models/concerns/solidus_promotions/coupon_code_normalizer.rb +37 -0
  21. data/app/models/concerns/solidus_promotions/discountable_amount.rb +3 -4
  22. data/app/models/concerns/solidus_promotions/discounted_amount.rb +54 -0
  23. data/app/models/solidus_promotions/benefit.rb +258 -37
  24. data/app/models/solidus_promotions/benefits/adjust_line_item.rb +28 -3
  25. data/app/models/solidus_promotions/benefits/adjust_line_item_quantity_groups.rb +1 -0
  26. data/app/models/solidus_promotions/benefits/adjust_shipment.rb +45 -3
  27. data/app/models/solidus_promotions/benefits/advertise_price.rb +28 -0
  28. data/app/models/solidus_promotions/benefits/create_discounted_item.rb +30 -7
  29. data/app/models/solidus_promotions/calculators/distributed_amount.rb +34 -8
  30. data/app/models/solidus_promotions/calculators/flat_rate.rb +52 -6
  31. data/app/models/solidus_promotions/calculators/flexi_rate.rb +69 -6
  32. data/app/models/solidus_promotions/calculators/percent.rb +40 -4
  33. data/app/models/solidus_promotions/calculators/percent_with_cap.rb +44 -3
  34. data/app/models/solidus_promotions/calculators/tiered_flat_rate.rb +81 -19
  35. data/app/models/solidus_promotions/calculators/tiered_percent.rb +96 -25
  36. data/app/models/solidus_promotions/calculators/tiered_percent_on_eligible_item_quantity.rb +101 -16
  37. data/app/models/solidus_promotions/condition.rb +186 -7
  38. data/app/models/solidus_promotions/conditions/first_order.rb +3 -1
  39. data/app/models/solidus_promotions/conditions/first_repeat_purchase_since.rb +3 -2
  40. data/app/models/solidus_promotions/conditions/item_total.rb +2 -1
  41. data/app/models/solidus_promotions/conditions/line_item_option_value.rb +4 -12
  42. data/app/models/solidus_promotions/conditions/line_item_product.rb +4 -22
  43. data/app/models/solidus_promotions/conditions/line_item_taxon.rb +7 -38
  44. data/app/models/solidus_promotions/conditions/minimum_quantity.rb +3 -2
  45. data/app/models/solidus_promotions/conditions/nth_order.rb +3 -2
  46. data/app/models/solidus_promotions/conditions/one_use_per_user.rb +2 -1
  47. data/app/models/solidus_promotions/conditions/option_value.rb +6 -11
  48. data/app/models/solidus_promotions/conditions/order_option_value.rb +19 -0
  49. data/app/models/solidus_promotions/conditions/order_product.rb +62 -0
  50. data/app/models/solidus_promotions/conditions/order_taxon.rb +60 -0
  51. data/app/models/solidus_promotions/conditions/price_option_value.rb +26 -0
  52. data/app/models/solidus_promotions/conditions/price_product.rb +36 -0
  53. data/app/models/solidus_promotions/conditions/price_taxon.rb +28 -0
  54. data/app/models/solidus_promotions/conditions/product.rb +17 -59
  55. data/app/models/solidus_promotions/conditions/shipping_method.rb +3 -5
  56. data/app/models/solidus_promotions/conditions/store.rb +2 -1
  57. data/app/models/solidus_promotions/conditions/taxon.rb +24 -73
  58. data/app/models/solidus_promotions/conditions/user.rb +2 -1
  59. data/app/models/solidus_promotions/conditions/user_logged_in.rb +1 -3
  60. data/app/models/solidus_promotions/conditions/user_role.rb +1 -3
  61. data/app/models/solidus_promotions/distributed_amounts_handler.rb +2 -6
  62. data/app/models/solidus_promotions/eligibility_results.rb +1 -0
  63. data/app/models/solidus_promotions/item_discount.rb +1 -0
  64. data/app/models/solidus_promotions/order_adjuster/discount_order.rb +29 -35
  65. data/app/models/solidus_promotions/order_adjuster/recalculate_promo_totals.rb +45 -0
  66. data/app/models/solidus_promotions/order_adjuster/set_discounts_to_zero.rb +33 -0
  67. data/app/models/solidus_promotions/order_adjuster.rb +4 -14
  68. data/app/models/solidus_promotions/order_promotion.rb +1 -0
  69. data/app/models/solidus_promotions/permission_sets/solidus_promotion_management.rb +10 -0
  70. data/app/models/solidus_promotions/product_advertiser.rb +57 -0
  71. data/app/models/solidus_promotions/promotion.rb +14 -11
  72. data/app/models/solidus_promotions/promotion_code/batch_builder.rb +1 -1
  73. data/app/models/solidus_promotions/promotion_code.rb +4 -4
  74. data/app/models/solidus_promotions/promotion_code_batch.rb +1 -1
  75. data/app/models/solidus_promotions/promotion_handler/coupon.rb +1 -1
  76. data/app/models/solidus_promotions/promotion_handler/page.rb +1 -1
  77. data/app/models/solidus_promotions/promotion_lane.rb +48 -0
  78. data/app/models/solidus_promotions/shipping_rate_discount.rb +3 -0
  79. data/app/patches/models/solidus_promotions/in_memory_order_updater_patch.rb +16 -0
  80. data/app/patches/models/solidus_promotions/line_item_patch.rb +2 -0
  81. data/app/patches/models/solidus_promotions/order_patch.rb +8 -0
  82. data/app/patches/models/solidus_promotions/{order_recalculator_patch.rb → order_updater_patch.rb} +3 -2
  83. data/app/patches/models/solidus_promotions/price_patch.rb +31 -0
  84. data/app/patches/models/solidus_promotions/shipment_patch.rb +2 -0
  85. data/app/patches/models/solidus_promotions/shipping_rate_patch.rb +15 -0
  86. data/config/locales/en.yml +47 -11
  87. data/config/routes.rb +1 -1
  88. data/db/migrate/20230703101637_create_promotions.rb +2 -2
  89. data/db/migrate/20230703113625_create_promotion_benefits.rb +3 -3
  90. data/db/migrate/20230703141116_create_promotion_categories.rb +1 -1
  91. data/db/migrate/20230703143943_create_promotion_conditions.rb +1 -1
  92. data/db/migrate/20230704083830_add_condition_join_tables.rb +8 -8
  93. data/db/migrate/20230704102444_create_promotion_codes.rb +1 -1
  94. data/db/migrate/20230704102656_create_promotion_code_batches.rb +1 -1
  95. data/db/migrate/20230705171556_create_order_promotions.rb +3 -3
  96. data/db/migrate/20230725074235_create_shipping_rate_discounts.rb +2 -2
  97. data/db/migrate/20231104135812_add_managed_by_order_benefit_to_line_items.rb +1 -1
  98. data/db/migrate/20251104170913_update_promotion_code_value_collation.rb +38 -0
  99. data/db/migrate/20251104214304_separate_out_order_only_conditions.rb +41 -0
  100. data/eslint.config.mjs +29 -0
  101. data/lib/components/admin/solidus_promotions/promotion_categories/index/component.rb +6 -6
  102. data/lib/components/admin/solidus_promotions/promotions/index/component.rb +5 -5
  103. data/lib/solidus_promotions/configuration.rb +57 -12
  104. data/lib/solidus_promotions/promotion_map.rb +14 -14
  105. data/lib/solidus_promotions/testing_support/shared_examples/option_value_condition.rb +18 -0
  106. data/lib/solidus_promotions/testing_support/shared_examples/product_condition.rb +37 -0
  107. data/lib/solidus_promotions/testing_support/shared_examples/promotion_calculator.rb +11 -0
  108. data/lib/solidus_promotions/testing_support/shared_examples/taxon_condition.rb +37 -0
  109. data/lib/solidus_promotions/testing_support/shared_examples.rb +6 -0
  110. data/lib/views/backend/solidus_promotions/admin/benefit_fields/_advertise_price.html.erb +7 -0
  111. data/lib/views/backend/solidus_promotions/admin/calculator_fields/_default_fields.html.erb +1 -1
  112. data/lib/views/backend/solidus_promotions/admin/calculator_fields/percent/_fields.html.erb +1 -1
  113. data/lib/views/backend/solidus_promotions/admin/condition_fields/_line_item_option_value.html.erb +6 -5
  114. data/lib/views/backend/solidus_promotions/admin/condition_fields/_option_value.html.erb +6 -12
  115. data/lib/views/backend/solidus_promotions/admin/condition_fields/_price_option_value.html.erb +26 -0
  116. data/lib/views/backend/solidus_promotions/admin/condition_fields/_price_product.html.erb +21 -0
  117. data/lib/views/backend/solidus_promotions/admin/condition_fields/_price_taxon.html.erb +17 -0
  118. data/lib/views/backend/solidus_promotions/admin/condition_fields/_product.html.erb +0 -7
  119. data/lib/views/backend/solidus_promotions/admin/condition_fields/_taxon.html.erb +0 -7
  120. data/lib/views/backend/solidus_promotions/admin/condition_fields/line_item_option_value/_option_value_fields.html.erb +10 -4
  121. data/solidus_promotions.gemspec +1 -1
  122. metadata +35 -6
  123. data/.eslintrc.json +0 -10
  124. data/app/models/solidus_promotions/order_adjuster/persist_discounted_order.rb +0 -79
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples "an option value condition" do
4
+ let(:condition) do
5
+ super()
6
+ rescue NoMethodError
7
+ described_class.new
8
+ end
9
+
10
+ describe "#preferred_eligible_values" do
11
+ subject { condition.preferred_eligible_values }
12
+
13
+ it "assigns a nicely formatted hash" do
14
+ condition.preferred_eligible_values = {"5" => "1,2", "6" => "1"}
15
+ expect(subject).to eq({5 => [1, 2], 6 => [1]})
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples "a product condition" do
4
+ let(:condition) do
5
+ super()
6
+ rescue NoMethodError
7
+ described_class.new
8
+ end
9
+
10
+ it { is_expected.to have_many :products }
11
+
12
+ describe "#product_ids_string" do
13
+ it "returns a string of product ids" do
14
+ condition.products = [create(:product), create(:product)]
15
+ expect(condition.product_ids_string).to eq("#{condition.products[0].id},#{condition.products[1].id}")
16
+ end
17
+ end
18
+
19
+ describe "#preload_relations" do
20
+ subject { condition.preload_relations }
21
+ it { is_expected.to eq([:products]) }
22
+ end
23
+
24
+ describe "#product_ids_string=" do
25
+ it "sets products based on a string of product ids" do
26
+ product_one = create(:product)
27
+ product_two = create(:product)
28
+ condition.product_ids_string = "#{product_one.id},#{product_two.id}"
29
+ expect(condition.products).to eq([product_one, product_two])
30
+ end
31
+ end
32
+
33
+ describe "#preload_relations" do
34
+ subject { condition.preload_relations }
35
+ it { is_expected.to eq([:products]) }
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples_for "a promotion calculator" do
4
+ describe ".description" do
5
+ subject { described_class.description }
6
+
7
+ it "has a description" do
8
+ expect(subject.size).to be > 0
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples "a taxon condition" do
4
+ let(:condition) do
5
+ super()
6
+ rescue NoMethodError
7
+ described_class.new
8
+ end
9
+
10
+ it { is_expected.to have_many :taxons }
11
+
12
+ describe "#taxon_ids_string" do
13
+ it "returns a string of taxon ids" do
14
+ condition.taxons = [create(:taxon), create(:taxon)]
15
+ expect(condition.taxon_ids_string).to eq("#{condition.taxons[0].id},#{condition.taxons[1].id}")
16
+ end
17
+ end
18
+
19
+ describe "#preload_relations" do
20
+ subject { condition.preload_relations }
21
+ it { is_expected.to eq([:taxons]) }
22
+ end
23
+
24
+ describe "#taxon_ids_string=" do
25
+ it "sets taxons based on a string of taxon ids" do
26
+ taxon_one = create(:taxon)
27
+ taxon_two = create(:taxon)
28
+ condition.taxon_ids_string = "#{taxon_one.id},#{taxon_two.id}"
29
+ expect(condition.taxons).to eq([taxon_one, taxon_two])
30
+ end
31
+ end
32
+
33
+ describe "#preload_relations" do
34
+ subject { condition.preload_relations }
35
+ it { is_expected.to eq([:taxons]) }
36
+ end
37
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "solidus_promotions/testing_support/shared_examples/product_condition"
4
+ require "solidus_promotions/testing_support/shared_examples/taxon_condition"
5
+ require "solidus_promotions/testing_support/shared_examples/option_value_condition"
6
+ require "solidus_promotions/testing_support/shared_examples/promotion_calculator"
@@ -0,0 +1,7 @@
1
+
2
+ <%= render(
3
+ "solidus_promotions/admin/benefit_fields/calculator_fields",
4
+ benefit: benefit,
5
+ param_prefix: param_prefix,
6
+ form: form
7
+ ) %>
@@ -2,5 +2,5 @@
2
2
  <%= render "solidus_promotions/admin/shared/preference_fields/#{calculator.preference_type(name)}",
3
3
  name: "#{prefix}[calculator_attributes][preferred_#{name}]",
4
4
  value: calculator.get_preference(name),
5
- label: calculator.class.human_attribute_name("preferred_#{name}", default: I18n.t(name, scope: :spree, default: name.humanize)) %>
5
+ label: calculator.class.human_attribute_name("preferred_#{name}", default: I18n.t(name, scope: :spree, default: name.to_s.humanize)) %>
6
6
  <% end %>
@@ -1,6 +1,6 @@
1
1
  <div class="form-group">
2
2
  <%= fields_for "#{prefix}[calculator_attributes]", calculator do |f| %>
3
3
  <%= f.label :preferred_percent %>
4
- <%= f.number_field :preferred_percent, step: 1, min: 1, max: 100, default: 1, class: "form-control" %>
4
+ <%= f.number_field :preferred_percent, step: 0.01, min: 1, max: 100, default: 1, class: "form-control" %>
5
5
  <% end %>
6
6
  </div>
@@ -5,19 +5,20 @@
5
5
  <div class="field promo-condition-option-values">
6
6
  <div class="param-prefix hidden" data-param-prefix="<%= param_prefix %>"></div>
7
7
  <div class="row">
8
- <div class="col-6"><%= label_tag nil, Spree::Product.model_name.human %></div>
8
+ <div class="col-5"><%= label_tag nil, Spree::Product.model_name.human %></div>
9
9
  <div class="col-6"><%= label_tag nil, plural_resource_name(Spree::OptionValue) %></div>
10
+ <div class="col-1">&nbsp;</div>
10
11
  </div>
11
12
 
12
13
  <div class="form-group">
13
14
  <div data-controller="product-option-values">
14
15
  <template data-product-option-values-target="template">
15
- <%= render "solidus_promotions/admin/condition_fields/line_item_option_value/option_value_fields", product_option_values: [nil, []], form: form %>
16
+ <%= render "solidus_promotions/admin/condition_fields/line_item_option_value/option_value_fields", product_option_values: [nil, []], form: form, index: 0 %>
16
17
  </template>
17
- <% form.object.preferred_eligible_values.each do |product_option_values| %>
18
- <%= render "solidus_promotions/admin/condition_fields/line_item_option_value/option_value_fields", product_option_values: product_option_values, form: form %>
18
+ <% form.object.preferred_eligible_values.each.with_index do |product_option_values, index| %>
19
+ <%= render "solidus_promotions/admin/condition_fields/line_item_option_value/option_value_fields", product_option_values:, form:, index: %>
19
20
  <% end %>
20
- <div class="mb-3" data-product-option-values-target="links">
21
+ <div class="mt-3" data-product-option-values-target="links">
21
22
  <%= link_to t(:add_product, scope: [:solidus_promotions, :line_item_option_value_condition]), "#", class: "btn btn-outline-primary", data: { action: "click->product-option-values#add_row" } %>
22
23
  </div>
23
24
  </div>
@@ -7,30 +7,24 @@
7
7
  <div class="field promo-condition-option-values">
8
8
  <div class="param-prefix hidden" data-param-prefix="<%= param_prefix %>"></div>
9
9
  <div class="row">
10
- <div class="col-6"><%= label_tag nil, Spree::Product.model_name.human %></div>
10
+ <div class="col-5"><%= label_tag nil, Spree::Product.model_name.human %></div>
11
11
  <div class="col-6"><%= label_tag nil, plural_resource_name(Spree::OptionValue) %></div>
12
+ <div class="col-1">&nbsp;</div>
12
13
  </div>
13
14
 
14
15
  <div class="form-group">
15
16
  <div data-controller="product-option-values">
16
17
  <template data-product-option-values-target="template">
17
- <%= render "solidus_promotions/admin/condition_fields/line_item_option_value/option_value_fields", product_option_values: [nil, []], form: form %>
18
+ <%= render "solidus_promotions/admin/condition_fields/line_item_option_value/option_value_fields", product_option_values: [nil, []], form:, index: 0 %>
18
19
  </template>
19
- <% form.object.preferred_eligible_values.each do |product_option_values| %>
20
- <%= render "solidus_promotions/admin/condition_fields/line_item_option_value/option_value_fields", product_option_values: product_option_values, form: form %>
20
+ <% form.object.preferred_eligible_values.each.with_index do |product_option_values, index| %>
21
+ <%= render "solidus_promotions/admin/condition_fields/line_item_option_value/option_value_fields", product_option_values:, form:, index: %>
21
22
  <% end %>
22
- <div class="mb-3" data-product-option-values-target="links">
23
+ <div class="mt-3" data-product-option-values-target="links">
23
24
  <%= link_to t(:add_product, scope: [:solidus_promotions, :option_value_condition]), "#", class: "btn btn-outline-primary", data: { action: "click->product-option-values#add_row" } %>
24
25
  </div>
25
26
  </div>
26
27
  </div>
27
-
28
- <div class="form-group">
29
- <%= form.label :preferred_line_item_applicable do %>
30
- <%= form.check_box :preferred_line_item_applicable %>
31
- <%= condition.class.human_attribute_name(:preferred_line_item_applicable) %>
32
- <% end %>
33
- </div>
34
28
  </div>
35
29
  <% else %>
36
30
  <p>
@@ -0,0 +1,26 @@
1
+
2
+ <p>
3
+ <%= condition.class.human_attribute_name(:description) %>
4
+ </p>
5
+ <div class="field promo-condition-option-values">
6
+ <div class="param-prefix hidden" data-param-prefix="<%= param_prefix %>"></div>
7
+ <div class="row">
8
+ <div class="col-5"><%= label_tag nil, Spree::Product.model_name.human %></div>
9
+ <div class="col-6"><%= label_tag nil, plural_resource_name(Spree::OptionValue) %></div>
10
+ <div class="col-1">&nbsp;</div>
11
+ </div>
12
+
13
+ <div class="form-group">
14
+ <div data-controller="product-option-values">
15
+ <template data-product-option-values-target="template">
16
+ <%= render "solidus_promotions/admin/condition_fields/line_item_option_value/option_value_fields", product_option_values: [nil, []], form: form, index: 0 %>
17
+ </template>
18
+ <% form.object.preferred_eligible_values.each.with_index do |product_option_values, index| %>
19
+ <%= render "solidus_promotions/admin/condition_fields/line_item_option_value/option_value_fields", product_option_values:, form:, index: %>
20
+ <% end %>
21
+ <div class="mt-3" data-product-option-values-target="links">
22
+ <%= link_to t(:add_product, scope: [:solidus_promotions, :line_item_option_value_condition]), "#", class: "btn btn-outline-primary", data: { action: "click->product-option-values#add_row" } %>
23
+ </div>
24
+ </div>
25
+ </div>
26
+ </div>
@@ -0,0 +1,21 @@
1
+ <p>
2
+ <%= condition.class.human_attribute_name(:description) %>
3
+ </p>
4
+ <div class="row">
5
+ <div class="col-12">
6
+ <div class="field products_condition_products">
7
+ <%= label_tag "#{param_prefix}_product_ids_string", t('solidus_promotions.product_condition.choose_products') %>
8
+ <%= hidden_field_tag "#{param_prefix}[product_ids_string]", condition.product_ids.join(","), class: "fullwidth", is: "product-picker" %>
9
+ </div>
10
+ </div>
11
+ <div class="col-12">
12
+ <div class="form-group">
13
+ <%= label_tag("#{param_prefix}_preferred_match_policy", condition.class.human_attribute_name(:preferred_match_policy)) %>
14
+ <%= select_tag(
15
+ "#{param_prefix}[preferred_match_policy]",
16
+ options_for_select(I18n.t("solidus_promotions.conditions.price_product.match_policies").to_a.map(&:reverse), condition.preferred_match_policy),
17
+ class: "custom-select fullwidth"
18
+ ) %>
19
+ </div>
20
+ </div>
21
+ </div>
@@ -0,0 +1,17 @@
1
+ <p>
2
+ <%= condition.class.human_attribute_name(:description) %>
3
+ </p>
4
+ <div class="field taxons_condition_taxons">
5
+ <%= label_tag "#{param_prefix}_taxon_ids_string", t("solidus_promotions.taxon_condition.choose_taxons") %>
6
+ <%= hidden_field_tag "#{param_prefix}[taxon_ids_string]", condition.taxon_ids.join(","), is: "taxon-picker", class: "fullwidth", id: "product_taxon_ids" %>
7
+ </div>
8
+ <div class="form-group">
9
+ <div class="form-group">
10
+ <%= label_tag("#{param_prefix}_preferred_match_policy", condition.class.human_attribute_name(:preferred_match_policy)) %>
11
+ <%= select_tag(
12
+ "#{param_prefix}[preferred_match_policy]",
13
+ options_for_select(I18n.t("solidus_promotions.conditions.price_taxon.match_policies").to_a.map(&:reverse), condition.preferred_match_policy),
14
+ class: "custom-select fullwidth",
15
+ ) %>
16
+ </div>
17
+ </div>
@@ -17,11 +17,4 @@
17
17
  <% select = form.select :preferred_match_policy, match_policy_options %>
18
18
  <%= form.label :preferred_match_policy, t('solidus_promotions.product_condition.label', select: select).html_safe %>
19
19
  </div>
20
-
21
- <div class="form-group">
22
- <%= form.label :preferred_line_item_applicable do %>
23
- <%= form.check_box :preferred_line_item_applicable %>
24
- <%= condition.class.human_attribute_name(:preferred_line_item_applicable) %>
25
- <% end %>
26
- </div>
27
20
  <% end %>
@@ -17,11 +17,4 @@
17
17
  <% select = form.select :preferred_match_policy, match_policy_options %>
18
18
  <%= form.label :preferred_match_policy, t('solidus_promotions.taxon_condition.label', select: select).html_safe %>
19
19
  </div>
20
-
21
- <div class="form-group">
22
- <%= form.label :preferred_line_item_applicable do %>
23
- <%= form.check_box :preferred_line_item_applicable %>
24
- <%= condition.class.human_attribute_name(:preferred_line_item_applicable) %>
25
- <% end %>
26
- </div>
27
20
  <% end %>
@@ -1,21 +1,27 @@
1
- <div class="fullwidth promo-condition-option-value d-flex align-content-stretch mb-3">
2
- <div class="mr-2" style="flex-grow: 1;">
1
+ <div class="promo-condition-option-value row">
2
+ <div class="col-5">
3
3
  <input
4
4
  is="product-picker"
5
+ id="ov-product-picker-<%= index %>"
5
6
  class="w-100"
6
7
  data-action="select2Change->product-option-values#propagate_product_id_to_value_input"
8
+ data-multiple="false"
7
9
  type="hidden"
8
10
  value="<%= product_option_values[0] %>"
9
11
  >
10
12
  </div>
11
- <div class="mr-2 ml-2" style="flex-grow: 1;">
13
+ <div class="col-6">
12
14
  <input
13
15
  is="option-value-picker"
16
+ id="option-value-picker-<%= index %>"
14
17
  class="fullwidth"
15
18
  name="<%= form.object_name %>[preferred_eligible_values][<%= product_option_values[0] %>]"
16
19
  type="hidden"
20
+ data-product-id="<%= product_option_values[0] %>"
17
21
  value="<%= product_option_values[1].join(",") %>"
18
22
  >
19
23
  </div>
20
- <a class="fa fa-trash remove p-2" data-action="click->product-option-values#remove_row"></a>
24
+ <div class="col-1">
25
+ <a class="fa fa-trash remove p-2 float-right" data-action="click->product-option-values#remove_row"></a>
26
+ </div>
21
27
  </div>
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
 
18
18
  spec.metadata["homepage_uri"] = spec.homepage
19
19
 
20
- spec.required_ruby_version = ">= 3.1.0"
20
+ spec.required_ruby_version = ">= 3.2.0"
21
21
 
22
22
  # Specify which files should be added to the gem when it is released.
23
23
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solidus_promotions
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.6.2
4
+ version: 4.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martin Meyerhoff
@@ -126,7 +126,6 @@ executables: []
126
126
  extensions: []
127
127
  extra_rdoc_files: []
128
128
  files:
129
- - ".eslintrc.json"
130
129
  - ".github/stale.yml"
131
130
  - MIGRATING.md
132
131
  - README.md
@@ -150,19 +149,26 @@ files:
150
149
  - app/javascript/backend/solidus_promotions/web_components/variant_picker.js
151
150
  - app/jobs/solidus_promotions/promotion_code_batch_job.rb
152
151
  - app/mailers/solidus_promotions/promotion_code_batch_mailer.rb
152
+ - app/models/concerns/solidus_promotions/adjustment_discounts.rb
153
153
  - app/models/concerns/solidus_promotions/benefits/line_item_benefit.rb
154
154
  - app/models/concerns/solidus_promotions/benefits/order_benefit.rb
155
155
  - app/models/concerns/solidus_promotions/benefits/shipment_benefit.rb
156
156
  - app/models/concerns/solidus_promotions/calculators/promotion_calculator.rb
157
157
  - app/models/concerns/solidus_promotions/conditions/line_item_applicable_order_level_condition.rb
158
158
  - app/models/concerns/solidus_promotions/conditions/line_item_level_condition.rb
159
+ - app/models/concerns/solidus_promotions/conditions/option_value_condition.rb
159
160
  - app/models/concerns/solidus_promotions/conditions/order_level_condition.rb
161
+ - app/models/concerns/solidus_promotions/conditions/product_condition.rb
160
162
  - app/models/concerns/solidus_promotions/conditions/shipment_level_condition.rb
163
+ - app/models/concerns/solidus_promotions/conditions/taxon_condition.rb
164
+ - app/models/concerns/solidus_promotions/coupon_code_normalizer.rb
161
165
  - app/models/concerns/solidus_promotions/discountable_amount.rb
166
+ - app/models/concerns/solidus_promotions/discounted_amount.rb
162
167
  - app/models/solidus_promotions/benefit.rb
163
168
  - app/models/solidus_promotions/benefits/adjust_line_item.rb
164
169
  - app/models/solidus_promotions/benefits/adjust_line_item_quantity_groups.rb
165
170
  - app/models/solidus_promotions/benefits/adjust_shipment.rb
171
+ - app/models/solidus_promotions/benefits/advertise_price.rb
166
172
  - app/models/solidus_promotions/benefits/create_discounted_item.rb
167
173
  - app/models/solidus_promotions/calculators/distributed_amount.rb
168
174
  - app/models/solidus_promotions/calculators/flat_rate.rb
@@ -188,6 +194,12 @@ files:
188
194
  - app/models/solidus_promotions/conditions/nth_order.rb
189
195
  - app/models/solidus_promotions/conditions/one_use_per_user.rb
190
196
  - app/models/solidus_promotions/conditions/option_value.rb
197
+ - app/models/solidus_promotions/conditions/order_option_value.rb
198
+ - app/models/solidus_promotions/conditions/order_product.rb
199
+ - app/models/solidus_promotions/conditions/order_taxon.rb
200
+ - app/models/solidus_promotions/conditions/price_option_value.rb
201
+ - app/models/solidus_promotions/conditions/price_product.rb
202
+ - app/models/solidus_promotions/conditions/price_taxon.rb
191
203
  - app/models/solidus_promotions/conditions/product.rb
192
204
  - app/models/solidus_promotions/conditions/shipping_method.rb
193
205
  - app/models/solidus_promotions/conditions/store.rb
@@ -205,9 +217,11 @@ files:
205
217
  - app/models/solidus_promotions/order_adjuster/choose_discounts.rb
206
218
  - app/models/solidus_promotions/order_adjuster/discount_order.rb
207
219
  - app/models/solidus_promotions/order_adjuster/load_promotions.rb
208
- - app/models/solidus_promotions/order_adjuster/persist_discounted_order.rb
220
+ - app/models/solidus_promotions/order_adjuster/recalculate_promo_totals.rb
221
+ - app/models/solidus_promotions/order_adjuster/set_discounts_to_zero.rb
209
222
  - app/models/solidus_promotions/order_promotion.rb
210
223
  - app/models/solidus_promotions/permission_sets/solidus_promotion_management.rb
224
+ - app/models/solidus_promotions/product_advertiser.rb
211
225
  - app/models/solidus_promotions/promotion.rb
212
226
  - app/models/solidus_promotions/promotion_advertiser.rb
213
227
  - app/models/solidus_promotions/promotion_category.rb
@@ -217,11 +231,14 @@ files:
217
231
  - app/models/solidus_promotions/promotion_finder.rb
218
232
  - app/models/solidus_promotions/promotion_handler/coupon.rb
219
233
  - app/models/solidus_promotions/promotion_handler/page.rb
234
+ - app/models/solidus_promotions/promotion_lane.rb
220
235
  - app/models/solidus_promotions/shipping_rate_discount.rb
221
236
  - app/patches/models/solidus_promotions/adjustment_patch.rb
237
+ - app/patches/models/solidus_promotions/in_memory_order_updater_patch.rb
222
238
  - app/patches/models/solidus_promotions/line_item_patch.rb
223
239
  - app/patches/models/solidus_promotions/order_patch.rb
224
- - app/patches/models/solidus_promotions/order_recalculator_patch.rb
240
+ - app/patches/models/solidus_promotions/order_updater_patch.rb
241
+ - app/patches/models/solidus_promotions/price_patch.rb
225
242
  - app/patches/models/solidus_promotions/shipment_patch.rb
226
243
  - app/patches/models/solidus_promotions/shipping_rate_patch.rb
227
244
  - app/subscribers/solidus_promotions/order_promotion_subscriber.rb
@@ -251,6 +268,9 @@ files:
251
268
  - db/migrate/20231012020928_add_db_comments_to_condition_products.rb
252
269
  - db/migrate/20231012120928_add_db_comments_to_promotion_categories.rb
253
270
  - db/migrate/20231104135812_add_managed_by_order_benefit_to_line_items.rb
271
+ - db/migrate/20251104170913_update_promotion_code_value_collation.rb
272
+ - db/migrate/20251104214304_separate_out_order_only_conditions.rb
273
+ - eslint.config.mjs
254
274
  - lib/components/admin/solidus_admin/orders/show/adjustments/index/source/solidus_promotions_benefit/component.rb
255
275
  - lib/components/admin/solidus_promotions/orders/index/component.rb
256
276
  - lib/components/admin/solidus_promotions/orders/index/component.yml
@@ -288,12 +308,18 @@ files:
288
308
  - lib/solidus_promotions/testing_support/factories/solidus_promotion_factory.rb
289
309
  - lib/solidus_promotions/testing_support/factories/solidus_shipping_rate_discount_factory.rb
290
310
  - lib/solidus_promotions/testing_support/factory_bot.rb
311
+ - lib/solidus_promotions/testing_support/shared_examples.rb
312
+ - lib/solidus_promotions/testing_support/shared_examples/option_value_condition.rb
313
+ - lib/solidus_promotions/testing_support/shared_examples/product_condition.rb
314
+ - lib/solidus_promotions/testing_support/shared_examples/promotion_calculator.rb
315
+ - lib/solidus_promotions/testing_support/shared_examples/taxon_condition.rb
291
316
  - lib/tasks/solidus_promotions/migrate_adjustments.rake
292
317
  - lib/tasks/solidus_promotions/migrate_existing_promotions.rake
293
318
  - lib/tasks/solidus_promotions/migrate_order_promotions.rake
294
319
  - lib/views/backend/solidus_promotions/admin/benefit_fields/_adjust_line_item.html.erb
295
320
  - lib/views/backend/solidus_promotions/admin/benefit_fields/_adjust_line_item_quantity_groups.html.erb
296
321
  - lib/views/backend/solidus_promotions/admin/benefit_fields/_adjust_shipment.html.erb
322
+ - lib/views/backend/solidus_promotions/admin/benefit_fields/_advertise_price.html.erb
297
323
  - lib/views/backend/solidus_promotions/admin/benefit_fields/_calculator_fields.erb
298
324
  - lib/views/backend/solidus_promotions/admin/benefit_fields/_create_discounted_item.html.erb
299
325
  - lib/views/backend/solidus_promotions/admin/benefits/_benefit.html.erb
@@ -324,6 +350,9 @@ files:
324
350
  - lib/views/backend/solidus_promotions/admin/condition_fields/_nth_order.html.erb
325
351
  - lib/views/backend/solidus_promotions/admin/condition_fields/_one_use_per_user.html.erb
326
352
  - lib/views/backend/solidus_promotions/admin/condition_fields/_option_value.html.erb
353
+ - lib/views/backend/solidus_promotions/admin/condition_fields/_price_option_value.html.erb
354
+ - lib/views/backend/solidus_promotions/admin/condition_fields/_price_product.html.erb
355
+ - lib/views/backend/solidus_promotions/admin/condition_fields/_price_taxon.html.erb
327
356
  - lib/views/backend/solidus_promotions/admin/condition_fields/_product.html.erb
328
357
  - lib/views/backend/solidus_promotions/admin/condition_fields/_shipping_method.html.erb
329
358
  - lib/views/backend/solidus_promotions/admin/condition_fields/_store.html.erb
@@ -377,14 +406,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
377
406
  requirements:
378
407
  - - ">="
379
408
  - !ruby/object:Gem::Version
380
- version: 3.1.0
409
+ version: 3.2.0
381
410
  required_rubygems_version: !ruby/object:Gem::Requirement
382
411
  requirements:
383
412
  - - ">="
384
413
  - !ruby/object:Gem::Version
385
414
  version: '0'
386
415
  requirements: []
387
- rubygems_version: 3.7.2
416
+ rubygems_version: 4.0.10
388
417
  specification_version: 4
389
418
  summary: New promotion system for Solidus
390
419
  test_files: []
data/.eslintrc.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "eslint:recommended",
3
- "parserOptions": {
4
- "ecmaVersion": 2023,
5
- "sourceType": "module"
6
- },
7
- "globals": {
8
- "Turbo": "readonly"
9
- }
10
- }
@@ -1,79 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SolidusPromotions
4
- class OrderAdjuster
5
- class PersistDiscountedOrder
6
- def initialize(order)
7
- @order = order
8
- end
9
-
10
- def call
11
- order.line_items.each do |line_item|
12
- update_adjustments(line_item, line_item.current_discounts)
13
- end
14
-
15
- order.shipments.each do |shipment|
16
- update_adjustments(shipment, shipment.current_discounts)
17
- end
18
-
19
- order.shipments.flat_map(&:shipping_rates).each do |shipping_rate|
20
- shipping_rate.discounts = shipping_rate.current_discounts.map do |discount|
21
- SolidusPromotions::ShippingRateDiscount.create!(
22
- shipping_rate: shipping_rate,
23
- amount: discount.amount,
24
- label: discount.label,
25
- benefit: discount.source
26
- )
27
- end
28
- end
29
- order.reset_current_discounts
30
- order
31
- end
32
-
33
- private
34
-
35
- attr_reader :order
36
-
37
- # Walk through the discounts for an item and update adjustments for it. Once
38
- # all of the discounts have been added as adjustments, remove any old promotion
39
- # adjustments that weren't touched.
40
- #
41
- # @private
42
- # @param [#adjustments] item a {Spree::LineItem} or {Spree::Shipment}
43
- # @param [Array<SolidusPromotions::ItemDiscount>] item_discounts a list of calculated discounts for an item
44
- # @return [void]
45
- def update_adjustments(item, item_discounts)
46
- promotion_adjustments = item.adjustments.select(&:promotion?)
47
-
48
- active_adjustments = item_discounts.map do |item_discount|
49
- update_adjustment(item, item_discount)
50
- end
51
- item.update(promo_total: active_adjustments.sum(&:amount))
52
- # Remove any promotion adjustments tied to promotion benefits which no longer match.
53
- unmatched_adjustments = promotion_adjustments - active_adjustments
54
-
55
- item.adjustments.destroy(unmatched_adjustments)
56
- end
57
-
58
- # Update or create a new promotion adjustment on an item.
59
- #
60
- # @private
61
- # @param [#adjustments] item a {Spree::LineItem} or {Spree::Shipment}
62
- # @param [SolidusPromotions::ItemDiscount] discount_item calculated discounts for an item
63
- # @return [Spree::Adjustment] the created or updated promotion adjustment
64
- def update_adjustment(item, discount_item)
65
- adjustment = item.adjustments.detect do |item_adjustment|
66
- item_adjustment.source == discount_item.source
67
- end
68
-
69
- adjustment ||= item.adjustments.new(
70
- source: discount_item.source,
71
- order_id: item.is_a?(Spree::Order) ? item.id : item.order_id,
72
- label: discount_item.label
73
- )
74
- adjustment.update!(amount: discount_item.amount)
75
- adjustment
76
- end
77
- end
78
- end
79
- end