diff --git a/app/models/spree/order.rb b/app/models/spree/order.rb index 018b6b5c8b..824143a459 100644 --- a/app/models/spree/order.rb +++ b/app/models/spree/order.rb @@ -745,6 +745,15 @@ module Spree # Update the customer record if the user changed their email address. def synchronise_customer_email if user && customer && user.email != customer.email + duplicate = Customer.find_by(email: user.email, enterprise: distributor) + + if duplicate.present? + Spree::Order.where(customer_id: duplicate.id).update_all(customer_id: customer.id) + Subscription.where(customer_id: duplicate.id).update_all(customer_id: customer.id) + + duplicate.destroy + end + customer.update(email: user.email) end end diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb index e9e1ab8879..0f51eb7b7f 100644 --- a/spec/models/spree/order_spec.rb +++ b/spec/models/spree/order_spec.rb @@ -990,6 +990,33 @@ describe Spree::Order do expect(order.customer).to eq other_order.customer expect(order.reload.customer.email).to eq "new@email.org" end + + it "resolves conflicts with duplicate customer entries" do + order.update!(state: "complete") + + # The user may check out as guest first: + guest_order = create(:order, user: nil, email: "new@email.org", distributor: distributor) + guest_order.update!(state: "complete") + + # Afterwards the user changes their email in their profile. + # Change email instantly without confirmation via Devise: + order.user.update_columns(email: "new@email.org") + + other_order = nil + + # The two customer entries are merged and one is deleted: + expect { + other_order = create(:order, user: order.user, distributor: distributor) + }.to change { Customer.count }.by(-1) + + expect(other_order.customer.email).to eq "new@email.org" + expect(order.customer).to eq other_order.customer + expect(order.reload.customer.email).to eq "new@email.org" + + expect(order.customer.orders).to match_array [ + order, guest_order, other_order + ] + end end end