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(Wed, 28 Mar 2012 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 =
/[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 =
35
ADDRESS_FIELDS_FOR_GEOCODING =
%w[street1 street2 street3 city state_code country_iso3 zip].freeze
ADDRESS_FIELDS_TO_RECALCULATE_SHIPPING_FOR =
(ADDRESS_FIELDS_FOR_GEOCODING + %w[is_residential require_signature_by_default]).freeze
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

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 Models::EventPublishable

#publish_event

Instance Attribute Details

#admin_modeObject

Returns the value of attribute admin_mode.



93
94
95
# File 'app/models/address.rb', line 93

def admin_mode
  @admin_mode
end

#autocorrect_messageObject

Returns the value of attribute autocorrect_message.



93
94
95
# File 'app/models/address.rb', line 93

def autocorrect_message
  @autocorrect_message
end

#check_for_duplicatesObject

Returns the value of attribute check_for_duplicates.



93
94
95
# File 'app/models/address.rb', line 93

def check_for_duplicates
  @check_for_duplicates
end

#cityObject (readonly)



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

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

#country_iso3Object (readonly)



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

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

#do_not_accept_legacy_verifiedObject

Returns the value of attribute do_not_accept_legacy_verified.



93
94
95
# File 'app/models/address.rb', line 93

def do_not_accept_legacy_verified
  @do_not_accept_legacy_verified
end

#require_carrier_validationObject

Returns the value of attribute require_carrier_validation.



93
94
95
# File 'app/models/address.rb', line 93

def require_carrier_validation
  @require_carrier_validation
end

#set_default_billing_addressObject

Returns the value of attribute set_default_billing_address.



93
94
95
# File 'app/models/address.rb', line 93

def set_default_billing_address
  @set_default_billing_address
end

#set_default_mailing_addressObject

Returns the value of attribute set_default_mailing_address.



93
94
95
# File 'app/models/address.rb', line 93

def set_default_mailing_address
  @set_default_mailing_address
end

#set_default_shipping_addressObject

Returns the value of attribute set_default_shipping_address.



93
94
95
# File 'app/models/address.rb', line 93

def set_default_shipping_address
  @set_default_shipping_address
end

#skip_carrier_validationObject

Returns the value of attribute skip_carrier_validation.



93
94
95
# File 'app/models/address.rb', line 93

def skip_carrier_validation
  @skip_carrier_validation
end

#state_codeObject (readonly)



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

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

#street1Object (readonly)



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

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

#street2Object (readonly)



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

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)



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

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.



93
94
95
# File 'app/models/address.rb', line 93

def suggested_addresses
  @suggested_addresses
end

#validate_with_carrierObject

Returns the value of attribute validate_with_carrier.



93
94
95
# File 'app/models/address.rb', line 93

def validate_with_carrier
  @validate_with_carrier
end

Class Method Details

.address_type_optionsObject



210
211
212
213
214
215
# File 'app/models/address.rb', line 210

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:



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

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

.clear_geocoder_cacheObject



193
194
195
196
# File 'app/models/address.rb', line 193

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



735
736
737
738
739
740
741
742
# File 'app/models/address.rb', line 735

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:



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

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:



158
159
160
161
162
163
164
165
166
# File 'app/models/address.rb', line 158

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



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

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.



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

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, 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:



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

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:



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

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

Instance Method Details

#==(other) ⇒ Object



326
327
328
329
330
# File 'app/models/address.rb', line 326

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

  same_as(other)
end

#address_dropdown_formatObject



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

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)


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

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)


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

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

#address_for_comparisonObject



451
452
453
454
# File 'app/models/address.rb', line 451

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



445
446
447
448
449
# File 'app/models/address.rb', line 445

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

#archiveable?Boolean

Returns:

  • (Boolean)


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

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

#belongs_to?(customer) ⇒ Boolean

INSTANCE METHODS

Returns:

  • (Boolean)


255
256
257
258
# File 'app/models/address.rb', line 255

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

#billing_credit_memosActiveRecord::Relation<CreditMemo>

Returns:

See Also:



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

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

#billing_customerCustomer

Returns:

See Also:



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

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:



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

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

#billing_ordersActiveRecord::Relation<Order>

Returns:

  • (ActiveRecord::Relation<Order>)

See Also:



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

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

#buying_groupBuyingGroup



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

belongs_to :buying_group, optional: true

#carrier_validation(autosave = false) ⇒ Object



916
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
# File 'app/models/address.rb', line 916

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



241
242
243
244
245
246
247
248
249
250
251
252
# File 'app/models/address.rb', line 241

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



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

def company_name
  company_name_override.presence || inherited_company_name
end

#company_name=(value) ⇒ Object



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

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

#correct_zipObject



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

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

#countryCountry

Returns:

See Also:



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

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

#country_isoObject



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

def country_iso
  iso3166_country&.alpha2
end

#country_iso=(val) ⇒ Object

Accessors when iso 2 character form is used



292
293
294
# File 'app/models/address.rb', line 292

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



709
710
711
712
# File 'app/models/address.rb', line 709

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

#credit_lineObject



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

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

#data_hashObject



260
261
262
263
264
265
266
267
268
269
270
271
# File 'app/models/address.rb', line 260

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



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

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

#default_billing=(new_value) ⇒ Object



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

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

#default_mailingObject



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

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

#default_mailing=(new_value) ⇒ Object



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

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

#default_shippingObject



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

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

#default_shipping=(new_value) ⇒ Object



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

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

#dependentsObject



552
553
554
555
556
557
558
559
560
561
562
563
564
# File 'app/models/address.rb', line 552

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


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

def destroy_or_unlink
  if ok_to_delete?
    destroy
  else
    unlink
  end
end

#determine_address_typeObject



217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'app/models/address.rb', line 217

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



322
323
324
# File 'app/models/address.rb', line 322

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

#do_not_save_if_warehouseObject



763
764
765
766
767
# File 'app/models/address.rb', line 763

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)


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

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

#external_validation_with_carrier(force = false) ⇒ Object



809
810
811
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
# File 'app/models/address.rb', line 809

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 && (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



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

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



535
536
537
538
539
540
541
542
543
544
545
546
# File 'app/models/address.rb', line 535

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



523
524
525
526
527
528
529
530
531
532
533
# File 'app/models/address.rb', line 523

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



490
491
492
493
494
495
496
497
498
499
500
501
502
503
# File 'app/models/address.rb', line 490

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



468
469
470
471
472
473
474
475
476
477
# File 'app/models/address.rb', line 468

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



514
515
516
517
518
519
520
521
# File 'app/models/address.rb', line 514

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



505
506
507
508
509
510
511
512
# File 'app/models/address.rb', line 505

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



479
480
481
482
483
484
485
486
487
488
# File 'app/models/address.rb', line 479

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.



692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
# File 'app/models/address.rb', line 692

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



769
770
771
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
# File 'app/models/address.rb', line 769

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



409
410
411
412
413
414
415
416
417
418
419
420
421
422
# File 'app/models/address.rb', line 409

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



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

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.



747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
# File 'app/models/address.rb', line 747

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)


804
805
806
# File 'app/models/address.rb', line 804

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

#has_postal_codes?Boolean

Returns:

  • (Boolean)


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

def has_postal_codes?
  iso3166_country&.postal_code
end

#has_states_or_provinces?Boolean

Returns:

  • (Boolean)


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

def has_states_or_provinces?
  iso3166_country.subdivisions.present?
end

#in_canada?Boolean

Returns:

  • (Boolean)


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

def in_canada?
  country_iso3 == 'CAN'
end

#in_usa?Boolean

Returns:

  • (Boolean)


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

def in_usa?
  country_iso3 == 'USA'
end

#inherited_company_nameObject



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

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



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

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)


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

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

#is_for_customer?Boolean

Returns:

  • (Boolean)


566
567
568
569
# File 'app/models/address.rb', line 566

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)


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

def is_for_supplier?
  party.instance_of?(Supplier)
end

#is_warehouse_and_disabled?Boolean

Returns:

  • (Boolean)


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

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)


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

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



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

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.



602
603
604
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
# File 'app/models/address.rb', line 602

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.map(&:presence).compact.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").reject(&:blank?)
end

#locator_recordLocatorRecord



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

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



308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'app/models/address.rb', line 308

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

  tz = begin
    Timezone.lookup(lat, lng)
  rescue StandardError
    nil
  end
  return unless Party::RecordTimezone.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:



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

has_many   :mail_activities, class_name: 'MailActivity'

#mailing_customerCustomer

Returns:

See Also:



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

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

#mailing_storeStore

Returns:

See Also:



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

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

#name_and_addressObject



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

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)


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

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

#not_a_po_box?(carrier = nil) ⇒ Boolean

Returns:

  • (Boolean)


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

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.include?(carrier) && !carrier.to_s.downcase.include?('post') && !carrier.to_s.downcase.include?('usps')
  nil_carrier_and_we_do_not_support_postal_carrier = false
  if carrier.nil? && !(SUPPORTED_SHIPPING_CARRIERS[country_iso3.to_sym] || []).include?(postal_carrier)
    nil_carrier_and_we_do_not_support_postal_carrier = true
  end # allow for nil carrier if we have Canada Post or USPS as supported 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)


548
549
550
# File 'app/models/address.rb', line 548

def ok_to_delete?
  dependents.empty?
end

#one_time_onlyObject



332
333
334
# File 'app/models/address.rb', line 332

def one_time_only
  party_id.nil? && !is_warehouse
end

#partyParty

Returns:

See Also:



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

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

#person_nameObject



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

def person_name
  person_name_override.presence || inherited_person_name
end

#person_name=(value) ⇒ Object



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

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)


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

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

#po_box_carriersObject



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

def po_box_carriers
  PO_BOX_CARRIERS_BY_COUNTRY[country_iso3.to_sym]
end

#postal_carrierObject



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

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

#postal_codePostalCode

Returns:

See Also:



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

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

#postal_compactObject



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

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

#recalc_tax_on_open_ordersObject



231
232
233
# File 'app/models/address.rb', line 231

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

#recipientObject



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

def recipient
  company_name.presence || person_name
end

#render_to(options = {}) ⇒ Object



731
732
733
# File 'app/models/address.rb', line 731

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

#requires_states_or_provinces?Boolean

Returns:

  • (Boolean)


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

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

#returned_rmasActiveRecord::Relation<Rma>

Returns:

  • (ActiveRecord::Relation<Rma>)

See Also:



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

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

#same_as(address) ⇒ Object



456
457
458
459
460
461
462
463
464
465
466
# File 'app/models/address.rb', line 456

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



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

def search_text
  to_array.join(' ')
end

#service_jobsActiveRecord::Relation<ServiceJob>

Returns:

See Also:



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

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

#set_freight_field_defaultsObject



714
715
716
717
718
719
720
721
# File 'app/models/address.rb', line 714

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:



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

has_many   :shipping_account_numbers

#shipping_credit_memosActiveRecord::Relation<CreditMemo>

Returns:

See Also:



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

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

#shipping_customerCustomer

Returns:

See Also:



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

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:



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

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

#shipping_ordersActiveRecord::Relation<Order>

Returns:

  • (ActiveRecord::Relation<Order>)

See Also:



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

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

#shipping_quotesActiveRecord::Relation<Quote>

Returns:

  • (ActiveRecord::Relation<Quote>)

See Also:



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

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

#stateState

Returns:

See Also:



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

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

#state_codes_listObject



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

def state_codes_list
  iso3166_country.subdivisions.keys
end

#state_present_and_has_states_or_provinces?Boolean

Returns:

  • (Boolean)


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

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

#states_for_selectObject



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

def states_for_select
  State.states_for_select(countries_iso: country_iso3)
end

#support_casesActiveRecord::Relation<SupportCase>

Returns:

See Also:



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

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

#temporary?Boolean

Returns:

  • (Boolean)


273
274
275
# File 'app/models/address.rb', line 273

def temporary?
  street1 == 'Unknown'
end

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



723
724
725
726
727
728
729
# File 'app/models/address.rb', line 723

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



282
283
284
285
286
287
288
289
# File 'app/models/address.rb', line 282

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



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

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.



660
661
662
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
# File 'app/models/address.rb', line 660

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



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

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


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

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



235
236
237
238
239
# File 'app/models/address.rb', line 235

def update_party_timezone
  return unless party && saved_change_to_timezone_name?

  Party::RecordTimezone.new.process_party_and_associations(party)
end

#via_jsonObject



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

def via_json
  to_json
end

#via_json=(x) ⇒ Object



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

def via_json=(x)
  from_json x
end

#via_xmlObject



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

def via_xml
  to_xml
end

#via_xml=(x) ⇒ Object



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

def via_xml=(x)
  from_xml x
end

#warehouse_storeStore

Returns:

See Also:



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

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

#zip_5Object



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

def zip_5
  zip.to_s.first(5)
end

#zip_compactObject



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

def zip_compact
  in_usa? ? zip_5 : postal_compact
end