Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate default billing addresses to address book #3838

Merged

Conversation

mamhoff
Copy link
Contributor

@mamhoff mamhoff commented Nov 11, 2020

Description

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.

Checklist:

  • I have followed Pull Request guidelines
  • I have added a detailed description into each commit message
  • I have updated Guides and README accordingly to this change (if needed)
  • I have added tests to cover this change (if needed)
  • I have attached screenshots to this PR for visual changes (if needed)

@mamhoff mamhoff force-pushed the migrate-default-billing-addresses branch 2 times, most recently from 06eef4f to f83707b Compare November 11, 2020 15:49
@kennyadsl
Copy link
Member

Ref: #3563

Copy link
Member

@tvdeyen tvdeyen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving although this ideally should be a data migration that runs in a potential solidus:upgrade rake task. We had this rake task once (back in 1.x times) but this was unfortunately removed.

Anyhow. Thanks 👍


class MigrateDefaultBillingAddressesToAddressBook < ActiveRecord::Migration[5.2]
def up
adapter_type = connection.adapter_name.downcase.to_sym
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this again, I think we should add a safe guard here. Since we already shipped this code maybe someone already migrated their data.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true also for people that already updated to 2.11 and has some address with default_billing to true, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I've added a safeguard so that the migration does not do anything if any default_billing flags are already set.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that only avoids the migration (and the fix) to run for people that used 2.11 for some time before this will be released, isn't it? The ideal would be something that fixes their database as well. Do you think it's possible?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mamhoff any thoughts on this? Not sure I was clear enough, I meant that I think this will prevent the issue to happen only for users upgrading from Solidus 2.10.x to 2.11.4 (assuming 2.11.4 will contain this fix), but doesn't cover who upgrades from 2.11.3 to 2.11.4. Does it make sense?

@tvdeyen tvdeyen self-requested a review November 13, 2020 09:34
@mamhoff mamhoff force-pushed the migrate-default-billing-addresses branch from f83707b to 686b9a1 Compare November 13, 2020 09:37
@ikraamg
Copy link
Contributor

ikraamg commented Nov 28, 2020

Hi, thank you for this fix 🐛 👍 !

Below I have a suggestion, tested locally, in addition to your fix, to account for any codebase that already uses the default_billing (Solidus >=2.11.0). This should be able to safely migrate and rollback the DB:

def up
    # Safely migrate to the use of `default_billing` if the boolean was already used for the default address.
    if Spree::UserAddress.where(default_billing: true).any?
      (Spree::User.select { |user| user.bill_address_id && !user.bill_address })
        .each { |user| Spree::UserAddress.find_by(user_id: user.id, address_id: user.bill_address_id).update_attribute(:default_billing, true) }
      return true
    end

    adapter_type = 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;
          AND spree_users.bill_address != true
      SQL
    end
    execute sql
  end

  def down
    # Safely rollback the use of `default_billing` if the boolean was used for the default address.
    if Spree::UserAddress.where(default_billing: true).any?
      (Spree::User.select { |user| user.bill_address })
        .each { |user| user.update_attribute(:bill_address_id, user.bill_address.id) }
    end
    Spree::UserAddress.update_all(default_billing: false) # rubocop:disable Rails/SkipsModelValidations
  end

@mamhoff
Copy link
Contributor Author

mamhoff commented Nov 30, 2020

Hey @ikraamg thank you - However, for a very large Solidus installation, this will be prohibitively slow. I've purposefully set this to run in pure SQL, and I'm sure it's possible to do this without iterating over ActiveRecord collections. Sometime this week :)

@ikraamg
Copy link
Contributor

ikraamg commented Dec 11, 2020

Hi @mamhoff, @DanielePalombo helped out with a solution where we exclude the user_addresses that are already using the new format by setting those bill_address_id to nil before running the query:

if Spree::UserAddress.where(default_billing: true).any?
  Spree::User.joins(:bill_address).update_all(bill_address_id: nil)
end

....

It probably also should be moved to a dedicated rake task as Thomas mentioned.
I can work on it if your hands are full right now.

@ikraamg
Copy link
Contributor

ikraamg commented Jan 22, 2021

The task is created in a PR to this branch, however, I am unsure where to run the task as we do not have the upgrade task anymore that was previously used for similar tasks.

mamhoff#1

@mamhoff mamhoff force-pushed the migrate-default-billing-addresses branch from d31e393 to c09dc03 Compare February 1, 2021 09:21
core/spec/lib/spree/event/subscriber_registry_spec.rb Outdated Show resolved Hide resolved
core/lib/spree/awesome_nested_set_override.rb Outdated Show resolved Hide resolved
core/lib/spree/awesome_nested_set_override.rb Outdated Show resolved Hide resolved
core/lib/spree/awesome_nested_set_override.rb Outdated Show resolved Hide resolved
core/lib/spree/core/importer/order.rb Outdated Show resolved Hide resolved
core/lib/spree/core/importer/order.rb Outdated Show resolved Hide resolved
core/app/models/spree/taxon.rb Outdated Show resolved Hide resolved
@mamhoff mamhoff force-pushed the migrate-default-billing-addresses branch from c09dc03 to ca3ea85 Compare February 1, 2021 09:23
@mamhoff
Copy link
Contributor Author

mamhoff commented Feb 1, 2021

@ikraamg @DanielePalombo Thank you for moving this ahead! I've merged @ikraamg s Pull Request and fixed a few whitespace issues, but I think this should be good to go now :)

core/lib/tasks/upgrade.rake Show resolved Hide resolved
CHANGELOG.md Outdated
@@ -1,5 +1,13 @@
## Solidus 3.0.0 (master, unreleased)

Migrated default billing addresses to address book
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not go into the 3.0 changelog, we need to backport this task into 2.11.x. I'll take care of the changelog, you can remove this entirely.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I will remove this when I add the test case.

@ikraamg
Copy link
Contributor

ikraamg commented Feb 2, 2021

@mamhoff I have made the fixes that @kennyadsl requested in a new PR: mamhoff#2.

Then after a squash here, I think we are ready to merge this PR 👍

@kennyadsl
Copy link
Member

@mamhoff any chance to take a look at the other PR that @ikraamg submitted on this branch? Let me know if you don't have time and we'll merge this and apply the patches directly with another PR against the main repo. Thanks!

`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.

MySQL has different SQL syntax than standard SQL, which is why we need
two SQL statements.

For stores that have run this or a similar migration before, there's a
safeguard so they remember to fix their migrations when they upgrade.

Co-authored-by: mamhoff <[email protected]>
Co-authored-by: DanielePalombo <[email protected]>
Co-authored-by: Ikraam Ghoor <[email protected]>
@mamhoff mamhoff force-pushed the migrate-default-billing-addresses branch from 34eb833 to c91b470 Compare February 15, 2021 09:27
@mamhoff
Copy link
Contributor Author

mamhoff commented Feb 15, 2021

@ikraamg @DanielePalombo @kennyadsl merged and squashed!

@kennyadsl kennyadsl added this to the 2.11 milestone Feb 15, 2021
Copy link
Member

@kennyadsl kennyadsl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kennyadsl kennyadsl merged commit 0e58e06 into solidusio:master Feb 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants