Skip to content

Commit

Permalink
Remove state_id or state_name when addresses country is changed to co…
Browse files Browse the repository at this point in the history
…untry without states spree#6598
  • Loading branch information
tanmay3011 committed Mar 8, 2016
1 parent cf54e0e commit 0e11f02
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 8 deletions.
30 changes: 26 additions & 4 deletions core/app/models/spree/address.rb
Expand Up @@ -7,6 +7,8 @@ class Address < Spree::Base

has_many :shipments, inverse_of: :address

before_validation :clear_invalid_state_entities, if: -> { country.present? }, on: :update

with_options presence: true do
validates :firstname, :lastname, :address1, :city, :country
validates :zipcode, if: :require_zipcode?
Expand Down Expand Up @@ -97,19 +99,39 @@ def require_zipcode?
end

private
def clear_state_entities
clear_state
clear_state_name
end

def clear_state
self.state = nil
end

def clear_state_name
self.state_name = nil
end

def clear_invalid_state_entities
if state.present? && (state.country != country)
clear_state
elsif state_name.present? && !country.states_required? && country.states.empty?
clear_state_name
end
end

def state_validate
# Skip state validation without country (also required)
# or when disabled by preference
return if country.blank? || !Spree::Config[:address_requires_state]
return unless country.states_required

# ensure associated state belongs to country
if state.present?
if state.country == country
self.state_name = nil #not required as we have a valid state and country combo
clear_state_name #not required as we have a valid state and country combo
else
if state_name.present?
self.state = nil
clear_state
else
errors.add(:state, :invalid)
end
Expand All @@ -123,7 +145,7 @@ def state_validate

if states.size == 1
self.state = states.first
self.state_name = nil
clear_state_name
else
errors.add(:state, :invalid)
end
Expand Down
113 changes: 109 additions & 4 deletions core/spec/models/spree/address_spec.rb
@@ -1,8 +1,10 @@
require 'spec_helper'

describe Spree::Address, :type => :model do
describe Spree::Address, type: :model do

subject { Spree::Address }
describe 'Callbacks' do
it { is_expected.to callback(:clear_invalid_state_entities).before(:validation).on(:update) }
end

describe "clone" do
it "creates a copy of the address with the exception of the id, updated_at and created_at attributes" do
Expand Down Expand Up @@ -232,12 +234,12 @@
let(:user) { double("User", bill_address: bill_address, ship_address: ship_address) }

it "returns a copy of that user bill address" do
expect(subject.default(user).phone).to eq bill_address.phone
expect(Spree::Address.default(user).phone).to eq bill_address.phone
end

it "falls back to build default when user has no address" do
allow(user).to receive_messages(bill_address: nil)
expect(subject.default(user)).to eq subject.build_default
expect(Spree::Address.default(user)).to eq Spree::Address.build_default
end
end
end
Expand Down Expand Up @@ -288,4 +290,107 @@
let(:address) { stub_model(Spree::Address) }
specify { expect(address.instance_eval{ require_phone? }).to be true}
end

context '#clear_state_entities' do
let (:address) { create(:address) }
before { address.state_name = 'maryland' }

it { expect{ address.send(:clear_state_entities) }.to change { address.state }.to(nil).from(address.state) }
it { expect{ address.send(:clear_state_entities) }.to change { address.state_name }.to(nil).from('maryland') }
end

context '#clear_state' do
let (:address) { create(:address) }
before { address.state_name = 'maryland' }

it { expect{ address.send(:clear_state) }.to change { address.state }.to(nil).from(address.state) }
it { expect{ address.send(:clear_state) }.to_not change(address, :state_name) }
end

context '#clear_state_name' do
let (:address) { create(:address) }
before { address.state_name = 'maryland' }

it { expect{ address.send(:clear_state_name) }.to_not change(address, :state_id) }
it { expect{ address.send(:clear_state_name) }.to change { address.state_name }.to(nil).from('maryland') }
end

context '#clear_invalid_state_entities' do
let(:country) { create(:country) }
let(:state) { create(:state, country: country) }
let (:address) { create(:address, country: country, state: state) }

def clear_state_entities
address.send(:clear_invalid_state_entities)
end

context 'state not present and state_name both not present' do
before do
address.state = nil
address.state_name = nil
clear_state_entities
end

it { expect(address.state).to be_nil }
it { expect(address.state_name).to be_nil }
end

context 'state_name not present and state present ' do
before { address.state_name = nil }

context 'state belongs to a different country than to which address is associated' do
before do
address.country = create(:country)
clear_state_entities
end

it { expect(address.state).to be_nil }
it { expect(address.state_name).to be_nil }
end

context 'state belongs to the same country associated with address' do
before { clear_state_entities }
it { expect(address.state).to eq(state) }
it { expect(address.state_name).to be_nil }
end
end

context 'state not present and state_name present' do
before do
address.state = nil
address.state_name = state.name
end

context 'when country has no states and state is required' do
before do
address.country = create(:country, states_required: true)
clear_state_entities
end

it { expect(address.state).to be_nil }
it { expect(address.state_name).to eq(state.name) }
end

context 'when country has states' do
before do
address.state_name = state.name
clear_state_entities
end

it { expect(address.state).to be_nil }
it { expect(address.state_name).to eq(state.name) }
end

context 'when country has no states and state is not required' do
before do
address.country = create(:country, states_required: false)
address.state_name = state.name
clear_state_entities
end

it { expect(address.state).to be_nil }
it { expect(address.state_name).to be_nil }
end
end
end
end

0 comments on commit 0e11f02

Please sign in to comment.