Files
openfoodnetwork/lib/open_food_network/address_finder.rb
2019-11-10 18:42:43 +00:00

104 lines
2.7 KiB
Ruby

# Finds an address based on the data provided
# Can take any combination of an email String, Customer or Spree::User as args
# The #bill_address and #ship_address methods automatically return matched addresses
# according to this order: customer addresses, user addresses, addresses from
# completed orders with an email that matches the email string provided.
module OpenFoodNetwork
class AddressFinder
attr_reader :email, :user, :customer
def initialize(*args)
args.each do |arg|
type = types[arg.class]
next unless type
public_send("#{type}=", arg)
end
end
def bill_address
customer_preferred_bill_address || user_preferred_bill_address || fallback_bill_address
end
def ship_address
customer_preferred_ship_address || user_preferred_ship_address || fallback_ship_address
end
def email=(arg)
@email ||= arg
end
def customer=(arg)
@customer ||= arg
end
def user=(arg)
@user ||= arg
end
private
def types
{
String => "email",
Customer => "customer",
Spree::User => "user"
}
end
def customer_preferred_bill_address
customer.andand.bill_address
end
def customer_preferred_ship_address
customer.andand.ship_address
end
def user_preferred_bill_address
user.andand.bill_address
end
def user_preferred_ship_address
user.andand.ship_address
end
def fallback_bill_address
last_used_bill_address.andand.clone || Spree::Address.default
end
def fallback_ship_address
last_used_ship_address.andand.clone || Spree::Address.default
end
def last_used_bill_address
return nil unless allow_search_by_email?
Spree::Order.joins(:bill_address).order('id DESC')
.complete.where(email: email)
.first.andand.bill_address
end
def last_used_ship_address
return nil unless allow_search_by_email?
Spree::Order.complete.joins(:ship_address, shipments: :shipping_methods).order('id DESC')
.where(email: email, spree_shipping_methods: { require_ship_address: true })
.first.andand.ship_address
end
# Only allow search for address by email if a customer or user with the
# same address has been provided, otherwise we are providing access to
# addresses with only an email address, which could be problematic.
# Assumption: front-end users can't ask this library for an address using
# a customer or user other than themselves...
def allow_search_by_email?
email.present? && email_matches_customer_or_user?
end
def email_matches_customer_or_user?
email == customer.andand.email || email == user.andand.email
end
end
end