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

Only save user-assigned order addresses if they are not new records. #7

Merged
merged 10 commits into from
Sep 30, 2015
Merged
6 changes: 6 additions & 0 deletions app/models/spree/address_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ def comparison_attributes
a
end

# Copied from Spree, modified to ignore user_id when checking for a blank
# address.
def empty?
attributes.except('id', 'created_at', 'updated_at', 'order_id', 'country_id', 'user_id').all? { |_, v| v.nil? }
end

# can modify an address if it's not been used in an completed order
# Users of the gem can override this method to provide different rules.
# See also Spree::Order#can_update_addresses? and Spree::User#can_update_addresses?
Expand Down
25 changes: 20 additions & 5 deletions app/models/spree/order_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

state_machine.after_transition to: :complete, do: :delink_addresses
before_validation :delink_addresses_validation, if: :complete?
# before_validation :merge_user_addresses, unless: :complete?
before_validation :discard_blank_addresses # Function itself limits to address and cart states
before_validation :merge_user_addresses, unless: :complete?

after_save :touch_addresses

Expand Down Expand Up @@ -143,6 +144,20 @@ def can_update_addresses?

private

# Removes blank addresses from the order before leaving the :cart state,
# ensuring that invalid addresses assigned to an order do not prevent a user
# from checking out.
def discard_blank_addresses
return unless self.state == 'address' || self.state == 'cart'

if bill_address && bill_address.invalid? && bill_address.blank?
self.bill_address = nil
end
if ship_address && ship_address.invalid? && ship_address.blank?
self.ship_address = nil
end
end

# While an order is in progress it refers to the same object as is in the
# address book (i.e. it is a reference). This makes the UI code easier. Once a
# order is complete we want to copy clone the address so the order/shipments
Expand Down Expand Up @@ -179,7 +194,7 @@ def merge_user_addresses
if user
l = Spree::AddressBookList.new(user)

if self.bill_address
if self.bill_address && self.bill_address.valid?
bill = l.find(self.bill_address)
if bill
if self.bill_address_id != bill.id
Expand All @@ -191,11 +206,11 @@ def merge_user_addresses

if self.bill_address.user_id.nil?
self.bill_address.user = self.user
self.bill_address.save
self.bill_address.save unless self.bill_address.new_record? || !self.bill_address.valid?
end
end

if self.ship_address
if self.ship_address && self.ship_address.valid?
if self.ship_address.same_as?(self.bill_address)
self.ship_address = self.bill_address
else
Expand All @@ -210,7 +225,7 @@ def merge_user_addresses

if self.ship_address.user_id.nil?
self.ship_address.user = self.user
self.ship_address.save
self.ship_address.save unless self.ship_address.new_record? || !self.ship_address.valid?
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/models/spree/user_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def link_address
self.bill_address = self.bill_address.clone
end
self.bill_address.user = self
self.bill_address.save unless self.bill_address.new_record?
self.bill_address.save unless self.bill_address.new_record? || !self.bill_address.valid?
end
end

Expand All @@ -62,7 +62,7 @@ def link_address
self.ship_address = self.ship_address.clone
end
self.ship_address.user = self
self.ship_address.save unless self.ship_address.new_record?
self.ship_address.save unless self.ship_address.new_record? || !self.ship_address.valid?
end
end
end
Expand Down
45 changes: 44 additions & 1 deletion spec/features/checkout_address_selection_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,49 @@
end.to change { user.addresses.count }.by(1)
end

context 'with invalid null addresses in the database' do
let(:nil_address) {
a = Spree::Address.new
a.save(validate: false)
a
}

let(:nil_user_address) {
a = nil
5.times do
a = Spree::Address.new(user: user)
a.save(validate: false)
end
a
}

let(:address1) { build(:fake_address) }
let(:address2) { build(:fake_address) }

before(:each) do
expect(nil_address.id).to be > 0
end

scenario 'a user can still check out' do
user.addresses.where.not(address1: nil).delete_all
user.orders.last.update_columns(bill_address_id: nil_user_address.id, ship_address_id: nil_address.id)
restart_checkout
expect(current_path).to eq('/checkout/address')

within '#billing' do
fill_in_address(address1)
end

within '#shipping' do
uncheck 'order_use_billing'
fill_in_address(address2)
end

complete_checkout
expect(page).to have_content("processed successfully")
end
end

describe "when invalid address is entered" do
let(:address) do
Spree::Address.new(:firstname => nil, :state => state)
Expand Down Expand Up @@ -383,7 +426,7 @@
end.to_not change{ user.addresses.count }
end

it 'should assign the the user default addresses to the order' do
it 'should assign the user default addresses to the order' do
user.update_attributes!(
bill_address_id: user.addresses.first.id,
ship_address_id: create(:address, user: user).id
Expand Down
39 changes: 39 additions & 0 deletions spec/features/guest_checkout_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Tests to make sure an aborted guest checkout (which due to a bug in
# spree_auth_devise creates invalid nil addresses in the database) doesn't
# prevent a customer from checking out.
require 'spec_helper'

feature 'Aborted guest checkout', js: true do
include_context 'checkout with product'

let(:user) { create(:user) }

scenario 'does not prevent later logged-in checkout' do
Spree::Order.delete_all
Spree::Address.delete_all

add_mug_to_cart
restart_checkout
fill_in 'order_email', with: '[email protected]'
click_button 'Continue'
click_button 'Continue'
sign_in_to_cart!(user)
click_button 'Continue'

expect(current_path).to eq(spree.checkout_state_path(:address))

expect {
within '#billing' do
fill_in_address(build(:fake_address))
end

within '#shipping' do
fill_in_address(build(:fake_address))
end

complete_checkout
}.to change{ Spree::Address.count }.by(4)

expect(Spree::Order.last.state).to eq('complete')
end
end
12 changes: 6 additions & 6 deletions spec/support/checkout_with_product.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@
Capybara.ignore_hidden_elements = true
end

def add_mug_to_cart
visit spree.root_path
click_link mug.name
click_button "add-to-cart-button"
end

private
def should_have_address_fields
expect(page).to have_field("First Name")
Expand Down Expand Up @@ -75,10 +81,4 @@ def expected_address_format(address)
Nokogiri::HTML(address.to_s).text
end

def add_mug_to_cart
visit spree.root_path
click_link mug.name
click_button "add-to-cart-button"
end

end
2 changes: 1 addition & 1 deletion spree_address_management.gemspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Gem::Specification.new do |s|
s.platform = Gem::Platform::RUBY
s.name = 'spree_address_management'
s.version = '2.3.2'
s.version = '2.3.3'
s.summary = "Allows users and admins to save and manage multiple addresses"
s.description = "A fork of spree_address_book (https://github.com/romul/spree_address_book). This gem allows Spree users to save multiple addresses for use during checkout, and provides robust tools for admins to assign, edit, and delete addresses."
s.required_ruby_version = '>= 1.9.3'
Expand Down