Class: Address

Inherits:
ApplicationRecord show all
Includes:
Comparable, Models::Auditable, Models::LiquidMethods, PgSearch::Model
Defined in:
app/models/address.rb

Overview

== Schema Information

Table name: addresses
Database name: primary

id :integer not null, primary key
address_text :text
address_text_tsvector :tsvector
address_type :string(255)
city :string(255)
company_name_override :string(255)
country_iso3 :string(3)
county_code :string(255)
county_name :string(255)
description :string(255)
disable_address_correction :boolean
has_loading_dock :boolean
is_construction_site :boolean
is_placeholder :boolean default(FALSE), not null
is_residential :boolean default(TRUE), not null
is_store_mailing_address :boolean default(FALSE)
is_trade_show :boolean
is_warehouse :boolean default(FALSE)
jde_number :integer
lat :float
limited_access :boolean
lng :float
normalized_address :string
override_all_address_validation :boolean
person_name_override :string(255)
recipients_tsv :tsvector
region :string
require_signature_by_default :boolean default(FALSE), not null
requires_appointment :boolean
requires_inside_delivery :boolean
requires_liftgate :boolean
series_geocoded :boolean
service_area_mile_radius :integer
smartfit_available_updated_at :datetime default(2012-03-28 20:35:14.000000000 CDT -05:00), not null
state_code :string(20)
street1 :string(255)
street2 :string(255)
street3 :string(35)
supported_carriers :string(255) is an Array
supports_third_party_shipping :boolean
timezone_name :string
verified :boolean default(FALSE)
verified_for_shipping :boolean
zip :string(255)
created_at :datetime
updated_at :datetime
creator_id :integer
party_id :integer
updater_id :integer

Indexes

addresses_jde_number_index (jde_number)
addresses_party_id_index (party_id)
index_addresses_on_address_text_tsvector (address_text_tsvector) USING gin
index_addresses_on_country_iso3 (country_iso3)
index_addresses_on_county_code (county_code)
index_addresses_on_county_name (county_name)
index_addresses_on_lat_and_lng (lat,lng)
index_addresses_on_recipients_tsv (recipients_tsv) USING gin
index_addresses_on_state_code (state_code)
index_addresses_street1_like (street1)
index_addresses_zip_like (zip)
tsearch_city_idx (to_tsvector('english'::regconfig, (city)::text)) USING gin
tsearch_zip_idx (to_tsvector('english'::regconfig, (zip)::text)) USING gin

Foreign Keys

addresses_party_id_fk (party_id => parties.id) ON DELETE => nullify
fk_addresses_country_iso3 (country_iso3 => countries.iso3)

Defined Under Namespace

Classes: Creator, LineAbbreviator, NormalizedAddress, RecalculateShipping, Updater

Constant Summary collapse

PO_BOX_REGEXP =

Po box regexp.

/[p|P]\s*[o|O]\s*[b|B]\s*[o|O]\s*[x|X]\s*[a-zA-Z0-9]*|\b[P|p]+(OST|ost|o|O)?\.?\s*[O|o0]+(ffice|FFICE)?\.?\s*[B|b][O|o0]?[X|x]+\.?\s+\#?(\d+)*(\D+)*\b|[c|C]\s*[p|P]\s*[0-9]/
MAX_STREET_FIELD_LENGTH =

Maximum street field length.

35
ADDRESS_FIELDS_FOR_GEOCODING =

Address fields for geocoding.

%w[street1 street2 street3 city state_code country_iso3 zip].freeze
ADDRESS_FIELDS_TO_RECALCULATE_SHIPPING_FOR =

Address fields to recalculate shipping for.

(ADDRESS_FIELDS_FOR_GEOCODING + %w[is_residential require_signature_by_default]).freeze
FREIGHT_FIELDS =

Recognised freight fields.

%w[has_loading_dock requires_liftgate requires_inside_delivery is_construction_site limited_access
requires_appointment].freeze

Constants included from Models::Auditable

Models::Auditable::ALWAYS_IGNORED

Constants included from Schedulable

Schedulable::SIMPLE_FORM_OPTIONS

Instance Attribute Summary collapse

Belongs to collapse

Methods included from Models::Auditable

#creator, #updater

Has one collapse

Has many collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Models::Auditable

#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Schedulable

config

Methods included from Models::AfterCommittable

#after_commit

Methods included from Models::EventPublishable

#publish_event

Instance Attribute Details

#admin_modeObject

Returns the value of attribute admin_mode.



99
100
101
# File 'app/models/address.rb', line 99

def admin_mode
  @admin_mode
end

#autocorrect_messageObject

Returns the value of attribute autocorrect_message.



99
100
101
# File 'app/models/address.rb', line 99

def autocorrect_message
  @autocorrect_message
end

#check_for_duplicatesObject

Returns the value of attribute check_for_duplicates.



99
100
101
# File 'app/models/address.rb', line 99

def check_for_duplicates
  @check_for_duplicates
end

#cityObject (readonly)



132
# File 'app/models/address.rb', line 132

validates :street1, :city, :country_iso3, presence: true

#country_iso3Object (readonly)



132
# File 'app/models/address.rb', line 132

validates :street1, :city, :country_iso3, presence: true

#do_not_accept_legacy_verifiedObject

Returns the value of attribute do_not_accept_legacy_verified.



99
100
101
# File 'app/models/address.rb', line 99

def do_not_accept_legacy_verified
  @do_not_accept_legacy_verified
end

#require_carrier_validationObject

Returns the value of attribute require_carrier_validation.



99
100
101
# File 'app/models/address.rb', line 99

def require_carrier_validation
  @require_carrier_validation
end

#set_default_billing_addressObject

Returns the value of attribute set_default_billing_address.



99
100
101
# File 'app/models/address.rb', line 99

def set_default_billing_address
  @set_default_billing_address
end

#set_default_mailing_addressObject

Returns the value of attribute set_default_mailing_address.



99
100
101
# File 'app/models/address.rb', line 99

def set_default_mailing_address
  @set_default_mailing_address
end

#set_default_shipping_addressObject

Returns the value of attribute set_default_shipping_address.



99
100
101
# File 'app/models/address.rb', line 99

def set_default_shipping_address
  @set_default_shipping_address
end

#skip_carrier_validationObject

Returns the value of attribute skip_carrier_validation.



99
100
101
# File 'app/models/address.rb', line 99

def skip_carrier_validation
  @skip_carrier_validation
end

#state_codeObject (readonly)



133
# File 'app/models/address.rb', line 133

validates :state_code, presence: { if: :requires_states_or_provinces? }

#street1Object (readonly)



132
# File 'app/models/address.rb', line 132

validates :street1, :city, :country_iso3, presence: true

#street2Object (readonly)



137
138
# File 'app/models/address.rb', line 137

validates :street1, :street2, :street3, length: { maximum: MAX_STREET_FIELD_LENGTH,
too_long: "is too long (maximum is #{MAX_STREET_FIELD_LENGTH} characters, you may need to DISABLE address correction)" }

#street3Object (readonly)



137
138
# File 'app/models/address.rb', line 137

validates :street1, :street2, :street3, length: { maximum: MAX_STREET_FIELD_LENGTH,
too_long: "is too long (maximum is #{MAX_STREET_FIELD_LENGTH} characters, you may need to DISABLE address correction)" }

#suggested_addressesObject

Returns the value of attribute suggested_addresses.



99
100
101
# File 'app/models/address.rb', line 99

def suggested_addresses
  @suggested_addresses
end

#validate_with_carrierObject

Returns the value of attribute validate_with_carrier.



99
100
101
# File 'app/models/address.rb', line 99

def validate_with_carrier
  @validate_with_carrier
end

Class Method Details

.address_type_optionsObject



213
214
215
216
217
218
# File 'app/models/address.rb', line 213

def self.address_type_options
  [['Residential', 'residential'],
   ['Commercial Building with Receiving Dock', 'commercial_building_with_receiving_dock'],
   ['Commercial Building without Receiving Dock', 'commercial_building_without_receiving_dock'],
   ['Construction Site/Limited Access', 'construction_site']]
end

.canadaActiveRecord::Relation<Address>

A relation of Addresses that are canada. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Address>)

See Also:



162
# File 'app/models/address.rb', line 162

scope :canada, -> { where(country_iso3: 'CAN') }

.clear_geocoder_cacheObject



196
197
198
199
# File 'app/models/address.rb', line 196

def self.clear_geocoder_cache
  # Queue all our locator address for geocoding
  Geocoder::Lookup.get(:google).cache.expire(:all)
end

.geocode_address_string(address_string) ⇒ Object



738
739
740
741
742
743
744
745
# File 'app/models/address.rb', line 738

def self.geocode_address_string(address_string)
  # aargh deal with &&^%^&% new Geocoder issue where it return no results when space is skipped in Canadian postal codes
  address_string = "#{address_string[0..2]} #{address_string[3..5]}" if address_string && (address_string.length == 6)
  results = Geocoder.search(address_string)
  return unless (geo = results.first)

  [geo.latitude, geo.longitude]
end

.is_warehouseActiveRecord::Relation<Address>

A relation of Addresses that are is warehouse. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Address>)

See Also:



160
# File 'app/models/address.rb', line 160

scope :is_warehouse, -> { where(is_warehouse: true) }

.linked_to_party_or_orderActiveRecord::Relation<Address>

A relation of Addresses that are linked to party or order. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Address>)

See Also:



163
164
165
166
167
168
169
170
171
# File 'app/models/address.rb', line 163

scope :linked_to_party_or_order, -> {
  where(%{exists(select 1 from parties
                          where addresses.party_id is not null
                            and parties.id = addresses.party_id
                            and parties.type IN ('Customer','Contact'))
                   OR
                   exists(select 1 from orders
                          where orders.shipping_address_id = addresses.id) })
}

.placeholder_address(country = 'USA') ⇒ Object



205
206
207
# File 'app/models/address.rb', line 205

def self.placeholder_address(country = 'USA')
  Address.find_by(is_placeholder: true, country_iso3: country)
end

.populate_regionObject

Populates the region field based on the country and state code.



1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
# File 'app/models/address.rb', line 1163

def self.populate_region
  Address.transaction do
    %w[US CA].each do |iso|
      ic = ISO3166::Country[iso]
      ic.subdivisions.each do |state_code, sub|
        n = sub.name
        Address.where(country_iso3: ic.alpha3, state_code: state_code, region: nil).update_all(region: n)
      end
    end
    # Now for the stragglers
    Address.where(region: nil).where.not(country_iso3: nil).where.not(state_code: nil).find_each do |a|
      next unless (ic = a.iso3166_country)
      next unless (sub = ic.find_subdivision_by_name(a.state_code))

      a.update_columns(region: sub.name, state_code: sub.code)
    end
  end
end

.usaActiveRecord::Relation<Address>

A relation of Addresses that are usa. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Address>)

See Also:



161
# File 'app/models/address.rb', line 161

scope :usa, -> { where(country_iso3: 'USA') }

.warehouse_addressesActiveRecord::Relation<Address>

A relation of Addresses that are warehouse addresses. Active Record Scope

Returns:

  • (ActiveRecord::Relation<Address>)

See Also:



159
# File 'app/models/address.rb', line 159

scope :warehouse_addresses, -> { where(is_warehouse: true) }

Instance Method Details

#==(other) ⇒ Object



329
330
331
332
333
# File 'app/models/address.rb', line 329

def ==(other)
  return false unless other.is_a?(Address)

  same_as(other)
end

#address_dropdown_formatObject



427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
# File 'app/models/address.rb', line 427

def address_dropdown_format
  address = []
  address << street1.presence
  address << street2.presence
  address << street3.presence
  address << city.presence
  address << "#{state_code} #{zip}"
  address << country_iso3
  address = address.uniq.compact

  if Party.where(mailing_address_id: id).present?
    { id: id, text: "#{address.join(', ')} ---> (MAILING)" }
  elsif Party.where(billing_address_id: id).present?
    { id: id, text: "#{address.join(', ')} ---> (BILLING)" }
  elsif Party.where(shipping_address_id: id).present?
    { id: id, text: "#{address.join(', ')} ---> (SHIPPING)" }
  else
    { id: id, text: "#{address.join(', ')} ---> (OTHER)" }
  end
end

#address_element_changed?Boolean

Returns:

  • (Boolean)


952
953
954
# File 'app/models/address.rb', line 952

def address_element_changed?
  (ADDRESS_FIELDS_TO_RECALCULATE_SHIPPING_FOR + FREIGHT_FIELDS).any? { |f| changes[f] || saved_changes[f] }
end

#address_element_changed_for_geocoding?Boolean

Returns:

  • (Boolean)


956
957
958
# File 'app/models/address.rb', line 956

def address_element_changed_for_geocoding?
  ADDRESS_FIELDS_FOR_GEOCODING.any? { |f| changes[f] || saved_changes[f] }
end

#address_for_comparisonObject



454
455
456
457
# File 'app/models/address.rb', line 454

def address_for_comparison
  # here we can sometimes get Null, NULL, null, etc. from some services for an address field, also replace common abbreviations with a standard set
  to_array(upcase: true, include_recipient: :overrides)
end

#address_for_geocoderObject



448
449
450
451
452
# File 'app/models/address.rb', line 448

def address_for_geocoder
  addr = [street1, street2, city, state&.name || state_code, zip, country&.name]
  addr = addr.map(&:to_s).map(&:squish).filter_map(&:presence)
  addr.join(',')
end

#archiveable?Boolean

Returns:

  • (Boolean)


996
997
998
# File 'app/models/address.rb', line 996

def archiveable?
  billing_customer.nil? && shipping_customer.nil? && mailing_customer.nil?
end

#belongs_to?(customer) ⇒ Boolean

INSTANCE METHODS

Returns:

  • (Boolean)


258
259
260
261
# File 'app/models/address.rb', line 258

def belongs_to?(customer)
  (party_id == customer.id) ||
    shipping_orders.find { |o| o.customer_id == customer.id }
end

#billing_credit_memosActiveRecord::Relation<CreditMemo>

Returns:

See Also:



119
# File 'app/models/address.rb', line 119

has_many   :billing_credit_memos, class_name: 'CreditMemo', foreign_key: :billing_address_id

#billing_customerCustomer

Returns:

See Also:



109
# File 'app/models/address.rb', line 109

has_one    :billing_customer, class_name: 'Customer', dependent: :nullify, foreign_key: :billing_address_id, inverse_of: :billing_address

#billing_invoicesActiveRecord::Relation<Invoice>

Returns:

  • (ActiveRecord::Relation<Invoice>)

See Also:



117
# File 'app/models/address.rb', line 117

has_many   :billing_invoices, class_name: 'Invoice', foreign_key: :billing_address_id

#billing_ordersActiveRecord::Relation<Order>

Returns:

  • (ActiveRecord::Relation<Order>)

See Also:



115
# File 'app/models/address.rb', line 115

has_many   :billing_orders, class_name: 'Order', foreign_key: :billing_address_id

#carrier_validation(autosave = false) ⇒ Object



917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
# File 'app/models/address.rb', line 917

def carrier_validation(autosave = false)
  # puts "!!!!!!!!!!!!!carrier_validation"
  return false, errors_to_s, [] if errors.any?
  if is_warehouse || override_all_address_validation
    return true, (is_warehouse ? 'Address is warehouse' : 'Address is marked override all validation'), []
  end

  require 'wy_shipping'
  result = WyShipping.valid_address?(self)
  logger.info "External Validation with Carrier result #{result[:valid_address]}:#{result[:status_message]}."
  ErrorReporting.error("Carrier validation params missing. 'valid_address' not present. Result params: #{result}") if result[:valid_address].nil?
  res = result[:valid_address]
  if res == true && is_residential == true && # be conservative here and tend to residential unless all suggested addressed say address_residential_indicator 'no'
     result[:suggested_address_hashes].all? do |ah|
       ah['address_residential_indicator'] == 'no'
     end
    res = true
    self.is_residential = false
    self.autocorrect_message = 'Address was AUTOCORRECTED, from residential to commercial.'
    logger.info 'Adjusting address marking it residential false because carrier says so.'
  elsif res == true && is_residential == false && # be conservative here and tend to residential if any suggested addressed say address_residential_indicator 'yes'
        result[:suggested_address_hashes].any? do |ah|
          ah['address_residential_indicator'] == 'yes'
        end
    res = true
    self.is_residential = true
    self.autocorrect_message = 'Address was AUTOCORRECTED, from commercial to residential.'
    logger.info "External Validation with Carrier result #{result[:valid_address]}:#{result[:status_message]}."
    logger.info 'Adjusting address marking it residential true because carrier says so.'
  end
  self.verified_for_shipping = res
  save if verified_for_shipping && autosave
  [res, result[:status_message], result[:suggested_address_hashes] || []]
end

#check_for_location_changeObject



244
245
246
247
248
249
250
251
252
253
254
255
# File 'app/models/address.rb', line 244

def check_for_location_change
  return unless party && lat && lng && (saved_change_to_lat? || saved_change_to_lng?)

  Rails.configuration.event_store.publish(
    Events::LocationChanged.new(data: {
      party_id: party.id,
      latitude: lat,
      longitude: lng
    }),
    stream_name: "Party-#{party.id}"
  )
end

#company_nameObject



988
989
990
# File 'app/models/address.rb', line 988

def company_name
  company_name_override.presence || inherited_company_name
end

#company_name=(value) ⇒ Object



992
993
994
# File 'app/models/address.rb', line 992

def company_name=(value)
  self.company_name_override = value unless inherited_company_name && value =~ /inherited_company_name/i
end

#correct_zipObject



201
202
203
# File 'app/models/address.rb', line 201

def correct_zip
  ValidatesZipcode.valid?(zip, country_iso) if has_postal_codes?
end

#countryCountry

Returns:

See Also:



106
# File 'app/models/address.rb', line 106

belongs_to :country, foreign_key: 'country_iso3', primary_key: 'iso3'

#country_isoObject



299
300
301
# File 'app/models/address.rb', line 299

def country_iso
  iso3166_country&.alpha2
end

#country_iso=(val) ⇒ Object

Accessors when iso 2 character form is used



295
296
297
# File 'app/models/address.rb', line 295

def country_iso=(val)
  self.country_iso3 = ISO3166::Country[val]&.alpha3
end

#country_printable_name(locale: I18n.locale) ⇒ Object

Saves us a db call in 99.99% of cases



712
713
714
715
# File 'app/models/address.rb', line 712

def country_printable_name(locale: I18n.locale)
  lang = locale.to_s.first(2).downcase
  iso3166_country.translation(lang)
end

#credit_lineObject



367
368
369
# File 'app/models/address.rb', line 367

def credit_line
  party&.has_terms? ? party.available_credit.to_i : 0
end

#data_hashObject



263
264
265
266
267
268
269
270
271
272
273
274
# File 'app/models/address.rb', line 263

def data_hash
  hsh = {
    street1: street1,
    city: city,
    state: state&.name || state_code,
    zip: zip,
    country: country.iso
  }
  # only add street2 if it's present, otherwise you'll end up with a 'NULL' string
  hsh[:street2] = street2 if street2.present?
  hsh
end

#default_billingObject



388
389
390
# File 'app/models/address.rb', line 388

def default_billing
  party && party.id.present? && (party.billing_address_id == id)
end

#default_billing=(new_value) ⇒ Object



392
393
394
# File 'app/models/address.rb', line 392

def default_billing=(new_value)
  self.set_default_billing_address = true if new_value.to_b
end

#default_mailingObject



371
372
373
# File 'app/models/address.rb', line 371

def default_mailing
  party&.id.present? && (party.mailing_address_id == id)
end

#default_mailing=(new_value) ⇒ Object



384
385
386
# File 'app/models/address.rb', line 384

def default_mailing=(new_value)
  self.set_default_mailing_address = true if new_value.to_b
end

#default_shippingObject



396
397
398
# File 'app/models/address.rb', line 396

def default_shipping
  party && party.id.present? && (party.shipping_address_id == id)
end

#default_shipping=(new_value) ⇒ Object



400
401
402
# File 'app/models/address.rb', line 400

def default_shipping=(new_value)
  self.set_default_shipping_address = true if new_value.to_b
end

#dependentsObject



555
556
557
558
559
560
561
562
563
564
565
566
567
# File 'app/models/address.rb', line 555

def dependents
  deps = []
  deps += shipping_orders
  deps << billing_customer
  deps += shipping_quotes
  deps += 
  deps += mail_activities
  deps += billing_invoices
  deps += shipping_invoices
  deps += billing_credit_memos
  deps += shipping_credit_memos
  deps.uniq.compact
end


1000
1001
1002
1003
1004
1005
1006
# File 'app/models/address.rb', line 1000

def destroy_or_unlink
  if ok_to_delete?
    destroy
  else
    unlink
  end
end

#determine_address_typeObject



220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'app/models/address.rb', line 220

def determine_address_type
  return unless persisted?

  if is_residential
    'residential'
  elsif is_construction_site
    'construction_site'
  elsif has_loading_dock
    'commercial_building_with_receiving_dock'
  elsif requires_liftgate
    'commercial_building_without_receiving_dock'
  end
end

#distance_from(target_lat, target_lng) ⇒ Object



325
326
327
# File 'app/models/address.rb', line 325

def distance_from(target_lat, target_lng)
  Geocoder::Calculations.distance_between([lat, lng], [target_lat, target_lng])
end

#do_not_save_if_warehouseObject



766
767
768
769
770
# File 'app/models/address.rb', line 766

def do_not_save_if_warehouse
  return unless is_warehouse? && changed? && !admin_mode.to_b

  errors.add(:is_warehouse, 'Warehouse addresses cannot be modified outside of admin console.')
end

#editing_locked?Boolean

Returns:

  • (Boolean)


303
304
305
# File 'app/models/address.rb', line 303

def editing_locked?
  shipping_orders.any?(&:editing_locked?) || support_cases.any?(&:editing_locked?)
end

#external_validation_with_carrier(force = false) ⇒ Object



812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
# File 'app/models/address.rb', line 812

def external_validation_with_carrier(force = false)
  return false if errors.present? # Don't bother hitting the server if we have other errors

  self.require_carrier_validation = require_carrier_validation.to_b # Make sure we interpret all flavors to boolean
  # Not checking for address change to justify this expensive validation causes horrendous performance *any* time this address is verified - CB11/4
  self.verified_for_shipping = false if address_element_changed? || disable_address_correction_changed? || override_all_address_validation_changed?
  return true if override_all_address_validation || (!do_not_accept_legacy_verified && verified) || (disable_address_correction || (!require_carrier_validation && !force))
  return true if verified_for_shipping

  logger.info "External Validation with Carrier called for #{id}. require_carrier_validation(#{require_carrier_validation}), previous verified_for_shipping(#{verified_for_shipping})"

  matches = Address.where(street1: street1)
                   .where(street2: street2)
                   .where(city: city)
                   .where(state_code: state_code)
                   .where(zip: zip)
                   .where(country_iso3: country_iso3)
                   .where(verified_for_shipping: true)
                   .where.not(id: id).limit(1)

  if matches.present?
    logger.info 'Address External Validation with Carrier: Found matching address in system'
    self.verified_for_shipping = true
    return true
  end

  res, message, suggested_address_hashes = carrier_validation
  if res && (suggested_address_hashes&.length == 1) && ((a = suggested_address_hashes.first)[:address].to_s.length > 1) && (a[:address].to_s.length <= MAX_STREET_FIELD_LENGTH)
    # One address, auto fix
    old_address = to_s(include_recipient: false, with_country: false, address_type: true)
    a = suggested_address_hashes.first
    self.street1 = I18n.transliterate(a[:address].to_s).upcase
    self.street2 = a[:address2] || street2 # here nil means use what was entered since we don't validate apartments, suites etc
    self.street3 = a[:address3] || street3 # here nil means use what was entered since we don't validate apartments, suites etc
    self.city = I18n.transliterate(a[:city].to_s).upcase
    self.state_code = a[:state]
    self.zip = a[:zip]
    self.is_residential = a[:is_residential].present? # If null or false it will be false, otherwise true
    self.verified_for_shipping = true
    # self.disable_address_correction = true
    unless changed?
      self.autocorrect_message = "Address was AUTOCORRECTED, FROM: #{old_address}, TO: #{to_s(include_recipient: false, with_country: false,
                                                                                              address_type: true)}."
    end
  elsif suggested_address_hashes&.length&.> 1
    self.suggested_addresses = suggested_address_hashes.map do |a|
      # This will do two things, first remove the address validation attributes that are not understood by address and convert all symbols to strings for merging into the attributes
      new_addr_attr = {}
      new_addr_attr['street1'] = I18n.transliterate(a[:address].to_s).upcase
      new_addr_attr['street2'] = a[:address2] || street2 # here nil means use what was entered since we don't validate apartments, suites etc
      new_addr_attr['street3'] = a[:address3] || street3 # here nil means use what was entered since we don't validate apartments, suites etc
      new_addr_attr['city'] = I18n.transliterate(a[:city].to_s).upcase
      new_addr_attr['state_code'] = a[:state]
      new_addr_attr['zip'] = a[:zip]
      new_addr_attr['is_residential'] = a[:is_residential].present?
      new_addr = dup
      new_addr.attributes = new_addr.attributes.merge(new_addr_attr)
      new_addr.id = id # Because if this is used it will replace it, the dup/cloning doesn't copy this attribute.
      new_addr.verified_for_shipping = true # No need to double validate this address if it gets selected
      # new_addr.disable_address_correction = true
      new_addr.check_for_duplicates = true # will need to verify this is not a duplicate
      new_addr
    end
  end
  self.verified_for_shipping = res
  unless res
    errors.add(:base,
               "We could not validate your address. Please check that your address is correct. If you want to skip validation, please check the 'Disable Address Correction' checkbox when editing the address. #{message}")
  end
  res
end

#first_duplicateObject



1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
# File 'app/models/address.rb', line 1037

def first_duplicate
  dupe_id = nil
  if party_id
    Address.where(party_id: party_id).where.not(id: id.to_i).find_each do |a|
      logger.info "Address - Comparing #{id} with address id #{a.id}"
      if a == self
        dupe_id = a.id
        break
      end
    end
  end
  dupe_id
end

#format_for_bread_billingObject



538
539
540
541
542
543
544
545
546
547
548
549
# File 'app/models/address.rb', line 538

def format_for_bread_billing
  names = (person_name || company_name).split
  { fullName: person_name || company_name,
    firstName: names.first,
    lastName: names.last,
    address: street1,
    address2: street2,
    city: city,
    state: state_code,
    zip: zip,
    email: party&.email }
end

#format_for_bread_shippingObject



526
527
528
529
530
531
532
533
534
535
536
# File 'app/models/address.rb', line 526

def format_for_bread_shipping
  names = (person_name || company_name).split
  { fullName: person_name || company_name,
    firstName: names.first,
    lastName: names.last,
    address: street1,
    address2: street2,
    city: city,
    state: state_code,
    zip: zip }
end

#format_for_forte(use_iso = false) ⇒ Object



493
494
495
496
497
498
499
500
501
502
503
504
505
506
# File 'app/models/address.rb', line 493

def format_for_forte(use_iso = false)
  names = (person_name || company_name).split
  { name: person_name || company_name,
    first_name: names.first,
    last_name: names.last,
    company_name: company_name || person_name,
    address1: street1,
    address2: street2,
    city: city,
    state: state_code,
    zip: zip,
    country: (use_iso ? country.iso : country.iso3),
    shipping_address_type: is_residential? ? 'residential' : 'commercial' }
end

#format_for_payment_gateway(use_iso = false) ⇒ Object



471
472
473
474
475
476
477
478
479
480
# File 'app/models/address.rb', line 471

def format_for_payment_gateway(use_iso = false)
  { name: person_name || company_name,
    address1: street1,
    address2: street2,
    city: city,
    state: state&.name || state_code,
    zip: zip,
    phone: party&.phone,
    country: (use_iso ? country.iso : country.iso3) }
end

#format_for_paypal_api_invoiceObject



517
518
519
520
521
522
523
524
# File 'app/models/address.rb', line 517

def format_for_paypal_api_invoice
  { line1: street1,
    line2: street2,
    city: city,
    state: state_code,
    postal_code: zip,
    country_code: country.iso }
end

#format_for_paypal_invoiceObject



508
509
510
511
512
513
514
515
# File 'app/models/address.rb', line 508

def format_for_paypal_invoice
  { line1: street1,
    line2: street2,
    city: city,
    state: state_code,
    postalCode: zip,
    countryCode: country.iso }
end

#format_for_paypal_payment_gateway(use_iso = false) ⇒ Object



482
483
484
485
486
487
488
489
490
491
# File 'app/models/address.rb', line 482

def format_for_paypal_payment_gateway(use_iso = false)
  { name: person_name || company_name,
    address1: street1,
    address2: street2,
    city: city,
    state: state_code,
    zip: zip,
    phone: party&.phone,
    country: (use_iso ? country.iso : country.iso3) }
end

#freight_fields_textObject

Returns a string summarizing the freight fields set on the address.
Joins freight field values like 'requires liftgate', 'limited access'
into a comma-separated string. Handles defaults like require signature.



695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
# File 'app/models/address.rb', line 695

def freight_fields_text
  freight_fields_text = nil
  freight_fields_text_arr = []
  freight_fields_text_arr << 'require signature by default' if require_signature_by_default?
  if has_freight_fields_defined?
    freight_fields_text_arr << 'has loading dock' if has_loading_dock?
    freight_fields_text_arr << 'requires inside delivery' if requires_inside_delivery?
    freight_fields_text_arr << 'requires lift-gate' if requires_liftgate?
    freight_fields_text_arr << 'is construction site' if is_construction_site?
    freight_fields_text_arr << 'limited_access' if limited_access?
    freight_fields_text_arr << 'requires appointment' if requires_appointment?
    freight_fields_text = freight_fields_text_arr.join(', ')
  end
  freight_fields_text
end

#freight_fields_validationObject



772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
# File 'app/models/address.rb', line 772

def freight_fields_validation
  return false if errors.present? # Don't bother hitting the server if we have other errors

  logger.info "freight_fields_validation called for #{id}. previous verified_for_shipping (#{verified_for_shipping})"

  # Not checking for address change to justify this expensive validation causes horrendous performance *any* time this address is verified - CB11/4
  self.verified_for_shipping = false if address_element_changed? || override_all_address_validation_changed?
  return true if override_all_address_validation
  return true if verified_for_shipping

  logger.info "freight_fields_validation called for #{id}. verified_for_shipping (#{verified_for_shipping})"

  res = true

  if is_residential && (has_loading_dock || is_trade_show)
    res = false
    errors.add(:is_residential,
               "Residential addresses generally speaking can't have loading docks. If this is *really* the case then please check the 'override all address validation' checkbox.")
  end

  if is_construction_site && requires_inside_delivery
    res = false
    errors.add(:is_construction_site,
               "Construction sites (ie unbuilt yet) generally speaking can't require inside delivery. If this is *really* the case then please check the 'override all address validation' checkbox.")
  end

  if has_loading_dock && requires_liftgate
    res = false
    errors.add(:has_loading_dock,
               "Addresses generally speaking don't usually both have loading docks and require a liftgate. If this is *really* the case then please check the 'override all address validation' checkbox.")
  end

  res
end

#full_address(include_recipient = true, sep = '.', attn_override_flag = nil, hide_country = false, hide_street_2 = false) ⇒ Object



412
413
414
415
416
417
418
419
420
421
422
423
424
425
# File 'app/models/address.rb', line 412

def full_address(include_recipient = true, sep = '.', attn_override_flag = nil, hide_country = false, hide_street_2 = false)
  addr = []
  if include_recipient
    addr << company_name.presence
    addr << (attn_override_flag || person_name.presence)
  end
  addr << street1.presence
  addr << street2.presence unless hide_street_2
  addr << street3.presence
  addr << "#{city}, #{state_code} #{zip}"
  addr << country unless country_iso3 == 'USA' || hide_country
  addr = addr.uniq.compact
  addr.join(sep)
end

#full_address_for_webObject



408
409
410
# File 'app/models/address.rb', line 408

def full_address_for_web
  full_address(false, '<br>')
end

#geocode_meObject

Geocodes the address by searching using Geocoder
and sets the latitude, longitude and normalized address
attributes on the model. Handles errors from the Geocoder gem.



750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
# File 'app/models/address.rb', line 750

def geocode_me
  results = Geocoder.search(address_for_geocoder)
  geo = results.first
  if geo
    logger.info "Geocoded address #{id} with lat:#{geo.latitude}, lng: #{geo.longitude}"
    self.lat = geo.latitude
    self.lng = geo.longitude
    na = [company_name_override.presence, person_name_override.presence, geo.formatted_address].compact.uniq.join(', ')
    self.normalized_address = na
  else
    logger.info "Geocoding failed on address #{id}, #{address_for_geocoder}"
  end
rescue StandardError => e
  @logger.error " Geocoder error from address(id=#{id}) geocode_me, #{e} skipping"
end

#has_freight_fields_defined?Boolean Also known as: is_valid_for_freight?

Returns:

  • (Boolean)


807
808
809
# File 'app/models/address.rb', line 807

def has_freight_fields_defined?
  FREIGHT_FIELDS.all? { |ff| !send(ff).nil? }
end

#has_postal_codes?Boolean

Returns:

  • (Boolean)


590
591
592
# File 'app/models/address.rb', line 590

def has_postal_codes?
  iso3166_country&.postal_code
end

#has_states_or_provinces?Boolean

Returns:

  • (Boolean)


582
583
584
# File 'app/models/address.rb', line 582

def has_states_or_provinces?
  iso3166_country.subdivisions.present?
end

#in_canada?Boolean

Returns:

  • (Boolean)


351
352
353
# File 'app/models/address.rb', line 351

def in_canada?
  country_iso3 == 'CAN'
end

#in_usa?Boolean

Returns:

  • (Boolean)


355
356
357
# File 'app/models/address.rb', line 355

def in_usa?
  country_iso3 == 'USA'
end

#inherited_company_nameObject



980
981
982
983
984
985
986
# File 'app/models/address.rb', line 980

def inherited_company_name
  return unless party
  return if party.has_guest_name?
  return party.full_name if party.is_a?(Supplier) || party.is_a?(GroupAssociation) || party&.is_organization?

  party.customer.full_name if party.customer&.is_organization?
end

#inherited_person_nameObject



960
961
962
963
964
965
966
# File 'app/models/address.rb', line 960

def inherited_person_name
  return unless party
  return if party.has_guest_name?
  return unless party.is_person?

  party.full_name
end

#is_amazon?Boolean

Returns:

  • (Boolean)


209
210
211
# File 'app/models/address.rb', line 209

def is_amazon?
  company_name_override&.match?(/amazon/i)
end

#is_for_customer?Boolean

Returns:

  • (Boolean)


569
570
571
572
# File 'app/models/address.rb', line 569

def is_for_customer?
  # handle one time shipping address party.nil? is true
  party.nil? || party.instance_of?(Customer) || party.instance_of?(Supplier)
end

#is_for_supplier?Boolean

Returns:

  • (Boolean)


574
575
576
# File 'app/models/address.rb', line 574

def is_for_supplier?
  party.instance_of?(Supplier)
end

#is_warehouse_and_disabled?Boolean

Returns:

  • (Boolean)


1055
1056
1057
1058
1059
1060
1061
1062
# File 'app/models/address.rb', line 1055

def is_warehouse_and_disabled?
  res = false
  if is_warehouse?
    res = true if WAREHOUSE_PICKUP_DISABLED_US && country_iso3 == 'USA'
    res = true if WAREHOUSE_PICKUP_DISABLED_CA && country_iso3 == 'CAN'
  end
  res
end

#is_warehouse_by_distance?Boolean

Returns:

  • (Boolean)


1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
# File 'app/models/address.rb', line 1064

def is_warehouse_by_distance?
  res = false
  if is_warehouse?
    res = true # trivial case
  else
    # find distance because there are like 86 instances of addresses that correspond to 300 Granton (aka CA warehouse)
    us_warehouse_address = Store.find(1).warehouse_address
    ca_warehouse_address = Store.find(2).warehouse_address
    distance_us = distance_from(us_warehouse_address.lat, us_warehouse_address.lng)
    distance_ca = distance_from(ca_warehouse_address.lat, ca_warehouse_address.lng)
    res = true if distance_us < 0.1 || distance_ca < 0.1
  end
  res
end

#iso3166_countryObject



380
381
382
# File 'app/models/address.rb', line 380

def iso3166_country
  ISO3166::Country.find_country_by_alpha3(country_iso3)
end

#localized_address_format_array(include_recipient: true, with_country: true, attention_name: nil, attention_prepend: nil, name: nil, locale: I18n.locale) ⇒ Object

Returns an array of address lines formatted according to the address format
for the country. Allows customizing included fields like recipient name,
street, city, etc.



605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
# File 'app/models/address.rb', line 605

def localized_address_format_array(include_recipient: true, with_country: true,
                                   attention_name: nil, attention_prepend: nil,
                                   name: nil,
                                   locale: I18n.locale)
  lang = locale.to_s.first(2).downcase
  address_format = iso3166_country&.address_format&.presence
  # Fallback to US format when iso3166 is not present
  address_format ||= "{{recipient}}\n{{street}}\n{{city}} {{region_short}} {{postalcode}}\n{{country}}"
  liquid_template = Liquid::ParseEnvironment.parse(address_format)

  recipient_names = []
  if include_recipient == :overrides
    recipient_names << company_name_override
    recipient_names << person_name_override
  elsif include_recipient
    if company_name.present?
      name = attention_name || person_name
      name = "#{attention_prepend} #{name}" if name.present? && attention_prepend.present?
      recipient_names << company_name
      recipient_names << name
    else
      name = attention_name || name || person_name
      recipient_names << name
    end
  end

  options = {}
  options[:recipient] = recipient_names.filter_map(&:presence).uniq.join("\n")
  options[:street] = [street1.presence, street2.presence, street3.presence].compact.join("\n")
  options[:city] = city
  options[:region] = region || state_code
  options[:region_short] = state_code
  options[:postalcode] = zip
  options[:country] = with_country && iso3166_country ? iso3166_country.translation(lang) : ''
  address_text = Liquid::Renderer.render(liquid_template, options, "Address(#{id})#localized_address_format_array")
  # Now split on new lines and remove empty lines
  address_text.split("\n").compact_blank
end

#locator_recordLocatorRecord



112
# File 'app/models/address.rb', line 112

has_one    :locator_record, dependent: :destroy, inverse_of: :address

#lookup_timezone(store_timezone = false) ⇒ Object

Looks up the timezone using google api. This requires lat / lng to be set
If the timezone returned is valid (sometime the api returns junk) then
the timezone object is returned. Pass true to store_timezone to record the timezone
upon lookup when missing without a callback



311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'app/models/address.rb', line 311

def lookup_timezone(store_timezone = false)
  return unless lat && lng

  tz = begin
    Timezone.lookup(lat, lng)
  rescue StandardError
    nil
  end
  return unless PartyRecordTimezone.valid_timezone?(tz)

  update_column(:timezone_name, tz.name) if timezone_name != tz.name && store_timezone
  tz
end

#mail_activitiesActiveRecord::Relation<MailActivity>

Returns:

See Also:



123
# File 'app/models/address.rb', line 123

has_many   :mail_activities, class_name: 'MailActivity'

#mailing_customerCustomer

Returns:

See Also:



111
# File 'app/models/address.rb', line 111

has_one    :mailing_customer, class_name: 'Customer', dependent: :nullify, foreign_key: :mailing_address_id, inverse_of: :mailing_address

#mailing_storeStore

Returns:

See Also:



114
# File 'app/models/address.rb', line 114

has_one    :mailing_store, class_name: 'Store', foreign_key: :mailing_address_id

#name_and_addressObject



375
376
377
378
# File 'app/models/address.rb', line 375

def name_and_address
  [party.full_name, street1, street2, city, "#{state_code} #{zip}",
   iso3166_country.common_name].compact.uniq.join(', ')
end

#north_america?Boolean

Returns:

  • (Boolean)


594
595
596
# File 'app/models/address.rb', line 594

def north_america?
  %w[USA CAN MEX].include?(country_iso3)
end

#not_a_po_box?(carrier = nil) ⇒ Boolean

Returns:

  • (Boolean)


884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
# File 'app/models/address.rb', line 884

def not_a_po_box?(carrier = nil)
  Rails.logger.debug { "not_a_po_box? carrier: #{carrier || 'nil'}" }
  carrier_is_not_postal = false
  carrier_is_not_postal = true if carrier && PO_BOX_CARRIERS.exclude?(carrier) && carrier.to_s.downcase.exclude?('post') && carrier.to_s.downcase.exclude?('usps')
  nil_carrier_and_we_do_not_support_postal_carrier = false
  nil_carrier_and_we_do_not_support_postal_carrier = true if carrier.nil? && (SUPPORTED_SHIPPING_CARRIERS[country_iso3.to_sym] || []).exclude?(postal_carrier)
  Rails.logger.debug { "not_a_po_box? carrier_is_not_postal: #{carrier_is_not_postal}" }
  Rails.logger.debug { "not_a_po_box? nil_carrier_and_we_do_not_support_postal_carrier: #{nil_carrier_and_we_do_not_support_postal_carrier}" }
  Rails.logger.debug { "not_a_po_box? po_box?: #{po_box?}" }
  if po_box? && (carrier_is_not_postal || nil_carrier_and_we_do_not_support_postal_carrier)
    errors.add(:base, "We can't ship to PO boxes unless the carrier is one of #{PO_BOX_CARRIERS.join(', ')}")
    false
  else
    true
  end
end

#ok_to_delete?Boolean

Returns:

  • (Boolean)


551
552
553
# File 'app/models/address.rb', line 551

def ok_to_delete?
  dependents.empty?
end

#one_time_onlyObject



335
336
337
# File 'app/models/address.rb', line 335

def one_time_only
  party_id.nil? && !is_warehouse
end

#partyParty

Returns:

See Also:



105
# File 'app/models/address.rb', line 105

belongs_to :party, inverse_of: :addresses, optional: true

#person_nameObject



968
969
970
# File 'app/models/address.rb', line 968

def person_name
  person_name_override.presence || inherited_person_name
end

#person_name=(value) ⇒ Object



972
973
974
975
976
977
978
# File 'app/models/address.rb', line 972

def person_name=(value)
  self.person_name_override = if value.nil? || (inherited_person_name && value.casecmp?(inherited_person_name))
                                nil
                              else
                                value
                              end
end

#po_box?Boolean

An address is defined as a PO box if all its address components matches the PO box regexp
Ex. if address 1 is 123 main st and address 2 is PO BOX 10 it is not considered a PO box
but if address 1 is PO BOX 10 and there's no other street address then it is considered a PO Box

Returns:

  • (Boolean)


904
905
906
# File 'app/models/address.rb', line 904

def po_box?
  [street1, street2, street3].filter_map(&:presence).all? { |s| s =~ PO_BOX_REGEXP }
end

#po_box_carriersObject



908
909
910
# File 'app/models/address.rb', line 908

def po_box_carriers
  PO_BOX_CARRIERS_BY_COUNTRY[country_iso3.to_sym]
end

#postal_carrierObject



912
913
914
915
# File 'app/models/address.rb', line 912

def postal_carrier
  postal_carriers = { USA: 'USPS', CAN: 'Canadapost' }
  postal_carriers[country_iso3.to_sym]
end

#postal_codePostalCode

Returns:

See Also:



108
# File 'app/models/address.rb', line 108

belongs_to :postal_code, foreign_key: :zip, primary_key: :code, optional: true

#postal_compactObject



347
348
349
# File 'app/models/address.rb', line 347

def postal_compact
  zip.to_s.scan(/\w/).join.first(6)
end

#recalc_tax_on_open_ordersObject



234
235
236
# File 'app/models/address.rb', line 234

def recalc_tax_on_open_orders
  shipping_orders.so_only.open_for_tax_update.each(&:refresh_tax_rate)
end

#recipientObject



404
405
406
# File 'app/models/address.rb', line 404

def recipient
  company_name.presence || person_name
end

#render_to(options = {}) ⇒ Object



734
735
736
# File 'app/models/address.rb', line 734

def render_to(options = {}, &)
  to_array(**options).each(&)
end

#requires_states_or_provinces?Boolean

Returns:

  • (Boolean)


578
579
580
# File 'app/models/address.rb', line 578

def requires_states_or_provinces?
  %w[USA CAN].include?(country_iso3)
end

#returned_rmasActiveRecord::Relation<Rma>

Returns:

  • (ActiveRecord::Relation<Rma>)

See Also:



125
# File 'app/models/address.rb', line 125

has_many   :returned_rmas, class_name: 'Rma', foreign_key: :return_shipping_address_id

#same_as(address) ⇒ Object



459
460
461
462
463
464
465
466
467
468
469
# File 'app/models/address.rb', line 459

def same_as(address)
  # Possible you're just giving me the same address so i'll just match on id
  if address.persisted? && persisted?
    address.id == id
  # If our address was normalized by geocoder, we will use that form to compare
  elsif address.normalized_address.present? && normalized_address.present?
    address.normalized_address == normalized_address
  else # Use native fields
    address_for_comparison == address.address_for_comparison
  end
end

#search_textObject



1051
1052
1053
# File 'app/models/address.rb', line 1051

def search_text
  to_array.join(' ')
end

#service_jobsActiveRecord::Relation<ServiceJob>

Returns:

See Also:



126
# File 'app/models/address.rb', line 126

has_many   :service_jobs, -> { order(:created_at) }, inverse_of: :address

#set_freight_field_defaultsObject



717
718
719
720
721
722
723
724
# File 'app/models/address.rb', line 717

def set_freight_field_defaults
  self.has_loading_dock ||= false
  self.requires_liftgate ||= true
  self.requires_inside_delivery ||= false
  self.is_construction_site ||= false
  self.limited_access ||= false
  self.requires_appointment ||= true
end

#shipping_account_numbersActiveRecord::Relation<ShippingAccountNumber>

Returns:

See Also:



124
# File 'app/models/address.rb', line 124

has_many   :shipping_account_numbers

#shipping_credit_memosActiveRecord::Relation<CreditMemo>

Returns:

See Also:



120
# File 'app/models/address.rb', line 120

has_many   :shipping_credit_memos, class_name: 'CreditMemo', foreign_key: :shipping_address_id

#shipping_customerCustomer

Returns:

See Also:



110
# File 'app/models/address.rb', line 110

has_one    :shipping_customer, class_name: 'Customer', dependent: :nullify, foreign_key: :shipping_address_id, inverse_of: :shipping_address

#shipping_invoicesActiveRecord::Relation<Invoice>

Returns:

  • (ActiveRecord::Relation<Invoice>)

See Also:



118
# File 'app/models/address.rb', line 118

has_many   :shipping_invoices, class_name: 'Invoice', foreign_key: :shipping_address_id

#shipping_ordersActiveRecord::Relation<Order>

Returns:

  • (ActiveRecord::Relation<Order>)

See Also:



116
# File 'app/models/address.rb', line 116

has_many   :shipping_orders, class_name: 'Order', foreign_key: :shipping_address_id

#shipping_quotesActiveRecord::Relation<Quote>

Returns:

  • (ActiveRecord::Relation<Quote>)

See Also:



121
# File 'app/models/address.rb', line 121

has_many   :shipping_quotes, class_name: 'Quote', foreign_key: :shipping_address_id

#stateState

Returns:

See Also:



107
# File 'app/models/address.rb', line 107

belongs_to :state, foreign_key: 'state_code', primary_key: 'code', optional: true

#state_codes_listObject



363
364
365
# File 'app/models/address.rb', line 363

def state_codes_list
  iso3166_country.subdivisions.keys
end

#state_present_and_has_states_or_provinces?Boolean

Returns:

  • (Boolean)


586
587
588
# File 'app/models/address.rb', line 586

def state_present_and_has_states_or_provinces?
  state_code.present? && iso3166_country && has_states_or_provinces?
end

#states_for_selectObject



359
360
361
# File 'app/models/address.rb', line 359

def states_for_select
  State.states_for_select(countries_iso: country_iso3)
end

#support_casesActiveRecord::Relation<SupportCase>

Returns:

See Also:



122
# File 'app/models/address.rb', line 122

has_many   :support_cases, class_name: 'SupportCase', foreign_key: :service_address_id

#temporary?Boolean

Returns:

  • (Boolean)


276
277
278
# File 'app/models/address.rb', line 276

def temporary?
  street1 == 'Unknown'
end

#text_block(with_recipient = false, with_country = false, phone = nil) ⇒ Object



726
727
728
729
730
731
732
# File 'app/models/address.rb', line 726

def text_block(with_recipient = false, with_country = false, phone = nil)
  options = {}
  options[:include_recipient] = with_recipient
  options[:with_country] = with_country
  options[:phone] = phone
  to_array(options).join("\n")
end

#timezoneObject

Returns a timezone object or look it up and store



285
286
287
288
289
290
291
292
# File 'app/models/address.rb', line 285

def timezone
  tz = begin
    ActiveSupport::TimeZone.find_tzinfo(timezone_name)
  rescue TZInfo::InvalidTimezoneIdentifier
    ErrorReporting.warning("Invalid timezone #{timezone_name} for address id #{id}")
  end
  tz || lookup_timezone(:store)
end

#timezones_for_selectObject



280
281
282
# File 'app/models/address.rb', line 280

def timezones_for_select
  iso3166_country.timezones.zone_identifiers
end

#to_array(include_recipient: true, with_country: true, attention_name: nil, attention_prepend: nil, name: nil, upcase: false, phone: nil, email: nil, address_type: false, extra_data: nil, locale: I18n.locale) ⇒ Object

Returns an array of address lines formatted according to the options passed in.

Allows customizing included fields like recipient name, street, city, etc.
Also includes phone, email, address type, and extra data if specified.
Can upcase the fields.

locale - The locale to use for translations (default: I18n.locale)
include_recipient - Whether to include the recipient name
with_country - Whether to include the country
attention_name - Custom attention name to use
attention_prepend - String to prepend to attention name
name - Custom recipient name to use
upcase - Whether to upcase the fields
phone - Phone number to include
email - Email to include
address_type - Whether to include the address type
extra_data - Extra data to append

Returns an array of address lines, based on the country formatting rules.



663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
# File 'app/models/address.rb', line 663

def to_array(include_recipient: true,
             with_country: true,
             attention_name: nil,
             attention_prepend: nil,
             name: nil,
             upcase: false,
             phone: nil,
             email: nil,
             address_type: false,
             extra_data: nil,
             locale: I18n.locale)
  a = localized_address_format_array(include_recipient:,
                                     with_country:,
                                     attention_name:,
                                     attention_prepend:,
                                     name:,
                                     locale:)
  a << "Phone: #{phone}" if phone.present?
  a << "E-mail: #{email}" if email.present?
  if address_type
    a << (is_residential? ? "(Residential #{freight_fields_text})" : "(Commercial #{freight_fields_text})")
    a << "Freight Ready?: #{is_valid_for_freight? ? '✔ Yes' : 'X No'}"
  end
  a << extra_data
  res = a.map(&:to_s).map(&:squish).map(&:presence).uniq.compact
  res = res.map(&:upcase) if upcase.to_b
  res.uniq
end

#to_s(params = {}) ⇒ Object



598
599
600
# File 'app/models/address.rb', line 598

def to_s(params = {})
  to_array(**params).join(', ')
end


1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
# File 'app/models/address.rb', line 1008

def unlink
  party_id
  return unless party

  Address.transaction do
    party.update_attribute!(:shipping_address_id, nil) if self == party.shipping_address
    party.update_attribute!(:mailing_address_id, nil) if self == party.mailing_address
    raise 'Cannot remove address from customer as it is used as the main billing address.' if self == party.billing_address

    update_attribute(:party_id, nil)
  end
end

#update_party_timezoneObject



238
239
240
241
242
# File 'app/models/address.rb', line 238

def update_party_timezone
  return unless party && saved_change_to_timezone_name?

  PartyRecordTimezone.new.process_party_and_associations(party)
end

#via_jsonObject



1021
1022
1023
# File 'app/models/address.rb', line 1021

def via_json
  to_json
end

#via_json=(x) ⇒ Object



1025
1026
1027
# File 'app/models/address.rb', line 1025

def via_json=(x)
  from_json x
end

#via_xmlObject



1029
1030
1031
# File 'app/models/address.rb', line 1029

def via_xml
  to_xml
end

#via_xml=(x) ⇒ Object



1033
1034
1035
# File 'app/models/address.rb', line 1033

def via_xml=(x)
  from_xml x
end

#warehouse_storeStore

Returns:

See Also:



113
# File 'app/models/address.rb', line 113

has_one    :warehouse_store, class_name: 'Store', foreign_key: :warehouse_address_id

#zip_5Object



339
340
341
# File 'app/models/address.rb', line 339

def zip_5
  zip.to_s.first(5)
end

#zip_compactObject



343
344
345
# File 'app/models/address.rb', line 343

def zip_compact
  in_usa? ? zip_5 : postal_compact
end