diff --git a/core/app/models/spree/order.rb b/core/app/models/spree/order.rb index 6f3cdd7539..b296fc0f57 100644 --- a/core/app/models/spree/order.rb +++ b/core/app/models/spree/order.rb @@ -151,7 +151,8 @@ def states validates :email, presence: true, if: :email_required? validates :email, "spree/email" => true, :allow_blank => true validates :guest_token, presence: {allow_nil: true} - validates :number, presence: true, uniqueness: {allow_blank: true, case_sensitive: true} + validates :number, presence: true + validates :number, uniqueness: {allow_blank: true, case_sensitive: true}, if: :number_changed? validates :store_id, presence: true def self.find_by_param(value) diff --git a/core/spec/models/spree/order_spec.rb b/core/spec/models/spree/order_spec.rb index 9ca1d93c31..448aff439c 100644 --- a/core/spec/models/spree/order_spec.rb +++ b/core/spec/models/spree/order_spec.rb @@ -920,6 +920,24 @@ def call end end + describe "number uniqueness" do + let(:existing_order) { create(:order) } + + it "rejects a new order that reuses an existing number" do + expect(build(:order, number: existing_order.number)).not_to be_valid + end + + it "rejects changing a persisted order's number to one already taken" do + order.number = existing_order.number + expect(order).not_to be_valid + end + + it "skips the uniqueness query when the number is unchanged" do + order + expect { order.valid? }.not_to make_database_queries(matching: /SELECT 1 .*spree_orders.*number/i) + end + end + context "#associate_user!" do let!(:user) { FactoryBot.create(:user) }