Skip to content

Commit

Permalink
Migrate default billing addresses to address book
Browse files Browse the repository at this point in the history
`Spree::User` records have a `bill_address_id` that denotes their saved
billing address to be reused in the next checkout. That column, however,
is not in use since Solidus 2.11.0. Instead, we rely on a`default_billing`
Boolean on the `spree_user_addresses` join table.

This migration sets the `default_billing` flag on that join table for
addresses matching the user's default billing address and the user's ID.

For stores that have already started using the `default_billing`
Boolean, this task excludes the user_addresses that are already using
the new format by setting those `bill_address_id`s to `nil` before
running the query.

Co-authored-by: mamhoff <[email protected]>
Co-authored-by: DanielePalombo <[email protected]>
  • Loading branch information
3 people committed Feb 1, 2021
1 parent 002f4a3 commit c09dc03
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 33 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
## Solidus 3.0.0 (master, unreleased)

Migrated default billing addresses to address book

Spree::User records have a default bill_address_id that is not in use since
Solidus 2.11.0. Instead, we rely on a default_billing Boolean on the
spree_user_addresses join table.
Please run `rake solidus:upgrade:two_point_eleven`
to make sure your default addresses are migrated accordingly.

## Solidus 2.11.0 (2020-10-23)

### Major Changes
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

namespace :solidus do
namespace :migrations do
namespace :migrate_default_billing_addresses_to_address_book do
task up: :environment do
print "Migrating default billing addresses to address book ... "
if Spree::UserAddress.where(default_billing: true).any?
Spree::LegacyUser.joins(:bill_address).update_all(bill_address_id: nil) # rubocop:disable Rails/SkipsModelValidations
end
adapter_type = Spree::Base.connection.adapter_name.downcase.to_sym
if adapter_type == :mysql2
sql = <<~SQL
UPDATE spree_user_addresses
JOIN spree_users ON spree_user_addresses.user_id = spree_users.id
AND spree_user_addresses.address_id = spree_users.bill_address_id
SET spree_user_addresses.default_billing = true
SQL
else
sql = <<~SQL
UPDATE spree_user_addresses
SET default_billing = true
FROM spree_users
WHERE spree_user_addresses.address_id = spree_users.bill_address_id
AND spree_user_addresses.user_id = spree_users.id;
SQL
end
Spree::Base.connection.execute sql
puts "Success"
end

task down: :environment do
Spree::UserAddress.update_all(default_billing: false) # rubocop:disable Rails/SkipsModelValidations
puts "Rolled back default billing address migration to address book"
end
end
end
end
10 changes: 10 additions & 0 deletions core/lib/tasks/upgrade.rake
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace :solidus do
namespace :upgrade do
desc "Upgrade Solidus to version 2.11.0"
task two_point_eleven: [
'solidus:migrations:migrate_default_billing_addresses_to_address_book:up'
] do
puts "Your Solidus install is ready for Solidus 2.11.0"
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe 'solidus:migrations:migrate_default_billing_addresses_to_address_book' do
describe 'up' do
include_context(
'rake',
task_path: Spree::Core::Engine.root.join('lib/tasks/migrations/migrate_default_billing_addresses_to_address_book.rake'),
task_name: 'solidus:migrations:migrate_default_billing_addresses_to_address_book:up',
)

let(:user1) { create(:user) }
let(:user2) { create(:user) }
let(:bill_address1) { FactoryBot.create(:address) }
let(:bill_address2) { FactoryBot.create(:address) }
let(:bill_address3) { FactoryBot.create(:address) }

before do
# Set two billing addresses for User1, the second address is the default.
user1.save_in_address_book(bill_address1.attributes, false, :billing)
user1.save_in_address_book(bill_address2.attributes, true, :billing)

# Update the "bill_address_id" for user1 to be diffirent from the address_book's default address.
user1.update!(bill_address_id: bill_address1.id)

# Set user2's bill address using old `bill_address_id` method.
user2.save_in_address_book(bill_address3.attributes, false, :billing)
user2.update!(bill_address_id: bill_address3.id)
Spree::UserAddress.where(user_id: user2.id).first.update!(default_billing: false)
end

it 'runs' do
expect { task.invoke }.to output(
"Migrating default billing addresses to address book ... Success\n"
).to_stdout
end

it "does not migrate a user's `bill_address_id` when a user already has a default `bill_address` in the address book" do
task.invoke
expect(user1.bill_address_id).not_to eq bill_address2.id
expect(user1.bill_address).to eq bill_address2
end

it "migrates a user's `bill_address_id` when a user does not have a default `bill_address` in the address book" do
task.invoke
expect(user2.bill_address_id).to eq bill_address3.id
expect(user2.bill_address).to eq bill_address3
end
end

describe 'down' do
include_context(
'rake',
task_path: Spree::Core::Engine.root.join('lib/tasks/migrations/migrate_default_billing_addresses_to_address_book.rake'),
task_name: 'solidus:migrations:migrate_default_billing_addresses_to_address_book:down',
)

let(:user) { create(:user) }
let(:bill_address) { FactoryBot.create(:address) }

before do
user.save_in_address_book(bill_address.attributes, true, :billing)
end

it 'runs' do
expect { task.invoke }.to output(
"Rolled back default billing address migration to address book\n"
).to_stdout
end

it "Rolls back default billing address migration to address book" do
task.invoke
expect(user.bill_address).to eq nil
end
end
end

0 comments on commit c09dc03

Please sign in to comment.