mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-24 01:13:21 +00:00
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.
166 lines
4.2 KiB
Ruby
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
|