mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge pull request #9642 from mkllnk/9002-customer-association
Delete duplicate customer entries
This commit is contained in:
@@ -44,6 +44,11 @@ Metrics/BlockLength:
|
||||
"xdescribe",
|
||||
]
|
||||
|
||||
Rails/ApplicationRecord:
|
||||
Exclude:
|
||||
# Migrations should not contain application code:
|
||||
- "db/migrate/*.rb"
|
||||
|
||||
Rails/SkipsModelValidations:
|
||||
AllowedMethods:
|
||||
- "touch"
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# A customer record is created the first time a person orders from a shop.
|
||||
#
|
||||
# It's a relationship between a user and an enterprise but for guest orders it
|
||||
# can also be between an email address and an enterprise.
|
||||
#
|
||||
# The main purpose is tagging of customers to access private shops, receive
|
||||
# discounts et cetera. A customer record is also needed for subscriptions.
|
||||
class Customer < ApplicationRecord
|
||||
include SetUnusedAddressFields
|
||||
|
||||
@@ -7,7 +14,7 @@ class Customer < ApplicationRecord
|
||||
|
||||
searchable_attributes :first_name, :last_name, :email, :code
|
||||
|
||||
belongs_to :enterprise
|
||||
belongs_to :enterprise, optional: false
|
||||
belongs_to :user, class_name: "Spree::User"
|
||||
has_many :orders, class_name: "Spree::Order"
|
||||
before_destroy :update_orders_and_delete_canceled_subscriptions
|
||||
@@ -26,7 +33,6 @@ class Customer < ApplicationRecord
|
||||
validates :code, uniqueness: { scope: :enterprise_id, allow_nil: true }
|
||||
validates :email, presence: true, 'valid_email_2/email': true,
|
||||
uniqueness: { scope: :enterprise_id, message: I18n.t('validation_msg_is_associated_with_an_exising_customer') }
|
||||
validates :enterprise, presence: true
|
||||
|
||||
scope :of, ->(enterprise) { where(enterprise_id: enterprise) }
|
||||
|
||||
|
||||
88
db/migrate/20220907055044_delete_duplicate_customers.rb
Normal file
88
db/migrate/20220907055044_delete_duplicate_customers.rb
Normal file
@@ -0,0 +1,88 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class DeleteDuplicateCustomers < ActiveRecord::Migration[6.1]
|
||||
class Customer < ActiveRecord::Base
|
||||
belongs_to :bill_address, class_name: "SpreeAddress"
|
||||
belongs_to :ship_address, class_name: "SpreeAddress"
|
||||
|
||||
after_destroy do
|
||||
destroy_unused_address(bill_address)
|
||||
destroy_unused_address(ship_address)
|
||||
end
|
||||
|
||||
def destroy_unused_address(record)
|
||||
return unless record
|
||||
return if in_use?(SpreeOrder, record)
|
||||
return if in_use?(Customer, record)
|
||||
return if in_use?(SpreeUser, record)
|
||||
|
||||
record.destroy
|
||||
end
|
||||
|
||||
def in_use?(model, record)
|
||||
model.where(bill_address_id: record).or(
|
||||
model.where(ship_address_id: record)
|
||||
).present?
|
||||
end
|
||||
end
|
||||
|
||||
class SpreeAddress < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class SpreeOrder < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class Subscription < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class Customer < ActiveRecord::Base
|
||||
end
|
||||
|
||||
class SpreeUser < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def up
|
||||
say "#{grouped_duplicates.keys.count} customers with duplicates."
|
||||
|
||||
grouped_duplicates.map do |key, customers|
|
||||
chosen = customers.first
|
||||
others = customers - [chosen]
|
||||
|
||||
say "- #{key}"
|
||||
|
||||
# We can't tell which attributes or associations are the correct ones.
|
||||
# Selection has been random so far and it's no regression to randomly
|
||||
# select the attributes of the first customer record.
|
||||
#
|
||||
# However, we do need to update references to the customer.
|
||||
update_references(others, chosen)
|
||||
|
||||
others.each(&:destroy!)
|
||||
end
|
||||
end
|
||||
|
||||
def grouped_duplicates
|
||||
@grouped_duplicates ||= duplicate_records.group_by do |customer|
|
||||
[customer.email, customer.enterprise_id]
|
||||
end
|
||||
end
|
||||
|
||||
def duplicate_records
|
||||
customer_duplicates = <<~SQL
|
||||
JOIN customers AS copy
|
||||
ON customers.id != copy.id
|
||||
AND customers.email = copy.email
|
||||
AND customers.enterprise_id = copy.enterprise_id
|
||||
SQL
|
||||
|
||||
Customer.joins(customer_duplicates)
|
||||
end
|
||||
|
||||
def update_references(source_customers, destination_customer)
|
||||
SpreeOrder.where(customer_id: source_customers.map(&:id)).
|
||||
update_all(customer_id: destination_customer.id)
|
||||
|
||||
Subscription.where(customer_id: source_customers.map(&:id)).
|
||||
update_all(customer_id: destination_customer.id)
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2022_07_13_195433) do
|
||||
ActiveRecord::Schema.define(version: 2022_09_07_055044) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
|
||||
Reference in New Issue
Block a user