From 2ebb69a60a64a29fff09506d6e39d7277a90a801 Mon Sep 17 00:00:00 2001 From: Martin Meyerhoff Date: Mon, 9 Oct 2023 17:31:22 +0200 Subject: [PATCH] Add "only" match policy to product rule This addition to the order product rule makes the rule match if the order contains exclusively the products specified in the rule. --- .../rules/product.rb | 7 +++- config/locales/en.yml | 9 +++-- .../rules/product_spec.rb | 37 +++++++++++++++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/app/models/solidus_friendly_promotions/rules/product.rb b/app/models/solidus_friendly_promotions/rules/product.rb index c7a5d837..a00dbbd9 100644 --- a/app/models/solidus_friendly_promotions/rules/product.rb +++ b/app/models/solidus_friendly_promotions/rules/product.rb @@ -17,7 +17,7 @@ def preload_relations [:products] end - MATCH_POLICIES = %w[any all none].freeze + MATCH_POLICIES = %w[any all none only].freeze validates :preferred_match_policy, inclusion: {in: MATCH_POLICIES} @@ -50,6 +50,11 @@ def eligible?(order, _options = {}) eligibility_errors.add(:base, eligibility_error_message(:has_excluded_product), error_code: :has_excluded_product) end + when "only" + unless order_products(order).all? { |product| eligible_products.include?(product) } + eligibility_errors.add(:base, eligibility_error_message(:has_excluded_product), + error_code: :has_excluded_product) + end else raise "unexpected match policy: #{preferred_match_policy.inspect}" end diff --git a/config/locales/en.yml b/config/locales/en.yml index ff47d1b8..ee39ca96 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -45,10 +45,11 @@ en: promotions: This is used to determine the promotional discount to be applied to an order, an item, or shipping charges. product_rule: choose_products: Choose products - label: Order must contain %{select} of these products - match_all: all - match_any: at least one - match_none: none + label: Order must contain %{select} these products + match_all: all of + match_any: at least one of + match_none: none of + match_only: only product_source: group: From product group manual: Manually choose diff --git a/spec/models/solidus_friendly_promotions/rules/product_spec.rb b/spec/models/solidus_friendly_promotions/rules/product_spec.rb index 3c0b03ab..41c170bf 100644 --- a/spec/models/solidus_friendly_promotions/rules/product_spec.rb +++ b/spec/models/solidus_friendly_promotions/rules/product_spec.rb @@ -113,6 +113,43 @@ end end + context "with 'only' match policy" do + let(:rule_options) { super().merge(preferred_match_policy: "only") } + + it "is not eligible if none of the order's products are in eligible products" do + allow(rule).to receive_messages(order_products: [product_one]) + allow(rule).to receive_messages(eligible_products: [product_two, product_three]) + expect(rule).not_to be_eligible(order) + end + + it "is eligible if all of the order's products are in eligible products" do + allow(rule).to receive_messages(order_products: [product_one]) + allow(rule).to receive_messages(eligible_products: [product_one]) + expect(rule).to be_eligible(order) + end + + context "when any of the order's products are in eligible products" do + before do + allow(rule).to receive_messages(order_products: [product_one, product_two]) + allow(rule).to receive_messages(eligible_products: [product_two, product_three]) + end + + it { expect(rule).not_to be_eligible(order) } + + it "sets an error message" do + rule.eligible?(order) + expect(rule.eligibility_errors.full_messages.first) + .to eq "Your cart contains a product that prevents this coupon code from being applied." + end + + it "sets an error code" do + rule.eligible?(order) + expect(rule.eligibility_errors.details[:base].first[:error_code]) + .to eq :has_excluded_product + end + end + end + context "with an invalid match policy" do let(:rule) do described_class.create!(