codeforamerica/clientcomm-rails

View on GitHub
app/models/reporting_relationship.rb

Summary

Maintainability
A
1 hr
Test Coverage
class ReportingRelationship < ApplicationRecord
  CATEGORIES = APP_CONFIG['client_categories']

  belongs_to :user
  belongs_to :client
  belongs_to :client_status
  has_one :department, through: :user
  has_many :messages, dependent: :nullify

  scope :active, -> { where(active: true) }

  scope :full_name_contains, ->(str) { joins(:client).where("clients.first_name || ' ' || clients.last_name ILIKE CONCAT('%', ?, '%')", str) }

  validates :client, uniqueness: { scope: :user }
  validates :client, :user, presence: true
  validates :active, inclusion: { in: [true, false] }

  validates :category, inclusion: { in: CATEGORIES.keys }

  validate :unique_within_department

  attr_reader :matching_record

  def self.ransackable_scopes(_auth_object = nil)
    [:full_name_contains]
  end

  def self.categories_linked_list
    links = {}
    last_cat, last_info = CATEGORIES.first
    CATEGORIES.to_a.reverse.each do |name, info|
      links[name] = last_info.merge(name: last_cat)
      last_cat = name
      last_info = info
    end
    links
  end

  def category_info
    CATEGORIES[category]
  end

  def analytics_tracker_data
    {
      has_unread_messages: has_unread_messages,
      hours_since_contact: hours_since_contact,
      messages_all_count: messages.messages.count,
      messages_received_count: messages.messages.inbound.count,
      messages_sent_count: messages.outbound.count - messages.outbound.scheduled.count,
      messages_attachments_count: attachments.count,
      messages_scheduled_count: messages.scheduled.count,
      has_client_notes: notes.present?
    }
  end

  def transfer_to(new_reporting_relationship)
    # Requires that current RR is active and transfer_user is in same dept.
    # If not it will behave improperly and have more than one active
    new_reporting_relationship.active = true
    self.active = false
    self.has_unread_messages = false
    user.set_has_unread_messages

    ActiveRecord::Base.transaction do
      save!
      new_reporting_relationship.save!
    end

    messages.scheduled.update(reporting_relationship: new_reporting_relationship)
    messages.messages.unread.update(read: true)
    if user == new_reporting_relationship.user.department.unclaimed_user
      messages.update(reporting_relationship: new_reporting_relationship)
    end
    new_reporting_relationship.client_status = client_status
    new_reporting_relationship.save!
    Message.create_transfer_markers(receiving_rr: new_reporting_relationship, sending_rr: self)
  end

  def merge_with(rr_from, copy_name = false)
    ActiveRecord::Base.transaction do
      to_full_name = client.full_name
      from_full_name = rr_from.client.full_name

      if copy_name
        client.update!(first_name: rr_from.client.first_name, last_name: rr_from.client.last_name)
        NotificationSender.notify_users_of_changes(user: user, client: client)
      end

      Message.create_conversation_ends_marker(
        reporting_relationship: rr_from,
        full_name: from_full_name,
        phone_number: rr_from.client.display_phone_number
      )

      rr_from.messages.each do |message|
        message.like_message&.update!(reporting_relationship: self)
        message.update!(reporting_relationship: self)
      end

      copy_relationship_details(rr_from)

      update!(has_unread_messages: rr_from.has_unread_messages) if rr_from.has_unread_messages

      Message.create_merged_with_marker(
        reporting_relationship: self,
        from_full_name: from_full_name,
        to_full_name: to_full_name,
        from_phone_number: rr_from.client.display_phone_number,
        to_phone_number: client.display_phone_number
      )

      rr_from.update!(active: false)
    end
  end

  def display_name
    client.full_name
  end

  def timestamp
    (last_contacted_at || created_at).to_time.to_i
  end

  def deactivate
    update!(active: false)
    messages.scheduled.destroy_all
    mark_messages_read(update_user: true)
  end

  def mark_messages_read(update_user: false)
    update!(has_unread_messages: false)
    messages.unread.update(read: true)
    user.set_has_unread_messages if update_user
  end

  private

  def copy_relationship_details(rr_from)
    copy_last_contacted_at(rr_from)
    copy_category(rr_from)
    copy_notes(rr_from)
    copy_client_status(rr_from)
  end

  def copy_last_contacted_at(rr_from)
    return if rr_from.last_contacted_at.blank?
    return unless last_contacted_at.nil? || last_contacted_at < rr_from.last_contacted_at
    update!(last_contacted_at: rr_from.last_contacted_at)
  end

  def copy_category(rr_from)
    return unless rr_from.category != 'no_cat' && category == 'no_cat'
    update!(category: rr_from.category)
  end

  def copy_notes(rr_from)
    return unless rr_from.notes.present? && notes.blank?
    update!(notes: rr_from.notes)
  end

  def copy_client_status(rr_from)
    return unless rr_from.client_status.present? && client_status.blank?
    update!(client_status: rr_from.client_status)
  end

  def attachments
    Attachment.where(message: messages)
  end

  def hours_since_contact
    ((Time.zone.now - (last_contacted_at || created_at)) / 3600).round
  end

  def unique_within_department
    @matching_record = ReportingRelationship
                       .active
                       .joins(:user)
                       .where(users: { department_id: user.try(:department_id) })
                       .where.not(user: user)
                       .find_by(client: client)

    errors.add(:client, :existing_dept_relationship, user_full_name: @matching_record.user.full_name) if @matching_record.present? && active
  end
end