Files
openfoodnetwork/app/models/spree/user.rb

203 lines
6.3 KiB
Ruby

# frozen_string_literal: true
module Spree
class User < ApplicationRecord
include SetUnusedAddressFields
self.belongs_to_required_by_default = false
searchable_attributes :email
devise :database_authenticatable, :token_authenticatable, :registerable, :recoverable,
:rememberable, :trackable, :validatable, :omniauthable,
:encryptable, :confirmable,
encryptor: 'authlogic_sha512', reconfirmable: true,
omniauth_providers: [:openid_connect]
has_many :orders, dependent: nil
belongs_to :ship_address, class_name: 'Spree::Address'
belongs_to :bill_address, class_name: 'Spree::Address'
before_validation :set_login
after_create :associate_customers, :associate_orders
before_destroy :check_completed_orders
scope :admin, -> { where(admin: true) }
has_many :enterprise_roles, dependent: :destroy
has_many :enterprises, through: :enterprise_roles
has_many :owned_enterprises, class_name: 'Enterprise',
foreign_key: :owner_id, inverse_of: :owner,
dependent: :restrict_with_exception
has_many :owned_groups, class_name: 'EnterpriseGroup',
foreign_key: :owner_id, inverse_of: :owner,
dependent: :restrict_with_exception
has_many :customers, dependent: :destroy
has_many :credit_cards, dependent: :destroy
has_many :report_rendering_options, class_name: "::ReportRenderingOptions", dependent: :destroy
has_many :webhook_endpoints, dependent: :destroy
has_many :column_preferences, dependent: :destroy
has_one :oidc_account, dependent: :destroy
accepts_nested_attributes_for :enterprise_roles, allow_destroy: true
accepts_nested_attributes_for :webhook_endpoints
accepts_nested_attributes_for :bill_address
accepts_nested_attributes_for :ship_address
validates :email, 'valid_email_2/email': { mx: true }, if: :email_changed?
validate :limit_owned_enterprises
class DestroyWithOrdersError < StandardError; end
def self.admin_created?
User.admin.count > 0
end
# Send devise-based user emails asyncronously via ActiveJob
# See: https://github.com/heartcombo/devise/tree/v3.5.10#activejob-integration
def send_devise_notification(notification, *)
devise_mailer.public_send(notification, self, *).deliver_later
end
def regenerate_reset_password_token
set_reset_password_token
end
def generate_api_key
self.spree_api_key = SecureRandom.hex(24)
end
def known_users
if admin?
Spree::User.where(nil)
else
Spree::User
.includes(:enterprises)
.references(:enterprises)
.where("enterprises.id IN (SELECT enterprise_id FROM enterprise_roles WHERE user_id = ?)",
id)
end
end
def build_enterprise_roles
Enterprise.find_each do |enterprise|
unless enterprise_roles.find_by enterprise_id: enterprise.id
enterprise_roles.build(enterprise:)
end
end
end
def customer_of(enterprise)
return nil unless enterprise
customers.find_by(enterprise_id: enterprise)
end
# This is a Devise Confirmable callback that runs on email confirmation
# It sends a welcome email after the user email is confirmed
def after_confirmation
return unless confirmed? && unconfirmed_email.nil? && !unconfirmed_email_changed?
send_signup_confirmation
end
def send_signup_confirmation
Spree::UserMailer.signup_confirmation(self).deliver_later
end
def associate_customers
self.customers = Customer.where(email:)
end
def associate_orders
Spree::Order.where(customer: customers).find_each do |order|
order.associate_user!(self)
end
end
def can_own_more_enterprises?
owned_enterprises.reload.size < enterprise_limit
end
def default_card
# Don't re-fetch associated cards from the DB if they're already eager-loaded
if credit_cards.loaded?
credit_cards.to_a.find(&:is_default)
else
credit_cards.where(is_default: true).first
end
end
def last_incomplete_spree_order
orders.incomplete.where(created_by_id: id).order('created_at DESC').first
end
def disabled
disabled_at.present?
end
def disabled=(value)
self.disabled_at = value == '1' ? Time.zone.now : nil
end
def affiliate_enterprises
return [] unless Flipper.enabled?(:affiliate_sales_data, self)
Enterprise.joins(:connected_apps).merge(ConnectedApps::AffiliateSalesData.ready)
end
# Users can manage orders if they have a sells own/any enterprise. or is admin
def can_manage_orders?
@can_manage_orders ||= (enterprises.pluck(:sells).intersect?(%w(own any)) or admin?)
end
# Users can manage line items in orders if they have producer enterprise and
# any of order distributors allow them to edit their orders.
def can_manage_line_items_in_orders?
return @can_manage_line_items_in_orders if defined? @can_manage_line_items_in_orders
@can_manage_line_items_in_orders =
enterprises.any?(&:is_producer_only) &&
Spree::Order.editable_by_producers(enterprises).exists?
end
def can_manage_line_items_in_orders_only?
!can_manage_orders? && can_manage_line_items_in_orders?
end
protected
def password_required?
!persisted? || password.present? || password_confirmation.present?
end
private
def check_completed_orders
raise DestroyWithOrdersError if orders.complete.present?
end
def set_login
# for now force login to be same as email, eventually we will make this configurable, etc.
self.login ||= email if email
end
def limit_owned_enterprises
return unless owned_enterprises.size > enterprise_limit
errors.add(:owned_enterprises, I18n.t(:spree_user_enterprise_limit_error,
email:,
enterprise_limit:))
end
def remove_payments_in_checkout(enterprises)
enterprises.each do |enterprise|
enterprise.distributed_orders.each do |order|
order.payments.keep_if { |payment| payment.state != "checkout" }
end
end
end
end
end