diff --git a/legacy_promotions/app/models/spree/promotion/rules/first_order.rb b/legacy_promotions/app/models/spree/promotion/rules/first_order.rb index 1c1fb64711d..a82cca8695e 100644 --- a/legacy_promotions/app/models/spree/promotion/rules/first_order.rb +++ b/legacy_promotions/app/models/spree/promotion/rules/first_order.rb @@ -24,11 +24,11 @@ def eligible?(order, options = {}) private def completed_orders - user ? user.orders.complete : orders_by_email + user ? user.orders.complete.not_canceled : orders_by_email end def orders_by_email - Spree::Order.where(email:).complete + Spree::Order.where(email:).complete.not_canceled end end end diff --git a/legacy_promotions/spec/models/spree/promotion/rules/first_order_spec.rb b/legacy_promotions/spec/models/spree/promotion/rules/first_order_spec.rb index aa64aec627f..ce2361526d7 100644 --- a/legacy_promotions/spec/models/spree/promotion/rules/first_order_spec.rb +++ b/legacy_promotions/spec/models/spree/promotion/rules/first_order_spec.rb @@ -1,85 +1,105 @@ # frozen_string_literal: true -require 'rails_helper' +require "rails_helper" RSpec.describe Spree::Promotion::Rules::FirstOrder, type: :model do - let(:rule) { Spree::Promotion::Rules::FirstOrder.new } - let(:order) { mock_model(Spree::Order, user: nil, email: nil) } - let(:user) { mock_model(Spree::LegacyUser) } + let(:condition) { described_class.new } + let(:order) { create(:order, user:, email:) } + let(:user) { nil } + let(:email) { nil } + + describe ".to_partial_path" do + subject { condition.to_partial_path } + + it { is_expected.to eq("spree/admin/promotions/rules/first_order") } + end context "without a user or email" do - it { expect(rule).to be_eligible(order) } + it { expect(condition).to be_eligible(order) } + it "does not set an error message" do - rule.eligible?(order) - expect(rule.eligibility_errors.full_messages.first). - to be_nil + condition.eligible?(order) + expect(condition.eligibility_errors.full_messages.first) + .to be_nil end end context "first order" do context "for a signed user" do - context "with no completed orders" do - before(:each) do - allow(user).to receive_message_chain(:orders, complete: []) - end + let(:user) { create(:user) } + let(:email) { user.email } - specify do - allow(order).to receive_messages(user:) - expect(rule).to be_eligible(order) - end - - it "should be eligible when user passed in payload data" do - expect(rule).to be_eligible(order, user:) + context "with no completed, un-canceled orders" do + it "is eligible when user passed in payload data" do + expect(condition).to be_eligible(order, user: user) end end context "with completed orders" do - before(:each) do - allow(order).to receive_messages(user:) - end + let(:order) { create(:completed_order_with_totals, user:, email:) } - it "should be eligible when checked against first completed order" do - allow(user).to receive_message_chain(:orders, complete: [order]) - expect(rule).to be_eligible(order) + it "is eligible when checked against first completed order" do + expect(condition).to be_eligible(order) end context "with another order" do - before { allow(user).to receive_message_chain(:orders, complete: [mock_model(Spree::Order)]) } - it { expect(rule).not_to be_eligible(order) } + let!(:previous_order) { create(:completed_order_with_totals, user:) } + + it { expect(condition).not_to be_eligible(order) } + + context "if previous order is canceled" do + before do + previous_order.cancel! + end + + it { expect(condition).to be_eligible(order) } + end + it "sets an error message" do - rule.eligible?(order) - expect(rule.eligibility_errors.full_messages.first). - to eq "This coupon code can only be applied to your first order." + condition.eligible?(order) + expect(condition.eligibility_errors.full_messages.first) + .to eq "This coupon code can only be applied to your first order." end + it "sets an error code" do - rule.eligible?(order) - expect(rule.eligibility_errors.details[:base].first[:error_code]). - to eq :not_first_order + condition.eligible?(order) + expect(condition.eligibility_errors.details[:base].first[:error_code]) + .to eq :not_first_order end end end end context "for a guest user" do - let(:email) { 'user@solidus.io' } - before { allow(order).to receive_messages email: 'user@solidus.io' } + let(:email) { "user@solidus.io" } context "with no other orders" do - it { expect(rule).to be_eligible(order) } + it { expect(condition).to be_eligible(order) } end context "with another order" do - before { allow(rule).to receive_messages(orders_by_email: [mock_model(Spree::Order)]) } - it { expect(rule).not_to be_eligible(order) } + let!(:previous_order) { create(:completed_order_with_totals, user: nil, email:) } + + it { expect(condition).not_to be_eligible(order) } + + context "if previous order is canceled" do + before do + previous_order.cancel! + end + + it { expect(condition).to be_eligible(order) } + end + it "sets an error message" do - rule.eligible?(order) - expect(rule.eligibility_errors.full_messages.first). - to eq "This coupon code can only be applied to your first order." + condition.eligible?(order) + expect(condition.eligibility_errors.full_messages.first) + .to eq "This coupon code can only be applied to your first order." end + it "sets an error code" do - rule.eligible?(order) - expect(rule.eligibility_errors.details[:base].first[:error_code]). - to eq :not_first_order + condition.eligible?(order) + expect(condition.eligibility_errors.details[:base].first[:error_code]) + .to eq :not_first_order end end end diff --git a/promotions/app/models/solidus_promotions/conditions/first_order.rb b/promotions/app/models/solidus_promotions/conditions/first_order.rb index 434b3b6446e..1894606c1fd 100644 --- a/promotions/app/models/solidus_promotions/conditions/first_order.rb +++ b/promotions/app/models/solidus_promotions/conditions/first_order.rb @@ -20,11 +20,11 @@ def eligible?(order, options = {}) private def completed_orders - user ? user.orders.complete : orders_by_email + user ? user.orders.complete.not_canceled : orders_by_email end def orders_by_email - Spree::Order.where(email: email).complete + Spree::Order.where(email: email).complete.not_canceled end end end diff --git a/promotions/spec/models/solidus_promotions/conditions/first_order_spec.rb b/promotions/spec/models/solidus_promotions/conditions/first_order_spec.rb index a539eeb2303..a25e73d2814 100644 --- a/promotions/spec/models/solidus_promotions/conditions/first_order_spec.rb +++ b/promotions/spec/models/solidus_promotions/conditions/first_order_spec.rb @@ -4,8 +4,9 @@ RSpec.describe SolidusPromotions::Conditions::FirstOrder, type: :model do let(:condition) { described_class.new } - let(:order) { mock_model(Spree::Order, user: nil, email: nil) } - let(:user) { mock_model(Spree::LegacyUser) } + let(:order) { create(:order, user:, email:) } + let(:user) { nil } + let(:email) { nil } describe "#level" do it "is order" do @@ -31,36 +32,35 @@ context "first order" do context "for a signed user" do - context "with no completed orders" do - before do - allow(user).to receive_message_chain(:orders, complete: []) - end - - specify do - allow(order).to receive_messages(user: user) - expect(condition).to be_eligible(order) - end + let(:user) { create(:user) } + let(:email) { user.email } + context "with no completed, un-canceled orders" do it "is eligible when user passed in payload data" do expect(condition).to be_eligible(order, user: user) end end context "with completed orders" do - before do - allow(order).to receive_messages(user: user) - end + let(:order) { create(:completed_order_with_totals, user:, email:) } it "is eligible when checked against first completed order" do - allow(user).to receive_message_chain(:orders, complete: [order]) expect(condition).to be_eligible(order) end context "with another order" do - before { allow(user).to receive_message_chain(:orders, complete: [mock_model(Spree::Order)]) } + let!(:previous_order) { create(:completed_order_with_totals, user:) } it { expect(condition).not_to be_eligible(order) } + context "if previous order is canceled" do + before do + previous_order.cancel! + end + + it { expect(condition).to be_eligible(order) } + end + it "sets an error message" do condition.eligible?(order) expect(condition.eligibility_errors.full_messages.first) @@ -79,17 +79,23 @@ context "for a guest user" do let(:email) { "user@solidus.io" } - before { allow(order).to receive_messages email: "user@solidus.io" } - context "with no other orders" do it { expect(condition).to be_eligible(order) } end context "with another order" do - before { allow(condition).to receive_messages(orders_by_email: [mock_model(Spree::Order)]) } + let!(:previous_order) { create(:completed_order_with_totals, user: nil, email:) } it { expect(condition).not_to be_eligible(order) } + context "if previous order is canceled" do + before do + previous_order.cancel! + end + + it { expect(condition).to be_eligible(order) } + end + it "sets an error message" do condition.eligible?(order) expect(condition.eligibility_errors.full_messages.first)