Files
openfoodnetwork/app/models/spree/address.rb
Maikel Linke 8ef6966891 Declare old belongs_to default on remaining models
It would take ages to go through all files now and assess all belongs_to
associations. So I just declare the old default and then we can move on
and apply the new default for the application while these classes still
use the old one. All new models will then use the new default which is
the goal of this excercise and we can refactor old classes when we touch
them anyway.
2023-08-11 10:14:43 +10:00

166 lines
4.2 KiB
Ruby

# frozen_string_literal: true
module Spree
class Address < ApplicationRecord
include AddressDisplay
self.belongs_to_required_by_default = false
searchable_attributes :firstname, :lastname, :phone, :full_name
searchable_associations :country, :state
belongs_to :country, class_name: "Spree::Country"
belongs_to :state, class_name: "Spree::State"
has_one :enterprise, dependent: :restrict_with_exception
has_many :shipments
validates :address1, :city, :country, :phone, presence: true
validates :company, presence: true, unless: -> { first_name.blank? || last_name.blank? }
validates :firstname, :lastname, presence: true, if: -> do
company.blank? || company == 'unused'
end
validates :zipcode, presence: true, if: :require_zipcode?
validate :state_validate
after_save :touch_enterprise
alias_attribute :first_name, :firstname
alias_attribute :last_name, :lastname
delegate :name, to: :state, prefix: true, allow_nil: true
ransacker :full_name, formatter: proc { |value| value.to_s } do |parent|
Arel::Nodes::SqlLiteral.new(
"CONCAT(#{parent.table_name}.firstname, ' ', #{parent.table_name}.lastname)"
)
end
def self.default
new(country: DefaultCountry.country)
end
def full_name
"#{firstname} #{lastname}".strip
end
def state_text
state.try(:abbr) || state.try(:name) || state_name
end
def same_as?(other)
return false if other.nil?
attributes.except('id', 'updated_at', 'created_at') ==
other.attributes.except('id', 'updated_at', 'created_at')
end
alias same_as same_as?
def to_s
"#{full_name}: #{address1}"
end
def clone
self.class.new(attributes.except('id', 'updated_at', 'created_at'))
end
def ==(other)
self_attrs = attributes
other_attrs = other.respond_to?(:attributes) ? other.attributes : {}
[self_attrs, other_attrs].each { |attrs|
attrs.except!('id', 'created_at', 'updated_at', 'order_id')
}
self_attrs == other_attrs
end
def empty?
attributes.except('id', 'created_at', 'updated_at', 'order_id', 'country_id').all? { |_, v|
v.nil?
}
end
# Generates an ActiveMerchant compatible address hash
def active_merchant_hash
{
name: full_name,
address1: address1,
address2: address2,
city: city,
state: state_text,
zip: zipcode,
country: country.try(:iso),
phone: phone
}
end
def full_address
render_address([address1, address2, city, zipcode, state&.name])
end
def address_part1
render_address([address1, address2])
end
def address_part2
render_address([city, zipcode, state&.name])
end
def address_and_city
[address1, address2, city].select(&:present?).join(' ')
end
private
def require_zipcode?
true
end
def state_validate
# Skip state validation without country (also required)
# or when disabled by preference
return if country.blank? || !Spree::Config[:address_requires_state]
return unless country.states_required
# Ensure associated state belongs to country
if state.present?
if state.country == country
self.state_name = nil # not required as we have a valid state and country combo
elsif state_name.present?
self.state = nil
else
errors.add(:state, :invalid)
end
end
# Ensure state_name belongs to country without states,
# or that it matches a predefined state name/abbr
if state_name.present? && country.states.present?
states = country.states.find_all_by_name_or_abbr(state_name)
if states.size == 1
self.state = states.first
self.state_name = nil
else
errors.add(:state, :invalid)
end
end
# ensure at least one state field is populated
errors.add :state, :blank if state.blank? && state_name.blank?
end
def touch_enterprise
return unless enterprise&.persisted?
enterprise.touch
end
def render_address(parts)
parts.select(&:present?).join(', ')
end
end
end