Skip to content

Commit

Permalink
Add code to reduce amount of applicable promotions
Browse files Browse the repository at this point in the history
If we reduce the amount of promotions that can be activated, the
performance when refreshing the cart improves dramatically.

Eventually, this might not be necessary since Solidus#master branch is
updated with solidusio#4304 and
solidusio#4296.
Until those land in master and we are able to update to Solidus 3.2, we need to
maintain this fork.
  • Loading branch information
5minpause committed Mar 22, 2022
1 parent 75da84d commit 3e0c58e
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 4 deletions.
43 changes: 39 additions & 4 deletions core/app/models/spree/promotion_handler/cart.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,49 @@ def connected_order_promotions
where(spree_orders_promotions: { order_id: order.id }).readonly(false).to_a
end

def sale_promotions
Spree::Promotion.where(apply_automatically: true).active.includes(:promotion_rules)
end

def promotion_code(promotion)
order_promotion = Spree::OrderPromotion.where(order: order, promotion: promotion).first
order_promotion.present? ? order_promotion.promotion_code : nil
end

def sale_promotions
scope = Spree::Promotion.where(apply_automatically: true).active.includes(:promotion_rules).distinct

Rails.application.config.spree.promotions.rules.each do |rule_class|
next unless rule_class.respond_to? :excluded_promotions_for_order

scope = scope.where.not(id: rule_class.excluded_promotions_for_order(order).select(:id))
end

# Filter promotions that are not eligible for current_user.
scope = scope.select do |promotion|
promotion.rules.where("spree_promotion_rules.type = 'Spree::Promotion::Rules::User'").none? ||
promotion.rules.where("spree_promotion_rules.type = 'Spree::Promotion::Rules::User'")
.flat_map(&:user_ids).include?(order.user_id)
end

# Filter promotions that are not eligible for the selected products in the order.
scope = scope.select do |promotion|
promotion.rules.where("spree_promotion_rules.type = 'Spree::Promotion::Rules::Product'").none? ||
order.product_ids.flat_map { |p_id| promotion.rules.where("spree_promotion_rules.type = 'Spree::Promotion::Rules::Product'").flat_map(&:product_ids).include?(p_id) }.include?(true)
end

# Filter promotions that are not eligible for the order's store.
scope = scope.select do |promotion|
promotion.rules.where("spree_promotion_rules.type = 'Spree::Promotion::Rules::Store'").none? ||
promotion.rules.where("spree_promotion_rules.type = 'Spree::Promotion::Rules::Store'").flat_map(&:store_ids)
.include?(order.store_id)
end

scope = scope.select do |promotion|
promotion.rules.where("spree_promotion_rules.type = 'Spree::Promotion::Rules::Taxon'").none? ||
order.products.flat_map(&:taxon_ids).uniq.map { |taxon_id|
promotion.rules.where("spree_promotion_rules.type = 'Spree::Promotion::Rules::Taxon'").flat_map(&:taxon_ids).include?(taxon_id)
}.include?(true)
end

scope
end
end
end
end
62 changes: 62 additions & 0 deletions core/spec/models/spree/promotion_handler/cart_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,68 @@ module PromotionHandler
include_context "creates an order promotion"
end

context "promotion does not activate for other items" do
let(:other_line_item) { create(:line_item) }
let!(:rule) { Promotion::Rules::Product.create(products: [line_item.product], promotion: promotion) }
let!(:other_rule) { Promotion::Rules::Product.create(products: [other_line_item.product], promotion: promotion) }

include_context "creates the adjustment"
include_context "creates an order promotion"
end

context "promotion activates for store" do
let!(:rule) { Promotion::Rules::Store.create(stores: [order.store], promotion: promotion) }

include_context "creates the adjustment"
include_context "creates an order promotion"
end

context "promotion does not activate for other store" do
let(:other_store) { create(:store) }
let(:other_promotion) { create(:promotion, apply_automatically: true) }
let!(:other_rule) { Promotion::Rules::Store.create(stores: [other_store], promotion: other_promotion) }
let!(:rule) { Promotion::Rules::Store.create(stores: [order.store], promotion: promotion) }

include_context "creates the adjustment"
include_context "creates an order promotion"

it "doesn't connect the promotion to the order" do
expect {
subject.activate
}.to change { order.promotions.count }.by(1)
end

it "doesn't create an adjustment" do
expect {
subject.activate
}.to change { adjustable.adjustments.count }.by(1)
end
end

context "promotion activates for user" do
let!(:rule) { Promotion::Rules::User.create(users: [order.user], promotion: promotion) }

include_context "creates the adjustment"
include_context "creates an order promotion"
end

context "promotion does not activate for other user" do
let(:user) { create(:user) }
let!(:rule) { Promotion::Rules::User.create(users: [user], promotion: promotion) }

it "doesn't connect the promotion to the order" do
expect {
subject.activate
}.to change { order.promotions.count }.by(0)
end

it "doesn't create an adjustment" do
expect {
subject.activate
}.to change { adjustable.adjustments.count }.by(0)
end
end

context "promotion has item total rule" do
let(:shirt) { create(:product) }
let!(:rule) { Promotion::Rules::ItemTotal.create(preferred_operator: 'gt', preferred_amount: 50, promotion: promotion) }
Expand Down

0 comments on commit 3e0c58e

Please sign in to comment.